Merge "[Wi-Fi] Fix transition mode problems" into qt-qpr1-dev

This commit is contained in:
TreeHugger Robot
2019-12-18 02:27:28 +00:00
committed by Android (Google) Code Review
4 changed files with 413 additions and 106 deletions

View File

@@ -176,6 +176,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
static final String KEY_CARRIER_AP_EAP_TYPE = "key_carrier_ap_eap_type"; static final String KEY_CARRIER_AP_EAP_TYPE = "key_carrier_ap_eap_type";
static final String KEY_CARRIER_NAME = "key_carrier_name"; static final String KEY_CARRIER_NAME = "key_carrier_name";
static final String KEY_EAPTYPE = "eap_psktype"; static final String KEY_EAPTYPE = "eap_psktype";
static final String KEY_IS_PSK_SAE_TRANSITION_MODE = "key_is_psk_sae_transition_mode";
static final String KEY_IS_OWE_TRANSITION_MODE = "key_is_owe_transition_mode";
static final AtomicInteger sLastId = new AtomicInteger(0); static final AtomicInteger sLastId = new AtomicInteger(0);
/* /*
@@ -190,15 +192,12 @@ public class AccessPoint implements Comparable<AccessPoint> {
public static final int SECURITY_OWE = 4; public static final int SECURITY_OWE = 4;
public static final int SECURITY_SAE = 5; public static final int SECURITY_SAE = 5;
public static final int SECURITY_EAP_SUITE_B = 6; public static final int SECURITY_EAP_SUITE_B = 6;
public static final int SECURITY_PSK_SAE_TRANSITION = 7; public static final int SECURITY_MAX_VAL = 7; // Has to be the last
public static final int SECURITY_OWE_TRANSITION = 8;
public static final int SECURITY_MAX_VAL = 9; // Has to be the last
private static final int PSK_UNKNOWN = 0; private static final int PSK_UNKNOWN = 0;
private static final int PSK_WPA = 1; private static final int PSK_WPA = 1;
private static final int PSK_WPA2 = 2; private static final int PSK_WPA2 = 2;
private static final int PSK_WPA_WPA2 = 3; private static final int PSK_WPA_WPA2 = 3;
private static final int PSK_SAE = 4;
private static final int EAP_UNKNOWN = 0; private static final int EAP_UNKNOWN = 0;
private static final int EAP_WPA = 1; // WPA-EAP private static final int EAP_WPA = 1; // WPA-EAP
@@ -259,6 +258,9 @@ public class AccessPoint implements Comparable<AccessPoint> {
private String mOsuFailure; private String mOsuFailure;
private boolean mOsuProvisioningComplete = false; private boolean mOsuProvisioningComplete = false;
private boolean mIsPskSaeTransitionMode = false;
private boolean mIsOweTransitionMode = false;
/** /**
* The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP. * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
*/ */
@@ -322,6 +324,13 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (savedState.containsKey(KEY_CARRIER_NAME)) { if (savedState.containsKey(KEY_CARRIER_NAME)) {
mCarrierName = savedState.getString(KEY_CARRIER_NAME); mCarrierName = savedState.getString(KEY_CARRIER_NAME);
} }
if (savedState.containsKey(KEY_IS_PSK_SAE_TRANSITION_MODE)) {
mIsPskSaeTransitionMode = savedState.getBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE);
}
if (savedState.containsKey(KEY_IS_OWE_TRANSITION_MODE)) {
mIsOweTransitionMode = savedState.getBoolean(KEY_IS_OWE_TRANSITION_MODE);
}
update(mConfig, mInfo, mNetworkInfo); update(mConfig, mInfo, mNetworkInfo);
// Calculate required fields // Calculate required fields
@@ -647,8 +656,15 @@ public class AccessPoint implements Comparable<AccessPoint> {
return oldMetering == mIsScoredNetworkMetered; return oldMetering == mIsScoredNetworkMetered;
} }
public static String getKey(ScanResult result) { /**
return getKey(result.SSID, result.BSSID, getSecurity(result)); * Generates an AccessPoint key for a given scan result
*
* @param context
* @param result Scan result
* @return AccessPoint key
*/
public static String getKey(Context context, ScanResult result) {
return getKey(result.SSID, result.BSSID, getSecurity(context, result));
} }
/** /**
@@ -706,9 +722,44 @@ public class AccessPoint implements Comparable<AccessPoint> {
* Determines if the other AccessPoint represents the same network as this AccessPoint * Determines if the other AccessPoint represents the same network as this AccessPoint
*/ */
public boolean matches(AccessPoint other) { public boolean matches(AccessPoint other) {
if (isPasspoint() || isPasspointConfig() || isOsuProvider()) {
return getKey().equals(other.getKey()); return getKey().equals(other.getKey());
} }
if (!isSameSsidOrBssid(other)) {
return false;
}
final int otherApSecurity = other.getSecurity();
if (mIsPskSaeTransitionMode) {
if (otherApSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) {
return true;
} else if (otherApSecurity == SECURITY_PSK) {
return true;
}
} else {
if ((security == SECURITY_SAE || security == SECURITY_PSK)
&& other.isPskSaeTransitionMode()) {
return true;
}
}
if (mIsOweTransitionMode) {
if (otherApSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
return true;
} else if (otherApSecurity == SECURITY_NONE) {
return true;
}
} else {
if ((security == SECURITY_OWE || security == SECURITY_NONE)
&& other.isOweTransitionMode()) {
return true;
}
}
return security == other.getSecurity();
}
public boolean matches(WifiConfiguration config) { public boolean matches(WifiConfiguration config) {
if (config.isPasspoint()) { if (config.isPasspoint()) {
return (isPasspoint() && config.FQDN.equals(mConfig.FQDN)); return (isPasspoint() && config.FQDN.equals(mConfig.FQDN));
@@ -720,20 +771,79 @@ public class AccessPoint implements Comparable<AccessPoint> {
} }
final int configSecurity = getSecurity(config); final int configSecurity = getSecurity(config);
final WifiManager wifiManager = getWifiManager(); if (mIsPskSaeTransitionMode) {
switch (security) { if (configSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) {
case SECURITY_PSK_SAE_TRANSITION: return true;
return configSecurity == SECURITY_PSK } else if (configSecurity == SECURITY_PSK) {
|| (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE); return true;
case SECURITY_OWE_TRANSITION:
return configSecurity == SECURITY_NONE
|| (wifiManager.isEnhancedOpenSupported()
&& configSecurity == SECURITY_OWE);
default:
return security == configSecurity;
} }
} }
if (mIsOweTransitionMode) {
if (configSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
return true;
} else if (configSecurity == SECURITY_NONE) {
return true;
}
}
return security == getSecurity(config);
}
private boolean matches(WifiConfiguration config, WifiInfo wifiInfo) {
if (config == null || wifiInfo == null) {
return false;
}
if (!config.isPasspoint() && !isSameSsidOrBssid(wifiInfo)) {
return false;
}
return matches(config);
}
@VisibleForTesting
boolean matches(ScanResult scanResult) {
if (scanResult == null) {
return false;
}
if (isPasspoint() || isOsuProvider()) {
throw new IllegalStateException("Should not matches a Passpoint by ScanResult");
}
if (!isSameSsidOrBssid(scanResult)) {
return false;
}
if (mIsPskSaeTransitionMode) {
if (scanResult.capabilities.contains("SAE")
&& getWifiManager().isWpa3SaeSupported()) {
return true;
} else if (scanResult.capabilities.contains("PSK")) {
return true;
}
} else {
if ((security == SECURITY_SAE || security == SECURITY_PSK)
&& AccessPoint.isPskSaeTransitionMode(scanResult)) {
return true;
}
}
if (mIsOweTransitionMode) {
final int scanResultSccurity = getSecurity(mContext, scanResult);
if (scanResultSccurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
return true;
} else if (scanResultSccurity == SECURITY_NONE) {
return true;
}
} else {
if ((security == SECURITY_OWE || security == SECURITY_NONE)
&& AccessPoint.isOweTransitionMode(scanResult)) {
return true;
}
}
return security == getSecurity(mContext, scanResult);
}
public WifiConfiguration getConfig() { public WifiConfiguration getConfig() {
return mConfig; return mConfig;
} }
@@ -818,14 +928,17 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (bestResult != null) { if (bestResult != null) {
ssid = bestResult.SSID; ssid = bestResult.SSID;
bssid = bestResult.BSSID; bssid = bestResult.BSSID;
security = getSecurity(bestResult); security = getSecurity(mContext, bestResult);
if (security == SECURITY_PSK || security == SECURITY_SAE if (security == SECURITY_PSK || security == SECURITY_SAE) {
|| security == SECURITY_PSK_SAE_TRANSITION) {
pskType = getPskType(bestResult); pskType = getPskType(bestResult);
} }
if (security == SECURITY_EAP) { if (security == SECURITY_EAP) {
mEapType = getEapType(bestResult); mEapType = getEapType(bestResult);
} }
mIsPskSaeTransitionMode = AccessPoint.isPskSaeTransitionMode(bestResult);
mIsOweTransitionMode = AccessPoint.isOweTransitionMode(bestResult);
mIsCarrierAp = bestResult.isCarrierAp; mIsCarrierAp = bestResult.isCarrierAp;
mCarrierApEapType = bestResult.carrierApEapType; mCarrierApEapType = bestResult.carrierApEapType;
mCarrierName = bestResult.carrierName; mCarrierName = bestResult.carrierName;
@@ -858,6 +971,12 @@ public class AccessPoint implements Comparable<AccessPoint> {
return concise ? context.getString(R.string.wifi_security_short_eap) : return concise ? context.getString(R.string.wifi_security_short_eap) :
context.getString(R.string.wifi_security_eap); context.getString(R.string.wifi_security_eap);
} }
if (mIsPskSaeTransitionMode) {
return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
context.getString(R.string.wifi_security_psk_sae);
}
switch(security) { switch(security) {
case SECURITY_EAP: case SECURITY_EAP:
switch (mEapType) { switch (mEapType) {
@@ -897,20 +1016,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
return concise ? context.getString(R.string.wifi_security_short_wep) : return concise ? context.getString(R.string.wifi_security_short_wep) :
context.getString(R.string.wifi_security_wep); context.getString(R.string.wifi_security_wep);
case SECURITY_SAE: case SECURITY_SAE:
case SECURITY_PSK_SAE_TRANSITION:
if (pskType == PSK_SAE) {
return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
context.getString(R.string.wifi_security_psk_sae);
} else {
return concise ? context.getString(R.string.wifi_security_short_sae) : return concise ? context.getString(R.string.wifi_security_short_sae) :
context.getString(R.string.wifi_security_sae); context.getString(R.string.wifi_security_sae);
}
case SECURITY_OWE_TRANSITION:
if (mConfig != null && getSecurity(mConfig) == SECURITY_OWE) {
return concise ? context.getString(R.string.wifi_security_short_owe) :
context.getString(R.string.wifi_security_owe);
}
return concise ? "" : context.getString(R.string.wifi_security_none);
case SECURITY_OWE: case SECURITY_OWE:
return concise ? context.getString(R.string.wifi_security_short_owe) : return concise ? context.getString(R.string.wifi_security_short_owe) :
context.getString(R.string.wifi_security_owe); context.getString(R.string.wifi_security_owe);
@@ -1194,7 +1301,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (networkId != WifiConfiguration.INVALID_NETWORK_ID) { if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
return networkId == info.getNetworkId(); return networkId == info.getNetworkId();
} else if (config != null) { } else if (config != null) {
return isKeyEqual(getKey(config)); return matches(config, info);
} else { } else {
// Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID. // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
// (Note that we only do this if the WifiConfiguration explicitly equals INVALID). // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
@@ -1220,8 +1327,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
* Can only be called for unsecured networks. * Can only be called for unsecured networks.
*/ */
public void generateOpenNetworkConfig() { public void generateOpenNetworkConfig() {
if ((security != SECURITY_NONE) && (security != SECURITY_OWE) if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
&& (security != SECURITY_OWE_TRANSITION)) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
if (mConfig != null) if (mConfig != null)
@@ -1264,43 +1370,14 @@ public class AccessPoint implements Comparable<AccessPoint> {
savedState.putBoolean(KEY_IS_CARRIER_AP, mIsCarrierAp); savedState.putBoolean(KEY_IS_CARRIER_AP, mIsCarrierAp);
savedState.putInt(KEY_CARRIER_AP_EAP_TYPE, mCarrierApEapType); savedState.putInt(KEY_CARRIER_AP_EAP_TYPE, mCarrierApEapType);
savedState.putString(KEY_CARRIER_NAME, mCarrierName); savedState.putString(KEY_CARRIER_NAME, mCarrierName);
savedState.putBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE, mIsPskSaeTransitionMode);
savedState.putBoolean(KEY_IS_OWE_TRANSITION_MODE, mIsOweTransitionMode);
} }
public void setListener(AccessPointListener listener) { public void setListener(AccessPointListener listener) {
mAccessPointListener = listener; mAccessPointListener = listener;
} }
private static final String sPskSuffix = "," + String.valueOf(SECURITY_PSK);
private static final String sSaeSuffix = "," + String.valueOf(SECURITY_SAE);
private static final String sPskSaeSuffix = "," + String.valueOf(SECURITY_PSK_SAE_TRANSITION);
private static final String sOweSuffix = "," + String.valueOf(SECURITY_OWE);
private static final String sOpenSuffix = "," + String.valueOf(SECURITY_NONE);
private static final String sOweTransSuffix = "," + String.valueOf(SECURITY_OWE_TRANSITION);
private boolean isKeyEqual(String compareTo) {
if (mKey == null) {
return false;
}
if (compareTo.endsWith(sPskSuffix) || compareTo.endsWith(sSaeSuffix)) {
if (mKey.endsWith(sPskSaeSuffix)) {
// Special handling for PSK-SAE transition mode. If the AP has advertised both,
// we compare the key with both PSK and SAE for a match.
return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
compareTo.substring(0, compareTo.lastIndexOf(',')));
}
}
if (compareTo.endsWith(sOpenSuffix) || compareTo.endsWith(sOweSuffix)) {
if (mKey.endsWith(sOweTransSuffix)) {
// Special handling for OWE/Open networks. If AP advertises OWE in transition mode
// and we have an Open network saved, allow this connection to be established.
return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
compareTo.substring(0, compareTo.lastIndexOf(',')));
}
}
return mKey.equals(compareTo);
}
/** /**
* Sets {@link #mScanResults} to the given collection and updates info based on the best RSSI * Sets {@link #mScanResults} to the given collection and updates info based on the best RSSI
* scan result. * scan result.
@@ -1317,11 +1394,10 @@ public class AccessPoint implements Comparable<AccessPoint> {
// Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint. // Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
if (mKey != null && !isPasspoint() && !isOsuProvider()) { if (mKey != null && !isPasspoint() && !isOsuProvider()) {
for (ScanResult result : scanResults) { for (ScanResult result : scanResults) {
String scanResultKey = AccessPoint.getKey(result); if (!matches(result)) {
if (!isKeyEqual(scanResultKey)) {
Log.d(TAG, String.format( Log.d(TAG, String.format(
"ScanResult %s\nkey of %s did not match current AP key %s", "ScanResult %s\nkey of %s did not match current AP key %s",
result, scanResultKey, mKey)); result, getKey(mContext, result), mKey));
return; return;
} }
} }
@@ -1594,11 +1670,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
private static int getPskType(ScanResult result) { private static int getPskType(ScanResult result) {
boolean wpa = result.capabilities.contains("WPA-PSK"); boolean wpa = result.capabilities.contains("WPA-PSK");
boolean wpa2 = result.capabilities.contains("RSN-PSK"); boolean wpa2 = result.capabilities.contains("RSN-PSK");
boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE");
boolean wpa3 = result.capabilities.contains("RSN-SAE"); boolean wpa3 = result.capabilities.contains("RSN-SAE");
if (wpa3TransitionMode) { if (wpa2 && wpa) {
return PSK_SAE;
} else if (wpa2 && wpa) {
return PSK_WPA_WPA2; return PSK_WPA_WPA2;
} else if (wpa2) { } else if (wpa2) {
return PSK_WPA2; return PSK_WPA2;
@@ -1625,22 +1698,37 @@ public class AccessPoint implements Comparable<AccessPoint> {
return EAP_UNKNOWN; return EAP_UNKNOWN;
} }
private static int getSecurity(ScanResult result) { private static int getSecurity(Context context, ScanResult result) {
if (result.capabilities.contains("WEP")) { final boolean isWep = result.capabilities.contains("WEP");
final boolean isSae = result.capabilities.contains("SAE");
final boolean isPsk = result.capabilities.contains("PSK");
final boolean isEapSuiteB192 = result.capabilities.contains("EAP_SUITE_B_192");
final boolean isEap = result.capabilities.contains("EAP");
final boolean isOwe = result.capabilities.contains("OWE");
final boolean isOweTransition = result.capabilities.contains("OWE_TRANSITION");
if (isSae && isPsk) {
final WifiManager wifiManager = (WifiManager)
context.getSystemService(Context.WIFI_SERVICE);
return wifiManager.isWpa3SaeSupported() ? SECURITY_SAE : SECURITY_PSK;
}
if (isOweTransition) {
final WifiManager wifiManager = (WifiManager)
context.getSystemService(Context.WIFI_SERVICE);
return wifiManager.isEnhancedOpenSupported() ? SECURITY_OWE : SECURITY_NONE;
}
if (isWep) {
return SECURITY_WEP; return SECURITY_WEP;
} else if (result.capabilities.contains("PSK+SAE")) { } else if (isSae) {
return SECURITY_PSK_SAE_TRANSITION;
} else if (result.capabilities.contains("SAE")) {
return SECURITY_SAE; return SECURITY_SAE;
} else if (result.capabilities.contains("PSK")) { } else if (isPsk) {
return SECURITY_PSK; return SECURITY_PSK;
} else if (result.capabilities.contains("EAP_SUITE_B_192")) { } else if (isEapSuiteB192) {
return SECURITY_EAP_SUITE_B; return SECURITY_EAP_SUITE_B;
} else if (result.capabilities.contains("EAP")) { } else if (isEap) {
return SECURITY_EAP; return SECURITY_EAP;
} else if (result.capabilities.contains("OWE_TRANSITION")) { } else if (isOwe) {
return SECURITY_OWE_TRANSITION;
} else if (result.capabilities.contains("OWE")) {
return SECURITY_OWE; return SECURITY_OWE;
} }
return SECURITY_NONE; return SECURITY_NONE;
@@ -1686,10 +1774,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
return "SUITE_B"; return "SUITE_B";
} else if (security == SECURITY_OWE) { } else if (security == SECURITY_OWE) {
return "OWE"; return "OWE";
} else if (security == SECURITY_PSK_SAE_TRANSITION) {
return "PSK+SAE";
} else if (security == SECURITY_OWE_TRANSITION) {
return "OWE_TRANSITION";
} }
return "NONE"; return "NONE";
} }
@@ -1859,4 +1943,61 @@ public class AccessPoint implements Comparable<AccessPoint> {
} }
} }
} }
public boolean isPskSaeTransitionMode() {
return mIsPskSaeTransitionMode;
}
public boolean isOweTransitionMode() {
return mIsOweTransitionMode;
}
private static boolean isPskSaeTransitionMode(ScanResult scanResult) {
return scanResult.capabilities.contains("PSK")
&& scanResult.capabilities.contains("SAE");
}
private static boolean isOweTransitionMode(ScanResult scanResult) {
return scanResult.capabilities.contains("OWE_TRANSITION");
}
private boolean isSameSsidOrBssid(ScanResult scanResult) {
if (scanResult == null) {
return false;
}
if (TextUtils.equals(ssid, scanResult.SSID)) {
return true;
} else if (scanResult.BSSID != null && TextUtils.equals(bssid, scanResult.BSSID)) {
return true;
}
return false;
}
private boolean isSameSsidOrBssid(WifiInfo wifiInfo) {
if (wifiInfo == null) {
return false;
}
if (TextUtils.equals(ssid, removeDoubleQuotes(wifiInfo.getSSID()))) {
return true;
} else if (wifiInfo.getBSSID() != null && TextUtils.equals(bssid, wifiInfo.getBSSID())) {
return true;
}
return false;
}
private boolean isSameSsidOrBssid(AccessPoint accessPoint) {
if (accessPoint == null) {
return false;
}
if (TextUtils.equals(ssid, accessPoint.getSsid())) {
return true;
} else if (accessPoint.getBssid() != null
&& TextUtils.equals(bssid, accessPoint.getBssid())) {
return true;
}
return false;
}
} }

View File

@@ -201,8 +201,7 @@ public class AccessPointPreference extends Preference {
return; return;
} }
if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
&& (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE) && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
&& (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) {
mFrictionSld.setState(STATE_SECURED); mFrictionSld.setState(STATE_SECURED);
} else if (mAccessPoint.isMetered()) { } else if (mAccessPoint.isMetered()) {
mFrictionSld.setState(STATE_METERED); mFrictionSld.setState(STATE_METERED);

View File

@@ -70,8 +70,10 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/** /**
* Tracks saved or available wifi networks and their state. * Tracks saved or available wifi networks and their state.
@@ -475,7 +477,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
continue; continue;
} }
String apKey = AccessPoint.getKey(result); String apKey = AccessPoint.getKey(mContext, result);
List<ScanResult> resultList; List<ScanResult> resultList;
if (scanResultsByApKey.containsKey(apKey)) { if (scanResultsByApKey.containsKey(apKey)) {
resultList = scanResultsByApKey.get(apKey); resultList = scanResultsByApKey.get(apKey);
@@ -548,14 +550,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private void updateAccessPoints(final List<ScanResult> newScanResults, private void updateAccessPoints(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) { List<WifiConfiguration> configs) {
// Map configs and scan results necessary to make AccessPoints
final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size());
if (configs != null) {
for (WifiConfiguration config : configs) {
configsByKey.put(AccessPoint.getKey(config), config);
}
}
WifiConfiguration connectionConfig = null; WifiConfiguration connectionConfig = null;
if (mLastInfo != null) { if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs); connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
@@ -587,7 +581,26 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
getCachedOrCreate(entry.getValue(), cachedAccessPoints); getCachedOrCreate(entry.getValue(), cachedAccessPoints);
// Update the matching config if there is one, to populate saved network info // Update the matching config if there is one, to populate saved network info
accessPoint.update(configsByKey.get(entry.getKey())); final List<WifiConfiguration> matchedConfigs = configs.stream()
.filter(config -> accessPoint.matches(config))
.collect(Collectors.toList());
final int matchedConfigCount = matchedConfigs.size();
if (matchedConfigCount == 0) {
accessPoint.update(null);
} else if (matchedConfigCount == 1) {
accessPoint.update(matchedConfigs.get(0));
} else {
// We may have 2 matched configured WifiCongiguration if the AccessPoint is
// of PSK/SAE transition mode or open/OWE transition mode.
Optional<WifiConfiguration> preferredConfig = matchedConfigs.stream()
.filter(config -> isSaeOrOwe(config)).findFirst();
if (preferredConfig.isPresent()) {
accessPoint.update(preferredConfig.get());
} else {
accessPoint.update(matchedConfigs.get(0));
}
}
accessPoints.add(accessPoint); accessPoints.add(accessPoint);
} }
@@ -653,6 +666,11 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
conditionallyNotifyListeners(); conditionallyNotifyListeners();
} }
private static boolean isSaeOrOwe(WifiConfiguration config) {
final int security = AccessPoint.getSecurity(config);
return security == AccessPoint.SECURITY_SAE || security == AccessPoint.SECURITY_OWE;
}
@VisibleForTesting @VisibleForTesting
List<AccessPoint> updatePasspointAccessPoints( List<AccessPoint> updatePasspointAccessPoints(
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans, List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans,
@@ -701,7 +719,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private AccessPoint getCachedOrCreate( private AccessPoint getCachedOrCreate(
List<ScanResult> scanResults, List<ScanResult> scanResults,
List<AccessPoint> cache) { List<AccessPoint> cache) {
AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0))); AccessPoint accessPoint = getCachedByKey(cache,
AccessPoint.getKey(mContext, scanResults.get(0)));
if (accessPoint == null) { if (accessPoint == null) {
accessPoint = new AccessPoint(mContext, scanResults); accessPoint = new AccessPoint(mContext, scanResults);
} else { } else {

View File

@@ -39,6 +39,7 @@ import android.net.ScoredNetwork;
import android.net.WifiKey; import android.net.WifiKey;
import android.net.wifi.ScanResult; import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
@@ -1272,7 +1273,7 @@ public class AccessPointTest {
@Test @Test
public void testGetKey_matchesKeysCorrectly() { public void testGetKey_matchesKeysCorrectly() {
AccessPoint ap = new AccessPoint(mContext, mScanResults); AccessPoint ap = new AccessPoint(mContext, mScanResults);
assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mScanResults.get(0))); assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mContext, mScanResults.get(0)));
WifiConfiguration spyConfig = spy(new WifiConfiguration()); WifiConfiguration spyConfig = spy(new WifiConfiguration());
when(spyConfig.isPasspoint()).thenReturn(true); when(spyConfig.isPasspoint()).thenReturn(true);
@@ -1293,6 +1294,44 @@ public class AccessPointTest {
assertThat(osuAp.getKey()).isEqualTo(AccessPoint.getKey(provider)); assertThat(osuAp.getKey()).isEqualTo(AccessPoint.getKey(provider));
} }
/**
* Test that getKey returns a key of SAE type for a PSK/SAE transition mode ScanResult.
*/
@Test
public void testGetKey_supportSaeTransitionMode_shouldGetSaeKey() {
ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
scanResult.capabilities =
"[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
StringBuilder key = new StringBuilder();
key.append(AccessPoint.KEY_PREFIX_AP);
key.append(TEST_SSID);
key.append(',');
key.append(AccessPoint.SECURITY_SAE);
assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
}
/**
* Test that getKey returns a key of PSK type for a PSK/SAE transition mode ScanResult.
*/
@Test
public void testGetKey_notSupportSaeTransitionMode_shouldGetPskKey() {
ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
scanResult.capabilities =
"[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
StringBuilder key = new StringBuilder();
key.append(AccessPoint.KEY_PREFIX_AP);
key.append(TEST_SSID);
key.append(',');
key.append(AccessPoint.SECURITY_PSK);
assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
}
/** /**
* Verifies that the Passpoint AccessPoint constructor creates AccessPoints whose isPasspoint() * Verifies that the Passpoint AccessPoint constructor creates AccessPoints whose isPasspoint()
* returns true. * returns true.
@@ -1522,4 +1561,113 @@ public class AccessPointTest {
verify(mMockConnectListener).onFailure(anyInt()); verify(mMockConnectListener).onFailure(anyInt());
} }
/**
* Verifies that matches(AccessPoint other) matches a PSK/SAE transition mode AP to a PSK or a
* SAE AP.
*/
@Test
public void testMatches1_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
// Transition mode AP matches a SAE AP.
AccessPoint saeAccessPoint = new TestAccessPointBuilder(mContext)
.setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
.setSecurity(AccessPoint.SECURITY_SAE)
.build();
assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isTrue();
// Transition mode AP matches a PSK AP.
AccessPoint pskAccessPoint = new TestAccessPointBuilder(mContext)
.setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
.setSecurity(AccessPoint.SECURITY_PSK)
.build();
assertThat(pskSaeTransitionModeAp.matches(pskAccessPoint)).isTrue();
// Transition mode AP does not match a SAE AP if the device does not support SAE.
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
saeAccessPoint = new TestAccessPointBuilder(mContext)
.setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
.setSecurity(AccessPoint.SECURITY_SAE)
.build();
assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isFalse();
}
/**
* Verifies that matches(WifiConfiguration config) matches a PSK/SAE transition mode AP to a PSK
* or a SAE WifiConfiguration.
*/
@Test
public void testMatches2_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
// Transition mode AP matches a SAE WifiConfiguration.
WifiConfiguration saeConfig = new WifiConfiguration();
saeConfig.SSID = TEST_SSID;
saeConfig.allowedKeyManagement.set(KeyMgmt.SAE);
assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isTrue();
// Transition mode AP matches a PSK WifiConfiguration.
WifiConfiguration pskConfig = new WifiConfiguration();
pskConfig.SSID = TEST_SSID;
pskConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
assertThat(pskSaeTransitionModeAp.matches(pskConfig)).isTrue();
// Transition mode AP does not matches a SAE WifiConfiguration if the device does not
// support SAE.
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isFalse();
}
/**
* Verifies that matches(ScanResult scanResult) matches a PSK/SAE transition mode AP to a PSK
* or a SAE ScanResult.
*/
@Test
public void testMatches3_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
// Transition mode AP matches a SAE ScanResult.
ScanResult saeScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
TEST_BSSID, DEFAULT_RSSI);
saeScanResult.capabilities = "[SAE-CCMP][ESS][WPS]";
assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isTrue();
// Transition mode AP matches a PSK ScanResult.
ScanResult pskScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
TEST_BSSID, DEFAULT_RSSI);
pskScanResult.capabilities = "[RSN-PSK-CCMP][ESS][WPS]";
assertThat(pskSaeTransitionModeAp.matches(pskScanResult)).isTrue();
// Transition mode AP does not matches a SAE ScanResult if the device does not support SAE.
when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isFalse();
}
private AccessPoint getPskSaeTransitionModeAp() {
ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
TEST_BSSID, DEFAULT_RSSI);
scanResult.capabilities =
"[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
return new TestAccessPointBuilder(mMockContext)
.setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
.build();
}
} }