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