summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorPeter Qiu <zqiu@google.com>2016-11-02 14:41:25 -0700
committerPeter Qiu <zqiu@google.com>2016-11-21 23:06:36 +0000
commitc04479601696f56c9cc240d4c7fc49fa99f51825 (patch)
tree95596aee5c2614353b37fb46b42cc8cc0f3e55cd /service
parent4365d22b77f31af7567fc12a90786c63cdc5c484 (diff)
hotspot2: add support for managing Passpoint configurations
Add the initial support to PasspointManager for managing Passpoint configurations. More todos: - add support to WifiKeyStore for installing/removing keys and certificates in the Passpoint configurations - add support to WifiConfigStore for loading/storing Passpoint configurations from/to the persistent storage Bug: 32618351 Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Test: download/install Boingo passpoint profile and verify configure is installed using log messages Merged-In: Id394bcf7514157bfaa3038b3f9f4d1003671d11f Change-Id: Id394bcf7514157bfaa3038b3f9f4d1003671d11f
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java4
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java16
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointManager.java153
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointProvider.java35
4 files changed, 198 insertions, 10 deletions
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index a5f132607..bfe6446af 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -91,6 +91,7 @@ public class WifiInjector {
private final WifiPermissionsWrapper mWifiPermissionsWrapper;
private final WifiPermissionsUtil mWifiPermissionsUtil;
private final PasspointManager mPasspointManager;
+ private final SIMAccessor mSimAccessor;
private final boolean mUseRealLogger;
@@ -166,7 +167,8 @@ public class WifiInjector {
mWifiPermissionsWrapper = new WifiPermissionsWrapper(mContext);
mWifiPermissionsUtil = new WifiPermissionsUtil(mWifiPermissionsWrapper, mContext,
mSettingsStore, UserManager.get(mContext));
- mPasspointManager = new PasspointManager(mContext, this);
+ mSimAccessor = new SIMAccessor(mContext);
+ mPasspointManager = new PasspointManager(mContext, this, mSimAccessor);
}
/**
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 420f92366..c70247043 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -85,6 +85,7 @@ import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
+import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.util.WifiPermissionsUtil;
import java.io.BufferedReader;
@@ -160,6 +161,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private WifiPermissionsUtil mWifiPermissionsUtil;
private final boolean mPermissionReviewRequired;
+ private final PasspointManager mPasspointManager;
/**
* Handles client connections
@@ -341,6 +343,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED
|| context.getResources().getBoolean(
com.android.internal.R.bool.config_permissionReviewRequired);
+ mPasspointManager = mWifiInjector.getPasspointManager();
+
enableVerboseLoggingInternal(getVerboseLoggingLevel());
}
@@ -1029,8 +1033,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
*/
@Override
public boolean addPasspointConfiguration(PasspointConfiguration config) {
- // TO BE IMPLEMENTED.
- return true;
+ enforceChangePermission();
+ return mPasspointManager.addProvider(config);
}
/**
@@ -1041,8 +1045,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
*/
@Override
public boolean removePasspointConfiguration(String fqdn) {
- // TO BE IMPLEMENTED.
- return true;
+ enforceChangePermission();
+ return mPasspointManager.removeProvider(fqdn);
}
/**
@@ -1052,8 +1056,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
*/
@Override
public List<PasspointConfiguration> getPasspointConfigurations() {
- // TO BE IMPLEMENTED.
- return null;
+ enforceAccessPermission();
+ return mPasspointManager.getProviderConfigs();
}
/**
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 762917170..2344440f2 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -29,20 +29,33 @@ import static android.net.wifi.WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION;
import android.content.Context;
import android.content.Intent;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.server.wifi.IMSIParameter;
+import com.android.server.wifi.SIMAccessor;
import com.android.server.wifi.WifiInjector;
import com.android.server.wifi.anqp.ANQPElement;
import com.android.server.wifi.anqp.Constants;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
/**
* Responsible for managing passpoint networks.
*/
public class PasspointManager {
- private final Context mContext;
+ private static final String TAG = "PasspointManager";
+
private final PasspointEventHandler mHandler;
+ private final SIMAccessor mSimAccessor;
+ private final Map<String, PasspointProvider> mProviders;
private class CallbackHandler implements PasspointEventHandler.Callbacks {
private final Context mContext;
@@ -91,9 +104,102 @@ public class PasspointManager {
}
}
- public PasspointManager(Context context, WifiInjector wifiInjector) {
- mContext = context;
+ public PasspointManager(Context context, WifiInjector wifiInjector, SIMAccessor simAccessor) {
mHandler = wifiInjector.makePasspointEventHandler(new CallbackHandler(context));
+ mSimAccessor = simAccessor;
+ mProviders = new HashMap<>();
+ // TODO(zqiu): load providers from the persistent storage.
+ }
+
+ /**
+ * Add or install a Passpoint provider with the given configuration.
+ *
+ * Each provider is uniquely identified by its FQDN (Fully Qualified Domain Name).
+ * In the case when there is an existing configuration with the same base
+ * domain, a provider with the new configuration will replace the existing provider.
+ *
+ * @param config Configuration of the Passpoint provider to be added
+ * @return true if provider is added, false otherwise
+ */
+ public boolean addProvider(PasspointConfiguration config) {
+ if (config == null) {
+ Log.e(TAG, "Configuration not provided");
+ return false;
+ }
+ if (!config.validate()) {
+ Log.e(TAG, "Invalid configuration");
+ return false;
+ }
+
+ // Verify IMSI against the IMSI of the installed SIM cards for SIM credential.
+ if (config.credential.simCredential != null) {
+ try {
+ if (mSimAccessor.getMatchingImsis(
+ new IMSIParameter(config.credential.simCredential.imsi)) == null) {
+ Log.e(TAG, "IMSI does not match any SIM card");
+ return false;
+ }
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ // TODO(b/32619189): install new key and certificates to the keystore.
+
+ // Detect existing configuration in the same base domain.
+ PasspointProvider existingProvider = findProviderInSameBaseDomain(config.homeSp.fqdn);
+ if (existingProvider != null) {
+ Log.d(TAG, "Replacing configuration for " + existingProvider.getConfig().homeSp.fqdn
+ + " with " + config.homeSp.fqdn);
+ // TODO(b/32619189): Remove existing key and certificates from the keystore.
+
+ mProviders.remove(existingProvider.getConfig().homeSp.fqdn);
+ }
+
+ // TODO(b/32714562): create/use a copy of configuration to avoid others from modifying it,
+ // since others might still have reference to it?
+ mProviders.put(config.homeSp.fqdn, new PasspointProvider(config));
+
+ // TODO(b/31065385): Persist updated providers configuration to the persistent storage.
+
+ return true;
+ }
+
+ /**
+ * Remove a Passpoint provider identified by the given FQDN.
+ *
+ * @param fqdn The FQDN of the provider to remove
+ * @return true if a provider is removed, false otherwise
+ */
+ public boolean removeProvider(String fqdn) {
+ if (!mProviders.containsKey(fqdn)) {
+ Log.e(TAG, "Config doesn't exist");
+ return false;
+ }
+
+ // TODO(b/32619189): Remove key and certificates from the keystore.
+
+ mProviders.remove(fqdn);
+ return true;
+ }
+
+ /**
+ * Return the installed Passpoint provider configurations.
+ *
+ * @return A list of {@link PasspointConfiguration} or null if none is installed
+ */
+ public List<PasspointConfiguration> getProviderConfigs() {
+ if (mProviders.size() == 0) {
+ return null;
+ }
+
+ List<PasspointConfiguration> configs = new ArrayList<>();
+ for (Map.Entry<String, PasspointProvider> entry : mProviders.entrySet()) {
+ // TODO(zqiu): return a copy of the configuration instead, to prevent others from
+ // modifying it?
+ configs.add(entry.getValue().getConfig());
+ }
+ return configs;
}
/**
@@ -130,4 +236,45 @@ public class PasspointManager {
public boolean queryPasspointIcon(long bssid, String fileName) {
return mHandler.requestIcon(bssid, fileName);
}
+
+ /**
+ * Find a provider that have FQDN in the same base domain as the given domain.
+ *
+ * @param domain The domain to be compared
+ * @return {@link PasspointProvider} if a match is found, null otherwise
+ */
+ private PasspointProvider findProviderInSameBaseDomain(String domain) {
+ for (Map.Entry<String, PasspointProvider> entry : mProviders.entrySet()) {
+ if (isSameBaseDomain(entry.getKey(), domain)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if one domain is the base domain for the other. For example, "test1.test.com"
+ * and "test.com" should return true.
+ *
+ * @param domain1 First domain to be compared
+ * @param domain2 Second domain to be compared
+ * @return true if one domain is a base domain for the other, false otherwise.
+ */
+ private static boolean isSameBaseDomain(String domain1, String domain2) {
+ if (domain1 == null || domain2 == null) {
+ return false;
+ }
+
+ List<String> labelList1 = Utils.splitDomain(domain1);
+ List<String> labelList2 = Utils.splitDomain(domain2);
+ Iterator<String> l1 = labelList1.iterator();
+ Iterator<String> l2 = labelList2.iterator();
+
+ while (l1.hasNext() && l2.hasNext()) {
+ if (!TextUtils.equals(l1.next(), l2.next())) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
new file mode 100644
index 000000000..2cf8c9f68
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2;
+
+import android.net.wifi.hotspot2.PasspointConfiguration;
+
+/**
+ * Abstraction for Passpoint service provider. This class contains the both static
+ * Passpoint configuration data and the runtime data (e.g. blacklisted SSIDs, statistics).
+ */
+public class PasspointProvider {
+ private final PasspointConfiguration mConfig;
+
+ public PasspointProvider(PasspointConfiguration config) {
+ mConfig = config;
+ }
+
+ public PasspointConfiguration getConfig() {
+ return mConfig;
+ }
+}