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