WifiConfigStore.java revision e6574ec7b6b2e7a678da7f77bdaaf31463852b2f
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.content.Context; 20import android.content.Intent; 21import android.net.IpConfiguration; 22import android.net.IpConfiguration.IpAssignment; 23import android.net.IpConfiguration.ProxySettings; 24import android.net.LinkAddress; 25import android.net.LinkProperties; 26import android.net.NetworkInfo.DetailedState; 27import android.net.ProxyInfo; 28import android.net.RouteInfo; 29import android.net.wifi.WifiConfiguration; 30import android.net.wifi.WifiConfiguration.KeyMgmt; 31import android.net.wifi.WifiConfiguration.Status; 32import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 33 34import android.net.wifi.WifiEnterpriseConfig; 35import android.net.wifi.WifiManager; 36import android.net.wifi.WifiSsid; 37import android.net.wifi.WpsInfo; 38import android.net.wifi.WpsResult; 39import android.net.wifi.ScanResult; 40import android.net.wifi.WifiInfo; 41 42import android.os.Environment; 43import android.os.FileObserver; 44import android.os.Process; 45import android.os.SystemClock; 46import android.os.UserHandle; 47import android.provider.Settings; 48import android.security.Credentials; 49import android.security.KeyChain; 50import android.security.KeyStore; 51import android.text.TextUtils; 52import android.util.LocalLog; 53import android.util.Log; 54import android.util.SparseArray; 55 56import com.android.server.net.DelayedDiskWrite; 57import com.android.server.net.IpConfigStore; 58 59import java.io.BufferedReader; 60import java.io.BufferedInputStream; 61import java.io.DataInputStream; 62import java.io.DataOutputStream; 63import java.io.EOFException; 64import java.io.File; 65import java.io.FileDescriptor; 66import java.io.FileInputStream; 67import java.io.FileNotFoundException; 68import java.io.FileReader; 69import java.io.IOException; 70import java.io.PrintWriter; 71import java.math.BigInteger; 72import java.net.InetAddress; 73import java.nio.charset.Charset; 74import java.security.PrivateKey; 75import java.security.cert.Certificate; 76import java.security.cert.CertificateException; 77import java.text.SimpleDateFormat; 78import java.text.DateFormat; 79import java.util.regex.Matcher; 80import java.util.regex.Pattern; 81import java.util.*; 82 83/** 84 * This class provides the API to manage configured 85 * wifi networks. The API is not thread safe is being 86 * used only from WifiStateMachine. 87 * 88 * It deals with the following 89 * - Add/update/remove a WifiConfiguration 90 * The configuration contains two types of information. 91 * = IP and proxy configuration that is handled by WifiConfigStore and 92 * is saved to disk on any change. 93 * 94 * The format of configuration file is as follows: 95 * <version> 96 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 97 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 98 * .. 99 * 100 * (key, value) pairs for a given network are grouped together and can 101 * be in any order. A EOS at the end of a set of (key, value) pairs 102 * indicates that the next set of (key, value) pairs are for a new 103 * network. A network is identified by a unique ID_KEY. If there is no 104 * ID_KEY in the (key, value) pairs, the data is discarded. 105 * 106 * An invalid version on read would result in discarding the contents of 107 * the file. On the next write, the latest version is written to file. 108 * 109 * Any failures during read or write to the configuration file are ignored 110 * without reporting to the user since the likelihood of these errors are 111 * low and the impact on connectivity is low. 112 * 113 * = SSID & security details that is pushed to the supplicant. 114 * supplicant saves these details to the disk on calling 115 * saveConfigCommand(). 116 * 117 * We have two kinds of APIs exposed: 118 * > public API calls that provide fine grained control 119 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 120 * removeNetwork(). For these calls, the config is not persisted 121 * to the disk. (TODO: deprecate these calls in WifiManager) 122 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 123 * These calls persist the supplicant config to disk. 124 * 125 * - Maintain a list of configured networks for quick access 126 * 127 */ 128public class WifiConfigStore extends IpConfigStore { 129 130 private Context mContext; 131 private static final String TAG = "WifiConfigStore"; 132 private static final boolean DBG = true; 133 private static boolean VDBG = false; 134 135 private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf"; 136 137 /* configured networks with network id as the key */ 138 private HashMap<Integer, WifiConfiguration> mConfiguredNetworks = 139 new HashMap<Integer, WifiConfiguration>(); 140 141 /* A network id is a unique identifier for a network configured in the 142 * supplicant. Network ids are generated when the supplicant reads 143 * the configuration file at start and can thus change for networks. 144 * We store the IP configuration for networks along with a unique id 145 * that is generated from SSID and security type of the network. A mapping 146 * from the generated unique id to network id of the network is needed to 147 * map supplicant config to IP configuration. */ 148 private HashMap<Integer, Integer> mNetworkIds = 149 new HashMap<Integer, Integer>(); 150 151 /* Tracks the highest priority of configured networks */ 152 private int mLastPriority = -1; 153 154 private static final String ipConfigFile = Environment.getDataDirectory() + 155 "/misc/wifi/ipconfig.txt"; 156 157 private static final String networkHistoryConfigFile = Environment.getDataDirectory() + 158 "/misc/wifi/networkHistory.txt"; 159 160 private static final String autoJoinConfigFile = Environment.getDataDirectory() + 161 "/misc/wifi/autojoinconfig.txt"; 162 163 /* Network History Keys */ 164 private static final String SSID_KEY = "SSID: "; 165 private static final String CONFIG_KEY = "CONFIG: "; 166 private static final String CHOICE_KEY = "CHOICE: "; 167 private static final String LINK_KEY = "LINK: "; 168 private static final String BSSID_KEY = "BSSID: "; 169 private static final String BSSID_KEY_END = "/BSSID: "; 170 private static final String RSSI_KEY = "RSSI: "; 171 private static final String FREQ_KEY = "FREQ: "; 172 private static final String DATE_KEY = "DATE: "; 173 private static final String MILLI_KEY = "MILLI: "; 174 private static final String BLACKLIST_MILLI_KEY = "BLACKLIST_MILLI: "; 175 private static final String NETWORK_ID_KEY = "ID: "; 176 private static final String PRIORITY_KEY = "PRIORITY: "; 177 private static final String DEFAULT_GW_KEY = "DEFAULT_GW: "; 178 private static final String AUTH_KEY = "AUTH: "; 179 private static final String SEPARATOR_KEY = "\n"; 180 private static final String STATUS_KEY = "AUTO_JOIN_STATUS: "; 181 private static final String BSSID_STATUS_KEY = "BSSID_STATUS: "; 182 private static final String SELF_ADDED_KEY = "SELF_ADDED: "; 183 private static final String FAILURE_KEY = "FAILURE: "; 184 private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD: "; 185 private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION: "; 186 private static final String CREATOR_UID_KEY = "CREATOR_UID_KEY: "; 187 private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY: "; 188 private static final String UPDATE_UID_KEY = "UPDATE_UID: "; 189 private static final String SUPPLICANT_STATUS_KEY = "SUP_STATUS: "; 190 private static final String SUPPLICANT_DISABLE_REASON_KEY = "SUP_DIS_REASON: "; 191 private static final String FQDN_KEY = "FQDN: "; 192 private static final String NUM_CONNECTION_FAILURES_KEY = "CONNECT_FAILURES: "; 193 private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE: "; 194 private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH: "; 195 private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION: "; 196 private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY 197 = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G: "; 198 private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY 199 = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G: "; 200 private static final String THRESHOLD_UNBLACKLIST_HARD_5G_KEY 201 = "THRESHOLD_UNBLACKLIST_HARD_5G: "; 202 private static final String THRESHOLD_UNBLACKLIST_SOFT_5G_KEY 203 = "THRESHOLD_UNBLACKLIST_SOFT_5G: "; 204 private static final String THRESHOLD_UNBLACKLIST_HARD_24G_KEY 205 = "THRESHOLD_UNBLACKLIST_HARD_24G: "; 206 private static final String THRESHOLD_UNBLACKLIST_SOFT_24G_KEY 207 = "THRESHOLD_UNBLACKLIST_SOFT_24G: "; 208 private static final String THRESHOLD_GOOD_RSSI_5_KEY 209 = "THRESHOLD_GOOD_RSSI_5: "; 210 private static final String THRESHOLD_LOW_RSSI_5_KEY 211 = "THRESHOLD_LOW_RSSI_5: "; 212 private static final String THRESHOLD_BAD_RSSI_5_KEY 213 = "THRESHOLD_BAD_RSSI_5: "; 214 private static final String THRESHOLD_GOOD_RSSI_24_KEY 215 = "THRESHOLD_GOOD_RSSI_24: "; 216 private static final String THRESHOLD_LOW_RSSI_24_KEY 217 = "THRESHOLD_LOW_RSSI_24: "; 218 private static final String THRESHOLD_BAD_RSSI_24_KEY 219 = "THRESHOLD_BAD_RSSI_24: "; 220 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY 221 = "THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING: "; 222 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY 223 = "THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING: "; 224 225 private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW_KEY = 226 "A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW: "; 227 private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY = 228 "A_BAND_PREFERENCE_RSSI_THRESHOLD: "; 229 private static final String G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY = 230 "G_BAND_PREFERENCE_RSSI_THRESHOLD: "; 231 232 private static final String ENABLE_AUTOJOIN_WHILE_ASSOCIATED_KEY 233 = "ENABLE_AUTOJOIN_WHILE_ASSOCIATED: "; 234 235 public boolean enableAutoJoinWhileAssociated = true; 236 237 public int maxTxPacketForNetworkSwitching = 40; 238 public int maxRxPacketForNetworkSwitching = 80; 239 240 public int thresholdInitialAutoJoinAttemptMin5RSSI 241 = WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5; 242 public int thresholdInitialAutoJoinAttemptMin24RSSI 243 = WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24; 244 245 public int thresholdBadRssi5 = WifiConfiguration.BAD_RSSI_5; 246 public int thresholdLowRssi5 = WifiConfiguration.LOW_RSSI_5; 247 public int thresholdGoodRssi5 = WifiConfiguration.GOOD_RSSI_5; 248 public int thresholdBadRssi24 = WifiConfiguration.BAD_RSSI_24; 249 public int thresholdLowRssi24 = WifiConfiguration.LOW_RSSI_24; 250 public int thresholdGoodRssi24 = WifiConfiguration.GOOD_RSSI_24; 251 252 public int thresholdBandPreferenceRssi24 253 = WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD; 254 public int thresholdBandPreferenceRssi5 255 = WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD; 256 public int thresholdBandPreferenceLowRssi5 257 = WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW; 258 259 public int thresholdUnblacklistThreshold5Hard 260 = WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD; 261 public int thresholdUnblacklistThreshold5Soft 262 = WifiConfiguration.UNBLACKLIST_THRESHOLD_5_SOFT; 263 public int thresholdUnblacklistThreshold24Hard 264 = WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD; 265 public int thresholdUnblacklistThreshold24Soft 266 = WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT; 267 268 /** 269 * Regex pattern for extracting a connect choice. 270 * Matches a strings like the following: 271 * <configKey>=([0:9]+) 272 */ 273 private static Pattern mConnectChoice = 274 Pattern.compile("(.*)=([0-9]+)"); 275 276 277 /* Enterprise configuration keys */ 278 /** 279 * In old configurations, the "private_key" field was used. However, newer 280 * configurations use the key_id field with the engine_id set to "keystore". 281 * If this field is found in the configuration, the migration code is 282 * triggered. 283 */ 284 public static final String OLD_PRIVATE_KEY_NAME = "private_key"; 285 286 /** 287 * This represents an empty value of an enterprise field. 288 * NULL is used at wpa_supplicant to indicate an empty value 289 */ 290 static final String EMPTY_VALUE = "NULL"; 291 292 // Internal use only 293 private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { 294 WifiEnterpriseConfig.EAP_KEY, WifiEnterpriseConfig.PHASE2_KEY, 295 WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.ANON_IDENTITY_KEY, 296 WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY, 297 WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY, 298 WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY, 299 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY }; 300 301 302 /** 303 * The maximum number of times we will retry a connection to an access point 304 * for which we have failed in acquiring an IP address from DHCP. A value of 305 * N means that we will make N+1 connection attempts in all. 306 * <p> 307 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 308 * value if a Settings value is not present. 309 */ 310 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 311 312 313 private final LocalLog mLocalLog; 314 private final WpaConfigFileObserver mFileObserver; 315 316 private WifiNative mWifiNative; 317 private final KeyStore mKeyStore = KeyStore.getInstance(); 318 319 /** 320 * The lastSelectedConfiguration is used to remember which network 321 * was selected last by the user. 322 * The connection to this network may not be successful, as well 323 * the selection (i.e. network priority) might not be persisted. 324 * WiFi state machine is the only object that sets this variable. 325 */ 326 private String lastSelectedConfiguration = null; 327 328 WifiConfigStore(Context c, WifiNative wn) { 329 mContext = c; 330 mWifiNative = wn; 331 332 if (VDBG) { 333 mLocalLog = mWifiNative.getLocalLog(); 334 mFileObserver = new WpaConfigFileObserver(); 335 mFileObserver.startWatching(); 336 } else { 337 mLocalLog = null; 338 mFileObserver = null; 339 } 340 } 341 342 void enableVerboseLogging(int verbose) { 343 if (verbose > 0) { 344 VDBG = true; 345 } else { 346 VDBG = false; 347 } 348 } 349 350 class WpaConfigFileObserver extends FileObserver { 351 352 public WpaConfigFileObserver() { 353 super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE); 354 } 355 356 @Override 357 public void onEvent(int event, String path) { 358 if (event == CLOSE_WRITE) { 359 File file = new File(SUPPLICANT_CONFIG_FILE); 360 if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length()); 361 } 362 } 363 } 364 365 366 /** 367 * Fetch the list of configured networks 368 * and enable all stored networks in supplicant. 369 */ 370 void loadAndEnableAllNetworks() { 371 if (DBG) log("Loading config and enabling all networks "); 372 loadConfiguredNetworks(); 373 enableAllNetworks(); 374 } 375 376 int getConfiguredNetworksSize() { 377 return mConfiguredNetworks.size(); 378 } 379 380 private List<WifiConfiguration> getConfiguredNetworks(Map<String, String> pskMap) { 381 List<WifiConfiguration> networks = new ArrayList<>(); 382 for(WifiConfiguration config : mConfiguredNetworks.values()) { 383 WifiConfiguration newConfig = new WifiConfiguration(config); 384 if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { 385 //do not enumerate and return this configuration to any one, 386 //for instance WiFi Picker. 387 //instead treat it as unknown. the configuration can still be retrieved 388 //directly by the key or networkId 389 continue; 390 } 391 if (pskMap != null && config.allowedKeyManagement != null 392 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 393 && pskMap.containsKey(config.SSID)) { 394 newConfig.preSharedKey = pskMap.get(config.SSID); 395 } 396 networks.add(newConfig); 397 } 398 return networks; 399 } 400 401 /** 402 * Fetch the list of currently configured networks 403 * @return List of networks 404 */ 405 List<WifiConfiguration> getConfiguredNetworks() { 406 return getConfiguredNetworks(null); 407 } 408 409 /** 410 * Fetch the list of currently configured networks, filled with real preSharedKeys 411 * @return List of networks 412 */ 413 List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 414 Map<String, String> pskMap = getCredentialsBySsidMap(); 415 return getConfiguredNetworks(pskMap); 416 } 417 418 /** 419 * Fetch the preSharedKeys for all networks. 420 * @return a map from Ssid to preSharedKey. 421 */ 422 private Map<String, String> getCredentialsBySsidMap() { 423 return readNetworkVariablesFromSupplicantFile("psk"); 424 } 425 426 /** 427 * Fetch the list of currently configured networks that were recently seen 428 * 429 * @return List of networks 430 */ 431 List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) { 432 List<WifiConfiguration> networks = null; 433 434 for (WifiConfiguration config : mConfiguredNetworks.values()) { 435 if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { 436 // Do not enumerate and return this configuration to any one, 437 // instead treat it as unknown. the configuration can still be retrieved 438 // directly by the key or networkId 439 continue; 440 } 441 442 // Calculate the RSSI for scan results that are more recent than milli 443 config.setVisibility(milli); 444 445 if (config.visibility == null) { 446 continue; 447 } 448 if (config.visibility.rssi5 == WifiConfiguration.INVALID_RSSI && 449 config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { 450 continue; 451 } 452 if (networks == null) 453 networks = new ArrayList<WifiConfiguration>(); 454 if (copy) { 455 networks.add(new WifiConfiguration(config)); 456 } else { 457 networks.add(config); 458 } 459 } 460 return networks; 461 } 462 463 /** 464 * Update the configuration and BSSID with latest RSSI value. 465 */ 466 void updateConfiguration(WifiInfo info) { 467 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 468 if (config != null && config.scanResultCache != null) { 469 ScanResult result = config.scanResultCache.get(info.getBSSID()); 470 if (result != null) { 471 long previousSeen = result.seen; 472 int previousRssi = result.level; 473 474 // Update the scan result 475 result.seen = System.currentTimeMillis(); 476 result.level = info.getRssi(); 477 478 // Average the RSSI value 479 result.averageRssi(previousRssi, previousSeen, 480 WifiAutoJoinController.mScanResultMaximumAge); 481 if (VDBG) { 482 loge("updateConfiguration freq=" + result.frequency 483 + " BSSID=" + result.BSSID 484 + " RSSI=" + result.level 485 + " " + config.configKey()); 486 } 487 } 488 } 489 } 490 491 /** 492 * get the Wificonfiguration for this netId 493 * 494 * @return Wificonfiguration 495 */ 496 WifiConfiguration getWifiConfiguration(int netId) { 497 if (mConfiguredNetworks == null) 498 return null; 499 return mConfiguredNetworks.get(netId); 500 } 501 502 /** 503 * Get the Wificonfiguration for this key 504 * @return Wificonfiguration 505 */ 506 WifiConfiguration getWifiConfiguration(String key) { 507 if (key == null) 508 return null; 509 int hash = key.hashCode(); 510 if (mNetworkIds == null) 511 return null; 512 Integer n = mNetworkIds.get(hash); 513 if (n == null) 514 return null; 515 int netId = n.intValue(); 516 return getWifiConfiguration(netId); 517 } 518 519 /** 520 * Enable all networks and save config. This will be a no-op if the list 521 * of configured networks indicates all networks as being enabled 522 */ 523 void enableAllNetworks() { 524 boolean networkEnabledStateChanged = false; 525 for(WifiConfiguration config : mConfiguredNetworks.values()) { 526 if(config != null && config.status == Status.DISABLED 527 && (config.autoJoinStatus <= WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED)) { 528 if(mWifiNative.enableNetwork(config.networkId, false)) { 529 networkEnabledStateChanged = true; 530 config.status = Status.ENABLED; 531 } else { 532 loge("Enable network failed on " + config.networkId); 533 } 534 } 535 } 536 537 if (networkEnabledStateChanged) { 538 mWifiNative.saveConfig(); 539 sendConfiguredNetworksChangedBroadcast(); 540 } 541 } 542 543 544 /** 545 * Selects the specified network for connection. This involves 546 * updating the priority of all the networks and enabling the given 547 * network while disabling others. 548 * 549 * Selecting a network will leave the other networks disabled and 550 * a call to enableAllNetworks() needs to be issued upon a connection 551 * or a failure event from supplicant 552 * 553 * @param netId network to select for connection 554 * @return false if the network id is invalid 555 */ 556 boolean selectNetwork(int netId) { 557 if (VDBG) localLog("selectNetwork", netId); 558 if (netId == INVALID_NETWORK_ID) return false; 559 560 // Reset the priority of each network at start or if it goes too high. 561 if (mLastPriority == -1 || mLastPriority > 1000000) { 562 for(WifiConfiguration config : mConfiguredNetworks.values()) { 563 if (config.networkId != INVALID_NETWORK_ID) { 564 config.priority = 0; 565 addOrUpdateNetworkNative(config); 566 } 567 } 568 mLastPriority = 0; 569 } 570 571 // Set to the highest priority and save the configuration. 572 WifiConfiguration config = new WifiConfiguration(); 573 config.networkId = netId; 574 config.priority = ++mLastPriority; 575 576 addOrUpdateNetworkNative(config); 577 mWifiNative.saveConfig(); 578 579 /* Enable the given network while disabling all other networks */ 580 enableNetworkWithoutBroadcast(netId, true); 581 582 /* Avoid saving the config & sending a broadcast to prevent settings 583 * from displaying a disabled list of networks */ 584 return true; 585 } 586 587 /** 588 * Add/update the specified configuration and save config 589 * 590 * @param config WifiConfiguration to be saved 591 * @return network update result 592 */ 593 NetworkUpdateResult saveNetwork(WifiConfiguration config) { 594 WifiConfiguration conf; 595 596 // A new network cannot have null SSID 597 if (config == null || (config.networkId == INVALID_NETWORK_ID && 598 config.SSID == null)) { 599 return new NetworkUpdateResult(INVALID_NETWORK_ID); 600 } 601 if (VDBG) localLog("WifiConfigStore: saveNetwork netId", config.networkId); 602 if (VDBG) { 603 loge("WifiConfigStore saveNetwork, size=" + mConfiguredNetworks.size() 604 + " SSID=" + config.SSID 605 + " Uid=" + Integer.toString(config.creatorUid) 606 + "/" + Integer.toString(config.lastUpdateUid)); 607 } 608 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 609 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 610 int netId = result.getNetworkId(); 611 612 if (VDBG) localLog("WifiConfigStore: saveNetwork got it back netId=", netId); 613 614 /* enable a new network */ 615 if (newNetwork && netId != INVALID_NETWORK_ID) { 616 if (VDBG) localLog("WifiConfigStore: will enable netId=", netId); 617 618 mWifiNative.enableNetwork(netId, false); 619 conf = mConfiguredNetworks.get(netId); 620 if (conf != null) 621 conf.status = Status.ENABLED; 622 } 623 624 conf = mConfiguredNetworks.get(netId); 625 if (conf != null) { 626 if (conf.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) { 627 if (VDBG) localLog("WifiConfigStore: re-enabling: " + conf.SSID); 628 629 // reenable autojoin, since new information has been provided 630 conf.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 631 enableNetworkWithoutBroadcast(conf.networkId, false); 632 } 633 if (VDBG) loge("WifiConfigStore: saveNetwork got config back netId=" 634 + Integer.toString(netId) 635 + " uid=" + Integer.toString(config.creatorUid)); 636 } 637 638 mWifiNative.saveConfig(); 639 sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ? 640 WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 641 return result; 642 } 643 644 void updateStatus(int netId, DetailedState state) { 645 if (netId != INVALID_NETWORK_ID) { 646 WifiConfiguration config = mConfiguredNetworks.get(netId); 647 if (config == null) return; 648 switch (state) { 649 case CONNECTED: 650 config.status = Status.CURRENT; 651 //we successfully connected, hence remove the blacklist 652 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 653 break; 654 case DISCONNECTED: 655 //If network is already disabled, keep the status 656 if (config.status == Status.CURRENT) { 657 config.status = Status.ENABLED; 658 } 659 break; 660 default: 661 //do nothing, retain the existing state 662 break; 663 } 664 } 665 } 666 667 /** 668 * Forget the specified network and save config 669 * 670 * @param netId network to forget 671 * @return {@code true} if it succeeds, {@code false} otherwise 672 */ 673 boolean forgetNetwork(int netId) { 674 if (VDBG) localLog("forgetNetwork", netId); 675 676 boolean remove = removeConfigAndSendBroadcastIfNeeded(netId); 677 if (!remove) { 678 //success but we dont want to remove the network from supplicant conf file 679 return true; 680 } 681 if (mWifiNative.removeNetwork(netId)) { 682 mWifiNative.saveConfig(); 683 return true; 684 } else { 685 loge("Failed to remove network " + netId); 686 return false; 687 } 688 } 689 690 /** 691 * Add/update a network. Note that there is no saveConfig operation. 692 * This function is retained for compatibility with the public 693 * API. The more powerful saveNetwork() is used by the 694 * state machine 695 * 696 * @param config wifi configuration to add/update 697 * @return network Id 698 */ 699 int addOrUpdateNetwork(WifiConfiguration config) { 700 if (VDBG) localLog("addOrUpdateNetwork id=", config.networkId); 701 //adding unconditional message to chase b/15111865 702 Log.e(TAG, " key=" + config.configKey() + " netId=" + Integer.toString(config.networkId) 703 + " uid=" + Integer.toString(config.creatorUid) 704 + "/" + Integer.toString(config.lastUpdateUid)); 705 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 706 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 707 WifiConfiguration conf = mConfiguredNetworks.get(result.getNetworkId()); 708 if (conf != null) { 709 sendConfiguredNetworksChangedBroadcast(conf, 710 result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : 711 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 712 } 713 } 714 return result.getNetworkId(); 715 } 716 717 /** 718 * Remove a network. Note that there is no saveConfig operation. 719 * This function is retained for compatibility with the public 720 * API. The more powerful forgetNetwork() is used by the 721 * state machine for network removal 722 * 723 * @param netId network to be removed 724 * @return {@code true} if it succeeds, {@code false} otherwise 725 */ 726 boolean removeNetwork(int netId) { 727 if (VDBG) localLog("removeNetwork", netId); 728 boolean ret = mWifiNative.removeNetwork(netId); 729 if (ret) { 730 removeConfigAndSendBroadcastIfNeeded(netId); 731 } 732 return ret; 733 } 734 735 private boolean removeConfigAndSendBroadcastIfNeeded(int netId) { 736 boolean remove = true; 737 WifiConfiguration config = mConfiguredNetworks.get(netId); 738 if (config != null) { 739 if (VDBG) { 740 loge("removeNetwork " + Integer.toString(netId) + " key=" + 741 config.configKey() + " config.id=" + Integer.toString(config.networkId)); 742 } 743 744 // cancel the last user choice 745 if (config.configKey().equals(lastSelectedConfiguration)) { 746 lastSelectedConfiguration = null; 747 } 748 749 // Remove any associated keys 750 if (config.enterpriseConfig != null) { 751 removeKeys(config.enterpriseConfig); 752 } 753 754 if (config.didSelfAdd) { 755 if (config.peerWifiConfiguration != null) { 756 for (WifiConfiguration peer : mConfiguredNetworks.values()) { 757 if (config.peerWifiConfiguration.equals(peer.configKey())) { 758 /* the configuration that trigger the add is still there */ 759 remove = false; 760 } 761 } 762 } else { 763 loge("removeNetwork " + Integer.toString(netId) 764 + " key=" + config.configKey() 765 + " config.id=" + Integer.toString(config.networkId) 766 + " didSelfAdd and null peerWifiConfiguration" 767 + " -> dont remove"); 768 remove = false; 769 } 770 } 771 772 if (remove) { 773 mConfiguredNetworks.remove(netId); 774 mNetworkIds.remove(configKey(config)); 775 } else { 776 /* we can't directly remove the configuration since we added it ourselves, because 777 * that could cause the system to re-add it right away. 778 * Instead black list it. It will be unblacklisted only thru a new add. 779 */ 780 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_DELETED); 781 mWifiNative.disableNetwork(config.networkId); 782 } 783 784 writeIpAndProxyConfigurations(); 785 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 786 writeKnownNetworkHistory(); 787 } 788 return remove; 789 } 790 791 /** 792 * Enable a network. Note that there is no saveConfig operation. 793 * This function is retained for compatibility with the public 794 * API. The more powerful selectNetwork()/saveNetwork() is used by the 795 * state machine for connecting to a network 796 * 797 * @param netId network to be enabled 798 * @return {@code true} if it succeeds, {@code false} otherwise 799 */ 800 boolean enableNetwork(int netId, boolean disableOthers) { 801 boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); 802 if (disableOthers) { 803 if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId); 804 sendConfiguredNetworksChangedBroadcast(); 805 } else { 806 if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId); 807 WifiConfiguration enabledNetwork = null; 808 synchronized(mConfiguredNetworks) { 809 enabledNetwork = mConfiguredNetworks.get(netId); 810 } 811 // check just in case the network was removed by someone else. 812 if (enabledNetwork != null) { 813 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 814 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 815 } 816 } 817 return ret; 818 } 819 820 boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { 821 boolean ret = mWifiNative.enableNetwork(netId, disableOthers); 822 823 WifiConfiguration config = mConfiguredNetworks.get(netId); 824 if (config != null) config.status = Status.ENABLED; 825 826 if (disableOthers) { 827 markAllNetworksDisabledExcept(netId); 828 } 829 return ret; 830 } 831 832 void disableAllNetworks() { 833 if (VDBG) localLog("disableAllNetworks"); 834 boolean networkDisabled = false; 835 for(WifiConfiguration config : mConfiguredNetworks.values()) { 836 if(config != null && config.status != Status.DISABLED) { 837 if(mWifiNative.disableNetwork(config.networkId)) { 838 networkDisabled = true; 839 config.status = Status.DISABLED; 840 } else { 841 loge("Disable network failed on " + config.networkId); 842 } 843 } 844 } 845 846 if (networkDisabled) { 847 sendConfiguredNetworksChangedBroadcast(); 848 } 849 } 850 /** 851 * Disable a network. Note that there is no saveConfig operation. 852 * @param netId network to be disabled 853 * @return {@code true} if it succeeds, {@code false} otherwise 854 */ 855 boolean disableNetwork(int netId) { 856 return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); 857 } 858 859 /** 860 * Disable a network. Note that there is no saveConfig operation. 861 * @param netId network to be disabled 862 * @param reason reason code network was disabled 863 * @return {@code true} if it succeeds, {@code false} otherwise 864 */ 865 boolean disableNetwork(int netId, int reason) { 866 if (VDBG) localLog("disableNetwork", netId); 867 boolean ret = mWifiNative.disableNetwork(netId); 868 WifiConfiguration network = null; 869 WifiConfiguration config = mConfiguredNetworks.get(netId); 870 871 if (VDBG) { 872 if (config != null) { 873 loge("disableNetwork netId=" + Integer.toString(netId) 874 + " SSID=" + config.SSID 875 + " disabled=" + (config.status == Status.DISABLED) 876 + " reason=" + Integer.toString(config.disableReason)); 877 } 878 } 879 /* Only change the reason if the network was not previously disabled */ 880 if (config != null && config.status != Status.DISABLED) { 881 config.status = Status.DISABLED; 882 config.disableReason = reason; 883 network = config; 884 } 885 if (network != null) { 886 sendConfiguredNetworksChangedBroadcast(network, 887 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 888 } 889 return ret; 890 } 891 892 /** 893 * Save the configured networks in supplicant to disk 894 * @return {@code true} if it succeeds, {@code false} otherwise 895 */ 896 boolean saveConfig() { 897 return mWifiNative.saveConfig(); 898 } 899 900 /** 901 * Start WPS pin method configuration with pin obtained 902 * from the access point 903 * @param config WPS configuration 904 * @return Wps result containing status and pin 905 */ 906 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 907 WpsResult result = new WpsResult(); 908 if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { 909 /* WPS leaves all networks disabled */ 910 markAllNetworksDisabled(); 911 result.status = WpsResult.Status.SUCCESS; 912 } else { 913 loge("Failed to start WPS pin method configuration"); 914 result.status = WpsResult.Status.FAILURE; 915 } 916 return result; 917 } 918 919 /** 920 * Start WPS pin method configuration with pin obtained 921 * from the device 922 * @return WpsResult indicating status and pin 923 */ 924 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 925 WpsResult result = new WpsResult(); 926 result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); 927 /* WPS leaves all networks disabled */ 928 if (!TextUtils.isEmpty(result.pin)) { 929 markAllNetworksDisabled(); 930 result.status = WpsResult.Status.SUCCESS; 931 } else { 932 loge("Failed to start WPS pin method configuration"); 933 result.status = WpsResult.Status.FAILURE; 934 } 935 return result; 936 } 937 938 /** 939 * Start WPS push button configuration 940 * @param config WPS configuration 941 * @return WpsResult indicating status and pin 942 */ 943 WpsResult startWpsPbc(WpsInfo config) { 944 WpsResult result = new WpsResult(); 945 if (mWifiNative.startWpsPbc(config.BSSID)) { 946 /* WPS leaves all networks disabled */ 947 markAllNetworksDisabled(); 948 result.status = WpsResult.Status.SUCCESS; 949 } else { 950 loge("Failed to start WPS push button configuration"); 951 result.status = WpsResult.Status.FAILURE; 952 } 953 return result; 954 } 955 956 /** 957 * Fetch the link properties for a given network id 958 * 959 * @return LinkProperties for the given network id 960 */ 961 LinkProperties getLinkProperties(int netId) { 962 WifiConfiguration config = mConfiguredNetworks.get(netId); 963 if (config != null) return new LinkProperties(config.getLinkProperties()); 964 return null; 965 } 966 967 /** 968 * set IP configuration for a given network id 969 */ 970 void setLinkProperties(int netId, LinkProperties linkProperties) { 971 WifiConfiguration config = mConfiguredNetworks.get(netId); 972 if (config != null) { 973 // add old proxy details - TODO - is this still needed? 974 if(config.getLinkProperties() != null) { 975 linkProperties.setHttpProxy(config.getLinkProperties().getHttpProxy()); 976 } 977 config.setLinkProperties(linkProperties); 978 } 979 } 980 981 /** 982 * set default GW MAC address 983 */ 984 void setDefaultGwMacAddress(int netId, String macAddress) { 985 WifiConfiguration config = mConfiguredNetworks.get(netId); 986 if (config != null) { 987 //update defaultGwMacAddress 988 config.defaultGwMacAddress = macAddress; 989 } 990 } 991 992 993 /** 994 * clear IP configuration for a given network id 995 * @param network id 996 */ 997 void clearLinkProperties(int netId) { 998 WifiConfiguration config = mConfiguredNetworks.get(netId); 999 if (config != null && config.getLinkProperties() != null) { 1000 // Clear everything except proxy 1001 ProxyInfo proxy = config.getLinkProperties().getHttpProxy(); 1002 config.getLinkProperties().clear(); 1003 config.getLinkProperties().setHttpProxy(proxy); 1004 } 1005 } 1006 1007 1008 /** 1009 * Fetch the proxy properties for a given network id 1010 * @param network id 1011 * @return ProxyInfo for the network id 1012 */ 1013 ProxyInfo getProxyProperties(int netId) { 1014 LinkProperties linkProperties = getLinkProperties(netId); 1015 if (linkProperties != null) { 1016 return new ProxyInfo(linkProperties.getHttpProxy()); 1017 } 1018 return null; 1019 } 1020 1021 /** 1022 * Return if the specified network is using static IP 1023 * @param network id 1024 * @return {@code true} if using static ip for netId 1025 */ 1026 boolean isUsingStaticIp(int netId) { 1027 WifiConfiguration config = mConfiguredNetworks.get(netId); 1028 if (config != null && config.getIpAssignment() == IpAssignment.STATIC) { 1029 return true; 1030 } 1031 return false; 1032 } 1033 1034 /** 1035 * Should be called when a single network configuration is made. 1036 * @param network The network configuration that changed. 1037 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 1038 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 1039 */ 1040 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 1041 int reason) { 1042 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1043 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1044 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 1045 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 1046 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 1047 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1048 } 1049 1050 /** 1051 * Should be called when multiple network configuration changes are made. 1052 */ 1053 private void sendConfiguredNetworksChangedBroadcast() { 1054 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1055 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1056 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 1057 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1058 } 1059 1060 void loadConfiguredNetworks() { 1061 String listStr = mWifiNative.listNetworks(); 1062 mLastPriority = 0; 1063 1064 mConfiguredNetworks.clear(); 1065 mNetworkIds.clear(); 1066 1067 if (listStr == null) 1068 return; 1069 1070 String[] lines = listStr.split("\n"); 1071 1072 if (VDBG) { 1073 loge("loadConfiguredNetworks: found " + Integer.toString(lines.length) 1074 + " networks", true); 1075 } 1076 1077 // Skip the first line, which is a header 1078 for (int i = 1; i < lines.length; i++) { 1079 String[] result = lines[i].split("\t"); 1080 // network-id | ssid | bssid | flags 1081 WifiConfiguration config = new WifiConfiguration(); 1082 try { 1083 config.networkId = Integer.parseInt(result[0]); 1084 } catch(NumberFormatException e) { 1085 loge("Failed to read network-id '" + result[0] + "'"); 1086 continue; 1087 } 1088 if (result.length > 3) { 1089 if (result[3].indexOf("[CURRENT]") != -1) 1090 config.status = WifiConfiguration.Status.CURRENT; 1091 else if (result[3].indexOf("[DISABLED]") != -1) 1092 config.status = WifiConfiguration.Status.DISABLED; 1093 else 1094 config.status = WifiConfiguration.Status.ENABLED; 1095 } else { 1096 config.status = WifiConfiguration.Status.ENABLED; 1097 } 1098 readNetworkVariables(config); 1099 if (config.priority > mLastPriority) { 1100 mLastPriority = config.priority; 1101 } 1102 1103 config.setIpAssignment(IpAssignment.DHCP); 1104 config.setProxySettings(ProxySettings.NONE); 1105 1106 if (mNetworkIds.containsKey(configKey(config))) { 1107 // That SSID is already known, just ignore this duplicate entry 1108 if (VDBG) localLog("discarded duplicate network ", config.networkId); 1109 } else if(config.isValid()){ 1110 mConfiguredNetworks.put(config.networkId, config); 1111 mNetworkIds.put(configKey(config), config.networkId); 1112 if (VDBG) localLog("loaded configured network", config.networkId); 1113 } else { 1114 if (DBG) log("Ignoring loaded configured for network " + config.networkId 1115 + " because config are not valid"); 1116 } 1117 } 1118 1119 readIpAndProxyConfigurations(); 1120 readNetworkHistory(); 1121 readAutoJoinConfig(); 1122 1123 sendConfiguredNetworksChangedBroadcast(); 1124 1125 if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks"); 1126 1127 if (mNetworkIds.size() == 0) { 1128 // no networks? Lets log if the wpa_supplicant.conf file contents 1129 BufferedReader reader = null; 1130 try { 1131 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 1132 if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---"); 1133 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 1134 if (VDBG) localLog(line); 1135 } 1136 if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---"); 1137 } catch (FileNotFoundException e) { 1138 if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 1139 } catch (IOException e) { 1140 if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 1141 } finally { 1142 try { 1143 if (reader != null) { 1144 reader.close(); 1145 } 1146 } catch (IOException e) { 1147 // Just ignore the fact that we couldn't close 1148 } 1149 } 1150 } 1151 } 1152 1153 private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) { 1154 Map<String, String> result = new HashMap<>(); 1155 BufferedReader reader = null; 1156 if (VDBG) loge("readNetworkVariablesFromSupplicantFile key=" + key); 1157 1158 try { 1159 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 1160 boolean found = false; 1161 String networkSsid = null; 1162 String value = null; 1163 1164 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 1165 if (VDBG) loge(line); 1166 1167 if (line.matches("[ \\t]*network=\\{")) { 1168 found = true; 1169 networkSsid = null; 1170 value = null; 1171 } else if (line.matches("[ \\t]*\\{")) { 1172 found = false; 1173 networkSsid = null; 1174 value = null; 1175 } 1176 1177 if (found) { 1178 int index; 1179 if ((index = line.indexOf("ssid=")) >= 0) { 1180 networkSsid = line.substring(index + 5); 1181 } else if ((index = line.indexOf(key + "=")) >= 0) { 1182 value = line.substring(index + key.length() + 1); 1183 } 1184 1185 if (networkSsid != null && value != null) { 1186 result.put(networkSsid, value); 1187 } 1188 } 1189 } 1190 } catch (FileNotFoundException e) { 1191 if (VDBG) loge("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 1192 } catch (IOException e) { 1193 if (VDBG) loge("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 1194 } finally { 1195 try { 1196 if (reader != null) { 1197 reader.close(); 1198 } 1199 } catch (IOException e) { 1200 // Just ignore the fact that we couldn't close 1201 } 1202 } 1203 1204 return result; 1205 } 1206 1207 private String readNetworkVariableFromSupplicantFile(String ssid, String key) { 1208 Map<String, String> data = readNetworkVariablesFromSupplicantFile(key); 1209 if (VDBG) loge("readNetworkVariableFromSupplicantFile ssid=[" + ssid + "] key=" + key); 1210 return data.get(ssid); 1211 } 1212 1213 /* Mark all networks except specified netId as disabled */ 1214 private void markAllNetworksDisabledExcept(int netId) { 1215 for(WifiConfiguration config : mConfiguredNetworks.values()) { 1216 if(config != null && config.networkId != netId) { 1217 if (config.status != Status.DISABLED) { 1218 config.status = Status.DISABLED; 1219 config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; 1220 } 1221 } 1222 } 1223 } 1224 1225 private void markAllNetworksDisabled() { 1226 markAllNetworksDisabledExcept(INVALID_NETWORK_ID); 1227 } 1228 1229 boolean needsUnlockedKeyStore() { 1230 1231 // Any network using certificates to authenticate access requires 1232 // unlocked key store; unless the certificates can be stored with 1233 // hardware encryption 1234 1235 for(WifiConfiguration config : mConfiguredNetworks.values()) { 1236 1237 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 1238 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 1239 1240 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 1241 return true; 1242 } 1243 } 1244 } 1245 1246 return false; 1247 } 1248 1249 public void writeKnownNetworkHistory() { 1250 if (VDBG) { 1251 loge(" writeKnownNetworkHistory() num networks:" + 1252 Integer.toString(mConfiguredNetworks.size()), true); 1253 } 1254 1255 /* Make a copy */ 1256 final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 1257 for (WifiConfiguration config : mConfiguredNetworks.values()) { 1258 networks.add(new WifiConfiguration(config)); 1259 } 1260 1261 mWriter.write(networkHistoryConfigFile, new DelayedDiskWrite.Writer() { 1262 public void onWriteCalled(DataOutputStream out) throws IOException { 1263 for (WifiConfiguration config : networks) { 1264 //loge("onWriteCalled write SSID: " + config.SSID); 1265 /* if (config.getLinkProperties() != null) 1266 loge(" lp " + config.getLinkProperties().toString()); 1267 else 1268 loge("attempt config w/o lp"); 1269 */ 1270 1271 if (VDBG) { 1272 int num = 0; 1273 if (config.connectChoices != null) { 1274 num = config.connectChoices.size(); 1275 } 1276 loge("saving network history: " + config.configKey() + " gw: " + 1277 config.defaultGwMacAddress + " autojoin status: " + 1278 config.autoJoinStatus + " ephemeral=" + config.ephemeral 1279 + " choices:" + Integer.toString(num)); 1280 } 1281 if (config.ephemeral == true) 1282 continue; 1283 1284 if (config.isValid() == false) 1285 continue; 1286 1287 if (config.SSID == null) { 1288 if (VDBG) { 1289 loge("writeKnownNetworkHistory trying to write config with null SSID"); 1290 } 1291 continue; 1292 } 1293 1294 out.writeUTF(CONFIG_KEY + config.configKey() + SEPARATOR_KEY); 1295 1296 out.writeUTF(SSID_KEY + config.SSID + SEPARATOR_KEY); 1297 out.writeUTF(FQDN_KEY + config.FQDN + SEPARATOR_KEY); 1298 1299 out.writeUTF(PRIORITY_KEY + Integer.toString(config.priority) + SEPARATOR_KEY); 1300 out.writeUTF(STATUS_KEY + Integer.toString(config.autoJoinStatus) 1301 + SEPARATOR_KEY); 1302 out.writeUTF(SUPPLICANT_STATUS_KEY + Integer.toString(config.status) 1303 + SEPARATOR_KEY); 1304 out.writeUTF(SUPPLICANT_DISABLE_REASON_KEY 1305 + Integer.toString(config.disableReason) 1306 + SEPARATOR_KEY); 1307 out.writeUTF(NETWORK_ID_KEY + Integer.toString(config.networkId) 1308 + SEPARATOR_KEY); 1309 out.writeUTF(SELF_ADDED_KEY + Boolean.toString(config.selfAdded) 1310 + SEPARATOR_KEY); 1311 out.writeUTF(DID_SELF_ADD_KEY + Boolean.toString(config.didSelfAdd) 1312 + SEPARATOR_KEY); 1313 if (config.peerWifiConfiguration != null) { 1314 out.writeUTF(PEER_CONFIGURATION_KEY + config.peerWifiConfiguration 1315 + SEPARATOR_KEY); 1316 } 1317 out.writeUTF(NUM_CONNECTION_FAILURES_KEY 1318 + Integer.toString(config.numConnectionFailures) 1319 + SEPARATOR_KEY); 1320 out.writeUTF(SCORER_OVERRIDE_KEY + Integer.toString(config.numScorerOverride) 1321 + SEPARATOR_KEY); 1322 out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY 1323 + Integer.toString(config.numScorerOverrideAndSwitchedNetwork) 1324 + SEPARATOR_KEY); 1325 out.writeUTF(NUM_ASSOCIATION_KEY 1326 + Integer.toString(config.numAssociation) 1327 + SEPARATOR_KEY); 1328 out.writeUTF(BLACKLIST_MILLI_KEY + Long.toString(config.blackListTimestamp) 1329 + SEPARATOR_KEY); 1330 out.writeUTF(CREATOR_UID_KEY + Integer.toString(config.creatorUid) 1331 + SEPARATOR_KEY); 1332 out.writeUTF(CONNECT_UID_KEY + Integer.toString(config.lastConnectUid) 1333 + SEPARATOR_KEY); 1334 out.writeUTF(UPDATE_UID_KEY + Integer.toString(config.lastUpdateUid) 1335 + SEPARATOR_KEY); 1336 String allowedKeyManagementString = 1337 makeString(config.allowedKeyManagement, 1338 WifiConfiguration.KeyMgmt.strings); 1339 out.writeUTF(AUTH_KEY + allowedKeyManagementString + SEPARATOR_KEY); 1340 1341 if (config.connectChoices != null) { 1342 for (String key : config.connectChoices.keySet()) { 1343 Integer choice = config.connectChoices.get(key); 1344 out.writeUTF(CHOICE_KEY + key + "=" 1345 + choice.toString() + SEPARATOR_KEY); 1346 } 1347 } 1348 if (config.linkedConfigurations != null) { 1349 for (String key : config.linkedConfigurations.keySet()) { 1350 out.writeUTF(LINK_KEY + key + SEPARATOR_KEY); 1351 } 1352 } 1353 1354 if (config.getLinkProperties() != null) { 1355 String macAddress = config.defaultGwMacAddress; 1356 if (macAddress != null) { 1357 out.writeUTF(DEFAULT_GW_KEY + macAddress + SEPARATOR_KEY); 1358 } 1359 } 1360 1361 if (config.scanResultCache != null) { 1362 for (ScanResult result : config.scanResultCache.values()) { 1363 out.writeUTF(BSSID_KEY + result.BSSID + SEPARATOR_KEY); 1364 1365 out.writeUTF(FREQ_KEY + Integer.toString(result.frequency) 1366 + SEPARATOR_KEY); 1367 1368 out.writeUTF(RSSI_KEY + Integer.toString(result.level) 1369 + SEPARATOR_KEY); 1370 1371 out.writeUTF(BSSID_STATUS_KEY + Integer.toString(result.status) 1372 + SEPARATOR_KEY); 1373 1374 if (result.seen != 0) { 1375 out.writeUTF(MILLI_KEY + Long.toString(result.seen) 1376 + SEPARATOR_KEY); 1377 } 1378 out.writeUTF(BSSID_KEY_END + SEPARATOR_KEY); 1379 } 1380 } 1381 if (config.lastFailure != null) { 1382 out.writeUTF(FAILURE_KEY + config.lastFailure + SEPARATOR_KEY); 1383 } 1384 out.writeUTF(SEPARATOR_KEY); 1385 } 1386 } 1387 1388 }); 1389 } 1390 1391 public void setLastSelectedConfiguration(int netId) { 1392 if (DBG) { 1393 loge("setLastSelectedConfiguration " + Integer.toString(netId)); 1394 } 1395 if (netId == WifiConfiguration.INVALID_NETWORK_ID) { 1396 lastSelectedConfiguration = null; 1397 } else { 1398 WifiConfiguration selected = getWifiConfiguration(netId); 1399 if (selected == null) { 1400 lastSelectedConfiguration = null; 1401 } else { 1402 lastSelectedConfiguration = selected.configKey(); 1403 if (VDBG) { 1404 loge("setLastSelectedConfiguration now: " + lastSelectedConfiguration); 1405 } 1406 } 1407 } 1408 } 1409 1410 public String getLastSelectedConfiguration() { 1411 return lastSelectedConfiguration; 1412 } 1413 1414 private void readNetworkHistory() { 1415 if (VDBG) { 1416 loge("will readNetworkHistory path:" + networkHistoryConfigFile, true); 1417 } 1418 DataInputStream in = null; 1419 try { 1420 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 1421 networkHistoryConfigFile))); 1422 WifiConfiguration config = null; 1423 while (true) { 1424 int id = -1; 1425 String key = in.readUTF(); 1426 String bssid = null; 1427 String ssid = null; 1428 1429 int freq = 0; 1430 int status = 0; 1431 long seen = 0; 1432 int rssi = WifiConfiguration.INVALID_RSSI; 1433 String caps = null; 1434 if (key.startsWith(CONFIG_KEY)) { 1435 1436 if (config != null) { 1437 config = null; 1438 } 1439 String configKey = key.replace(CONFIG_KEY, ""); 1440 configKey = configKey.replace(SEPARATOR_KEY, ""); 1441 // get the networkId for that config Key 1442 Integer n = mNetworkIds.get(configKey.hashCode()); 1443 // skip reading that configuration data 1444 // since we don't have a corresponding network ID 1445 if (n == null) { 1446 loge("readNetworkHistory didnt find netid for hash=" 1447 + Integer.toString(configKey.hashCode()) 1448 + " key: " + configKey); 1449 continue; 1450 } 1451 config = mConfiguredNetworks.get(n); 1452 if (config == null) { 1453 loge("readNetworkHistory didnt find config for netid=" 1454 + n.toString() 1455 + " key: " + configKey); 1456 } 1457 status = 0; 1458 ssid = null; 1459 bssid = null; 1460 freq = 0; 1461 seen = 0; 1462 rssi = WifiConfiguration.INVALID_RSSI; 1463 caps = null; 1464 1465 } else if (config != null) { 1466 if (key.startsWith(SSID_KEY)) { 1467 ssid = key.replace(SSID_KEY, ""); 1468 ssid = ssid.replace(SEPARATOR_KEY, ""); 1469 if (config.SSID != null && !config.SSID.equals(ssid)) { 1470 loge("Error parsing network history file, mismatched SSIDs"); 1471 config = null; //error 1472 ssid = null; 1473 } else { 1474 config.SSID = ssid; 1475 } 1476 } 1477 1478 if (key.startsWith(FQDN_KEY)) { 1479 String fqdn = key.replace(FQDN_KEY, ""); 1480 fqdn = fqdn.replace(SEPARATOR_KEY, ""); 1481 config.FQDN = fqdn; 1482 } 1483 1484 if (key.startsWith(DEFAULT_GW_KEY)) { 1485 String gateway = key.replace(DEFAULT_GW_KEY, ""); 1486 gateway = gateway.replace(SEPARATOR_KEY, ""); 1487 config.defaultGwMacAddress = gateway; 1488 } 1489 1490 if (key.startsWith(STATUS_KEY)) { 1491 String st = key.replace(STATUS_KEY, ""); 1492 st = st.replace(SEPARATOR_KEY, ""); 1493 config.autoJoinStatus = Integer.parseInt(st); 1494 } 1495 1496 /* 1497 if (key.startsWith(SUPPLICANT_STATUS_KEY)) { 1498 String status = key.replace(SUPPLICANT_STATUS_KEY, ""); 1499 status = status.replace(SEPARATOR_KEY, ""); 1500 config.status = Integer.parseInt(status); 1501 } 1502 1503 if (key.startsWith(SUPPLICANT_DISABLE_REASON_KEY)) { 1504 String reason = key.replace(SUPPLICANT_DISABLE_REASON_KEY, ""); 1505 reason = reason.replace(SEPARATOR_KEY, ""); 1506 config.disableReason = Integer.parseInt(reason); 1507 }*/ 1508 1509 if (key.startsWith(SELF_ADDED_KEY)) { 1510 String selfAdded = key.replace(SELF_ADDED_KEY, ""); 1511 selfAdded = selfAdded.replace(SEPARATOR_KEY, ""); 1512 config.selfAdded = Boolean.parseBoolean(selfAdded); 1513 } 1514 1515 if (key.startsWith(DID_SELF_ADD_KEY)) { 1516 String didSelfAdd = key.replace(DID_SELF_ADD_KEY, ""); 1517 didSelfAdd = didSelfAdd.replace(SEPARATOR_KEY, ""); 1518 config.didSelfAdd = Boolean.parseBoolean(didSelfAdd); 1519 } 1520 1521 if (key.startsWith(CREATOR_UID_KEY)) { 1522 String uid = key.replace(CREATOR_UID_KEY, ""); 1523 uid = uid.replace(SEPARATOR_KEY, ""); 1524 config.creatorUid = Integer.parseInt(uid); 1525 } 1526 1527 if (key.startsWith(BLACKLIST_MILLI_KEY)) { 1528 String milli = key.replace(BLACKLIST_MILLI_KEY, ""); 1529 milli = milli.replace(SEPARATOR_KEY, ""); 1530 config.blackListTimestamp = Long.parseLong(milli); 1531 } 1532 1533 if (key.startsWith(NUM_CONNECTION_FAILURES_KEY)) { 1534 String num = key.replace(NUM_CONNECTION_FAILURES_KEY, ""); 1535 num = num.replace(SEPARATOR_KEY, ""); 1536 config.numConnectionFailures = Integer.parseInt(num); 1537 } 1538 1539 if (key.startsWith(SCORER_OVERRIDE_KEY)) { 1540 String num = key.replace(SCORER_OVERRIDE_KEY, ""); 1541 num = num.replace(SEPARATOR_KEY, ""); 1542 config.numScorerOverride = Integer.parseInt(num); 1543 } 1544 1545 if (key.startsWith(SCORER_OVERRIDE_AND_SWITCH_KEY)) { 1546 String num = key.replace(SCORER_OVERRIDE_AND_SWITCH_KEY, ""); 1547 num = num.replace(SEPARATOR_KEY, ""); 1548 config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(num); 1549 } 1550 1551 if (key.startsWith(NUM_ASSOCIATION_KEY)) { 1552 String num = key.replace(NUM_ASSOCIATION_KEY, ""); 1553 num = num.replace(SEPARATOR_KEY, ""); 1554 config.numAssociation = Integer.parseInt(num); 1555 } 1556 1557 if (key.startsWith(CONNECT_UID_KEY)) { 1558 String uid = key.replace(CONNECT_UID_KEY, ""); 1559 uid = uid.replace(SEPARATOR_KEY, ""); 1560 config.lastConnectUid = Integer.parseInt(uid); 1561 } 1562 1563 if (key.startsWith(UPDATE_UID_KEY)) { 1564 String uid = key.replace(UPDATE_UID_KEY, ""); 1565 uid = uid.replace(SEPARATOR_KEY, ""); 1566 config.lastUpdateUid = Integer.parseInt(uid); 1567 } 1568 1569 if (key.startsWith(FAILURE_KEY)) { 1570 config.lastFailure = key.replace(FAILURE_KEY, ""); 1571 config.lastFailure = config.lastFailure.replace(SEPARATOR_KEY, ""); 1572 } 1573 1574 if (key.startsWith(PEER_CONFIGURATION_KEY)) { 1575 config.peerWifiConfiguration = key.replace(PEER_CONFIGURATION_KEY, ""); 1576 config.peerWifiConfiguration = 1577 config.peerWifiConfiguration.replace(SEPARATOR_KEY, ""); 1578 } 1579 1580 if (key.startsWith(CHOICE_KEY)) { 1581 String choiceStr = key.replace(CHOICE_KEY, ""); 1582 choiceStr = choiceStr.replace(SEPARATOR_KEY, ""); 1583 String configKey = ""; 1584 int choice = 0; 1585 Matcher match = mConnectChoice.matcher(choiceStr); 1586 if (!match.find()) { 1587 if (DBG) Log.d(TAG, "WifiConfigStore: connectChoice: " + 1588 " Couldnt match pattern : " + choiceStr); 1589 } else { 1590 configKey = match.group(1); 1591 try { 1592 choice = Integer.parseInt(match.group(2)); 1593 } catch (NumberFormatException e) { 1594 choice = 0; 1595 } 1596 if (choice > 0) { 1597 if (config.connectChoices == null) { 1598 config.connectChoices = new HashMap<String, Integer>(); 1599 } 1600 config.connectChoices.put(configKey, choice); 1601 } 1602 } 1603 } 1604 1605 if (key.startsWith(LINK_KEY)) { 1606 String configKey = key.replace(LINK_KEY, ""); 1607 configKey = configKey.replace(SEPARATOR_KEY, ""); 1608 if (config.linkedConfigurations == null) { 1609 config.linkedConfigurations = new HashMap<String, Integer>(); 1610 } 1611 if (config.linkedConfigurations != null) { 1612 config.linkedConfigurations.put(configKey, -1); 1613 } 1614 } 1615 1616 if (key.startsWith(BSSID_KEY)) { 1617 if (key.startsWith(BSSID_KEY)) { 1618 bssid = key.replace(BSSID_KEY, ""); 1619 bssid = bssid.replace(SEPARATOR_KEY, ""); 1620 freq = 0; 1621 seen = 0; 1622 rssi = WifiConfiguration.INVALID_RSSI; 1623 caps = ""; 1624 status = 0; 1625 } 1626 1627 if (key.startsWith(RSSI_KEY)) { 1628 String lvl = key.replace(RSSI_KEY, ""); 1629 lvl = lvl.replace(SEPARATOR_KEY, ""); 1630 rssi = Integer.parseInt(lvl); 1631 } 1632 1633 if (key.startsWith(BSSID_STATUS_KEY)) { 1634 String st = key.replace(BSSID_STATUS_KEY, ""); 1635 st = st.replace(SEPARATOR_KEY, ""); 1636 status = Integer.parseInt(st); 1637 } 1638 1639 if (key.startsWith(FREQ_KEY)) { 1640 String channel = key.replace(FREQ_KEY, ""); 1641 channel = channel.replace(SEPARATOR_KEY, ""); 1642 freq = Integer.parseInt(channel); 1643 } 1644 1645 if (key.startsWith(DATE_KEY)) { 1646 /* 1647 * when reading the configuration from file we don't update the date 1648 * so as to avoid reading back stale or non-sensical data that would 1649 * depend on network time. 1650 * The date of a WifiConfiguration should only come from actual scan result. 1651 * 1652 String s = key.replace(FREQ_KEY, ""); 1653 seen = Integer.getInteger(s); 1654 */ 1655 } 1656 1657 if (key.startsWith(BSSID_KEY_END)) { 1658 1659 if ((bssid != null) && (ssid != null)) { 1660 1661 if (config.scanResultCache == null) { 1662 config.scanResultCache = new HashMap<String, ScanResult>(); 1663 } 1664 WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid); 1665 ScanResult result = new ScanResult(wssid, bssid, 1666 caps, rssi, freq, (long) 0); 1667 result.seen = seen; 1668 config.scanResultCache.put(bssid, result); 1669 result.status = status; 1670 } 1671 } 1672 } 1673 } 1674 } 1675 } catch (EOFException ignore) { 1676 if (in != null) { 1677 try { 1678 in.close(); 1679 } catch (Exception e) { 1680 loge("readNetworkHistory: Error reading file" + e); 1681 } 1682 } 1683 } catch (IOException e) { 1684 loge("readNetworkHistory: No config file, revert to default" + e); 1685 } 1686 1687 if(in!=null) { 1688 try { 1689 in.close(); 1690 } catch (Exception e) { 1691 loge("readNetworkHistory: Error closing file" + e); 1692 } 1693 } 1694 } 1695 1696 private void readAutoJoinConfig() { 1697 BufferedReader reader = null; 1698 try { 1699 1700 reader = new BufferedReader(new FileReader(autoJoinConfigFile)); 1701 1702 for (String key = reader.readLine(); key != null; key = reader.readLine()) { 1703 if (key != null) { 1704 Log.d(TAG, "readAutoJoinConfig line: " + key); 1705 } 1706 if (key.startsWith(ENABLE_AUTOJOIN_WHILE_ASSOCIATED_KEY)) { 1707 String st = key.replace(ENABLE_AUTOJOIN_WHILE_ASSOCIATED_KEY, ""); 1708 st = st.replace(SEPARATOR_KEY, ""); 1709 try { 1710 enableAutoJoinWhileAssociated = Integer.parseInt(st) != 0; 1711 Log.d(TAG,"readAutoJoinConfig: enabled = " + enableAutoJoinWhileAssociated); 1712 } catch (NumberFormatException e) { 1713 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1714 } 1715 } 1716 1717 if (key.startsWith(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY)) { 1718 String st = 1719 key.replace(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY, ""); 1720 st = st.replace(SEPARATOR_KEY, ""); 1721 try { 1722 thresholdInitialAutoJoinAttemptMin5RSSI = Integer.parseInt(st); 1723 Log.d(TAG,"readAutoJoinConfig: thresholdInitialAutoJoinAttemptMin5RSSI = " 1724 + Integer.toString(thresholdInitialAutoJoinAttemptMin5RSSI)); 1725 } catch (NumberFormatException e) { 1726 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1727 } 1728 } 1729 1730 if (key.startsWith(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY)) { 1731 String st = 1732 key.replace(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY, ""); 1733 st = st.replace(SEPARATOR_KEY, ""); 1734 try { 1735 thresholdInitialAutoJoinAttemptMin24RSSI = Integer.parseInt(st); 1736 Log.d(TAG,"readAutoJoinConfig: thresholdInitialAutoJoinAttemptMin24RSSI = " 1737 + Integer.toString(thresholdInitialAutoJoinAttemptMin24RSSI)); 1738 } catch (NumberFormatException e) { 1739 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1740 } 1741 } 1742 1743 if (key.startsWith(THRESHOLD_UNBLACKLIST_HARD_5G_KEY)) { 1744 String st = key.replace(THRESHOLD_UNBLACKLIST_HARD_5G_KEY, ""); 1745 st = st.replace(SEPARATOR_KEY, ""); 1746 try { 1747 thresholdUnblacklistThreshold5Hard = Integer.parseInt(st); 1748 Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold5Hard = " 1749 + Integer.toString(thresholdUnblacklistThreshold5Hard)); 1750 } catch (NumberFormatException e) { 1751 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1752 } 1753 } 1754 if (key.startsWith(THRESHOLD_UNBLACKLIST_SOFT_5G_KEY)) { 1755 String st = key.replace(THRESHOLD_UNBLACKLIST_SOFT_5G_KEY, ""); 1756 st = st.replace(SEPARATOR_KEY, ""); 1757 try { 1758 thresholdUnblacklistThreshold5Soft = Integer.parseInt(st); 1759 Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold5Soft = " 1760 + Integer.toString(thresholdUnblacklistThreshold5Soft)); 1761 } catch (NumberFormatException e) { 1762 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1763 } 1764 } 1765 if (key.startsWith(THRESHOLD_UNBLACKLIST_HARD_24G_KEY)) { 1766 String st = key.replace(THRESHOLD_UNBLACKLIST_HARD_24G_KEY, ""); 1767 st = st.replace(SEPARATOR_KEY, ""); 1768 try { 1769 thresholdUnblacklistThreshold24Hard = Integer.parseInt(st); 1770 Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold24Hard = " 1771 + Integer.toString(thresholdUnblacklistThreshold24Hard)); 1772 } catch (NumberFormatException e) { 1773 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1774 } 1775 } 1776 if (key.startsWith(THRESHOLD_UNBLACKLIST_SOFT_24G_KEY)) { 1777 String st = key.replace(THRESHOLD_UNBLACKLIST_SOFT_24G_KEY, ""); 1778 st = st.replace(SEPARATOR_KEY, ""); 1779 try { 1780 thresholdUnblacklistThreshold24Soft = Integer.parseInt(st); 1781 Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold24Soft = " 1782 + Integer.toString(thresholdUnblacklistThreshold24Soft)); 1783 } catch (NumberFormatException e) { 1784 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1785 } 1786 } 1787 1788 if (key.startsWith(THRESHOLD_GOOD_RSSI_5_KEY)) { 1789 String st = key.replace(THRESHOLD_GOOD_RSSI_5_KEY, ""); 1790 st = st.replace(SEPARATOR_KEY, ""); 1791 try { 1792 thresholdGoodRssi5 = Integer.parseInt(st); 1793 Log.d(TAG,"readAutoJoinConfig: thresholdGoodRssi5 = " 1794 + Integer.toString(thresholdGoodRssi5)); 1795 } catch (NumberFormatException e) { 1796 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1797 } 1798 } 1799 if (key.startsWith(THRESHOLD_LOW_RSSI_5_KEY)) { 1800 String st = key.replace(THRESHOLD_LOW_RSSI_5_KEY, ""); 1801 st = st.replace(SEPARATOR_KEY, ""); 1802 try { 1803 thresholdLowRssi5 = Integer.parseInt(st); 1804 Log.d(TAG,"readAutoJoinConfig: thresholdLowRssi5 = " 1805 + Integer.toString(thresholdLowRssi5)); 1806 } catch (NumberFormatException e) { 1807 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1808 } 1809 } 1810 if (key.startsWith(THRESHOLD_BAD_RSSI_5_KEY)) { 1811 String st = key.replace(THRESHOLD_BAD_RSSI_5_KEY, ""); 1812 st = st.replace(SEPARATOR_KEY, ""); 1813 try { 1814 thresholdBadRssi5 = Integer.parseInt(st); 1815 Log.d(TAG,"readAutoJoinConfig: thresholdBadRssi5 = " 1816 + Integer.toString(thresholdBadRssi5)); 1817 } catch (NumberFormatException e) { 1818 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1819 } 1820 } 1821 1822 if (key.startsWith(THRESHOLD_GOOD_RSSI_24_KEY)) { 1823 String st = key.replace(THRESHOLD_GOOD_RSSI_24_KEY, ""); 1824 st = st.replace(SEPARATOR_KEY, ""); 1825 try { 1826 thresholdGoodRssi24 = Integer.parseInt(st); 1827 Log.d(TAG,"readAutoJoinConfig: thresholdGoodRssi24 = " 1828 + Integer.toString(thresholdGoodRssi24)); 1829 } catch (NumberFormatException e) { 1830 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1831 } 1832 } 1833 if (key.startsWith(THRESHOLD_LOW_RSSI_24_KEY)) { 1834 String st = key.replace(THRESHOLD_LOW_RSSI_24_KEY, ""); 1835 st = st.replace(SEPARATOR_KEY, ""); 1836 try { 1837 thresholdLowRssi24 = Integer.parseInt(st); 1838 Log.d(TAG,"readAutoJoinConfig: thresholdLowRssi24 = " 1839 + Integer.toString(thresholdLowRssi24)); 1840 } catch (NumberFormatException e) { 1841 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1842 } 1843 } 1844 if (key.startsWith(THRESHOLD_BAD_RSSI_24_KEY)) { 1845 String st = key.replace(THRESHOLD_BAD_RSSI_24_KEY, ""); 1846 st = st.replace(SEPARATOR_KEY, ""); 1847 try { 1848 thresholdBadRssi24 = Integer.parseInt(st); 1849 Log.d(TAG,"readAutoJoinConfig: thresholdBadRssi24 = " 1850 + Integer.toString(thresholdBadRssi24)); 1851 } catch (NumberFormatException e) { 1852 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1853 } 1854 } 1855 1856 if (key.startsWith(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY)) { 1857 String st = key.replace(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY, ""); 1858 st = st.replace(SEPARATOR_KEY, ""); 1859 try { 1860 maxTxPacketForNetworkSwitching = Integer.parseInt(st); 1861 Log.d(TAG,"readAutoJoinConfig: maxTxPacketForNetworkSwitching = " 1862 + Integer.toString(maxTxPacketForNetworkSwitching)); 1863 } catch (NumberFormatException e) { 1864 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1865 } 1866 } 1867 if (key.startsWith(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY)) { 1868 String st = key.replace(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY, ""); 1869 st = st.replace(SEPARATOR_KEY, ""); 1870 try { 1871 maxRxPacketForNetworkSwitching = Integer.parseInt(st); 1872 Log.d(TAG,"readAutoJoinConfig: maxRxPacketForNetworkSwitching = " 1873 + Integer.toString(maxRxPacketForNetworkSwitching)); 1874 } catch (NumberFormatException e) { 1875 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1876 } 1877 } 1878 1879 if (key.startsWith(A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW_KEY)) { 1880 String st = key.replace(A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW_KEY, ""); 1881 st = st.replace(SEPARATOR_KEY, ""); 1882 try { 1883 thresholdBandPreferenceLowRssi5 = Integer.parseInt(st); 1884 Log.d(TAG,"readAutoJoinConfig: thresholdBandPreferenceLowRssi5 = " 1885 + Integer.toString(thresholdBandPreferenceLowRssi5)); 1886 } catch (NumberFormatException e) { 1887 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1888 } 1889 } 1890 if (key.startsWith(A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY)) { 1891 String st = key.replace(A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, ""); 1892 st = st.replace(SEPARATOR_KEY, ""); 1893 try { 1894 thresholdBandPreferenceRssi5 = Integer.parseInt(st); 1895 Log.d(TAG,"readAutoJoinConfig: thresholdBandPreferenceRssi5 = " 1896 + Integer.toString(thresholdBandPreferenceRssi5)); 1897 } catch (NumberFormatException e) { 1898 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1899 } 1900 } 1901 if (key.startsWith(G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY)) { 1902 String st = key.replace(G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, ""); 1903 st = st.replace(SEPARATOR_KEY, ""); 1904 try { 1905 thresholdBandPreferenceRssi24 = Integer.parseInt(st); 1906 Log.d(TAG,"readAutoJoinConfig: thresholdBandPreferenceRssi24 = " 1907 + Integer.toString(thresholdBandPreferenceRssi24)); 1908 } catch (NumberFormatException e) { 1909 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 1910 } 1911 } 1912 } 1913 } catch (EOFException ignore) { 1914 if (reader != null) { 1915 try { 1916 reader.close(); 1917 reader = null; 1918 } catch (Exception e) { 1919 loge("readAutoJoinStatus: Error closing file" + e); 1920 } 1921 } 1922 } catch (IOException e) { 1923 loge("readAutoJoinStatus: Error parsing configuration" + e); 1924 } 1925 1926 if (reader!=null) { 1927 try { 1928 reader.close(); 1929 } catch (Exception e) { 1930 loge("readAutoJoinStatus: Error closing file" + e); 1931 } 1932 } 1933 } 1934 1935 1936 private void writeIpAndProxyConfigurations() { 1937 final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>(); 1938 for(WifiConfiguration config : mConfiguredNetworks.values()) { 1939 if (!config.ephemeral && config.autoJoinStatus != WifiConfiguration.AUTO_JOIN_DELETED) { 1940 networks.put(configKey(config), config.getIpConfiguration()); 1941 } 1942 } 1943 1944 super.writeIpAndProxyConfigurations(ipConfigFile, networks); 1945 } 1946 1947 private void readIpAndProxyConfigurations() { 1948 SparseArray<IpConfiguration> networks = super.readIpAndProxyConfigurations(ipConfigFile); 1949 1950 if (networks.size() == 0) { 1951 // IpConfigStore.readIpAndProxyConfigurations has already logged an error. 1952 return; 1953 } 1954 1955 for (int i = 0; i < networks.size(); i++) { 1956 int id = networks.keyAt(i); 1957 WifiConfiguration config = mConfiguredNetworks.get(mNetworkIds.get(id)); 1958 1959 1960 if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { 1961 loge("configuration found for missing network, nid=" + id 1962 +", ignored, networks.size=" + Integer.toString(networks.size())); 1963 } else { 1964 config.setIpConfiguration(networks.valueAt(i)); 1965 } 1966 } 1967 } 1968 1969 /* 1970 * Convert string to Hexadecimal before passing to wifi native layer 1971 * In native function "doCommand()" have trouble in converting Unicode character string to UTF8 1972 * conversion to hex is required because SSIDs can have space characters in them; 1973 * and that can confuses the supplicant because it uses space charaters as delimiters 1974 */ 1975 1976 private String encodeSSID(String str){ 1977 String tmp = removeDoubleQuotes(str); 1978 return String.format("%x", new BigInteger(1, tmp.getBytes(Charset.forName("UTF-8")))); 1979 } 1980 1981 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { 1982 /* 1983 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1984 * network configuration. Otherwise, the networkId should 1985 * refer to an existing configuration. 1986 */ 1987 1988 if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 1989 1990 int netId = config.networkId; 1991 boolean newNetwork = false; 1992 // networkId of INVALID_NETWORK_ID means we want to create a new network 1993 if (netId == INVALID_NETWORK_ID) { 1994 Integer savedNetId = mNetworkIds.get(configKey(config)); 1995 //paranoia: check if either we have a network Id or a WifiConfiguration 1996 //matching the one we are trying to add. 1997 if (savedNetId == null) { 1998 for (WifiConfiguration test : mConfiguredNetworks.values()) { 1999 if (test.configKey().equals(config.configKey())) { 2000 savedNetId = test.networkId; 2001 loge("addOrUpdateNetworkNative " + config.configKey() 2002 + " was found, but no network Id"); 2003 break; 2004 } 2005 } 2006 } 2007 if (savedNetId != null) { 2008 netId = savedNetId; 2009 } else { 2010 newNetwork = true; 2011 netId = mWifiNative.addNetwork(); 2012 if (netId < 0) { 2013 loge("Failed to add a network!"); 2014 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2015 } else { 2016 loge("addOrUpdateNetworkNative created netId=" + netId); 2017 } 2018 } 2019 } 2020 2021 boolean updateFailed = true; 2022 2023 setVariables: { 2024 2025 if (config.SSID != null && 2026 !mWifiNative.setNetworkVariable( 2027 netId, 2028 WifiConfiguration.ssidVarName, 2029 encodeSSID(config.SSID))) { 2030 loge("failed to set SSID: "+config.SSID); 2031 break setVariables; 2032 } 2033 2034 if (config.BSSID != null) { 2035 loge("Setting BSSID for " + config.configKey() + " to " + config.BSSID); 2036 if (!mWifiNative.setNetworkVariable( 2037 netId, 2038 WifiConfiguration.bssidVarName, 2039 config.BSSID)) { 2040 loge("failed to set BSSID: " + config.BSSID); 2041 break setVariables; 2042 } 2043 } 2044 2045 String allowedKeyManagementString = 2046 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 2047 if (config.allowedKeyManagement.cardinality() != 0 && 2048 !mWifiNative.setNetworkVariable( 2049 netId, 2050 WifiConfiguration.KeyMgmt.varName, 2051 allowedKeyManagementString)) { 2052 loge("failed to set key_mgmt: "+ 2053 allowedKeyManagementString); 2054 break setVariables; 2055 } 2056 2057 String allowedProtocolsString = 2058 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 2059 if (config.allowedProtocols.cardinality() != 0 && 2060 !mWifiNative.setNetworkVariable( 2061 netId, 2062 WifiConfiguration.Protocol.varName, 2063 allowedProtocolsString)) { 2064 loge("failed to set proto: "+ 2065 allowedProtocolsString); 2066 break setVariables; 2067 } 2068 2069 String allowedAuthAlgorithmsString = 2070 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 2071 if (config.allowedAuthAlgorithms.cardinality() != 0 && 2072 !mWifiNative.setNetworkVariable( 2073 netId, 2074 WifiConfiguration.AuthAlgorithm.varName, 2075 allowedAuthAlgorithmsString)) { 2076 loge("failed to set auth_alg: "+ 2077 allowedAuthAlgorithmsString); 2078 break setVariables; 2079 } 2080 2081 String allowedPairwiseCiphersString = 2082 makeString(config.allowedPairwiseCiphers, 2083 WifiConfiguration.PairwiseCipher.strings); 2084 if (config.allowedPairwiseCiphers.cardinality() != 0 && 2085 !mWifiNative.setNetworkVariable( 2086 netId, 2087 WifiConfiguration.PairwiseCipher.varName, 2088 allowedPairwiseCiphersString)) { 2089 loge("failed to set pairwise: "+ 2090 allowedPairwiseCiphersString); 2091 break setVariables; 2092 } 2093 2094 String allowedGroupCiphersString = 2095 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 2096 if (config.allowedGroupCiphers.cardinality() != 0 && 2097 !mWifiNative.setNetworkVariable( 2098 netId, 2099 WifiConfiguration.GroupCipher.varName, 2100 allowedGroupCiphersString)) { 2101 loge("failed to set group: "+ 2102 allowedGroupCiphersString); 2103 break setVariables; 2104 } 2105 2106 // Prevent client screw-up by passing in a WifiConfiguration we gave it 2107 // by preventing "*" as a key. 2108 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 2109 !mWifiNative.setNetworkVariable( 2110 netId, 2111 WifiConfiguration.pskVarName, 2112 config.preSharedKey)) { 2113 loge("failed to set psk"); 2114 break setVariables; 2115 } 2116 2117 boolean hasSetKey = false; 2118 if (config.wepKeys != null) { 2119 for (int i = 0; i < config.wepKeys.length; i++) { 2120 // Prevent client screw-up by passing in a WifiConfiguration we gave it 2121 // by preventing "*" as a key. 2122 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 2123 if (!mWifiNative.setNetworkVariable( 2124 netId, 2125 WifiConfiguration.wepKeyVarNames[i], 2126 config.wepKeys[i])) { 2127 loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); 2128 break setVariables; 2129 } 2130 hasSetKey = true; 2131 } 2132 } 2133 } 2134 2135 if (hasSetKey) { 2136 if (!mWifiNative.setNetworkVariable( 2137 netId, 2138 WifiConfiguration.wepTxKeyIdxVarName, 2139 Integer.toString(config.wepTxKeyIndex))) { 2140 loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); 2141 break setVariables; 2142 } 2143 } 2144 2145 if (!mWifiNative.setNetworkVariable( 2146 netId, 2147 WifiConfiguration.priorityVarName, 2148 Integer.toString(config.priority))) { 2149 loge(config.SSID + ": failed to set priority: " 2150 +config.priority); 2151 break setVariables; 2152 } 2153 2154 if (config.hiddenSSID && !mWifiNative.setNetworkVariable( 2155 netId, 2156 WifiConfiguration.hiddenSSIDVarName, 2157 Integer.toString(config.hiddenSSID ? 1 : 0))) { 2158 loge(config.SSID + ": failed to set hiddenSSID: "+ 2159 config.hiddenSSID); 2160 break setVariables; 2161 } 2162 2163 if (config.requirePMF && !mWifiNative.setNetworkVariable( 2164 netId, 2165 WifiConfiguration.pmfVarName, 2166 "2")) { 2167 loge(config.SSID + ": failed to set requirePMF: "+ 2168 config.requirePMF); 2169 break setVariables; 2170 } 2171 2172 if (config.updateIdentifier != null && !mWifiNative.setNetworkVariable( 2173 netId, 2174 WifiConfiguration.updateIdentiferVarName, 2175 config.updateIdentifier)) { 2176 loge(config.SSID + ": failed to set updateIdentifier: "+ 2177 config.updateIdentifier); 2178 break setVariables; 2179 } 2180 2181 if (config.enterpriseConfig != null && 2182 config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { 2183 2184 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 2185 2186 if (needsKeyStore(enterpriseConfig)) { 2187 /** 2188 * Keyguard settings may eventually be controlled by device policy. 2189 * We check here if keystore is unlocked before installing 2190 * credentials. 2191 * TODO: Do we need a dialog here ? 2192 */ 2193 if (mKeyStore.state() != KeyStore.State.UNLOCKED) { 2194 loge(config.SSID + ": key store is locked"); 2195 break setVariables; 2196 } 2197 2198 try { 2199 /* config passed may include only fields being updated. 2200 * In order to generate the key id, fetch uninitialized 2201 * fields from the currently tracked configuration 2202 */ 2203 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 2204 String keyId = config.getKeyIdForCredentials(currentConfig); 2205 2206 if (!installKeys(enterpriseConfig, keyId)) { 2207 loge(config.SSID + ": failed to install keys"); 2208 break setVariables; 2209 } 2210 } catch (IllegalStateException e) { 2211 loge(config.SSID + " invalid config for key installation"); 2212 break setVariables; 2213 } 2214 } 2215 2216 HashMap<String, String> enterpriseFields = enterpriseConfig.getFields(); 2217 for (String key : enterpriseFields.keySet()) { 2218 String value = enterpriseFields.get(key); 2219 if (key.equals("password") && value != null && value.equals("*")) { 2220 //no need to try to set an obfuscated password, which will fail 2221 continue; 2222 } 2223 if (!mWifiNative.setNetworkVariable( 2224 netId, 2225 key, 2226 value)) { 2227 removeKeys(enterpriseConfig); 2228 loge(config.SSID + ": failed to set " + key + 2229 ": " + value); 2230 break setVariables; 2231 } 2232 } 2233 } 2234 updateFailed = false; 2235 } //end of setVariables 2236 2237 if (updateFailed) { 2238 if (newNetwork) { 2239 mWifiNative.removeNetwork(netId); 2240 loge("Failed to set a network variable, removed network: " + netId); 2241 } 2242 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2243 } 2244 2245 /* An update of the network variables requires reading them 2246 * back from the supplicant to update mConfiguredNetworks. 2247 * This is because some of the variables (SSID, wep keys & 2248 * passphrases) reflect different values when read back than 2249 * when written. For example, wep key is stored as * irrespective 2250 * of the value sent to the supplicant 2251 */ 2252 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 2253 if (currentConfig == null) { 2254 currentConfig = new WifiConfiguration(); 2255 currentConfig.setIpAssignment(IpAssignment.DHCP); 2256 currentConfig.setProxySettings(ProxySettings.NONE); 2257 currentConfig.networkId = netId; 2258 if (config != null) { 2259 //carry over the creation parameters 2260 currentConfig.selfAdded = config.selfAdded; 2261 currentConfig.didSelfAdd = config.didSelfAdd; 2262 currentConfig.lastConnectUid = config.lastConnectUid; 2263 currentConfig.lastUpdateUid = config.lastUpdateUid; 2264 currentConfig.creatorUid = config.creatorUid; 2265 currentConfig.peerWifiConfiguration = config.peerWifiConfiguration; 2266 } 2267 if (DBG) { 2268 loge("created new config netId=" + Integer.toString(netId) 2269 + " uid=" + Integer.toString(currentConfig.creatorUid)); 2270 } 2271 } 2272 2273 if (currentConfig.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { 2274 //make sure the configuration is not deleted anymore since we just 2275 //added or modified it. 2276 currentConfig.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 2277 currentConfig.selfAdded = false; 2278 currentConfig.didSelfAdd = false; 2279 } 2280 2281 if (DBG) loge("will read network variables netId=" + Integer.toString(netId)); 2282 2283 readNetworkVariables(currentConfig); 2284 2285 mConfiguredNetworks.put(netId, currentConfig); 2286 mNetworkIds.put(configKey(currentConfig), netId); 2287 2288 NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); 2289 result.setIsNewNetwork(newNetwork); 2290 result.setNetworkId(netId); 2291 return result; 2292 } 2293 2294 2295 public void linkConfiguration(WifiConfiguration config) { 2296 if (config.scanResultCache != null && config.scanResultCache.size() > 6) { 2297 // Ignore configurations with large number of BSSIDs 2298 return; 2299 } 2300 if (!config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 2301 // Only link WPA_PSK config 2302 return; 2303 } 2304 for (WifiConfiguration link : mConfiguredNetworks.values()) { 2305 boolean doLink = false; 2306 2307 if (link.configKey().equals(config.configKey())) { 2308 continue; 2309 } 2310 2311 if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { 2312 continue; 2313 } 2314 2315 // Autojoin will be allowed to dynamically jump from a linked configuration 2316 // to another, hence only link configurations that have equivalent level of security 2317 if (!link.allowedKeyManagement.equals(config.allowedKeyManagement)) { 2318 continue; 2319 } 2320 2321 if (link.scanResultCache != null && link.scanResultCache.size() > 6) { 2322 // Ignore configurations with large number of BSSIDs 2323 continue; 2324 } 2325 2326 if (config.defaultGwMacAddress != null && link.defaultGwMacAddress != null) { 2327 // If both default GW are known, compare based on RSSI only if the GW is equal 2328 if (config.defaultGwMacAddress.equals(link.defaultGwMacAddress)) { 2329 if (VDBG) { 2330 loge("linkConfiguration link due to same gw" + link.SSID + 2331 " and " + config.SSID + " GW " + config.defaultGwMacAddress); 2332 } 2333 doLink = true; 2334 } 2335 } else { 2336 // We do not know BOTH default gateways hence we will try to link 2337 // hoping that WifiConfigurations are indeed behind the same gateway. 2338 // once both WifiConfiguration have been tried and thus once both efault gateways 2339 // are known we will revisit the choice of linking them 2340 if ((config.scanResultCache != null) && (config.scanResultCache.size() <= 6) 2341 && (link.scanResultCache != null) && (link.scanResultCache.size() <= 6)) { 2342 for (String abssid : config.scanResultCache.keySet()) { 2343 for (String bbssid : link.scanResultCache.keySet()) { 2344 if (VDBG) { 2345 loge("linkConfiguration try to link due to DBDC BSSID match " 2346 + link.SSID + 2347 " and " + config.SSID + " bssida " + abssid 2348 + " bssidb " + bbssid); 2349 } 2350 if (abssid.regionMatches(true, 0, bbssid, 0, 16)) { 2351 // If first 16 ascii characters of BSSID matches, 2352 // we assume this is a DBDC 2353 doLink = true; 2354 } 2355 } 2356 } 2357 } 2358 } 2359 2360 if (doLink) { 2361 if (VDBG) { 2362 loge("linkConfiguration: will link " + link.SSID + " and " + config.SSID); 2363 } 2364 if (link.linkedConfigurations == null) { 2365 link.linkedConfigurations = new HashMap<String, Integer>(); 2366 } 2367 if (config.linkedConfigurations == null) { 2368 config.linkedConfigurations = new HashMap<String, Integer>(); 2369 } 2370 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 2371 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 2372 } else { 2373 //todo if they are linked, break the link 2374 } 2375 } 2376 } 2377 2378 /* 2379 * We try to link a scan result with a WifiConfiguration for which SSID and 2380 * key management dont match, 2381 * for instance, we try identify the 5GHz SSID of a DBDC AP, 2382 * even though we know only of the 2.4GHz 2383 * 2384 * Obviously, this function is not optimal since it is used to compare every scan 2385 * result with every Saved WifiConfiguration, with a string.equals operation. 2386 * As a speed up, might be better to implement the mConfiguredNetworks store as a 2387 * <String, WifiConfiguration> object instead of a <Integer, WifiConfiguration> object 2388 * so as to speed this up. Also to prevent the tiny probability of hash collision. 2389 * 2390 */ 2391 public WifiConfiguration associateWithConfiguration(ScanResult result) { 2392 String configKey = WifiConfiguration.configKey(result); 2393 if (configKey == null) { 2394 if (DBG) loge("associateWithConfiguration(): no config key " ); 2395 return null; 2396 } 2397 2398 //need to compare with quoted string 2399 String SSID = "\"" + result.SSID + "\""; 2400 2401 WifiConfiguration config = null; 2402 for (WifiConfiguration link : mConfiguredNetworks.values()) { 2403 boolean doLink = false; 2404 2405 if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.didSelfAdd) { 2406 //make sure we dont associate the scan result to a deleted config 2407 continue; 2408 } 2409 2410 if (configKey.equals(link.configKey())) { 2411 if (VDBG) loge("associateWithConfiguration(): found it!!! " + configKey ); 2412 return link; //found it exactly 2413 } 2414 2415 if ((link.scanResultCache != null) && (link.scanResultCache.size() <= 4)) { 2416 String bssid = ""; 2417 for (String key : link.scanResultCache.keySet()) { 2418 bssid = key; 2419 } 2420 2421 if (result.BSSID.regionMatches(true, 0, bssid, 0, 16) 2422 && SSID.regionMatches(false, 0, link.SSID, 0, 3)) { 2423 // if first 16 ascii characters of BSSID matches, and first 3 2424 // characters of SSID match, we assume this is a home setup 2425 // and thus we will try to transfer the password from the known 2426 // BSSID/SSID to the recently found BSSID/SSID 2427 2428 //if (VDBG) 2429 // loge("associateWithConfiguration OK " ); 2430 doLink = true; 2431 } 2432 } 2433 2434 if (doLink) { 2435 //try to make a non verified WifiConfiguration, but only if the original 2436 //configuration was not self already added 2437 if (VDBG) { 2438 loge("associateWithConfiguration: will create " + 2439 result.SSID + " and associate it with: " + link.SSID); 2440 } 2441 config = wifiConfigurationFromScanResult(result); 2442 if (config != null) { 2443 config.selfAdded = true; 2444 config.didSelfAdd = true; 2445 config.peerWifiConfiguration = link.configKey(); 2446 if (config.allowedKeyManagement.equals(link.allowedKeyManagement) && 2447 config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 2448 //transfer the credentials from the configuration we are linking from 2449 String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); 2450 if (psk != null) { 2451 config.preSharedKey = psk; 2452 if (VDBG) { 2453 if (config.preSharedKey != null) 2454 loge(" transfer PSK : " + config.preSharedKey); 2455 } 2456 2457 //link configurations 2458 if (link.linkedConfigurations == null) { 2459 link.linkedConfigurations = new HashMap<String, Integer>(); 2460 } 2461 if (config.linkedConfigurations == null) { 2462 config.linkedConfigurations = new HashMap<String, Integer>(); 2463 } 2464 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 2465 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 2466 } else { 2467 config = null; 2468 } 2469 } else { 2470 config = null; 2471 } 2472 } 2473 } else { 2474 //todo if they are linked, break the link 2475 } 2476 } 2477 return config; 2478 } 2479 2480 public HashSet<Integer> makeChannelList(WifiConfiguration config, int age, boolean restrict) { 2481 if (config == null) 2482 return null; 2483 long now_ms = System.currentTimeMillis(); 2484 2485 HashSet<Integer> channels = new HashSet<Integer>(); 2486 2487 //get channels for this configuration, if there are at least 2 BSSIDs 2488 if (config.scanResultCache == null && config.linkedConfigurations == null) { 2489 return null; 2490 } 2491 2492 if (VDBG) { 2493 StringBuilder dbg = new StringBuilder(); 2494 dbg.append("makeChannelList age=" + Integer.toString(age) 2495 + " for " + config.configKey()); 2496 if (config.scanResultCache != null) { 2497 dbg.append(" bssids=" + config.scanResultCache.size()); 2498 } 2499 if (config.linkedConfigurations != null) { 2500 dbg.append(" linked=" + config.linkedConfigurations.size()); 2501 } 2502 loge(dbg.toString()); 2503 } 2504 2505 if (config.scanResultCache != null && config.scanResultCache.size() > 0) { 2506 for (ScanResult result : config.scanResultCache.values()) { 2507 if (VDBG) { 2508 boolean test = (now_ms - result.seen) < age; 2509 loge("has " + result.BSSID + " freq=" + Integer.toString(result.frequency) 2510 + " age=" + Long.toString(now_ms - result.seen) + " ?=" + test); 2511 } 2512 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 2513 channels.add(result.frequency); 2514 } 2515 } 2516 } 2517 2518 //get channels for linked configurations 2519 if (config.linkedConfigurations != null) { 2520 for (String key : config.linkedConfigurations.keySet()) { 2521 WifiConfiguration linked = getWifiConfiguration(key); 2522 if (linked == null) 2523 continue; 2524 if (linked.scanResultCache == null) { 2525 continue; 2526 } 2527 for (ScanResult result : linked.scanResultCache.values()) { 2528 if (VDBG) { 2529 loge("has link: " + result.BSSID 2530 + " freq=" + Integer.toString(result.frequency) 2531 + " age=" + Long.toString(now_ms - result.seen)); 2532 } 2533 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 2534 channels.add(result.frequency); 2535 } 2536 } 2537 } 2538 } 2539 return channels; 2540 } 2541 2542 public WifiConfiguration updateSavedNetworkHistory(ScanResult scanResult) { 2543 WifiConfiguration found = null; 2544 if (scanResult == null) 2545 return found; 2546 2547 //first step, look for this scan Result by SSID + Key Management 2548 String key = WifiConfiguration.configKey(scanResult); 2549 int hash = key.hashCode(); 2550 2551 Integer netId = mNetworkIds.get(hash); 2552 if (netId == null) return null; 2553 WifiConfiguration config = mConfiguredNetworks.get(netId); 2554 if (config != null) { 2555 if (config.scanResultCache == null) { 2556 config.scanResultCache = new HashMap<String, ScanResult>(); 2557 } 2558 if (config.scanResultCache == null) { 2559 return null; 2560 } 2561 //add the scan result to this WifiConfiguration 2562 config.scanResultCache.put(scanResult.BSSID, scanResult); 2563 mConfiguredNetworks.put(netId, config); 2564 linkConfiguration(config); 2565 found = config; 2566 } 2567 2568 if (VDBG) { 2569 config = mConfiguredNetworks.get(netId); 2570 if (config != null) { 2571 if (config.scanResultCache != null) { 2572 String status = ""; 2573 if (scanResult.status > 0) { 2574 status = " status=" + Integer.toString(scanResult.status); 2575 } 2576 loge(" got known scan result " + 2577 scanResult.BSSID + " key : " + key + " num: " + 2578 Integer.toString(config.scanResultCache.size()) 2579 + " rssi=" + Integer.toString(scanResult.level) 2580 + " freq=" + Integer.toString(scanResult.frequency) 2581 + status); 2582 } else { 2583 loge(" got known scan result and no cache" + 2584 scanResult.BSSID + " key : " + key); 2585 } 2586 } 2587 } 2588 return found; 2589 2590 } 2591 2592 /* Compare current and new configuration and write to file on change */ 2593 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 2594 WifiConfiguration currentConfig, 2595 WifiConfiguration newConfig) { 2596 boolean ipChanged = false; 2597 boolean proxyChanged = false; 2598 LinkProperties linkProperties = null; 2599 2600 if (VDBG) { 2601 loge("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " + 2602 newConfig.SSID + " path: " + ipConfigFile); 2603 } 2604 2605 2606 switch (newConfig.getIpAssignment()) { 2607 case STATIC: 2608 Collection<LinkAddress> currentLinkAddresses = currentConfig.getLinkProperties() 2609 .getLinkAddresses(); 2610 Collection<LinkAddress> newLinkAddresses = newConfig.getLinkProperties() 2611 .getLinkAddresses(); 2612 Collection<InetAddress> currentDnses = 2613 currentConfig.getLinkProperties().getDnsServers(); 2614 Collection<InetAddress> newDnses = newConfig.getLinkProperties().getDnsServers(); 2615 Collection<RouteInfo> currentRoutes = currentConfig.getLinkProperties().getRoutes(); 2616 Collection<RouteInfo> newRoutes = newConfig.getLinkProperties().getRoutes(); 2617 2618 boolean linkAddressesDiffer = 2619 (currentLinkAddresses.size() != newLinkAddresses.size()) || 2620 !currentLinkAddresses.containsAll(newLinkAddresses); 2621 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || 2622 !currentDnses.containsAll(newDnses); 2623 boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || 2624 !currentRoutes.containsAll(newRoutes); 2625 2626 if ((currentConfig.getIpAssignment() != newConfig.getIpAssignment()) || 2627 linkAddressesDiffer || 2628 dnsesDiffer || 2629 routesDiffer) { 2630 ipChanged = true; 2631 } 2632 break; 2633 case DHCP: 2634 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 2635 ipChanged = true; 2636 } 2637 break; 2638 case UNASSIGNED: 2639 /* Ignore */ 2640 break; 2641 default: 2642 loge("Ignore invalid ip assignment during write"); 2643 break; 2644 } 2645 2646 switch (newConfig.getProxySettings()) { 2647 case STATIC: 2648 case PAC: 2649 ProxyInfo newHttpProxy = newConfig.getLinkProperties().getHttpProxy(); 2650 ProxyInfo currentHttpProxy = currentConfig.getLinkProperties().getHttpProxy(); 2651 2652 if (newHttpProxy != null) { 2653 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 2654 } else { 2655 proxyChanged = (currentHttpProxy != null); 2656 } 2657 break; 2658 case NONE: 2659 if (currentConfig.getProxySettings() != newConfig.getProxySettings()) { 2660 proxyChanged = true; 2661 } 2662 break; 2663 case UNASSIGNED: 2664 /* Ignore */ 2665 break; 2666 default: 2667 loge("Ignore invalid proxy configuration during write"); 2668 break; 2669 } 2670 2671 if (!ipChanged) { 2672 linkProperties = copyIpSettingsFromConfig(currentConfig); 2673 } else { 2674 currentConfig.setIpAssignment(newConfig.getIpAssignment()); 2675 linkProperties = copyIpSettingsFromConfig(newConfig); 2676 log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " + 2677 linkProperties.toString()); 2678 } 2679 2680 2681 if (!proxyChanged) { 2682 linkProperties.setHttpProxy(currentConfig.getLinkProperties().getHttpProxy()); 2683 } else { 2684 currentConfig.setProxySettings(newConfig.getProxySettings()); 2685 linkProperties.setHttpProxy(newConfig.getLinkProperties().getHttpProxy()); 2686 log("proxy changed SSID = " + currentConfig.SSID); 2687 if (linkProperties.getHttpProxy() != null) { 2688 log(" proxyProperties: " + linkProperties.getHttpProxy().toString()); 2689 } 2690 } 2691 2692 if (ipChanged || proxyChanged) { 2693 currentConfig.setLinkProperties(linkProperties); 2694 writeIpAndProxyConfigurations(); 2695 sendConfiguredNetworksChangedBroadcast(currentConfig, 2696 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 2697 } 2698 return new NetworkUpdateResult(ipChanged, proxyChanged); 2699 } 2700 2701 private LinkProperties copyIpSettingsFromConfig(WifiConfiguration config) { 2702 LinkProperties linkProperties = new LinkProperties(); 2703 linkProperties.setInterfaceName(config.getLinkProperties().getInterfaceName()); 2704 for (LinkAddress linkAddr : config.getLinkProperties().getLinkAddresses()) { 2705 linkProperties.addLinkAddress(linkAddr); 2706 } 2707 for (RouteInfo route : config.getLinkProperties().getRoutes()) { 2708 linkProperties.addRoute(route); 2709 } 2710 for (InetAddress dns : config.getLinkProperties().getDnsServers()) { 2711 linkProperties.addDnsServer(dns); 2712 } 2713 return linkProperties; 2714 } 2715 2716 /** Returns true if a particular config key needs to be quoted when passed to the supplicant. */ 2717 private boolean enterpriseConfigKeyShouldBeQuoted(String key) { 2718 switch (key) { 2719 case WifiEnterpriseConfig.EAP_KEY: 2720 case WifiEnterpriseConfig.ENGINE_KEY: 2721 return false; 2722 default: 2723 return true; 2724 } 2725 } 2726 2727 /** 2728 * Read the variables from the supplicant daemon that are needed to 2729 * fill in the WifiConfiguration object. 2730 * 2731 * @param config the {@link WifiConfiguration} object to be filled in. 2732 */ 2733 private void readNetworkVariables(WifiConfiguration config) { 2734 2735 int netId = config.networkId; 2736 if (netId < 0) 2737 return; 2738 2739 /* 2740 * TODO: maybe should have a native method that takes an array of 2741 * variable names and returns an array of values. But we'd still 2742 * be doing a round trip to the supplicant daemon for each variable. 2743 */ 2744 String value; 2745 2746 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 2747 if (!TextUtils.isEmpty(value)) { 2748 if (value.charAt(0) != '"') { 2749 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 2750 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 2751 //supplicant string 2752 } else { 2753 config.SSID = value; 2754 } 2755 } else { 2756 config.SSID = null; 2757 } 2758 2759 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 2760 if (!TextUtils.isEmpty(value)) { 2761 config.BSSID = value; 2762 } else { 2763 config.BSSID = null; 2764 } 2765 2766 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 2767 config.priority = -1; 2768 if (!TextUtils.isEmpty(value)) { 2769 try { 2770 config.priority = Integer.parseInt(value); 2771 } catch (NumberFormatException ignore) { 2772 } 2773 } 2774 2775 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 2776 config.hiddenSSID = false; 2777 if (!TextUtils.isEmpty(value)) { 2778 try { 2779 config.hiddenSSID = Integer.parseInt(value) != 0; 2780 } catch (NumberFormatException ignore) { 2781 } 2782 } 2783 2784 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 2785 config.wepTxKeyIndex = -1; 2786 if (!TextUtils.isEmpty(value)) { 2787 try { 2788 config.wepTxKeyIndex = Integer.parseInt(value); 2789 } catch (NumberFormatException ignore) { 2790 } 2791 } 2792 2793 for (int i = 0; i < 4; i++) { 2794 value = mWifiNative.getNetworkVariable(netId, 2795 WifiConfiguration.wepKeyVarNames[i]); 2796 if (!TextUtils.isEmpty(value)) { 2797 config.wepKeys[i] = value; 2798 } else { 2799 config.wepKeys[i] = null; 2800 } 2801 } 2802 2803 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 2804 if (!TextUtils.isEmpty(value)) { 2805 config.preSharedKey = value; 2806 } else { 2807 config.preSharedKey = null; 2808 } 2809 2810 value = mWifiNative.getNetworkVariable(config.networkId, 2811 WifiConfiguration.Protocol.varName); 2812 if (!TextUtils.isEmpty(value)) { 2813 String vals[] = value.split(" "); 2814 for (String val : vals) { 2815 int index = 2816 lookupString(val, WifiConfiguration.Protocol.strings); 2817 if (0 <= index) { 2818 config.allowedProtocols.set(index); 2819 } 2820 } 2821 } 2822 2823 value = mWifiNative.getNetworkVariable(config.networkId, 2824 WifiConfiguration.KeyMgmt.varName); 2825 if (!TextUtils.isEmpty(value)) { 2826 String vals[] = value.split(" "); 2827 for (String val : vals) { 2828 int index = 2829 lookupString(val, WifiConfiguration.KeyMgmt.strings); 2830 if (0 <= index) { 2831 config.allowedKeyManagement.set(index); 2832 } 2833 } 2834 } 2835 2836 value = mWifiNative.getNetworkVariable(config.networkId, 2837 WifiConfiguration.AuthAlgorithm.varName); 2838 if (!TextUtils.isEmpty(value)) { 2839 String vals[] = value.split(" "); 2840 for (String val : vals) { 2841 int index = 2842 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 2843 if (0 <= index) { 2844 config.allowedAuthAlgorithms.set(index); 2845 } 2846 } 2847 } 2848 2849 value = mWifiNative.getNetworkVariable(config.networkId, 2850 WifiConfiguration.PairwiseCipher.varName); 2851 if (!TextUtils.isEmpty(value)) { 2852 String vals[] = value.split(" "); 2853 for (String val : vals) { 2854 int index = 2855 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 2856 if (0 <= index) { 2857 config.allowedPairwiseCiphers.set(index); 2858 } 2859 } 2860 } 2861 2862 value = mWifiNative.getNetworkVariable(config.networkId, 2863 WifiConfiguration.GroupCipher.varName); 2864 if (!TextUtils.isEmpty(value)) { 2865 String vals[] = value.split(" "); 2866 for (String val : vals) { 2867 int index = 2868 lookupString(val, WifiConfiguration.GroupCipher.strings); 2869 if (0 <= index) { 2870 config.allowedGroupCiphers.set(index); 2871 } 2872 } 2873 } 2874 2875 if (config.enterpriseConfig == null) { 2876 config.enterpriseConfig = new WifiEnterpriseConfig(); 2877 } 2878 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 2879 for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { 2880 value = mWifiNative.getNetworkVariable(netId, key); 2881 if (!TextUtils.isEmpty(value)) { 2882 if (!enterpriseConfigKeyShouldBeQuoted(key)) { 2883 value = removeDoubleQuotes(value); 2884 } 2885 enterpriseFields.put(key, value); 2886 } else { 2887 enterpriseFields.put(key, EMPTY_VALUE); 2888 } 2889 } 2890 2891 if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { 2892 saveConfig(); 2893 } 2894 2895 migrateCerts(config.enterpriseConfig); 2896 // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); 2897 } 2898 2899 private static String removeDoubleQuotes(String string) { 2900 int length = string.length(); 2901 if ((length > 1) && (string.charAt(0) == '"') 2902 && (string.charAt(length - 1) == '"')) { 2903 return string.substring(1, length - 1); 2904 } 2905 return string; 2906 } 2907 2908 private static String makeString(BitSet set, String[] strings) { 2909 StringBuffer buf = new StringBuffer(); 2910 int nextSetBit = -1; 2911 2912 /* Make sure all set bits are in [0, strings.length) to avoid 2913 * going out of bounds on strings. (Shouldn't happen, but...) */ 2914 set = set.get(0, strings.length); 2915 2916 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 2917 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 2918 } 2919 2920 // remove trailing space 2921 if (set.cardinality() > 0) { 2922 buf.setLength(buf.length() - 1); 2923 } 2924 2925 return buf.toString(); 2926 } 2927 2928 private int lookupString(String string, String[] strings) { 2929 int size = strings.length; 2930 2931 string = string.replace('-', '_'); 2932 2933 for (int i = 0; i < size; i++) 2934 if (string.equals(strings[i])) 2935 return i; 2936 2937 // if we ever get here, we should probably add the 2938 // value to WifiConfiguration to reflect that it's 2939 // supported by the WPA supplicant 2940 loge("Failed to look-up a string: " + string); 2941 2942 return -1; 2943 } 2944 2945 /* return the allowed key management based on a scan result */ 2946 2947 public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) { 2948 WifiConfiguration config = new WifiConfiguration(); 2949 2950 config.SSID = "\"" + result.SSID + "\""; 2951 2952 if (VDBG) { 2953 loge("WifiConfiguration from scan results " + 2954 config.SSID + " cap " + result.capabilities); 2955 } 2956 if (result.capabilities.contains("WEP")) { 2957 config.allowedKeyManagement.set(KeyMgmt.NONE); 2958 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); //? 2959 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 2960 } 2961 2962 if (result.capabilities.contains("PSK")) { 2963 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 2964 } 2965 2966 if (result.capabilities.contains("EAP")) { 2967 //this is probably wrong, as we don't have a way to enter the enterprise config 2968 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 2969 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 2970 } 2971 2972 config.scanResultCache = new HashMap<String, ScanResult>(); 2973 if (config.scanResultCache == null) 2974 return null; 2975 config.scanResultCache.put(result.BSSID, result); 2976 2977 return config; 2978 } 2979 2980 2981 /* Returns a unique for a given configuration */ 2982 private static int configKey(WifiConfiguration config) { 2983 String key = config.configKey(); 2984 return key.hashCode(); 2985 } 2986 2987 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2988 pw.println("WifiConfigStore"); 2989 pw.println("mLastPriority " + mLastPriority); 2990 pw.println("Configured networks"); 2991 for (WifiConfiguration conf : getConfiguredNetworks()) { 2992 pw.println(conf); 2993 } 2994 pw.println(); 2995 2996 if (mLocalLog != null) { 2997 pw.println("WifiConfigStore - Log Begin ----"); 2998 mLocalLog.dump(fd, pw, args); 2999 pw.println("WifiConfigStore - Log End ----"); 3000 } 3001 } 3002 3003 public String getConfigFile() { 3004 return ipConfigFile; 3005 } 3006 3007 protected void loge(String s) { 3008 loge(s, false); 3009 } 3010 3011 protected void loge(String s, boolean stack) { 3012 if (stack) { 3013 Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3014 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 3015 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 3016 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 3017 } else { 3018 Log.e(TAG, s); 3019 } 3020 } 3021 3022 protected void log(String s) { 3023 Log.d(TAG, s); 3024 } 3025 3026 private void localLog(String s) { 3027 if (mLocalLog != null) { 3028 mLocalLog.log(s); 3029 } 3030 } 3031 3032 private void localLog(String s, int netId) { 3033 if (mLocalLog == null) { 3034 return; 3035 } 3036 3037 WifiConfiguration config; 3038 synchronized(mConfiguredNetworks) { 3039 config = mConfiguredNetworks.get(netId); 3040 } 3041 3042 if (config != null) { 3043 mLocalLog.log(s + " " + config.getPrintableSsid()); 3044 } else { 3045 mLocalLog.log(s + " " + netId); 3046 } 3047 } 3048 3049 // Certificate and private key management for EnterpriseConfig 3050 static boolean needsKeyStore(WifiEnterpriseConfig config) { 3051 // Has no keys to be installed 3052 if (config.getClientCertificate() == null && config.getCaCertificate() == null) 3053 return false; 3054 return true; 3055 } 3056 3057 static boolean isHardwareBackedKey(PrivateKey key) { 3058 return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 3059 } 3060 3061 static boolean hasHardwareBackedKey(Certificate certificate) { 3062 return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 3063 } 3064 3065 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 3066 String client = config.getClientCertificateAlias(); 3067 if (!TextUtils.isEmpty(client)) { 3068 // a valid client certificate is configured 3069 3070 // BUGBUG: keyStore.get() never returns certBytes; because it is not 3071 // taking WIFI_UID as a parameter. It always looks for certificate 3072 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 3073 // all certificates need software keystore until we get the get() API 3074 // fixed. 3075 3076 return true; 3077 } 3078 3079 /* 3080 try { 3081 3082 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 3083 .USER_CERTIFICATE + client); 3084 3085 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 3086 if (factory == null) { 3087 Slog.e(TAG, "Error getting certificate factory"); 3088 return; 3089 } 3090 3091 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 3092 if (certBytes != null) { 3093 Certificate cert = (X509Certificate) factory.generateCertificate( 3094 new ByteArrayInputStream(certBytes)); 3095 3096 if (cert != null) { 3097 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 3098 3099 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 3100 .USER_CERTIFICATE + client); 3101 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 3102 "does not need" ) + " software key store"); 3103 } else { 3104 Slog.d(TAG, "could not generate certificate"); 3105 } 3106 } else { 3107 Slog.e(TAG, "Could not load client certificate " + Credentials 3108 .USER_CERTIFICATE + client); 3109 mNeedsSoftwareKeystore = true; 3110 } 3111 3112 } catch(CertificateException e) { 3113 Slog.e(TAG, "Could not read certificates"); 3114 mCaCert = null; 3115 mClientCertificate = null; 3116 } 3117 */ 3118 3119 return false; 3120 } 3121 3122 /** called when CS ask WiFistateMachine to disconnect the current network 3123 * because the score is bad. 3124 */ 3125 void handleBadNetworkDisconnectReport(int netId, WifiInfo info) { 3126 /* TODO verify the bad network is current */ 3127 WifiConfiguration config = mConfiguredNetworks.get(netId); 3128 if (config != null) { 3129 if ((info.getRssi() < WifiConfiguration.UNWANTED_BLACKLIST_SOFT_RSSI_24 3130 && info.is24GHz()) || (info.getRssi() < 3131 WifiConfiguration.UNWANTED_BLACKLIST_SOFT_RSSI_5 && info.is5GHz())) { 3132 //we got disconnected and RSSI was bad, so disable light 3133 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED 3134 + WifiConfiguration.UNWANTED_BLACKLIST_SOFT_BUMP); 3135 loge("handleBadNetworkDisconnectReport (+4) " 3136 + Integer.toString(netId) + " " + info); 3137 } else { 3138 //we got disabled but RSSI is good, so disable hard 3139 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED 3140 + WifiConfiguration.UNWANTED_BLACKLIST_HARD_BUMP); 3141 loge("handleBadNetworkDisconnectReport (+8) " 3142 + Integer.toString(netId) + " " + info); 3143 } 3144 } 3145 } 3146 3147 boolean handleBSSIDBlackList(int netId, String BSSID, boolean enable) { 3148 boolean found = false; 3149 if (BSSID == null) 3150 return found; 3151 3152 // Look for the BSSID in our config store 3153 for (WifiConfiguration config : mConfiguredNetworks.values()) { 3154 if (config.scanResultCache != null) { 3155 for (ScanResult result: config.scanResultCache.values()) { 3156 if (result.BSSID.equals(BSSID)) { 3157 if (enable) { 3158 result.status = ScanResult.ENABLED; 3159 } else { 3160 // Black list the BSSID we we were trying to join 3161 // so as the Roam state machine 3162 // doesn't pick it up over and over 3163 result.status = ScanResult.AUTO_ROAM_DISABLED; 3164 found = true; 3165 } 3166 } 3167 } 3168 } 3169 } 3170 return found; 3171 } 3172 3173 int getMaxDhcpRetries() { 3174 return Settings.Global.getInt(mContext.getContentResolver(), 3175 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 3176 DEFAULT_MAX_DHCP_RETRIES); 3177 } 3178 3179 void handleSSIDStateChange(int netId, boolean enabled, String message) { 3180 WifiConfiguration config = mConfiguredNetworks.get(netId); 3181 if (config != null) { 3182 if (enabled) { 3183 loge("SSID re-enabled for " + config.configKey() + 3184 " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus) 3185 + " self added " + config.selfAdded + " ephemeral " + config.ephemeral); 3186 //TODO: http://b/16381983 Fix Wifi Network Blacklisting 3187 //TODO: really I don't know if re-enabling is right but we 3188 //TODO: should err on the side of trying to connect 3189 //TODO: even if the attempt will fail 3190 if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { 3191 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 3192 } 3193 } else { 3194 loge("SSID temp disabled for " + config.configKey() + 3195 " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus) 3196 + " self added " + config.selfAdded + " ephemeral " + config.ephemeral); 3197 if (message != null) { 3198 loge(" message=" + message); 3199 } 3200 if (config.selfAdded && config.lastConnected == 0) { 3201 // This is a network we self added, and we never succeeded, 3202 // the user did not create this network and never entered its credentials, 3203 // so we want to be very aggressive in disabling it completely. 3204 disableNetwork(config.networkId, WifiConfiguration.DISABLED_AUTH_FAILURE); 3205 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); 3206 config.disableReason = WifiConfiguration.DISABLED_AUTH_FAILURE; 3207 } else { 3208 if (message != null) { 3209 if (message.contains("WRONG_KEY") 3210 || message.contains("AUTH_FAILED")) { 3211 // This configuration has received an auth failure, so disable it 3212 // temporarily because we don't want auto-join to try it out. 3213 // this network may be re-enabled by the "usual" 3214 // enableAllNetwork function 3215 //TODO: resolve interpretation of WRONG_KEY and AUTH_FAILURE: 3216 //TODO: if we could count on the wrong_ley or auth_failure 3217 //TODO: message to be correct 3218 //TODO: then we could just mark the configuration as 3219 //TODO: DISABLED_ON_AUTH_FAILURE 3220 //TODO: and the configuration will stay there until 3221 //TODO: user enter new credentials 3222 //TODO: It is not the case however, so instead of disabling, let's 3223 //TODO: start blacklisting hard 3224 //TODO: http://b/16381983 Fix Wifi Network Blacklisting 3225 if (config.autoJoinStatus <= 3226 WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { 3227 // 4 auth failure will reach 128 and disable permanently 3228 // autoJoinStatus: 0 -> 4 -> 20 -> 84 -> 128 3229 config.setAutoJoinStatus(4 + config.autoJoinStatus * 4); 3230 if (config.autoJoinStatus > 3231 WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) 3232 config.setAutoJoinStatus 3233 (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); 3234 } 3235 if (DBG) { 3236 loge("blacklisted " + config.configKey() + " to " 3237 + Integer.toString(config.autoJoinStatus)); 3238 } 3239 } else if (message.contains("DHCP FAILURE")) { 3240 config.numConnectionFailures++; 3241 config.lastConnectionFailure = System.currentTimeMillis(); 3242 int maxRetries = getMaxDhcpRetries(); 3243 // maxRetries == 0 means keep trying forever 3244 if (maxRetries > 0 && config.numConnectionFailures > maxRetries) { 3245 /** 3246 * If we've exceeded the maximum number of retries for DHCP 3247 * to a given network, disable the network 3248 */ 3249 config.setAutoJoinStatus 3250 (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); 3251 disableNetwork(netId, WifiConfiguration.DISABLED_DHCP_FAILURE); 3252 } 3253 if (DBG) { 3254 loge("blacklisted " + config.configKey() + " to " 3255 + config.autoJoinStatus 3256 + " due to DHCP failure, count=" 3257 + config.numConnectionFailures); 3258 } 3259 } 3260 message.replace("\n", ""); 3261 message.replace("\r", ""); 3262 config.lastFailure = message; 3263 } 3264 } 3265 } 3266 } 3267 } 3268 3269 boolean installKeys(WifiEnterpriseConfig config, String name) { 3270 boolean ret = true; 3271 String privKeyName = Credentials.USER_PRIVATE_KEY + name; 3272 String userCertName = Credentials.USER_CERTIFICATE + name; 3273 String caCertName = Credentials.CA_CERTIFICATE + name; 3274 if (config.getClientCertificate() != null) { 3275 byte[] privKeyData = config.getClientPrivateKey().getEncoded(); 3276 if (isHardwareBackedKey(config.getClientPrivateKey())) { 3277 // Hardware backed key store is secure enough to store keys un-encrypted, this 3278 // removes the need for user to punch a PIN to get access to these keys 3279 if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); 3280 ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, 3281 KeyStore.FLAG_NONE); 3282 } else { 3283 // Software backed key store is NOT secure enough to store keys un-encrypted. 3284 // Save keys encrypted so they are protected with user's PIN. User will 3285 // have to unlock phone before being able to use these keys and connect to 3286 // networks. 3287 if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); 3288 ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 3289 KeyStore.FLAG_ENCRYPTED); 3290 } 3291 if (ret == false) { 3292 return ret; 3293 } 3294 3295 ret = putCertInKeyStore(userCertName, config.getClientCertificate()); 3296 if (ret == false) { 3297 // Remove private key installed 3298 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 3299 return ret; 3300 } 3301 } 3302 3303 if (config.getCaCertificate() != null) { 3304 ret = putCertInKeyStore(caCertName, config.getCaCertificate()); 3305 if (ret == false) { 3306 if (config.getClientCertificate() != null) { 3307 // Remove client key+cert 3308 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 3309 mKeyStore.delete(userCertName, Process.WIFI_UID); 3310 } 3311 return ret; 3312 } 3313 } 3314 3315 // Set alias names 3316 if (config.getClientCertificate() != null) { 3317 config.setClientCertificateAlias(name); 3318 config.resetClientKeyEntry(); 3319 } 3320 3321 if (config.getCaCertificate() != null) { 3322 config.setCaCertificateAlias(name); 3323 config.resetCaCertificate(); 3324 } 3325 3326 return ret; 3327 } 3328 3329 private boolean putCertInKeyStore(String name, Certificate cert) { 3330 try { 3331 byte[] certData = Credentials.convertToPem(cert); 3332 if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); 3333 return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 3334 3335 } catch (IOException e1) { 3336 return false; 3337 } catch (CertificateException e2) { 3338 return false; 3339 } 3340 } 3341 3342 void removeKeys(WifiEnterpriseConfig config) { 3343 String client = config.getClientCertificateAlias(); 3344 // a valid client certificate is configured 3345 if (!TextUtils.isEmpty(client)) { 3346 if (DBG) Log.d(TAG, "removing client private key and user cert"); 3347 mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 3348 mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 3349 } 3350 3351 String ca = config.getCaCertificateAlias(); 3352 // a valid ca certificate is configured 3353 if (!TextUtils.isEmpty(ca)) { 3354 if (DBG) Log.d(TAG, "removing CA cert"); 3355 mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 3356 } 3357 } 3358 3359 3360 /** Migrates the old style TLS config to the new config style. This should only be used 3361 * when restoring an old wpa_supplicant.conf or upgrading from a previous 3362 * platform version. 3363 * @return true if the config was updated 3364 * @hide 3365 */ 3366 boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { 3367 String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 3368 /* 3369 * If the old configuration value is not present, then there is nothing 3370 * to do. 3371 */ 3372 if (TextUtils.isEmpty(oldPrivateKey)) { 3373 return false; 3374 } else { 3375 // Also ignore it if it's empty quotes. 3376 oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 3377 if (TextUtils.isEmpty(oldPrivateKey)) { 3378 return false; 3379 } 3380 } 3381 3382 config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE); 3383 config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, 3384 WifiEnterpriseConfig.ENGINE_ID_KEYSTORE); 3385 3386 /* 3387 * The old key started with the keystore:// URI prefix, but we don't 3388 * need that anymore. Trim it off if it exists. 3389 */ 3390 final String keyName; 3391 if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) { 3392 keyName = new String( 3393 oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length())); 3394 } else { 3395 keyName = oldPrivateKey; 3396 } 3397 config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName); 3398 3399 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY, 3400 config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 3401 3402 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY, 3403 config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 3404 3405 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, 3406 config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 3407 3408 // Remove old private_key string so we don't run this again. 3409 mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 3410 3411 return true; 3412 } 3413 3414 /** Migrate certs from global pool to wifi UID if not already done */ 3415 void migrateCerts(WifiEnterpriseConfig config) { 3416 String client = config.getClientCertificateAlias(); 3417 // a valid client certificate is configured 3418 if (!TextUtils.isEmpty(client)) { 3419 if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 3420 mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 3421 Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 3422 mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 3423 Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 3424 } 3425 } 3426 3427 String ca = config.getCaCertificateAlias(); 3428 // a valid ca certificate is configured 3429 if (!TextUtils.isEmpty(ca)) { 3430 if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 3431 mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 3432 Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 3433 } 3434 } 3435 } 3436 3437} 3438