summaryrefslogtreecommitdiffstats
path: root/service/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'service/java/com')
-rw-r--r--service/java/com/android/server/wifi/CarrierNetworkConfig.java40
-rw-r--r--service/java/com/android/server/wifi/CarrierNetworkEvaluator.java16
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java53
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java15
-rw-r--r--service/java/com/android/server/wifi/WifiDiagnostics.java2
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java4
-rw-r--r--service/java/com/android/server/wifi/WifiKeyStore.java73
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkFactory.java2
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java2
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java2
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointManager.java6
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java7
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java42
-rw-r--r--service/java/com/android/server/wifi/hotspot2/soap/RedirectListener.java44
-rw-r--r--service/java/com/android/server/wifi/util/TelephonyUtil.java59
15 files changed, 269 insertions, 98 deletions
diff --git a/service/java/com/android/server/wifi/CarrierNetworkConfig.java b/service/java/com/android/server/wifi/CarrierNetworkConfig.java
index cf39e0a7b..2d99d14d9 100644
--- a/service/java/com/android/server/wifi/CarrierNetworkConfig.java
+++ b/service/java/com/android/server/wifi/CarrierNetworkConfig.java
@@ -53,6 +53,7 @@ public class CarrierNetworkConfig {
private static final int ENCODED_SSID_INDEX = 0;
private static final int EAP_TYPE_INDEX = 1;
private static final int CONFIG_ELEMENT_SIZE = 2;
+
private static final Uri CONTENT_URI = Uri.parse("content://carrier_information/carrier");
private boolean mDbg = false;
@@ -61,6 +62,12 @@ public class CarrierNetworkConfig {
private boolean mIsCarrierImsiEncryptionInfoAvailable = false;
private ImsiEncryptionInfo mLastImsiEncryptionInfo = null; // used for dumpsys only
+ // RFC2045: adds Line Feed at each 76 chars and encode it.
+ public static final int ENCODING_METHOD_RFC_2045 = 2045;
+
+ // RFC4648: encodes whole data into one string.
+ public static final int ENCODING_METHOD_RFC_4648 = 4648;
+
/**
* Enable/disable verbose logging.
*/
@@ -118,6 +125,15 @@ public class CarrierNetworkConfig {
}
/**
+ * @return the base64 encoding flag with a carrier AP, or -1 if the specified AP is not
+ * associate with a carrier network.
+ */
+ public int getBase64EncodingFlag(String ssid) {
+ NetworkInfo info = mCarrierNetworkMap.get(ssid);
+ return info == null ? -1 : info.mBase64EncodingFlag;
+ }
+
+ /**
* @return True if carrier IMSI encryption info is available, False otherwise.
*/
public boolean isCarrierEncryptionInfoAvailable() {
@@ -157,16 +173,19 @@ public class CarrierNetworkConfig {
private static class NetworkInfo {
final int mEapType;
final String mCarrierName;
+ final int mBase64EncodingFlag;
- NetworkInfo(int eapType, String carrierName) {
+ NetworkInfo(int eapType, String carrierName, int base64EncodingFlag) {
mEapType = eapType;
mCarrierName = carrierName;
+ mBase64EncodingFlag = base64EncodingFlag;
}
@Override
public String toString() {
return new StringBuffer("NetworkInfo: eap=").append(mEapType).append(
- ", carrier=").append(mCarrierName).toString();
+ ", carrier=").append(mCarrierName).append("base64EncodingFlag=").append(
+ mBase64EncodingFlag).toString();
}
}
@@ -230,22 +249,35 @@ public class CarrierNetworkConfig {
return;
}
+ int encodeMethod = carrierConfig.getInt(
+ CarrierConfigManager.KEY_IMSI_ENCODING_METHOD_INT, ENCODING_METHOD_RFC_2045);
+ if (encodeMethod != ENCODING_METHOD_RFC_2045 && encodeMethod != ENCODING_METHOD_RFC_4648) {
+ Log.e(TAG, "Invalid encoding method type: " + encodeMethod);
+ return;
+ }
+
for (String networkConfig : networkConfigs) {
String[] configArr = networkConfig.split(NETWORK_CONFIG_SEPARATOR);
+
if (configArr.length != CONFIG_ELEMENT_SIZE) {
Log.e(TAG, "Ignore invalid config: " + networkConfig);
continue;
}
+
try {
+ int flag = Base64.DEFAULT;
+ if (encodeMethod == ENCODING_METHOD_RFC_4648) {
+ flag = Base64.NO_WRAP;
+ }
String ssid = new String(Base64.decode(
- configArr[ENCODED_SSID_INDEX], Base64.DEFAULT));
+ configArr[ENCODED_SSID_INDEX], flag));
int eapType = parseEapType(Integer.parseInt(configArr[EAP_TYPE_INDEX]));
// Verify EAP type, must be a SIM based EAP type.
if (eapType == -1) {
Log.e(TAG, "Invalid EAP type: " + configArr[EAP_TYPE_INDEX]);
continue;
}
- mCarrierNetworkMap.put(ssid, new NetworkInfo(eapType, carrierName));
+ mCarrierNetworkMap.put(ssid, new NetworkInfo(eapType, carrierName, flag));
} catch (NumberFormatException e) {
Log.e(TAG, "Failed to parse EAP type: '" + configArr[EAP_TYPE_INDEX] + "' "
+ e.getMessage());
diff --git a/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java b/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java
index b052c7d94..323cfc0b9 100644
--- a/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java
+++ b/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java
@@ -110,6 +110,17 @@ public class CarrierNetworkEvaluator implements NetworkEvaluator {
}
config.enterpriseConfig.setEapMethod(eapType);
+ // Check if we already have a network with the same credentials in WifiConfigManager
+ // database. If yes, we should check if the network is currently blacklisted.
+ WifiConfiguration existingNetwork =
+ mWifiConfigManager.getConfiguredNetwork(config.configKey());
+ if (existingNetwork != null
+ && !existingNetwork.getNetworkSelectionStatus().isNetworkEnabled()
+ && !mWifiConfigManager.tryEnableNetwork(existingNetwork.networkId)) {
+ mLocalLog.log(TAG + ": Ignoring blacklisted network: "
+ + WifiNetworkSelector.toNetworkString(existingNetwork));
+ continue;
+ }
// Add the newly created WifiConfiguration to WifiConfigManager.
NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(config,
Process.WIFI_UID);
@@ -131,7 +142,10 @@ public class CarrierNetworkEvaluator implements NetworkEvaluator {
config = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId());
- WifiConfiguration.NetworkSelectionStatus nss = config.getNetworkSelectionStatus();
+ WifiConfiguration.NetworkSelectionStatus nss = null;
+ if (config != null) {
+ nss = config.getNetworkSelectionStatus();
+ }
if (nss == null) {
mLocalLog.log(TAG + ": null network selection status for: " + config);
continue;
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index ff17e410e..64f800571 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -17,7 +17,6 @@
package com.android.server.wifi;
import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
-import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER_DISCONNECT;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
@@ -811,6 +810,7 @@ public class ClientModeImpl extends StateMachine {
mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
mWifiConnectivityManager = mWifiInjector.makeWifiConnectivityManager(this);
+
mLinkProperties = new LinkProperties();
mMcastLockManagerFilterController = new McastLockManagerFilterController();
@@ -1590,19 +1590,20 @@ public class ClientModeImpl extends StateMachine {
}
/**
- * Method to trigger a disconnect.
- * Note: To be used from within the wifi stack.
+ * Disconnect from Access Point
*/
- public void disconnectCommandInternal() {
- sendMessage(CMD_DISCONNECT, 0 /* fromExternal */);
+ public void disconnectCommand() {
+ sendMessage(CMD_DISCONNECT);
}
/**
* Method to trigger a disconnect.
- * Note: To be used from public API surface.
+ *
+ * @param uid UID of requesting caller
+ * @param reason disconnect reason
*/
- public void disconnectCommandExternal() {
- sendMessage(CMD_DISCONNECT, 1 /* fromExternal */);
+ public void disconnectCommand(int uid, int reason) {
+ sendMessage(CMD_DISCONNECT, uid, reason);
}
/**
@@ -3675,7 +3676,7 @@ public class ClientModeImpl extends StateMachine {
if (removedNetworkIds.contains(mTargetNetworkId)
|| removedNetworkIds.contains(mLastNetworkId)) {
// Disconnect and let autojoin reselect a new network
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
break;
case CMD_USER_UNLOCK:
@@ -4133,7 +4134,7 @@ public class ClientModeImpl extends StateMachine {
netId = message.arg1;
if (netId == mTargetNetworkId || netId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
break;
case CMD_ENABLE_NETWORK:
@@ -4157,7 +4158,7 @@ public class ClientModeImpl extends StateMachine {
replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
if (netId == mTargetNetworkId || netId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
} else {
loge("Failed to disable network");
@@ -4172,7 +4173,7 @@ public class ClientModeImpl extends StateMachine {
if (config.networkId == mTargetNetworkId
|| config.networkId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
}
break;
@@ -4186,7 +4187,8 @@ public class ClientModeImpl extends StateMachine {
// Pair<identity, encrypted identity>
Pair<String, String> identityPair =
TelephonyUtil.getSimIdentity(getTelephonyManager(),
- new TelephonyUtil(), mTargetWifiConfiguration);
+ new TelephonyUtil(), mTargetWifiConfiguration,
+ mWifiInjector.getCarrierNetworkConfig());
Log.i(TAG, "SUP_REQUEST_IDENTITY: identityPair=" + identityPair);
if (identityPair != null && identityPair.first != null) {
mWifiNative.simIdentityResponse(mInterfaceName, netId,
@@ -4332,7 +4334,7 @@ public class ClientModeImpl extends StateMachine {
if (removedNetworkIds.contains(mTargetNetworkId)
|| removedNetworkIds.contains(mLastNetworkId)) {
// Disconnect and let autojoin reselect a new network.
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
break;
case CMD_REMOVE_USER_CONFIGURATIONS:
@@ -4341,7 +4343,7 @@ public class ClientModeImpl extends StateMachine {
if (removedNetworkIds.contains(mTargetNetworkId)
|| removedNetworkIds.contains(mLastNetworkId)) {
// Disconnect and let autojoin reselect a new network.
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
break;
case WifiManager.CONNECT_NETWORK:
@@ -4422,7 +4424,7 @@ public class ClientModeImpl extends StateMachine {
netId = message.arg1;
if (netId == mTargetNetworkId || netId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
break;
case CMD_ASSOCIATED_BSSID:
@@ -4486,7 +4488,7 @@ public class ClientModeImpl extends StateMachine {
} else {
logw("Connected to unknown networkId " + mLastNetworkId
+ ", disconnecting...");
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
break;
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
@@ -4519,7 +4521,7 @@ public class ClientModeImpl extends StateMachine {
if (isProviderOwnedNetwork(mTargetNetworkId, fqdn)
|| isProviderOwnedNetwork(mLastNetworkId, fqdn)) {
logd("Disconnect from current network since its provider is updated");
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
replyToMessage(message, message.what, SUCCESS);
} else {
@@ -4532,7 +4534,7 @@ public class ClientModeImpl extends StateMachine {
if (isProviderOwnedNetwork(mTargetNetworkId, fqdn)
|| isProviderOwnedNetwork(mLastNetworkId, fqdn)) {
logd("Disconnect from current network since its provider is removed");
- disconnectCommandInternal();
+ sendMessage(CMD_DISCONNECT);
}
mWifiConfigManager.removePasspointConfiguredNetwork(fqdn);
replyToMessage(message, message.what, SUCCESS);
@@ -5062,17 +5064,8 @@ public class ClientModeImpl extends StateMachine {
}
break;
case CMD_DISCONNECT:
- boolean fromExternal = message.arg1 == 1;
- if (fromExternal) {
- mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
- StaEvent.DISCONNECT_API);
- // For external disconnect requests, temporarily disable the network.
- mWifiConfigManager.updateNetworkSelectionStatus(
- mLastNetworkId, DISABLED_BY_WIFI_MANAGER_DISCONNECT);
- } else {
- mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
- StaEvent.DISCONNECT_GENERIC);
- }
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_GENERIC);
mWifiNative.disconnect(mInterfaceName);
transitionTo(mDisconnectingState);
break;
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 92bec08a3..81b513920 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -16,8 +16,6 @@
package com.android.server.wifi;
-import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_PERMANENT_STARTING_INDEX;
-
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.admin.DeviceAdminInfo;
@@ -128,7 +126,6 @@ public class WifiConfigManager {
1, // threshold for DISABLED_NO_INTERNET_TEMPORARY
1, // threshold for DISABLED_WPS_START
6, // threshold for DISABLED_TLS_VERSION_MISMATCH
- 1, // threshold for DISABLED_BY_WIFI_MANAGER_DISCONNECT
1, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS
1, // threshold for DISABLED_NO_INTERNET_PERMANENT
1, // threshold for DISABLED_BY_WIFI_MANAGER
@@ -153,7 +150,6 @@ public class WifiConfigManager {
10 * 60 * 1000, // threshold for DISABLED_NO_INTERNET_TEMPORARY
0 * 60 * 1000, // threshold for DISABLED_WPS_START
Integer.MAX_VALUE, // threshold for DISABLED_TLS_VERSION
- 1 * 60 * 60 * 1000, // threshold for DISABLED_BY_WIFI_MANAGER_DISCONNECT
Integer.MAX_VALUE, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS
Integer.MAX_VALUE, // threshold for DISABLED_NO_INTERNET_PERMANENT
Integer.MAX_VALUE, // threshold for DISABLED_BY_WIFI_MANAGER
@@ -940,11 +936,7 @@ public class WifiConfigManager {
internalConfig.allowedGroupManagementCiphers =
(BitSet) externalConfig.allowedGroupManagementCiphers.clone();
}
- if (externalConfig.allowedSuiteBCiphers != null
- && !externalConfig.allowedSuiteBCiphers.isEmpty()) {
- internalConfig.allowedSuiteBCiphers =
- (BitSet) externalConfig.allowedSuiteBCiphers.clone();
- }
+ // allowedSuiteBCiphers is set internally according to the certificate type
// Copy over the |IpConfiguration| parameters if set.
if (externalConfig.getIpConfiguration() != null) {
@@ -1568,7 +1560,7 @@ public class WifiConfigManager {
if (reason == NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) {
setNetworkSelectionEnabled(config);
setNetworkStatus(config, WifiConfiguration.Status.ENABLED);
- } else if (reason < NETWORK_SELECTION_DISABLED_PERMANENT_STARTING_INDEX) {
+ } else if (reason < NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) {
setNetworkSelectionTemporarilyDisabled(config, reason);
} else {
setNetworkSelectionPermanentlyDisabled(config, reason);
@@ -2796,7 +2788,8 @@ public class WifiConfigManager {
if (TelephonyUtil.isSimConfig(config)) {
Pair<String, String> currentIdentity =
TelephonyUtil.getSimIdentity(mTelephonyManager,
- new TelephonyUtil(), config);
+ new TelephonyUtil(), config,
+ mWifiInjector.getCarrierNetworkConfig());
if (mVerboseLoggingEnabled) {
Log.d(TAG, "New identity for config " + config + ": " + currentIdentity);
}
diff --git a/service/java/com/android/server/wifi/WifiDiagnostics.java b/service/java/com/android/server/wifi/WifiDiagnostics.java
index a5425dbc1..b288ccb24 100644
--- a/service/java/com/android/server/wifi/WifiDiagnostics.java
+++ b/service/java/com/android/server/wifi/WifiDiagnostics.java
@@ -530,8 +530,6 @@ class WifiDiagnostics extends BaseWifiDiagnostics {
}
private boolean flushDump(int errorCode) {
- if (mBuildProperties.isUserBuild()) return false;
-
if (errorCode == REPORT_REASON_USER_ACTION) return false;
long currentTime = mClock.getWallClockMillis();
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 755a80fb6..d45f78e6b 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -484,6 +484,10 @@ public class WifiInjector {
return mPasspointManager;
}
+ public CarrierNetworkConfig getCarrierNetworkConfig() {
+ return mCarrierNetworkConfig;
+ }
+
public WakeupController getWakeupController() {
return mWakeupController;
}
diff --git a/service/java/com/android/server/wifi/WifiKeyStore.java b/service/java/com/android/server/wifi/WifiKeyStore.java
index 3b8c5bbd7..a22be9b51 100644
--- a/service/java/com/android/server/wifi/WifiKeyStore.java
+++ b/service/java/com/android/server/wifi/WifiKeyStore.java
@@ -26,10 +26,13 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.security.Key;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
@@ -250,6 +253,21 @@ public class WifiKeyStore {
}
}
+
+ /**
+ * @param certData byte array of the certificate
+ */
+ private X509Certificate buildCACertificate(byte[] certData) {
+ try {
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ InputStream inputStream = new ByteArrayInputStream(certData);
+ X509Certificate caCertificateX509 = (X509Certificate) certificateFactory
+ .generateCertificate(inputStream);
+ return caCertificateX509;
+ } catch (CertificateException e) {
+ return null;
+ }
+ }
/**
* Update/Install keys for given enterprise network.
*
@@ -277,6 +295,61 @@ public class WifiKeyStore {
return false;
}
}
+
+ // For WPA3-Enterprise 192-bit networks, set the SuiteBCipher field based on the
+ // CA certificate type. Suite-B requires SHA384, reject other certs.
+ if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192)) {
+ // Read the first CA certificate, and initialize
+ byte[] certData = mKeyStore.get(
+ Credentials.CA_CERTIFICATE + config.enterpriseConfig.getCaCertificateAlias(),
+ android.os.Process.WIFI_UID);
+
+ if (certData == null) {
+ Log.e(TAG, "Failed reading CA certificate for Suite-B");
+ return false;
+ }
+
+ X509Certificate x509CaCert = buildCACertificate(certData);
+
+ if (x509CaCert != null) {
+ String sigAlgOid = x509CaCert.getSigAlgOID();
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Signature algorithm: " + sigAlgOid);
+ }
+ config.allowedSuiteBCiphers.clear();
+
+ // Wi-Fi alliance requires the use of both ECDSA secp384r1 and RSA 3072 certificates
+ // in WPA3-Enterprise 192-bit security networks, which are also known as Suite-B-192
+ // networks, even though NSA Suite-B-192 mandates ECDSA only. The use of the term
+ // Suite-B was already coined in the IEEE 802.11-2016 specification for
+ // AKM 00-0F-AC but the test plan for WPA3-Enterprise 192-bit for APs mandates
+ // support for both RSA and ECDSA, and for STAs it mandates ECDSA and optionally
+ // RSA. In order to be compatible with all WPA3-Enterprise 192-bit deployments,
+ // we are supporting both types here.
+ if (sigAlgOid.equals("1.2.840.113549.1.1.12")) {
+ // sha384WithRSAEncryption
+ config.allowedSuiteBCiphers.set(
+ WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Selecting Suite-B RSA");
+ }
+ } else if (sigAlgOid.equals("1.2.840.10045.4.3.3")) {
+ // ecdsa-with-SHA384
+ config.allowedSuiteBCiphers.set(
+ WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Selecting Suite-B ECDSA");
+ }
+ } else {
+ Log.e(TAG, "Invalid CA certificate type for Suite-B: "
+ + sigAlgOid);
+ return false;
+ }
+ } else {
+ Log.e(TAG, "Invalid CA certificate for Suite-B");
+ return false;
+ }
+ }
return true;
}
}
diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java
index 174379e33..a8e554f2d 100644
--- a/service/java/com/android/server/wifi/WifiNetworkFactory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java
@@ -940,7 +940,7 @@ public class WifiNetworkFactory extends NetworkFactory {
// Invoked at the termination of current connected request processing.
private void teardownForConnectedNetwork() {
Log.i(TAG, "Disconnecting from network on reset");
- mWifiInjector.getClientModeImpl().disconnectCommandInternal();
+ mWifiInjector.getClientModeImpl().disconnectCommand();
mConnectedSpecificNetworkRequest = null;
mConnectedSpecificNetworkRequestSpecifier = null;
// ensure there is no active request in progress.
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index ad09dce8e..a633a0c71 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -504,7 +504,7 @@ public class WifiNetworkSuggestionsManager {
if (mActiveNetworkSuggestionsMatchingConnection.isEmpty()) {
Log.i(TAG, "Only network suggestion matching the connected network removed. "
+ "Disconnecting...");
- mWifiInjector.getClientModeImpl().disconnectCommandInternal();
+ mWifiInjector.getClientModeImpl().disconnectCommand();
}
}
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 276ead4a4..a7d6f4b85 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -1644,7 +1644,7 @@ public class WifiServiceImpl extends BaseWifiService {
return false;
}
mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush();
- mClientModeImpl.disconnectCommandExternal();
+ mClientModeImpl.disconnectCommand();
return true;
}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index d23905729..e874ed1a5 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -338,7 +338,7 @@ public class PasspointManager {
return -1;
}
- String mccMnc = mTelephonyManager.getNetworkOperator();
+ String mccMnc = mTelephonyManager.getSimOperator();
if (mccMnc == null || mccMnc.length() < IMSIParameter.MCC_MNC_LENGTH - 1) {
return -1;
}
@@ -399,7 +399,7 @@ public class PasspointManager {
* {@code null} otherwise.
*/
public PasspointConfiguration createEphemeralPasspointConfigForCarrier(int eapMethod) {
- String mccMnc = mTelephonyManager.getNetworkOperator();
+ String mccMnc = mTelephonyManager.getSimOperator();
if (mccMnc == null || mccMnc.length() < IMSIParameter.MCC_MNC_LENGTH - 1) {
Log.e(TAG, "invalid length of mccmnc");
return null;
@@ -418,7 +418,7 @@ public class PasspointManager {
PasspointConfiguration config = new PasspointConfiguration();
HomeSp homeSp = new HomeSp();
homeSp.setFqdn(domain);
- homeSp.setFriendlyName(mTelephonyManager.getNetworkOperatorName());
+ homeSp.setFriendlyName(mTelephonyManager.getSimOperatorName());
config.setHomeSp(homeSp);
Credential credential = new Credential();
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
index df17389fb..fe882f630 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
@@ -33,6 +33,7 @@ import com.android.server.wifi.ScanDetail;
import com.android.server.wifi.WifiConfigManager;
import com.android.server.wifi.WifiNetworkSelector;
import com.android.server.wifi.util.ScanResultUtil;
+import com.android.server.wifi.util.TelephonyUtil;
import java.util.ArrayList;
import java.util.List;
@@ -96,11 +97,11 @@ public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEva
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()
+ // of the current MNO carrier on the device.
+ if ((TelephonyUtil.getCarrierType(mTelephonyManager) == TelephonyUtil.CARRIER_MNO_TYPE)
&& mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()
&& !mPasspointManager.hasCarrierProvider(
- mTelephonyManager.getNetworkOperator())) {
+ mTelephonyManager.getSimOperator())) {
int eapMethod = mPasspointManager.findEapMethodFromNAIRealmMatchedWithCarrier(
scanDetails);
if (isCarrierEapMethod(eapMethod)) {
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java
index 664824a2a..bf9e6d390 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java
@@ -29,6 +29,7 @@ import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
import android.net.wifi.hotspot2.omadm.PpsMoParser;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -81,12 +82,12 @@ public class PasspointProvisioner {
private final WfaKeyStore mWfaKeyStore;
private final PasspointObjectFactory mObjectFactory;
private final SystemInfo mSystemInfo;
- private RedirectListener mRedirectListener;
private int mCurrentSessionId = 0;
private int mCallingUid;
private boolean mVerboseLoggingEnabled = false;
private WifiManager mWifiManager;
private PasspointManager mPasspointManager;
+ private Looper mLooper;
PasspointProvisioner(Context context, WifiNative wifiNative,
PasspointObjectFactory objectFactory, PasspointManager passpointManager) {
@@ -107,12 +108,12 @@ public class PasspointProvisioner {
* @param looper Looper on which the Provisioning state machine will run
*/
public void init(Looper looper) {
+ mLooper = looper;
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- mProvisioningStateMachine.start(new Handler(looper));
+ mProvisioningStateMachine.start(new Handler(mLooper));
mOsuNetworkConnection.init(mProvisioningStateMachine.getHandler());
// Offload the heavy load job to another thread
mProvisioningStateMachine.getHandler().post(() -> {
- mRedirectListener = RedirectListener.createInstance(looper);
mWfaKeyStore.load();
mOsuServerConnection.init(mObjectFactory.getSSLContext(TLS_VERSION),
mObjectFactory.getTrustManagerImpl(mWfaKeyStore.get()));
@@ -142,10 +143,6 @@ public class PasspointProvisioner {
*/
public boolean startSubscriptionProvisioning(int callingUid, OsuProvider provider,
IProvisioningCallback callback) {
- if (mRedirectListener == null) {
- Log.e(TAG, "RedirectListener is not possible to run");
- return false;
- }
mCallingUid = callingUid;
Log.v(TAG, "Provisioning started with " + provider.toString());
@@ -181,12 +178,20 @@ public class PasspointProvisioner {
private String mSessionId;
private String mWebUrl;
private PasspointConfiguration mPasspointConfiguration;
+ private RedirectListener mRedirectListener;
+ private HandlerThread mRedirectHandlerThread;
+ private Handler mRedirectStartStopHandler;
/**
* Initializes and starts the state machine with a handler to handle incoming events
*/
public void start(Handler handler) {
mHandler = handler;
+ if (mRedirectHandlerThread == null) {
+ mRedirectHandlerThread = new HandlerThread("RedirectListenerHandler");
+ mRedirectHandlerThread.start();
+ mRedirectStartStopHandler = new Handler(mRedirectHandlerThread.getLooper());
+ }
}
/**
@@ -216,9 +221,17 @@ public class PasspointProvisioner {
}
resetStateMachineForFailure(ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED);
}
+ mProvisioningCallback = callback;
+ mRedirectListener = RedirectListener.createInstance(mLooper);
+
+ if (mRedirectListener == null) {
+ resetStateMachineForFailure(
+ ProvisioningCallback.OSU_FAILURE_START_REDIRECT_LISTENER);
+ return;
+ }
+
if (!mOsuServerConnection.canValidateServer()) {
Log.w(TAG, "Provisioning is not possible");
- mProvisioningCallback = callback;
resetStateMachineForFailure(
ProvisioningCallback.OSU_FAILURE_PROVISIONING_NOT_AVAILABLE);
return;
@@ -228,12 +241,10 @@ public class PasspointProvisioner {
serverUrl = new URL(provider.getServerUri().toString());
} catch (MalformedURLException e) {
Log.e(TAG, "Invalid Server URL");
- mProvisioningCallback = callback;
resetStateMachineForFailure(ProvisioningCallback.OSU_FAILURE_SERVER_URL_INVALID);
return;
}
mServerUrl = serverUrl;
- mProvisioningCallback = callback;
mOsuProvider = provider;
if (mOsuProvider.getOsuSsid() == null) {
// Find a best matching OsuProvider that has an OSU SSID from current scanResults
@@ -376,7 +387,7 @@ public class PasspointProvisioner {
invokeProvisioningCallback(PROVISIONING_STATUS,
ProvisioningCallback.OSU_STATUS_REDIRECT_RESPONSE_RECEIVED);
- mRedirectListener.stopServer();
+ mRedirectListener.stopServer(mRedirectStartStopHandler);
secondSoapExchange();
}
@@ -395,7 +406,7 @@ public class PasspointProvisioner {
resetStateMachineForFailure(ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED);
return;
}
- mRedirectListener.stopServer();
+ mRedirectListener.stopServer(mRedirectStartStopHandler);
resetStateMachineForFailure(
ProvisioningCallback.OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER);
}
@@ -754,7 +765,7 @@ public class PasspointProvisioner {
}
mProvisioningStateMachine.handleTimeOutForRedirectResponse();
}
- })) {
+ }, mRedirectStartStopHandler)) {
Log.e(TAG, "fails to start redirect listener");
resetStateMachineForFailure(
ProvisioningCallback.OSU_FAILURE_START_REDIRECT_LISTENER);
@@ -944,12 +955,15 @@ public class PasspointProvisioner {
}
private void resetStateMachine() {
- mRedirectListener.stopServer();
+ if (mRedirectListener != null) {
+ mRedirectListener.stopServer(mRedirectStartStopHandler);
+ }
mOsuNetworkConnection.setEventCallback(null);
mOsuNetworkConnection.disconnectIfNeeded();
mOsuServerConnection.setEventCallback(null);
mOsuServerConnection.cleanup();
mPasspointConfiguration = null;
+ mProvisioningCallback = null;
changeState(STATE_INIT);
}
diff --git a/service/java/com/android/server/wifi/hotspot2/soap/RedirectListener.java b/service/java/com/android/server/wifi/hotspot2/soap/RedirectListener.java
index 03c3ebebb..75a226efd 100644
--- a/service/java/com/android/server/wifi/hotspot2/soap/RedirectListener.java
+++ b/service/java/com/android/server/wifi/hotspot2/soap/RedirectListener.java
@@ -17,9 +17,7 @@
package com.android.server.wifi.hotspot2.soap;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
@@ -47,10 +45,8 @@ public class RedirectListener extends NanoHTTPD {
static final int USER_TIMEOUT_MILLIS = 4 * 60 * 1000;
private static final String TAG = "PasspointRedirectListener";
-
private final String mPath;
private final URL mServerUrl;
- private final Handler mStartStopHandler;
private final Handler mHandler;
private Runnable mTimeOutTask;
private RedirectCallback mRedirectCallback;
@@ -72,7 +68,7 @@ public class RedirectListener extends NanoHTTPD {
}
@VisibleForTesting
- /* package */ RedirectListener(Looper looper, @Nullable Looper startStopLooper, int port)
+ /* package */ RedirectListener(Looper looper, int port)
throws IOException {
super(InetAddress.getLocalHost().getHostAddress(), port);
@@ -82,12 +78,6 @@ public class RedirectListener extends NanoHTTPD {
mServerUrl = new URL("http", getHostname(), port, mPath);
mHandler = new Handler(looper);
mTimeOutTask = () -> mRedirectCallback.onRedirectTimedOut();
- if (startStopLooper == null) {
- HandlerThread redirectHandlerThread = new HandlerThread("RedirectListenerHandler");
- redirectHandlerThread.start();
- startStopLooper = redirectHandlerThread.getLooper();
- }
- mStartStopHandler = new Handler(startStopLooper);
}
/**
@@ -99,8 +89,14 @@ public class RedirectListener extends NanoHTTPD {
public static RedirectListener createInstance(@NonNull Looper looper) {
RedirectListener redirectListener;
try {
- redirectListener = new RedirectListener(looper, null,
- new ServerSocket(0, 1, InetAddress.getLocalHost()).getLocalPort());
+ ServerSocket serverSocket = new ServerSocket(0, 1, InetAddress.getLocalHost());
+ redirectListener = new RedirectListener(looper, serverSocket.getLocalPort());
+ redirectListener.setServerSocketFactory(() -> {
+ // Close current server socket so that new server socket is able to bind the port
+ // in the start() of NanoHTTPD.
+ serverSocket.close();
+ return new ServerSocket();
+ });
} catch (IOException e) {
Log.e(TAG, "fails to create an instance: " + e);
return null;
@@ -112,21 +108,26 @@ public class RedirectListener extends NanoHTTPD {
* Start redirect listener
*
* @param callback to be notified when the redirect request is received or timed out.
- * @return {@code true} in success, {@code false} if the {@code callback} is {@code null} or the
- * server is already running.
+ * @param startHandler handler on which the start code is executed.
+ * @return {@code true} in success, {@code false} if the {@code callback} and {@code
+ * startHandler} are {@code null} or the server is already running.
*/
- public boolean startServer(@NonNull RedirectCallback callback) {
+ public boolean startServer(@NonNull RedirectCallback callback, @NonNull Handler startHandler) {
if (callback == null) {
return false;
}
+ if (startHandler == null) {
+ return false;
+ }
+
if (isAlive()) {
Log.e(TAG, "redirect listener is already running");
return false;
}
mRedirectCallback = callback;
- mStartStopHandler.post(() -> {
+ startHandler.post(() -> {
try {
start();
} catch (IOException e) {
@@ -139,13 +140,18 @@ public class RedirectListener extends NanoHTTPD {
/**
* Stop redirect listener
+ *
+ * @param stopHandler handler on which the stop code is executed.
*/
- public void stopServer() {
+ public void stopServer(@NonNull Handler stopHandler) {
if (mHandler.hasCallbacks(mTimeOutTask)) {
mHandler.removeCallbacks(mTimeOutTask);
}
+ if (stopHandler == null) {
+ return;
+ }
if (isServerAlive()) {
- mStartStopHandler.post(() -> stop());
+ stopHandler.post(() -> stop());
}
}
diff --git a/service/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java
index 597aa71ad..d453c91ea 100644
--- a/service/java/com/android/server/wifi/util/TelephonyUtil.java
+++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java
@@ -16,6 +16,7 @@
package com.android.server.wifi.util;
+import android.annotation.NonNull;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.telephony.ImsiEncryptionInfo;
@@ -25,6 +26,7 @@ import android.util.Log;
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wifi.CarrierNetworkConfig;
import com.android.server.wifi.WifiNative;
import java.security.InvalidKeyException;
@@ -45,6 +47,10 @@ public class TelephonyUtil {
public static final String DEFAULT_EAP_PREFIX = "\0";
+ public static final int CARRIER_INVALID_TYPE = -1;
+ public static final int CARRIER_MNO_TYPE = 0; // Mobile Network Operator
+ public static final int CARRIER_MVNO_TYPE = 1; // Mobile Virtual Network Operator
+
private static final String THREE_GPP_NAI_REALM_FORMAT = "wlan.mnc%s.mcc%s.3gppnetwork.org";
// IMSI encryption method: RSA-OAEP with SHA-256 hash function
@@ -73,16 +79,22 @@ public class TelephonyUtil {
*
* @param tm TelephonyManager instance
* @param config WifiConfiguration that indicates what sort of authentication is necessary
+ * @param telephonyUtil TelephonyUtil instance
+ * @param carrierNetworkConfig CarrierNetworkConfig instance
* @return Pair<identify, encrypted identity> or null if the SIM is not available
* or config is invalid
*/
public static Pair<String, String> getSimIdentity(TelephonyManager tm,
- TelephonyUtil telephonyUtil,
- WifiConfiguration config) {
+ TelephonyUtil telephonyUtil,
+ WifiConfiguration config, CarrierNetworkConfig carrierNetworkConfig) {
if (tm == null) {
Log.e(TAG, "No valid TelephonyManager");
return null;
}
+ if (carrierNetworkConfig == null) {
+ Log.e(TAG, "No valid CarrierNetworkConfig");
+ return null;
+ }
String imsi = tm.getSubscriberId();
String mccMnc = "";
@@ -104,8 +116,15 @@ public class TelephonyUtil {
return null;
}
+ int base64EncodingFlag = carrierNetworkConfig.getBase64EncodingFlag(config.SSID);
+ if (base64EncodingFlag == -1) {
+ // no encrypted IMSI identity.
+ return Pair.create(identity, "");
+ }
String encryptedIdentity = buildEncryptedIdentity(telephonyUtil,
- getSimMethodForConfig(config), imsi, mccMnc, imsiEncryptionInfo);
+ getSimMethodForConfig(config), imsi, mccMnc, imsiEncryptionInfo,
+ base64EncodingFlag);
+
// In case of failure for encryption, set empty string
if (encryptedIdentity == null) encryptedIdentity = "";
return Pair.create(identity, encryptedIdentity);
@@ -116,15 +135,17 @@ public class TelephonyUtil {
* a Base64 encoded string.
*
* @param key The public key to use for encryption
+ * @param encodingFlag base64 encoding flag
* @return Base64 encoded string, or null if encryption failed
*/
@VisibleForTesting
- public String encryptDataUsingPublicKey(PublicKey key, byte[] data) {
+ public String encryptDataUsingPublicKey(PublicKey key, byte[] data, int encodingFlag) {
try {
Cipher cipher = Cipher.getInstance(IMSI_CIPHER_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(data);
- return Base64.encodeToString(encryptedBytes, 0, encryptedBytes.length, Base64.DEFAULT);
+
+ return Base64.encodeToString(encryptedBytes, 0, encryptedBytes.length, encodingFlag);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | BadPaddingException e) {
Log.e(TAG, "Encryption failed: " + e.getMessage());
@@ -138,14 +159,16 @@ public class TelephonyUtil {
* "0" - EAP-AKA Identity
* "1" - EAP-SIM Identity
* "6" - EAP-AKA' Identity
+ *
* @param eapMethod EAP authentication method: EAP-SIM, EAP-AKA, EAP-AKA'
* @param imsi The IMSI retrieved from the SIM
* @param mccMnc The MCC MNC identifier retrieved from the SIM
* @param imsiEncryptionInfo The IMSI encryption info retrieved from the SIM
+ * @param base64EncodingFlag base64 encoding flag
*/
private static String buildEncryptedIdentity(TelephonyUtil telephonyUtil, int eapMethod,
- String imsi, String mccMnc,
- ImsiEncryptionInfo imsiEncryptionInfo) {
+ String imsi, String mccMnc,
+ ImsiEncryptionInfo imsiEncryptionInfo, int base64EncodingFlag) {
if (imsiEncryptionInfo == null) {
return null;
}
@@ -155,9 +178,10 @@ public class TelephonyUtil {
return null;
}
imsi = prefix + imsi;
+
// Build and return the encrypted identity.
String encryptedImsi = telephonyUtil.encryptDataUsingPublicKey(
- imsiEncryptionInfo.getPublicKey(), imsi.getBytes());
+ imsiEncryptionInfo.getPublicKey(), imsi.getBytes(), base64EncodingFlag);
if (encryptedImsi == null) {
Log.e(TAG, "Failed to encrypt IMSI");
return null;
@@ -621,4 +645,23 @@ public class TelephonyUtil {
return null;
}
}
+
+ /**
+ * Get the carrier type of current SIM.
+ *
+ * @param tm {@link TelephonyManager} instance
+ * @return carrier type of current active sim, {{@link #CARRIER_INVALID_TYPE}} if sim is not
+ * ready or {@code tm} is {@code null}
+ */
+ public static int getCarrierType(@NonNull TelephonyManager tm) {
+ if (tm == null || tm.getSimState() != TelephonyManager.SIM_STATE_READY) {
+ return CARRIER_INVALID_TYPE;
+ }
+
+ // If two APIs return the same carrier ID, then is considered as MNO, otherwise MVNO
+ if (tm.getCarrierIdFromSimMccMnc() == tm.getSimCarrierId()) {
+ return CARRIER_MNO_TYPE;
+ }
+ return CARRIER_MVNO_TYPE;
+ }
}