WifiConfigManager.java revision 78bfa19f8eb5f8e05f72b831b6629d07ec6909e1
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 20 21import android.app.admin.DeviceAdminInfo; 22import android.app.admin.DevicePolicyManagerInternal; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.ApplicationInfo; 27import android.content.pm.PackageManager; 28import android.net.IpConfiguration; 29import android.net.IpConfiguration.IpAssignment; 30import android.net.IpConfiguration.ProxySettings; 31import android.net.NetworkInfo.DetailedState; 32import android.net.ProxyInfo; 33import android.net.StaticIpConfiguration; 34import android.net.wifi.PasspointManagementObjectDefinition; 35import android.net.wifi.ScanResult; 36import android.net.wifi.WifiConfiguration; 37import android.net.wifi.WifiConfiguration.KeyMgmt; 38import android.net.wifi.WifiConfiguration.Status; 39import android.net.wifi.WifiEnterpriseConfig; 40import android.net.wifi.WifiInfo; 41import android.net.wifi.WifiManager; 42import android.net.wifi.WifiScanner; 43import android.net.wifi.WpsInfo; 44import android.net.wifi.WpsResult; 45import android.os.Environment; 46import android.os.RemoteException; 47import android.os.SystemClock; 48import android.os.UserHandle; 49import android.os.UserManager; 50import android.provider.Settings; 51import android.security.KeyStore; 52import android.text.TextUtils; 53import android.util.LocalLog; 54import android.util.Log; 55import android.util.SparseArray; 56 57import com.android.internal.R; 58import com.android.server.LocalServices; 59import com.android.server.net.DelayedDiskWrite; 60import com.android.server.net.IpConfigStore; 61import com.android.server.wifi.anqp.ANQPElement; 62import com.android.server.wifi.anqp.ANQPFactory; 63import com.android.server.wifi.anqp.Constants; 64import com.android.server.wifi.hotspot2.ANQPData; 65import com.android.server.wifi.hotspot2.AnqpCache; 66import com.android.server.wifi.hotspot2.IconEvent; 67import com.android.server.wifi.hotspot2.NetworkDetail; 68import com.android.server.wifi.hotspot2.PasspointMatch; 69import com.android.server.wifi.hotspot2.SupplicantBridge; 70import com.android.server.wifi.hotspot2.Utils; 71import com.android.server.wifi.hotspot2.omadm.PasspointManagementObjectManager; 72import com.android.server.wifi.hotspot2.pps.Credential; 73import com.android.server.wifi.hotspot2.pps.HomeSP; 74 75import org.xml.sax.SAXException; 76 77import java.io.BufferedReader; 78import java.io.DataOutputStream; 79import java.io.File; 80import java.io.FileDescriptor; 81import java.io.FileNotFoundException; 82import java.io.FileReader; 83import java.io.IOException; 84import java.io.PrintWriter; 85import java.text.DateFormat; 86import java.util.ArrayList; 87import java.util.Calendar; 88import java.util.Collection; 89import java.util.Collections; 90import java.util.Comparator; 91import java.util.Date; 92import java.util.HashMap; 93import java.util.HashSet; 94import java.util.List; 95import java.util.Map; 96import java.util.Objects; 97import java.util.Set; 98import java.util.concurrent.ConcurrentHashMap; 99import java.util.concurrent.atomic.AtomicBoolean; 100import java.util.concurrent.atomic.AtomicInteger; 101import java.util.zip.CRC32; 102import java.util.zip.Checksum; 103 104 105/** 106 * This class provides the API to manage configured 107 * wifi networks. The API is not thread safe is being 108 * used only from WifiStateMachine. 109 * 110 * It deals with the following 111 * - Add/update/remove a WifiConfiguration 112 * The configuration contains two types of information. 113 * = IP and proxy configuration that is handled by WifiConfigManager and 114 * is saved to disk on any change. 115 * 116 * The format of configuration file is as follows: 117 * <version> 118 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 119 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 120 * .. 121 * 122 * (key, value) pairs for a given network are grouped together and can 123 * be in any order. A EOS at the end of a set of (key, value) pairs 124 * indicates that the next set of (key, value) pairs are for a new 125 * network. A network is identified by a unique ID_KEY. If there is no 126 * ID_KEY in the (key, value) pairs, the data is discarded. 127 * 128 * An invalid version on read would result in discarding the contents of 129 * the file. On the next write, the latest version is written to file. 130 * 131 * Any failures during read or write to the configuration file are ignored 132 * without reporting to the user since the likelihood of these errors are 133 * low and the impact on connectivity is low. 134 * 135 * = SSID & security details that is pushed to the supplicant. 136 * supplicant saves these details to the disk on calling 137 * saveConfigCommand(). 138 * 139 * We have two kinds of APIs exposed: 140 * > public API calls that provide fine grained control 141 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 142 * removeNetwork(). For these calls, the config is not persisted 143 * to the disk. (TODO: deprecate these calls in WifiManager) 144 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 145 * These calls persist the supplicant config to disk. 146 * 147 * - Maintain a list of configured networks for quick access 148 * 149 */ 150public class WifiConfigManager { 151 152 private Context mContext; 153 public static final String TAG = "WifiConfigManager"; 154 public static final int MAX_TX_PACKET_FOR_FULL_SCANS = 8; 155 public static final int MAX_RX_PACKET_FOR_FULL_SCANS = 16; 156 public static final int MAX_TX_PACKET_FOR_PARTIAL_SCANS = 40; 157 public static final int MAX_RX_PACKET_FOR_PARTIAL_SCANS = 80; 158 public static final boolean ROAM_ON_ANY = false; 159 public static final int MAX_NUM_SCAN_CACHE_ENTRIES = 128; 160 161 /* Enterprise configuration keys */ 162 /** 163 * In old configurations, the "private_key" field was used. However, newer 164 * configurations use the key_id field with the engine_id set to "keystore". 165 * If this field is found in the configuration, the migration code is 166 * triggered. 167 */ 168 public static final String OLD_PRIVATE_KEY_NAME = "private_key"; 169 170 private static boolean sVDBG = false; 171 private static boolean sVVDBG = false; 172 173 private static final boolean DBG = true; 174 private static final String PPS_FILE = "/data/misc/wifi/PerProviderSubscription.conf"; 175 private static final String IP_CONFIG_FILE = 176 Environment.getDataDirectory() + "/misc/wifi/ipconfig.txt"; 177 178 // The Wifi verbose log is provided as a way to persist the verbose logging settings 179 // for testing purpose. 180 // It is not intended for normal use. 181 private static final String WIFI_VERBOSE_LOGS_KEY = "WIFI_VERBOSE_LOGS"; 182 183 // As we keep deleted PSK WifiConfiguration for a while, the PSK of 184 // those deleted WifiConfiguration is set to this random unused PSK 185 private static final String DELETED_CONFIG_PSK = "Mjkd86jEMGn79KhKll298Uu7-deleted"; 186 187 /** 188 * The maximum number of times we will retry a connection to an access point 189 * for which we have failed in acquiring an IP address from DHCP. A value of 190 * N means that we will make N+1 connection attempts in all. 191 * <p> 192 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 193 * value if a Settings value is not present. 194 */ 195 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 196 197 /** 198 * The threshold for each kind of error. If a network continuously encounter the same error more 199 * than the threshold times, this network will be disabled. -1 means unavailable. 200 */ 201 private static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = { 202 -1, // threshold for NETWORK_SELECTION_ENABLE 203 1, // threshold for DISABLED_BAD_LINK 204 5, // threshold for DISABLED_ASSOCIATION_REJECTION 205 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 206 5, // threshold for DISABLED_DHCP_FAILURE 207 5, // threshold for DISABLED_DNS_FAILURE 208 6, // threshold for DISABLED_TLS_VERSION_MISMATCH 209 1, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 210 1, // threshold for DISABLED_NO_INTERNET 211 1 // threshold for DISABLED_BY_WIFI_MANAGER 212 }; 213 214 /** 215 * Timeout for each kind of error. After the timeout minutes, unblock the network again. 216 */ 217 private static final int[] NETWORK_SELECTION_DISABLE_TIMEOUT = { 218 Integer.MAX_VALUE, // threshold for NETWORK_SELECTION_ENABLE 219 15, // threshold for DISABLED_BAD_LINK 220 5, // threshold for DISABLED_ASSOCIATION_REJECTION 221 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 222 5, // threshold for DISABLED_DHCP_FAILURE 223 5, // threshold for DISABLED_DNS_FAILURE 224 Integer.MAX_VALUE, // threshold for DISABLED_TLS_VERSION 225 Integer.MAX_VALUE, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 226 Integer.MAX_VALUE, // threshold for DISABLED_NO_INTERNET 227 Integer.MAX_VALUE // threshold for DISABLED_BY_WIFI_MANAGER 228 }; 229 230 public final AtomicBoolean mEnableHalBasedPno = new AtomicBoolean(); 231 public final AtomicBoolean mEnableSsidWhitelist = new AtomicBoolean(); 232 public final AtomicBoolean mEnableAutoJoinWhenAssociated = new AtomicBoolean(); 233 public final AtomicBoolean mEnableFullBandScanWhenAssociated = new AtomicBoolean(true); 234 public final AtomicBoolean mEnableChipWakeUpWhenAssociated = new AtomicBoolean(true); 235 public final AtomicBoolean mEnableRssiPollWhenAssociated = new AtomicBoolean(true); 236 public final AtomicInteger mThresholdSaturatedRssi5 = new AtomicInteger(); 237 public final AtomicInteger mThresholdQualifiedRssi24 = new AtomicInteger(); 238 public final AtomicInteger mEnableVerboseLogging = new AtomicInteger(0); 239 public final AtomicInteger mAssociatedFullScanBackoff = 240 new AtomicInteger(); // Will be divided by 8 by WifiStateMachine 241 public final AtomicInteger mAlwaysEnableScansWhileAssociated = new AtomicInteger(0); 242 public final AtomicInteger mMaxNumActiveChannelsForPartialScans = new AtomicInteger(); 243 public final AtomicInteger mWifiDisconnectedShortScanIntervalMs = new AtomicInteger(); 244 public final AtomicInteger mWifiAssociatedShortScanIntervalMs = new AtomicInteger(); 245 246 public boolean mEnableLinkDebouncing; 247 public boolean mEnableWifiCellularHandoverUserTriggeredAdjustment; 248 public int mAssociatedFullScanMaxIntervalMs; 249 public int mNetworkSwitchingBlackListPeriodMs; 250 public int mBadLinkSpeed24; 251 public int mBadLinkSpeed5; 252 public int mGoodLinkSpeed24; 253 public int mGoodLinkSpeed5; 254 255 // These fields are non-final for testing. 256 public AtomicInteger mThresholdQualifiedRssi5 = new AtomicInteger(); 257 public AtomicInteger mThresholdMinimumRssi5 = new AtomicInteger(); 258 public AtomicInteger mThresholdSaturatedRssi24 = new AtomicInteger(); 259 public AtomicInteger mThresholdMinimumRssi24 = new AtomicInteger(); 260 public AtomicInteger mCurrentNetworkBoost = new AtomicInteger(); 261 public AtomicInteger mBandAward5Ghz = new AtomicInteger(); 262 263 /** 264 * If Connectivity Service has triggered an unwanted network disconnect 265 */ 266 public long mLastUnwantedNetworkDisconnectTimestamp = 0; 267 268 /** 269 * Framework keeps a list of ephemeral SSIDs that where deleted by user, 270 * so as, framework knows not to autojoin again those SSIDs based on scorer input. 271 * The list is never cleared up. 272 * 273 * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. 274 */ 275 public Set<String> mDeletedEphemeralSSIDs = new HashSet<String>(); 276 277 /* configured networks with network id as the key */ 278 private final ConfigurationMap mConfiguredNetworks; 279 280 private final LocalLog mLocalLog; 281 private final KeyStore mKeyStore; 282 private final WifiNetworkHistory mWifiNetworkHistory; 283 private final WifiConfigStore mWifiConfigStore; 284 private final AnqpCache mAnqpCache; 285 private final SupplicantBridge mSupplicantBridge; 286 private final SupplicantBridgeCallbacks mSupplicantBridgeCallbacks; 287 private final PasspointManagementObjectManager mMOManager; 288 private final boolean mEnableOsuQueries; 289 private final SIMAccessor mSIMAccessor; 290 291 private WifiStateMachine mWifiStateMachine; 292 private FrameworkFacade mFacade; 293 private Clock mClock; 294 private boolean mOnlyLinkSameCredentialConfigurations; 295 private IpConfigStore mIpconfigStore; 296 private DelayedDiskWrite mWriter; 297 298 /* A network id is a unique identifier for a network configured in the 299 * supplicant. Network ids are generated when the supplicant reads 300 * the configuration file at start and can thus change for networks. 301 * We store the IP configuration for networks along with a unique id 302 * that is generated from SSID and security type of the network. A mapping 303 * from the generated unique id to network id of the network is needed to 304 * map supplicant config to IP configuration. */ 305 306 /* Stores a map of NetworkId to ScanCache */ 307 private ConcurrentHashMap<Integer, ScanDetailCache> mScanDetailCaches; 308 309 /** 310 * Framework keeps a list of (the CRC32 hashes of) all SSIDs that where deleted by user, 311 * so as, framework knows not to re-add those SSIDs automatically to the Saved networks 312 */ 313 private Set<Long> mDeletedSSIDs = new HashSet<Long>(); 314 315 /* Tracks the highest priority of configured networks */ 316 private int mLastPriority = -1; 317 318 // TODO set this back to false, used for debugging b/17516271. 319 private boolean mShowNetworks = true; 320 321 /** 322 * The mLastSelectedConfiguration is used to remember which network 323 * was selected last by the user. 324 * The connection to this network may not be successful, as well 325 * the selection (i.e. network priority) might not be persisted. 326 * WiFi state machine is the only object that sets this variable. 327 */ 328 private String mLastSelectedConfiguration = null; 329 private long mLastSelectedTimeStamp = 330 WifiConfiguration.NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP; 331 332 /* 333 * Lost config list, whenever we read a config from networkHistory.txt that was not in 334 * wpa_supplicant.conf 335 */ 336 private HashSet<String> mLostConfigsDbg = new HashSet<String>(); 337 338 339 private class SupplicantBridgeCallbacks implements SupplicantBridge.SupplicantBridgeCallbacks { 340 @Override 341 public void notifyANQPResponse(ScanDetail scanDetail, 342 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 343 updateAnqpCache(scanDetail, anqpElements); 344 if (anqpElements == null || anqpElements.isEmpty()) { 345 return; 346 } 347 scanDetail.propagateANQPInfo(anqpElements); 348 349 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, false); 350 Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() + " pass 2 matches: " 351 + toMatchString(matches)); 352 353 cacheScanResultForPasspointConfigs(scanDetail, matches, null); 354 } 355 @Override 356 public void notifyIconFailed(long bssid) { 357 Intent intent = new Intent(WifiManager.PASSPOINT_ICON_RECEIVED_ACTION); 358 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 359 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_BSSID, bssid); 360 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 361 } 362 363 } 364 365 WifiConfigManager(Context context, WifiStateMachine wifiStateMachine, WifiNative wifiNative, 366 FrameworkFacade facade, Clock clock, UserManager userManager, KeyStore keyStore) { 367 mContext = context; 368 mFacade = facade; 369 mClock = clock; 370 mWifiStateMachine = wifiStateMachine; 371 mKeyStore = keyStore; 372 373 if (mShowNetworks) { 374 mLocalLog = wifiNative.getLocalLog(); 375 } else { 376 mLocalLog = null; 377 } 378 379 mWifiAssociatedShortScanIntervalMs.set(mContext.getResources().getInteger( 380 R.integer.config_wifi_associated_short_scan_interval)); 381 mWifiDisconnectedShortScanIntervalMs.set(mContext.getResources().getInteger( 382 R.integer.config_wifi_disconnected_short_scan_interval)); 383 mOnlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean( 384 R.bool.config_wifi_only_link_same_credential_configurations); 385 mMaxNumActiveChannelsForPartialScans.set(mContext.getResources().getInteger( 386 R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels)); 387 mAssociatedFullScanMaxIntervalMs = mContext.getResources().getInteger( 388 R.integer.config_wifi_framework_associated_full_scan_max_interval); 389 mAssociatedFullScanBackoff.set(mContext.getResources().getInteger( 390 R.integer.config_wifi_framework_associated_full_scan_backoff)); 391 mEnableLinkDebouncing = mContext.getResources().getBoolean( 392 R.bool.config_wifi_enable_disconnection_debounce); 393 mBandAward5Ghz.set(mContext.getResources().getInteger( 394 R.integer.config_wifi_framework_5GHz_preference_boost_factor)); 395 mThresholdMinimumRssi5.set(mContext.getResources().getInteger( 396 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz)); 397 mThresholdQualifiedRssi5.set(mContext.getResources().getInteger( 398 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz)); 399 mThresholdSaturatedRssi5.set(mContext.getResources().getInteger( 400 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz)); 401 mThresholdMinimumRssi24.set(mContext.getResources().getInteger( 402 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz)); 403 mThresholdQualifiedRssi24.set(mContext.getResources().getInteger( 404 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz)); 405 mThresholdSaturatedRssi24.set(mContext.getResources().getInteger( 406 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)); 407 mEnableWifiCellularHandoverUserTriggeredAdjustment = mContext.getResources().getBoolean( 408 R.bool.config_wifi_framework_cellular_handover_enable_user_triggered_adjustment); 409 mBadLinkSpeed24 = mContext.getResources().getInteger( 410 R.integer.config_wifi_framework_wifi_score_bad_link_speed_24); 411 mBadLinkSpeed5 = mContext.getResources().getInteger( 412 R.integer.config_wifi_framework_wifi_score_bad_link_speed_5); 413 mGoodLinkSpeed24 = mContext.getResources().getInteger( 414 R.integer.config_wifi_framework_wifi_score_good_link_speed_24); 415 mGoodLinkSpeed5 = mContext.getResources().getInteger( 416 R.integer.config_wifi_framework_wifi_score_good_link_speed_5); 417 mEnableAutoJoinWhenAssociated.set(mContext.getResources().getBoolean( 418 R.bool.config_wifi_framework_enable_associated_network_selection)); 419 mCurrentNetworkBoost.set(mContext.getResources().getInteger( 420 R.integer.config_wifi_framework_current_network_boost)); 421 mNetworkSwitchingBlackListPeriodMs = mContext.getResources().getInteger( 422 R.integer.config_wifi_network_switching_blacklist_time); 423 424 mEnableHalBasedPno.set(mContext.getResources().getBoolean( 425 R.bool.config_wifi_hal_pno_enable)); 426 mEnableSsidWhitelist.set(mContext.getResources().getBoolean( 427 R.bool.config_wifi_ssid_white_list_enable)); 428 if (!mEnableHalBasedPno.get() && mEnableSsidWhitelist.get()) { 429 mEnableSsidWhitelist.set(false); 430 } 431 432 boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled); 433 Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled")); 434 435 mConfiguredNetworks = new ConfigurationMap(userManager); 436 mMOManager = new PasspointManagementObjectManager(new File(PPS_FILE), hs2on); 437 mEnableOsuQueries = true; 438 mAnqpCache = new AnqpCache(mClock); 439 mSupplicantBridgeCallbacks = new SupplicantBridgeCallbacks(); 440 mSupplicantBridge = new SupplicantBridge(wifiNative, mSupplicantBridgeCallbacks); 441 mScanDetailCaches = new ConcurrentHashMap<>(16, 0.75f, 2); 442 mSIMAccessor = new SIMAccessor(mContext); 443 mWriter = new DelayedDiskWrite(); 444 mIpconfigStore = new IpConfigStore(mWriter); 445 mWifiNetworkHistory = new WifiNetworkHistory(context, mLocalLog, mWriter); 446 mWifiConfigStore = 447 new WifiConfigStore(wifiNative, mKeyStore, mLocalLog, mShowNetworks, true); 448 } 449 450 public void trimANQPCache(boolean all) { 451 mAnqpCache.clear(all, DBG); 452 } 453 454 void enableVerboseLogging(int verbose) { 455 mEnableVerboseLogging.set(verbose); 456 if (verbose > 0) { 457 sVDBG = true; 458 mShowNetworks = true; 459 } else { 460 sVDBG = false; 461 } 462 if (verbose > 1) { 463 sVVDBG = true; 464 } else { 465 sVVDBG = false; 466 } 467 } 468 469 /** 470 * Fetch the list of configured networks 471 * and enable all stored networks in supplicant. 472 */ 473 void loadAndEnableAllNetworks() { 474 if (DBG) log("Loading config and enabling all networks "); 475 loadConfiguredNetworks(); 476 enableAllNetworks(); 477 } 478 479 int getConfiguredNetworksSize() { 480 return mConfiguredNetworks.sizeForCurrentUser(); 481 } 482 483 private List<WifiConfiguration> getConfiguredNetworks(Map<String, String> pskMap) { 484 List<WifiConfiguration> networks = new ArrayList<>(); 485 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 486 WifiConfiguration newConfig = new WifiConfiguration(config); 487 // When updating this condition, update WifiStateMachine's CONNECT_NETWORK handler to 488 // correctly handle updating existing configs that are filtered out here. 489 if (config.ephemeral) { 490 // Do not enumerate and return this configuration to any one, 491 // for instance WiFi Picker. 492 // instead treat it as unknown. the configuration can still be retrieved 493 // directly by the key or networkId 494 continue; 495 } 496 497 if (pskMap != null && config.allowedKeyManagement != null 498 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 499 && pskMap.containsKey(config.configKey(true))) { 500 newConfig.preSharedKey = pskMap.get(config.configKey(true)); 501 } 502 networks.add(newConfig); 503 } 504 return networks; 505 } 506 507 /** 508 * This function returns all configuration, and is used for cebug and creating bug reports. 509 */ 510 private List<WifiConfiguration> getAllConfiguredNetworks() { 511 List<WifiConfiguration> networks = new ArrayList<>(); 512 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 513 WifiConfiguration newConfig = new WifiConfiguration(config); 514 networks.add(newConfig); 515 } 516 return networks; 517 } 518 519 /** 520 * Fetch the list of currently configured networks 521 * @return List of networks 522 */ 523 public List<WifiConfiguration> getConfiguredNetworks() { 524 return getConfiguredNetworks(null); 525 } 526 527 /** 528 * Fetch the list of currently configured networks, filled with real preSharedKeys 529 * @return List of networks 530 */ 531 List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 532 Map<String, String> pskMap = getCredentialsByConfigKeyMap(); 533 List<WifiConfiguration> configurations = getConfiguredNetworks(pskMap); 534 for (WifiConfiguration configuration : configurations) { 535 try { 536 configuration 537 .setPasspointManagementObjectTree(mMOManager.getMOTree(configuration.FQDN)); 538 } catch (IOException ioe) { 539 Log.w(TAG, "Failed to parse MO from " + configuration.FQDN + ": " + ioe); 540 } 541 } 542 return configurations; 543 } 544 545 /** 546 * Fetch the list of networkId's which are hidden in current user's configuration. 547 * @return List of networkIds 548 */ 549 public Set<Integer> getHiddenConfiguredNetworkIds() { 550 return mConfiguredNetworks.getHiddenNetworkIdsForCurrentUser(); 551 } 552 553 /** 554 * Find matching network for this scanResult 555 */ 556 WifiConfiguration getMatchingConfig(ScanResult scanResult) { 557 558 for (Map.Entry entry : mScanDetailCaches.entrySet()) { 559 Integer netId = (Integer) entry.getKey(); 560 ScanDetailCache cache = (ScanDetailCache) entry.getValue(); 561 WifiConfiguration config = getWifiConfiguration(netId); 562 if (config == null) { 563 continue; 564 } 565 if (cache.get(scanResult.BSSID) != null) { 566 return config; 567 } 568 } 569 570 return null; 571 } 572 573 /** 574 * Fetch the preSharedKeys for all networks. 575 * @return a map from configKey to preSharedKey. 576 */ 577 private Map<String, String> getCredentialsByConfigKeyMap() { 578 return readNetworkVariablesFromSupplicantFile("psk"); 579 } 580 581 /** 582 * Fetch the list of currently configured networks that were recently seen 583 * 584 * @return List of networks 585 */ 586 List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) { 587 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 588 589 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 590 if (config.ephemeral) { 591 // Do not enumerate and return this configuration to any one, 592 // instead treat it as unknown. the configuration can still be retrieved 593 // directly by the key or networkId 594 continue; 595 } 596 597 // Calculate the RSSI for scan results that are more recent than milli 598 ScanDetailCache cache = getScanDetailCache(config); 599 if (cache == null) { 600 continue; 601 } 602 config.setVisibility(cache.getVisibility(milli)); 603 if (config.visibility == null) { 604 continue; 605 } 606 if (config.visibility.rssi5 == WifiConfiguration.INVALID_RSSI 607 && config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { 608 continue; 609 } 610 if (copy) { 611 networks.add(new WifiConfiguration(config)); 612 } else { 613 networks.add(config); 614 } 615 } 616 return networks; 617 } 618 619 /** 620 * Update the configuration and BSSID with latest RSSI value. 621 */ 622 void updateConfiguration(WifiInfo info) { 623 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 624 if (config != null && getScanDetailCache(config) != null) { 625 ScanDetail scanDetail = getScanDetailCache(config).getScanDetail(info.getBSSID()); 626 if (scanDetail != null) { 627 ScanResult result = scanDetail.getScanResult(); 628 long previousSeen = result.seen; 629 int previousRssi = result.level; 630 631 // Update the scan result 632 scanDetail.setSeen(); 633 result.level = info.getRssi(); 634 635 // Average the RSSI value 636 result.averageRssi(previousRssi, previousSeen, 637 WifiQualifiedNetworkSelector.SCAN_RESULT_MAXIMUNM_AGE); 638 if (sVDBG) { 639 loge("updateConfiguration freq=" + result.frequency 640 + " BSSID=" + result.BSSID 641 + " RSSI=" + result.level 642 + " " + config.configKey()); 643 } 644 } 645 } 646 } 647 648 /** 649 * get the Wificonfiguration for this netId 650 * 651 * @return Wificonfiguration 652 */ 653 public WifiConfiguration getWifiConfiguration(int netId) { 654 return mConfiguredNetworks.getForCurrentUser(netId); 655 } 656 657 /** 658 * Get the Wificonfiguration for this key 659 * @return Wificonfiguration 660 */ 661 public WifiConfiguration getWifiConfiguration(String key) { 662 return mConfiguredNetworks.getByConfigKeyForCurrentUser(key); 663 } 664 665 /** 666 * Enable all networks (if disabled time expire) and save config. This will be a no-op if the 667 * list of configured networks indicates all networks as being enabled 668 */ 669 void enableAllNetworks() { 670 boolean networkEnabledStateChanged = false; 671 672 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 673 if (config != null && !config.ephemeral 674 && !config.getNetworkSelectionStatus().isNetworkEnabled()) { 675 if (tryEnableQualifiedNetwork(config)) { 676 networkEnabledStateChanged = true; 677 } 678 } 679 } 680 681 if (networkEnabledStateChanged) { 682 saveConfig(); 683 sendConfiguredNetworksChangedBroadcast(); 684 } 685 } 686 687 /** 688 * Enable a network in wpa_supplicant. 689 */ 690 boolean enableNetworkNative(WifiConfiguration config) { 691 return mWifiConfigStore.enableNetwork(config); 692 } 693 694 /** 695 * Enable all networks in wpa_supplicant. 696 */ 697 void enableAllNetworksNative() { 698 if (mWifiConfigStore.enableAllNetworks(mConfiguredNetworks.valuesForCurrentUser())) { 699 sendConfiguredNetworksChangedBroadcast(); 700 } 701 } 702 703 private boolean setNetworkPriorityNative(WifiConfiguration config, int priority) { 704 return mWifiConfigStore.setNetworkPriority(config, priority); 705 } 706 707 private boolean setSSIDNative(WifiConfiguration config, String ssid) { 708 return mWifiConfigStore.setNetworkSSID(config, ssid); 709 } 710 711 public boolean updateLastConnectUid(WifiConfiguration config, int uid) { 712 if (config != null) { 713 if (config.lastConnectUid != uid) { 714 config.lastConnectUid = uid; 715 return true; 716 } 717 } 718 return false; 719 } 720 721 /** 722 * Selects the specified network for connection. This involves 723 * updating the priority of all the networks and enabling the given 724 * network while disabling others. 725 * 726 * Selecting a network will leave the other networks disabled and 727 * a call to enableAllNetworks() needs to be issued upon a connection 728 * or a failure event from supplicant 729 * 730 * @param config network to select for connection 731 * @param updatePriorities makes config highest priority network 732 * @return false if the network id is invalid 733 */ 734 boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) { 735 if (sVDBG) localLogNetwork("selectNetwork", config.networkId); 736 if (config.networkId == INVALID_NETWORK_ID) return false; 737 if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, 738 mWifiStateMachine.getCurrentUserProfiles())) { 739 loge("selectNetwork " + Integer.toString(config.networkId) + ": Network config is not " 740 + "visible to current user."); 741 return false; 742 } 743 744 // Reset the priority of each network at start or if it goes too high. 745 if (mLastPriority == -1 || mLastPriority > 1000000) { 746 if (updatePriorities) { 747 for (WifiConfiguration config2 : mConfiguredNetworks.valuesForCurrentUser()) { 748 if (config2.networkId != INVALID_NETWORK_ID) { 749 setNetworkPriorityNative(config2, 0); 750 } 751 } 752 } 753 mLastPriority = 0; 754 } 755 756 // Set to the highest priority and save the configuration. 757 if (updatePriorities) { 758 setNetworkPriorityNative(config, ++mLastPriority); 759 } 760 761 if (config.isPasspoint()) { 762 /* need to slap on the SSID of selected bssid to work */ 763 if (getScanDetailCache(config).size() != 0) { 764 ScanDetail result = getScanDetailCache(config).getFirst(); 765 if (result == null) { 766 loge("Could not find scan result for " + config.BSSID); 767 } else { 768 log("Setting SSID for " + config.networkId + " to" + result.getSSID()); 769 setSSIDNative(config, result.getSSID()); 770 } 771 772 } else { 773 loge("Could not find bssid for " + config); 774 } 775 } 776 777 mWifiConfigStore.enableHS20(config.isPasspoint()); 778 779 if (updatePriorities) { 780 saveConfig(); 781 } 782 783 updateLastConnectUid(config, uid); 784 785 writeKnownNetworkHistory(); 786 787 /* Enable the given network while disabling all other networks */ 788 selectNetworkWithoutBroadcast(config.networkId); 789 790 /* Avoid saving the config & sending a broadcast to prevent settings 791 * from displaying a disabled list of networks */ 792 return true; 793 } 794 795 /** 796 * Add/update the specified configuration and save config 797 * 798 * @param config WifiConfiguration to be saved 799 * @return network update result 800 */ 801 NetworkUpdateResult saveNetwork(WifiConfiguration config, int uid) { 802 WifiConfiguration conf; 803 804 // A new network cannot have null SSID 805 if (config == null || (config.networkId == INVALID_NETWORK_ID && config.SSID == null)) { 806 return new NetworkUpdateResult(INVALID_NETWORK_ID); 807 } 808 809 if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, 810 mWifiStateMachine.getCurrentUserProfiles())) { 811 return new NetworkUpdateResult(INVALID_NETWORK_ID); 812 } 813 814 if (sVDBG) localLogNetwork("WifiConfigManager: saveNetwork netId", config.networkId); 815 if (sVDBG) { 816 logd("WifiConfigManager saveNetwork," 817 + " size=" + Integer.toString(mConfiguredNetworks.sizeForAllUsers()) 818 + " (for all users)" 819 + " SSID=" + config.SSID 820 + " Uid=" + Integer.toString(config.creatorUid) 821 + "/" + Integer.toString(config.lastUpdateUid)); 822 } 823 824 if (mDeletedEphemeralSSIDs.remove(config.SSID)) { 825 if (sVDBG) { 826 loge("WifiConfigManager: removed from ephemeral blacklist: " + config.SSID); 827 } 828 // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call 829 // below, since we're creating/modifying a config. 830 } 831 832 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 833 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 834 int netId = result.getNetworkId(); 835 836 if (sVDBG) localLogNetwork("WifiConfigManager: saveNetwork got it back netId=", netId); 837 838 conf = mConfiguredNetworks.getForCurrentUser(netId); 839 if (conf != null) { 840 if (!conf.getNetworkSelectionStatus().isNetworkEnabled()) { 841 if (sVDBG) localLog("WifiConfigManager: re-enabling: " + conf.SSID); 842 843 // reenable autojoin, since new information has been provided 844 updateNetworkSelectionStatus(netId, 845 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 846 } 847 if (sVDBG) { 848 loge("WifiConfigManager: saveNetwork got config back netId=" 849 + Integer.toString(netId) 850 + " uid=" + Integer.toString(config.creatorUid)); 851 } 852 } 853 854 saveConfig(); 855 sendConfiguredNetworksChangedBroadcast( 856 conf, 857 result.isNewNetwork() 858 ? WifiManager.CHANGE_REASON_ADDED 859 : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 860 return result; 861 } 862 863 void noteRoamingFailure(WifiConfiguration config, int reason) { 864 if (config == null) return; 865 config.lastRoamingFailure = System.currentTimeMillis(); 866 config.roamingFailureBlackListTimeMilli = 867 2 * (config.roamingFailureBlackListTimeMilli + 1000); 868 if (config.roamingFailureBlackListTimeMilli > mNetworkSwitchingBlackListPeriodMs) { 869 config.roamingFailureBlackListTimeMilli = mNetworkSwitchingBlackListPeriodMs; 870 } 871 config.lastRoamingFailureReason = reason; 872 } 873 874 void saveWifiConfigBSSID(WifiConfiguration config, String bssid) { 875 mWifiConfigStore.setNetworkBSSID(config, bssid); 876 } 877 878 879 void updateStatus(int netId, DetailedState state) { 880 if (netId != INVALID_NETWORK_ID) { 881 WifiConfiguration config = mConfiguredNetworks.getForAllUsers(netId); 882 if (config == null) return; 883 switch (state) { 884 case CONNECTED: 885 config.status = Status.CURRENT; 886 //we successfully connected, hence remove the blacklist 887 updateNetworkSelectionStatus(netId, 888 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 889 break; 890 case DISCONNECTED: 891 //If network is already disabled, keep the status 892 if (config.status == Status.CURRENT) { 893 config.status = Status.ENABLED; 894 } 895 break; 896 default: 897 //do nothing, retain the existing state 898 break; 899 } 900 } 901 } 902 903 904 /** 905 * Disable an ephemeral SSID for the purpose of auto-joining thru scored. 906 * This SSID will never be scored anymore. 907 * The only way to "un-disable it" is if the user create a network for that SSID and then 908 * forget it. 909 * 910 * @param ssid caller must ensure that the SSID passed thru this API match 911 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 912 * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can 913 * disconnect if this is the current network. 914 */ 915 WifiConfiguration disableEphemeralNetwork(String ssid) { 916 if (ssid == null) { 917 return null; 918 } 919 920 WifiConfiguration foundConfig = mConfiguredNetworks.getEphemeralForCurrentUser(ssid); 921 922 mDeletedEphemeralSSIDs.add(ssid); 923 loge("Forget ephemeral SSID " + ssid + " num=" + mDeletedEphemeralSSIDs.size()); 924 925 if (foundConfig != null) { 926 loge("Found ephemeral config in disableEphemeralNetwork: " + foundConfig.networkId); 927 } 928 929 writeKnownNetworkHistory(); 930 return foundConfig; 931 } 932 933 /** 934 * Forget the specified network and save config 935 * 936 * @param netId network to forget 937 * @return {@code true} if it succeeds, {@code false} otherwise 938 */ 939 boolean forgetNetwork(int netId) { 940 if (mShowNetworks) localLogNetwork("forgetNetwork", netId); 941 if (!removeNetwork(netId)) { 942 loge("Failed to forget network " + netId); 943 return false; 944 } 945 saveConfig(); 946 writeKnownNetworkHistory(); 947 return true; 948 } 949 950 /** 951 * Add/update a network. Note that there is no saveConfig operation. 952 * This function is retained for compatibility with the public 953 * API. The more powerful saveNetwork() is used by the 954 * state machine 955 * 956 * @param config wifi configuration to add/update 957 * @return network Id 958 */ 959 int addOrUpdateNetwork(WifiConfiguration config, int uid) { 960 if (config == null || !WifiConfigurationUtil.isVisibleToAnyProfile(config, 961 mWifiStateMachine.getCurrentUserProfiles())) { 962 return WifiConfiguration.INVALID_NETWORK_ID; 963 } 964 965 if (mShowNetworks) localLogNetwork("addOrUpdateNetwork id=", config.networkId); 966 if (config.isPasspoint()) { 967 /* create a temporary SSID with providerFriendlyName */ 968 Long csum = getChecksum(config.FQDN); 969 config.SSID = csum.toString(); 970 config.enterpriseConfig.setDomainSuffixMatch(config.FQDN); 971 } 972 973 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 974 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 975 WifiConfiguration conf = mConfiguredNetworks.getForCurrentUser(result.getNetworkId()); 976 if (conf != null) { 977 sendConfiguredNetworksChangedBroadcast( 978 conf, 979 result.isNewNetwork 980 ? WifiManager.CHANGE_REASON_ADDED 981 : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 982 } 983 } 984 985 return result.getNetworkId(); 986 } 987 988 public int addPasspointManagementObject(String managementObject) { 989 try { 990 mMOManager.addSP(managementObject); 991 return 0; 992 } catch (IOException | SAXException e) { 993 return -1; 994 } 995 } 996 997 public int modifyPasspointMo(String fqdn, List<PasspointManagementObjectDefinition> mos) { 998 try { 999 return mMOManager.modifySP(fqdn, mos); 1000 } catch (IOException | SAXException e) { 1001 return -1; 1002 } 1003 } 1004 1005 public boolean queryPasspointIcon(long bssid, String fileName) { 1006 return mSupplicantBridge.doIconQuery(bssid, fileName); 1007 } 1008 1009 public int matchProviderWithCurrentNetwork(String fqdn) { 1010 ScanDetail scanDetail = mWifiStateMachine.getActiveScanDetail(); 1011 if (scanDetail == null) { 1012 return PasspointMatch.None.ordinal(); 1013 } 1014 HomeSP homeSP = mMOManager.getHomeSP(fqdn); 1015 if (homeSP == null) { 1016 return PasspointMatch.None.ordinal(); 1017 } 1018 1019 ANQPData anqpData = mAnqpCache.getEntry(scanDetail.getNetworkDetail()); 1020 1021 Map<Constants.ANQPElementType, ANQPElement> anqpElements = 1022 anqpData != null ? anqpData.getANQPElements() : null; 1023 1024 return homeSP.match(scanDetail.getNetworkDetail(), anqpElements, mSIMAccessor).ordinal(); 1025 } 1026 1027 /** 1028 * General PnoNetwork list sorting algorithm: 1029 * 1, Place the fully enabled networks first. Among the fully enabled networks, 1030 * sort them in the oder determined by the return of |compareConfigurations| method 1031 * implementation. 1032 * 2. Next place all the temporarily disabled networks. Among the temporarily disabled 1033 * networks, sort them in the order determined by the return of |compareConfigurations| method 1034 * implementation. 1035 * 3. Place the permanently disabled networks last. The order among permanently disabled 1036 * networks doesn't matter. 1037 */ 1038 private static class PnoListComparator implements Comparator<WifiConfiguration> { 1039 1040 public final int ENABLED_NETWORK_SCORE = 3; 1041 public final int TEMPORARY_DISABLED_NETWORK_SCORE = 2; 1042 public final int PERMANENTLY_DISABLED_NETWORK_SCORE = 1; 1043 1044 @Override 1045 public int compare(WifiConfiguration a, WifiConfiguration b) { 1046 int configAScore = getPnoNetworkSortScore(a); 1047 int configBScore = getPnoNetworkSortScore(b); 1048 if (configAScore == configBScore) { 1049 return compareConfigurations(a, b); 1050 } else { 1051 return Integer.compare(configBScore, configAScore); 1052 } 1053 } 1054 1055 // This needs to be implemented by the connected/disconnected PNO list comparator. 1056 public int compareConfigurations(WifiConfiguration a, WifiConfiguration b) { 1057 return 0; 1058 } 1059 1060 /** 1061 * Returns an integer representing a score for each configuration. The scores are assigned 1062 * based on the status of the configuration. The scores are assigned according to the order: 1063 * Fully enabled network > Temporarily disabled network > Permanently disabled network. 1064 */ 1065 private int getPnoNetworkSortScore(WifiConfiguration config) { 1066 if (config.getNetworkSelectionStatus().isNetworkEnabled()) { 1067 return ENABLED_NETWORK_SCORE; 1068 } else if (config.getNetworkSelectionStatus().isNetworkTemporaryDisabled()) { 1069 return TEMPORARY_DISABLED_NETWORK_SCORE; 1070 } else { 1071 return PERMANENTLY_DISABLED_NETWORK_SCORE; 1072 } 1073 } 1074 } 1075 1076 /** 1077 * Disconnected PnoNetwork list sorting algorithm: 1078 * Place the configurations in descending order of their |numAssociation| values. If networks 1079 * have the same |numAssociation|, then sort them in descending order of their |priority| 1080 * values. 1081 */ 1082 private static final PnoListComparator sDisconnectedPnoListComparator = 1083 new PnoListComparator() { 1084 @Override 1085 public int compareConfigurations(WifiConfiguration a, WifiConfiguration b) { 1086 if (a.numAssociation != b.numAssociation) { 1087 return Long.compare(b.numAssociation, a.numAssociation); 1088 } else { 1089 return Integer.compare(b.priority, a.priority); 1090 } 1091 } 1092 }; 1093 1094 /** 1095 * Retrieves an updated list of priorities for all the saved networks before 1096 * enabling disconnected PNO (wpa_supplicant based PNO). 1097 * 1098 * @return list of networks with updated priorities. 1099 */ 1100 public ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrieveDisconnectedPnoNetworkList() { 1101 return retrievePnoNetworkList(true, sDisconnectedPnoListComparator); 1102 } 1103 1104 /** 1105 * Retrieves an updated list of priorities for all the saved networks before 1106 * enabling/disabling disconnected PNO (wpa_supplicant based PNO). 1107 * 1108 * wpa_supplicant uses the priority of networks to build the list of SSID's to monitor 1109 * during PNO. If there are a lot of saved networks, this list will be truncated and we 1110 * might end up not connecting to the networks we use most frequently. So, We want the networks 1111 * to be re-sorted based on the relative |numAssociation| values. 1112 * 1113 * @param enablePno boolean indicating whether PNO is being enabled or disabled. 1114 * @return list of networks with updated priorities. 1115 */ 1116 public ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrieveDisconnectedPnoNetworkList( 1117 boolean enablePno) { 1118 return retrievePnoNetworkList(enablePno, sDisconnectedPnoListComparator); 1119 } 1120 1121 /** 1122 * Connected PnoNetwork list sorting algorithm: 1123 * Place the configurations with |lastSeenInQualifiedNetworkSelection| set first. If networks 1124 * have the same value, then sort them in descending order of their |numAssociation| 1125 * values. 1126 */ 1127 private static final PnoListComparator sConnectedPnoListComparator = 1128 new PnoListComparator() { 1129 @Override 1130 public int compareConfigurations(WifiConfiguration a, WifiConfiguration b) { 1131 boolean isConfigALastSeen = 1132 a.getNetworkSelectionStatus().getSeenInLastQualifiedNetworkSelection(); 1133 boolean isConfigBLastSeen = 1134 b.getNetworkSelectionStatus().getSeenInLastQualifiedNetworkSelection(); 1135 if (isConfigALastSeen != isConfigBLastSeen) { 1136 return Boolean.compare(isConfigBLastSeen, isConfigALastSeen); 1137 } else { 1138 return Long.compare(b.numAssociation, a.numAssociation); 1139 } 1140 } 1141 }; 1142 1143 /** 1144 * Retrieves an updated list of priorities for all the saved networks before 1145 * enabling connected PNO (HAL based ePno). 1146 * 1147 * @return list of networks with updated priorities. 1148 */ 1149 public ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrieveConnectedPnoNetworkList() { 1150 return retrievePnoNetworkList(true, sConnectedPnoListComparator); 1151 } 1152 1153 /** 1154 * Create a PnoNetwork object from the provided WifiConfiguration. 1155 * @param config Configuration corresponding to the network. 1156 * @param newPriority New priority to be assigned to the network. 1157 */ 1158 private static WifiScanner.PnoSettings.PnoNetwork createPnoNetworkFromWifiConfiguration( 1159 WifiConfiguration config, int newPriority) { 1160 WifiScanner.PnoSettings.PnoNetwork pnoNetwork = 1161 new WifiScanner.PnoSettings.PnoNetwork(config.SSID); 1162 pnoNetwork.networkId = config.networkId; 1163 pnoNetwork.priority = newPriority; 1164 if (config.hiddenSSID) { 1165 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN; 1166 } 1167 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_A_BAND; 1168 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_G_BAND; 1169 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 1170 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_PSK; 1171 } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) 1172 || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) { 1173 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_EAPOL; 1174 } else { 1175 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_OPEN; 1176 } 1177 return pnoNetwork; 1178 } 1179 1180 /** 1181 * Retrieves an updated list of priorities for all the saved networks before 1182 * enabling/disabling PNO. 1183 * 1184 * @param enablePno boolean indicating whether PNO is being enabled or disabled. 1185 * @return list of networks with updated priorities. 1186 */ 1187 private ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrievePnoNetworkList( 1188 boolean enablePno, PnoListComparator pnoListComparator) { 1189 ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoList = new ArrayList<>(); 1190 ArrayList<WifiConfiguration> wifiConfigurations = 1191 new ArrayList<>(mConfiguredNetworks.valuesForCurrentUser()); 1192 if (enablePno) { 1193 Collections.sort(wifiConfigurations, pnoListComparator); 1194 // Let's use the network list size as the highest priority and then go down from there. 1195 // So, the most frequently connected network has the highest priority now. 1196 int priority = wifiConfigurations.size(); 1197 if (DBG) { 1198 Log.d(TAG, "Retrieve network priorities before PNO. Max priority: " + priority); 1199 } 1200 for (WifiConfiguration config : wifiConfigurations) { 1201 pnoList.add(createPnoNetworkFromWifiConfiguration(config, priority)); 1202 priority--; 1203 } 1204 } else { 1205 // Revert the priorities back to the saved config values after PNO. 1206 if (DBG) Log.d(TAG, "Retrieve network priorities after PNO."); 1207 for (WifiConfiguration config : wifiConfigurations) { 1208 pnoList.add(createPnoNetworkFromWifiConfiguration(config, config.priority)); 1209 } 1210 } 1211 return pnoList; 1212 } 1213 1214 /** 1215 * Remove a network. Note that there is no saveConfig operation. 1216 * This function is retained for compatibility with the public 1217 * API. The more powerful forgetNetwork() is used by the 1218 * state machine for network removal 1219 * 1220 * @param netId network to be removed 1221 * @return {@code true} if it succeeds, {@code false} otherwise 1222 */ 1223 boolean removeNetwork(int netId) { 1224 if (mShowNetworks) localLogNetwork("removeNetwork", netId); 1225 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1226 if (!removeConfigAndSendBroadcastIfNeeded(config)) { 1227 return false; 1228 } 1229 if (config.isPasspoint()) { 1230 writePasspointConfigs(config.FQDN, null); 1231 } 1232 return true; 1233 } 1234 1235 private static Long getChecksum(String source) { 1236 Checksum csum = new CRC32(); 1237 csum.update(source.getBytes(), 0, source.getBytes().length); 1238 return csum.getValue(); 1239 } 1240 1241 private boolean removeConfigWithoutBroadcast(WifiConfiguration config) { 1242 if (config == null) { 1243 return false; 1244 } 1245 if (!mWifiConfigStore.removeNetwork(config)) { 1246 loge("Failed to remove network " + config.networkId); 1247 return false; 1248 } 1249 if (config.configKey().equals(mLastSelectedConfiguration)) { 1250 mLastSelectedConfiguration = null; 1251 } 1252 mConfiguredNetworks.remove(config.networkId); 1253 mScanDetailCaches.remove(config.networkId); 1254 return true; 1255 } 1256 1257 private boolean removeConfigAndSendBroadcastIfNeeded(WifiConfiguration config) { 1258 if (!removeConfigWithoutBroadcast(config)) { 1259 return false; 1260 } 1261 String key = config.configKey(); 1262 if (sVDBG) { 1263 logd("removeNetwork " + " key=" + key + " config.id=" + config.networkId); 1264 } 1265 if (config.selfAdded || config.linkedConfigurations != null 1266 || config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1267 if (!TextUtils.isEmpty(config.SSID)) { 1268 /* Remember that we deleted this PSK SSID */ 1269 if (config.SSID != null) { 1270 Long csum = getChecksum(config.SSID); 1271 mDeletedSSIDs.add(csum); 1272 logd("removeNetwork " 1273 + " key=" + key 1274 + " config.id=" + config.networkId 1275 + " crc=" + csum); 1276 } else { 1277 logd("removeNetwork " 1278 + " key=" + key 1279 + " config.id=" + config.networkId); 1280 } 1281 } 1282 } 1283 writeIpAndProxyConfigurations(); 1284 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 1285 if (!config.ephemeral) { 1286 removeUserSelectionPreference(key); 1287 } 1288 writeKnownNetworkHistory(); 1289 return true; 1290 } 1291 1292 private void removeUserSelectionPreference(String configKey) { 1293 if (DBG) { 1294 Log.d(TAG, "removeUserSelectionPreference: key is " + configKey); 1295 } 1296 if (configKey == null) { 1297 return; 1298 } 1299 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 1300 WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 1301 String connectChoice = status.getConnectChoice(); 1302 if (connectChoice != null && connectChoice.equals(configKey)) { 1303 Log.d(TAG, "remove connect choice:" + connectChoice + " from " + config.SSID 1304 + " : " + config.networkId); 1305 status.setConnectChoice(null); 1306 status.setConnectChoiceTimestamp(WifiConfiguration.NetworkSelectionStatus 1307 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1308 } 1309 } 1310 } 1311 1312 /* 1313 * Remove all networks associated with an application 1314 * 1315 * @param packageName name of the package of networks to remove 1316 * @return {@code true} if all networks removed successfully, {@code false} otherwise 1317 */ 1318 boolean removeNetworksForApp(ApplicationInfo app) { 1319 if (app == null || app.packageName == null) { 1320 return false; 1321 } 1322 1323 boolean success = true; 1324 1325 WifiConfiguration [] copiedConfigs = 1326 mConfiguredNetworks.valuesForCurrentUser().toArray(new WifiConfiguration[0]); 1327 for (WifiConfiguration config : copiedConfigs) { 1328 if (app.uid != config.creatorUid || !app.packageName.equals(config.creatorName)) { 1329 continue; 1330 } 1331 if (mShowNetworks) { 1332 localLog("Removing network " + config.SSID 1333 + ", application \"" + app.packageName + "\" uninstalled" 1334 + " from user " + UserHandle.getUserId(app.uid)); 1335 } 1336 success &= removeNetwork(config.networkId); 1337 } 1338 1339 saveConfig(); 1340 1341 return success; 1342 } 1343 1344 boolean removeNetworksForUser(int userId) { 1345 boolean success = true; 1346 1347 WifiConfiguration[] copiedConfigs = 1348 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1349 for (WifiConfiguration config : copiedConfigs) { 1350 if (userId != UserHandle.getUserId(config.creatorUid)) { 1351 continue; 1352 } 1353 success &= removeNetwork(config.networkId); 1354 if (mShowNetworks) { 1355 localLog("Removing network " + config.SSID 1356 + ", user " + userId + " removed"); 1357 } 1358 } 1359 1360 return success; 1361 } 1362 1363 /** 1364 * Enable a network. Note that there is no saveConfig operation. 1365 * This function is retained for compatibility with the public 1366 * API. The more powerful selectNetwork()/saveNetwork() is used by the 1367 * state machine for connecting to a network 1368 * 1369 * @param netId network to be enabled 1370 * @return {@code true} if it succeeds, {@code false} otherwise 1371 */ 1372 boolean enableNetwork(int netId, boolean disableOthers, int uid) { 1373 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1374 if (config == null) { 1375 return false; 1376 } 1377 boolean ret = true; 1378 if (disableOthers) { 1379 ret = selectNetworkWithoutBroadcast(netId); 1380 if (sVDBG) { 1381 localLogNetwork("enableNetwork(disableOthers=true, uid=" + uid + ") ", netId); 1382 } 1383 updateLastConnectUid(getWifiConfiguration(netId), uid); 1384 1385 writeKnownNetworkHistory(); 1386 sendConfiguredNetworksChangedBroadcast(); 1387 } else { 1388 if (sVDBG) localLogNetwork("enableNetwork(disableOthers=false) ", netId); 1389 WifiConfiguration enabledNetwork; 1390 synchronized (mConfiguredNetworks) { // !!! Useless synchronization! 1391 enabledNetwork = mConfiguredNetworks.getForCurrentUser(netId); 1392 } 1393 // check just in case the network was removed by someone else. 1394 if (enabledNetwork != null) { 1395 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 1396 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1397 } 1398 } 1399 return ret; 1400 } 1401 1402 boolean selectNetworkWithoutBroadcast(int netId) { 1403 return mWifiConfigStore.selectNetwork( 1404 mConfiguredNetworks.getForCurrentUser(netId), 1405 mConfiguredNetworks.valuesForCurrentUser()); 1406 } 1407 1408 /** 1409 * Disable a network in wpa_supplicant. 1410 */ 1411 boolean disableNetworkNative(WifiConfiguration config) { 1412 return mWifiConfigStore.disableNetwork(config); 1413 } 1414 1415 /** 1416 * Disable all networks in wpa_supplicant. 1417 */ 1418 void disableAllNetworksNative() { 1419 mWifiConfigStore.disableAllNetworks(mConfiguredNetworks.valuesForCurrentUser()); 1420 } 1421 1422 /** 1423 * Disable a network. Note that there is no saveConfig operation. 1424 * @param netId network to be disabled 1425 * @return {@code true} if it succeeds, {@code false} otherwise 1426 */ 1427 boolean disableNetwork(int netId) { 1428 return mWifiConfigStore.disableNetwork(mConfiguredNetworks.getForCurrentUser(netId)); 1429 } 1430 1431 /** 1432 * Update a network according to the update reason and its current state 1433 * @param netId The network ID of the network need update 1434 * @param reason The reason to update the network 1435 * @return false if no change made to the input configure file, can due to error or need not 1436 * true the input config file has been changed 1437 */ 1438 boolean updateNetworkSelectionStatus(int netId, int reason) { 1439 WifiConfiguration config = getWifiConfiguration(netId); 1440 return updateNetworkSelectionStatus(config, reason); 1441 } 1442 1443 /** 1444 * Update a network according to the update reason and its current state 1445 * @param config the network need update 1446 * @param reason The reason to update the network 1447 * @return false if no change made to the input configure file, can due to error or need not 1448 * true the input config file has been changed 1449 */ 1450 boolean updateNetworkSelectionStatus(WifiConfiguration config, int reason) { 1451 if (config == null) { 1452 return false; 1453 } 1454 1455 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1456 if (reason == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1457 updateNetworkStatus(config, WifiConfiguration.NetworkSelectionStatus 1458 .NETWORK_SELECTION_ENABLE); 1459 localLog("Enable network:" + config.configKey()); 1460 return true; 1461 } 1462 1463 networkStatus.incrementDisableReasonCounter(reason); 1464 if (DBG) { 1465 localLog("Network:" + config.SSID + "disable counter of " 1466 + WifiConfiguration.NetworkSelectionStatus.getNetworkDisableReasonString(reason) 1467 + " is: " + networkStatus.getDisableReasonCounter(reason) + "and threshold is: " 1468 + NETWORK_SELECTION_DISABLE_THRESHOLD[reason]); 1469 } 1470 1471 if (networkStatus.getDisableReasonCounter(reason) 1472 >= NETWORK_SELECTION_DISABLE_THRESHOLD[reason]) { 1473 return updateNetworkStatus(config, reason); 1474 } 1475 return true; 1476 } 1477 1478 /** 1479 * Check the config. If it is temporarily disabled, check the disable time is expired or not, If 1480 * expired, enabled it again for qualified network selection. 1481 * @param networkId the id of the network to be checked for possible unblock (due to timeout) 1482 * @return true if network status has been changed 1483 * false network status is not changed 1484 */ 1485 boolean tryEnableQualifiedNetwork(int networkId) { 1486 WifiConfiguration config = getWifiConfiguration(networkId); 1487 if (config == null) { 1488 localLog("updateQualifiedNetworkstatus invalid network."); 1489 return false; 1490 } 1491 return tryEnableQualifiedNetwork(config); 1492 } 1493 1494 /** 1495 * Check the config. If it is temporarily disabled, check the disable is expired or not, If 1496 * expired, enabled it again for qualified network selection. 1497 * @param config network to be checked for possible unblock (due to timeout) 1498 * @return true if network status has been changed 1499 * false network status is not changed 1500 */ 1501 boolean tryEnableQualifiedNetwork(WifiConfiguration config) { 1502 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1503 if (networkStatus.isNetworkTemporaryDisabled()) { 1504 //time difference in minutes 1505 long timeDifference = (System.currentTimeMillis() 1506 - networkStatus.getDisableTime()) / 1000 / 60; 1507 if (timeDifference < 0 || timeDifference 1508 >= NETWORK_SELECTION_DISABLE_TIMEOUT[ 1509 networkStatus.getNetworkSelectionDisableReason()]) { 1510 updateNetworkSelectionStatus(config.networkId, 1511 networkStatus.NETWORK_SELECTION_ENABLE); 1512 return true; 1513 } 1514 } 1515 return false; 1516 } 1517 1518 /** 1519 * Update a network's status. Note that there is no saveConfig operation. 1520 * @param config network to be updated 1521 * @param reason reason code for updated 1522 * @return false if no change made to the input configure file, can due to error or need not 1523 * true the input config file has been changed 1524 */ 1525 boolean updateNetworkStatus(WifiConfiguration config, int reason) { 1526 localLog("updateNetworkStatus:" + (config == null ? null : config.SSID)); 1527 if (config == null) { 1528 return false; 1529 } 1530 1531 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1532 if (reason < 0 || reason >= WifiConfiguration.NetworkSelectionStatus 1533 .NETWORK_SELECTION_DISABLED_MAX) { 1534 localLog("Invalid Network disable reason:" + reason); 1535 return false; 1536 } 1537 1538 if (reason == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1539 if (networkStatus.isNetworkEnabled()) { 1540 if (DBG) { 1541 localLog("Need not change Qualified network Selection status since" 1542 + " already enabled"); 1543 } 1544 return false; 1545 } 1546 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1547 .NETWORK_SELECTION_ENABLED); 1548 networkStatus.setNetworkSelectionDisableReason(reason); 1549 networkStatus.setDisableTime( 1550 WifiConfiguration.NetworkSelectionStatus 1551 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1552 networkStatus.clearDisableReasonCounter(); 1553 String disableTime = DateFormat.getDateTimeInstance().format(new Date()); 1554 if (DBG) { 1555 localLog("Re-enable network: " + config.SSID + " at " + disableTime); 1556 } 1557 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1558 } else { 1559 //disable the network 1560 if (networkStatus.isNetworkPermanentlyDisabled()) { 1561 //alreay permanent disable 1562 if (DBG) { 1563 localLog("Do nothing. Alreay permanent disabled! " 1564 + WifiConfiguration.NetworkSelectionStatus 1565 .getNetworkDisableReasonString(reason)); 1566 } 1567 return false; 1568 } else if (networkStatus.isNetworkTemporaryDisabled() 1569 && reason < WifiConfiguration.NetworkSelectionStatus 1570 .DISABLED_TLS_VERSION_MISMATCH) { 1571 //alreay temporarily disable 1572 if (DBG) { 1573 localLog("Do nothing. Already temporarily disabled! " 1574 + WifiConfiguration.NetworkSelectionStatus 1575 .getNetworkDisableReasonString(reason)); 1576 } 1577 return false; 1578 } 1579 1580 if (networkStatus.isNetworkEnabled()) { 1581 disableNetworkNative(config); 1582 sendConfiguredNetworksChangedBroadcast(config, 1583 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1584 localLog("Disable network " + config.SSID + " reason:" 1585 + WifiConfiguration.NetworkSelectionStatus 1586 .getNetworkDisableReasonString(reason)); 1587 } 1588 if (reason < WifiConfiguration.NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) { 1589 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1590 .NETWORK_SELECTION_TEMPORARY_DISABLED); 1591 networkStatus.setDisableTime(System.currentTimeMillis()); 1592 } else { 1593 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1594 .NETWORK_SELECTION_PERMANENTLY_DISABLED); 1595 } 1596 networkStatus.setNetworkSelectionDisableReason(reason); 1597 if (DBG) { 1598 String disableTime = DateFormat.getDateTimeInstance().format(new Date()); 1599 localLog("Network:" + config.SSID + "Configure new status:" 1600 + networkStatus.getNetworkStatusString() + " with reason:" 1601 + networkStatus.getNetworkDisableReasonString() + " at: " + disableTime); 1602 } 1603 } 1604 return true; 1605 } 1606 1607 /** 1608 * Save the configured networks in supplicant to disk 1609 * @return {@code true} if it succeeds, {@code false} otherwise 1610 */ 1611 boolean saveConfig() { 1612 return mWifiConfigStore.saveConfig(); 1613 } 1614 1615 /** 1616 * Start WPS pin method configuration with pin obtained 1617 * from the access point 1618 * @param config WPS configuration 1619 * @return Wps result containing status and pin 1620 */ 1621 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 1622 return mWifiConfigStore.startWpsWithPinFromAccessPoint( 1623 config, mConfiguredNetworks.valuesForCurrentUser()); 1624 } 1625 1626 /** 1627 * Start WPS pin method configuration with obtained 1628 * from the device 1629 * @return WpsResult indicating status and pin 1630 */ 1631 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 1632 return mWifiConfigStore.startWpsWithPinFromDevice( 1633 config, mConfiguredNetworks.valuesForCurrentUser()); 1634 } 1635 1636 /** 1637 * Start WPS push button configuration 1638 * @param config WPS configuration 1639 * @return WpsResult indicating status and pin 1640 */ 1641 WpsResult startWpsPbc(WpsInfo config) { 1642 return mWifiConfigStore.startWpsPbc( 1643 config, mConfiguredNetworks.valuesForCurrentUser()); 1644 } 1645 1646 /** 1647 * Fetch the static IP configuration for a given network id 1648 */ 1649 StaticIpConfiguration getStaticIpConfiguration(int netId) { 1650 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1651 if (config != null) { 1652 return config.getStaticIpConfiguration(); 1653 } 1654 return null; 1655 } 1656 1657 /** 1658 * Set the static IP configuration for a given network id 1659 */ 1660 void setStaticIpConfiguration(int netId, StaticIpConfiguration staticIpConfiguration) { 1661 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1662 if (config != null) { 1663 config.setStaticIpConfiguration(staticIpConfiguration); 1664 } 1665 } 1666 1667 /** 1668 * set default GW MAC address 1669 */ 1670 void setDefaultGwMacAddress(int netId, String macAddress) { 1671 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1672 if (config != null) { 1673 //update defaultGwMacAddress 1674 config.defaultGwMacAddress = macAddress; 1675 } 1676 } 1677 1678 1679 /** 1680 * Fetch the proxy properties for a given network id 1681 * @param netId id 1682 * @return ProxyInfo for the network id 1683 */ 1684 ProxyInfo getProxyProperties(int netId) { 1685 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1686 if (config != null) { 1687 return config.getHttpProxy(); 1688 } 1689 return null; 1690 } 1691 1692 /** 1693 * Return if the specified network is using static IP 1694 * @param netId id 1695 * @return {@code true} if using static ip for netId 1696 */ 1697 boolean isUsingStaticIp(int netId) { 1698 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1699 if (config != null && config.getIpAssignment() == IpAssignment.STATIC) { 1700 return true; 1701 } 1702 return false; 1703 } 1704 1705 boolean isEphemeral(int netId) { 1706 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1707 return config != null && config.ephemeral; 1708 } 1709 1710 boolean getMeteredHint(int netId) { 1711 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1712 return config != null && config.meteredHint; 1713 } 1714 1715 /** 1716 * Should be called when a single network configuration is made. 1717 * @param network The network configuration that changed. 1718 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 1719 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 1720 */ 1721 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 1722 int reason) { 1723 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1724 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1725 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 1726 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 1727 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 1728 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1729 } 1730 1731 /** 1732 * Should be called when multiple network configuration changes are made. 1733 */ 1734 private void sendConfiguredNetworksChangedBroadcast() { 1735 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1736 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1737 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 1738 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1739 } 1740 1741 void loadConfiguredNetworks() { 1742 1743 final Map<String, WifiConfiguration> configs = new HashMap<>(); 1744 final SparseArray<Map<String, String>> networkExtras = new SparseArray<>(); 1745 mLastPriority = mWifiConfigStore.loadNetworks(configs, networkExtras); 1746 1747 readNetworkHistory(configs); 1748 readPasspointConfig(configs, networkExtras); 1749 1750 // We are only now updating mConfiguredNetworks for two reasons: 1751 // 1) The information required to compute configKeys is spread across wpa_supplicant.conf 1752 // and networkHistory.txt. Thus, we had to load both files first. 1753 // 2) mConfiguredNetworks caches a Passpoint network's FQDN the moment the network is added. 1754 // Thus, we had to load the FQDNs first. 1755 mConfiguredNetworks.clear(); 1756 for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) { 1757 final String configKey = entry.getKey(); 1758 final WifiConfiguration config = entry.getValue(); 1759 if (!configKey.equals(config.configKey())) { 1760 if (mShowNetworks) { 1761 log("Ignoring network " + config.networkId + " because the configKey loaded " 1762 + "from wpa_supplicant.conf is not valid."); 1763 } 1764 mWifiConfigStore.removeNetwork(config); 1765 continue; 1766 } 1767 mConfiguredNetworks.put(config); 1768 } 1769 1770 readIpAndProxyConfigurations(); 1771 1772 sendConfiguredNetworksChangedBroadcast(); 1773 1774 if (mShowNetworks) { 1775 localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.sizeForAllUsers() 1776 + " networks (for all users)"); 1777 } 1778 1779 if (mConfiguredNetworks.sizeForAllUsers() == 0) { 1780 // no networks? Lets log if the file contents 1781 logKernelTime(); 1782 logContents(WifiConfigStore.SUPPLICANT_CONFIG_FILE); 1783 logContents(WifiConfigStore.SUPPLICANT_CONFIG_FILE_BACKUP); 1784 logContents(WifiNetworkHistory.NETWORK_HISTORY_CONFIG_FILE); 1785 } 1786 } 1787 1788 private void logContents(String file) { 1789 localLogAndLogcat("--- Begin " + file + " ---"); 1790 BufferedReader reader = null; 1791 try { 1792 reader = new BufferedReader(new FileReader(file)); 1793 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 1794 localLogAndLogcat(line); 1795 } 1796 } catch (FileNotFoundException e) { 1797 localLog("Could not open " + file + ", " + e); 1798 Log.w(TAG, "Could not open " + file + ", " + e); 1799 } catch (IOException e) { 1800 localLog("Could not read " + file + ", " + e); 1801 Log.w(TAG, "Could not read " + file + ", " + e); 1802 } finally { 1803 try { 1804 if (reader != null) { 1805 reader.close(); 1806 } 1807 } catch (IOException e) { 1808 // Just ignore the fact that we couldn't close 1809 } 1810 } 1811 localLogAndLogcat("--- End " + file + " Contents ---"); 1812 } 1813 1814 private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) { 1815 return mWifiConfigStore.readNetworkVariablesFromSupplicantFile(key); 1816 } 1817 1818 private String readNetworkVariableFromSupplicantFile(String configKey, String key) { 1819 long start = SystemClock.elapsedRealtimeNanos(); 1820 Map<String, String> data = mWifiConfigStore.readNetworkVariablesFromSupplicantFile(key); 1821 long end = SystemClock.elapsedRealtimeNanos(); 1822 1823 if (sVDBG) { 1824 localLog("readNetworkVariableFromSupplicantFile configKey=[" + configKey + "] key=" 1825 + key + " duration=" + (long) (end - start)); 1826 } 1827 return data.get(configKey); 1828 } 1829 1830 boolean needsUnlockedKeyStore() { 1831 1832 // Any network using certificates to authenticate access requires 1833 // unlocked key store; unless the certificates can be stored with 1834 // hardware encryption 1835 1836 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 1837 1838 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 1839 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 1840 1841 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 1842 return true; 1843 } 1844 } 1845 } 1846 1847 return false; 1848 } 1849 1850 void readPasspointConfig(Map<String, WifiConfiguration> configs, 1851 SparseArray<Map<String, String>> networkExtras) { 1852 List<HomeSP> homeSPs; 1853 try { 1854 homeSPs = mMOManager.loadAllSPs(); 1855 } catch (IOException e) { 1856 loge("Could not read " + PPS_FILE + " : " + e); 1857 return; 1858 } 1859 1860 int matchedConfigs = 0; 1861 for (HomeSP homeSp : homeSPs) { 1862 String fqdn = homeSp.getFQDN(); 1863 Log.d(TAG, "Looking for " + fqdn); 1864 for (WifiConfiguration config : configs.values()) { 1865 Log.d(TAG, "Testing " + config.SSID); 1866 1867 if (config.enterpriseConfig == null) { 1868 continue; 1869 } 1870 final String configFqdn = 1871 networkExtras.get(config.networkId).get(WifiConfigStore.ID_STRING_KEY_FQDN); 1872 if (configFqdn != null && configFqdn.equals(fqdn)) { 1873 Log.d(TAG, "Matched " + configFqdn + " with " + config.networkId); 1874 ++matchedConfigs; 1875 config.FQDN = fqdn; 1876 config.providerFriendlyName = homeSp.getFriendlyName(); 1877 1878 HashSet<Long> roamingConsortiumIds = homeSp.getRoamingConsortiums(); 1879 config.roamingConsortiumIds = new long[roamingConsortiumIds.size()]; 1880 int i = 0; 1881 for (long id : roamingConsortiumIds) { 1882 config.roamingConsortiumIds[i] = id; 1883 i++; 1884 } 1885 IMSIParameter imsiParameter = homeSp.getCredential().getImsi(); 1886 config.enterpriseConfig.setPlmn( 1887 imsiParameter != null ? imsiParameter.toString() : null); 1888 config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm()); 1889 } 1890 } 1891 } 1892 1893 Log.d(TAG, "loaded " + matchedConfigs + " passpoint configs"); 1894 } 1895 1896 public void writePasspointConfigs(final String fqdn, final HomeSP homeSP) { 1897 mWriter.write(PPS_FILE, new DelayedDiskWrite.Writer() { 1898 @Override 1899 public void onWriteCalled(DataOutputStream out) throws IOException { 1900 try { 1901 if (homeSP != null) { 1902 mMOManager.addSP(homeSP); 1903 } else { 1904 mMOManager.removeSP(fqdn); 1905 } 1906 } catch (IOException e) { 1907 loge("Could not write " + PPS_FILE + " : " + e); 1908 } 1909 } 1910 }, false); 1911 } 1912 1913 /** 1914 * Write network history, WifiConfigurations and mScanDetailCaches to file. 1915 */ 1916 private void readNetworkHistory(Map<String, WifiConfiguration> configs) { 1917 mWifiNetworkHistory.readNetworkHistory(configs, 1918 mScanDetailCaches, 1919 mDeletedSSIDs, 1920 mDeletedEphemeralSSIDs); 1921 } 1922 1923 /** 1924 * Read Network history from file, merge it into mConfiguredNetowrks and mScanDetailCaches 1925 */ 1926 public void writeKnownNetworkHistory() { 1927 final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 1928 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 1929 networks.add(new WifiConfiguration(config)); 1930 } 1931 mWifiNetworkHistory.writeKnownNetworkHistory(networks, 1932 mScanDetailCaches, 1933 mDeletedSSIDs, 1934 mDeletedEphemeralSSIDs); 1935 } 1936 1937 public void setAndEnableLastSelectedConfiguration(int netId) { 1938 if (sVDBG) { 1939 loge("setLastSelectedConfiguration " + Integer.toString(netId)); 1940 } 1941 if (netId == WifiConfiguration.INVALID_NETWORK_ID) { 1942 mLastSelectedConfiguration = null; 1943 mLastSelectedTimeStamp = -1; 1944 } else { 1945 WifiConfiguration selected = getWifiConfiguration(netId); 1946 if (selected == null) { 1947 mLastSelectedConfiguration = null; 1948 mLastSelectedTimeStamp = -1; 1949 } else { 1950 mLastSelectedConfiguration = selected.configKey(); 1951 mLastSelectedTimeStamp = System.currentTimeMillis(); 1952 updateNetworkSelectionStatus(netId, 1953 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1954 if (sVDBG) { 1955 loge("setLastSelectedConfiguration now: " + mLastSelectedConfiguration); 1956 } 1957 } 1958 } 1959 } 1960 1961 public void setLatestUserSelectedConfiguration(WifiConfiguration network) { 1962 if (network != null) { 1963 mLastSelectedConfiguration = network.configKey(); 1964 mLastSelectedTimeStamp = System.currentTimeMillis(); 1965 } 1966 } 1967 1968 public String getLastSelectedConfiguration() { 1969 return mLastSelectedConfiguration; 1970 } 1971 1972 public long getLastSelectedTimeStamp() { 1973 return mLastSelectedTimeStamp; 1974 } 1975 1976 public boolean isLastSelectedConfiguration(WifiConfiguration config) { 1977 return (mLastSelectedConfiguration != null 1978 && config != null 1979 && mLastSelectedConfiguration.equals(config.configKey())); 1980 } 1981 1982 private void writeIpAndProxyConfigurations() { 1983 final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>(); 1984 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 1985 if (!config.ephemeral) { 1986 networks.put(configKey(config), config.getIpConfiguration()); 1987 } 1988 } 1989 1990 mIpconfigStore.writeIpAndProxyConfigurations(IP_CONFIG_FILE, networks); 1991 } 1992 1993 private void readIpAndProxyConfigurations() { 1994 SparseArray<IpConfiguration> networks = 1995 mIpconfigStore.readIpAndProxyConfigurations(IP_CONFIG_FILE); 1996 1997 if (networks == null || networks.size() == 0) { 1998 // IpConfigStore.readIpAndProxyConfigurations has already logged an error. 1999 return; 2000 } 2001 2002 for (int i = 0; i < networks.size(); i++) { 2003 int id = networks.keyAt(i); 2004 WifiConfiguration config = mConfiguredNetworks.getByConfigKeyIDForAllUsers(id); 2005 // This is the only place the map is looked up through a (dangerous) hash-value! 2006 2007 if (config == null || config.ephemeral) { 2008 loge("configuration found for missing network, nid=" + id 2009 + ", ignored, networks.size=" + Integer.toString(networks.size())); 2010 } else { 2011 config.setIpConfiguration(networks.valueAt(i)); 2012 } 2013 } 2014 } 2015 2016 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config, int uid) { 2017 /* 2018 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 2019 * network configuration. Otherwise, the networkId should 2020 * refer to an existing configuration. 2021 */ 2022 2023 if (sVDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 2024 if (config.isPasspoint() && !mMOManager.isEnabled()) { 2025 Log.e(TAG, "Passpoint is not enabled"); 2026 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2027 } 2028 2029 boolean newNetwork = false; 2030 boolean existingMO = false; 2031 WifiConfiguration currentConfig; 2032 // networkId of INVALID_NETWORK_ID means we want to create a new network 2033 if (config.networkId == INVALID_NETWORK_ID) { 2034 // Try to fetch the existing config using configKey 2035 currentConfig = mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 2036 if (currentConfig != null) { 2037 config.networkId = currentConfig.networkId; 2038 } else { 2039 if (mMOManager.getHomeSP(config.FQDN) != null) { 2040 loge("addOrUpdateNetworkNative passpoint " + config.FQDN 2041 + " was found, but no network Id"); 2042 existingMO = true; 2043 } 2044 newNetwork = true; 2045 } 2046 } else { 2047 // Fetch the existing config using networkID 2048 currentConfig = mConfiguredNetworks.getForCurrentUser(config.networkId); 2049 } 2050 if (!mWifiConfigStore.addOrUpdateNetwork(config, currentConfig)) { 2051 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2052 } 2053 int netId = config.networkId; 2054 String savedConfigKey = config.configKey(); 2055 2056 /* An update of the network variables requires reading them 2057 * back from the supplicant to update mConfiguredNetworks. 2058 * This is because some of the variables (SSID, wep keys & 2059 * passphrases) reflect different values when read back than 2060 * when written. For example, wep key is stored as * irrespective 2061 * of the value sent to the supplicant. 2062 */ 2063 if (currentConfig == null) { 2064 currentConfig = new WifiConfiguration(); 2065 currentConfig.setIpAssignment(IpAssignment.DHCP); 2066 currentConfig.setProxySettings(ProxySettings.NONE); 2067 currentConfig.networkId = netId; 2068 if (config != null) { 2069 // Carry over the creation parameters 2070 currentConfig.selfAdded = config.selfAdded; 2071 currentConfig.didSelfAdd = config.didSelfAdd; 2072 currentConfig.ephemeral = config.ephemeral; 2073 currentConfig.meteredHint = config.meteredHint; 2074 currentConfig.lastConnectUid = config.lastConnectUid; 2075 currentConfig.lastUpdateUid = config.lastUpdateUid; 2076 currentConfig.creatorUid = config.creatorUid; 2077 currentConfig.creatorName = config.creatorName; 2078 currentConfig.lastUpdateName = config.lastUpdateName; 2079 currentConfig.peerWifiConfiguration = config.peerWifiConfiguration; 2080 currentConfig.FQDN = config.FQDN; 2081 currentConfig.providerFriendlyName = config.providerFriendlyName; 2082 currentConfig.roamingConsortiumIds = config.roamingConsortiumIds; 2083 currentConfig.validatedInternetAccess = config.validatedInternetAccess; 2084 currentConfig.numNoInternetAccessReports = config.numNoInternetAccessReports; 2085 currentConfig.updateTime = config.updateTime; 2086 currentConfig.creationTime = config.creationTime; 2087 currentConfig.shared = config.shared; 2088 } 2089 if (DBG) { 2090 log("created new config netId=" + Integer.toString(netId) 2091 + " uid=" + Integer.toString(currentConfig.creatorUid) 2092 + " name=" + currentConfig.creatorName); 2093 } 2094 } 2095 2096 /* save HomeSP object for passpoint networks */ 2097 HomeSP homeSP = null; 2098 2099 if (!existingMO && config.isPasspoint()) { 2100 try { 2101 if (config.updateIdentifier == null) { // Only create an MO for r1 networks 2102 Credential credential = 2103 new Credential(config.enterpriseConfig, mKeyStore, !newNetwork); 2104 HashSet<Long> roamingConsortiumIds = new HashSet<Long>(); 2105 for (Long roamingConsortiumId : config.roamingConsortiumIds) { 2106 roamingConsortiumIds.add(roamingConsortiumId); 2107 } 2108 2109 homeSP = new HomeSP(Collections.<String, Long>emptyMap(), config.FQDN, 2110 roamingConsortiumIds, Collections.<String>emptySet(), 2111 Collections.<Long>emptySet(), Collections.<Long>emptyList(), 2112 config.providerFriendlyName, null, credential); 2113 2114 log("created a homeSP object for " + config.networkId + ":" + config.SSID); 2115 } 2116 2117 /* fix enterprise config properties for passpoint */ 2118 currentConfig.enterpriseConfig.setRealm(config.enterpriseConfig.getRealm()); 2119 currentConfig.enterpriseConfig.setPlmn(config.enterpriseConfig.getPlmn()); 2120 } catch (IOException ioe) { 2121 Log.e(TAG, "Failed to create Passpoint config: " + ioe); 2122 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2123 } 2124 } 2125 2126 if (uid != WifiConfiguration.UNKNOWN_UID) { 2127 if (newNetwork) { 2128 currentConfig.creatorUid = uid; 2129 } else { 2130 currentConfig.lastUpdateUid = uid; 2131 } 2132 } 2133 2134 // For debug, record the time the configuration was modified 2135 StringBuilder sb = new StringBuilder(); 2136 sb.append("time="); 2137 Calendar c = Calendar.getInstance(); 2138 c.setTimeInMillis(System.currentTimeMillis()); 2139 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 2140 2141 if (newNetwork) { 2142 currentConfig.creationTime = sb.toString(); 2143 } else { 2144 currentConfig.updateTime = sb.toString(); 2145 } 2146 2147 if (currentConfig.status == WifiConfiguration.Status.ENABLED) { 2148 // Make sure autojoin remain in sync with user modifying the configuration 2149 updateNetworkSelectionStatus(currentConfig.networkId, 2150 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 2151 } 2152 2153 if (currentConfig.configKey().equals(getLastSelectedConfiguration()) 2154 && currentConfig.ephemeral) { 2155 // Make the config non-ephemeral since the user just explicitly clicked it. 2156 currentConfig.ephemeral = false; 2157 if (DBG) { 2158 log("remove ephemeral status netId=" + Integer.toString(netId) 2159 + " " + currentConfig.configKey()); 2160 } 2161 } 2162 2163 if (sVDBG) log("will read network variables netId=" + Integer.toString(netId)); 2164 2165 readNetworkVariables(currentConfig); 2166 // When we read back the config from wpa_supplicant, some of the default values are set 2167 // which could change the configKey. 2168 if (!savedConfigKey.equals(currentConfig.configKey())) { 2169 if (!mWifiConfigStore.saveNetworkMetadata(currentConfig)) { 2170 loge("Failed to set network metadata. Removing config " + config.networkId); 2171 mWifiConfigStore.removeNetwork(config); 2172 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2173 } 2174 } 2175 2176 // Persist configuration paramaters that are not saved by supplicant. 2177 if (config.lastUpdateName != null) { 2178 currentConfig.lastUpdateName = config.lastUpdateName; 2179 } 2180 if (config.lastUpdateUid != WifiConfiguration.UNKNOWN_UID) { 2181 currentConfig.lastUpdateUid = config.lastUpdateUid; 2182 } 2183 2184 mConfiguredNetworks.put(currentConfig); 2185 2186 NetworkUpdateResult result = 2187 writeIpAndProxyConfigurationsOnChange(currentConfig, config, newNetwork); 2188 result.setIsNewNetwork(newNetwork); 2189 result.setNetworkId(netId); 2190 2191 if (homeSP != null) { 2192 writePasspointConfigs(null, homeSP); 2193 } 2194 2195 saveConfig(); 2196 writeKnownNetworkHistory(); 2197 2198 return result; 2199 } 2200 2201 public WifiConfiguration getWifiConfigForHomeSP(HomeSP homeSP) { 2202 WifiConfiguration config = mConfiguredNetworks.getByFQDNForCurrentUser(homeSP.getFQDN()); 2203 if (config == null) { 2204 Log.e(TAG, "Could not find network for homeSP " + homeSP.getFQDN()); 2205 } 2206 return config; 2207 } 2208 2209 public HomeSP getHomeSPForConfig(WifiConfiguration config) { 2210 WifiConfiguration storedConfig = mConfiguredNetworks.getForCurrentUser(config.networkId); 2211 return storedConfig != null && storedConfig.isPasspoint() 2212 ? mMOManager.getHomeSP(storedConfig.FQDN) 2213 : null; 2214 } 2215 2216 public ScanDetailCache getScanDetailCache(WifiConfiguration config) { 2217 if (config == null) return null; 2218 ScanDetailCache cache = mScanDetailCaches.get(config.networkId); 2219 if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { 2220 cache = new ScanDetailCache(config); 2221 mScanDetailCaches.put(config.networkId, cache); 2222 } 2223 return cache; 2224 } 2225 2226 /** 2227 * This function run thru the Saved WifiConfigurations and check if some should be linked. 2228 * @param config 2229 */ 2230 public void linkConfiguration(WifiConfiguration config) { 2231 if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, 2232 mWifiStateMachine.getCurrentUserProfiles())) { 2233 loge("linkConfiguration: Attempting to link config " + config.configKey() 2234 + " that is not visible to the current user."); 2235 return; 2236 } 2237 2238 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 6) { 2239 // Ignore configurations with large number of BSSIDs 2240 return; 2241 } 2242 if (!config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 2243 // Only link WPA_PSK config 2244 return; 2245 } 2246 for (WifiConfiguration link : mConfiguredNetworks.valuesForCurrentUser()) { 2247 boolean doLink = false; 2248 2249 if (link.configKey().equals(config.configKey())) { 2250 continue; 2251 } 2252 2253 if (link.ephemeral) { 2254 continue; 2255 } 2256 2257 // Autojoin will be allowed to dynamically jump from a linked configuration 2258 // to another, hence only link configurations that have equivalent level of security 2259 if (!link.allowedKeyManagement.equals(config.allowedKeyManagement)) { 2260 continue; 2261 } 2262 2263 ScanDetailCache linkedScanDetailCache = getScanDetailCache(link); 2264 if (linkedScanDetailCache != null && linkedScanDetailCache.size() > 6) { 2265 // Ignore configurations with large number of BSSIDs 2266 continue; 2267 } 2268 2269 if (config.defaultGwMacAddress != null && link.defaultGwMacAddress != null) { 2270 // If both default GW are known, link only if they are equal 2271 if (config.defaultGwMacAddress.equals(link.defaultGwMacAddress)) { 2272 if (sVDBG) { 2273 loge("linkConfiguration link due to same gw " + link.SSID 2274 + " and " + config.SSID + " GW " + config.defaultGwMacAddress); 2275 } 2276 doLink = true; 2277 } 2278 } else { 2279 // We do not know BOTH default gateways hence we will try to link 2280 // hoping that WifiConfigurations are indeed behind the same gateway. 2281 // once both WifiConfiguration have been tried and thus once both efault gateways 2282 // are known we will revisit the choice of linking them 2283 if ((getScanDetailCache(config) != null) 2284 && (getScanDetailCache(config).size() <= 6)) { 2285 2286 for (String abssid : getScanDetailCache(config).keySet()) { 2287 for (String bbssid : linkedScanDetailCache.keySet()) { 2288 if (sVVDBG) { 2289 loge("linkConfiguration try to link due to DBDC BSSID match " 2290 + link.SSID + " and " + config.SSID + " bssida " + abssid 2291 + " bssidb " + bbssid); 2292 } 2293 if (abssid.regionMatches(true, 0, bbssid, 0, 16)) { 2294 // If first 16 ascii characters of BSSID matches, 2295 // we assume this is a DBDC 2296 doLink = true; 2297 } 2298 } 2299 } 2300 } 2301 } 2302 2303 if (doLink && mOnlyLinkSameCredentialConfigurations) { 2304 String apsk = 2305 readNetworkVariableFromSupplicantFile(link.configKey(), "psk"); 2306 String bpsk = 2307 readNetworkVariableFromSupplicantFile(config.configKey(), "psk"); 2308 if (apsk == null || bpsk == null 2309 || TextUtils.isEmpty(apsk) || TextUtils.isEmpty(apsk) 2310 || apsk.equals("*") || apsk.equals(DELETED_CONFIG_PSK) 2311 || !apsk.equals(bpsk)) { 2312 doLink = false; 2313 } 2314 } 2315 2316 if (doLink) { 2317 if (sVDBG) { 2318 loge("linkConfiguration: will link " + link.configKey() 2319 + " and " + config.configKey()); 2320 } 2321 if (link.linkedConfigurations == null) { 2322 link.linkedConfigurations = new HashMap<String, Integer>(); 2323 } 2324 if (config.linkedConfigurations == null) { 2325 config.linkedConfigurations = new HashMap<String, Integer>(); 2326 } 2327 if (link.linkedConfigurations.get(config.configKey()) == null) { 2328 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 2329 } 2330 if (config.linkedConfigurations.get(link.configKey()) == null) { 2331 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 2332 } 2333 } else { 2334 if (link.linkedConfigurations != null 2335 && (link.linkedConfigurations.get(config.configKey()) != null)) { 2336 if (sVDBG) { 2337 loge("linkConfiguration: un-link " + config.configKey() 2338 + " from " + link.configKey()); 2339 } 2340 link.linkedConfigurations.remove(config.configKey()); 2341 } 2342 if (config.linkedConfigurations != null 2343 && (config.linkedConfigurations.get(link.configKey()) != null)) { 2344 if (sVDBG) { 2345 loge("linkConfiguration: un-link " + link.configKey() 2346 + " from " + config.configKey()); 2347 } 2348 config.linkedConfigurations.remove(link.configKey()); 2349 } 2350 } 2351 } 2352 } 2353 2354 public HashSet<Integer> makeChannelList(WifiConfiguration config, int age, boolean restrict) { 2355 if (config == null) { 2356 return null; 2357 } 2358 long now_ms = System.currentTimeMillis(); 2359 2360 HashSet<Integer> channels = new HashSet<Integer>(); 2361 2362 //get channels for this configuration, if there are at least 2 BSSIDs 2363 if (getScanDetailCache(config) == null && config.linkedConfigurations == null) { 2364 return null; 2365 } 2366 2367 if (sVDBG) { 2368 StringBuilder dbg = new StringBuilder(); 2369 dbg.append("makeChannelList age=" + Integer.toString(age) 2370 + " for " + config.configKey() 2371 + " max=" + mMaxNumActiveChannelsForPartialScans); 2372 if (getScanDetailCache(config) != null) { 2373 dbg.append(" bssids=" + getScanDetailCache(config).size()); 2374 } 2375 if (config.linkedConfigurations != null) { 2376 dbg.append(" linked=" + config.linkedConfigurations.size()); 2377 } 2378 loge(dbg.toString()); 2379 } 2380 2381 int numChannels = 0; 2382 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 0) { 2383 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 2384 ScanResult result = scanDetail.getScanResult(); 2385 //TODO : cout active and passive channels separately 2386 if (numChannels > mMaxNumActiveChannelsForPartialScans.get()) { 2387 break; 2388 } 2389 if (sVDBG) { 2390 boolean test = (now_ms - result.seen) < age; 2391 loge("has " + result.BSSID + " freq=" + Integer.toString(result.frequency) 2392 + " age=" + Long.toString(now_ms - result.seen) + " ?=" + test); 2393 } 2394 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 2395 channels.add(result.frequency); 2396 numChannels++; 2397 } 2398 } 2399 } 2400 2401 //get channels for linked configurations 2402 if (config.linkedConfigurations != null) { 2403 for (String key : config.linkedConfigurations.keySet()) { 2404 WifiConfiguration linked = getWifiConfiguration(key); 2405 if (linked == null) { 2406 continue; 2407 } 2408 if (getScanDetailCache(linked) == null) { 2409 continue; 2410 } 2411 for (ScanDetail scanDetail : getScanDetailCache(linked).values()) { 2412 ScanResult result = scanDetail.getScanResult(); 2413 if (sVDBG) { 2414 loge("has link: " + result.BSSID 2415 + " freq=" + Integer.toString(result.frequency) 2416 + " age=" + Long.toString(now_ms - result.seen)); 2417 } 2418 if (numChannels > mMaxNumActiveChannelsForPartialScans.get()) { 2419 break; 2420 } 2421 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 2422 channels.add(result.frequency); 2423 numChannels++; 2424 } 2425 } 2426 } 2427 } 2428 return channels; 2429 } 2430 2431 private Map<HomeSP, PasspointMatch> matchPasspointNetworks(ScanDetail scanDetail) { 2432 if (!mMOManager.isConfigured()) { 2433 if (mEnableOsuQueries) { 2434 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2435 List<Constants.ANQPElementType> querySet = 2436 ANQPFactory.buildQueryList(networkDetail, false, true); 2437 2438 if (networkDetail.queriable(querySet)) { 2439 querySet = mAnqpCache.initiate(networkDetail, querySet); 2440 if (querySet != null) { 2441 mSupplicantBridge.startANQP(scanDetail, querySet); 2442 } 2443 updateAnqpCache(scanDetail, networkDetail.getANQPElements()); 2444 } 2445 } 2446 return null; 2447 } 2448 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2449 if (!networkDetail.hasInterworking()) { 2450 return null; 2451 } 2452 updateAnqpCache(scanDetail, networkDetail.getANQPElements()); 2453 2454 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, true); 2455 Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() 2456 + " pass 1 matches: " + toMatchString(matches)); 2457 return matches; 2458 } 2459 2460 private Map<HomeSP, PasspointMatch> matchNetwork(ScanDetail scanDetail, boolean query) { 2461 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2462 2463 ANQPData anqpData = mAnqpCache.getEntry(networkDetail); 2464 2465 Map<Constants.ANQPElementType, ANQPElement> anqpElements = 2466 anqpData != null ? anqpData.getANQPElements() : null; 2467 2468 boolean queried = !query; 2469 Collection<HomeSP> homeSPs = mMOManager.getLoadedSPs().values(); 2470 Map<HomeSP, PasspointMatch> matches = new HashMap<>(homeSPs.size()); 2471 Log.d(Utils.hs2LogTag(getClass()), "match nwk " + scanDetail.toKeyString() 2472 + ", anqp " + (anqpData != null ? "present" : "missing") 2473 + ", query " + query + ", home sps: " + homeSPs.size()); 2474 2475 for (HomeSP homeSP : homeSPs) { 2476 PasspointMatch match = homeSP.match(networkDetail, anqpElements, mSIMAccessor); 2477 2478 Log.d(Utils.hs2LogTag(getClass()), " -- " 2479 + homeSP.getFQDN() + ": match " + match + ", queried " + queried); 2480 2481 if ((match == PasspointMatch.Incomplete || mEnableOsuQueries) && !queried) { 2482 boolean matchSet = match == PasspointMatch.Incomplete; 2483 boolean osu = mEnableOsuQueries; 2484 List<Constants.ANQPElementType> querySet = 2485 ANQPFactory.buildQueryList(networkDetail, matchSet, osu); 2486 if (networkDetail.queriable(querySet)) { 2487 querySet = mAnqpCache.initiate(networkDetail, querySet); 2488 if (querySet != null) { 2489 mSupplicantBridge.startANQP(scanDetail, querySet); 2490 } 2491 } 2492 queried = true; 2493 } 2494 matches.put(homeSP, match); 2495 } 2496 return matches; 2497 } 2498 2499 public Map<Constants.ANQPElementType, ANQPElement> getANQPData(NetworkDetail network) { 2500 ANQPData data = mAnqpCache.getEntry(network); 2501 return data != null ? data.getANQPElements() : null; 2502 } 2503 2504 public SIMAccessor getSIMAccessor() { 2505 return mSIMAccessor; 2506 } 2507 2508 public void notifyANQPDone(Long bssid, boolean success) { 2509 mSupplicantBridge.notifyANQPDone(bssid, success); 2510 } 2511 2512 public void notifyIconReceived(IconEvent iconEvent) { 2513 Intent intent = new Intent(WifiManager.PASSPOINT_ICON_RECEIVED_ACTION); 2514 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2515 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_BSSID, iconEvent.getBSSID()); 2516 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_FILE, iconEvent.getFileName()); 2517 try { 2518 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_DATA, 2519 mSupplicantBridge.retrieveIcon(iconEvent)); 2520 } catch (IOException ioe) { 2521 /* Simply omit the icon data as a failure indication */ 2522 } 2523 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2524 2525 } 2526 2527 public void wnmFrameReceived(WnmData event) { 2528 // %012x HS20-SUBSCRIPTION-REMEDIATION "%u %s", osu_method, url 2529 // %012x HS20-DEAUTH-IMMINENT-NOTICE "%u %u %s", code, reauth_delay, url 2530 2531 Intent intent = new Intent(WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION); 2532 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2533 2534 intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_BSSID, event.getBssid()); 2535 intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_URL, event.getUrl()); 2536 2537 if (event.isDeauthEvent()) { 2538 intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_ESS, event.isEss()); 2539 intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_DELAY, event.getDelay()); 2540 } else { 2541 intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_METHOD, event.getMethod()); 2542 WifiConfiguration config = mWifiStateMachine.getCurrentWifiConfiguration(); 2543 if (config != null && config.FQDN != null) { 2544 intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH, 2545 matchProviderWithCurrentNetwork(config.FQDN)); 2546 } 2547 } 2548 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2549 } 2550 2551 private void updateAnqpCache(ScanDetail scanDetail, 2552 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 2553 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2554 2555 if (anqpElements == null) { 2556 // Try to pull cached data if query failed. 2557 ANQPData data = mAnqpCache.getEntry(networkDetail); 2558 if (data != null) { 2559 scanDetail.propagateANQPInfo(data.getANQPElements()); 2560 } 2561 return; 2562 } 2563 2564 mAnqpCache.update(networkDetail, anqpElements); 2565 } 2566 2567 private static String toMatchString(Map<HomeSP, PasspointMatch> matches) { 2568 StringBuilder sb = new StringBuilder(); 2569 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 2570 sb.append(' ').append(entry.getKey().getFQDN()).append("->").append(entry.getValue()); 2571 } 2572 return sb.toString(); 2573 } 2574 2575 private void cacheScanResultForPasspointConfigs(ScanDetail scanDetail, 2576 Map<HomeSP, PasspointMatch> matches, 2577 List<WifiConfiguration> associatedWifiConfigurations) { 2578 2579 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 2580 PasspointMatch match = entry.getValue(); 2581 if (match == PasspointMatch.HomeProvider || match == PasspointMatch.RoamingProvider) { 2582 WifiConfiguration config = getWifiConfigForHomeSP(entry.getKey()); 2583 if (config != null) { 2584 cacheScanResultForConfig(config, scanDetail, entry.getValue()); 2585 if (associatedWifiConfigurations != null) { 2586 associatedWifiConfigurations.add(config); 2587 } 2588 } else { 2589 Log.w(Utils.hs2LogTag(getClass()), "Failed to find config for '" 2590 + entry.getKey().getFQDN() + "'"); 2591 /* perhaps the configuration was deleted?? */ 2592 } 2593 } 2594 } 2595 } 2596 2597 private void cacheScanResultForConfig( 2598 WifiConfiguration config, ScanDetail scanDetail, PasspointMatch passpointMatch) { 2599 2600 ScanResult scanResult = scanDetail.getScanResult(); 2601 2602 ScanDetailCache scanDetailCache = getScanDetailCache(config); 2603 if (scanDetailCache == null) { 2604 Log.w(TAG, "Could not allocate scan cache for " + config.SSID); 2605 return; 2606 } 2607 2608 // Adding a new BSSID 2609 ScanResult result = scanDetailCache.get(scanResult.BSSID); 2610 if (result != null) { 2611 // transfer the black list status 2612 scanResult.blackListTimestamp = result.blackListTimestamp; 2613 scanResult.numIpConfigFailures = result.numIpConfigFailures; 2614 scanResult.numConnection = result.numConnection; 2615 scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate; 2616 } 2617 2618 if (config.ephemeral) { 2619 // For an ephemeral Wi-Fi config, the ScanResult should be considered 2620 // untrusted. 2621 scanResult.untrusted = true; 2622 } 2623 2624 if (scanDetailCache.size() > (MAX_NUM_SCAN_CACHE_ENTRIES + 64)) { 2625 long now_dbg = 0; 2626 if (sVVDBG) { 2627 loge(" Will trim config " + config.configKey() 2628 + " size " + scanDetailCache.size()); 2629 2630 for (ScanDetail sd : scanDetailCache.values()) { 2631 loge(" " + sd.getBSSIDString() + " " + sd.getSeen()); 2632 } 2633 now_dbg = SystemClock.elapsedRealtimeNanos(); 2634 } 2635 // Trim the scan result cache to MAX_NUM_SCAN_CACHE_ENTRIES entries max 2636 // Since this operation is expensive, make sure it is not performed 2637 // until the cache has grown significantly above the trim treshold 2638 scanDetailCache.trim(MAX_NUM_SCAN_CACHE_ENTRIES); 2639 if (sVVDBG) { 2640 long diff = SystemClock.elapsedRealtimeNanos() - now_dbg; 2641 loge(" Finished trimming config, time(ns) " + diff); 2642 for (ScanDetail sd : scanDetailCache.values()) { 2643 loge(" " + sd.getBSSIDString() + " " + sd.getSeen()); 2644 } 2645 } 2646 } 2647 2648 // Add the scan result to this WifiConfiguration 2649 if (passpointMatch != null) { 2650 scanDetailCache.put(scanDetail, passpointMatch, getHomeSPForConfig(config)); 2651 } else { 2652 scanDetailCache.put(scanDetail); 2653 } 2654 2655 // Since we added a scan result to this configuration, re-attempt linking 2656 linkConfiguration(config); 2657 } 2658 2659 private boolean isEncryptionWep(String encryption) { 2660 return encryption.contains("WEP"); 2661 } 2662 2663 private boolean isEncryptionPsk(String encryption) { 2664 return encryption.contains("PSK"); 2665 } 2666 2667 private boolean isEncryptionEap(String encryption) { 2668 return encryption.contains("EAP"); 2669 } 2670 2671 public boolean isOpenNetwork(String encryption) { 2672 if (!isEncryptionWep(encryption) && !isEncryptionPsk(encryption) 2673 && !isEncryptionEap(encryption)) { 2674 return true; 2675 } 2676 return false; 2677 } 2678 2679 public boolean isOpenNetwork(ScanResult scan) { 2680 String scanResultEncrypt = scan.capabilities; 2681 return isOpenNetwork(scanResultEncrypt); 2682 } 2683 2684 public boolean isOpenNetwork(WifiConfiguration config) { 2685 String configEncrypt = config.configKey(); 2686 return isOpenNetwork(configEncrypt); 2687 } 2688 2689 /** 2690 * create a mapping between the scandetail and the Wificonfiguration it associated with 2691 * because Passpoint, one BSSID can associated with multiple SSIDs 2692 * @param scanDetail input a scanDetail from the scan result 2693 * @return List<WifiConfiguration> a list of WifiConfigurations associated to this scanDetail 2694 */ 2695 public List<WifiConfiguration> updateSavedNetworkWithNewScanDetail(ScanDetail scanDetail) { 2696 2697 ScanResult scanResult = scanDetail.getScanResult(); 2698 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2699 List<WifiConfiguration> associatedWifiConfigurations = new ArrayList<WifiConfiguration>(); 2700 2701 if (scanResult == null) { 2702 return null; 2703 } 2704 2705 String ssid = "\"" + scanResult.SSID + "\""; 2706 2707 if (networkDetail.hasInterworking()) { 2708 Map<HomeSP, PasspointMatch> matches = matchPasspointNetworks(scanDetail); 2709 if (matches != null) { 2710 cacheScanResultForPasspointConfigs(scanDetail, matches, 2711 associatedWifiConfigurations); 2712 //Do not return here. A BSSID can belong to both passpoint network and non-passpoint 2713 //Network 2714 } 2715 } 2716 2717 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2718 boolean found = false; 2719 if (config.SSID == null || !config.SSID.equals(ssid)) { 2720 continue; 2721 } 2722 if (DBG) { 2723 localLog("updateSavedNetworkWithNewScanDetail(): try " + config.configKey() 2724 + " SSID=" + config.SSID + " " + scanResult.SSID + " " 2725 + scanResult.capabilities); 2726 } 2727 2728 String scanResultEncrypt = scanResult.capabilities; 2729 String configEncrypt = config.configKey(); 2730 if (isEncryptionWep(scanResultEncrypt) && isEncryptionWep(configEncrypt) 2731 || (isEncryptionPsk(scanResultEncrypt) && isEncryptionPsk(configEncrypt)) 2732 || (isEncryptionEap(scanResultEncrypt) && isEncryptionEap(configEncrypt)) 2733 || (isOpenNetwork(scanResultEncrypt) && isOpenNetwork(configEncrypt))) { 2734 found = true; 2735 } 2736 2737 if (found) { 2738 cacheScanResultForConfig(config, scanDetail, null); 2739 associatedWifiConfigurations.add(config); 2740 } 2741 } 2742 2743 if (associatedWifiConfigurations.size() == 0) { 2744 return null; 2745 } else { 2746 return associatedWifiConfigurations; 2747 } 2748 } 2749 2750 /** 2751 * Handles the switch to a different foreground user: 2752 * - Removes all ephemeral networks 2753 * - Disables private network configurations belonging to the previous foreground user 2754 * - Enables private network configurations belonging to the new foreground user 2755 * 2756 * TODO(b/26785736): Terminate background users if the new foreground user has one or more 2757 * private network configurations. 2758 */ 2759 public void handleUserSwitch() { 2760 Set<WifiConfiguration> ephemeralConfigs = new HashSet<>(); 2761 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2762 if (config.ephemeral) { 2763 ephemeralConfigs.add(config); 2764 } 2765 } 2766 if (!ephemeralConfigs.isEmpty()) { 2767 for (WifiConfiguration config : ephemeralConfigs) { 2768 removeConfigWithoutBroadcast(config); 2769 } 2770 saveConfig(); 2771 writeKnownNetworkHistory(); 2772 } 2773 2774 final List<WifiConfiguration> hiddenConfigurations = 2775 mConfiguredNetworks.handleUserSwitch(mWifiStateMachine.getCurrentUserId()); 2776 for (WifiConfiguration network : hiddenConfigurations) { 2777 disableNetworkNative(network); 2778 } 2779 enableAllNetworks(); 2780 2781 // TODO(b/26785746): This broadcast is unnecessary if either of the following is true: 2782 // * The user switch did not change the list of visible networks 2783 // * The user switch revealed additional networks that were temporarily disabled and got 2784 // re-enabled now (because enableAllNetworks() sent the same broadcast already). 2785 sendConfiguredNetworksChangedBroadcast(); 2786 } 2787 2788 /* Compare current and new configuration and write to file on change */ 2789 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 2790 WifiConfiguration currentConfig, 2791 WifiConfiguration newConfig, 2792 boolean isNewNetwork) { 2793 boolean ipChanged = false; 2794 boolean proxyChanged = false; 2795 2796 switch (newConfig.getIpAssignment()) { 2797 case STATIC: 2798 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 2799 ipChanged = true; 2800 } else { 2801 ipChanged = !Objects.equals( 2802 currentConfig.getStaticIpConfiguration(), 2803 newConfig.getStaticIpConfiguration()); 2804 } 2805 break; 2806 case DHCP: 2807 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 2808 ipChanged = true; 2809 } 2810 break; 2811 case UNASSIGNED: 2812 /* Ignore */ 2813 break; 2814 default: 2815 loge("Ignore invalid ip assignment during write"); 2816 break; 2817 } 2818 2819 switch (newConfig.getProxySettings()) { 2820 case STATIC: 2821 case PAC: 2822 ProxyInfo newHttpProxy = newConfig.getHttpProxy(); 2823 ProxyInfo currentHttpProxy = currentConfig.getHttpProxy(); 2824 2825 if (newHttpProxy != null) { 2826 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 2827 } else { 2828 proxyChanged = (currentHttpProxy != null); 2829 } 2830 break; 2831 case NONE: 2832 if (currentConfig.getProxySettings() != newConfig.getProxySettings()) { 2833 proxyChanged = true; 2834 } 2835 break; 2836 case UNASSIGNED: 2837 /* Ignore */ 2838 break; 2839 default: 2840 loge("Ignore invalid proxy configuration during write"); 2841 break; 2842 } 2843 2844 if (ipChanged) { 2845 currentConfig.setIpAssignment(newConfig.getIpAssignment()); 2846 currentConfig.setStaticIpConfiguration(newConfig.getStaticIpConfiguration()); 2847 log("IP config changed SSID = " + currentConfig.SSID); 2848 if (currentConfig.getStaticIpConfiguration() != null) { 2849 log(" static configuration: " 2850 + currentConfig.getStaticIpConfiguration().toString()); 2851 } 2852 } 2853 2854 if (proxyChanged) { 2855 currentConfig.setProxySettings(newConfig.getProxySettings()); 2856 currentConfig.setHttpProxy(newConfig.getHttpProxy()); 2857 log("proxy changed SSID = " + currentConfig.SSID); 2858 if (currentConfig.getHttpProxy() != null) { 2859 log(" proxyProperties: " + currentConfig.getHttpProxy().toString()); 2860 } 2861 } 2862 2863 if (ipChanged || proxyChanged || isNewNetwork) { 2864 if (sVDBG) { 2865 logd("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " 2866 + newConfig.SSID + " path: " + IP_CONFIG_FILE); 2867 } 2868 writeIpAndProxyConfigurations(); 2869 } 2870 return new NetworkUpdateResult(ipChanged, proxyChanged); 2871 } 2872 2873 /** 2874 * Read the variables from the supplicant daemon that are needed to 2875 * fill in the WifiConfiguration object. 2876 * 2877 * @param config the {@link WifiConfiguration} object to be filled in. 2878 */ 2879 private void readNetworkVariables(WifiConfiguration config) { 2880 mWifiConfigStore.readNetworkVariables(config); 2881 } 2882 2883 /* return the allowed key management based on a scan result */ 2884 2885 public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) { 2886 2887 WifiConfiguration config = new WifiConfiguration(); 2888 2889 config.SSID = "\"" + result.SSID + "\""; 2890 2891 if (sVDBG) { 2892 loge("WifiConfiguration from scan results " 2893 + config.SSID + " cap " + result.capabilities); 2894 } 2895 2896 if (result.capabilities.contains("PSK") || result.capabilities.contains("EAP") 2897 || result.capabilities.contains("WEP")) { 2898 if (result.capabilities.contains("PSK")) { 2899 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 2900 } 2901 2902 if (result.capabilities.contains("EAP")) { 2903 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 2904 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 2905 } 2906 2907 if (result.capabilities.contains("WEP")) { 2908 config.allowedKeyManagement.set(KeyMgmt.NONE); 2909 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 2910 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 2911 } 2912 } else { 2913 config.allowedKeyManagement.set(KeyMgmt.NONE); 2914 } 2915 2916 return config; 2917 } 2918 2919 public WifiConfiguration wifiConfigurationFromScanResult(ScanDetail scanDetail) { 2920 ScanResult result = scanDetail.getScanResult(); 2921 return wifiConfigurationFromScanResult(result); 2922 } 2923 2924 /* Returns a unique for a given configuration */ 2925 private static int configKey(WifiConfiguration config) { 2926 String key = config.configKey(); 2927 return key.hashCode(); 2928 } 2929 2930 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2931 pw.println("Dump of WifiConfigManager"); 2932 pw.println("mLastPriority " + mLastPriority); 2933 pw.println("Configured networks"); 2934 for (WifiConfiguration conf : getAllConfiguredNetworks()) { 2935 pw.println(conf); 2936 } 2937 pw.println(); 2938 if (mLostConfigsDbg != null && mLostConfigsDbg.size() > 0) { 2939 pw.println("LostConfigs: "); 2940 for (String s : mLostConfigsDbg) { 2941 pw.println(s); 2942 } 2943 } 2944 if (mLocalLog != null) { 2945 pw.println("WifiConfigManager - Log Begin ----"); 2946 mLocalLog.dump(fd, pw, args); 2947 pw.println("WifiConfigManager - Log End ----"); 2948 } 2949 if (mMOManager.isConfigured()) { 2950 pw.println("Begin dump of ANQP Cache"); 2951 mAnqpCache.dump(pw); 2952 pw.println("End dump of ANQP Cache"); 2953 } 2954 } 2955 2956 public String getConfigFile() { 2957 return IP_CONFIG_FILE; 2958 } 2959 2960 protected void logd(String s) { 2961 Log.d(TAG, s); 2962 } 2963 2964 protected void loge(String s) { 2965 loge(s, false); 2966 } 2967 2968 protected void loge(String s, boolean stack) { 2969 if (stack) { 2970 Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2971 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 2972 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 2973 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 2974 } else { 2975 Log.e(TAG, s); 2976 } 2977 } 2978 2979 private void logKernelTime() { 2980 long kernelTimeMs = System.nanoTime() / (1000 * 1000); 2981 StringBuilder builder = new StringBuilder(); 2982 builder.append("kernel time = ") 2983 .append(kernelTimeMs / 1000) 2984 .append(".") 2985 .append(kernelTimeMs % 1000) 2986 .append("\n"); 2987 localLog(builder.toString()); 2988 } 2989 2990 protected void log(String s) { 2991 Log.d(TAG, s); 2992 } 2993 2994 private void localLog(String s) { 2995 if (mLocalLog != null) { 2996 mLocalLog.log(s); 2997 } 2998 } 2999 3000 private void localLogAndLogcat(String s) { 3001 localLog(s); 3002 Log.d(TAG, s); 3003 } 3004 3005 private void localLogNetwork(String s, int netId) { 3006 if (mLocalLog == null) { 3007 return; 3008 } 3009 3010 WifiConfiguration config; 3011 synchronized (mConfiguredNetworks) { // !!! Useless synchronization 3012 config = mConfiguredNetworks.getForAllUsers(netId); 3013 } 3014 3015 if (config != null) { 3016 mLocalLog.log(s + " " + config.getPrintableSsid() + " " + netId 3017 + " status=" + config.status 3018 + " key=" + config.configKey()); 3019 } else { 3020 mLocalLog.log(s + " " + netId); 3021 } 3022 } 3023 3024 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 3025 String client = config.getClientCertificateAlias(); 3026 if (!TextUtils.isEmpty(client)) { 3027 // a valid client certificate is configured 3028 3029 // BUGBUG: keyStore.get() never returns certBytes; because it is not 3030 // taking WIFI_UID as a parameter. It always looks for certificate 3031 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 3032 // all certificates need software keystore until we get the get() API 3033 // fixed. 3034 3035 return true; 3036 } 3037 3038 /* 3039 try { 3040 3041 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 3042 .USER_CERTIFICATE + client); 3043 3044 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 3045 if (factory == null) { 3046 Slog.e(TAG, "Error getting certificate factory"); 3047 return; 3048 } 3049 3050 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 3051 if (certBytes != null) { 3052 Certificate cert = (X509Certificate) factory.generateCertificate( 3053 new ByteArrayInputStream(certBytes)); 3054 3055 if (cert != null) { 3056 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 3057 3058 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 3059 .USER_CERTIFICATE + client); 3060 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 3061 "does not need" ) + " software key store"); 3062 } else { 3063 Slog.d(TAG, "could not generate certificate"); 3064 } 3065 } else { 3066 Slog.e(TAG, "Could not load client certificate " + Credentials 3067 .USER_CERTIFICATE + client); 3068 mNeedsSoftwareKeystore = true; 3069 } 3070 3071 } catch(CertificateException e) { 3072 Slog.e(TAG, "Could not read certificates"); 3073 mCaCert = null; 3074 mClientCertificate = null; 3075 } 3076 */ 3077 3078 return false; 3079 } 3080 3081 /** 3082 * Checks if the network is a sim config. 3083 * @param config Config corresponding to the network. 3084 * @return true if it is a sim config, false otherwise. 3085 */ 3086 public boolean isSimConfig(WifiConfiguration config) { 3087 return mWifiConfigStore.isSimConfig(config); 3088 } 3089 3090 /** 3091 * Resets all sim networks from the network list. 3092 */ 3093 public void resetSimNetworks() { 3094 mWifiConfigStore.resetSimNetworks(mConfiguredNetworks.valuesForCurrentUser()); 3095 } 3096 3097 boolean isNetworkConfigured(WifiConfiguration config) { 3098 // Check if either we have a network Id or a WifiConfiguration 3099 // matching the one we are trying to add. 3100 3101 if (config.networkId != INVALID_NETWORK_ID) { 3102 return (mConfiguredNetworks.getForCurrentUser(config.networkId) != null); 3103 } 3104 3105 return (mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()) != null); 3106 } 3107 3108 /** 3109 * Checks if uid has access to modify the configuration corresponding to networkId. 3110 * 3111 * The conditions checked are, in descending priority order: 3112 * - Disallow modification if the the configuration is not visible to the uid. 3113 * - Allow modification if the uid represents the Device Owner app. 3114 * - Allow modification if both of the following are true: 3115 * - The uid represents the configuration's creator or an app holding OVERRIDE_CONFIG_WIFI. 3116 * - The modification is only for administrative annotation (e.g. when connecting) or the 3117 * configuration is not lockdown eligible (which currently means that it was not last 3118 * updated by the DO). 3119 * - Allow modification if configuration lockdown is explicitly disabled and the uid represents 3120 * an app holding OVERRIDE_CONFIG_WIFI. 3121 * - In all other cases, disallow modification. 3122 */ 3123 boolean canModifyNetwork(int uid, int networkId, boolean onlyAnnotate) { 3124 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(networkId); 3125 3126 if (config == null) { 3127 loge("canModifyNetwork: cannot find config networkId " + networkId); 3128 return false; 3129 } 3130 3131 final DevicePolicyManagerInternal dpmi = LocalServices.getService( 3132 DevicePolicyManagerInternal.class); 3133 3134 final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid, 3135 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 3136 3137 if (isUidDeviceOwner) { 3138 return true; 3139 } 3140 3141 final boolean isCreator = (config.creatorUid == uid); 3142 3143 if (onlyAnnotate) { 3144 return isCreator || checkConfigOverridePermission(uid); 3145 } 3146 3147 // Check if device has DPM capability. If it has and dpmi is still null, then we 3148 // treat this case with suspicion and bail out. 3149 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) 3150 && dpmi == null) { 3151 return false; 3152 } 3153 3154 // WiFi config lockdown related logic. At this point we know uid NOT to be a Device Owner. 3155 3156 final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy( 3157 config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 3158 if (!isConfigEligibleForLockdown) { 3159 return isCreator || checkConfigOverridePermission(uid); 3160 } 3161 3162 final ContentResolver resolver = mContext.getContentResolver(); 3163 final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver, 3164 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; 3165 return !isLockdownFeatureEnabled && checkConfigOverridePermission(uid); 3166 } 3167 3168 /** 3169 * Checks if uid has access to modify config. 3170 */ 3171 boolean canModifyNetwork(int uid, WifiConfiguration config, boolean onlyAnnotate) { 3172 if (config == null) { 3173 loge("canModifyNetowrk recieved null configuration"); 3174 return false; 3175 } 3176 3177 // Resolve the correct network id. 3178 int netid; 3179 if (config.networkId != INVALID_NETWORK_ID) { 3180 netid = config.networkId; 3181 } else { 3182 WifiConfiguration test = 3183 mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 3184 if (test == null) { 3185 return false; 3186 } else { 3187 netid = test.networkId; 3188 } 3189 } 3190 3191 return canModifyNetwork(uid, netid, onlyAnnotate); 3192 } 3193 3194 boolean checkConfigOverridePermission(int uid) { 3195 try { 3196 return (mFacade.checkUidPermission( 3197 android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid) 3198 == PackageManager.PERMISSION_GRANTED); 3199 } catch (RemoteException e) { 3200 return false; 3201 } 3202 } 3203 3204 /** called when CS ask WiFistateMachine to disconnect the current network 3205 * because the score is bad. 3206 */ 3207 void handleBadNetworkDisconnectReport(int netId, WifiInfo info) { 3208 /* TODO verify the bad network is current */ 3209 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 3210 if (config != null) { 3211 if ((info.is24GHz() && info.getRssi() 3212 <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND) 3213 || (info.is5GHz() && info.getRssi() 3214 <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND)) { 3215 // We do not block due to bad RSSI since network selection should not select bad 3216 // RSSI candidate 3217 } else { 3218 // We got disabled but RSSI is good, so disable hard 3219 updateNetworkSelectionStatus(config, 3220 WifiConfiguration.NetworkSelectionStatus.DISABLED_BAD_LINK); 3221 } 3222 } 3223 // Record last time Connectivity Service switched us away from WiFi and onto Cell 3224 mLastUnwantedNetworkDisconnectTimestamp = System.currentTimeMillis(); 3225 } 3226 3227 int getMaxDhcpRetries() { 3228 return mFacade.getIntegerSetting(mContext, 3229 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 3230 DEFAULT_MAX_DHCP_RETRIES); 3231 } 3232 3233 void clearBssidBlacklist() { 3234 mWifiConfigStore.clearBssidBlacklist(); 3235 } 3236 3237 void blackListBssid(String bssid) { 3238 mWifiConfigStore.blackListBssid(bssid); 3239 } 3240 3241 public boolean isBssidBlacklisted(String bssid) { 3242 return mWifiConfigStore.isBssidBlacklisted(bssid); 3243 } 3244 3245 public boolean getEnableAutoJoinWhenAssociated() { 3246 return mEnableAutoJoinWhenAssociated.get(); 3247 } 3248 3249 public void enableAutoJoinWhenAssociated(boolean enabled) { 3250 mEnableAutoJoinWhenAssociated.set(enabled); 3251 } 3252} 3253