WifiConfigStore.java revision 7b6cd1fce7850fc2aa0e510b170e6fd509308d21
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.AppGlobals; 22import android.app.admin.DeviceAdminInfo; 23import android.app.admin.DevicePolicyManagerInternal; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.pm.ApplicationInfo; 28import android.content.pm.PackageManager; 29import android.net.IpConfiguration; 30import android.net.IpConfiguration.IpAssignment; 31import android.net.IpConfiguration.ProxySettings; 32import android.net.NetworkInfo.DetailedState; 33import android.net.ProxyInfo; 34import android.net.StaticIpConfiguration; 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.WifiSsid; 43import android.net.wifi.WpsInfo; 44import android.net.wifi.WpsResult; 45import android.os.Environment; 46import android.os.FileObserver; 47import android.os.Process; 48import android.os.RemoteException; 49import android.os.SystemClock; 50import android.os.UserHandle; 51import android.provider.Settings; 52import android.security.Credentials; 53import android.security.KeyChain; 54import android.security.KeyStore; 55import android.text.TextUtils; 56import android.util.ArraySet; 57import android.util.LocalLog; 58import android.util.Log; 59import android.util.SparseArray; 60 61import com.android.internal.R; 62import com.android.server.LocalServices; 63import com.android.server.net.DelayedDiskWrite; 64import com.android.server.net.IpConfigStore; 65import com.android.server.wifi.anqp.ANQPElement; 66import com.android.server.wifi.anqp.ANQPFactory; 67import com.android.server.wifi.anqp.Constants; 68import com.android.server.wifi.hotspot2.ANQPData; 69import com.android.server.wifi.hotspot2.AnqpCache; 70import com.android.server.wifi.hotspot2.IconEvent; 71import com.android.server.wifi.hotspot2.NetworkDetail; 72import com.android.server.wifi.hotspot2.PasspointMatch; 73import com.android.server.wifi.hotspot2.SupplicantBridge; 74import com.android.server.wifi.hotspot2.Utils; 75import com.android.server.wifi.hotspot2.omadm.MOManager; 76import com.android.server.wifi.hotspot2.osu.OSUInfo; 77import com.android.server.wifi.hotspot2.osu.OSUManager; 78import com.android.server.wifi.hotspot2.pps.Credential; 79import com.android.server.wifi.hotspot2.pps.HomeSP; 80 81import java.io.BufferedInputStream; 82import java.io.BufferedReader; 83import java.io.DataInputStream; 84import java.io.DataOutputStream; 85import java.io.EOFException; 86import java.io.File; 87import java.io.FileDescriptor; 88import java.io.FileInputStream; 89import java.io.FileNotFoundException; 90import java.io.FileReader; 91import java.io.IOException; 92import java.io.PrintWriter; 93import java.nio.charset.StandardCharsets; 94import java.security.PrivateKey; 95import java.security.cert.Certificate; 96import java.security.cert.CertificateException; 97import java.security.cert.X509Certificate; 98import java.text.DateFormat; 99import java.util.ArrayList; 100import java.util.Arrays; 101import java.util.BitSet; 102import java.util.Calendar; 103import java.util.Collection; 104import java.util.Collections; 105import java.util.Comparator; 106import java.util.Date; 107import java.util.HashMap; 108import java.util.HashSet; 109import java.util.List; 110import java.util.Map; 111import java.util.Objects; 112import java.util.Set; 113import java.util.concurrent.atomic.AtomicBoolean; 114import java.util.concurrent.atomic.AtomicInteger; 115import java.util.regex.Pattern; 116import java.util.zip.CRC32; 117import java.util.zip.Checksum; 118 119 120/** 121 * This class provides the API to manage configured 122 * wifi networks. The API is not thread safe is being 123 * used only from WifiStateMachine. 124 * 125 * It deals with the following 126 * - Add/update/remove a WifiConfiguration 127 * The configuration contains two types of information. 128 * = IP and proxy configuration that is handled by WifiConfigStore and 129 * is saved to disk on any change. 130 * 131 * The format of configuration file is as follows: 132 * <version> 133 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 134 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 135 * .. 136 * 137 * (key, value) pairs for a given network are grouped together and can 138 * be in any order. A EOS at the end of a set of (key, value) pairs 139 * indicates that the next set of (key, value) pairs are for a new 140 * network. A network is identified by a unique ID_KEY. If there is no 141 * ID_KEY in the (key, value) pairs, the data is discarded. 142 * 143 * An invalid version on read would result in discarding the contents of 144 * the file. On the next write, the latest version is written to file. 145 * 146 * Any failures during read or write to the configuration file are ignored 147 * without reporting to the user since the likelihood of these errors are 148 * low and the impact on connectivity is low. 149 * 150 * = SSID & security details that is pushed to the supplicant. 151 * supplicant saves these details to the disk on calling 152 * saveConfigCommand(). 153 * 154 * We have two kinds of APIs exposed: 155 * > public API calls that provide fine grained control 156 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 157 * removeNetwork(). For these calls, the config is not persisted 158 * to the disk. (TODO: deprecate these calls in WifiManager) 159 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 160 * These calls persist the supplicant config to disk. 161 * 162 * - Maintain a list of configured networks for quick access 163 * 164 */ 165public class WifiConfigStore extends IpConfigStore { 166 167 private Context mContext; 168 public static final String TAG = "WifiConfigStore"; 169 private static final boolean DBG = true; 170 private static boolean VDBG = false; 171 private static boolean VVDBG = false; 172 173 private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf"; 174 private static final String SUPPLICANT_CONFIG_FILE_BACKUP = SUPPLICANT_CONFIG_FILE + ".tmp"; 175 private static final String PPS_FILE = "/data/misc/wifi/PerProviderSubscription.conf"; 176 177 /* configured networks with network id as the key */ 178 private final ConfigurationMap mConfiguredNetworks = new ConfigurationMap(); 179 180 /* A network id is a unique identifier for a network configured in the 181 * supplicant. Network ids are generated when the supplicant reads 182 * the configuration file at start and can thus change for networks. 183 * We store the IP configuration for networks along with a unique id 184 * that is generated from SSID and security type of the network. A mapping 185 * from the generated unique id to network id of the network is needed to 186 * map supplicant config to IP configuration. */ 187 188 /* Stores a map of NetworkId to ScanCache */ 189 private HashMap<Integer, ScanDetailCache> mScanDetailCaches; 190 191 /** 192 * Framework keeps a list of (the CRC32 hashes of) all SSIDs that where deleted by user, 193 * so as, framework knows not to re-add those SSIDs automatically to the Saved networks 194 */ 195 private Set<Long> mDeletedSSIDs = new HashSet<Long>(); 196 197 /** 198 * Framework keeps a list of ephemeral SSIDs that where deleted by user, 199 * so as, framework knows not to autojoin again those SSIDs based on scorer input. 200 * The list is never cleared up. 201 * 202 * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. 203 */ 204 public Set<String> mDeletedEphemeralSSIDs = new HashSet<String>(); 205 206 /* Tracks the highest priority of configured networks */ 207 private int mLastPriority = -1; 208 209 private static final String ipConfigFile = Environment.getDataDirectory() + 210 "/misc/wifi/ipconfig.txt"; 211 212 private static final String networkHistoryConfigFile = Environment.getDataDirectory() + 213 "/misc/wifi/networkHistory.txt"; 214 215 private static final String autoJoinConfigFile = Environment.getDataDirectory() + 216 "/misc/wifi/autojoinconfig.txt"; 217 218 /* Network History Keys */ 219 private static final String SSID_KEY = "SSID"; 220 static final String CONFIG_KEY = "CONFIG"; 221 private static final String CONFIG_BSSID_KEY = "CONFIG_BSSID"; 222 private static final String CHOICE_KEY = "CHOICE"; 223 private static final String CHOICE_TIME_KEY = "CHOICE_TIME"; 224 private static final String LINK_KEY = "LINK"; 225 private static final String BSSID_KEY = "BSSID"; 226 private static final String BSSID_KEY_END = "/BSSID"; 227 private static final String RSSI_KEY = "RSSI"; 228 private static final String FREQ_KEY = "FREQ"; 229 private static final String DATE_KEY = "DATE"; 230 private static final String MILLI_KEY = "MILLI"; 231 private static final String BLACKLIST_MILLI_KEY = "BLACKLIST_MILLI"; 232 private static final String NETWORK_ID_KEY = "ID"; 233 private static final String PRIORITY_KEY = "PRIORITY"; 234 private static final String DEFAULT_GW_KEY = "DEFAULT_GW"; 235 private static final String AUTH_KEY = "AUTH"; 236 private static final String BSSID_STATUS_KEY = "BSSID_STATUS"; 237 private static final String SELF_ADDED_KEY = "SELF_ADDED"; 238 private static final String FAILURE_KEY = "FAILURE"; 239 private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD"; 240 private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION"; 241 static final String CREATOR_UID_KEY = "CREATOR_UID_KEY"; 242 private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY"; 243 private static final String UPDATE_UID_KEY = "UPDATE_UID"; 244 private static final String FQDN_KEY = "FQDN"; 245 private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE"; 246 private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH"; 247 private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS"; 248 private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS"; 249 private static final String EPHEMERAL_KEY = "EPHEMERAL"; 250 private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION"; 251 private static final String DELETED_CRC32_KEY = "DELETED_CRC32"; 252 private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL"; 253 private static final String CREATOR_NAME_KEY = "CREATOR_NAME"; 254 private static final String UPDATE_NAME_KEY = "UPDATE_NAME"; 255 private static final String USER_APPROVED_KEY = "USER_APPROVED"; 256 private static final String CREATION_TIME_KEY = "CREATION_TIME"; 257 private static final String UPDATE_TIME_KEY = "UPDATE_TIME"; 258 static final String SHARED_KEY = "SHARED"; 259 260 private static final String SEPARATOR = ": "; 261 private static final String NL = "\n"; 262 263 private static final String THRESHOLD_GOOD_RSSI_5_KEY 264 = "THRESHOLD_GOOD_RSSI_5"; 265 private static final String THRESHOLD_LOW_RSSI_5_KEY 266 = "THRESHOLD_LOW_RSSI_5"; 267 private static final String THRESHOLD_BAD_RSSI_5_KEY 268 = "THRESHOLD_BAD_RSSI_5"; 269 private static final String THRESHOLD_GOOD_RSSI_24_KEY 270 = "THRESHOLD_GOOD_RSSI_24"; 271 private static final String THRESHOLD_LOW_RSSI_24_KEY 272 = "THRESHOLD_LOW_RSSI_24"; 273 private static final String THRESHOLD_BAD_RSSI_24_KEY 274 = "THRESHOLD_BAD_RSSI_24"; 275 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY 276 = "THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING"; 277 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY 278 = "THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING"; 279 280 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY 281 = "THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS"; 282 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY 283 = "THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS"; 284 285 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY 286 = "THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS"; 287 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY 288 = "THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS"; 289 290 private static final String MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY 291 = "MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS"; 292 private static final String MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY 293 = "MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS"; 294 295 private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW_KEY = 296 "A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW"; 297 private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY = 298 "A_BAND_PREFERENCE_RSSI_THRESHOLD"; 299 private static final String G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY = 300 "G_BAND_PREFERENCE_RSSI_THRESHOLD"; 301 302 private static final String ENABLE_AUTOJOIN_WHILE_ASSOCIATED_KEY 303 = "ENABLE_AUTOJOIN_WHILE_ASSOCIATED: "; 304 305 private static final String ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY 306 = "ASSOCIATED_PARTIAL_SCAN_PERIOD"; 307 private static final String ASSOCIATED_FULL_SCAN_BACKOFF_KEY 308 = "ASSOCIATED_FULL_SCAN_BACKOFF_PERIOD"; 309 private static final String ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY 310 = "ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED"; 311 private static final String ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS_KEY 312 = "ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS"; 313 314 private static final String ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY 315 = "ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED"; 316 317 private static final String ENABLE_HAL_BASED_PNO 318 = "ENABLE_HAL_BASED_PNO"; 319 320 // The three below configurations are mainly for power stats and CPU usage tracking 321 // allowing to incrementally disable framework features 322 private static final String ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY 323 = "ENABLE_AUTO_JOIN_WHILE_ASSOCIATED"; 324 private static final String ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY 325 = "ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED"; 326 private static final String ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY 327 = "ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY"; 328 329 // This is the only variable whose contents will not be interpreted by wpa_supplicant. We use it 330 // to store metadata that allows us to correlate a wpa_supplicant.conf entry with additional 331 // information about the same network stored in other files. The metadata is stored as a 332 // serialized JSON dictionary. 333 public static final String ID_STRING_VAR_NAME = "id_str"; 334 public static final String ID_STRING_KEY_FQDN = "fqdn"; 335 public static final String ID_STRING_KEY_CREATOR_UID = "creatorUid"; 336 public static final String ID_STRING_KEY_CONFIG_KEY = "configKey"; 337 338 // The Wifi verbose log is provided as a way to persist the verbose logging settings 339 // for testing purpose. 340 // It is not intended for normal use. 341 private static final String WIFI_VERBOSE_LOGS_KEY 342 = "WIFI_VERBOSE_LOGS"; 343 344 // As we keep deleted PSK WifiConfiguration for a while, the PSK of 345 // those deleted WifiConfiguration is set to this random unused PSK 346 private static final String DELETED_CONFIG_PSK = "Mjkd86jEMGn79KhKll298Uu7-deleted"; 347 348 /** 349 * The threshold for each kind of error. If a network continuously encounter the same error more 350 * than the threshold times, this network will be disabled. -1 means unavailable. 351 */ 352 private static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = { 353 -1, // threshold for NETWORK_SELECTION_ENABLE 354 1, // threshold for DISABLED_BAD_LINK 355 5, // threshold for DISABLED_ASSOCIATION_REJECTION 356 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 357 5, // threshold for DISABLED_DHCP_FAILURE 358 5, // threshold for DISABLED_DNS_FAILURE 359 6, // threshold for DISABLED_TLS_VERSION_MISMATCH 360 1, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 361 1, // threshold for DISABLED_NO_INTERNET 362 1 // threshold for DISABLED_BY_WIFI_MANAGER 363 }; 364 365 /** 366 * Timeout for each kind of error. After the timeout minutes, unblock the network again. 367 */ 368 private static final int[] NETWORK_SELECTION_DISABLE_TIMEOUT = { 369 Integer.MAX_VALUE, // threshold for NETWORK_SELECTION_ENABLE 370 15, // threshold for DISABLED_BAD_LINK 371 5, // threshold for DISABLED_ASSOCIATION_REJECTION 372 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 373 5, // threshold for DISABLED_DHCP_FAILURE 374 5, // threshold for DISABLED_DNS_FAILURE 375 Integer.MAX_VALUE, // threshold for DISABLED_TLS_VERSION 376 Integer.MAX_VALUE, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 377 Integer.MAX_VALUE, // threshold for DISABLED_NO_INTERNET 378 Integer.MAX_VALUE // threshold for DISABLED_BY_WIFI_MANAGER 379 }; 380 381 public int maxTxPacketForFullScans = 8; 382 public int maxRxPacketForFullScans = 16; 383 384 public int maxTxPacketForPartialScans = 40; 385 public int maxRxPacketForPartialScans = 80; 386 387 public int associatedFullScanMaxIntervalMilli = 300000; 388 389 // Sane value for roam blacklisting (not switching to a network if already associated) 390 // 2 days 391 public int networkSwitchingBlackListPeriodMilli = 2 * 24 * 60 * 60 * 1000; 392 393 public int badLinkSpeed24 = 6; 394 public int badLinkSpeed5 = 12; 395 public int goodLinkSpeed24 = 24; 396 public int goodLinkSpeed5 = 36; 397 398 public int maxAuthErrorsToBlacklist = 4; 399 public int maxConnectionErrorsToBlacklist = 4; 400 public int wifiConfigBlacklistMinTimeMilli = 1000 * 60 * 5; 401 402 // How long a disconnected config remain considered as the last user selection 403 public int wifiConfigLastSelectionHysteresis = 1000 * 60 * 3; 404 405 // Boost RSSI values of associated networks 406 public int associatedHysteresisHigh = +14; 407 public int associatedHysteresisLow = +8; 408 409 boolean showNetworks = true; // TODO set this back to false, used for debugging 17516271 410 411 public boolean roamOnAny = false; 412 public boolean onlyLinkSameCredentialConfigurations = true; 413 414 public boolean enableLinkDebouncing = true; 415 public boolean enable5GHzPreference = true; 416 public boolean enableWifiCellularHandoverUserTriggeredAdjustment = true; 417 418 public static final int maxNumScanCacheEntries = 128; 419 420 public final AtomicBoolean enableHalBasedPno = new AtomicBoolean(false); 421 public final AtomicBoolean enableSsidWhitelist = new AtomicBoolean(false); 422 public final AtomicBoolean enableAutoJoinWhenAssociated = new AtomicBoolean(true); 423 public final AtomicBoolean enableFullBandScanWhenAssociated = new AtomicBoolean(true); 424 public final AtomicBoolean enableChipWakeUpWhenAssociated = new AtomicBoolean(true); 425 public final AtomicBoolean enableRssiPollWhenAssociated = new AtomicBoolean(true); 426 public AtomicInteger thresholdSaturatedRssi5 = new AtomicInteger( 427 WifiQualifiedNetworkSelector.RSSI_SATURATION_5G_BAND); 428 public AtomicInteger thresholdQualifiedRssi5 = new AtomicInteger( 429 WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND); 430 public AtomicInteger thresholdMinimumRssi5 = new AtomicInteger( 431 WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI); 432 public AtomicInteger thresholdSaturatedRssi24 = new AtomicInteger( 433 WifiQualifiedNetworkSelector.RSSI_SATURATION_2G_BAND); 434 public AtomicInteger thresholdQualifiedRssi24 = new AtomicInteger( 435 WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND); 436 public AtomicInteger thresholdMinimumRssi24 = new AtomicInteger( 437 WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI); 438 public final AtomicInteger maxTxPacketForNetworkSwitching = new AtomicInteger(40); 439 public final AtomicInteger maxRxPacketForNetworkSwitching = new AtomicInteger(80); 440 public final AtomicInteger enableVerboseLogging = new AtomicInteger(0); 441 public final AtomicInteger associatedFullScanBackoff = 442 new AtomicInteger(12); // Will be divided by 8 by WifiStateMachine 443 public final AtomicInteger alwaysEnableScansWhileAssociated = new AtomicInteger(0); 444 public final AtomicInteger maxNumPassiveChannelsForPartialScans = new AtomicInteger(2); 445 public final AtomicInteger maxNumActiveChannelsForPartialScans = new AtomicInteger(6); 446 public final AtomicInteger wifiDisconnectedShortScanIntervalMilli = new AtomicInteger(15000); 447 public final AtomicInteger wifiDisconnectedLongScanIntervalMilli = new AtomicInteger(120000); 448 public final AtomicInteger wifiAssociatedShortScanIntervalMilli = new AtomicInteger(20000); 449 public final AtomicInteger wifiAssociatedLongScanIntervalMilli = new AtomicInteger(180000); 450 public AtomicInteger currentNetworkBoost = new AtomicInteger( 451 WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD); 452 public AtomicInteger bandAward5Ghz = new AtomicInteger( 453 WifiQualifiedNetworkSelector.BAND_AWARD_5GHz); 454 private static final Map<String, Object> sKeyMap = new HashMap<>(); 455 456 /** 457 * Regex pattern for extracting a connect choice. 458 * Matches a strings like the following: 459 * <configKey>=([0:9]+) 460 */ 461 private static Pattern mConnectChoice = 462 Pattern.compile("(.*)=([0-9]+)"); 463 464 465 /* Enterprise configuration keys */ 466 /** 467 * In old configurations, the "private_key" field was used. However, newer 468 * configurations use the key_id field with the engine_id set to "keystore". 469 * If this field is found in the configuration, the migration code is 470 * triggered. 471 */ 472 public static final String OLD_PRIVATE_KEY_NAME = "private_key"; 473 474 /** 475 * This represents an empty value of an enterprise field. 476 * NULL is used at wpa_supplicant to indicate an empty value 477 */ 478 static final String EMPTY_VALUE = "NULL"; 479 480 // Internal use only 481 private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { 482 WifiEnterpriseConfig.EAP_KEY, WifiEnterpriseConfig.PHASE2_KEY, 483 WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.ANON_IDENTITY_KEY, 484 WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY, 485 WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY, 486 WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY, 487 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, 488 WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY 489 }; 490 491 492 /** 493 * If Connectivity Service has triggered an unwanted network disconnect 494 */ 495 public long lastUnwantedNetworkDisconnectTimestamp = 0; 496 497 /** 498 * The maximum number of times we will retry a connection to an access point 499 * for which we have failed in acquiring an IP address from DHCP. A value of 500 * N means that we will make N+1 connection attempts in all. 501 * <p> 502 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 503 * value if a Settings value is not present. 504 */ 505 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 506 507 508 private final LocalLog mLocalLog; 509 private final WpaConfigFileObserver mFileObserver; 510 511 private WifiNative mWifiNative; 512 private final KeyStore mKeyStore = KeyStore.getInstance(); 513 514 /** 515 * The lastSelectedConfiguration is used to remember which network 516 * was selected last by the user. 517 * The connection to this network may not be successful, as well 518 * the selection (i.e. network priority) might not be persisted. 519 * WiFi state machine is the only object that sets this variable. 520 */ 521 private String lastSelectedConfiguration = null; 522 private long mLastSelectedTimeStamp = 523 WifiConfiguration.NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP; 524 525 /** 526 * Cached PNO list, it is updated when WifiConfiguration changes due to user input. 527 */ 528 ArrayList<WifiNative.WifiPnoNetwork> mCachedPnoList 529 = new ArrayList<WifiNative.WifiPnoNetwork>(); 530 531 /* 532 * BSSID blacklist, i.e. list of BSSID we want to avoid 533 */ 534 HashSet<String> mBssidBlacklist = new HashSet<String>(); 535 536 /* 537 * Lost config list, whenever we read a config from networkHistory.txt that was not in 538 * wpa_supplicant.conf 539 */ 540 HashSet<String> mLostConfigsDbg = new HashSet<String>(); 541 542 private final AnqpCache mAnqpCache; 543 private final SupplicantBridge mSupplicantBridge; 544 private final MOManager mMOManager; 545 private final SIMAccessor mSIMAccessor; 546 private final OSUManager mOSUManager; 547 548 private WifiStateMachine mWifiStateMachine; 549 private FrameworkFacade mFacade; 550 551 WifiConfigStore(Context c, WifiStateMachine w, WifiNative wn, FrameworkFacade f) { 552 mContext = c; 553 mFacade = f; 554 mWifiNative = wn; 555 mWifiStateMachine = w; 556 557 // A map for value setting in readAutoJoinConfig() - replacing the replicated code. 558 sKeyMap.put(ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY, enableAutoJoinWhenAssociated); 559 sKeyMap.put(ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY, enableFullBandScanWhenAssociated); 560 sKeyMap.put(ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY, enableChipWakeUpWhenAssociated); 561 sKeyMap.put(ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY, enableRssiPollWhenAssociated); 562 sKeyMap.put(THRESHOLD_GOOD_RSSI_5_KEY, thresholdSaturatedRssi5); 563 sKeyMap.put(THRESHOLD_LOW_RSSI_5_KEY, thresholdQualifiedRssi5); 564 sKeyMap.put(THRESHOLD_BAD_RSSI_5_KEY, thresholdMinimumRssi5); 565 sKeyMap.put(THRESHOLD_GOOD_RSSI_24_KEY, thresholdSaturatedRssi24); 566 sKeyMap.put(THRESHOLD_LOW_RSSI_24_KEY, thresholdQualifiedRssi24); 567 sKeyMap.put(THRESHOLD_BAD_RSSI_24_KEY, thresholdMinimumRssi24); 568 sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY, 569 maxTxPacketForNetworkSwitching); 570 sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY, 571 maxRxPacketForNetworkSwitching); 572 sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY, maxTxPacketForNetworkSwitching); 573 sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY, maxRxPacketForNetworkSwitching); 574 sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY, maxTxPacketForNetworkSwitching); 575 sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY, maxRxPacketForNetworkSwitching); 576 sKeyMap.put(WIFI_VERBOSE_LOGS_KEY, enableVerboseLogging); 577 sKeyMap.put(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY, wifiAssociatedShortScanIntervalMilli); 578 sKeyMap.put(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY, wifiAssociatedShortScanIntervalMilli); 579 580 sKeyMap.put(ASSOCIATED_FULL_SCAN_BACKOFF_KEY, associatedFullScanBackoff); 581 sKeyMap.put(ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY, alwaysEnableScansWhileAssociated); 582 sKeyMap.put(MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, 583 maxNumPassiveChannelsForPartialScans); 584 sKeyMap.put(MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, 585 maxNumActiveChannelsForPartialScans); 586 sKeyMap.put(ENABLE_HAL_BASED_PNO, enableHalBasedPno); 587 sKeyMap.put(ENABLE_HAL_BASED_PNO, enableSsidWhitelist); 588 589 if (showNetworks) { 590 mLocalLog = mWifiNative.getLocalLog(); 591 mFileObserver = new WpaConfigFileObserver(); 592 mFileObserver.startWatching(); 593 } else { 594 mLocalLog = null; 595 mFileObserver = null; 596 } 597 598 wifiAssociatedShortScanIntervalMilli.set(mContext.getResources().getInteger( 599 R.integer.config_wifi_associated_short_scan_interval)); 600 wifiAssociatedLongScanIntervalMilli.set(mContext.getResources().getInteger( 601 R.integer.config_wifi_associated_short_scan_interval)); 602 wifiDisconnectedShortScanIntervalMilli.set(mContext.getResources().getInteger( 603 R.integer.config_wifi_disconnected_short_scan_interval)); 604 wifiDisconnectedLongScanIntervalMilli.set(mContext.getResources().getInteger( 605 R.integer.config_wifi_disconnected_long_scan_interval)); 606 607 onlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean( 608 R.bool.config_wifi_only_link_same_credential_configurations); 609 maxNumActiveChannelsForPartialScans.set(mContext.getResources().getInteger( 610 R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels)); 611 maxNumPassiveChannelsForPartialScans.set(mContext.getResources().getInteger( 612 R.integer.config_wifi_framework_associated_partial_scan_max_num_passive_channels)); 613 associatedFullScanMaxIntervalMilli = mContext.getResources().getInteger( 614 R.integer.config_wifi_framework_associated_full_scan_max_interval); 615 associatedFullScanBackoff.set(mContext.getResources().getInteger( 616 R.integer.config_wifi_framework_associated_full_scan_backoff)); 617 enableLinkDebouncing = mContext.getResources().getBoolean( 618 R.bool.config_wifi_enable_disconnection_debounce); 619 620 enable5GHzPreference = mContext.getResources().getBoolean( 621 R.bool.config_wifi_enable_5GHz_preference); 622 623 bandAward5Ghz.set(mContext.getResources().getInteger( 624 R.integer.config_wifi_framework_5GHz_preference_boost_factor)); 625 626 associatedHysteresisHigh = mContext.getResources().getInteger( 627 R.integer.config_wifi_framework_current_association_hysteresis_high); 628 associatedHysteresisLow = mContext.getResources().getInteger( 629 R.integer.config_wifi_framework_current_association_hysteresis_low); 630 631 thresholdMinimumRssi5.set(mContext.getResources().getInteger( 632 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz)); 633 thresholdQualifiedRssi5.set(mContext.getResources().getInteger( 634 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz)); 635 thresholdSaturatedRssi5.set(mContext.getResources().getInteger( 636 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz)); 637 thresholdMinimumRssi24.set(mContext.getResources().getInteger( 638 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz)); 639 thresholdQualifiedRssi24.set(mContext.getResources().getInteger( 640 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz)); 641 thresholdSaturatedRssi24.set(mContext.getResources().getInteger( 642 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)); 643 644 enableWifiCellularHandoverUserTriggeredAdjustment = mContext.getResources().getBoolean( 645 R.bool.config_wifi_framework_cellular_handover_enable_user_triggered_adjustment); 646 647 badLinkSpeed24 = mContext.getResources().getInteger( 648 R.integer.config_wifi_framework_wifi_score_bad_link_speed_24); 649 badLinkSpeed5 = mContext.getResources().getInteger( 650 R.integer.config_wifi_framework_wifi_score_bad_link_speed_5); 651 goodLinkSpeed24 = mContext.getResources().getInteger( 652 R.integer.config_wifi_framework_wifi_score_good_link_speed_24); 653 goodLinkSpeed5 = mContext.getResources().getInteger( 654 R.integer.config_wifi_framework_wifi_score_good_link_speed_5); 655 656 maxAuthErrorsToBlacklist = mContext.getResources().getInteger( 657 R.integer.config_wifi_framework_max_auth_errors_to_blacklist); 658 maxConnectionErrorsToBlacklist = mContext.getResources().getInteger( 659 R.integer.config_wifi_framework_max_connection_errors_to_blacklist); 660 wifiConfigBlacklistMinTimeMilli = mContext.getResources().getInteger( 661 R.integer.config_wifi_framework_network_black_list_min_time_milli); 662 663 enableAutoJoinWhenAssociated.set(mContext.getResources().getBoolean( 664 R.bool.config_wifi_framework_enable_associated_network_selection)); 665 666 currentNetworkBoost.set(mContext.getResources().getInteger( 667 R.integer.config_wifi_framework_current_network_boost)); 668 networkSwitchingBlackListPeriodMilli = mContext.getResources().getInteger( 669 R.integer.config_wifi_network_switching_blacklist_time); 670 671 enableHalBasedPno.set(mContext.getResources().getBoolean( 672 R.bool.config_wifi_hal_pno_enable)); 673 674 enableSsidWhitelist.set(mContext.getResources().getBoolean( 675 R.bool.config_wifi_ssid_white_list_enable)); 676 if (!enableHalBasedPno.get() && enableSsidWhitelist.get()) { 677 enableSsidWhitelist.set(false); 678 } 679 680 boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled); 681 Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled")); 682 683 mMOManager = new MOManager(new File(PPS_FILE), hs2on); 684 mAnqpCache = new AnqpCache(); 685 mSupplicantBridge = new SupplicantBridge(mWifiNative, this); 686 mScanDetailCaches = new HashMap<>(); 687 mOSUManager = mFacade.makeOsuManager( 688 this, mContext, mSupplicantBridge, mMOManager, mWifiStateMachine); 689 690 mSIMAccessor = new SIMAccessor(mContext); 691 692 if (OSUManager.R2_TEST) { 693 mOSUManager.addMockOSUEnvironment(mOSUManager); 694 } 695 } 696 697 public void trimANQPCache(boolean all) { 698 mAnqpCache.clear(all, DBG); 699 mOSUManager.tickleIconCache(all); 700 } 701 702 void enableVerboseLogging(int verbose) { 703 enableVerboseLogging.set(verbose); 704 if (verbose > 0) { 705 VDBG = true; 706 showNetworks = true; 707 } else { 708 VDBG = false; 709 } 710 if (verbose > 1) { 711 VVDBG = true; 712 } else { 713 VVDBG = false; 714 } 715 } 716 717 class WpaConfigFileObserver extends FileObserver { 718 719 public WpaConfigFileObserver() { 720 super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE); 721 } 722 723 @Override 724 public void onEvent(int event, String path) { 725 if (event == CLOSE_WRITE) { 726 File file = new File(SUPPLICANT_CONFIG_FILE); 727 if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length()); 728 } 729 } 730 } 731 732 733 /** 734 * Fetch the list of configured networks 735 * and enable all stored networks in supplicant. 736 */ 737 void loadAndEnableAllNetworks() { 738 if (DBG) log("Loading config and enabling all networks "); 739 loadConfiguredNetworks(); 740 enableAllNetworks(); 741 } 742 743 int getConfiguredNetworksSize() { 744 return mConfiguredNetworks.sizeForCurrentUser(); 745 } 746 747 private List<WifiConfiguration> 748 getConfiguredNetworks(Map<String, String> pskMap) { 749 List<WifiConfiguration> networks = new ArrayList<>(); 750 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 751 WifiConfiguration newConfig = new WifiConfiguration(config); 752 // When updating this condition, update WifiStateMachine's CONNECT_NETWORK handler to 753 // correctly handle updating existing configs that are filtered out here. 754 if (config.ephemeral) { 755 // Do not enumerate and return this configuration to any one, 756 // for instance WiFi Picker. 757 // instead treat it as unknown. the configuration can still be retrieved 758 // directly by the key or networkId 759 continue; 760 } 761 762 if (pskMap != null && config.allowedKeyManagement != null 763 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 764 && pskMap.containsKey(config.SSID)) { 765 newConfig.preSharedKey = pskMap.get(config.SSID); 766 } 767 networks.add(newConfig); 768 } 769 return networks; 770 } 771 772 /** 773 * This function returns all configuration, and is used for cebug and creating bug reports. 774 */ 775 private List<WifiConfiguration> 776 getAllConfiguredNetworks() { 777 List<WifiConfiguration> networks = new ArrayList<>(); 778 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 779 WifiConfiguration newConfig = new WifiConfiguration(config); 780 networks.add(newConfig); 781 } 782 return networks; 783 } 784 785 /** 786 * Fetch the list of currently configured networks 787 * @return List of networks 788 */ 789 public List<WifiConfiguration> getConfiguredNetworks() { 790 return getConfiguredNetworks(null); 791 } 792 793 /** 794 * Fetch the list of currently configured networks, filled with real preSharedKeys 795 * @return List of networks 796 */ 797 List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 798 Map<String, String> pskMap = getCredentialsBySsidMap(); 799 return getConfiguredNetworks(pskMap); 800 } 801 802 /** 803 * Find matching network for this scanResult 804 */ 805 WifiConfiguration getMatchingConfig(ScanResult scanResult) { 806 807 for (Map.Entry entry : mScanDetailCaches.entrySet()) { 808 Integer netId = (Integer) entry.getKey(); 809 ScanDetailCache cache = (ScanDetailCache) entry.getValue(); 810 WifiConfiguration config = getWifiConfiguration(netId); 811 if (config == null) 812 continue; 813 if (cache.get(scanResult.BSSID) != null) { 814 return config; 815 } 816 } 817 818 return null; 819 } 820 821 /** 822 * Fetch the preSharedKeys for all networks. 823 * @return a map from Ssid to preSharedKey. 824 */ 825 private Map<String, String> getCredentialsBySsidMap() { 826 return readNetworkVariablesFromSupplicantFile("psk"); 827 } 828 829 /** 830 * Fetch the list of currently configured networks that were recently seen 831 * 832 * @return List of networks 833 */ 834 List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) { 835 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 836 837 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 838 if (config.ephemeral) { 839 // Do not enumerate and return this configuration to any one, 840 // instead treat it as unknown. the configuration can still be retrieved 841 // directly by the key or networkId 842 continue; 843 } 844 845 // Calculate the RSSI for scan results that are more recent than milli 846 ScanDetailCache cache = getScanDetailCache(config); 847 if (cache == null) { 848 continue; 849 } 850 config.setVisibility(cache.getVisibility(milli)); 851 if (config.visibility == null) { 852 continue; 853 } 854 if (config.visibility.rssi5 == WifiConfiguration.INVALID_RSSI && 855 config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { 856 continue; 857 } 858 if (copy) { 859 networks.add(new WifiConfiguration(config)); 860 } else { 861 networks.add(config); 862 } 863 } 864 return networks; 865 } 866 867 /** 868 * Update the configuration and BSSID with latest RSSI value. 869 */ 870 void updateConfiguration(WifiInfo info) { 871 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 872 if (config != null && getScanDetailCache(config) != null) { 873 ScanDetail scanDetail = getScanDetailCache(config).getScanDetail(info.getBSSID()); 874 if (scanDetail != null) { 875 ScanResult result = scanDetail.getScanResult(); 876 long previousSeen = result.seen; 877 int previousRssi = result.level; 878 879 // Update the scan result 880 scanDetail.setSeen(); 881 result.level = info.getRssi(); 882 883 // Average the RSSI value 884 result.averageRssi(previousRssi, previousSeen, 885 WifiQualifiedNetworkSelector.SCAN_RESULT_MAXIMUNM_AGE); 886 if (VDBG) { 887 loge("updateConfiguration freq=" + result.frequency 888 + " BSSID=" + result.BSSID 889 + " RSSI=" + result.level 890 + " " + config.configKey()); 891 } 892 } 893 } 894 } 895 896 /** 897 * get the Wificonfiguration for this netId 898 * 899 * @return Wificonfiguration 900 */ 901 public WifiConfiguration getWifiConfiguration(int netId) { 902 return mConfiguredNetworks.getForCurrentUser(netId); 903 } 904 905 /** 906 * Get the Wificonfiguration for this key 907 * @return Wificonfiguration 908 */ 909 public WifiConfiguration getWifiConfiguration(String key) { 910 return mConfiguredNetworks.getByConfigKeyForCurrentUser(key); 911 } 912 913 /** 914 * Enable all networks (if disabled time expire) and save config. This will be a no-op if the 915 * list of configured networks indicates all networks as being enabled 916 */ 917 void enableAllNetworks() { 918 boolean networkEnabledStateChanged = false; 919 920 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 921 if (config != null && !config.ephemeral 922 && !config.getNetworkSelectionStatus().isNetworkEnabled()) { 923 if (tryEnableQualifiedNetwork(config)) { 924 networkEnabledStateChanged = true; 925 } 926 } 927 } 928 929 if (networkEnabledStateChanged) { 930 mWifiNative.saveConfig(); 931 sendConfiguredNetworksChangedBroadcast(); 932 } 933 } 934 935 private boolean setNetworkPriorityNative(int netId, int priority) { 936 return mWifiNative.setNetworkVariable(netId, 937 WifiConfiguration.priorityVarName, Integer.toString(priority)); 938 } 939 940 private boolean setSSIDNative(int netId, String ssid) { 941 return mWifiNative.setNetworkVariable(netId, WifiConfiguration.ssidVarName, 942 encodeSSID(ssid)); 943 } 944 945 public boolean updateLastConnectUid(WifiConfiguration config, int uid) { 946 if (config != null) { 947 if (config.lastConnectUid != uid) { 948 config.lastConnectUid = uid; 949 return true; 950 } 951 } 952 return false; 953 } 954 955 /** 956 * Selects the specified network for connection. This involves 957 * updating the priority of all the networks and enabling the given 958 * network while disabling others. 959 * 960 * Selecting a network will leave the other networks disabled and 961 * a call to enableAllNetworks() needs to be issued upon a connection 962 * or a failure event from supplicant 963 * 964 * @param config network to select for connection 965 * @param updatePriorities makes config highest priority network 966 * @return false if the network id is invalid 967 */ 968 boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) { 969 if (VDBG) localLogNetwork("selectNetwork", config.networkId); 970 if (config.networkId == INVALID_NETWORK_ID) return false; 971 if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { 972 loge("selectNetwork " + Integer.toString(config.networkId) + ": Network config is not " 973 + "visible to current user."); 974 return false; 975 } 976 977 // Reset the priority of each network at start or if it goes too high. 978 if (mLastPriority == -1 || mLastPriority > 1000000) { 979 for (WifiConfiguration config2 : mConfiguredNetworks.valuesForCurrentUser()) { 980 if (updatePriorities) { 981 if (config2.networkId != INVALID_NETWORK_ID) { 982 config2.priority = 0; 983 setNetworkPriorityNative(config2.networkId, config.priority); 984 } 985 } 986 } 987 mLastPriority = 0; 988 } 989 990 // Set to the highest priority and save the configuration. 991 if (updatePriorities) { 992 config.priority = ++mLastPriority; 993 setNetworkPriorityNative(config.networkId, config.priority); 994 buildPnoList(); 995 } 996 997 if (config.isPasspoint()) { 998 /* need to slap on the SSID of selected bssid to work */ 999 if (getScanDetailCache(config).size() != 0) { 1000 ScanDetail result = getScanDetailCache(config).getFirst(); 1001 if (result == null) { 1002 loge("Could not find scan result for " + config.BSSID); 1003 } else { 1004 log("Setting SSID for " + config.networkId + " to" + result.getSSID()); 1005 setSSIDNative(config.networkId, result.getSSID()); 1006 config.SSID = result.getSSID(); 1007 } 1008 1009 } else { 1010 loge("Could not find bssid for " + config); 1011 } 1012 } 1013 1014 mWifiNative.setHs20(config.isPasspoint()); 1015 1016 if (updatePriorities) 1017 mWifiNative.saveConfig(); 1018 else 1019 mWifiNative.selectNetwork(config.networkId); 1020 1021 updateLastConnectUid(config, uid); 1022 writeKnownNetworkHistory(); 1023 1024 /* Enable the given network while disabling all other networks */ 1025 enableNetworkWithoutBroadcast(config.networkId, true); 1026 1027 /* Avoid saving the config & sending a broadcast to prevent settings 1028 * from displaying a disabled list of networks */ 1029 return true; 1030 } 1031 1032 /** 1033 * Add/update the specified configuration and save config 1034 * 1035 * @param config WifiConfiguration to be saved 1036 * @return network update result 1037 */ 1038 NetworkUpdateResult saveNetwork(WifiConfiguration config, int uid) { 1039 WifiConfiguration conf; 1040 1041 // A new network cannot have null SSID 1042 if (config == null || (config.networkId == INVALID_NETWORK_ID && 1043 config.SSID == null)) { 1044 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1045 } 1046 1047 if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { 1048 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1049 } 1050 1051 if (VDBG) localLogNetwork("WifiConfigStore: saveNetwork netId", config.networkId); 1052 if (VDBG) { 1053 logd("WifiConfigStore saveNetwork," 1054 + " size=" + Integer.toString(mConfiguredNetworks.sizeForAllUsers()) 1055 + " (for all users)" 1056 + " SSID=" + config.SSID 1057 + " Uid=" + Integer.toString(config.creatorUid) 1058 + "/" + Integer.toString(config.lastUpdateUid)); 1059 } 1060 1061 if (mDeletedEphemeralSSIDs.remove(config.SSID)) { 1062 if (VDBG) { 1063 loge("WifiConfigStore: removed from ephemeral blacklist: " + config.SSID); 1064 } 1065 // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call 1066 // below, since we're creating/modifying a config. 1067 } 1068 1069 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 1070 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 1071 int netId = result.getNetworkId(); 1072 1073 if (VDBG) localLogNetwork("WifiConfigStore: saveNetwork got it back netId=", netId); 1074 1075 /* enable a new network */ 1076 if (newNetwork && netId != INVALID_NETWORK_ID) { 1077 if (VDBG) localLogNetwork("WifiConfigStore: will enable netId=", netId); 1078 1079 mWifiNative.enableNetwork(netId, false); 1080 conf = mConfiguredNetworks.getForCurrentUser(netId); 1081 if (conf != null) 1082 conf.status = Status.ENABLED; 1083 } 1084 1085 conf = mConfiguredNetworks.getForCurrentUser(netId); 1086 if (conf != null) { 1087 if (!conf.getNetworkSelectionStatus().isNetworkEnabled()) { 1088 if (VDBG) localLog("WifiConfigStore: re-enabling: " + conf.SSID); 1089 1090 // reenable autojoin, since new information has been provided 1091 updateNetworkSelectionStatus(netId, 1092 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1093 enableNetworkWithoutBroadcast(conf.networkId, false); 1094 } 1095 if (VDBG) { 1096 loge("WifiConfigStore: saveNetwork got config back netId=" 1097 + Integer.toString(netId) 1098 + " uid=" + Integer.toString(config.creatorUid)); 1099 } 1100 } 1101 1102 mWifiNative.saveConfig(); 1103 sendConfiguredNetworksChangedBroadcast(conf, result.isNewNetwork() ? 1104 WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1105 return result; 1106 } 1107 1108 /** 1109 * Firmware is roaming away from this BSSID, and this BSSID was on 5GHz, and it's RSSI was good, 1110 * this means we have a situation where we would want to remain on this BSSID but firmware 1111 * is not successful at it. 1112 * This situation is observed on a small number of Access Points, b/17960587 1113 * In that situation, blacklist this BSSID really hard so as framework will not attempt to 1114 * roam to it for the next 8 hours. We do not to keep flipping between 2.4 and 5GHz band.. 1115 * TODO: review the blacklisting strategy so as to make it softer and adaptive 1116 * @param info 1117 */ 1118 void driverRoamedFrom(WifiInfo info) { 1119 if (info != null && info.getBSSID() != null && ScanResult.is5GHz(info.getFrequency()) 1120 && info.getRssi() > (thresholdSaturatedRssi5.get())) { 1121 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 1122 if (config != null) { 1123 if (getScanDetailCache(config) != null) { 1124 ScanResult result = getScanDetailCache(config).get(info.getBSSID()); 1125 if (result != null) { 1126 result.setAutoJoinStatus(ScanResult.AUTO_ROAM_DISABLED + 1); 1127 } 1128 } 1129 } 1130 } 1131 } 1132 1133 void noteRoamingFailure(WifiConfiguration config, int reason) { 1134 if (config == null) return; 1135 config.lastRoamingFailure = System.currentTimeMillis(); 1136 config.roamingFailureBlackListTimeMilli 1137 = 2 * (config.roamingFailureBlackListTimeMilli + 1000); 1138 if (config.roamingFailureBlackListTimeMilli 1139 > networkSwitchingBlackListPeriodMilli) { 1140 config.roamingFailureBlackListTimeMilli = 1141 networkSwitchingBlackListPeriodMilli; 1142 } 1143 config.lastRoamingFailureReason = reason; 1144 } 1145 1146 void saveWifiConfigBSSID(WifiConfiguration config) { 1147 // Sanity check the config is valid 1148 if (config == null || (config.networkId == INVALID_NETWORK_ID && 1149 config.SSID == null)) { 1150 return; 1151 } 1152 1153 // If Network Selection specified a BSSID then write it in the network block 1154 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1155 String bssid = networkStatus.getNetworkSelectionBSSID(); 1156 if (bssid != null) { 1157 localLog("saveWifiConfigBSSID Setting BSSID for " + config.configKey() 1158 + " to " + bssid); 1159 if (!mWifiNative.setNetworkVariable( 1160 config.networkId, 1161 WifiConfiguration.bssidVarName, 1162 bssid)) { 1163 loge("failed to set BSSID: " + bssid); 1164 } else if (bssid.equals("any")) { 1165 // Paranoia, we just want to make sure that we restore the config to normal 1166 mWifiNative.saveConfig(); 1167 } 1168 } 1169 } 1170 1171 1172 void updateStatus(int netId, DetailedState state) { 1173 if (netId != INVALID_NETWORK_ID) { 1174 WifiConfiguration config = mConfiguredNetworks.getForAllUsers(netId); 1175 if (config == null) return; 1176 switch (state) { 1177 case CONNECTED: 1178 config.status = Status.CURRENT; 1179 //we successfully connected, hence remove the blacklist 1180 updateNetworkSelectionStatus(netId, 1181 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1182 break; 1183 case DISCONNECTED: 1184 //If network is already disabled, keep the status 1185 if (config.status == Status.CURRENT) { 1186 config.status = Status.ENABLED; 1187 } 1188 break; 1189 default: 1190 //do nothing, retain the existing state 1191 break; 1192 } 1193 } 1194 } 1195 1196 1197 /** 1198 * Disable an ephemeral SSID for the purpose of auto-joining thru scored. 1199 * This SSID will never be scored anymore. 1200 * The only way to "un-disable it" is if the user create a network for that SSID and then 1201 * forget it. 1202 * 1203 * @param SSID caller must ensure that the SSID passed thru this API match 1204 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 1205 * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can 1206 * disconnect if this is the current network. 1207 */ 1208 WifiConfiguration disableEphemeralNetwork(String SSID) { 1209 if (SSID == null) { 1210 return null; 1211 } 1212 1213 WifiConfiguration foundConfig = mConfiguredNetworks.getEphemeralForCurrentUser(SSID); 1214 1215 mDeletedEphemeralSSIDs.add(SSID); 1216 loge("Forget ephemeral SSID " + SSID + " num=" + mDeletedEphemeralSSIDs.size()); 1217 1218 if (foundConfig != null) { 1219 loge("Found ephemeral config in disableEphemeralNetwork: " + foundConfig.networkId); 1220 } 1221 1222 writeKnownNetworkHistory(); 1223 1224 return foundConfig; 1225 } 1226 1227 /** 1228 * Forget the specified network and save config 1229 * 1230 * @param netId network to forget 1231 * @return {@code true} if it succeeds, {@code false} otherwise 1232 */ 1233 boolean forgetNetwork(int netId) { 1234 if (showNetworks) localLogNetwork("forgetNetwork", netId); 1235 1236 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1237 1238 boolean remove = removeConfigAndSendBroadcastIfNeeded(netId); 1239 if (!remove) { 1240 //success but we dont want to remove the network from supplicant conf file 1241 return true; 1242 } 1243 if (mWifiNative.removeNetwork(netId)) { 1244 if (config != null && config.isPasspoint()) { 1245 writePasspointConfigs(config.FQDN, null); 1246 } 1247 mWifiNative.saveConfig(); 1248 writeKnownNetworkHistory(); 1249 return true; 1250 } else { 1251 loge("Failed to remove network " + netId); 1252 return false; 1253 } 1254 } 1255 1256 /** 1257 * Add/update a network. Note that there is no saveConfig operation. 1258 * This function is retained for compatibility with the public 1259 * API. The more powerful saveNetwork() is used by the 1260 * state machine 1261 * 1262 * @param config wifi configuration to add/update 1263 * @return network Id 1264 */ 1265 int addOrUpdateNetwork(WifiConfiguration config, int uid) { 1266 if (config == null || !config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { 1267 return WifiConfiguration.INVALID_NETWORK_ID; 1268 } 1269 1270 if (showNetworks) localLogNetwork("addOrUpdateNetwork id=", config.networkId); 1271 if (config.isPasspoint()) { 1272 /* create a temporary SSID with providerFriendlyName */ 1273 Long csum = getChecksum(config.FQDN); 1274 config.SSID = csum.toString(); 1275 config.enterpriseConfig.setDomainSuffixMatch(config.FQDN); 1276 } 1277 1278 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 1279 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 1280 WifiConfiguration conf = mConfiguredNetworks.getForCurrentUser(result.getNetworkId()); 1281 if (conf != null) { 1282 sendConfiguredNetworksChangedBroadcast(conf, 1283 result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : 1284 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1285 } 1286 } 1287 1288 return result.getNetworkId(); 1289 } 1290 1291 1292 /** 1293 * Get the Wifi PNO list 1294 * 1295 * @return list of WifiNative.WifiPnoNetwork 1296 */ 1297 private void buildPnoList() { 1298 mCachedPnoList = new ArrayList<WifiNative.WifiPnoNetwork>(); 1299 1300 ArrayList<WifiConfiguration> sortedWifiConfigurations 1301 = new ArrayList<WifiConfiguration>(getConfiguredNetworks()); 1302 Log.e(TAG, "buildPnoList sortedWifiConfigurations size " + sortedWifiConfigurations.size()); 1303 if (sortedWifiConfigurations.size() != 0) { 1304 // Sort by descending priority 1305 Collections.sort(sortedWifiConfigurations, new Comparator<WifiConfiguration>() { 1306 public int compare(WifiConfiguration a, WifiConfiguration b) { 1307 return a.priority - b.priority; 1308 } 1309 }); 1310 } 1311 1312 for (WifiConfiguration config : sortedWifiConfigurations) { 1313 // Initialize the RSSI threshold with sane value: 1314 // Use the 2.4GHz threshold since most WifiConfigurations are dual bands 1315 // There is very little penalty with triggering too soon, i.e. if PNO finds a network 1316 // that has an RSSI too low for us to attempt joining it. 1317 int threshold = thresholdMinimumRssi24.get(); 1318 Log.e(TAG, "found sortedWifiConfigurations : " + config.configKey()); 1319 WifiNative.WifiPnoNetwork network = new WifiNative.WifiPnoNetwork(config, threshold); 1320 mCachedPnoList.add(network); 1321 } 1322 } 1323 1324 String[] getWhiteListedSsids(WifiConfiguration config) { 1325 int num_ssids = 0; 1326 String nonQuoteSSID; 1327 int length; 1328 if (enableSsidWhitelist.get() == false) 1329 return null; 1330 List<String> list = new ArrayList<String>(); 1331 if (config == null) 1332 return null; 1333 if (config.linkedConfigurations == null) { 1334 return null; 1335 } 1336 if (config.SSID == null || TextUtils.isEmpty(config.SSID)) { 1337 return null; 1338 } 1339 for (String configKey : config.linkedConfigurations.keySet()) { 1340 // Sanity check that the linked configuration is still valid 1341 WifiConfiguration link = getWifiConfiguration(configKey); 1342 if (link == null) { 1343 continue; 1344 } 1345 1346 if (!link.getNetworkSelectionStatus().isNetworkEnabled()) { 1347 continue; 1348 } 1349 1350 if (link.hiddenSSID == true) { 1351 continue; 1352 } 1353 1354 if (link.SSID == null || TextUtils.isEmpty(link.SSID)) { 1355 continue; 1356 } 1357 1358 length = link.SSID.length(); 1359 if (length > 2 && (link.SSID.charAt(0) == '"') && link.SSID.charAt(length - 1) == '"') { 1360 nonQuoteSSID = link.SSID.substring(1, length - 1); 1361 } else { 1362 nonQuoteSSID = link.SSID; 1363 } 1364 1365 list.add(nonQuoteSSID); 1366 } 1367 1368 if (list.size() != 0) { 1369 length = config.SSID.length(); 1370 if (length > 2 && (config.SSID.charAt(0) == '"') 1371 && config.SSID.charAt(length - 1) == '"') { 1372 nonQuoteSSID = config.SSID.substring(1, length - 1); 1373 } else { 1374 nonQuoteSSID = config.SSID; 1375 } 1376 1377 list.add(nonQuoteSSID); 1378 } 1379 1380 return (String[])list.toArray(new String[0]); 1381 } 1382 1383 /** 1384 * Remove a network. Note that there is no saveConfig operation. 1385 * This function is retained for compatibility with the public 1386 * API. The more powerful forgetNetwork() is used by the 1387 * state machine for network removal 1388 * 1389 * @param netId network to be removed 1390 * @return {@code true} if it succeeds, {@code false} otherwise 1391 */ 1392 boolean removeNetwork(int netId) { 1393 if (showNetworks) localLogNetwork("removeNetwork", netId); 1394 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1395 if (config == null) { 1396 return false; 1397 } 1398 1399 boolean ret = mWifiNative.removeNetwork(netId); 1400 if (ret) { 1401 removeConfigAndSendBroadcastIfNeeded(netId); 1402 if (config != null && config.isPasspoint()) { 1403 writePasspointConfigs(config.FQDN, null); 1404 } 1405 } 1406 return ret; 1407 } 1408 1409 1410 static private Long getChecksum(String source) { 1411 Checksum csum = new CRC32(); 1412 csum.update(source.getBytes(), 0, source.getBytes().length); 1413 return csum.getValue(); 1414 } 1415 1416 private boolean removeConfigAndSendBroadcastIfNeeded(int netId) { 1417 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1418 if (config != null) { 1419 String key = config.configKey(); 1420 if (VDBG) { 1421 loge("removeNetwork " + netId + " key=" + key + " config.id=" + config.networkId); 1422 } 1423 1424 // cancel the last user choice 1425 if (key.equals(lastSelectedConfiguration)) { 1426 lastSelectedConfiguration = null; 1427 } 1428 1429 // Remove any associated keys 1430 if (config.enterpriseConfig != null) { 1431 removeKeys(config.enterpriseConfig); 1432 } 1433 1434 if (config.selfAdded || config.linkedConfigurations != null 1435 || config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1436 if (!TextUtils.isEmpty(config.SSID)) { 1437 /* Remember that we deleted this PSK SSID */ 1438 if (config.SSID != null) { 1439 Long csum = getChecksum(config.SSID); 1440 mDeletedSSIDs.add(csum); 1441 loge("removeNetwork " + netId 1442 + " key=" + key 1443 + " config.id=" + config.networkId 1444 + " crc=" + csum); 1445 } else { 1446 loge("removeNetwork " + netId 1447 + " key=" + key 1448 + " config.id=" + config.networkId); 1449 } 1450 } 1451 } 1452 1453 mConfiguredNetworks.remove(netId); 1454 mScanDetailCaches.remove(netId); 1455 1456 writeIpAndProxyConfigurations(); 1457 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 1458 if (!config.ephemeral) { 1459 removeUserSelectionPreference(key); 1460 } 1461 writeKnownNetworkHistory(); 1462 } 1463 return true; 1464 } 1465 1466 private void removeUserSelectionPreference(String configKey) { 1467 if (DBG) { 1468 Log.d(TAG, "removeUserSelectionPreference: key is " + configKey); 1469 } 1470 if (configKey == null) { 1471 return; 1472 } 1473 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 1474 WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 1475 String connectChoice = status.getConnectChoice(); 1476 if (connectChoice != null && connectChoice.equals(configKey)) { 1477 Log.d(TAG, "remove connect choice:" + connectChoice + " from " + config.SSID 1478 + " : " + config.networkId); 1479 status.setConnectChoice(null); 1480 status.setConnectChoiceTimestamp(WifiConfiguration.NetworkSelectionStatus 1481 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1482 } 1483 } 1484 } 1485 1486 /* 1487 * Remove all networks associated with an application 1488 * 1489 * @param packageName name of the package of networks to remove 1490 * @return {@code true} if all networks removed successfully, {@code false} otherwise 1491 */ 1492 boolean removeNetworksForApp(ApplicationInfo app) { 1493 if (app == null || app.packageName == null) { 1494 return false; 1495 } 1496 1497 boolean success = true; 1498 1499 WifiConfiguration [] copiedConfigs = 1500 mConfiguredNetworks.valuesForCurrentUser().toArray(new WifiConfiguration[0]); 1501 for (WifiConfiguration config : copiedConfigs) { 1502 if (app.uid != config.creatorUid || !app.packageName.equals(config.creatorName)) { 1503 continue; 1504 } 1505 if (showNetworks) { 1506 localLog("Removing network " + config.SSID 1507 + ", application \"" + app.packageName + "\" uninstalled" 1508 + " from user " + UserHandle.getUserId(app.uid)); 1509 } 1510 success &= removeNetwork(config.networkId); 1511 } 1512 1513 mWifiNative.saveConfig(); 1514 1515 return success; 1516 } 1517 1518 boolean removeNetworksForUser(int userId) { 1519 boolean success = true; 1520 1521 WifiConfiguration[] copiedConfigs = 1522 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1523 for (WifiConfiguration config : copiedConfigs) { 1524 if (userId != UserHandle.getUserId(config.creatorUid)) { 1525 continue; 1526 } 1527 success &= removeNetwork(config.networkId); 1528 if (showNetworks) { 1529 localLog("Removing network " + config.SSID 1530 + ", user " + userId + " removed"); 1531 } 1532 } 1533 1534 return success; 1535 } 1536 1537 /** 1538 * Enable a network. Note that there is no saveConfig operation. 1539 * This function is retained for compatibility with the public 1540 * API. The more powerful selectNetwork()/saveNetwork() is used by the 1541 * state machine for connecting to a network 1542 * 1543 * @param netId network to be enabled 1544 * @return {@code true} if it succeeds, {@code false} otherwise 1545 */ 1546 boolean enableNetwork(int netId, boolean disableOthers, int uid) { 1547 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1548 if (config == null) { 1549 return false; 1550 } 1551 1552 boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); 1553 if (disableOthers) { 1554 if (VDBG) localLogNetwork("enableNetwork(disableOthers=true, uid=" + uid + ") ", netId); 1555 updateLastConnectUid(getWifiConfiguration(netId), uid); 1556 writeKnownNetworkHistory(); 1557 sendConfiguredNetworksChangedBroadcast(); 1558 } else { 1559 if (VDBG) localLogNetwork("enableNetwork(disableOthers=false) ", netId); 1560 WifiConfiguration enabledNetwork; 1561 synchronized(mConfiguredNetworks) { // !!! Useless synchronization! 1562 enabledNetwork = mConfiguredNetworks.getForCurrentUser(netId); 1563 } 1564 // check just in case the network was removed by someone else. 1565 if (enabledNetwork != null) { 1566 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 1567 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1568 } 1569 } 1570 return ret; 1571 } 1572 1573 boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { 1574 final WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1575 if (config == null) { 1576 return false; 1577 } 1578 1579 boolean ret = mWifiNative.enableNetwork(netId, disableOthers); 1580 1581 config.status = Status.ENABLED; 1582 1583 if (disableOthers) { 1584 markAllNetworksDisabledExcept(netId); 1585 } 1586 return ret; 1587 } 1588 1589 void disableAllNetworks() { 1590 if (VDBG) localLog("disableAllNetworks"); 1591 boolean networkDisabled = false; 1592 for (WifiConfiguration enabled : mConfiguredNetworks.getEnabledNetworksForCurrentUser()) { 1593 if(mWifiNative.disableNetwork(enabled.networkId)) { 1594 networkDisabled = true; 1595 enabled.status = Status.DISABLED; 1596 } else { 1597 loge("Disable network failed on " + enabled.networkId); 1598 } 1599 } 1600 1601 if (networkDisabled) { 1602 sendConfiguredNetworksChangedBroadcast(); 1603 } 1604 } 1605 /** 1606 * Disable a network. Note that there is no saveConfig operation. 1607 * @param netId network to be disabled 1608 * @return {@code true} if it succeeds, {@code false} otherwise 1609 */ 1610 boolean disableNetwork(int netId) { 1611 boolean ret = mWifiNative.disableNetwork(netId); 1612 if (ret) { 1613 mWifiStateMachine.registerNetworkDisabled(netId); 1614 } 1615 return ret; 1616 } 1617 1618 /** 1619 * Update a network according to the update reason and its current state 1620 * @param netId The network ID of the network need update 1621 * @param reason The reason to update the network 1622 * @return false if no change made to the input configure file, can due to error or need not 1623 * true the input config file has been changed 1624 */ 1625 boolean updateNetworkSelectionStatus(int netId, int reason) { 1626 WifiConfiguration config = getWifiConfiguration(netId); 1627 return updateNetworkSelectionStatus(config, reason); 1628 } 1629 1630 /** 1631 * Update a network according to the update reason and its current state 1632 * @param config the network need update 1633 * @param reason The reason to update the network 1634 * @return false if no change made to the input configure file, can due to error or need not 1635 * true the input config file has been changed 1636 */ 1637 boolean updateNetworkSelectionStatus(WifiConfiguration config, int reason) { 1638 if (config == null) { 1639 return false; 1640 } 1641 1642 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1643 if (reason == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1644 updateNetworkStatus(config, WifiConfiguration.NetworkSelectionStatus 1645 .NETWORK_SELECTION_ENABLE); 1646 localLog("Enable network:" + config.configKey()); 1647 return true; 1648 } 1649 1650 networkStatus.incrementDisableReasonCounter(reason); 1651 if (DBG) { 1652 localLog("Network:" + config.SSID + "disable counter of " 1653 + WifiConfiguration.NetworkSelectionStatus.getNetworkDisableReasonString(reason) 1654 + " is: " + networkStatus.getDisableReasonCounter(reason) + "and threshold is: " 1655 + NETWORK_SELECTION_DISABLE_THRESHOLD[reason]); 1656 } 1657 1658 if (networkStatus.getDisableReasonCounter(reason) 1659 >= NETWORK_SELECTION_DISABLE_THRESHOLD[reason]) { 1660 return updateNetworkStatus(config, reason); 1661 } 1662 return true; 1663 } 1664 1665 /** 1666 * Check the config. If it is temporarily disabled, check the disable time is expired or not, If 1667 * expired, enabled it again for qualified network selection. 1668 * @param networkId the id of the network to be checked for possible unblock (due to timeout) 1669 * @return true if network status has been changed 1670 * false network status is not changed 1671 */ 1672 boolean tryEnableQualifiedNetwork(int networkId) { 1673 WifiConfiguration config = getWifiConfiguration(networkId); 1674 if (config == null) { 1675 localLog("updateQualifiedNetworkstatus invalid network."); 1676 return false; 1677 } 1678 return tryEnableQualifiedNetwork(config); 1679 } 1680 1681 /** 1682 * Check the config. If it is temporarily disabled, check the disable is expired or not, If 1683 * expired, enabled it again for qualified network selection. 1684 * @param config network to be checked for possible unblock (due to timeout) 1685 * @return true if network status has been changed 1686 * false network status is not changed 1687 */ 1688 boolean tryEnableQualifiedNetwork(WifiConfiguration config) { 1689 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1690 if (networkStatus.isNetworkTemporaryDisabled()) { 1691 //time difference in minutes 1692 long timeDifference = (System.currentTimeMillis() 1693 - networkStatus.getDisableTime()) / 1000 / 60; 1694 if (timeDifference < 0 || timeDifference 1695 >= NETWORK_SELECTION_DISABLE_TIMEOUT[ 1696 networkStatus.getNetworkSelectionDisableReason()]) { 1697 updateNetworkSelectionStatus(config.networkId, 1698 networkStatus.NETWORK_SELECTION_ENABLE); 1699 return true; 1700 } 1701 } 1702 return false; 1703 } 1704 1705 /** 1706 * Update a network's status. Note that there is no saveConfig operation. 1707 * @param config network to be updated 1708 * @param reason reason code for updated 1709 * @return false if no change made to the input configure file, can due to error or need not 1710 * true the input config file has been changed 1711 */ 1712 boolean updateNetworkStatus(WifiConfiguration config, int reason) { 1713 localLog("updateNetworkStatus:" + (config == null ? null : config.SSID)); 1714 if (config == null) { 1715 return false; 1716 } 1717 1718 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1719 if (reason < 0 || reason >= WifiConfiguration.NetworkSelectionStatus 1720 .NETWORK_SELECTION_DISABLED_MAX) { 1721 localLog("Invalid Network disable reason:" + reason); 1722 return false; 1723 } 1724 1725 if (reason == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1726 if (networkStatus.isNetworkEnabled()) { 1727 if (DBG) { 1728 localLog("Need not change Qualified network Selection status since" 1729 + " already enabled"); 1730 } 1731 return false; 1732 } 1733 //enable the network 1734 if (!mWifiNative.enableNetwork(config.networkId, false)) { 1735 localLog("fail to disable network: " + config.SSID + " With reason:" 1736 + WifiConfiguration.NetworkSelectionStatus 1737 .getNetworkDisableReasonString(reason)); 1738 return false; 1739 } 1740 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1741 .NETWORK_SELECTION_ENABLED); 1742 networkStatus.setNetworkSelectionDisableReason(reason); 1743 networkStatus.setDisableTime( 1744 WifiConfiguration.NetworkSelectionStatus 1745 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1746 networkStatus.clearDisableReasonCounter(); 1747 String disableTime = DateFormat.getDateTimeInstance().format(new Date()); 1748 if (DBG) { 1749 localLog("Re-enable network: " + config.SSID + " at " + disableTime); 1750 } 1751 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1752 } else { 1753 //disable the network 1754 if (networkStatus.isNetworkPermanentlyDisabled()) { 1755 //alreay permanent disable 1756 if (DBG) { 1757 localLog("Do nothing. Alreay permanent disabled! " 1758 + WifiConfiguration.NetworkSelectionStatus 1759 .getNetworkDisableReasonString(reason)); 1760 } 1761 return false; 1762 } else if (networkStatus.isNetworkTemporaryDisabled() 1763 && reason < WifiConfiguration.NetworkSelectionStatus 1764 .DISABLED_TLS_VERSION_MISMATCH) { 1765 //alreay temporarily disable 1766 if (DBG) { 1767 localLog("Do nothing. Already temporarily disabled! " 1768 + WifiConfiguration.NetworkSelectionStatus 1769 .getNetworkDisableReasonString(reason)); 1770 } 1771 return false; 1772 } 1773 1774 if (networkStatus.isNetworkEnabled()) { 1775 mWifiNative.disableNetwork(config.networkId); 1776 sendConfiguredNetworksChangedBroadcast(config, 1777 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1778 localLog("Disable network " + config.SSID + " reason:" 1779 + WifiConfiguration.NetworkSelectionStatus 1780 .getNetworkDisableReasonString(reason)); 1781 } 1782 if (reason < WifiConfiguration.NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) { 1783 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1784 .NETWORK_SELECTION_TEMPORARY_DISABLED); 1785 networkStatus.setDisableTime(System.currentTimeMillis()); 1786 } else { 1787 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1788 .NETWORK_SELECTION_PERMANENTLY_DISABLED); 1789 } 1790 networkStatus.setNetworkSelectionDisableReason(reason); 1791 if (DBG) { 1792 String disableTime = DateFormat.getDateTimeInstance().format(new Date()); 1793 localLog("Network:" + config.SSID + "Configure new status:" 1794 + networkStatus.getNetworkStatusString() + " with reason:" 1795 + networkStatus.getNetworkDisableReasonString() + " at: " + disableTime); 1796 } 1797 } 1798 return true; 1799 } 1800 1801 /** 1802 * Save the configured networks in supplicant to disk 1803 * @return {@code true} if it succeeds, {@code false} otherwise 1804 */ 1805 boolean saveConfig() { 1806 return mWifiNative.saveConfig(); 1807 } 1808 1809 /** 1810 * Start WPS pin method configuration with pin obtained 1811 * from the access point 1812 * @param config WPS configuration 1813 * @return Wps result containing status and pin 1814 */ 1815 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 1816 WpsResult result = new WpsResult(); 1817 if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { 1818 /* WPS leaves all networks disabled */ 1819 markAllNetworksDisabled(); 1820 result.status = WpsResult.Status.SUCCESS; 1821 } else { 1822 loge("Failed to start WPS pin method configuration"); 1823 result.status = WpsResult.Status.FAILURE; 1824 } 1825 return result; 1826 } 1827 1828 /** 1829 * Start WPS pin method configuration with obtained 1830 * from the device 1831 * @return WpsResult indicating status and pin 1832 */ 1833 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 1834 WpsResult result = new WpsResult(); 1835 result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); 1836 /* WPS leaves all networks disabled */ 1837 if (!TextUtils.isEmpty(result.pin)) { 1838 markAllNetworksDisabled(); 1839 result.status = WpsResult.Status.SUCCESS; 1840 } else { 1841 loge("Failed to start WPS pin method configuration"); 1842 result.status = WpsResult.Status.FAILURE; 1843 } 1844 return result; 1845 } 1846 1847 /** 1848 * Start WPS push button configuration 1849 * @param config WPS configuration 1850 * @return WpsResult indicating status and pin 1851 */ 1852 WpsResult startWpsPbc(WpsInfo config) { 1853 WpsResult result = new WpsResult(); 1854 if (mWifiNative.startWpsPbc(config.BSSID)) { 1855 /* WPS leaves all networks disabled */ 1856 markAllNetworksDisabled(); 1857 result.status = WpsResult.Status.SUCCESS; 1858 } else { 1859 loge("Failed to start WPS push button configuration"); 1860 result.status = WpsResult.Status.FAILURE; 1861 } 1862 return result; 1863 } 1864 1865 /** 1866 * Fetch the static IP configuration for a given network id 1867 */ 1868 StaticIpConfiguration getStaticIpConfiguration(int netId) { 1869 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1870 if (config != null) { 1871 return config.getStaticIpConfiguration(); 1872 } 1873 return null; 1874 } 1875 1876 /** 1877 * Set the static IP configuration for a given network id 1878 */ 1879 void setStaticIpConfiguration(int netId, StaticIpConfiguration staticIpConfiguration) { 1880 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1881 if (config != null) { 1882 config.setStaticIpConfiguration(staticIpConfiguration); 1883 } 1884 } 1885 1886 /** 1887 * set default GW MAC address 1888 */ 1889 void setDefaultGwMacAddress(int netId, String macAddress) { 1890 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1891 if (config != null) { 1892 //update defaultGwMacAddress 1893 config.defaultGwMacAddress = macAddress; 1894 } 1895 } 1896 1897 1898 /** 1899 * Fetch the proxy properties for a given network id 1900 * @param netId id 1901 * @return ProxyInfo for the network id 1902 */ 1903 ProxyInfo getProxyProperties(int netId) { 1904 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1905 if (config != null) { 1906 return config.getHttpProxy(); 1907 } 1908 return null; 1909 } 1910 1911 /** 1912 * Return if the specified network is using static IP 1913 * @param netId id 1914 * @return {@code true} if using static ip for netId 1915 */ 1916 boolean isUsingStaticIp(int netId) { 1917 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1918 if (config != null && config.getIpAssignment() == IpAssignment.STATIC) { 1919 return true; 1920 } 1921 return false; 1922 } 1923 1924 boolean isEphemeral(int netId) { 1925 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1926 return config != null && config.ephemeral; 1927 } 1928 1929 /** 1930 * Should be called when a single network configuration is made. 1931 * @param network The network configuration that changed. 1932 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 1933 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 1934 */ 1935 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 1936 int reason) { 1937 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1938 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1939 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 1940 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 1941 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 1942 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1943 } 1944 1945 /** 1946 * Should be called when multiple network configuration changes are made. 1947 */ 1948 private void sendConfiguredNetworksChangedBroadcast() { 1949 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1950 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1951 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 1952 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1953 } 1954 1955 void loadConfiguredNetworks() { 1956 1957 mLastPriority = 0; 1958 1959 final Map<String, WifiConfiguration> configs = new HashMap<>(); 1960 1961 final SparseArray<Map<String, String>> networkExtras = new SparseArray<>(); 1962 1963 int last_id = -1; 1964 boolean done = false; 1965 while (!done) { 1966 1967 String listStr = mWifiNative.listNetworks(last_id); 1968 if (listStr == null) 1969 return; 1970 1971 String[] lines = listStr.split("\n"); 1972 1973 if (showNetworks) { 1974 localLog("WifiConfigStore: loadConfiguredNetworks: "); 1975 for (String net : lines) { 1976 localLog(net); 1977 } 1978 } 1979 1980 // Skip the first line, which is a header 1981 for (int i = 1; i < lines.length; i++) { 1982 String[] result = lines[i].split("\t"); 1983 // network-id | ssid | bssid | flags 1984 WifiConfiguration config = new WifiConfiguration(); 1985 try { 1986 config.networkId = Integer.parseInt(result[0]); 1987 last_id = config.networkId; 1988 } catch(NumberFormatException e) { 1989 loge("Failed to read network-id '" + result[0] + "'"); 1990 continue; 1991 } 1992 if (result.length > 3) { 1993 if (result[3].indexOf("[CURRENT]") != -1) 1994 config.status = WifiConfiguration.Status.CURRENT; 1995 else if (result[3].indexOf("[DISABLED]") != -1) 1996 config.status = WifiConfiguration.Status.DISABLED; 1997 else 1998 config.status = WifiConfiguration.Status.ENABLED; 1999 } else { 2000 config.status = WifiConfiguration.Status.ENABLED; 2001 } 2002 2003 readNetworkVariables(config); 2004 2005 // Parse the serialized JSON dictionary in ID_STRING_VAR_NAME once and cache the 2006 // result for efficiency. 2007 Map<String, String> extras = mWifiNative.getNetworkExtra(config.networkId, 2008 ID_STRING_VAR_NAME); 2009 if (extras == null) { 2010 extras = new HashMap<String, String>(); 2011 // If ID_STRING_VAR_NAME did not contain a dictionary, assume that it contains 2012 // just a quoted FQDN. This is the legacy format that was used in Marshmallow. 2013 final String fqdn = Utils.unquote(mWifiNative.getNetworkVariable( 2014 config.networkId, ID_STRING_VAR_NAME)); 2015 if (fqdn != null) { 2016 extras.put(ID_STRING_KEY_FQDN, fqdn); 2017 config.FQDN = fqdn; 2018 // Mark the configuration as a Hotspot 2.0 network. 2019 config.providerFriendlyName = ""; 2020 } 2021 } 2022 networkExtras.put(config.networkId, extras); 2023 2024 Checksum csum = new CRC32(); 2025 if (config.SSID != null) { 2026 csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length); 2027 long d = csum.getValue(); 2028 if (mDeletedSSIDs.contains(d)) { 2029 loge(" got CRC for SSID " + config.SSID + " -> " + d + ", was deleted"); 2030 } 2031 } 2032 2033 if (config.priority > mLastPriority) { 2034 mLastPriority = config.priority; 2035 } 2036 2037 config.setIpAssignment(IpAssignment.DHCP); 2038 config.setProxySettings(ProxySettings.NONE); 2039 2040 if (!WifiServiceImpl.isValid(config)) { 2041 if (showNetworks) { 2042 localLog("Ignoring network " + config.networkId + " because configuration " 2043 + "loaded from wpa_supplicant.conf is not valid."); 2044 } 2045 continue; 2046 } 2047 2048 // The configKey is explicitly stored in wpa_supplicant.conf, because config does 2049 // not contain sufficient information to compute it at this point. 2050 String configKey = extras.get(ID_STRING_KEY_CONFIG_KEY); 2051 if (configKey == null) { 2052 // Handle the legacy case where the configKey is not stored in 2053 // wpa_supplicant.conf but can be computed straight away. 2054 configKey = config.configKey(); 2055 } 2056 2057 final WifiConfiguration duplicateConfig = configs.put(configKey, config); 2058 if (duplicateConfig != null) { 2059 // The network is already known. Overwrite the duplicate entry. 2060 if (showNetworks) { 2061 localLog("Replacing duplicate network " + duplicateConfig.networkId 2062 + " with " + config.networkId + "."); 2063 } 2064 // This can happen after the user manually connected to an AP and tried to use 2065 // WPS to connect the AP later. In this case, the supplicant will create a new 2066 // network for the AP although there is an existing network already. 2067 mWifiNative.removeNetwork(duplicateConfig.networkId); 2068 } 2069 } 2070 2071 done = (lines.length == 1); 2072 } 2073 2074 readNetworkHistory(configs); 2075 readPasspointConfig(configs, networkExtras); 2076 2077 // We are only now updating mConfiguredNetworks for two reasons: 2078 // 1) The information required to compute configKeys is spread across wpa_supplicant.conf 2079 // and networkHistory.txt. Thus, we had to load both files first. 2080 // 2) mConfiguredNetworks caches a Passpoint network's FQDN the moment the network is added. 2081 // Thus, we had to load the FQDNs first. 2082 mConfiguredNetworks.clear(); 2083 for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) { 2084 final String configKey = entry.getKey(); 2085 final WifiConfiguration config = entry.getValue(); 2086 if (!configKey.equals(config.configKey())) { 2087 if (showNetworks) { 2088 log("Ignoring network " + config.networkId + " because the configKey loaded " 2089 + "from wpa_supplicant.conf is not valid."); 2090 } 2091 mWifiNative.removeNetwork(config.networkId); 2092 continue; 2093 } 2094 mConfiguredNetworks.put(config); 2095 } 2096 2097 readIpAndProxyConfigurations(); 2098 readAutoJoinConfig(); 2099 2100 buildPnoList(); 2101 2102 sendConfiguredNetworksChangedBroadcast(); 2103 2104 if (showNetworks) { 2105 localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.sizeForAllUsers() 2106 + " networks (for all users)"); 2107 } 2108 2109 if (mConfiguredNetworks.sizeForAllUsers() == 0) { 2110 // no networks? Lets log if the file contents 2111 logKernelTime(); 2112 logContents(SUPPLICANT_CONFIG_FILE); 2113 logContents(SUPPLICANT_CONFIG_FILE_BACKUP); 2114 logContents(networkHistoryConfigFile); 2115 } 2116 } 2117 2118 private void logContents(String file) { 2119 localLogAndLogcat("--- Begin " + file + " ---"); 2120 BufferedReader reader = null; 2121 try { 2122 reader = new BufferedReader(new FileReader(file)); 2123 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 2124 localLogAndLogcat(line); 2125 } 2126 } catch (FileNotFoundException e) { 2127 localLog("Could not open " + file + ", " + e); 2128 Log.w(TAG, "Could not open " + file + ", " + e); 2129 } catch (IOException e) { 2130 localLog("Could not read " + file + ", " + e); 2131 Log.w(TAG, "Could not read " + file + ", " + e); 2132 } finally { 2133 try { 2134 if (reader != null) { 2135 reader.close(); 2136 } 2137 } catch (IOException e) { 2138 // Just ignore the fact that we couldn't close 2139 } 2140 } 2141 localLogAndLogcat("--- End " + file + " Contents ---"); 2142 } 2143 2144 private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) { 2145 // TODO(b/26733972): This method assumes that the SSID is a unique identifier for network 2146 // configurations. That is wrong. There may be any number of networks with the same SSID. 2147 // There may also be any number of network configurations for the same network. The correct 2148 // unique identifier is the configKey. This method should be switched from SSID to configKey 2149 // (which is either stored in wpa_supplicant.conf directly or can be computed from the 2150 // information found in that file). 2151 Map<String, String> result = new HashMap<>(); 2152 BufferedReader reader = null; 2153 if (VDBG) loge("readNetworkVariablesFromSupplicantFile key=" + key); 2154 2155 try { 2156 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 2157 boolean found = false; 2158 String networkSsid = null; 2159 String value = null; 2160 2161 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 2162 2163 if (line.matches("[ \\t]*network=\\{")) { 2164 found = true; 2165 networkSsid = null; 2166 value = null; 2167 } else if (line.matches("[ \\t]*\\}")) { 2168 found = false; 2169 networkSsid = null; 2170 value = null; 2171 } 2172 2173 if (found) { 2174 String trimmedLine = line.trim(); 2175 if (trimmedLine.startsWith("ssid=")) { 2176 networkSsid = trimmedLine.substring(5); 2177 } else if (trimmedLine.startsWith(key + "=")) { 2178 value = trimmedLine.substring(key.length() + 1); 2179 } 2180 2181 if (networkSsid != null && value != null) { 2182 result.put(networkSsid, value); 2183 } 2184 } 2185 } 2186 } catch (FileNotFoundException e) { 2187 if (VDBG) loge("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 2188 } catch (IOException e) { 2189 if (VDBG) loge("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 2190 } finally { 2191 try { 2192 if (reader != null) { 2193 reader.close(); 2194 } 2195 } catch (IOException e) { 2196 // Just ignore the fact that we couldn't close 2197 } 2198 } 2199 2200 return result; 2201 } 2202 2203 private String readNetworkVariableFromSupplicantFile(String ssid, String key) { 2204 long start = SystemClock.elapsedRealtimeNanos(); 2205 Map<String, String> data = readNetworkVariablesFromSupplicantFile(key); 2206 long end = SystemClock.elapsedRealtimeNanos(); 2207 2208 if (VDBG) { 2209 loge("readNetworkVariableFromSupplicantFile ssid=[" + ssid + "] key=" + key 2210 + " duration=" + (long)(end - start)); 2211 } 2212 return data.get(ssid); 2213 } 2214 2215 /* Mark all networks except specified netId as disabled */ 2216 private void markAllNetworksDisabledExcept(int netId) { 2217 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2218 if(config != null && config.networkId != netId) { 2219 if (config.status != Status.DISABLED) { 2220 config.status = Status.DISABLED; 2221 } 2222 } 2223 } 2224 } 2225 2226 private void markAllNetworksDisabled() { 2227 markAllNetworksDisabledExcept(INVALID_NETWORK_ID); 2228 } 2229 2230 boolean needsUnlockedKeyStore() { 2231 2232 // Any network using certificates to authenticate access requires 2233 // unlocked key store; unless the certificates can be stored with 2234 // hardware encryption 2235 2236 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2237 2238 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 2239 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 2240 2241 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 2242 return true; 2243 } 2244 } 2245 } 2246 2247 return false; 2248 } 2249 2250 void readPasspointConfig(Map<String, WifiConfiguration> configs, 2251 SparseArray<Map<String, String>> networkExtras) { 2252 List<HomeSP> homeSPs; 2253 try { 2254 homeSPs = mMOManager.loadAllSPs(); 2255 } catch (IOException e) { 2256 loge("Could not read " + PPS_FILE + " : " + e); 2257 return; 2258 } 2259 2260 int matchedConfigs = 0; 2261 for (HomeSP homeSp : homeSPs) { 2262 String fqdn = homeSp.getFQDN(); 2263 Log.d(TAG, "Looking for " + fqdn); 2264 for (WifiConfiguration config : configs.values()) { 2265 Log.d(TAG, "Testing " + config.SSID); 2266 2267 if (config.enterpriseConfig == null) { 2268 continue; 2269 } 2270 final String configFqdn = 2271 networkExtras.get(config.networkId).get(ID_STRING_KEY_FQDN); 2272 if (configFqdn != null && configFqdn.equals(fqdn)) { 2273 Log.d(TAG, "Matched " + configFqdn + " with " + config.networkId); 2274 ++matchedConfigs; 2275 config.FQDN = fqdn; 2276 config.providerFriendlyName = homeSp.getFriendlyName(); 2277 2278 HashSet<Long> roamingConsortiumIds = homeSp.getRoamingConsortiums(); 2279 config.roamingConsortiumIds = new long[roamingConsortiumIds.size()]; 2280 int i = 0; 2281 for (long id : roamingConsortiumIds) { 2282 config.roamingConsortiumIds[i] = id; 2283 i++; 2284 } 2285 IMSIParameter imsiParameter = homeSp.getCredential().getImsi(); 2286 config.enterpriseConfig.setPlmn( 2287 imsiParameter != null ? imsiParameter.toString() : null); 2288 config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm()); 2289 } 2290 } 2291 } 2292 2293 Log.d(TAG, "loaded " + matchedConfigs + " passpoint configs"); 2294 } 2295 2296 public void writePasspointConfigs(final String fqdn, final HomeSP homeSP) { 2297 mWriter.write(PPS_FILE, new DelayedDiskWrite.Writer() { 2298 @Override 2299 public void onWriteCalled(DataOutputStream out) throws IOException { 2300 try { 2301 if (homeSP != null) { 2302 mMOManager.addSP(homeSP, mOSUManager); 2303 } else { 2304 mMOManager.removeSP(fqdn, mOSUManager); 2305 } 2306 } catch (IOException e) { 2307 loge("Could not write " + PPS_FILE + " : " + e); 2308 } 2309 } 2310 }, false); 2311 } 2312 2313 public void writeKnownNetworkHistory() { 2314 2315 /* Make a copy */ 2316 final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 2317 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 2318 networks.add(new WifiConfiguration(config)); 2319 } 2320 if (VDBG) { 2321 loge(" writeKnownNetworkHistory() num networks:" 2322 + mConfiguredNetworks.valuesForCurrentUser()); 2323 } 2324 2325 mWriter.write(networkHistoryConfigFile, new DelayedDiskWrite.Writer() { 2326 public void onWriteCalled(DataOutputStream out) throws IOException { 2327 for (WifiConfiguration config : networks) { 2328 //loge("onWriteCalled write SSID: " + config.SSID); 2329 /* if (config.getLinkProperties() != null) 2330 loge(" lp " + config.getLinkProperties().toString()); 2331 else 2332 loge("attempt config w/o lp"); 2333 */ 2334 WifiConfiguration.NetworkSelectionStatus status = 2335 config.getNetworkSelectionStatus(); 2336 if (VDBG) { 2337 int numlink = 0; 2338 if (config.linkedConfigurations != null) { 2339 numlink = config.linkedConfigurations.size(); 2340 } 2341 String disableTime; 2342 if (config.getNetworkSelectionStatus().isNetworkEnabled()) { 2343 disableTime = ""; 2344 } else { 2345 disableTime = "Disable time: " + DateFormat.getInstance().format( 2346 config.getNetworkSelectionStatus().getDisableTime()); 2347 } 2348 loge("saving network history: " + config.configKey() + " gw: " 2349 + config.defaultGwMacAddress + " Network Selection-status: " 2350 + status.getNetworkStatusString() 2351 + disableTime + " ephemeral=" + config.ephemeral 2352 + " choice:" + status.getConnectChoice() 2353 + " link:" + numlink 2354 + " status:" + config.status 2355 + " nid:" + config.networkId); 2356 } 2357 2358 if (!WifiServiceImpl.isValid(config)) 2359 continue; 2360 2361 if (config.SSID == null) { 2362 if (VDBG) { 2363 loge("writeKnownNetworkHistory trying to write config with null SSID"); 2364 } 2365 continue; 2366 } 2367 if (VDBG) { 2368 loge("writeKnownNetworkHistory write config " + config.configKey()); 2369 } 2370 out.writeUTF(CONFIG_KEY + SEPARATOR + config.configKey() + NL); 2371 2372 if (config.SSID != null) { 2373 out.writeUTF(SSID_KEY + SEPARATOR + config.SSID + NL); 2374 } 2375 if (config.BSSID != null) { 2376 out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + config.BSSID + NL); 2377 } else { 2378 out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + "null" + NL); 2379 } 2380 if (config.FQDN != null) { 2381 out.writeUTF(FQDN_KEY + SEPARATOR + config.FQDN + NL); 2382 } 2383 2384 out.writeUTF(PRIORITY_KEY + SEPARATOR + 2385 Integer.toString(config.priority) + NL); 2386 out.writeUTF(NETWORK_ID_KEY + SEPARATOR + 2387 Integer.toString(config.networkId) + NL); 2388 out.writeUTF(SELF_ADDED_KEY + SEPARATOR + 2389 Boolean.toString(config.selfAdded) + NL); 2390 out.writeUTF(DID_SELF_ADD_KEY + SEPARATOR + 2391 Boolean.toString(config.didSelfAdd) + NL); 2392 out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY + SEPARATOR + 2393 Integer.toString(config.numNoInternetAccessReports) + NL); 2394 out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY + SEPARATOR + 2395 Boolean.toString(config.validatedInternetAccess) + NL); 2396 out.writeUTF(EPHEMERAL_KEY + SEPARATOR + 2397 Boolean.toString(config.ephemeral) + NL); 2398 if (config.creationTime != null) { 2399 out.writeUTF(CREATION_TIME_KEY + SEPARATOR + config.creationTime + NL); 2400 } 2401 if (config.updateTime != null) { 2402 out.writeUTF(UPDATE_TIME_KEY + SEPARATOR + config.updateTime + NL); 2403 } 2404 if (config.peerWifiConfiguration != null) { 2405 out.writeUTF(PEER_CONFIGURATION_KEY + SEPARATOR + 2406 config.peerWifiConfiguration + NL); 2407 } 2408 out.writeUTF(SCORER_OVERRIDE_KEY + SEPARATOR + 2409 Integer.toString(config.numScorerOverride) + NL); 2410 out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY + SEPARATOR + 2411 Integer.toString(config.numScorerOverrideAndSwitchedNetwork) + NL); 2412 out.writeUTF(NUM_ASSOCIATION_KEY + SEPARATOR + 2413 Integer.toString(config.numAssociation) + NL); 2414 out.writeUTF(CREATOR_UID_KEY + SEPARATOR + 2415 Integer.toString(config.creatorUid) + NL); 2416 out.writeUTF(CONNECT_UID_KEY + SEPARATOR + 2417 Integer.toString(config.lastConnectUid) + NL); 2418 out.writeUTF(UPDATE_UID_KEY + SEPARATOR + 2419 Integer.toString(config.lastUpdateUid) + NL); 2420 out.writeUTF(CREATOR_NAME_KEY + SEPARATOR + 2421 config.creatorName + NL); 2422 out.writeUTF(UPDATE_NAME_KEY + SEPARATOR + 2423 config.lastUpdateName + NL); 2424 out.writeUTF(USER_APPROVED_KEY + SEPARATOR + 2425 Integer.toString(config.userApproved) + NL); 2426 out.writeUTF(SHARED_KEY + SEPARATOR + Boolean.toString(config.shared) + NL); 2427 String allowedKeyManagementString = 2428 makeString(config.allowedKeyManagement, 2429 WifiConfiguration.KeyMgmt.strings); 2430 out.writeUTF(AUTH_KEY + SEPARATOR + 2431 allowedKeyManagementString + NL); 2432 2433 2434 if (status.getConnectChoice() != null) { 2435 out.writeUTF(CHOICE_KEY + SEPARATOR + status.getConnectChoice() + NL); 2436 out.writeUTF(CHOICE_TIME_KEY + SEPARATOR 2437 + status.getConnectChoiceTimestamp() + NL); 2438 } 2439 2440 if (config.linkedConfigurations != null) { 2441 log("writeKnownNetworkHistory write linked " 2442 + config.linkedConfigurations.size()); 2443 2444 for (String key : config.linkedConfigurations.keySet()) { 2445 out.writeUTF(LINK_KEY + SEPARATOR + key + NL); 2446 } 2447 } 2448 2449 String macAddress = config.defaultGwMacAddress; 2450 if (macAddress != null) { 2451 out.writeUTF(DEFAULT_GW_KEY + SEPARATOR + macAddress + NL); 2452 } 2453 2454 if (getScanDetailCache(config) != null) { 2455 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 2456 ScanResult result = scanDetail.getScanResult(); 2457 out.writeUTF(BSSID_KEY + SEPARATOR + 2458 result.BSSID + NL); 2459 2460 out.writeUTF(FREQ_KEY + SEPARATOR + 2461 Integer.toString(result.frequency) + NL); 2462 2463 out.writeUTF(RSSI_KEY + SEPARATOR + 2464 Integer.toString(result.level) + NL); 2465 2466 out.writeUTF(BSSID_KEY_END + NL); 2467 } 2468 } 2469 if (config.lastFailure != null) { 2470 out.writeUTF(FAILURE_KEY + SEPARATOR + config.lastFailure + NL); 2471 } 2472 out.writeUTF(NL); 2473 // Add extra blank lines for clarity 2474 out.writeUTF(NL); 2475 out.writeUTF(NL); 2476 } 2477 if (mDeletedSSIDs != null && mDeletedSSIDs.size() > 0) { 2478 for (Long i : mDeletedSSIDs) { 2479 out.writeUTF(DELETED_CRC32_KEY); 2480 out.writeUTF(String.valueOf(i)); 2481 out.writeUTF(NL); 2482 } 2483 } 2484 if (mDeletedEphemeralSSIDs != null && mDeletedEphemeralSSIDs.size() > 0) { 2485 for (String ssid : mDeletedEphemeralSSIDs) { 2486 out.writeUTF(DELETED_EPHEMERAL_KEY); 2487 out.writeUTF(ssid); 2488 out.writeUTF(NL); 2489 } 2490 } 2491 } 2492 }); 2493 } 2494 2495 public void setAndEnableLastSelectedConfiguration(int netId) { 2496 if (VDBG) { 2497 loge("setLastSelectedConfiguration " + Integer.toString(netId)); 2498 } 2499 if (netId == WifiConfiguration.INVALID_NETWORK_ID) { 2500 lastSelectedConfiguration = null; 2501 mLastSelectedTimeStamp = -1; 2502 } else { 2503 WifiConfiguration selected = getWifiConfiguration(netId); 2504 if (selected == null) { 2505 lastSelectedConfiguration = null; 2506 mLastSelectedTimeStamp = -1; 2507 } else { 2508 lastSelectedConfiguration = selected.configKey(); 2509 mLastSelectedTimeStamp = System.currentTimeMillis(); 2510 if (selected.status == Status.DISABLED) { 2511 mWifiNative.enableNetwork(netId, false); 2512 } 2513 updateNetworkSelectionStatus(netId, 2514 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 2515 if (VDBG) { 2516 loge("setLastSelectedConfiguration now: " + lastSelectedConfiguration); 2517 } 2518 } 2519 } 2520 } 2521 2522 public void setLatestUserSelectedConfiguration(WifiConfiguration network) { 2523 if (network != null) { 2524 lastSelectedConfiguration = network.configKey(); 2525 mLastSelectedTimeStamp = System.currentTimeMillis(); 2526 } 2527 } 2528 2529 public String getLastSelectedConfiguration() { 2530 return lastSelectedConfiguration; 2531 } 2532 2533 public long getLastSelectedTimeStamp() { 2534 return mLastSelectedTimeStamp; 2535 } 2536 2537 public boolean isLastSelectedConfiguration(WifiConfiguration config) { 2538 return (lastSelectedConfiguration != null 2539 && config != null 2540 && lastSelectedConfiguration.equals(config.configKey())); 2541 } 2542 2543 /** 2544 * Adds information stored in networkHistory.txt to the given configs. The configs are provided 2545 * as a mapping from configKey to WifiConfiguration, because the WifiConfigurations themselves 2546 * do not contain sufficient information to compute their configKeys until after the information 2547 * that is stored in networkHistory.txt has been added to them. 2548 * 2549 * @param configs mapping from configKey to a WifiConfiguration that contains the information 2550 * information read from wpa_supplicant.conf 2551 */ 2552 private void readNetworkHistory(Map<String, WifiConfiguration> configs) { 2553 if (showNetworks) { 2554 localLog("readNetworkHistory() path:" + networkHistoryConfigFile); 2555 } 2556 2557 try (DataInputStream in = 2558 new DataInputStream(new BufferedInputStream( 2559 new FileInputStream(networkHistoryConfigFile)))) { 2560 2561 String bssid = null; 2562 String ssid = null; 2563 2564 int freq = 0; 2565 int status = 0; 2566 long seen = 0; 2567 int rssi = WifiConfiguration.INVALID_RSSI; 2568 String caps = null; 2569 2570 WifiConfiguration config = null; 2571 while (true) { 2572 String line = in.readUTF(); 2573 if (line == null) { 2574 break; 2575 } 2576 int colon = line.indexOf(':'); 2577 if (colon < 0) { 2578 continue; 2579 } 2580 2581 String key = line.substring(0, colon).trim(); 2582 String value = line.substring(colon + 1).trim(); 2583 2584 if (key.equals(CONFIG_KEY)) { 2585 config = configs.get(value); 2586 2587 // skip reading that configuration data 2588 // since we don't have a corresponding network ID 2589 if (config == null) { 2590 localLog("readNetworkHistory didnt find netid for hash=" 2591 + Integer.toString(value.hashCode()) 2592 + " key: " + value); 2593 mLostConfigsDbg.add(value); 2594 continue; 2595 } else { 2596 // After an upgrade count old connections as owned by system 2597 if (config.creatorName == null || config.lastUpdateName == null) { 2598 config.creatorName = 2599 mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID); 2600 config.lastUpdateName = config.creatorName; 2601 2602 if (DBG) Log.w(TAG, "Upgrading network " + config.networkId 2603 + " to " + config.creatorName); 2604 } 2605 } 2606 } else if (config != null) { 2607 WifiConfiguration.NetworkSelectionStatus networkStatus = 2608 config.getNetworkSelectionStatus(); 2609 switch (key) { 2610 case SSID_KEY: 2611 if (config.isPasspoint()) { 2612 break; 2613 } 2614 ssid = value; 2615 if (config.SSID != null && !config.SSID.equals(ssid)) { 2616 loge("Error parsing network history file, mismatched SSIDs"); 2617 config = null; //error 2618 ssid = null; 2619 } else { 2620 config.SSID = ssid; 2621 } 2622 break; 2623 case CONFIG_BSSID_KEY: 2624 config.BSSID = value.equals("null") ? null : value; 2625 break; 2626 case FQDN_KEY: 2627 // Check for literal 'null' to be backwards compatible. 2628 config.FQDN = value.equals("null") ? null : value; 2629 break; 2630 case DEFAULT_GW_KEY: 2631 config.defaultGwMacAddress = value; 2632 break; 2633 case SELF_ADDED_KEY: 2634 config.selfAdded = Boolean.parseBoolean(value); 2635 break; 2636 case DID_SELF_ADD_KEY: 2637 config.didSelfAdd = Boolean.parseBoolean(value); 2638 break; 2639 case NO_INTERNET_ACCESS_REPORTS_KEY: 2640 config.numNoInternetAccessReports = Integer.parseInt(value); 2641 break; 2642 case VALIDATED_INTERNET_ACCESS_KEY: 2643 config.validatedInternetAccess = Boolean.parseBoolean(value); 2644 break; 2645 case CREATION_TIME_KEY: 2646 config.creationTime = value; 2647 break; 2648 case UPDATE_TIME_KEY: 2649 config.updateTime = value; 2650 break; 2651 case EPHEMERAL_KEY: 2652 config.ephemeral = Boolean.parseBoolean(value); 2653 break; 2654 case CREATOR_UID_KEY: 2655 config.creatorUid = Integer.parseInt(value); 2656 break; 2657 case BLACKLIST_MILLI_KEY: 2658 networkStatus.setDisableTime(Long.parseLong(value)); 2659 break; 2660 case SCORER_OVERRIDE_KEY: 2661 config.numScorerOverride = Integer.parseInt(value); 2662 break; 2663 case SCORER_OVERRIDE_AND_SWITCH_KEY: 2664 config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(value); 2665 break; 2666 case NUM_ASSOCIATION_KEY: 2667 config.numAssociation = Integer.parseInt(value); 2668 break; 2669 case CONNECT_UID_KEY: 2670 config.lastConnectUid = Integer.parseInt(value); 2671 break; 2672 case UPDATE_UID_KEY: 2673 config.lastUpdateUid = Integer.parseInt(value); 2674 break; 2675 case FAILURE_KEY: 2676 config.lastFailure = value; 2677 break; 2678 case PEER_CONFIGURATION_KEY: 2679 config.peerWifiConfiguration = value; 2680 break; 2681 case CHOICE_KEY: 2682 networkStatus.setConnectChoice(value); 2683 break; 2684 case CHOICE_TIME_KEY: 2685 networkStatus.setConnectChoiceTimestamp(Long.parseLong(value)); 2686 break; 2687 case LINK_KEY: 2688 if (config.linkedConfigurations == null) { 2689 config.linkedConfigurations = new HashMap<>(); 2690 } 2691 else { 2692 config.linkedConfigurations.put(value, -1); 2693 } 2694 break; 2695 case BSSID_KEY: 2696 status = 0; 2697 ssid = null; 2698 bssid = null; 2699 freq = 0; 2700 seen = 0; 2701 rssi = WifiConfiguration.INVALID_RSSI; 2702 caps = ""; 2703 break; 2704 case RSSI_KEY: 2705 rssi = Integer.parseInt(value); 2706 break; 2707 case FREQ_KEY: 2708 freq = Integer.parseInt(value); 2709 break; 2710 case DATE_KEY: 2711 /* 2712 * when reading the configuration from file we don't update the date 2713 * so as to avoid reading back stale or non-sensical data that would 2714 * depend on network time. 2715 * The date of a WifiConfiguration should only come from actual scan result. 2716 * 2717 String s = key.replace(FREQ_KEY, ""); 2718 seen = Integer.getInteger(s); 2719 */ 2720 break; 2721 case BSSID_KEY_END: 2722 if ((bssid != null) && (ssid != null)) { 2723 2724 if (getScanDetailCache(config) != null) { 2725 WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid); 2726 ScanDetail scanDetail = new ScanDetail(wssid, bssid, 2727 caps, rssi, freq, (long) 0, seen); 2728 getScanDetailCache(config).put(scanDetail); 2729 scanDetail.getScanResult().autoJoinStatus = status; 2730 } 2731 } 2732 break; 2733 case DELETED_CRC32_KEY: 2734 mDeletedSSIDs.add(Long.parseLong(value)); 2735 break; 2736 case DELETED_EPHEMERAL_KEY: 2737 if (!TextUtils.isEmpty(value)) { 2738 mDeletedEphemeralSSIDs.add(value); 2739 } 2740 break; 2741 case CREATOR_NAME_KEY: 2742 config.creatorName = value; 2743 break; 2744 case UPDATE_NAME_KEY: 2745 config.lastUpdateName = value; 2746 break; 2747 case USER_APPROVED_KEY: 2748 config.userApproved = Integer.parseInt(value); 2749 break; 2750 case SHARED_KEY: 2751 config.shared = Boolean.parseBoolean(value); 2752 break; 2753 } 2754 } 2755 } 2756 } catch (NumberFormatException e) { 2757 Log.e(TAG, "readNetworkHistory: failed to read, revert to default, " + e, e); 2758 } catch (EOFException e) { 2759 // do nothing 2760 } catch (IOException e) { 2761 Log.e(TAG, "readNetworkHistory: No config file, revert to default, " + e, e); 2762 } 2763 } 2764 2765 private void readAutoJoinConfig() { 2766 try (BufferedReader reader = new BufferedReader(new FileReader(autoJoinConfigFile))) { 2767 for (String key = reader.readLine(); key != null; key = reader.readLine()) { 2768 Log.d(TAG, "readAutoJoinConfig line: " + key); 2769 2770 int split = key.indexOf(':'); 2771 if (split < 0) { 2772 continue; 2773 } 2774 2775 String name = key.substring(0, split); 2776 Object reference = sKeyMap.get(name); 2777 if (reference == null) { 2778 continue; 2779 } 2780 2781 try { 2782 int value = Integer.parseInt(key.substring(split+1).trim()); 2783 if (reference.getClass() == AtomicBoolean.class) { 2784 ((AtomicBoolean)reference).set(value != 0); 2785 } 2786 else { 2787 ((AtomicInteger)reference).set(value); 2788 } 2789 Log.d(TAG,"readAutoJoinConfig: " + name + " = " + value); 2790 } 2791 catch (NumberFormatException nfe) { 2792 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 2793 } 2794 } 2795 } catch (IOException e) { 2796 loge("readNetworkSelectionStatus: Error parsing configuration" + e); 2797 } 2798 } 2799 2800 2801 private void writeIpAndProxyConfigurations() { 2802 final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>(); 2803 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 2804 if (!config.ephemeral) { 2805 networks.put(configKey(config), config.getIpConfiguration()); 2806 } 2807 } 2808 2809 super.writeIpAndProxyConfigurations(ipConfigFile, networks); 2810 } 2811 2812 private void readIpAndProxyConfigurations() { 2813 SparseArray<IpConfiguration> networks = super.readIpAndProxyConfigurations(ipConfigFile); 2814 2815 if (networks == null || networks.size() == 0) { 2816 // IpConfigStore.readIpAndProxyConfigurations has already logged an error. 2817 return; 2818 } 2819 2820 for (int i = 0; i < networks.size(); i++) { 2821 int id = networks.keyAt(i); 2822 WifiConfiguration config = mConfiguredNetworks.getByConfigKeyIDForAllUsers(id); 2823 // This is the only place the map is looked up through a (dangerous) hash-value! 2824 2825 if (config == null || config.ephemeral) { 2826 loge("configuration found for missing network, nid=" + id 2827 +", ignored, networks.size=" + Integer.toString(networks.size())); 2828 } else { 2829 config.setIpConfiguration(networks.valueAt(i)); 2830 } 2831 } 2832 } 2833 2834 /* 2835 * Convert string to Hexadecimal before passing to wifi native layer 2836 * In native function "doCommand()" have trouble in converting Unicode character string to UTF8 2837 * conversion to hex is required because SSIDs can have space characters in them; 2838 * and that can confuses the supplicant because it uses space charaters as delimiters 2839 */ 2840 2841 public static String encodeSSID(String str){ 2842 return Utils.toHex(removeDoubleQuotes(str).getBytes(StandardCharsets.UTF_8)); 2843 } 2844 2845 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config, int uid) { 2846 /* 2847 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 2848 * network configuration. Otherwise, the networkId should 2849 * refer to an existing configuration. 2850 */ 2851 2852 if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 2853 if (config.isPasspoint() && !mMOManager.isEnabled()) { 2854 Log.e(TAG, "Passpoint is not enabled"); 2855 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2856 } 2857 2858 int netId = config.networkId; 2859 boolean newNetwork = false; 2860 boolean existingMO = false; 2861 // networkId of INVALID_NETWORK_ID means we want to create a new network 2862 if (netId == INVALID_NETWORK_ID) { 2863 WifiConfiguration savedConfig = 2864 mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 2865 if (savedConfig != null) { 2866 netId = savedConfig.networkId; 2867 } else { 2868 if (mMOManager.getHomeSP(config.FQDN) != null) { 2869 loge("addOrUpdateNetworkNative passpoint " + config.FQDN 2870 + " was found, but no network Id"); 2871 existingMO = true; 2872 } 2873 newNetwork = true; 2874 netId = mWifiNative.addNetwork(); 2875 if (netId < 0) { 2876 loge("Failed to add a network!"); 2877 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2878 } else { 2879 loge("addOrUpdateNetworkNative created netId=" + netId); 2880 } 2881 } 2882 } 2883 2884 boolean updateFailed = true; 2885 2886 setVariables: { 2887 2888 if (config.SSID != null && 2889 !mWifiNative.setNetworkVariable( 2890 netId, 2891 WifiConfiguration.ssidVarName, 2892 encodeSSID(config.SSID))) { 2893 loge("failed to set SSID: "+config.SSID); 2894 break setVariables; 2895 } 2896 2897 final Map<String, String> metadata = new HashMap<String, String>(); 2898 if (config.isPasspoint()) { 2899 metadata.put(ID_STRING_KEY_FQDN, config.FQDN); 2900 } 2901 metadata.put(ID_STRING_KEY_CONFIG_KEY, config.configKey()); 2902 metadata.put(ID_STRING_KEY_CREATOR_UID, Integer.toString(config.creatorUid)); 2903 if (!mWifiNative.setNetworkExtra(netId, ID_STRING_VAR_NAME, metadata)) { 2904 loge("failed to set id_str: " + metadata.toString()); 2905 break setVariables; 2906 } 2907 2908 //set selected BSSID to supplicant 2909 if (config.getNetworkSelectionStatus().getNetworkSelectionBSSID() != null) { 2910 String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 2911 if (!mWifiNative.setNetworkVariable( 2912 netId, 2913 WifiConfiguration.bssidVarName, 2914 bssid)) { 2915 loge("failed to set BSSID: " + bssid); 2916 break setVariables; 2917 } 2918 } 2919 2920 String allowedKeyManagementString = 2921 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 2922 if (config.allowedKeyManagement.cardinality() != 0 && 2923 !mWifiNative.setNetworkVariable( 2924 netId, 2925 WifiConfiguration.KeyMgmt.varName, 2926 allowedKeyManagementString)) { 2927 loge("failed to set key_mgmt: "+ 2928 allowedKeyManagementString); 2929 break setVariables; 2930 } 2931 2932 String allowedProtocolsString = 2933 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 2934 if (config.allowedProtocols.cardinality() != 0 && 2935 !mWifiNative.setNetworkVariable( 2936 netId, 2937 WifiConfiguration.Protocol.varName, 2938 allowedProtocolsString)) { 2939 loge("failed to set proto: "+ 2940 allowedProtocolsString); 2941 break setVariables; 2942 } 2943 2944 String allowedAuthAlgorithmsString = 2945 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 2946 if (config.allowedAuthAlgorithms.cardinality() != 0 && 2947 !mWifiNative.setNetworkVariable( 2948 netId, 2949 WifiConfiguration.AuthAlgorithm.varName, 2950 allowedAuthAlgorithmsString)) { 2951 loge("failed to set auth_alg: "+ 2952 allowedAuthAlgorithmsString); 2953 break setVariables; 2954 } 2955 2956 String allowedPairwiseCiphersString = 2957 makeString(config.allowedPairwiseCiphers, 2958 WifiConfiguration.PairwiseCipher.strings); 2959 if (config.allowedPairwiseCiphers.cardinality() != 0 && 2960 !mWifiNative.setNetworkVariable( 2961 netId, 2962 WifiConfiguration.PairwiseCipher.varName, 2963 allowedPairwiseCiphersString)) { 2964 loge("failed to set pairwise: "+ 2965 allowedPairwiseCiphersString); 2966 break setVariables; 2967 } 2968 2969 String allowedGroupCiphersString = 2970 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 2971 if (config.allowedGroupCiphers.cardinality() != 0 && 2972 !mWifiNative.setNetworkVariable( 2973 netId, 2974 WifiConfiguration.GroupCipher.varName, 2975 allowedGroupCiphersString)) { 2976 loge("failed to set group: "+ 2977 allowedGroupCiphersString); 2978 break setVariables; 2979 } 2980 2981 // Prevent client screw-up by passing in a WifiConfiguration we gave it 2982 // by preventing "*" as a key. 2983 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 2984 !mWifiNative.setNetworkVariable( 2985 netId, 2986 WifiConfiguration.pskVarName, 2987 config.preSharedKey)) { 2988 loge("failed to set psk"); 2989 break setVariables; 2990 } 2991 2992 boolean hasSetKey = false; 2993 if (config.wepKeys != null) { 2994 for (int i = 0; i < config.wepKeys.length; i++) { 2995 // Prevent client screw-up by passing in a WifiConfiguration we gave it 2996 // by preventing "*" as a key. 2997 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 2998 if (!mWifiNative.setNetworkVariable( 2999 netId, 3000 WifiConfiguration.wepKeyVarNames[i], 3001 config.wepKeys[i])) { 3002 loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); 3003 break setVariables; 3004 } 3005 hasSetKey = true; 3006 } 3007 } 3008 } 3009 3010 if (hasSetKey) { 3011 if (!mWifiNative.setNetworkVariable( 3012 netId, 3013 WifiConfiguration.wepTxKeyIdxVarName, 3014 Integer.toString(config.wepTxKeyIndex))) { 3015 loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); 3016 break setVariables; 3017 } 3018 } 3019 3020 if (!mWifiNative.setNetworkVariable( 3021 netId, 3022 WifiConfiguration.priorityVarName, 3023 Integer.toString(config.priority))) { 3024 loge(config.SSID + ": failed to set priority: " 3025 +config.priority); 3026 break setVariables; 3027 } 3028 3029 if (config.hiddenSSID && !mWifiNative.setNetworkVariable( 3030 netId, 3031 WifiConfiguration.hiddenSSIDVarName, 3032 Integer.toString(config.hiddenSSID ? 1 : 0))) { 3033 loge(config.SSID + ": failed to set hiddenSSID: "+ 3034 config.hiddenSSID); 3035 break setVariables; 3036 } 3037 3038 if (config.requirePMF && !mWifiNative.setNetworkVariable( 3039 netId, 3040 WifiConfiguration.pmfVarName, 3041 "2")) { 3042 loge(config.SSID + ": failed to set requirePMF: "+ 3043 config.requirePMF); 3044 break setVariables; 3045 } 3046 3047 if (config.updateIdentifier != null && !mWifiNative.setNetworkVariable( 3048 netId, 3049 WifiConfiguration.updateIdentiferVarName, 3050 config.updateIdentifier)) { 3051 loge(config.SSID + ": failed to set updateIdentifier: "+ 3052 config.updateIdentifier); 3053 break setVariables; 3054 } 3055 3056 if (config.enterpriseConfig != null && 3057 config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { 3058 3059 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 3060 3061 if (needsKeyStore(enterpriseConfig)) { 3062 /** 3063 * Keyguard settings may eventually be controlled by device policy. 3064 * We check here if keystore is unlocked before installing 3065 * credentials. 3066 * TODO: Do we need a dialog here ? 3067 */ 3068 if (mKeyStore.state() != KeyStore.State.UNLOCKED) { 3069 loge(config.SSID + ": key store is locked"); 3070 break setVariables; 3071 } 3072 3073 try { 3074 /* config passed may include only fields being updated. 3075 * In order to generate the key id, fetch uninitialized 3076 * fields from the currently tracked configuration 3077 */ 3078 WifiConfiguration currentConfig = 3079 mConfiguredNetworks.getForCurrentUser(netId); 3080 String keyId = config.getKeyIdForCredentials(currentConfig); 3081 3082 if (!installKeys(currentConfig != null 3083 ? currentConfig.enterpriseConfig : null, enterpriseConfig, keyId)) { 3084 loge(config.SSID + ": failed to install keys"); 3085 break setVariables; 3086 } 3087 } catch (IllegalStateException e) { 3088 loge(config.SSID + " invalid config for key installation"); 3089 break setVariables; 3090 } 3091 } 3092 3093 HashMap<String, String> enterpriseFields = enterpriseConfig.getFields(); 3094 for (String key : enterpriseFields.keySet()) { 3095 String value = enterpriseFields.get(key); 3096 if (key.equals("password") && value != null && value.equals("*")) { 3097 // No need to try to set an obfuscated password, which will fail 3098 continue; 3099 } 3100 if (key.equals(WifiEnterpriseConfig.REALM_KEY) 3101 || key.equals(WifiEnterpriseConfig.PLMN_KEY)) { 3102 // No need to save realm or PLMN in supplicant 3103 continue; 3104 } 3105 if (!mWifiNative.setNetworkVariable( 3106 netId, 3107 key, 3108 value)) { 3109 removeKeys(enterpriseConfig); 3110 loge(config.SSID + ": failed to set " + key + 3111 ": " + value); 3112 break setVariables; 3113 } 3114 } 3115 } 3116 updateFailed = false; 3117 } // End of setVariables 3118 3119 if (updateFailed) { 3120 if (newNetwork) { 3121 mWifiNative.removeNetwork(netId); 3122 loge("Failed to set a network variable, removed network: " + netId); 3123 } 3124 return new NetworkUpdateResult(INVALID_NETWORK_ID); 3125 } 3126 3127 /* An update of the network variables requires reading them 3128 * back from the supplicant to update mConfiguredNetworks. 3129 * This is because some of the variables (SSID, wep keys & 3130 * passphrases) reflect different values when read back than 3131 * when written. For example, wep key is stored as * irrespective 3132 * of the value sent to the supplicant 3133 */ 3134 WifiConfiguration currentConfig = mConfiguredNetworks.getForCurrentUser(netId); 3135 if (currentConfig == null) { 3136 currentConfig = new WifiConfiguration(); 3137 currentConfig.setIpAssignment(IpAssignment.DHCP); 3138 currentConfig.setProxySettings(ProxySettings.NONE); 3139 currentConfig.networkId = netId; 3140 if (config != null) { 3141 // Carry over the creation parameters 3142 currentConfig.selfAdded = config.selfAdded; 3143 currentConfig.didSelfAdd = config.didSelfAdd; 3144 currentConfig.ephemeral = config.ephemeral; 3145 currentConfig.lastConnectUid = config.lastConnectUid; 3146 currentConfig.lastUpdateUid = config.lastUpdateUid; 3147 currentConfig.creatorUid = config.creatorUid; 3148 currentConfig.creatorName = config.creatorName; 3149 currentConfig.lastUpdateName = config.lastUpdateName; 3150 currentConfig.peerWifiConfiguration = config.peerWifiConfiguration; 3151 currentConfig.FQDN = config.FQDN; 3152 currentConfig.providerFriendlyName = config.providerFriendlyName; 3153 currentConfig.roamingConsortiumIds = config.roamingConsortiumIds; 3154 currentConfig.validatedInternetAccess = config.validatedInternetAccess; 3155 currentConfig.numNoInternetAccessReports = config.numNoInternetAccessReports; 3156 currentConfig.updateTime = config.updateTime; 3157 currentConfig.creationTime = config.creationTime; 3158 currentConfig.shared = config.shared; 3159 } 3160 if (DBG) { 3161 log("created new config netId=" + Integer.toString(netId) 3162 + " uid=" + Integer.toString(currentConfig.creatorUid) 3163 + " name=" + currentConfig.creatorName); 3164 } 3165 } 3166 3167 /* save HomeSP object for passpoint networks */ 3168 HomeSP homeSP = null; 3169 3170 if (!existingMO && config.isPasspoint()) { 3171 try { 3172 Credential credential = 3173 new Credential(config.enterpriseConfig, mKeyStore, !newNetwork); 3174 HashSet<Long> roamingConsortiumIds = new HashSet<Long>(); 3175 for (Long roamingConsortiumId : config.roamingConsortiumIds) { 3176 roamingConsortiumIds.add(roamingConsortiumId); 3177 } 3178 3179 homeSP = new HomeSP(Collections.<String, Long>emptyMap(), config.FQDN, 3180 roamingConsortiumIds, Collections.<String>emptySet(), 3181 Collections.<Long>emptySet(), Collections.<Long>emptyList(), 3182 config.providerFriendlyName, null, credential); 3183 3184 log("created a homeSP object for " + config.networkId + ":" + config.SSID); 3185 3186 /* fix enterprise config properties for passpoint */ 3187 currentConfig.enterpriseConfig.setRealm(config.enterpriseConfig.getRealm()); 3188 currentConfig.enterpriseConfig.setPlmn(config.enterpriseConfig.getPlmn()); 3189 } 3190 catch (IOException ioe) { 3191 Log.e(TAG, "Failed to create Passpoint config: " + ioe); 3192 return new NetworkUpdateResult(INVALID_NETWORK_ID); 3193 } 3194 } 3195 3196 if (uid != WifiConfiguration.UNKNOWN_UID) { 3197 if (newNetwork) { 3198 currentConfig.creatorUid = uid; 3199 } else { 3200 currentConfig.lastUpdateUid = uid; 3201 } 3202 } 3203 3204 // For debug, record the time the configuration was modified 3205 StringBuilder sb = new StringBuilder(); 3206 sb.append("time="); 3207 Calendar c = Calendar.getInstance(); 3208 c.setTimeInMillis(System.currentTimeMillis()); 3209 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 3210 3211 if (newNetwork) { 3212 currentConfig.creationTime = sb.toString(); 3213 } else { 3214 currentConfig.updateTime = sb.toString(); 3215 } 3216 3217 if (currentConfig.status == WifiConfiguration.Status.ENABLED) { 3218 // Make sure autojoin remain in sync with user modifying the configuration 3219 updateNetworkSelectionStatus(currentConfig.networkId, 3220 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 3221 } 3222 3223 if (currentConfig.configKey().equals(getLastSelectedConfiguration()) && 3224 currentConfig.ephemeral) { 3225 // Make the config non-ephemeral since the user just explicitly clicked it. 3226 currentConfig.ephemeral = false; 3227 if (DBG) log("remove ephemeral status netId=" + Integer.toString(netId) 3228 + " " + currentConfig.configKey()); 3229 } 3230 3231 if (VDBG) log("will read network variables netId=" + Integer.toString(netId)); 3232 3233 readNetworkVariables(currentConfig); 3234 3235 // Persist configuration paramaters that are not saved by supplicant. 3236 if (config.lastUpdateName != null) { 3237 currentConfig.lastUpdateName = config.lastUpdateName; 3238 } 3239 if (config.lastUpdateUid != WifiConfiguration.UNKNOWN_UID) { 3240 currentConfig.lastUpdateUid = config.lastUpdateUid; 3241 } 3242 3243 mConfiguredNetworks.put(currentConfig); 3244 3245 NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); 3246 result.setIsNewNetwork(newNetwork); 3247 result.setNetworkId(netId); 3248 3249 if (homeSP != null) { 3250 writePasspointConfigs(null, homeSP); 3251 } 3252 3253 writeKnownNetworkHistory(); 3254 3255 return result; 3256 } 3257 3258 public WifiConfiguration getWifiConfigForHomeSP(HomeSP homeSP) { 3259 WifiConfiguration config = mConfiguredNetworks.getByFQDNForCurrentUser(homeSP.getFQDN()); 3260 if (config == null) { 3261 Log.e(TAG, "Could not find network for homeSP " + homeSP.getFQDN()); 3262 } 3263 return config; 3264 } 3265 3266 public HomeSP getHomeSPForConfig(WifiConfiguration config) { 3267 WifiConfiguration storedConfig = mConfiguredNetworks.getForCurrentUser(config.networkId); 3268 return storedConfig != null && storedConfig.isPasspoint() ? 3269 mMOManager.getHomeSP(storedConfig.FQDN) : null; 3270 } 3271 3272 public ScanDetailCache getScanDetailCache(WifiConfiguration config) { 3273 if (config == null) return null; 3274 ScanDetailCache cache = mScanDetailCaches.get(config.networkId); 3275 if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { 3276 cache = new ScanDetailCache(config); 3277 mScanDetailCaches.put(config.networkId, cache); 3278 } 3279 return cache; 3280 } 3281 3282 /** 3283 * This function run thru the Saved WifiConfigurations and check if some should be linked. 3284 * @param config 3285 */ 3286 public void linkConfiguration(WifiConfiguration config) { 3287 if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { 3288 loge("linkConfiguration: Attempting to link config " + config.configKey() 3289 + " that is not visible to the current user."); 3290 return; 3291 } 3292 3293 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 6) { 3294 // Ignore configurations with large number of BSSIDs 3295 return; 3296 } 3297 if (!config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 3298 // Only link WPA_PSK config 3299 return; 3300 } 3301 for (WifiConfiguration link : mConfiguredNetworks.valuesForCurrentUser()) { 3302 boolean doLink = false; 3303 3304 if (link.configKey().equals(config.configKey())) { 3305 continue; 3306 } 3307 3308 if (link.ephemeral) { 3309 continue; 3310 } 3311 3312 // Autojoin will be allowed to dynamically jump from a linked configuration 3313 // to another, hence only link configurations that have equivalent level of security 3314 if (!link.allowedKeyManagement.equals(config.allowedKeyManagement)) { 3315 continue; 3316 } 3317 3318 ScanDetailCache linkedScanDetailCache = getScanDetailCache(link); 3319 if (linkedScanDetailCache != null && linkedScanDetailCache.size() > 6) { 3320 // Ignore configurations with large number of BSSIDs 3321 continue; 3322 } 3323 3324 if (config.defaultGwMacAddress != null && link.defaultGwMacAddress != null) { 3325 // If both default GW are known, link only if they are equal 3326 if (config.defaultGwMacAddress.equals(link.defaultGwMacAddress)) { 3327 if (VDBG) { 3328 loge("linkConfiguration link due to same gw " + link.SSID + 3329 " and " + config.SSID + " GW " + config.defaultGwMacAddress); 3330 } 3331 doLink = true; 3332 } 3333 } else { 3334 // We do not know BOTH default gateways hence we will try to link 3335 // hoping that WifiConfigurations are indeed behind the same gateway. 3336 // once both WifiConfiguration have been tried and thus once both efault gateways 3337 // are known we will revisit the choice of linking them 3338 if ((getScanDetailCache(config) != null) 3339 && (getScanDetailCache(config).size() <= 6)) { 3340 3341 for (String abssid : getScanDetailCache(config).keySet()) { 3342 for (String bbssid : linkedScanDetailCache.keySet()) { 3343 if (VVDBG) { 3344 loge("linkConfiguration try to link due to DBDC BSSID match " 3345 + link.SSID + 3346 " and " + config.SSID + " bssida " + abssid 3347 + " bssidb " + bbssid); 3348 } 3349 if (abssid.regionMatches(true, 0, bbssid, 0, 16)) { 3350 // If first 16 ascii characters of BSSID matches, 3351 // we assume this is a DBDC 3352 doLink = true; 3353 } 3354 } 3355 } 3356 } 3357 } 3358 3359 if (doLink == true && onlyLinkSameCredentialConfigurations) { 3360 String apsk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); 3361 String bpsk = readNetworkVariableFromSupplicantFile(config.SSID, "psk"); 3362 if (apsk == null || bpsk == null 3363 || TextUtils.isEmpty(apsk) || TextUtils.isEmpty(apsk) 3364 || apsk.equals("*") || apsk.equals(DELETED_CONFIG_PSK) 3365 || !apsk.equals(bpsk)) { 3366 doLink = false; 3367 } 3368 } 3369 3370 if (doLink) { 3371 if (VDBG) { 3372 loge("linkConfiguration: will link " + link.configKey() 3373 + " and " + config.configKey()); 3374 } 3375 if (link.linkedConfigurations == null) { 3376 link.linkedConfigurations = new HashMap<String, Integer>(); 3377 } 3378 if (config.linkedConfigurations == null) { 3379 config.linkedConfigurations = new HashMap<String, Integer>(); 3380 } 3381 if (link.linkedConfigurations.get(config.configKey()) == null) { 3382 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 3383 } 3384 if (config.linkedConfigurations.get(link.configKey()) == null) { 3385 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 3386 } 3387 } else { 3388 if (link.linkedConfigurations != null 3389 && (link.linkedConfigurations.get(config.configKey()) != null)) { 3390 if (VDBG) { 3391 loge("linkConfiguration: un-link " + config.configKey() 3392 + " from " + link.configKey()); 3393 } 3394 link.linkedConfigurations.remove(config.configKey()); 3395 } 3396 if (config.linkedConfigurations != null 3397 && (config.linkedConfigurations.get(link.configKey()) != null)) { 3398 if (VDBG) { 3399 loge("linkConfiguration: un-link " + link.configKey() 3400 + " from " + config.configKey()); 3401 } 3402 config.linkedConfigurations.remove(link.configKey()); 3403 } 3404 } 3405 } 3406 } 3407 3408 public HashSet<Integer> makeChannelList(WifiConfiguration config, int age, boolean restrict) { 3409 if (config == null) 3410 return null; 3411 long now_ms = System.currentTimeMillis(); 3412 3413 HashSet<Integer> channels = new HashSet<Integer>(); 3414 3415 //get channels for this configuration, if there are at least 2 BSSIDs 3416 if (getScanDetailCache(config) == null && config.linkedConfigurations == null) { 3417 return null; 3418 } 3419 3420 if (VDBG) { 3421 StringBuilder dbg = new StringBuilder(); 3422 dbg.append("makeChannelList age=" + Integer.toString(age) 3423 + " for " + config.configKey() 3424 + " max=" + maxNumActiveChannelsForPartialScans); 3425 if (getScanDetailCache(config) != null) { 3426 dbg.append(" bssids=" + getScanDetailCache(config).size()); 3427 } 3428 if (config.linkedConfigurations != null) { 3429 dbg.append(" linked=" + config.linkedConfigurations.size()); 3430 } 3431 loge(dbg.toString()); 3432 } 3433 3434 int numChannels = 0; 3435 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 0) { 3436 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 3437 ScanResult result = scanDetail.getScanResult(); 3438 //TODO : cout active and passive channels separately 3439 if (numChannels > maxNumActiveChannelsForPartialScans.get()) { 3440 break; 3441 } 3442 if (VDBG) { 3443 boolean test = (now_ms - result.seen) < age; 3444 loge("has " + result.BSSID + " freq=" + Integer.toString(result.frequency) 3445 + " age=" + Long.toString(now_ms - result.seen) + " ?=" + test); 3446 } 3447 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 3448 channels.add(result.frequency); 3449 numChannels++; 3450 } 3451 } 3452 } 3453 3454 //get channels for linked configurations 3455 if (config.linkedConfigurations != null) { 3456 for (String key : config.linkedConfigurations.keySet()) { 3457 WifiConfiguration linked = getWifiConfiguration(key); 3458 if (linked == null) 3459 continue; 3460 if (getScanDetailCache(linked) == null) { 3461 continue; 3462 } 3463 for (ScanDetail scanDetail : getScanDetailCache(linked).values()) { 3464 ScanResult result = scanDetail.getScanResult(); 3465 if (VDBG) { 3466 loge("has link: " + result.BSSID 3467 + " freq=" + Integer.toString(result.frequency) 3468 + " age=" + Long.toString(now_ms - result.seen)); 3469 } 3470 if (numChannels > maxNumActiveChannelsForPartialScans.get()) { 3471 break; 3472 } 3473 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 3474 channels.add(result.frequency); 3475 numChannels++; 3476 } 3477 } 3478 } 3479 } 3480 return channels; 3481 } 3482 3483 private Map<HomeSP, PasspointMatch> matchPasspointNetworks(ScanDetail scanDetail) { 3484 if (!mMOManager.isConfigured()) { 3485 if (mOSUManager.enableOSUQueries()) { 3486 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3487 List<Constants.ANQPElementType> querySet = 3488 ANQPFactory.buildQueryList(networkDetail, false, true); 3489 3490 if (networkDetail.queriable(querySet)) { 3491 querySet = mAnqpCache.initiate(networkDetail, querySet); 3492 if (querySet != null) { 3493 if (mSupplicantBridge.startANQP(scanDetail, querySet)) { 3494 mOSUManager.anqpInitiated(scanDetail); 3495 } 3496 } 3497 updateAnqpCache(scanDetail, networkDetail.getANQPElements()); 3498 } 3499 } 3500 return null; 3501 } 3502 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3503 if (!networkDetail.hasInterworking()) { 3504 return null; 3505 } 3506 updateAnqpCache(scanDetail, networkDetail.getANQPElements()); 3507 3508 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, true); 3509 Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() + 3510 " pass 1 matches: " + toMatchString(matches)); 3511 return matches; 3512 } 3513 3514 private Map<HomeSP, PasspointMatch> matchNetwork(ScanDetail scanDetail, boolean query) { 3515 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3516 3517 ANQPData anqpData = mAnqpCache.getEntry(networkDetail); 3518 3519 Map<Constants.ANQPElementType, ANQPElement> anqpElements = 3520 anqpData != null ? anqpData.getANQPElements() : null; 3521 3522 boolean queried = !query; 3523 Collection<HomeSP> homeSPs = mMOManager.getLoadedSPs().values(); 3524 Map<HomeSP, PasspointMatch> matches = new HashMap<>(homeSPs.size()); 3525 Log.d(Utils.hs2LogTag(getClass()), "match nwk " + scanDetail.toKeyString() + 3526 ", anqp " + ( anqpData != null ? "present" : "missing" ) + 3527 ", query " + query + ", home sps: " + homeSPs.size()); 3528 3529 for (HomeSP homeSP : homeSPs) { 3530 PasspointMatch match = homeSP.match(networkDetail, anqpElements, mSIMAccessor); 3531 3532 Log.d(Utils.hs2LogTag(getClass()), " -- " + 3533 homeSP.getFQDN() + ": match " + match + ", queried " + queried); 3534 3535 if ((match == PasspointMatch.Incomplete || mOSUManager.enableOSUQueries()) && !queried) { 3536 boolean matchSet = match == PasspointMatch.Incomplete; 3537 boolean osu = mOSUManager.enableOSUQueries(); 3538 List<Constants.ANQPElementType> querySet = 3539 ANQPFactory.buildQueryList(networkDetail, matchSet, osu); 3540 if (networkDetail.queriable(querySet)) { 3541 querySet = mAnqpCache.initiate(networkDetail, querySet); 3542 if (querySet != null) { 3543 if (mSupplicantBridge.startANQP(scanDetail, querySet)) { 3544 mOSUManager.anqpInitiated(scanDetail); 3545 } 3546 } 3547 } 3548 queried = true; 3549 } 3550 matches.put(homeSP, match); 3551 } 3552 return matches; 3553 } 3554 3555 public Map<Constants.ANQPElementType, ANQPElement> getANQPData(NetworkDetail network) { 3556 ANQPData data = mAnqpCache.getEntry(network); 3557 return data != null ? data.getANQPElements() : null; 3558 } 3559 3560 public SIMAccessor getSIMAccessor() { 3561 return mSIMAccessor; 3562 } 3563 3564 public void notifyScanComplete() { 3565 mOSUManager.scanComplete(); 3566 } 3567 3568 public boolean isOSUNetwork(WifiConfiguration config) { 3569 return mOSUManager.isOSU(Utils.unquote(config.SSID)); 3570 } 3571 3572 public void setOSUSelection(int osuID) { 3573 mOSUManager.setOSUSelection(osuID); 3574 } 3575 3576 public void notifyANQPDone(Long bssid, boolean success) { 3577 mSupplicantBridge.notifyANQPDone(bssid, success); 3578 } 3579 3580 public void notifyIconReceived(IconEvent iconEvent) { 3581 mOSUManager.notifyIconReceived(iconEvent); 3582 } 3583 3584 public void notifyIconFailed(long bssid) { 3585 mOSUManager.notifyIconFailed(bssid); 3586 } 3587 3588 public void wnmFrameReceived(String event) { 3589 mOSUManager.wnmReceived(event); 3590 } 3591 3592 public Collection<OSUInfo> getOSUInfos() { 3593 return mOSUManager.getAvailableOSUs(); 3594 } 3595 3596 public void notifyANQPResponse(ScanDetail scanDetail, 3597 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 3598 3599 mOSUManager.anqpDone(scanDetail, anqpElements); 3600 updateAnqpCache(scanDetail, anqpElements); 3601 if (anqpElements == null || anqpElements.isEmpty()) { 3602 return; 3603 } 3604 scanDetail.propagateANQPInfo(anqpElements); 3605 3606 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, false); 3607 Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() + 3608 " pass 2 matches: " + toMatchString(matches)); 3609 3610 cacheScanResultForPasspointConfigs(scanDetail, matches, null); 3611 } 3612 3613 private void updateAnqpCache(ScanDetail scanDetail, 3614 Map<Constants.ANQPElementType,ANQPElement> anqpElements) 3615 { 3616 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3617 3618 if (anqpElements == null) { 3619 // Try to pull cached data if query failed. 3620 ANQPData data = mAnqpCache.getEntry(networkDetail); 3621 if (data != null) { 3622 scanDetail.propagateANQPInfo(data.getANQPElements()); 3623 } 3624 return; 3625 } 3626 3627 mAnqpCache.update(networkDetail, anqpElements); 3628 } 3629 3630 private static String toMatchString(Map<HomeSP, PasspointMatch> matches) { 3631 StringBuilder sb = new StringBuilder(); 3632 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 3633 sb.append(' ').append(entry.getKey().getFQDN()).append("->").append(entry.getValue()); 3634 } 3635 return sb.toString(); 3636 } 3637 3638 private void cacheScanResultForPasspointConfigs(ScanDetail scanDetail, 3639 Map<HomeSP, PasspointMatch> matches, 3640 List<WifiConfiguration> associatedWifiConfigurations) { 3641 3642 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 3643 PasspointMatch match = entry.getValue(); 3644 if (match == PasspointMatch.HomeProvider || match == PasspointMatch.RoamingProvider) { 3645 WifiConfiguration config = getWifiConfigForHomeSP(entry.getKey()); 3646 if (config != null) { 3647 cacheScanResultForConfig(config, scanDetail, entry.getValue()); 3648 if (associatedWifiConfigurations != null) { 3649 associatedWifiConfigurations.add(config); 3650 } 3651 } else { 3652 Log.w(Utils.hs2LogTag(getClass()), "Failed to find config for '" + 3653 entry.getKey().getFQDN() + "'"); 3654 /* perhaps the configuration was deleted?? */ 3655 } 3656 } 3657 } 3658 } 3659 3660 private void cacheScanResultForConfig( 3661 WifiConfiguration config, ScanDetail scanDetail, PasspointMatch passpointMatch) { 3662 3663 ScanResult scanResult = scanDetail.getScanResult(); 3664 3665 ScanDetailCache scanDetailCache = getScanDetailCache(config); 3666 if (scanDetailCache == null) { 3667 Log.w(TAG, "Could not allocate scan cache for " + config.SSID); 3668 return; 3669 } 3670 3671 // Adding a new BSSID 3672 ScanResult result = scanDetailCache.get(scanResult.BSSID); 3673 if (result != null) { 3674 // transfer the black list status 3675 scanResult.autoJoinStatus = result.autoJoinStatus; 3676 scanResult.blackListTimestamp = result.blackListTimestamp; 3677 scanResult.numIpConfigFailures = result.numIpConfigFailures; 3678 scanResult.numConnection = result.numConnection; 3679 scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate; 3680 } 3681 3682 if (config.ephemeral) { 3683 // For an ephemeral Wi-Fi config, the ScanResult should be considered 3684 // untrusted. 3685 scanResult.untrusted = true; 3686 } 3687 3688 if (scanDetailCache.size() > (maxNumScanCacheEntries + 64)) { 3689 long now_dbg = 0; 3690 if (VVDBG) { 3691 loge(" Will trim config " + config.configKey() 3692 + " size " + scanDetailCache.size()); 3693 3694 for (ScanDetail sd : scanDetailCache.values()) { 3695 loge(" " + sd.getBSSIDString() + " " + sd.getSeen()); 3696 } 3697 now_dbg = SystemClock.elapsedRealtimeNanos(); 3698 } 3699 // Trim the scan result cache to maxNumScanCacheEntries entries max 3700 // Since this operation is expensive, make sure it is not performed 3701 // until the cache has grown significantly above the trim treshold 3702 scanDetailCache.trim(maxNumScanCacheEntries); 3703 if (VVDBG) { 3704 long diff = SystemClock.elapsedRealtimeNanos() - now_dbg; 3705 loge(" Finished trimming config, time(ns) " + diff); 3706 for (ScanDetail sd : scanDetailCache.values()) { 3707 loge(" " + sd.getBSSIDString() + " " + sd.getSeen()); 3708 } 3709 } 3710 } 3711 3712 // Add the scan result to this WifiConfiguration 3713 if (passpointMatch != null) 3714 scanDetailCache.put(scanDetail, passpointMatch, getHomeSPForConfig(config)); 3715 else 3716 scanDetailCache.put(scanDetail); 3717 3718 // Since we added a scan result to this configuration, re-attempt linking 3719 linkConfiguration(config); 3720 } 3721 3722 private boolean isEncryptionWep(String encryption) { 3723 return encryption.contains("WEP"); 3724 } 3725 3726 private boolean isEncryptionWep(ScanResult scan) { 3727 String scanResultEncrypt = scan.capabilities; 3728 return isEncryptionWep(scanResultEncrypt); 3729 } 3730 3731 private boolean isEncryptionWep(WifiConfiguration config) { 3732 String configEncrypt = config.configKey(); 3733 return isEncryptionWep(configEncrypt); 3734 } 3735 3736 private boolean isEncryptionPsk(String encryption) { 3737 return encryption.contains("PSK"); 3738 } 3739 3740 private boolean isEncryptionPsk(ScanResult scan) { 3741 String scanResultEncrypt = scan.capabilities; 3742 return isEncryptionPsk(scanResultEncrypt); 3743 } 3744 3745 private boolean isEncryptionPsk(WifiConfiguration config) { 3746 String configEncrypt = config.configKey(); 3747 return isEncryptionPsk(configEncrypt); 3748 } 3749 3750 private boolean isEncryptionEap(String encryption) { 3751 return encryption.contains("EAP"); 3752 } 3753 3754 private boolean isEncryptionEap(ScanResult scan) { 3755 String scanResultEncrypt = scan.capabilities; 3756 return isEncryptionEap(scanResultEncrypt); 3757 } 3758 3759 private boolean isEncryptionEap(WifiConfiguration config) { 3760 String configEncrypt = config.configKey(); 3761 return isEncryptionEap(configEncrypt); 3762 } 3763 3764 public boolean isOpenNetwork(String encryption) { 3765 if (!isEncryptionWep(encryption) && !isEncryptionPsk(encryption) 3766 && !isEncryptionEap(encryption)) { 3767 return true; 3768 } 3769 return false; 3770 } 3771 3772 public boolean isOpenNetwork(ScanResult scan) { 3773 String scanResultEncrypt = scan.capabilities; 3774 return isOpenNetwork(scanResultEncrypt); 3775 } 3776 3777 public boolean isOpenNetwork(WifiConfiguration config) { 3778 String configEncrypt = config.configKey(); 3779 return isOpenNetwork(configEncrypt); 3780 } 3781 3782 /** 3783 * create a mapping between the scandetail and the Wificonfiguration it associated with 3784 * because Passpoint, one BSSID can associated with multiple SSIDs 3785 * @param scanDetail input a scanDetail from the scan result 3786 * @return List<WifiConfiguration> a list of WifiConfigurations associated to this scanDetail 3787 */ 3788 public List<WifiConfiguration> updateSavedNetworkWithNewScanDetail(ScanDetail scanDetail) { 3789 3790 ScanResult scanResult = scanDetail.getScanResult(); 3791 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3792 List<WifiConfiguration> associatedWifiConfigurations = new ArrayList<WifiConfiguration>(); 3793 3794 if (scanResult == null) 3795 return null; 3796 3797 String SSID = "\"" + scanResult.SSID + "\""; 3798 3799 if (networkDetail.hasInterworking()) { 3800 Map<HomeSP, PasspointMatch> matches = matchPasspointNetworks(scanDetail); 3801 mOSUManager.addScanResult(scanDetail.getNetworkDetail()); 3802 if (matches != null) { 3803 cacheScanResultForPasspointConfigs(scanDetail, matches, 3804 associatedWifiConfigurations); 3805 //Do not return here. A BSSID can belong to both passpoint network and non-passpoint 3806 //Network 3807 } 3808 } 3809 3810 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 3811 boolean found = false; 3812 if (config.SSID == null || !config.SSID.equals(SSID)) { 3813 continue; 3814 } 3815 if (DBG) { 3816 localLog("updateSavedNetworkWithNewScanDetail(): try " + config.configKey() 3817 + " SSID=" + config.SSID + " " + scanResult.SSID + " " 3818 + scanResult.capabilities); 3819 } 3820 3821 String scanResultEncrypt = scanResult.capabilities; 3822 String configEncrypt = config.configKey(); 3823 if (isEncryptionWep(scanResultEncrypt) && isEncryptionWep(configEncrypt) 3824 || (isEncryptionPsk(scanResultEncrypt) && isEncryptionPsk(configEncrypt)) 3825 || (isEncryptionEap(scanResultEncrypt) && isEncryptionEap(configEncrypt)) 3826 || (isOpenNetwork(scanResultEncrypt) && isOpenNetwork(configEncrypt))) { 3827 found = true; 3828 } 3829 3830 if (found) { 3831 cacheScanResultForConfig(config, scanDetail, null); 3832 associatedWifiConfigurations.add(config); 3833 } 3834 } 3835 3836 if (associatedWifiConfigurations.size() == 0) { 3837 return null; 3838 } else { 3839 return associatedWifiConfigurations; 3840 } 3841 } 3842 3843 /** 3844 * Handles the switch to a different foreground user: 3845 * - Removes all ephemeral networks 3846 * - Disables private network configurations belonging to the previous foreground user 3847 * - Enables private network configurations belonging to the new foreground user 3848 * 3849 * TODO(b/26785736): Terminate background users if the new foreground user has one or more 3850 * private network configurations. 3851 */ 3852 public void handleUserSwitch() { 3853 Set<WifiConfiguration> ephemeralConfigs = new HashSet<>(); 3854 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 3855 if (config.ephemeral) { 3856 ephemeralConfigs.add(config); 3857 } 3858 } 3859 if (!ephemeralConfigs.isEmpty()) { 3860 for (WifiConfiguration config : ephemeralConfigs) { 3861 if (config.configKey().equals(lastSelectedConfiguration)) { 3862 lastSelectedConfiguration = null; 3863 } 3864 if (config.enterpriseConfig != null) { 3865 removeKeys(config.enterpriseConfig); 3866 } 3867 mConfiguredNetworks.remove(config.networkId); 3868 mScanDetailCaches.remove(config.networkId); 3869 mWifiNative.removeNetwork(config.networkId); 3870 } 3871 mWifiNative.saveConfig(); 3872 writeKnownNetworkHistory(); 3873 } 3874 3875 final List<WifiConfiguration> hiddenConfigurations = 3876 mConfiguredNetworks.handleUserSwitch(mWifiStateMachine.getCurrentUserId()); 3877 for (WifiConfiguration network : hiddenConfigurations) { 3878 if (mWifiNative.disableNetwork(network.networkId)) { 3879 network.status = Status.DISABLED; 3880 } 3881 } 3882 3883 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 3884 enableNetworkWithoutBroadcast(config.networkId, false); 3885 } 3886 enableAllNetworks(); 3887 3888 // TODO(b/26785746): This broadcast is unnecessary if either of the following is true: 3889 // * The user switch did not change the list of visible networks 3890 // * The user switch revealed additional networks that were temporarily disabled and got 3891 // re-enabled now (because enableAllNetworks() sent the same broadcast already). 3892 sendConfiguredNetworksChangedBroadcast(); 3893 } 3894 3895 /* Compare current and new configuration and write to file on change */ 3896 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 3897 WifiConfiguration currentConfig, 3898 WifiConfiguration newConfig) { 3899 boolean ipChanged = false; 3900 boolean proxyChanged = false; 3901 3902 if (VDBG) { 3903 loge("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " + 3904 newConfig.SSID + " path: " + ipConfigFile); 3905 } 3906 3907 3908 switch (newConfig.getIpAssignment()) { 3909 case STATIC: 3910 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 3911 ipChanged = true; 3912 } else { 3913 ipChanged = !Objects.equals( 3914 currentConfig.getStaticIpConfiguration(), 3915 newConfig.getStaticIpConfiguration()); 3916 } 3917 break; 3918 case DHCP: 3919 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 3920 ipChanged = true; 3921 } 3922 break; 3923 case UNASSIGNED: 3924 /* Ignore */ 3925 break; 3926 default: 3927 loge("Ignore invalid ip assignment during write"); 3928 break; 3929 } 3930 3931 switch (newConfig.getProxySettings()) { 3932 case STATIC: 3933 case PAC: 3934 ProxyInfo newHttpProxy = newConfig.getHttpProxy(); 3935 ProxyInfo currentHttpProxy = currentConfig.getHttpProxy(); 3936 3937 if (newHttpProxy != null) { 3938 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 3939 } else { 3940 proxyChanged = (currentHttpProxy != null); 3941 } 3942 break; 3943 case NONE: 3944 if (currentConfig.getProxySettings() != newConfig.getProxySettings()) { 3945 proxyChanged = true; 3946 } 3947 break; 3948 case UNASSIGNED: 3949 /* Ignore */ 3950 break; 3951 default: 3952 loge("Ignore invalid proxy configuration during write"); 3953 break; 3954 } 3955 3956 if (ipChanged) { 3957 currentConfig.setIpAssignment(newConfig.getIpAssignment()); 3958 currentConfig.setStaticIpConfiguration(newConfig.getStaticIpConfiguration()); 3959 log("IP config changed SSID = " + currentConfig.SSID); 3960 if (currentConfig.getStaticIpConfiguration() != null) { 3961 log(" static configuration: " + 3962 currentConfig.getStaticIpConfiguration().toString()); 3963 } 3964 } 3965 3966 if (proxyChanged) { 3967 currentConfig.setProxySettings(newConfig.getProxySettings()); 3968 currentConfig.setHttpProxy(newConfig.getHttpProxy()); 3969 log("proxy changed SSID = " + currentConfig.SSID); 3970 if (currentConfig.getHttpProxy() != null) { 3971 log(" proxyProperties: " + currentConfig.getHttpProxy().toString()); 3972 } 3973 } 3974 3975 if (ipChanged || proxyChanged) { 3976 writeIpAndProxyConfigurations(); 3977 sendConfiguredNetworksChangedBroadcast(currentConfig, 3978 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 3979 } 3980 return new NetworkUpdateResult(ipChanged, proxyChanged); 3981 } 3982 3983 /** Returns true if a particular config key needs to be quoted when passed to the supplicant. */ 3984 private boolean enterpriseConfigKeyShouldBeQuoted(String key) { 3985 switch (key) { 3986 case WifiEnterpriseConfig.EAP_KEY: 3987 case WifiEnterpriseConfig.ENGINE_KEY: 3988 return false; 3989 default: 3990 return true; 3991 } 3992 } 3993 3994 /** 3995 * Read the variables from the supplicant daemon that are needed to 3996 * fill in the WifiConfiguration object. 3997 * 3998 * @param config the {@link WifiConfiguration} object to be filled in. 3999 */ 4000 private void readNetworkVariables(WifiConfiguration config) { 4001 4002 int netId = config.networkId; 4003 if (netId < 0) 4004 return; 4005 4006 /* 4007 * TODO: maybe should have a native method that takes an array of 4008 * variable names and returns an array of values. But we'd still 4009 * be doing a round trip to the supplicant daemon for each variable. 4010 */ 4011 String value; 4012 4013 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 4014 if (!TextUtils.isEmpty(value)) { 4015 if (value.charAt(0) != '"') { 4016 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 4017 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 4018 //supplicant string 4019 } else { 4020 config.SSID = value; 4021 } 4022 } else { 4023 config.SSID = null; 4024 } 4025 4026 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 4027 if (!TextUtils.isEmpty(value)) { 4028 config.getNetworkSelectionStatus().setNetworkSelectionBSSID(value); 4029 } else { 4030 config.getNetworkSelectionStatus().setNetworkSelectionBSSID(null); 4031 } 4032 4033 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 4034 config.priority = -1; 4035 if (!TextUtils.isEmpty(value)) { 4036 try { 4037 config.priority = Integer.parseInt(value); 4038 } catch (NumberFormatException ignore) { 4039 } 4040 } 4041 4042 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 4043 config.hiddenSSID = false; 4044 if (!TextUtils.isEmpty(value)) { 4045 try { 4046 config.hiddenSSID = Integer.parseInt(value) != 0; 4047 } catch (NumberFormatException ignore) { 4048 } 4049 } 4050 4051 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 4052 config.wepTxKeyIndex = -1; 4053 if (!TextUtils.isEmpty(value)) { 4054 try { 4055 config.wepTxKeyIndex = Integer.parseInt(value); 4056 } catch (NumberFormatException ignore) { 4057 } 4058 } 4059 4060 for (int i = 0; i < 4; i++) { 4061 value = mWifiNative.getNetworkVariable(netId, 4062 WifiConfiguration.wepKeyVarNames[i]); 4063 if (!TextUtils.isEmpty(value)) { 4064 config.wepKeys[i] = value; 4065 } else { 4066 config.wepKeys[i] = null; 4067 } 4068 } 4069 4070 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 4071 if (!TextUtils.isEmpty(value)) { 4072 config.preSharedKey = value; 4073 } else { 4074 config.preSharedKey = null; 4075 } 4076 4077 readNetworkBitsetVariable(config.networkId, config.allowedProtocols, 4078 WifiConfiguration.Protocol.varName, WifiConfiguration.Protocol.strings); 4079 4080 readNetworkBitsetVariable(config.networkId, config.allowedKeyManagement, 4081 WifiConfiguration.KeyMgmt.varName, WifiConfiguration.KeyMgmt.strings); 4082 4083 readNetworkBitsetVariable(config.networkId, config.allowedAuthAlgorithms, 4084 WifiConfiguration.AuthAlgorithm.varName, WifiConfiguration.AuthAlgorithm.strings); 4085 4086 readNetworkBitsetVariable(config.networkId, config.allowedPairwiseCiphers, 4087 WifiConfiguration.PairwiseCipher.varName, WifiConfiguration.PairwiseCipher.strings); 4088 4089 readNetworkBitsetVariable(config.networkId, config.allowedGroupCiphers, 4090 WifiConfiguration.GroupCipher.varName, WifiConfiguration.GroupCipher.strings); 4091 4092 if (config.enterpriseConfig == null) { 4093 config.enterpriseConfig = new WifiEnterpriseConfig(); 4094 } 4095 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 4096 for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { 4097 value = mWifiNative.getNetworkVariable(netId, key); 4098 if (!TextUtils.isEmpty(value)) { 4099 if (!enterpriseConfigKeyShouldBeQuoted(key)) { 4100 value = removeDoubleQuotes(value); 4101 } 4102 enterpriseFields.put(key, value); 4103 } else { 4104 enterpriseFields.put(key, EMPTY_VALUE); 4105 } 4106 } 4107 4108 if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { 4109 saveConfig(); 4110 } 4111 4112 migrateCerts(config.enterpriseConfig); 4113 // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); 4114 } 4115 4116 private static String removeDoubleQuotes(String string) { 4117 int length = string.length(); 4118 if ((length > 1) && (string.charAt(0) == '"') 4119 && (string.charAt(length - 1) == '"')) { 4120 return string.substring(1, length - 1); 4121 } 4122 return string; 4123 } 4124 4125 private static String makeString(BitSet set, String[] strings) { 4126 StringBuffer buf = new StringBuffer(); 4127 int nextSetBit = -1; 4128 4129 /* Make sure all set bits are in [0, strings.length) to avoid 4130 * going out of bounds on strings. (Shouldn't happen, but...) */ 4131 set = set.get(0, strings.length); 4132 4133 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 4134 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 4135 } 4136 4137 // remove trailing space 4138 if (set.cardinality() > 0) { 4139 buf.setLength(buf.length() - 1); 4140 } 4141 4142 return buf.toString(); 4143 } 4144 4145 private int lookupString(String string, String[] strings) { 4146 int size = strings.length; 4147 4148 string = string.replace('-', '_'); 4149 4150 for (int i = 0; i < size; i++) 4151 if (string.equals(strings[i])) 4152 return i; 4153 4154 // if we ever get here, we should probably add the 4155 // value to WifiConfiguration to reflect that it's 4156 // supported by the WPA supplicant 4157 loge("Failed to look-up a string: " + string); 4158 4159 return -1; 4160 } 4161 4162 /* return the allowed key management based on a scan result */ 4163 4164 public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) { 4165 4166 WifiConfiguration config = new WifiConfiguration(); 4167 4168 config.SSID = "\"" + result.SSID + "\""; 4169 4170 if (VDBG) { 4171 loge("WifiConfiguration from scan results " + 4172 config.SSID + " cap " + result.capabilities); 4173 } 4174 if (result.capabilities.contains("WEP")) { 4175 config.allowedKeyManagement.set(KeyMgmt.NONE); 4176 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); //? 4177 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 4178 } 4179 4180 if (result.capabilities.contains("PSK")) { 4181 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 4182 } 4183 4184 if (result.capabilities.contains("EAP")) { 4185 //this is probably wrong, as we don't have a way to enter the enterprise config 4186 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 4187 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 4188 } 4189 4190 /* getScanDetailCache(config).put(scanDetail); */ 4191 4192 return config; 4193 } 4194 4195 public WifiConfiguration wifiConfigurationFromScanResult(ScanDetail scanDetail) { 4196 ScanResult result = scanDetail.getScanResult(); 4197 return wifiConfigurationFromScanResult(result); 4198 } 4199 4200 /* Returns a unique for a given configuration */ 4201 private static int configKey(WifiConfiguration config) { 4202 String key = config.configKey(); 4203 return key.hashCode(); 4204 } 4205 4206 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4207 pw.println("Dump of WifiConfigStore"); 4208 pw.println("mLastPriority " + mLastPriority); 4209 pw.println("Configured networks"); 4210 for (WifiConfiguration conf : getAllConfiguredNetworks()) { 4211 pw.println(conf); 4212 } 4213 pw.println(); 4214 if (mLostConfigsDbg != null && mLostConfigsDbg.size() > 0) { 4215 pw.println("LostConfigs: "); 4216 for (String s : mLostConfigsDbg) { 4217 pw.println(s); 4218 } 4219 } 4220 if (mLocalLog != null) { 4221 pw.println("WifiConfigStore - Log Begin ----"); 4222 mLocalLog.dump(fd, pw, args); 4223 pw.println("WifiConfigStore - Log End ----"); 4224 } 4225 if (mMOManager.isConfigured()) { 4226 pw.println("Begin dump of ANQP Cache"); 4227 mAnqpCache.dump(pw); 4228 pw.println("End dump of ANQP Cache"); 4229 } 4230 } 4231 4232 public String getConfigFile() { 4233 return ipConfigFile; 4234 } 4235 4236 protected void logd(String s) { 4237 Log.d(TAG, s); 4238 } 4239 4240 protected void loge(String s) { 4241 loge(s, false); 4242 } 4243 4244 protected void loge(String s, boolean stack) { 4245 if (stack) { 4246 Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 4247 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 4248 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 4249 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 4250 } else { 4251 Log.e(TAG, s); 4252 } 4253 } 4254 4255 private void logKernelTime() { 4256 long kernelTimeMs = System.nanoTime()/(1000*1000); 4257 StringBuilder builder = new StringBuilder(); 4258 builder.append("kernel time = ").append(kernelTimeMs/1000).append(".").append 4259 (kernelTimeMs%1000).append("\n"); 4260 localLog(builder.toString()); 4261 } 4262 4263 protected void log(String s) { 4264 Log.d(TAG, s); 4265 } 4266 4267 private void localLog(String s) { 4268 if (mLocalLog != null) { 4269 mLocalLog.log(s); 4270 } 4271 } 4272 4273 private void localLogAndLogcat(String s) { 4274 localLog(s); 4275 Log.d(TAG, s); 4276 } 4277 4278 private void localLogNetwork(String s, int netId) { 4279 if (mLocalLog == null) { 4280 return; 4281 } 4282 4283 WifiConfiguration config; 4284 synchronized(mConfiguredNetworks) { // !!! Useless synchronization 4285 config = mConfiguredNetworks.getForAllUsers(netId); 4286 } 4287 4288 if (config != null) { 4289 mLocalLog.log(s + " " + config.getPrintableSsid() + " " + netId 4290 + " status=" + config.status 4291 + " key=" + config.configKey()); 4292 } else { 4293 mLocalLog.log(s + " " + netId); 4294 } 4295 } 4296 4297 // Certificate and private key management for EnterpriseConfig 4298 static boolean needsKeyStore(WifiEnterpriseConfig config) { 4299 // Has no keys to be installed 4300 if (config.getClientCertificate() == null && config.getCaCertificate() == null) 4301 return false; 4302 return true; 4303 } 4304 4305 static boolean isHardwareBackedKey(PrivateKey key) { 4306 return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 4307 } 4308 4309 static boolean hasHardwareBackedKey(Certificate certificate) { 4310 return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 4311 } 4312 4313 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 4314 String client = config.getClientCertificateAlias(); 4315 if (!TextUtils.isEmpty(client)) { 4316 // a valid client certificate is configured 4317 4318 // BUGBUG: keyStore.get() never returns certBytes; because it is not 4319 // taking WIFI_UID as a parameter. It always looks for certificate 4320 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 4321 // all certificates need software keystore until we get the get() API 4322 // fixed. 4323 4324 return true; 4325 } 4326 4327 /* 4328 try { 4329 4330 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 4331 .USER_CERTIFICATE + client); 4332 4333 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 4334 if (factory == null) { 4335 Slog.e(TAG, "Error getting certificate factory"); 4336 return; 4337 } 4338 4339 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 4340 if (certBytes != null) { 4341 Certificate cert = (X509Certificate) factory.generateCertificate( 4342 new ByteArrayInputStream(certBytes)); 4343 4344 if (cert != null) { 4345 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 4346 4347 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 4348 .USER_CERTIFICATE + client); 4349 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 4350 "does not need" ) + " software key store"); 4351 } else { 4352 Slog.d(TAG, "could not generate certificate"); 4353 } 4354 } else { 4355 Slog.e(TAG, "Could not load client certificate " + Credentials 4356 .USER_CERTIFICATE + client); 4357 mNeedsSoftwareKeystore = true; 4358 } 4359 4360 } catch(CertificateException e) { 4361 Slog.e(TAG, "Could not read certificates"); 4362 mCaCert = null; 4363 mClientCertificate = null; 4364 } 4365 */ 4366 4367 return false; 4368 } 4369 4370 boolean isSimConfig(WifiConfiguration config) { 4371 if (config == null) { 4372 return false; 4373 } 4374 4375 if (config.enterpriseConfig == null) { 4376 return false; 4377 } 4378 4379 int method = config.enterpriseConfig.getEapMethod(); 4380 return (method == WifiEnterpriseConfig.Eap.SIM 4381 || method == WifiEnterpriseConfig.Eap.AKA 4382 || method == WifiEnterpriseConfig.Eap.AKA_PRIME); 4383 } 4384 4385 void resetSimNetworks() { 4386 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 4387 if (isSimConfig(config)) { 4388 /* This configuration may have cached Pseudonym IDs; lets remove them */ 4389 mWifiNative.setNetworkVariable(config.networkId, "identity", "NULL"); 4390 mWifiNative.setNetworkVariable(config.networkId, "anonymous_identity", "NULL"); 4391 } 4392 } 4393 } 4394 4395 boolean isNetworkConfigured(WifiConfiguration config) { 4396 // Check if either we have a network Id or a WifiConfiguration 4397 // matching the one we are trying to add. 4398 4399 if(config.networkId != INVALID_NETWORK_ID) { 4400 return (mConfiguredNetworks.getForCurrentUser(config.networkId) != null); 4401 } 4402 4403 return (mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()) != null); 4404 } 4405 4406 /** 4407 * Checks if uid has access to modify the configuration corresponding to networkId. 4408 * 4409 * The conditions checked are, in descending priority order: 4410 * - Disallow modification if the the configuration is not visible to the uid. 4411 * - Allow modification if the uid represents the Device Owner app. 4412 * - Allow modification if both of the following are true: 4413 * - The uid represents the configuration's creator or an app holding OVERRIDE_CONFIG_WIFI. 4414 * - The modification is only for administrative annotation (e.g. when connecting) or the 4415 * configuration is not lockdown eligible (which currently means that it was not last 4416 * updated by the DO). 4417 * - Allow modification if configuration lockdown is explicitly disabled and the uid represents 4418 * an app holding OVERRIDE_CONFIG_WIFI. 4419 * - In all other cases, disallow modification. 4420 */ 4421 boolean canModifyNetwork(int uid, int networkId, boolean onlyAnnotate) { 4422 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(networkId); 4423 4424 if (config == null) { 4425 loge("canModifyNetwork: cannot find config networkId " + networkId); 4426 return false; 4427 } 4428 4429 final DevicePolicyManagerInternal dpmi = LocalServices.getService( 4430 DevicePolicyManagerInternal.class); 4431 4432 final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid, 4433 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 4434 4435 if (isUidDeviceOwner) { 4436 return true; 4437 } 4438 4439 final boolean isCreator = (config.creatorUid == uid); 4440 4441 if (onlyAnnotate) { 4442 return isCreator || checkConfigOverridePermission(uid); 4443 } 4444 4445 // Check if device has DPM capability. If it has and dpmi is still null, then we 4446 // treat this case with suspicion and bail out. 4447 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) 4448 && dpmi == null) { 4449 return false; 4450 } 4451 4452 // WiFi config lockdown related logic. At this point we know uid NOT to be a Device Owner. 4453 4454 final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy( 4455 config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 4456 if (!isConfigEligibleForLockdown) { 4457 return isCreator || checkConfigOverridePermission(uid); 4458 } 4459 4460 final ContentResolver resolver = mContext.getContentResolver(); 4461 final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver, 4462 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; 4463 return !isLockdownFeatureEnabled && checkConfigOverridePermission(uid); 4464 } 4465 4466 /** 4467 * Checks if uid has access to modify config. 4468 */ 4469 boolean canModifyNetwork(int uid, WifiConfiguration config, boolean onlyAnnotate) { 4470 if (config == null) { 4471 loge("canModifyNetowrk recieved null configuration"); 4472 return false; 4473 } 4474 4475 // Resolve the correct network id. 4476 int netid; 4477 if (config.networkId != INVALID_NETWORK_ID){ 4478 netid = config.networkId; 4479 } else { 4480 WifiConfiguration test = 4481 mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 4482 if (test == null) { 4483 return false; 4484 } else { 4485 netid = test.networkId; 4486 } 4487 } 4488 4489 return canModifyNetwork(uid, netid, onlyAnnotate); 4490 } 4491 4492 boolean checkConfigOverridePermission(int uid) { 4493 try { 4494 return (AppGlobals.getPackageManager().checkUidPermission( 4495 android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid) 4496 == PackageManager.PERMISSION_GRANTED); 4497 } catch (RemoteException e) { 4498 return false; 4499 } 4500 } 4501 4502 /** called when CS ask WiFistateMachine to disconnect the current network 4503 * because the score is bad. 4504 */ 4505 void handleBadNetworkDisconnectReport(int netId, WifiInfo info) { 4506 /* TODO verify the bad network is current */ 4507 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 4508 if (config != null) { 4509 if ((info.is24GHz() && info.getRssi() 4510 <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND) 4511 || (info.is5GHz() && info.getRssi() 4512 <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND)) { 4513 // We do not block due to bad RSSI since network selection should not select bad 4514 // RSSI candidate 4515 } else { 4516 // We got disabled but RSSI is good, so disable hard 4517 updateNetworkSelectionStatus(config, 4518 WifiConfiguration.NetworkSelectionStatus.DISABLED_BAD_LINK); 4519 } 4520 } 4521 // Record last time Connectivity Service switched us away from WiFi and onto Cell 4522 lastUnwantedNetworkDisconnectTimestamp = System.currentTimeMillis(); 4523 } 4524 4525 int getMaxDhcpRetries() { 4526 return mFacade.getIntegerSetting(mContext, 4527 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 4528 DEFAULT_MAX_DHCP_RETRIES); 4529 } 4530 4531 void clearBssidBlacklist() { 4532 if (!mWifiStateMachine.useHalBasedAutoJoinOffload()) { 4533 if(DBG) { 4534 Log.d(TAG, "No blacklist allowed without epno enabled"); 4535 } 4536 return; 4537 } 4538 mBssidBlacklist = new HashSet<String>(); 4539 mWifiNative.clearBlacklist(); 4540 mWifiNative.setBssidBlacklist(null); 4541 } 4542 4543 void blackListBssid(String BSSID) { 4544 if (!mWifiStateMachine.useHalBasedAutoJoinOffload()) { 4545 if(DBG) { 4546 Log.d(TAG, "No blacklist allowed without epno enabled"); 4547 } 4548 return; 4549 } 4550 if (BSSID == null) 4551 return; 4552 mBssidBlacklist.add(BSSID); 4553 // Blacklist at wpa_supplicant 4554 mWifiNative.addToBlacklist(BSSID); 4555 // Blacklist at firmware 4556 String list[] = new String[mBssidBlacklist.size()]; 4557 int count = 0; 4558 for (String bssid : mBssidBlacklist) { 4559 list[count++] = bssid; 4560 } 4561 mWifiNative.setBssidBlacklist(list); 4562 } 4563 4564 public boolean isBssidBlacklisted(String bssid) { 4565 return mBssidBlacklist.contains(bssid); 4566 } 4567 4568 public boolean getEnableNewNetworkSelectionWhenAssociated() { 4569 return enableAutoJoinWhenAssociated.get(); 4570 } 4571 4572 boolean installKeys(WifiEnterpriseConfig oldConfig, WifiEnterpriseConfig config, String name) { 4573 boolean ret = true; 4574 String privKeyName = Credentials.USER_PRIVATE_KEY + name; 4575 String userCertName = Credentials.USER_CERTIFICATE + name; 4576 if (config.getClientCertificate() != null) { 4577 byte[] privKeyData = config.getClientPrivateKey().getEncoded(); 4578 if (isHardwareBackedKey(config.getClientPrivateKey())) { 4579 // Hardware backed key store is secure enough to store keys un-encrypted, this 4580 // removes the need for user to punch a PIN to get access to these keys 4581 if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); 4582 ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, 4583 KeyStore.FLAG_NONE); 4584 } else { 4585 // Software backed key store is NOT secure enough to store keys un-encrypted. 4586 // Save keys encrypted so they are protected with user's PIN. User will 4587 // have to unlock phone before being able to use these keys and connect to 4588 // networks. 4589 if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); 4590 ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 4591 KeyStore.FLAG_ENCRYPTED); 4592 } 4593 if (ret == false) { 4594 return ret; 4595 } 4596 4597 ret = putCertInKeyStore(userCertName, config.getClientCertificate()); 4598 if (ret == false) { 4599 // Remove private key installed 4600 mKeyStore.delete(privKeyName, Process.WIFI_UID); 4601 return ret; 4602 } 4603 } 4604 4605 X509Certificate[] caCertificates = config.getCaCertificates(); 4606 Set<String> oldCaCertificatesToRemove = new ArraySet<String>(); 4607 if (oldConfig != null && oldConfig.getCaCertificateAliases() != null) { 4608 oldCaCertificatesToRemove.addAll(Arrays.asList(oldConfig.getCaCertificateAliases())); 4609 } 4610 List<String> caCertificateAliases = null; 4611 if (caCertificates != null) { 4612 caCertificateAliases = new ArrayList<String>(); 4613 for (int i = 0; i < caCertificates.length; i++) { 4614 String alias = caCertificates.length == 1 ? name 4615 : String.format("%s_%d", name, i); 4616 4617 oldCaCertificatesToRemove.remove(alias); 4618 ret = putCertInKeyStore(Credentials.CA_CERTIFICATE + alias, caCertificates[i]); 4619 if (!ret) { 4620 // Remove client key+cert 4621 if (config.getClientCertificate() != null) { 4622 mKeyStore.delete(privKeyName, Process.WIFI_UID); 4623 mKeyStore.delete(userCertName, Process.WIFI_UID); 4624 } 4625 // Remove added CA certs. 4626 for (String addedAlias : caCertificateAliases) { 4627 mKeyStore.delete(Credentials.CA_CERTIFICATE + addedAlias, Process.WIFI_UID); 4628 } 4629 return ret; 4630 } else { 4631 caCertificateAliases.add(alias); 4632 } 4633 } 4634 } 4635 // Remove old CA certs. 4636 for (String oldAlias : oldCaCertificatesToRemove) { 4637 mKeyStore.delete(Credentials.CA_CERTIFICATE + oldAlias, Process.WIFI_UID); 4638 } 4639 // Set alias names 4640 if (config.getClientCertificate() != null) { 4641 config.setClientCertificateAlias(name); 4642 config.resetClientKeyEntry(); 4643 } 4644 4645 if (caCertificates != null) { 4646 config.setCaCertificateAliases( 4647 caCertificateAliases.toArray(new String[caCertificateAliases.size()])); 4648 config.resetCaCertificate(); 4649 } 4650 4651 return ret; 4652 } 4653 4654 private boolean putCertInKeyStore(String name, Certificate cert) { 4655 try { 4656 byte[] certData = Credentials.convertToPem(cert); 4657 if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); 4658 return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 4659 4660 } catch (IOException e1) { 4661 return false; 4662 } catch (CertificateException e2) { 4663 return false; 4664 } 4665 } 4666 4667 void removeKeys(WifiEnterpriseConfig config) { 4668 String client = config.getClientCertificateAlias(); 4669 // a valid client certificate is configured 4670 if (!TextUtils.isEmpty(client)) { 4671 if (DBG) Log.d(TAG, "removing client private key and user cert"); 4672 mKeyStore.delete(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 4673 mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 4674 } 4675 4676 String[] aliases = config.getCaCertificateAliases(); 4677 // a valid ca certificate is configured 4678 if (aliases != null) { 4679 for (String ca: aliases) { 4680 if (!TextUtils.isEmpty(ca)) { 4681 if (DBG) Log.d(TAG, "removing CA cert: " + ca); 4682 mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 4683 } 4684 } 4685 } 4686 } 4687 4688 4689 /** Migrates the old style TLS config to the new config style. This should only be used 4690 * when restoring an old wpa_supplicant.conf or upgrading from a previous 4691 * platform version. 4692 * @return true if the config was updated 4693 * @hide 4694 */ 4695 boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { 4696 String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 4697 /* 4698 * If the old configuration value is not present, then there is nothing 4699 * to do. 4700 */ 4701 if (TextUtils.isEmpty(oldPrivateKey)) { 4702 return false; 4703 } else { 4704 // Also ignore it if it's empty quotes. 4705 oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 4706 if (TextUtils.isEmpty(oldPrivateKey)) { 4707 return false; 4708 } 4709 } 4710 4711 config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE); 4712 config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, 4713 WifiEnterpriseConfig.ENGINE_ID_KEYSTORE); 4714 4715 /* 4716 * The old key started with the keystore:// URI prefix, but we don't 4717 * need that anymore. Trim it off if it exists. 4718 */ 4719 final String keyName; 4720 if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) { 4721 keyName = new String( 4722 oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length())); 4723 } else { 4724 keyName = oldPrivateKey; 4725 } 4726 config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName); 4727 4728 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY, 4729 config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 4730 4731 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY, 4732 config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 4733 4734 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, 4735 config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 4736 4737 // Remove old private_key string so we don't run this again. 4738 mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 4739 4740 return true; 4741 } 4742 4743 /** Migrate certs from global pool to wifi UID if not already done */ 4744 void migrateCerts(WifiEnterpriseConfig config) { 4745 String client = config.getClientCertificateAlias(); 4746 // a valid client certificate is configured 4747 if (!TextUtils.isEmpty(client)) { 4748 if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 4749 mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 4750 Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 4751 mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 4752 Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 4753 } 4754 } 4755 4756 String[] aliases = config.getCaCertificateAliases(); 4757 // a valid ca certificate is configured 4758 if (aliases != null) { 4759 for (String ca : aliases) { 4760 if (!TextUtils.isEmpty(ca) 4761 && !mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 4762 mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 4763 Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 4764 } 4765 } 4766 } 4767 } 4768 4769 private void readNetworkBitsetVariable(int netId, BitSet variable, String varName, 4770 String[] strings) { 4771 String value = mWifiNative.getNetworkVariable(netId, varName); 4772 if (!TextUtils.isEmpty(value)) { 4773 variable.clear(); 4774 String vals[] = value.split(" "); 4775 for (String val : vals) { 4776 int index = lookupString(val, strings); 4777 if (0 <= index) { 4778 variable.set(index); 4779 } 4780 } 4781 } 4782 } 4783} 4784