[Passpoint] Allow multiple profiles w/identical FQDN

Allow to install multiple Passpoint profiles with identical
FQDN. The FQDN is not used as a key for profiles.
Existing Passpoint APIs that require FQDN (e.g. remove,
allow auto-join) , will apply the request to all matching
profiles with the same FQDN.

Bug: 148556276
Test: atest android.net.wifi
Test: atest com.android.server.wifi
Change-Id: Ife57367ea974ae361478ff66b2bd9ac1af0fd6ee
This commit is contained in:
Hai Shalom
2020-02-07 09:30:41 -08:00
parent aa2bdfbb49
commit 623e9afbf2
9 changed files with 141 additions and 26 deletions

View File

@@ -270,4 +270,6 @@ interface IWifiManager
void setScanThrottleEnabled(boolean enable);
boolean isScanThrottleEnabled();
Map getAllMatchingPasspointProfilesForScanResults(in List<ScanResult> scanResult);
}

View File

@@ -2112,7 +2112,8 @@ public class WifiConfiguration implements Parcelable {
return !TextUtils.isEmpty(FQDN)
&& !TextUtils.isEmpty(providerFriendlyName)
&& enterpriseConfig != null
&& enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
&& enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
&& !TextUtils.isEmpty(mPasspointUniqueId);
}
/**
@@ -2494,12 +2495,17 @@ public class WifiConfiguration implements Parcelable {
*/
@NonNull
public String getKey() {
String key = providerFriendlyName == null
? getSsidAndSecurityTypeString()
: FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
// Passpoint ephemeral networks have their unique identifier set. Return it as is to be
// able to match internally.
if (mPasspointUniqueId != null) {
return mPasspointUniqueId;
}
String key = getSsidAndSecurityTypeString();
if (!shared) {
key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
return key;
}
@@ -2754,6 +2760,7 @@ public class WifiConfiguration implements Parcelable {
requirePMF = source.requirePMF;
updateIdentifier = source.updateIdentifier;
carrierId = source.carrierId;
mPasspointUniqueId = source.mPasspointUniqueId;
}
}
@@ -2826,6 +2833,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(osu ? 1 : 0);
dest.writeLong(randomizedMacExpirationTimeMs);
dest.writeInt(carrierId);
dest.writeString(mPasspointUniqueId);
}
/** Implement the Parcelable interface {@hide} */
@@ -2900,6 +2908,7 @@ public class WifiConfiguration implements Parcelable {
config.osu = in.readInt() != 0;
config.randomizedMacExpirationTimeMs = in.readLong();
config.carrierId = in.readInt();
config.mPasspointUniqueId = in.readString();
return config;
}
@@ -2907,4 +2916,28 @@ public class WifiConfiguration implements Parcelable {
return new WifiConfiguration[size];
}
};
/**
* Passpoint Unique identifier
* @hide
*/
private String mPasspointUniqueId = null;
/**
* Set the Passpoint unique identifier
* @param uniqueId Passpoint unique identifier to be set
* @hide
*/
public void setPasspointUniqueId(String uniqueId) {
mPasspointUniqueId = uniqueId;
}
/**
* Set the Passpoint unique identifier
* @hide
*/
public String getPasspointUniqueId() {
return mPasspointUniqueId;
}
}

View File

@@ -291,6 +291,11 @@ public class WifiInfo implements Parcelable {
*/
private boolean mMeteredHint;
/**
* Passpoint unique key
*/
private String mPasspointUniqueId;
/** @hide */
@UnsupportedAppUsage
public WifiInfo() {
@@ -322,6 +327,7 @@ public class WifiInfo implements Parcelable {
setRequestingPackageName(null);
setFQDN(null);
setProviderFriendlyName(null);
setPasspointUniqueId(null);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
@@ -370,6 +376,7 @@ public class WifiInfo implements Parcelable {
mWifiStandard = source.mWifiStandard;
mMaxSupportedTxLinkSpeed = source.mMaxSupportedTxLinkSpeed;
mMaxSupportedRxLinkSpeed = source.mMaxSupportedRxLinkSpeed;
mPasspointUniqueId = source.mPasspointUniqueId;
}
}
@@ -977,6 +984,7 @@ public class WifiInfo implements Parcelable {
dest.writeInt(mWifiStandard);
dest.writeInt(mMaxSupportedTxLinkSpeed);
dest.writeInt(mMaxSupportedRxLinkSpeed);
dest.writeString(mPasspointUniqueId);
}
/** Implement the Parcelable interface {@hide} */
@@ -1021,6 +1029,7 @@ public class WifiInfo implements Parcelable {
info.mWifiStandard = in.readInt();
info.mMaxSupportedTxLinkSpeed = in.readInt();
info.mMaxSupportedRxLinkSpeed = in.readInt();
info.mPasspointUniqueId = in.readString();
return info;
}
@@ -1028,4 +1037,24 @@ public class WifiInfo implements Parcelable {
return new WifiInfo[size];
}
};
/**
* Set the Passpoint unique identifier for the current connection
*
* @param passpointUniqueId Unique identifier
* @hide
*/
public void setPasspointUniqueId(@Nullable String passpointUniqueId) {
mPasspointUniqueId = passpointUniqueId;
}
/**
* Get the Passpoint unique identifier for the current connection
*
* @return Passpoint unique identifier
* @hide
*/
public @Nullable String getPasspointUniqueId() {
return mPasspointUniqueId;
}
}

View File

@@ -1400,8 +1400,7 @@ public class WifiManager {
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
try {
Map<String, Map<Integer, List<ScanResult>>> results =
mService.getAllMatchingFqdnsForScanResults(
scanResults);
mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
if (results.isEmpty()) {
return configs;
}
@@ -1409,8 +1408,8 @@ public class WifiManager {
mService.getWifiConfigsForPasspointProfiles(
new ArrayList<>(results.keySet()));
for (WifiConfiguration configuration : wifiConfigurations) {
Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
configuration.FQDN);
Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
results.get(configuration.getKey());
if (scanResultsPerNetworkType != null) {
configs.add(Pair.create(configuration, scanResultsPerNetworkType));
}
@@ -1962,9 +1961,11 @@ public class WifiManager {
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
*
* Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
* Name). In the case when there is an existing configuration with the same
* FQDN, the new configuration will replace the existing configuration.
* Each configuration is uniquely identified by a unique key which depends on the contents of
* the configuration. This allows the caller to install multiple profiles with the same FQDN
* (Fully qualified domain name). Therefore, in order to update an existing profile, it is
* first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
* Otherwise, a new profile will be added with both configuration.
*
* @param config The Passpoint configuration to be added
* @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on

View File

@@ -569,6 +569,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
private WifiConfiguration buildWifiConfigurationForPasspoint() {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.FQDN = mPasspointConfiguration.getHomeSp().getFqdn();
wifiConfiguration.setPasspointUniqueId(mPasspointConfiguration.getUniqueId());
wifiConfiguration.priority = mPriority;
wifiConfiguration.meteredOverride =
mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
@@ -804,7 +805,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN);
wifiConfiguration.allowedKeyManagement, wifiConfiguration.getKey());
}
/**
@@ -827,7 +828,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
&& TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
&& Objects.equals(this.wifiConfiguration.allowedKeyManagement,
lhs.wifiConfiguration.allowedKeyManagement)
&& TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN);
&& TextUtils.equals(this.wifiConfiguration.getKey(),
lhs.wifiConfiguration.getKey());
}
@Override

View File

@@ -908,6 +908,9 @@ public final class PasspointConfiguration implements Parcelable {
throw new IllegalStateException("Credential or HomeSP are not initialized");
}
return mHomeSp.getFqdn();
StringBuilder sb = new StringBuilder();
sb.append(String.format("%s_%x%x", mHomeSp.getFqdn(), mHomeSp.hashCode(),
mCredential.hashCode()));
return sb.toString();
}
}

View File

@@ -16,8 +16,8 @@
package android.net.wifi.hotspot2.pps;
import android.os.Parcelable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
@@ -299,8 +299,10 @@ public final class HomeSp implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis,
mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
return Objects.hash(mFqdn, mFriendlyName, mIconUrl,
mHomeNetworkIds, Arrays.hashCode(mMatchAllOis),
Arrays.hashCode(mMatchAnyOis), Arrays.hashCode(mOtherHomePartners),
Arrays.hashCode(mRoamingConsortiumOis));
}
@Override

View File

@@ -1551,14 +1551,15 @@ public class WifiManagerTest {
*/
@Test
public void testGetAllMatchingWifiConfigs() throws Exception {
Map<String, List<ScanResult>> fqdns = new HashMap<>();
fqdns.put("www.test.com", new ArrayList<>());
when(mWifiService.getAllMatchingFqdnsForScanResults(any(List.class))).thenReturn(fqdns);
Map<String, List<ScanResult>> passpointProfiles = new HashMap<>();
passpointProfiles.put("www.test.com_987a69bca26", new ArrayList<>());
when(mWifiService.getAllMatchingPasspointProfilesForScanResults(
any(List.class))).thenReturn(passpointProfiles);
InOrder inOrder = inOrder(mWifiService);
mWifiManager.getAllMatchingWifiConfigs(new ArrayList<>());
inOrder.verify(mWifiService).getAllMatchingFqdnsForScanResults(any(List.class));
inOrder.verify(mWifiService).getAllMatchingPasspointProfilesForScanResults(any(List.class));
inOrder.verify(mWifiService).getWifiConfigsForPasspointProfiles(any(List.class));
}

View File

@@ -20,8 +20,11 @@ import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -367,16 +370,55 @@ public class PasspointConfigurationTest {
}
/**
* Verify that the unique identifier generated is correct.
* Verify that the unique identifier generated is identical for two instances
*
* @throws Exception
*/
@Test
public void validateUniqueId() throws Exception {
PasspointConfiguration config = PasspointTestUtils.createConfig();
String uniqueId;
uniqueId = config.getUniqueId();
assertEquals(uniqueId, config.getHomeSp().getFqdn());
PasspointConfiguration config1 = PasspointTestUtils.createConfig();
PasspointConfiguration config2 = PasspointTestUtils.createConfig();
assertEquals(config1.getUniqueId(), config2.getUniqueId());
}
/**
* Verify that the unique identifier generated is different for two instances with different
* HomeSp node
*
* @throws Exception
*/
@Test
public void validateUniqueIdDifferentHomeSp() throws Exception {
PasspointConfiguration config1 = PasspointTestUtils.createConfig();
// Modify config2's RCOIs to a different set of values
PasspointConfiguration config2 = PasspointTestUtils.createConfig();
HomeSp homeSp = config2.getHomeSp();
homeSp.setRoamingConsortiumOis(new long[] {0xaa, 0xbb});
config2.setHomeSp(homeSp);
assertNotEquals(config1.getUniqueId(), config2.getUniqueId());
}
/**
* Verify that the unique identifier generated is different for two instances with different
* Credential node
*
* @throws Exception
*/
@Test
public void validateUniqueIdDifferentCredential() throws Exception {
PasspointConfiguration config1 = PasspointTestUtils.createConfig();
// Modify config2's RCOIs to a different set of values
PasspointConfiguration config2 = PasspointTestUtils.createConfig();
Credential credential = config2.getCredential();
credential.setRealm("realm2.example.com");
credential.getSimCredential().setImsi("350460*");
config2.setCredential(credential);
assertNotEquals(config1.getUniqueId(), config2.getUniqueId());
}
/**