summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEcco Park <eccopark@google.com>2019-01-30 01:00:15 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-01-30 01:00:15 +0000
commitf71fed24f316cdf228312c0320077cb509d60788 (patch)
tree73f7a2c2597bca06950009e1c6805bd20d87dfee
parentf167c24a7c5634b42583551357fec7e2a3409dde (diff)
parent21c656b1685937afc33b5ea9f4a14fc5b0e14b79 (diff)
downloadandroid_frameworks_opt_net_wifi-f71fed24f316cdf228312c0320077cb509d60788.tar.gz
android_frameworks_opt_net_wifi-f71fed24f316cdf228312c0320077cb509d60788.tar.bz2
android_frameworks_opt_net_wifi-f71fed24f316cdf228312c0320077cb509d60788.zip
Merge "Passpoint: auto-connection for SIM-based profiles."
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java6
-rw-r--r--service/java/com/android/server/wifi/IMSIParameter.java6
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java3
-rw-r--r--service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java47
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java3
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointManager.java235
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java32
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointProvider.java18
-rw-r--r--service/java/com/android/server/wifi/hotspot2/Utils.java49
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java16
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java96
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java247
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java110
13 files changed, 849 insertions, 19 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 4668cca66..b408b9469 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -4492,7 +4492,11 @@ public class ClientModeImpl extends StateMachine {
break;
case CMD_RESET_SIM_NETWORKS:
log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed");
- mWifiConfigManager.resetSimNetworks(message.arg1 == 1);
+ boolean simPresent = message.arg1 == 1;
+ if (!simPresent) {
+ mPasspointManager.removeEphemeralProviders();
+ }
+ mWifiConfigManager.resetSimNetworks(simPresent);
break;
case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
mBluetoothConnectionActive = (message.arg1
diff --git a/service/java/com/android/server/wifi/IMSIParameter.java b/service/java/com/android/server/wifi/IMSIParameter.java
index ab9ec0a28..5754fb132 100644
--- a/service/java/com/android/server/wifi/IMSIParameter.java
+++ b/service/java/com/android/server/wifi/IMSIParameter.java
@@ -24,13 +24,13 @@ import android.text.TextUtils;
* IMSI is a prefix.
*/
public class IMSIParameter {
- private static final int MAX_IMSI_LENGTH = 15;
-
/**
* MCC (Mobile Country Code) is a 3 digit number and MNC (Mobile Network Code) is also a 3
* digit number.
*/
- private static final int MCC_MNC_LENGTH = 6;
+ public static final int MCC_MNC_LENGTH = 6;
+
+ private static final int MAX_IMSI_LENGTH = 15;
private final String mImsi;
private final boolean mPrefix;
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 37544fbab..3525cf51b 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -277,7 +277,8 @@ public class WifiInjector {
mSimAccessor, new PasspointObjectFactory(), mWifiConfigManager, mWifiConfigStore,
mWifiMetrics);
mPasspointNetworkEvaluator = new PasspointNetworkEvaluator(
- mPasspointManager, mWifiConfigManager, mConnectivityLocalLog);
+ mPasspointManager, mWifiConfigManager, mConnectivityLocalLog,
+ mCarrierNetworkConfig, TelephonyManager.from(mContext));
mWifiMetrics.setPasspointManager(mPasspointManager);
mScanRequestProxy = new ScanRequestProxy(mContext,
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE),
diff --git a/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java b/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java
index a75a48896..d95ab3831 100644
--- a/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java
+++ b/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java
@@ -16,6 +16,8 @@
package com.android.server.wifi.hotspot2;
+import static com.android.server.wifi.hotspot2.Utils.isCarrierEapMethod;
+
import com.android.server.wifi.IMSIParameter;
import com.android.server.wifi.hotspot2.anqp.CellularNetwork;
import com.android.server.wifi.hotspot2.anqp.DomainNameElement;
@@ -122,6 +124,28 @@ public class ANQPMatcher {
}
/**
+ * Get a EAP-Method from a corresponding NAI realm that has one of them (EAP-SIM/AKA/AKA)'.
+ *
+ * @param realm a realm of the provider's credential.
+ * @param element The NAI Realm ANQP element
+ * @return a EAP Method (EAP-SIM/AKA/AKA') from matching NAI realm, {@code -1} otherwise.
+ */
+ public static int getCarrierEapMethodFromMatchingNAIRealm(String realm,
+ NAIRealmElement element) {
+ if (element == null || element.getRealmDataList().isEmpty()) {
+ return -1;
+ }
+
+ for (NAIRealmData realmData : element.getRealmDataList()) {
+ int eapMethodID = getEapMethodForNAIRealmWithCarrier(realm, realmData);
+ if (eapMethodID != -1) {
+ return eapMethodID;
+ }
+ }
+ return -1;
+ }
+
+ /**
* Match the 3GPP Network in the ANQP element against the SIM credential of a provider.
*
* @param element 3GPP Network ANQP element
@@ -186,6 +210,29 @@ public class ANQPMatcher {
return realmMatch | eapMethodMatch;
}
+ private static int getEapMethodForNAIRealmWithCarrier(String realm,
+ NAIRealmData realmData) {
+ int realmMatch = AuthMatch.NONE;
+
+ for (String realmStr : realmData.getRealms()) {
+ if (DomainMatcher.arg2SubdomainOfArg1(realm, realmStr)) {
+ realmMatch = AuthMatch.REALM;
+ break;
+ }
+ }
+
+ if (realmMatch == AuthMatch.NONE) {
+ return -1;
+ }
+
+ for (EAPMethod eapMethod : realmData.getEAPMethods()) {
+ if (isCarrierEapMethod(eapMethod.getEAPMethodID())) {
+ return eapMethod.getEAPMethodID();
+ }
+ }
+ return -1;
+ }
+
/**
* Match the given EAPMethod against the authentication method of a provider.
*
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java
index 1ba4ff4ca..d0bd6ba5d 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java
@@ -168,6 +168,9 @@ public class PasspointConfigUserStoreData implements WifiConfigStore.StoreData {
}
XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST);
for (PasspointProvider provider : providerList) {
+ if (provider.isEphemeral()) {
+ continue;
+ }
serializeProvider(out, provider);
}
XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST);
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 5683b8306..d23905729 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -27,6 +27,9 @@ import static android.net.wifi.WifiManager.EXTRA_ICON;
import static android.net.wifi.WifiManager.EXTRA_SUBSCRIPTION_REMEDIATION_METHOD;
import static android.net.wifi.WifiManager.EXTRA_URL;
+import static com.android.server.wifi.hotspot2.Utils.isCarrierEapMethod;
+
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
@@ -37,14 +40,20 @@ import android.net.wifi.WifiManager;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
import android.os.Looper;
+import android.os.Process;
import android.os.UserHandle;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import com.android.server.wifi.Clock;
+import com.android.server.wifi.IMSIParameter;
import com.android.server.wifi.SIMAccessor;
+import com.android.server.wifi.ScanDetail;
import com.android.server.wifi.WifiConfigManager;
import com.android.server.wifi.WifiConfigStore;
import com.android.server.wifi.WifiKeyStore;
@@ -53,6 +62,7 @@ import com.android.server.wifi.WifiNative;
import com.android.server.wifi.hotspot2.anqp.ANQPElement;
import com.android.server.wifi.hotspot2.anqp.Constants;
import com.android.server.wifi.hotspot2.anqp.HSOsuProvidersElement;
+import com.android.server.wifi.hotspot2.anqp.NAIRealmElement;
import com.android.server.wifi.hotspot2.anqp.OsuProviderInfo;
import com.android.server.wifi.util.InformationElementUtil;
@@ -106,6 +116,7 @@ public class PasspointManager {
private final CertificateVerifier mCertVerifier;
private final WifiMetrics mWifiMetrics;
private final PasspointProvisioner mPasspointProvisioner;
+ private final TelephonyManager mTelephonyManager;
// Counter used for assigning unique identifier to each provider.
private long mProviderIndex;
@@ -225,6 +236,7 @@ public class PasspointManager {
mWifiConfigManager = wifiConfigManager;
mWifiMetrics = wifiMetrics;
mProviderIndex = 0;
+ mTelephonyManager = TelephonyManager.from(context);
wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigUserStoreData(
mKeyStore, mSimAccessor, new UserDataSourceHandler()));
wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigSharedStoreData(
@@ -312,6 +324,216 @@ public class PasspointManager {
}
/**
+ * Finds a EAP method from a NAI realm element matched with MCC/MNC of current carrier.
+ *
+ * @param scanDetails a list of scanResults used to find a matching AP.
+ * @return a EAP method which should be one of EAP-Methods(EAP-SIM,AKA and AKA') if matching
+ * realm is found, {@code -1} otherwise.
+ */
+ public int findEapMethodFromNAIRealmMatchedWithCarrier(List<ScanDetail> scanDetails) {
+ if (!mWifiConfigManager.isSimPresent()) {
+ return -1;
+ }
+ if (scanDetails == null || scanDetails.isEmpty()) {
+ return -1;
+ }
+
+ String mccMnc = mTelephonyManager.getNetworkOperator();
+ if (mccMnc == null || mccMnc.length() < IMSIParameter.MCC_MNC_LENGTH - 1) {
+ return -1;
+ }
+
+ String domain = Utils.getRealmForMccMnc(mccMnc);
+ if (domain == null) {
+ return -1;
+ }
+ for (ScanDetail scanDetail : scanDetails) {
+ if (!scanDetail.getNetworkDetail().isInterworking()) {
+ // Skip non-Passpoint APs.
+ continue;
+ }
+
+ // Lookup ANQP data in the cache.
+ long bssid;
+ ScanResult scanResult = scanDetail.getScanResult();
+ InformationElementUtil.RoamingConsortium roamingConsortium =
+ InformationElementUtil.getRoamingConsortiumIE(scanResult.informationElements);
+ InformationElementUtil.Vsa vsa = InformationElementUtil.getHS2VendorSpecificIE(
+ scanResult.informationElements);
+ try {
+ bssid = Utils.parseMac(scanResult.BSSID);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid BSSID provided in the scan result: " + scanResult.BSSID);
+ continue;
+ }
+ ANQPNetworkKey anqpKey = ANQPNetworkKey.buildKey(scanResult.SSID, bssid,
+ scanResult.hessid,
+ vsa.anqpDomainID);
+ ANQPData anqpEntry = mAnqpCache.getEntry(anqpKey);
+
+ if (anqpEntry == null) {
+ mAnqpRequestManager.requestANQPElements(bssid, anqpKey,
+ roamingConsortium.anqpOICount > 0,
+ vsa.hsRelease == NetworkDetail.HSRelease.R2);
+ Log.d(TAG, "ANQP entry not found for: " + anqpKey);
+ continue;
+ }
+
+ // Find a matching domain that has following EAP methods(SIM/AKA/AKA') in NAI realms.
+ NAIRealmElement naiRealmElement = (NAIRealmElement) anqpEntry.getElements().get(
+ Constants.ANQPElementType.ANQPNAIRealm);
+ int eapMethod = ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(domain,
+ naiRealmElement);
+ if (eapMethod != -1) {
+ return eapMethod;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Creates an ephemeral {@link PasspointConfiguration} for current carrier(SIM) on the device.
+ *
+ * @param eapMethod eapMethod used to connect Passpoint Network.
+ * @return return the {@link PasspointConfiguration} if a configuration is created successfully,
+ * {@code null} otherwise.
+ */
+ public PasspointConfiguration createEphemeralPasspointConfigForCarrier(int eapMethod) {
+ String mccMnc = mTelephonyManager.getNetworkOperator();
+ if (mccMnc == null || mccMnc.length() < IMSIParameter.MCC_MNC_LENGTH - 1) {
+ Log.e(TAG, "invalid length of mccmnc");
+ return null;
+ }
+
+ if (!isCarrierEapMethod(eapMethod)) {
+ Log.e(TAG, "invalid eapMethod type");
+ return null;
+ }
+
+ String domain = Utils.getRealmForMccMnc(mccMnc);
+ if (domain == null) {
+ Log.e(TAG, "can't make a home domain name using " + mccMnc);
+ return null;
+ }
+ PasspointConfiguration config = new PasspointConfiguration();
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn(domain);
+ homeSp.setFriendlyName(mTelephonyManager.getNetworkOperatorName());
+ config.setHomeSp(homeSp);
+
+ Credential credential = new Credential();
+ credential.setRealm(domain);
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+
+ // prefix match
+ simCredential.setImsi(mccMnc + "*");
+ simCredential.setEapType(eapMethod);
+ credential.setSimCredential(simCredential);
+ config.setCredential(credential);
+ if (!config.validate()) {
+ Log.e(TAG, "Transient PasspointConfiguration is not a valid format");
+ return null;
+ }
+ return config;
+ }
+
+ /**
+ * Check if the {@link PasspointProvider} for a carrier exists.
+ * @param mccmnc a MCC/MNC of the carrier to find
+ * @return {@code true} if the provider already exists, {@code false} otherwise.
+ */
+ public boolean hasCarrierProvider(@Nullable String mccmnc) {
+ String domain = Utils.getRealmForMccMnc(mccmnc);
+ if (domain == null) {
+ Log.e(TAG, "can't make a home domain name using " + mccmnc);
+ return false;
+ }
+
+ // Check if we already have this provider
+ for (Map.Entry<String, PasspointProvider> provider : mProviders.entrySet()) {
+ PasspointConfiguration installedConfig = provider.getValue().getConfig();
+ if (installedConfig.getCredential().getSimCredential() == null) {
+ continue;
+ }
+ if (domain.equals(provider.getKey())) {
+ // We already have the provider that has same FQDN.
+ return true;
+ }
+
+ IMSIParameter imsiParameter = provider.getValue().getImsiParameter();
+ if (imsiParameter == null) {
+ continue;
+ }
+
+ if (imsiParameter.matchesMccMnc(mccmnc)) {
+ // We already have the provider that has same IMSI.
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Installs a {@link PasspointConfiguration} created for auto connection with EAP-SIM/AKA/AKA'.
+ *
+ * It install the Passpoint configuration created on runtime when the (MCC/MNC) of carrier that
+ * supports encrypted IMSI is matched with one of ScanResults
+ *
+ * @param config the Passpoint Configuration to connect the AP with EAP-SIM/AKA/AKA'
+ * @return {@code true} if config is installed successfully, {@code false} otherwise.
+ */
+ public boolean installEphemeralPasspointConfigForCarrier(PasspointConfiguration config) {
+ if (config == null) {
+ Log.e(TAG, "PasspointConfiguration for carrier is null");
+ return false;
+ }
+ if (!mWifiConfigManager.isSimPresent()) {
+ Log.e(TAG, "Sim is not presented on the device");
+ return false;
+ }
+
+ Credential.SimCredential simCredential = config.getCredential().getSimCredential();
+ if (simCredential == null || simCredential.getImsi() == null) {
+ Log.e(TAG, "This is not for a carrier configuration using EAP-SIM/AKA/AKA'");
+ return false;
+ }
+ if (!config.validate()) {
+ Log.e(TAG,
+ "It is not a valid format for Passpoint Configuration with EAP-SIM/AKA/AKA'");
+ return false;
+ }
+
+ String imsi = simCredential.getImsi();
+ if (imsi.length() < IMSIParameter.MCC_MNC_LENGTH) {
+ Log.e(TAG, "Invalid IMSI length: " + imsi.length());
+ return false;
+ }
+
+ int index = imsi.indexOf("*");
+ if (index == -1) {
+ Log.e(TAG, "missing * in imsi");
+ return false;
+ }
+
+ if (hasCarrierProvider(imsi.substring(0, index))) {
+ Log.e(TAG, "It is already in the Provider list");
+ return false;
+ }
+
+ // Create a provider and install the necessary certificates and keys.
+ PasspointProvider newProvider = mObjectFactory.makePasspointProvider(
+ config, mKeyStore, mSimAccessor, mProviderIndex++, Process.WIFI_UID);
+ newProvider.setEphemeral(true);
+
+ Log.d(TAG, "installed PasspointConfiguration for carrier : "
+ + config.getHomeSp().getFriendlyName());
+
+ mProviders.put(config.getHomeSp().getFqdn(), newProvider);
+ mWifiConfigManager.saveToStore(true /* forceWrite */);
+ return true;
+ }
+
+ /**
* Remove a Passpoint provider identified by the given FQDN.
*
* @param fqdn The FQDN of the provider to remove
@@ -334,6 +556,19 @@ public class PasspointManager {
}
/**
+ * Remove the ephemeral providers that are created temporarily for a carrier.
+ */
+ public void removeEphemeralProviders() {
+ for (Map.Entry<String, PasspointProvider> entry : mProviders.entrySet()) {
+ PasspointProvider provider = entry.getValue();
+ if (provider != null && provider.isEphemeral()) {
+ mProviders.remove(entry.getKey());
+ mWifiConfigManager.removePasspointConfiguredNetwork(entry.getKey());
+ }
+ }
+ }
+
+ /**
* Return the installed Passpoint provider configurations.
*
* An empty list will be returned when no provider is installed.
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
index e18280c1d..86f3f0efe 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
@@ -16,18 +16,22 @@
package com.android.server.wifi.hotspot2;
+import static com.android.server.wifi.hotspot2.Utils.isCarrierEapMethod;
+
import android.annotation.NonNull;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Process;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Pair;
+import com.android.server.wifi.CarrierNetworkConfig;
import com.android.server.wifi.NetworkUpdateResult;
import com.android.server.wifi.ScanDetail;
import com.android.server.wifi.WifiConfigManager;
import com.android.server.wifi.WifiNetworkSelector;
-import com.android.server.wifi.WifiNetworkSelector.NetworkEvaluator.OnConnectableListener;
import com.android.server.wifi.util.ScanResultUtil;
import java.util.ArrayList;
@@ -43,7 +47,8 @@ public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEva
private final PasspointManager mPasspointManager;
private final WifiConfigManager mWifiConfigManager;
private final LocalLog mLocalLog;
-
+ private final CarrierNetworkConfig mCarrierNetworkConfig;
+ private final TelephonyManager mTelephonyManager;
/**
* Contained information for a Passpoint network candidate.
*/
@@ -60,10 +65,13 @@ public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEva
}
public PasspointNetworkEvaluator(PasspointManager passpointManager,
- WifiConfigManager wifiConfigManager, LocalLog localLog) {
+ WifiConfigManager wifiConfigManager, LocalLog localLog,
+ CarrierNetworkConfig carrierNetworkConfig, TelephonyManager telephonyManager) {
mPasspointManager = passpointManager;
mWifiConfigManager = wifiConfigManager;
mLocalLog = localLog;
+ mCarrierNetworkConfig = carrierNetworkConfig;
+ mTelephonyManager = telephonyManager;
}
@Override
@@ -82,6 +90,24 @@ public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEva
// Sweep the ANQP cache to remove any expired ANQP entries.
mPasspointManager.sweepCache();
+ // Creates an ephemeral Passpoint profile if it finds a matching Passpoint AP for MCC/MNC
+ // of the current carrier on the device.
+ if (mWifiConfigManager.isSimPresent()
+ && mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()
+ && !mPasspointManager.hasCarrierProvider(
+ mTelephonyManager.getNetworkOperator())) {
+ int eapMethod = mPasspointManager.findEapMethodFromNAIRealmMatchedWithCarrier(
+ scanDetails);
+ if (isCarrierEapMethod(eapMethod)) {
+ PasspointConfiguration carrierConfig =
+ mPasspointManager.createEphemeralPasspointConfigForCarrier(
+ eapMethod);
+ if (carrierConfig != null) {
+ mPasspointManager.installEphemeralPasspointConfigForCarrier(carrierConfig);
+ }
+ }
+ }
+
// Go through each ScanDetail and find the best provider for each ScanDetail.
List<PasspointNetworkCandidate> candidateList = new ArrayList<>();
for (ScanDetail scanDetail : scanDetails) {
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
index 334da7d73..3d73b533e 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
@@ -94,6 +94,12 @@ public class PasspointProvider {
private boolean mHasEverConnected;
private boolean mIsShared;
+ /**
+ * This is a flag to indicate if the Provider is created temporarily.
+ * Thus, it is not saved permanently unlike normal Passpoint profile.
+ */
+ private boolean mIsEphemeral = false;
+
public PasspointProvider(PasspointConfiguration config, WifiKeyStore keyStore,
SIMAccessor simAccessor, long providerId, int creatorUid) {
this(config, keyStore, simAccessor, providerId, creatorUid, null, null, null, null, false,
@@ -176,6 +182,18 @@ public class PasspointProvider {
mHasEverConnected = hasEverConnected;
}
+ public boolean isEphemeral() {
+ return mIsEphemeral;
+ }
+
+ public void setEphemeral(boolean isEphemeral) {
+ mIsEphemeral = isEphemeral;
+ }
+
+ public IMSIParameter getImsiParameter() {
+ return mImsiParameter;
+ }
+
/**
* Install certificates and key based on current configuration.
* Note: the certificates and keys in the configuration will get cleared once
diff --git a/service/java/com/android/server/wifi/hotspot2/Utils.java b/service/java/com/android/server/wifi/hotspot2/Utils.java
index 005af2a87..e523f2f0a 100644
--- a/service/java/com/android/server/wifi/hotspot2/Utils.java
+++ b/service/java/com/android/server/wifi/hotspot2/Utils.java
@@ -1,5 +1,11 @@
package com.android.server.wifi.hotspot2;
+import static com.android.server.wifi.hotspot2.anqp.Constants.BYTE_MASK;
+import static com.android.server.wifi.hotspot2.anqp.Constants.NIBBLE_MASK;
+
+import android.net.wifi.EAPConstants;
+
+import com.android.server.wifi.IMSIParameter;
import com.android.server.wifi.hotspot2.anqp.Constants;
import java.nio.ByteBuffer;
@@ -10,9 +16,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
-import static com.android.server.wifi.hotspot2.anqp.Constants.BYTE_MASK;
-import static com.android.server.wifi.hotspot2.anqp.Constants.NIBBLE_MASK;
-
public abstract class Utils {
public static final long UNSET_TIME = -1;
@@ -101,6 +104,46 @@ public abstract class Utils {
return prefix;
}
+ /**
+ * Creates a realm that consists of mcc and mnc.
+ *
+ * @param mccmnc MCC(Mobile Country Code) and MNC (Mobile Network Code)
+ * @return a realm that has the MCC and MNC as format (wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org).
+ */
+ public static String getRealmForMccMnc(String mccmnc) {
+ // The length of mccmnc is 5 or 6.
+ if (mccmnc == null || (mccmnc.length() != (IMSIParameter.MCC_MNC_LENGTH - 1)
+ && mccmnc.length() != IMSIParameter.MCC_MNC_LENGTH)) {
+ return null;
+ }
+
+ // Please refer to 3GPP TS 23.003 for the definition of Home network realm when making
+ // the home network realm using mcc/mnc.
+ // 1. Take first 5 or 6 digits, depending on whether a 2 or 3 digit MNC used and separate
+ // them into MCC and MNC; if the MNC is 2 digits then a zero shall be added at the
+ // beginning.
+ // 2. Create the wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org domain name.
+ String mcc = mccmnc.substring(0, 3);
+ String mnc = mccmnc.substring(3);
+ if (mnc.length() == 2) {
+ mnc = "0" + mnc;
+ }
+ return String.format("wlan.mnc%s.mcc%s.3gppnetwork.org", mnc, mcc);
+ }
+
+ /**
+ * Check if the eapMethod is for EAP-Methods that carrier supports.
+ *
+ * @param eapMethod eap method to check
+ * @return {@code true} if the provided {@code eapMethod} belongs to the
+ * EAP-Methods(EAP-SIM/AKA/AKA'), {@code false} otherwise.
+ */
+ public static boolean isCarrierEapMethod(int eapMethod) {
+ return eapMethod == EAPConstants.EAP_SIM
+ || eapMethod == EAPConstants.EAP_AKA
+ || eapMethod == EAPConstants.EAP_AKA_PRIME;
+ }
+
public static String roamingConsortiumsToString(long[] ois) {
if (ois == null) {
return "null";
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index 71793c974..28307813b 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -3199,6 +3199,22 @@ public class ClientModeImplTest {
}
/**
+ * Verify removing sim will also remove an ephemeral Passpoint Provider.
+ */
+ @Test
+ public void testResetSimNetworkWhenRemovingSim() throws Exception {
+ // Switch to connect mode and verify wifi is reported as enabled
+ startSupplicantAndDispatchMessages();
+
+ // Indicate that sim is removed.
+ mCmi.sendMessage(ClientModeImpl.CMD_RESET_SIM_NETWORKS, false);
+ mLooper.dispatchAll();
+
+ verify(mPasspointManager).removeEphemeralProviders();
+ verify(mWifiConfigManager).resetSimNetworks(eq(false));
+ }
+
+ /**
* Verifies that WifiLastResortWatchdog is notified of FOURWAY_HANDSHAKE_TIMEOUT.
*/
@Test
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 134d27d0a..4d4ea4487 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java
@@ -51,6 +51,9 @@ import java.util.Set;
*/
@SmallTest
public class ANQPMatcherTest {
+ private static final String TEST_MCC_MNC = "123456";
+ private static final String TEST_3GPP_FQDN = String.format("wlan.mnc%s.mcc%s.3gppnetwork.org",
+ TEST_MCC_MNC.substring(3), TEST_MCC_MNC.substring(0, 3));
/**
* Verify that domain name match will fail when a null Domain Name ANQP element is provided.
*
@@ -362,4 +365,97 @@ public class ANQPMatcherTest {
// The MCC-MNC provided in 3GPP Network ANQP element doesn't match the IMSI parameter.
assertFalse(ANQPMatcher.matchThreeGPPNetwork(element, imsiParam, simImsiList));
}
+
+ /**
+ * Verify that it will return a EAP-Method from the NAI realm when there is a matched realm in
+ * the NAIRealm element.
+ */
+ @Test
+ public void getEapMethodForNAIRealmWithCarrierInMatch() {
+ // Test data.
+ String realm = TEST_3GPP_FQDN;
+ int eapMethodID = EAPConstants.EAP_AKA;
+
+ // Create a realm that has the EAP method
+ EAPMethod method = new EAPMethod(eapMethodID, null);
+ NAIRealmData realmData = new NAIRealmData(
+ Arrays.asList(new String[]{realm}), Arrays.asList(new EAPMethod[]{method}));
+
+ // Setup NAI Realm element.
+ NAIRealmElement element = new NAIRealmElement(
+ Arrays.asList(new NAIRealmData[]{realmData}));
+
+ assertEquals(EAPConstants.EAP_AKA,
+ ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(TEST_3GPP_FQDN, element));
+ }
+
+ /**
+ * Verify that it will return -1 when there is a matched realm in the NAIRealm element, but it
+ * does not have a EAP Method.
+ */
+ @Test
+ public void getEapMethodForNAIRealmWithCarrierInMatchButNotEapMethod() {
+ // Test data.
+ String realm = TEST_3GPP_FQDN;
+ NAIRealmData realmData = new NAIRealmData(Arrays.asList(new String[]{realm}),
+ new ArrayList<>());
+
+ // Setup NAI Realm element.
+ NAIRealmElement element = new NAIRealmElement(
+ Arrays.asList(new NAIRealmData[]{realmData}));
+
+ assertEquals(-1,
+ ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(TEST_3GPP_FQDN, element));
+ }
+
+ /**
+ * Verify that it will return -1 when there is a matched realm in the NAIRealm element, but it
+ * does have non-carrier EAP-method.
+ */
+ @Test
+ public void getEapMethodForNAIRealmWithCarrierInMatchButNotCarrierEapMethod() {
+ // Test data.
+ String realm = TEST_3GPP_FQDN;
+ int eapMethodID = EAPConstants.EAP_TTLS;
+ NonEAPInnerAuth authParam = new NonEAPInnerAuth(NonEAPInnerAuth.AUTH_TYPE_MSCHAP);
+ Set<AuthParam> authSet = new HashSet<>();
+ authSet.add(authParam);
+ Map<Integer, Set<AuthParam>> authMap = new HashMap<>();
+ authMap.put(authParam.getAuthTypeID(), authSet);
+
+ // Setup NAI Realm element.
+ EAPMethod method = new EAPMethod(eapMethodID, authMap);
+ NAIRealmData realmData = new NAIRealmData(
+ Arrays.asList(new String[]{realm}), Arrays.asList(new EAPMethod[]{method}));
+ NAIRealmElement element = new NAIRealmElement(
+ Arrays.asList(new NAIRealmData[]{realmData}));
+
+ assertEquals(-1,
+ ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(TEST_3GPP_FQDN, element));
+ }
+
+ /**
+ * Verify that it will return -1 when there is no matched realm in the NAIRealm element.
+ */
+ @Test
+ public void getEapMethodForNAIRealmWithCarrierInNoMatch() {
+ // Test data.
+ String realm = "test.com";
+ int eapMethodID = EAPConstants.EAP_TTLS;
+ NonEAPInnerAuth authParam = new NonEAPInnerAuth(NonEAPInnerAuth.AUTH_TYPE_MSCHAP);
+ Set<AuthParam> authSet = new HashSet<>();
+ authSet.add(authParam);
+ Map<Integer, Set<AuthParam>> authMap = new HashMap<>();
+ authMap.put(authParam.getAuthTypeID(), authSet);
+
+ // Setup NAI Realm element.
+ EAPMethod method = new EAPMethod(eapMethodID, authMap);
+ NAIRealmData realmData = new NAIRealmData(
+ Arrays.asList(new String[]{realm}), Arrays.asList(new EAPMethod[]{method}));
+ NAIRealmElement element = new NAIRealmElement(
+ Arrays.asList(new NAIRealmData[]{realmData}));
+
+ assertEquals(-1,
+ ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(TEST_3GPP_FQDN, element));
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 35b66c2b8..2442751b4 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -30,6 +30,7 @@ import static android.net.wifi.WifiManager.EXTRA_URL;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -67,15 +68,18 @@ import android.net.wifi.hotspot2.pps.HomeSp;
import android.os.Looper;
import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.telephony.TelephonyManager;
import android.util.Base64;
import android.util.Pair;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.wifi.Clock;
import com.android.server.wifi.FakeKeys;
import com.android.server.wifi.IMSIParameter;
import com.android.server.wifi.SIMAccessor;
+import com.android.server.wifi.ScanDetail;
import com.android.server.wifi.WifiConfigManager;
import com.android.server.wifi.WifiConfigStore;
import com.android.server.wifi.WifiKeyStore;
@@ -86,7 +90,10 @@ import com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType;
import com.android.server.wifi.hotspot2.anqp.DomainNameElement;
import com.android.server.wifi.hotspot2.anqp.HSOsuProvidersElement;
import com.android.server.wifi.hotspot2.anqp.I18Name;
+import com.android.server.wifi.hotspot2.anqp.NAIRealmData;
+import com.android.server.wifi.hotspot2.anqp.NAIRealmElement;
import com.android.server.wifi.hotspot2.anqp.OsuProviderInfo;
+import com.android.server.wifi.hotspot2.anqp.eap.EAPMethod;
import com.android.server.wifi.util.InformationElementUtil;
import com.android.server.wifi.util.InformationElementUtil.RoamingConsortium;
@@ -121,7 +128,7 @@ public class PasspointManagerTest {
private static final String TEST_FRIENDLY_NAME = "friendly name";
private static final String TEST_FRIENDLY_NAME2 = "second friendly name";
private static final String TEST_REALM = "realm.test.com";
- private static final String TEST_IMSI = "1234*";
+ private static final String TEST_IMSI = "123456*";
private static final IMSIParameter TEST_IMSI_PARAM = IMSIParameter.build(TEST_IMSI);
private static final long TEST_BSSID = 0x112233445566L;
@@ -131,6 +138,9 @@ public class PasspointManagerTest {
private static final String TEST_BSSID_STRING2 = "11:22:33:44:55:77";
private static final String TEST_SSID3 = "TestSSID3";
private static final String TEST_BSSID_STRING3 = "11:22:33:44:55:88";
+ private static final String TEST_MCC_MNC = "123456";
+ private static final String TEST_3GPP_FQDN = String.format("wlan.mnc%s.mcc%s.3gppnetwork.org",
+ TEST_MCC_MNC.substring(3), TEST_MCC_MNC.substring(0, 3));
private static final long TEST_HESSID = 0x5678L;
private static final int TEST_ANQP_DOMAIN_ID = 0;
@@ -286,16 +296,17 @@ public class PasspointManagerTest {
*
* @return {@link PasspointConfiguration}
*/
- private PasspointConfiguration createTestConfigWithSimCredential() {
+ private PasspointConfiguration createTestConfigWithSimCredential(String fqdn, String imsi,
+ String realm) {
PasspointConfiguration config = new PasspointConfiguration();
HomeSp homeSp = new HomeSp();
- homeSp.setFqdn(TEST_FQDN);
+ homeSp.setFqdn(fqdn);
homeSp.setFriendlyName(TEST_FRIENDLY_NAME);
config.setHomeSp(homeSp);
Credential credential = new Credential();
credential.setRealm(TEST_REALM);
Credential.SimCredential simCredential = new Credential.SimCredential();
- simCredential.setImsi(TEST_IMSI);
+ simCredential.setImsi(imsi);
simCredential.setEapType(EAPConstants.EAP_SIM);
credential.setSimCredential(simCredential);
config.setCredential(credential);
@@ -320,6 +331,23 @@ public class PasspointManagerTest {
}
/**
+ * Helper function for adding a test provider with SIM credentials to the manager. Return the
+ * mock provider that's added to the manager.
+ *
+ * @return {@link PasspointProvider}
+ */
+ private PasspointProvider addTestCarrierProvider(String fqdn, String imsi, String realm) {
+ PasspointConfiguration config = createTestConfigWithSimCredential(fqdn, imsi, realm);
+ PasspointProvider provider = createMockProvider(config);
+ when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
+ eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(provider);
+
+ assertTrue(mManager.addOrUpdateProvider(config, TEST_CREATOR_UID));
+
+ return provider;
+ }
+
+ /**
* Helper function for creating a ScanResult for testing.
*
* @return {@link ScanResult}
@@ -372,6 +400,31 @@ public class PasspointManagerTest {
}
/**
+ * Helper function for generating {@link ScanDetail} for testing.
+ */
+ private ScanDetail generateScanDetail(String ssid, String bssid, long hessid, int anqpDomaiId,
+ boolean isPasspoint) {
+ NetworkDetail networkDetail = mock(NetworkDetail.class);
+
+ ScanDetail scanDetail = mock(ScanDetail.class);
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.BSSID = bssid;
+ scanResult.hessid = hessid;
+ scanResult.anqpDomainId = anqpDomaiId;
+ if (isPasspoint) {
+ lenient().when(networkDetail.isInterworking()).thenReturn(true);
+ scanResult.flags = ScanResult.FLAG_PASSPOINT_NETWORK;
+ } else {
+ lenient().when(networkDetail.isInterworking()).thenReturn(false);
+ }
+
+ lenient().when(scanDetail.getScanResult()).thenReturn(scanResult);
+ lenient().when(scanDetail.getNetworkDetail()).thenReturn(networkDetail);
+ return scanDetail;
+ }
+
+ /**
* Verify that the ANQP elements will be added to the ANQP cache on receiving a successful
* response.
*
@@ -587,7 +640,8 @@ public class PasspointManagerTest {
*/
@Test
public void addRemoveProviderWithValidSimCredential() throws Exception {
- PasspointConfiguration config = createTestConfigWithSimCredential();
+ PasspointConfiguration config = createTestConfigWithSimCredential(TEST_FQDN, TEST_IMSI,
+ TEST_REALM);
PasspointProvider provider = createMockProvider(config);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(provider);
@@ -630,7 +684,8 @@ public class PasspointManagerTest {
@Test
public void addProviderWithExistingConfig() throws Exception {
// Add a provider with the original configuration.
- PasspointConfiguration origConfig = createTestConfigWithSimCredential();
+ PasspointConfiguration origConfig = createTestConfigWithSimCredential(TEST_FQDN, TEST_IMSI,
+ TEST_REALM);
PasspointProvider origProvider = createMockProvider(origConfig);
when(mObjectFactory.makePasspointProvider(eq(origConfig), eq(mWifiKeyStore),
eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(origProvider);
@@ -1518,4 +1573,184 @@ public class PasspointManagerTest {
assertEquals(true,
mManager.startSubscriptionProvisioning(TEST_UID, osuProvider, mCallback));
}
+
+ /**
+ * Verify that it will return {@code null} if the EAP-Method provided is not a carrier
+ * EAP-Method.
+ */
+ @Test
+ public void verifyCreateEphemeralPasspointConfigurationWithNonCarrierEapMethod() {
+ // static mocking
+ MockitoSession session = ExtendedMockito.mockitoSession().mockStatic(
+ TelephonyManager.class).startMocking();
+ try {
+ TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ when(TelephonyManager.from(any(Context.class))).thenReturn(telephonyManager);
+ when(telephonyManager.getNetworkOperator()).thenReturn("123456");
+ PasspointManager passpointManager = new PasspointManager(mContext, mWifiNative,
+ mWifiKeyStore, mClock,
+ mSimAccessor, mObjectFactory, mWifiConfigManager, mWifiConfigStore,
+ mWifiMetrics);
+
+ assertNull(passpointManager.createEphemeralPasspointConfigForCarrier(
+ EAPConstants.EAP_TLS));
+ } finally {
+ session.finishMocking();
+ }
+ }
+
+ /**
+ * Verify that it creates an ephemeral Passpoint configuration for the carrier.
+ */
+ @Test
+ public void verifyCreateEphemeralPasspointConfigurationWithCarrierEapMethod() {
+ // static mocking
+ MockitoSession session = ExtendedMockito.mockitoSession().mockStatic(
+ TelephonyManager.class).startMocking();
+ try {
+ TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ String mccmnc = "123456";
+ when(TelephonyManager.from(any(Context.class))).thenReturn(telephonyManager);
+ when(telephonyManager.getNetworkOperator()).thenReturn(mccmnc);
+ when(telephonyManager.getNetworkOperatorName()).thenReturn("test");
+
+ PasspointManager passpointManager = new PasspointManager(mContext, mWifiNative,
+ mWifiKeyStore, mClock,
+ mSimAccessor, mObjectFactory, mWifiConfigManager, mWifiConfigStore,
+ mWifiMetrics);
+
+ PasspointConfiguration result =
+ passpointManager.createEphemeralPasspointConfigForCarrier(
+ EAPConstants.EAP_AKA);
+
+ assertNotNull(result);
+ assertTrue(result.validate());
+ assertEquals(Utils.getRealmForMccMnc(mccmnc), result.getHomeSp().getFqdn());
+ assertEquals(mccmnc + "*", result.getCredential().getSimCredential().getImsi());
+ } finally {
+ session.finishMocking();
+ }
+ }
+
+ /**
+ * Verify that it will not install the Passpoint configuration with Non-Carrier EAP method.
+ */
+ @Test
+ public void verifyInstallEphemeralPasspointConfigurationWithNonCarrierEapMethod() {
+ when(mWifiConfigManager.isSimPresent()).thenReturn(true);
+ PasspointConfiguration config = createTestConfigWithUserCredential("abc.com", "test");
+ PasspointProvider provider = createMockProvider(config);
+ when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
+ eq(mSimAccessor), anyLong(), anyInt())).thenReturn(provider);
+
+ assertFalse(mManager.installEphemeralPasspointConfigForCarrier(config));
+ }
+
+ /**
+ * Verify that it installs the carrier Passpoint configuration successfully.
+ */
+ @Test
+ public void verifyInstallEphemeralPasspointConfiguration() {
+ when(mWifiConfigManager.isSimPresent()).thenReturn(true);
+ PasspointConfiguration config = createTestConfigWithSimCredential(TEST_FQDN, TEST_IMSI,
+ TEST_REALM);
+ PasspointProvider provider = createMockProvider(config);
+ when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
+ eq(mSimAccessor), anyLong(), anyInt())).thenReturn(provider);
+
+ assertTrue(mManager.installEphemeralPasspointConfigForCarrier(config));
+ }
+
+ /**
+ * Verify that it returns {@code true} when it has Carrier Provider.
+ */
+ @Test
+ public void verifyHasProviderForCarrierWithMatch() {
+ addTestCarrierProvider(TEST_3GPP_FQDN, TEST_MCC_MNC, TEST_3GPP_FQDN);
+
+ assertTrue(mManager.hasCarrierProvider(TEST_MCC_MNC));
+ }
+
+ /**
+ * Verify that it returns {@code false} when it does not have Carrier Provider.
+ */
+ @Test
+ public void verifyHasProviderForCarrierWithNoMatch() {
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME);
+
+ assertFalse(mManager.hasCarrierProvider(TEST_MCC_MNC));
+ }
+
+ /**
+ * Verify that it returns a carrier EAP-method from NAI-Realm matched with the carrier.
+ */
+ @Test
+ public void verifyFindEapMethodFromNAIRealmMatchedWithCarrierWithMatch() {
+ // static mocking
+ MockitoSession session = ExtendedMockito.mockitoSession().mockStatic(
+ TelephonyManager.class).mockStatic(
+ InformationElementUtil.class).startMocking();
+ try {
+ TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ when(TelephonyManager.from(any(Context.class))).thenReturn(telephonyManager);
+ when(telephonyManager.getNetworkOperator()).thenReturn(TEST_MCC_MNC);
+ when(mWifiConfigManager.isSimPresent()).thenReturn(true);
+ List<ScanDetail> scanDetails = new ArrayList<>();
+ scanDetails.add(generateScanDetail(TEST_SSID, TEST_BSSID_STRING, TEST_HESSID,
+ TEST_ANQP_DOMAIN_ID, true));
+ InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
+
+ // ANQP_DOMAIN_ID(TEST_ANQP_KEY)
+ vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
+ when(InformationElementUtil.getHS2VendorSpecificIE(isNull())).thenReturn(vsa);
+ Map<ANQPElementType, ANQPElement> anqpElementMapOfAp1 = new HashMap<>();
+ List<NAIRealmData> realmDataList = new ArrayList<>();
+ realmDataList.add(new NAIRealmData(Arrays.asList(TEST_3GPP_FQDN),
+ Arrays.asList(new EAPMethod(EAPConstants.EAP_AKA, null))));
+ anqpElementMapOfAp1.put(ANQPElementType.ANQPNAIRealm,
+ new NAIRealmElement(realmDataList));
+
+ ANQPData anqpData = new ANQPData(mClock, anqpElementMapOfAp1);
+ when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(anqpData);
+
+ PasspointManager passpointManager = new PasspointManager(mContext, mWifiNative,
+ mWifiKeyStore, mClock,
+ mSimAccessor, mObjectFactory, mWifiConfigManager, mWifiConfigStore,
+ mWifiMetrics);
+
+ assertEquals(EAPConstants.EAP_AKA,
+ passpointManager.findEapMethodFromNAIRealmMatchedWithCarrier(scanDetails));
+ } finally {
+ session.finishMocking();
+ }
+ }
+
+ /**
+ * Verify that it returns -1 when there is no NAI-Realm matched with the carrier.
+ */
+ @Test
+ public void verifyFindEapMethodFromNAIRealmMatchedWithCarrierWithNoMatch() {
+ // static mocking
+ MockitoSession session = ExtendedMockito.mockitoSession().mockStatic(
+ TelephonyManager.class).mockStatic(
+ InformationElementUtil.class).startMocking();
+ try {
+ TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ when(TelephonyManager.from(any(Context.class))).thenReturn(telephonyManager);
+ when(telephonyManager.getNetworkOperator()).thenReturn(TEST_MCC_MNC);
+ when(mWifiConfigManager.isSimPresent()).thenReturn(true);
+ List<ScanDetail> scanDetails = new ArrayList<>();
+ scanDetails.add(generateScanDetail(TEST_SSID, TEST_BSSID_STRING, 0, 0, false));
+
+ PasspointManager passpointManager = new PasspointManager(mContext, mWifiNative,
+ mWifiKeyStore, mClock,
+ mSimAccessor, mObjectFactory, mWifiConfigManager, mWifiConfigStore,
+ mWifiMetrics);
+
+ assertEquals(-1,
+ passpointManager.findEapMethodFromNAIRealmMatchedWithCarrier(scanDetails));
+ } finally {
+ session.finishMocking();
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java
index dc7e9bb3b..fe0b26bac 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -29,15 +30,18 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
+import android.net.wifi.EAPConstants;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.pps.HomeSp;
+import android.telephony.TelephonyManager;
import android.util.LocalLog;
import android.util.Pair;
import androidx.test.filters.SmallTest;
+import com.android.server.wifi.CarrierNetworkConfig;
import com.android.server.wifi.NetworkUpdateResult;
import com.android.server.wifi.ScanDetail;
import com.android.server.wifi.WifiConfigManager;
@@ -70,8 +74,11 @@ public class PasspointNetworkEvaluatorTest {
private static final PasspointProvider TEST_PROVIDER2 = generateProvider(TEST_CONFIG2);
@Mock PasspointManager mPasspointManager;
+ @Mock PasspointConfiguration mPasspointConfiguration;
@Mock WifiConfigManager mWifiConfigManager;
@Mock OnConnectableListener mOnConnectableListener;
+ @Mock TelephonyManager mTelephonyManager;
+ @Mock CarrierNetworkConfig mCarrierNetworkConfig;
LocalLog mLocalLog;
PasspointNetworkEvaluator mEvaluator;
@@ -108,7 +115,7 @@ public class PasspointNetworkEvaluatorTest {
* Helper function for generating {@link ScanDetail} for testing.
*
* @param ssid The SSID associated with the scan
- * @param rssiLevel The RSSI level associated with the scan
+ * @param bssid The BSSID associated with the scan
* @return {@link ScanDetail}
*/
private static ScanDetail generateScanDetail(String ssid, String bssid) {
@@ -135,7 +142,9 @@ public class PasspointNetworkEvaluatorTest {
initMocks(this);
mLocalLog = new LocalLog(512);
mEvaluator = new PasspointNetworkEvaluator(mPasspointManager, mWifiConfigManager,
- mLocalLog);
+ mLocalLog, mCarrierNetworkConfig, mTelephonyManager);
+ when(mWifiConfigManager.isSimPresent()).thenReturn(true);
+ when(mTelephonyManager.getNetworkOperator()).thenReturn("123456");
}
/**
@@ -367,6 +376,103 @@ public class PasspointNetworkEvaluatorTest {
}
/**
+ * Verify that it never creates an ephemeral Passpoint Configuration when the carrier does not
+ * support encrypted IMSI.
+ */
+ @Test
+ public void skipCreateEphemeralPasspointConfigurationWhenNoSupportEncryptedIMSI() {
+ // Setup ScanDetail and match providers.
+ List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
+ generateScanDetail(TEST_SSID1, TEST_BSSID1)});
+ when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(false);
+ when(mPasspointManager.hasCarrierProvider(anyString())).thenReturn(false);
+
+ assertEquals(null, mEvaluator.evaluateNetworks(
+ scanDetails, null, null, false, false, mOnConnectableListener));
+ verify(mPasspointManager, never()).createEphemeralPasspointConfigForCarrier(anyInt());
+ }
+
+ /**
+ * Verify that it never creates an ephemeral Passpoint Configuration when there is no SIM on the
+ * device.
+ */
+ @Test
+ public void skipCreateEphemeralPasspointConfigurationWithoutSIMCard() {
+ // Setup ScanDetail and match providers.
+ List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
+ generateScanDetail(TEST_SSID1, TEST_BSSID1)});
+ when(mWifiConfigManager.isSimPresent()).thenReturn(false);
+ when(mPasspointManager.hasCarrierProvider(anyString())).thenReturn(false);
+ when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
+
+ assertEquals(null, mEvaluator.evaluateNetworks(
+ scanDetails, null, null, false, false, mOnConnectableListener));
+ verify(mPasspointManager, never()).createEphemeralPasspointConfigForCarrier(anyInt());
+ }
+
+ /**
+ * Verify that it never creates an ephemeral Passpoint Configuration when the profile for the
+ * carrier already exists.
+ */
+ @Test
+ public void skipCreateEphemeralPasspointConfigurationWhenProfileExists() {
+ // Setup ScanDetail and match providers.
+ List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
+ generateScanDetail(TEST_SSID1, TEST_BSSID1)});
+ when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
+ when(mPasspointManager.hasCarrierProvider(anyString())).thenReturn(true);
+
+ assertEquals(null, mEvaluator.evaluateNetworks(
+ scanDetails, null, null, false, false, mOnConnectableListener));
+ verify(mPasspointManager, never()).createEphemeralPasspointConfigForCarrier(anyInt());
+ }
+
+ /**
+ * Verify that it creates an ephemeral Passpoint Configuration when a EAP-Method is found from
+ * NAI realms matched with the carrier.
+ */
+ @Test
+ public void createEphemeralPasspointConfigurationWhenEapMethodIsFoundFromMatchingNAIRealm() {
+ // Setup ScanDetail
+ List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[]{
+ generateScanDetail(TEST_SSID1, TEST_BSSID1)});
+ when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
+ when(mPasspointManager.hasCarrierProvider(anyString())).thenReturn(false);
+ when(mPasspointManager.findEapMethodFromNAIRealmMatchedWithCarrier(
+ any(List.class))).thenReturn(
+ EAPConstants.EAP_AKA);
+
+ assertEquals(null, mEvaluator.evaluateNetworks(
+ scanDetails, null, null, false, false, mOnConnectableListener));
+ verify(mPasspointManager).findEapMethodFromNAIRealmMatchedWithCarrier(any(List.class));
+ verify(mPasspointManager).createEphemeralPasspointConfigForCarrier(
+ eq(EAPConstants.EAP_AKA));
+ }
+
+ /**
+ * Verify that it installs the ephemeral configuration when the config is created for the
+ * carrier.
+ */
+ @Test
+ public void installEphemeralPasspointConfiguration() {
+ // Setup ScanDetail
+ List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[]{
+ generateScanDetail(TEST_SSID1, TEST_BSSID1)});
+ when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
+ when(mPasspointManager.hasCarrierProvider(anyString())).thenReturn(false);
+ when(mPasspointManager.findEapMethodFromNAIRealmMatchedWithCarrier(
+ any(List.class))).thenReturn(
+ EAPConstants.EAP_AKA);
+ when(mPasspointManager.createEphemeralPasspointConfigForCarrier(
+ EAPConstants.EAP_AKA)).thenReturn(mPasspointConfiguration);
+
+ assertEquals(null, mEvaluator.evaluateNetworks(
+ scanDetails, null, null, false, false, mOnConnectableListener));
+ verify(mPasspointManager).installEphemeralPasspointConfigForCarrier(
+ eq(mPasspointConfiguration));
+ }
+
+ /**
* Verify that when the current active network is matched, the scan info associated with
* the network is updated.
*