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