WifiConfigStore.java revision ecd2b88214b5d214fd1f63a9560caff9058912dd
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.LinkAddress; 22import android.net.LinkProperties; 23import android.net.NetworkUtils; 24import android.net.NetworkInfo.DetailedState; 25import android.net.ProxyInfo; 26import android.net.RouteInfo; 27import android.net.wifi.WifiConfiguration; 28import android.net.wifi.WifiConfiguration.IpAssignment; 29import android.net.wifi.WifiConfiguration.KeyMgmt; 30import android.net.wifi.WifiConfiguration.ProxySettings; 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; 40 41import android.os.Environment; 42import android.os.FileObserver; 43import android.os.Handler; 44import android.os.HandlerThread; 45import android.os.Process; 46import android.os.SystemClock; 47import android.os.UserHandle; 48import android.security.Credentials; 49import android.security.KeyChain; 50import android.security.KeyStore; 51import android.text.TextUtils; 52import android.util.LocalLog; 53import android.util.Log; 54 55import java.io.BufferedInputStream; 56import java.io.BufferedOutputStream; 57import java.io.BufferedReader; 58import java.io.DataInputStream; 59import java.io.DataOutputStream; 60import java.io.EOFException; 61import java.io.File; 62import java.io.FileDescriptor; 63import java.io.FileInputStream; 64import java.io.FileNotFoundException; 65import java.io.FileOutputStream; 66import java.io.FileReader; 67import java.io.IOException; 68import java.io.PrintWriter; 69import java.net.InetAddress; 70import java.security.PrivateKey; 71import java.security.cert.Certificate; 72import java.security.cert.CertificateException; 73import java.text.SimpleDateFormat; 74import java.text.DateFormat; 75import java.util.ArrayList; 76import java.util.BitSet; 77import java.util.Collection; 78import java.util.HashMap; 79import java.util.List; 80import java.util.Date; 81 82/** 83 * This class provides the API to manage configured 84 * wifi networks. The API is not thread safe is being 85 * used only from WifiStateMachine. 86 * 87 * It deals with the following 88 * - Add/update/remove a WifiConfiguration 89 * The configuration contains two types of information. 90 * = IP and proxy configuration that is handled by WifiConfigStore and 91 * is saved to disk on any change. 92 * 93 * The format of configuration file is as follows: 94 * <version> 95 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 96 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 97 * .. 98 * 99 * (key, value) pairs for a given network are grouped together and can 100 * be in any order. A EOS at the end of a set of (key, value) pairs 101 * indicates that the next set of (key, value) pairs are for a new 102 * network. A network is identified by a unique ID_KEY. If there is no 103 * ID_KEY in the (key, value) pairs, the data is discarded. 104 * 105 * An invalid version on read would result in discarding the contents of 106 * the file. On the next write, the latest version is written to file. 107 * 108 * Any failures during read or write to the configuration file are ignored 109 * without reporting to the user since the likelihood of these errors are 110 * low and the impact on connectivity is low. 111 * 112 * = SSID & security details that is pushed to the supplicant. 113 * supplicant saves these details to the disk on calling 114 * saveConfigCommand(). 115 * 116 * We have two kinds of APIs exposed: 117 * > public API calls that provide fine grained control 118 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 119 * removeNetwork(). For these calls, the config is not persisted 120 * to the disk. (TODO: deprecate these calls in WifiManager) 121 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 122 * These calls persist the supplicant config to disk. 123 * 124 * - Maintain a list of configured networks for quick access 125 * 126 */ 127public class WifiConfigStore { 128 129 private Context mContext; 130 private static final String TAG = "WifiConfigStore"; 131 private static final boolean DBG = true; 132 private static final boolean VDBG = false; 133 134 private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf"; 135 136 /* configured networks with network id as the key */ 137 private HashMap<Integer, WifiConfiguration> mConfiguredNetworks = 138 new HashMap<Integer, WifiConfiguration>(); 139 140 /* A network id is a unique identifier for a network configured in the 141 * supplicant. Network ids are generated when the supplicant reads 142 * the configuration file at start and can thus change for networks. 143 * We store the IP configuration for networks along with a unique id 144 * that is generated from SSID and security type of the network. A mapping 145 * from the generated unique id to network id of the network is needed to 146 * map supplicant config to IP configuration. */ 147 private HashMap<Integer, Integer> mNetworkIds = 148 new HashMap<Integer, Integer>(); 149 150 /* Tracks the highest priority of configured networks */ 151 private int mLastPriority = -1; 152 153 private static final String ipConfigFile = Environment.getDataDirectory() + 154 "/misc/wifi/ipconfig.txt"; 155 156 private static final String networkHistoryConfigFile = Environment.getDataDirectory() + 157 "/misc/wifi/networkHistory.txt"; 158 159 private static final int IPCONFIG_FILE_VERSION = 2; 160 161 /* IP and proxy configuration keys */ 162 private static final String ID_KEY = "id"; 163 private static final String IP_ASSIGNMENT_KEY = "ipAssignment"; 164 private static final String LINK_ADDRESS_KEY = "linkAddress"; 165 private static final String GATEWAY_KEY = "gateway"; 166 private static final String DNS_KEY = "dns"; 167 private static final String PROXY_SETTINGS_KEY = "proxySettings"; 168 private static final String PROXY_HOST_KEY = "proxyHost"; 169 private static final String PROXY_PORT_KEY = "proxyPort"; 170 private static final String PROXY_PAC_FILE = "proxyPac"; 171 private static final String EXCLUSION_LIST_KEY = "exclusionList"; 172 private static final String EOS = "eos"; 173 174 /* Network History Keys */ 175 private static final String SSID_KEY = "SSID: "; 176 private static final String CONFIG_KEY = "CONFIG: "; 177 private static final String CHOICE_KEY = "CHOICE: "; 178 private static final String LINK_KEY = "LINK: "; 179 private static final String BSSID_KEY = "BSSID: "; 180 private static final String BSSID_KEY_END = "/BSSID: "; 181 private static final String RSSI_KEY = "RSSI: "; 182 private static final String FREQ_KEY = "FREQ: "; 183 private static final String DATE_KEY = "DATE: "; 184 private static final String MILLI_KEY = "MILLI: "; 185 private static final String NETWORK_ID_KEY = "ID: "; 186 private static final String PRIORITY_KEY = "PRIORITY: "; 187 private static final String DEFAULT_GW_KEY = "DEFAULT_GW: "; 188 private static final String AUTH_KEY = "AUTH: "; 189 private static final String SEPARATOR_KEY = "\n"; 190 private static final String STATUS_KEY = "AUTO_JOIN_STATUS: "; 191 192 /* Enterprise configuration keys */ 193 /** 194 * In old configurations, the "private_key" field was used. However, newer 195 * configurations use the key_id field with the engine_id set to "keystore". 196 * If this field is found in the configuration, the migration code is 197 * triggered. 198 */ 199 public static final String OLD_PRIVATE_KEY_NAME = "private_key"; 200 201 /** This represents an empty value of an enterprise field. 202 * NULL is used at wpa_supplicant to indicate an empty value 203 */ 204 static final String EMPTY_VALUE = "NULL"; 205 206 /** Internal use only */ 207 private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { 208 WifiEnterpriseConfig.EAP_KEY, WifiEnterpriseConfig.PHASE2_KEY, 209 WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.ANON_IDENTITY_KEY, 210 WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY, 211 WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY, 212 WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY, 213 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY }; 214 215 private final LocalLog mLocalLog; 216 private final WpaConfigFileObserver mFileObserver; 217 218 private WifiNative mWifiNative; 219 private final KeyStore mKeyStore = KeyStore.getInstance(); 220 221 WifiConfigStore(Context c, WifiNative wn) { 222 mContext = c; 223 mWifiNative = wn; 224 225 if (VDBG) { 226 mLocalLog = mWifiNative.getLocalLog(); 227 mFileObserver = new WpaConfigFileObserver(); 228 mFileObserver.startWatching(); 229 } else { 230 mLocalLog = null; 231 mFileObserver = null; 232 } 233 } 234 235 class WpaConfigFileObserver extends FileObserver { 236 237 public WpaConfigFileObserver() { 238 super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE); 239 } 240 241 @Override 242 public void onEvent(int event, String path) { 243 if (event == CLOSE_WRITE) { 244 File file = new File(SUPPLICANT_CONFIG_FILE); 245 if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length()); 246 } 247 } 248 } 249 250 251 /** 252 * Fetch the list of configured networks 253 * and enable all stored networks in supplicant. 254 */ 255 void loadAndEnableAllNetworks() { 256 if (DBG) log("Loading config and enabling all networks"); 257 loadConfiguredNetworks(); 258 enableAllNetworks(); 259 } 260 261 /** 262 * Fetch the list of currently configured networks 263 * @return List of networks 264 */ 265 List<WifiConfiguration> getConfiguredNetworks() { 266 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 267 for(WifiConfiguration config : mConfiguredNetworks.values()) { 268 networks.add(new WifiConfiguration(config)); 269 } 270 return networks; 271 } 272 273 /** 274 * Fetch the list of currently configured networks that were recently seen 275 * 276 * @return List of networks 277 */ 278 List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) { 279 List<WifiConfiguration> networks = null; 280 281 for (WifiConfiguration config : mConfiguredNetworks.values()) { 282 // calculate the RSSI for scan results that are more recent than milli 283 config.setVisibility(milli); 284 285 if (config.visibility == null) { 286 continue; 287 } 288 if (config.visibility.rssi5 == WifiConfiguration.INVALID_RSSI && 289 config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { 290 continue; 291 } 292 if (networks == null) 293 networks = new ArrayList<WifiConfiguration>(); 294 if (copy) { 295 networks.add(new WifiConfiguration(config)); 296 } else { 297 networks.add(config); 298 } 299 } 300 return networks; 301 } 302 303 /** 304 * get the Wificonfiguration for this netId 305 * 306 * @return Wificonfiguration 307 */ 308 309 WifiConfiguration getWifiConfiguration(int netId) { 310 if (mConfiguredNetworks == null) 311 return null; 312 return mConfiguredNetworks.get(netId); 313 } 314 315 316 /** 317 * get the Wificonfiguration for this key 318 * 319 * @return Wificonfiguration 320 */ 321 322 WifiConfiguration getWifiConfiguration(String key) { 323 if (key == null) 324 return null; 325 int hash = key.hashCode(); 326 if (mNetworkIds == null) 327 return null; 328 Integer n = mNetworkIds.get(hash); 329 if (n == null) 330 return null; 331 int netId = n.intValue(); 332 return getWifiConfiguration(netId); 333 } 334 335 /** 336 * enable all networks and save config. This will be a no-op if the list 337 * of configured networks indicates all networks as being enabled 338 */ 339 void enableAllNetworks() { 340 boolean networkEnabledStateChanged = false; 341 for(WifiConfiguration config : mConfiguredNetworks.values()) { 342 if(config != null && config.status == Status.DISABLED 343 && (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) { 344 if(mWifiNative.enableNetwork(config.networkId, false)) { 345 networkEnabledStateChanged = true; 346 config.status = Status.ENABLED; 347 } else { 348 loge("Enable network failed on " + config.networkId); 349 } 350 } 351 } 352 353 if (networkEnabledStateChanged) { 354 mWifiNative.saveConfig(); 355 sendConfiguredNetworksChangedBroadcast(); 356 } 357 } 358 359 360 /** 361 * Selects the specified network for connection. This involves 362 * updating the priority of all the networks and enabling the given 363 * network while disabling others. 364 * 365 * Selecting a network will leave the other networks disabled and 366 * a call to enableAllNetworks() needs to be issued upon a connection 367 * or a failure event from supplicant 368 * 369 * @param netId network to select for connection 370 * @return false if the network id is invalid 371 */ 372 boolean selectNetwork(int netId) { 373 if (VDBG) localLog("selectNetwork", netId); 374 if (netId == INVALID_NETWORK_ID) return false; 375 376 // Reset the priority of each network at start or if it goes too high. 377 if (mLastPriority == -1 || mLastPriority > 1000000) { 378 for(WifiConfiguration config : mConfiguredNetworks.values()) { 379 if (config.networkId != INVALID_NETWORK_ID) { 380 config.priority = 0; 381 addOrUpdateNetworkNative(config); 382 } 383 } 384 mLastPriority = 0; 385 } 386 387 // Set to the highest priority and save the configuration. 388 WifiConfiguration config = new WifiConfiguration(); 389 config.networkId = netId; 390 config.priority = ++mLastPriority; 391 392 addOrUpdateNetworkNative(config); 393 mWifiNative.saveConfig(); 394 395 /* Enable the given network while disabling all other networks */ 396 enableNetworkWithoutBroadcast(netId, true); 397 398 /* Avoid saving the config & sending a broadcast to prevent settings 399 * from displaying a disabled list of networks */ 400 return true; 401 } 402 403 /** 404 * Add/update the specified configuration and save config 405 * 406 * @param config WifiConfiguration to be saved 407 * @return network update result 408 */ 409 NetworkUpdateResult saveNetwork(WifiConfiguration config) { 410 WifiConfiguration conf; 411 412 // A new network cannot have null SSID 413 if (config == null || (config.networkId == INVALID_NETWORK_ID && 414 config.SSID == null)) { 415 return new NetworkUpdateResult(INVALID_NETWORK_ID); 416 } 417 if (VDBG) localLog("WifiConfigStore: saveNetwork netId", config.networkId); 418 if (VDBG) { 419 loge("WifiConfigStore saveNetwork, size=" + mConfiguredNetworks.size() 420 + " SSID=" + config.SSID); 421 } 422 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 423 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 424 int netId = result.getNetworkId(); 425 426 if (VDBG) localLog("WifiConfigStore: saveNetwork got it back netId=", netId); 427 428 /* enable a new network */ 429 if (newNetwork && netId != INVALID_NETWORK_ID) { 430 if (VDBG) localLog("WifiConfigStore: will enable netId=", netId); 431 432 mWifiNative.enableNetwork(netId, false); 433 conf = mConfiguredNetworks.get(netId); 434 if (conf != null) 435 conf.status = Status.ENABLED; 436 } 437 438 conf = mConfiguredNetworks.get(netId); 439 if (conf != null) { 440 if (conf.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) { 441 if (VDBG) localLog("WifiConfigStore: re-enabling: " + conf.SSID); 442 443 // reenable autojoin, since new information has been provided 444 conf.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED; 445 enableNetworkWithoutBroadcast(conf.networkId, false); 446 } 447 } 448 449 mWifiNative.saveConfig(); 450 sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ? 451 WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 452 return result; 453 } 454 455 void updateStatus(int netId, DetailedState state) { 456 if (netId != INVALID_NETWORK_ID) { 457 WifiConfiguration config = mConfiguredNetworks.get(netId); 458 if (config == null) return; 459 switch (state) { 460 case CONNECTED: 461 config.status = Status.CURRENT; 462 break; 463 case DISCONNECTED: 464 //If network is already disabled, keep the status 465 if (config.status == Status.CURRENT) { 466 config.status = Status.ENABLED; 467 } 468 break; 469 default: 470 //do nothing, retain the existing state 471 break; 472 } 473 } 474 } 475 476 /** 477 * Forget the specified network and save config 478 * 479 * @param netId network to forget 480 * @return {@code true} if it succeeds, {@code false} otherwise 481 */ 482 boolean forgetNetwork(int netId) { 483 if (VDBG) localLog("forgetNetwork", netId); 484 if (mWifiNative.removeNetwork(netId)) { 485 mWifiNative.saveConfig(); 486 removeConfigAndSendBroadcastIfNeeded(netId); 487 return true; 488 } else { 489 loge("Failed to remove network " + netId); 490 return false; 491 } 492 } 493 494 /** 495 * Add/update a network. Note that there is no saveConfig operation. 496 * This function is retained for compatibility with the public 497 * API. The more powerful saveNetwork() is used by the 498 * state machine 499 * 500 * @param config wifi configuration to add/update 501 * @return network Id 502 */ 503 int addOrUpdateNetwork(WifiConfiguration config) { 504 if (VDBG) localLog("addOrUpdateNetwork", config.networkId); 505 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 506 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 507 WifiConfiguration conf = mConfiguredNetworks.get(result.getNetworkId()); 508 if (conf != null) { 509 sendConfiguredNetworksChangedBroadcast(conf, 510 result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : 511 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 512 } 513 } 514 return result.getNetworkId(); 515 } 516 517 /** 518 * Remove a network. Note that there is no saveConfig operation. 519 * This function is retained for compatibility with the public 520 * API. The more powerful forgetNetwork() is used by the 521 * state machine for network removal 522 * 523 * @param netId network to be removed 524 * @return {@code true} if it succeeds, {@code false} otherwise 525 */ 526 boolean removeNetwork(int netId) { 527 if (VDBG) localLog("removeNetwork", netId); 528 boolean ret = mWifiNative.removeNetwork(netId); 529 if (ret) { 530 removeConfigAndSendBroadcastIfNeeded(netId); 531 } 532 return ret; 533 } 534 535 private void removeConfigAndSendBroadcastIfNeeded(int netId) { 536 WifiConfiguration config = mConfiguredNetworks.get(netId); 537 if (config != null) { 538 if (VDBG) { 539 loge("removeNetwork " + Integer.toString(netId) + " key=" + 540 config.configKey() + " config.id=" + Integer.toString(config.networkId)); 541 } 542 543 // Remove any associated keys 544 if (config.enterpriseConfig != null) { 545 removeKeys(config.enterpriseConfig); 546 } 547 mConfiguredNetworks.remove(netId); 548 mNetworkIds.remove(configKey(config)); 549 if (VDBG) { 550 loge("removeNetwork -> num " + mConfiguredNetworks.size()); 551 for (WifiConfiguration c : mConfiguredNetworks.values()) { 552 loge(" has got " + c.configKey() + " id=" + Integer.toString(c.networkId)); 553 554 } 555 } 556 557 writeIpAndProxyConfigurations(); 558 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 559 writeKnownNetworkHistory(); 560 } 561 } 562 563 /** 564 * Enable a network. Note that there is no saveConfig operation. 565 * This function is retained for compatibility with the public 566 * API. The more powerful selectNetwork()/saveNetwork() is used by the 567 * state machine for connecting to a network 568 * 569 * @param netId network to be enabled 570 * @return {@code true} if it succeeds, {@code false} otherwise 571 */ 572 boolean enableNetwork(int netId, boolean disableOthers) { 573 boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); 574 if (disableOthers) { 575 if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId); 576 sendConfiguredNetworksChangedBroadcast(); 577 } else { 578 if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId); 579 WifiConfiguration enabledNetwork = null; 580 synchronized(mConfiguredNetworks) { 581 enabledNetwork = mConfiguredNetworks.get(netId); 582 } 583 // check just in case the network was removed by someone else. 584 if (enabledNetwork != null) { 585 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 586 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 587 } 588 } 589 return ret; 590 } 591 592 boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { 593 boolean ret = mWifiNative.enableNetwork(netId, disableOthers); 594 595 WifiConfiguration config = mConfiguredNetworks.get(netId); 596 if (config != null) config.status = Status.ENABLED; 597 598 if (disableOthers) { 599 markAllNetworksDisabledExcept(netId); 600 } 601 return ret; 602 } 603 604 void disableAllNetworks() { 605 if (VDBG) localLog("disableAllNetworks"); 606 boolean networkDisabled = false; 607 for(WifiConfiguration config : mConfiguredNetworks.values()) { 608 if(config != null && config.status != Status.DISABLED) { 609 if(mWifiNative.disableNetwork(config.networkId)) { 610 networkDisabled = true; 611 config.status = Status.DISABLED; 612 } else { 613 loge("Disable network failed on " + config.networkId); 614 } 615 } 616 } 617 618 if (networkDisabled) { 619 sendConfiguredNetworksChangedBroadcast(); 620 } 621 } 622 /** 623 * Disable a network. Note that there is no saveConfig operation. 624 * @param netId network to be disabled 625 * @return {@code true} if it succeeds, {@code false} otherwise 626 */ 627 boolean disableNetwork(int netId) { 628 return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); 629 } 630 631 /** 632 * Disable a network. Note that there is no saveConfig operation. 633 * @param netId network to be disabled 634 * @param reason reason code network was disabled 635 * @return {@code true} if it succeeds, {@code false} otherwise 636 */ 637 boolean disableNetwork(int netId, int reason) { 638 if (VDBG) localLog("disableNetwork", netId); 639 boolean ret = mWifiNative.disableNetwork(netId); 640 WifiConfiguration network = null; 641 WifiConfiguration config = mConfiguredNetworks.get(netId); 642 643 if (VDBG) { 644 if (config != null) { 645 loge("disableNetwork netId=" + Integer.toString(netId) 646 + " SSID=" + config.SSID 647 + " disabled=" + (config.status == Status.DISABLED) 648 + " reason=" + Integer.toString(config.disableReason)); 649 } 650 } 651 /* Only change the reason if the network was not previously disabled */ 652 if (config != null && config.status != Status.DISABLED) { 653 config.status = Status.DISABLED; 654 config.disableReason = reason; 655 network = config; 656 } 657 if (network != null) { 658 sendConfiguredNetworksChangedBroadcast(network, 659 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 660 } 661 return ret; 662 } 663 664 /** 665 * Save the configured networks in supplicant to disk 666 * @return {@code true} if it succeeds, {@code false} otherwise 667 */ 668 boolean saveConfig() { 669 return mWifiNative.saveConfig(); 670 } 671 672 /** 673 * Start WPS pin method configuration with pin obtained 674 * from the access point 675 * @param config WPS configuration 676 * @return Wps result containing status and pin 677 */ 678 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 679 WpsResult result = new WpsResult(); 680 if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { 681 /* WPS leaves all networks disabled */ 682 markAllNetworksDisabled(); 683 result.status = WpsResult.Status.SUCCESS; 684 } else { 685 loge("Failed to start WPS pin method configuration"); 686 result.status = WpsResult.Status.FAILURE; 687 } 688 return result; 689 } 690 691 /** 692 * Start WPS pin method configuration with pin obtained 693 * from the device 694 * @return WpsResult indicating status and pin 695 */ 696 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 697 WpsResult result = new WpsResult(); 698 result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); 699 /* WPS leaves all networks disabled */ 700 if (!TextUtils.isEmpty(result.pin)) { 701 markAllNetworksDisabled(); 702 result.status = WpsResult.Status.SUCCESS; 703 } else { 704 loge("Failed to start WPS pin method configuration"); 705 result.status = WpsResult.Status.FAILURE; 706 } 707 return result; 708 } 709 710 /** 711 * Start WPS push button configuration 712 * @param config WPS configuration 713 * @return WpsResult indicating status and pin 714 */ 715 WpsResult startWpsPbc(WpsInfo config) { 716 WpsResult result = new WpsResult(); 717 if (mWifiNative.startWpsPbc(config.BSSID)) { 718 /* WPS leaves all networks disabled */ 719 markAllNetworksDisabled(); 720 result.status = WpsResult.Status.SUCCESS; 721 } else { 722 loge("Failed to start WPS push button configuration"); 723 result.status = WpsResult.Status.FAILURE; 724 } 725 return result; 726 } 727 728 /** 729 * Fetch the link properties for a given network id 730 * 731 * @return LinkProperties for the given network id 732 */ 733 LinkProperties getLinkProperties(int netId) { 734 WifiConfiguration config = mConfiguredNetworks.get(netId); 735 if (config != null) return new LinkProperties(config.linkProperties); 736 return null; 737 } 738 739 /** 740 * set IP configuration for a given network id 741 */ 742 void setLinkProperties(int netId, LinkProperties linkProperties) { 743 WifiConfiguration config = mConfiguredNetworks.get(netId); 744 if (config != null) { 745 // add old proxy details - TODO - is this still needed? 746 if(config.linkProperties != null) { 747 linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); 748 } 749 config.linkProperties = linkProperties; 750 } 751 } 752 753 /** 754 * set default GW MAC address 755 */ 756 void setDefaultGwMacAddress(int netId, String macAddress) { 757 WifiConfiguration config = mConfiguredNetworks.get(netId); 758 if (config != null) { 759 //update defaultGwMacAddress 760 config.defaultGwMacAddress = macAddress; 761 } 762 } 763 764 765 /** 766 * clear IP configuration for a given network id 767 * @param network id 768 */ 769 void clearLinkProperties(int netId) { 770 WifiConfiguration config = mConfiguredNetworks.get(netId); 771 if (config != null && config.linkProperties != null) { 772 // Clear everything except proxy 773 ProxyInfo proxy = config.linkProperties.getHttpProxy(); 774 config.linkProperties.clear(); 775 config.linkProperties.setHttpProxy(proxy); 776 } 777 } 778 779 780 /** 781 * Fetch the proxy properties for a given network id 782 * @param network id 783 * @return ProxyInfo for the network id 784 */ 785 ProxyInfo getProxyProperties(int netId) { 786 LinkProperties linkProperties = getLinkProperties(netId); 787 if (linkProperties != null) { 788 return new ProxyInfo(linkProperties.getHttpProxy()); 789 } 790 return null; 791 } 792 793 /** 794 * Return if the specified network is using static IP 795 * @param network id 796 * @return {@code true} if using static ip for netId 797 */ 798 boolean isUsingStaticIp(int netId) { 799 WifiConfiguration config = mConfiguredNetworks.get(netId); 800 if (config != null && config.ipAssignment == IpAssignment.STATIC) { 801 return true; 802 } 803 return false; 804 } 805 806 /** 807 * Should be called when a single network configuration is made. 808 * @param network The network configuration that changed. 809 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 810 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 811 */ 812 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 813 int reason) { 814 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 815 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 816 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 817 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 818 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 819 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 820 } 821 822 /** 823 * Should be called when multiple network configuration changes are made. 824 */ 825 private void sendConfiguredNetworksChangedBroadcast() { 826 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 827 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 828 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 829 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 830 } 831 832 void loadConfiguredNetworks() { 833 String listStr = mWifiNative.listNetworks(); 834 mLastPriority = 0; 835 836 mConfiguredNetworks.clear(); 837 mNetworkIds.clear(); 838 839 if (listStr == null) 840 return; 841 842 String[] lines = listStr.split("\n"); 843 // Skip the first line, which is a header 844 for (int i = 1; i < lines.length; i++) { 845 String[] result = lines[i].split("\t"); 846 // network-id | ssid | bssid | flags 847 WifiConfiguration config = new WifiConfiguration(); 848 try { 849 config.networkId = Integer.parseInt(result[0]); 850 } catch(NumberFormatException e) { 851 loge("Failed to read network-id '" + result[0] + "'"); 852 continue; 853 } 854 if (result.length > 3) { 855 if (result[3].indexOf("[CURRENT]") != -1) 856 config.status = WifiConfiguration.Status.CURRENT; 857 else if (result[3].indexOf("[DISABLED]") != -1) 858 config.status = WifiConfiguration.Status.DISABLED; 859 else 860 config.status = WifiConfiguration.Status.ENABLED; 861 } else { 862 config.status = WifiConfiguration.Status.ENABLED; 863 } 864 readNetworkVariables(config); 865 if (config.priority > mLastPriority) { 866 mLastPriority = config.priority; 867 } 868 config.ipAssignment = IpAssignment.DHCP; 869 config.proxySettings = ProxySettings.NONE; 870 871 if (mNetworkIds.containsKey(configKey(config))) { 872 // That SSID is already known, just ignore this duplicate entry 873 if (VDBG) localLog("discarded duplicate network", config.networkId); 874 } else { 875 mConfiguredNetworks.put(config.networkId, config); 876 mNetworkIds.put(configKey(config), config.networkId); 877 if (VDBG) localLog("loaded configured network", config.networkId); 878 } 879 } 880 881 readIpAndProxyConfigurations(); 882 readNetworkHistory(); 883 884 sendConfiguredNetworksChangedBroadcast(); 885 886 if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks"); 887 888 if (mNetworkIds.size() == 0) { 889 // no networks? Lets log if the wpa_supplicant.conf file contents 890 BufferedReader reader = null; 891 try { 892 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 893 if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---"); 894 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 895 if (VDBG) localLog(line); 896 } 897 if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---"); 898 } catch (FileNotFoundException e) { 899 if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 900 } catch (IOException e) { 901 if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 902 } finally { 903 try { 904 if (reader != null) { 905 reader.close(); 906 } 907 } catch (IOException e) { 908 // Just ignore the fact that we couldn't close 909 } 910 } 911 } 912 } 913 914 private String readNetworkVariableFromSupplicantFile(String ssid, String key) { 915 BufferedReader reader = null; 916 if (VDBG) loge("readNetworkVariableFromSupplicantFile ssid=[" + ssid + "] key=" + key); 917 918 String value = null; 919 try { 920 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 921 boolean found = false; 922 boolean networkMatched = false; 923 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 924 if (VDBG) loge(line); 925 926 if (line.matches("[ \\t]*network=\\{")) { 927 found = true; 928 networkMatched = false; 929 } else if (line.matches("[ \\t]*\\{")) { 930 found = false; 931 networkMatched = false; 932 } 933 934 if (found) { 935 int index; 936 if ((index = line.indexOf("ssid=")) >= 0) { 937 String networkSSid = line.substring(index + 5); 938 if (networkSSid.regionMatches(0, ssid, 0, ssid.length())) { 939 networkMatched = true; 940 } else { 941 networkMatched = false; 942 } 943 } 944 945 if (networkMatched) { 946 if ((index = line.indexOf(key + "=")) >= 0) { 947 948 value = line.substring(index + key.length() + 1); 949 if (VDBG) loge("found key " + value); 950 951 } 952 } 953 } 954 } 955 } catch (FileNotFoundException e) { 956 if (VDBG) loge("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 957 } catch (IOException e) { 958 if (VDBG) loge("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 959 } finally { 960 try { 961 if (reader != null) { 962 reader.close(); 963 } 964 } catch (IOException e) { 965 // Just ignore the fact that we couldn't close 966 } 967 } 968 969 return value; 970 } 971 972 /* Mark all networks except specified netId as disabled */ 973 private void markAllNetworksDisabledExcept(int netId) { 974 for(WifiConfiguration config : mConfiguredNetworks.values()) { 975 if(config != null && config.networkId != netId) { 976 if (config.status != Status.DISABLED) { 977 config.status = Status.DISABLED; 978 config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; 979 } 980 } 981 } 982 } 983 984 private void markAllNetworksDisabled() { 985 markAllNetworksDisabledExcept(INVALID_NETWORK_ID); 986 } 987 988 boolean needsUnlockedKeyStore() { 989 990 // Any network using certificates to authenticate access requires 991 // unlocked key store; unless the certificates can be stored with 992 // hardware encryption 993 994 for(WifiConfiguration config : mConfiguredNetworks.values()) { 995 996 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 997 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 998 999 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 1000 return true; 1001 } 1002 } 1003 } 1004 1005 return false; 1006 } 1007 1008 private void writeIpAndProxyConfigurations() { 1009 1010 if (VDBG) loge(" writeIpAndProxyConfigurations()"); 1011 1012 /* Make a copy */ 1013 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 1014 for(WifiConfiguration config : mConfiguredNetworks.values()) { 1015 networks.add(new WifiConfiguration(config)); 1016 } 1017 1018 DelayedDiskWrite.write(networks, DelayedDiskWrite.WRITE_IP_CONFIG); 1019 } 1020 1021 public void writeKnownNetworkHistory() { 1022 1023 if (VDBG) { 1024 loge(" writeKnownNetworkHistory() num networks:" + 1025 Integer.toString(mConfiguredNetworks.size()) ); 1026 } 1027 1028 /* Make a copy */ 1029 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 1030 for (WifiConfiguration config : mConfiguredNetworks.values()) { 1031 networks.add(new WifiConfiguration(config)); 1032 } 1033 1034 DelayedDiskWrite.write(networks, DelayedDiskWrite.WRITE_NETWORK_HISTORY); 1035 1036 } 1037 1038 private static class DelayedDiskWrite { 1039 1040 private static HandlerThread sDiskWriteHandlerThread; 1041 private static Handler sDiskWriteHandler; 1042 /* Tracks multiple writes on the same thread */ 1043 private static int sWriteSequence = 0; 1044 private static final String TAG = "DelayedDiskWrite"; 1045 1046 static final int WRITE_IP_CONFIG = 0; 1047 static final int WRITE_NETWORK_HISTORY = 1; 1048 1049 static void write(final List<WifiConfiguration> networks, final int what) { 1050 1051 /* Do a delayed write to disk on a separate handler thread */ 1052 synchronized (DelayedDiskWrite.class) { 1053 if (++sWriteSequence == 1) { 1054 sDiskWriteHandlerThread = new HandlerThread("WifiConfigThread"); 1055 sDiskWriteHandlerThread.start(); 1056 sDiskWriteHandler = new Handler(sDiskWriteHandlerThread.getLooper()); 1057 } 1058 } 1059 1060 sDiskWriteHandler.post(new Runnable() { 1061 @Override 1062 public void run() { 1063 onWriteCalled(networks, what); 1064 } 1065 }); 1066 } 1067 1068 private static void onWriteCalled(List<WifiConfiguration> networks, int what) { 1069 DataOutputStream out = null; 1070 try { 1071 String outfile; 1072 if (what == WRITE_IP_CONFIG) { 1073 outfile = ipConfigFile; 1074 } else { 1075 outfile = networkHistoryConfigFile; 1076 } 1077 1078 out = new DataOutputStream(new BufferedOutputStream( 1079 new FileOutputStream(outfile))); 1080 1081 if (what == WRITE_IP_CONFIG) { 1082 1083 out.writeInt(IPCONFIG_FILE_VERSION); 1084 1085 for(WifiConfiguration config : networks) { 1086 boolean writeToFile = false; 1087 1088 if (config.ephemeral == true) 1089 continue; 1090 1091 try { 1092 LinkProperties linkProperties = config.linkProperties; 1093 switch (config.ipAssignment) { 1094 case STATIC: 1095 out.writeUTF(IP_ASSIGNMENT_KEY); 1096 out.writeUTF(config.ipAssignment.toString()); 1097 for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { 1098 out.writeUTF(LINK_ADDRESS_KEY); 1099 out.writeUTF(linkAddr.getAddress().getHostAddress()); 1100 out.writeInt(linkAddr.getNetworkPrefixLength()); 1101 } 1102 for (RouteInfo route : linkProperties.getRoutes()) { 1103 out.writeUTF(GATEWAY_KEY); 1104 LinkAddress dest = route.getDestination(); 1105 if (dest != null) { 1106 out.writeInt(1); 1107 out.writeUTF(dest.getAddress().getHostAddress()); 1108 out.writeInt(dest.getNetworkPrefixLength()); 1109 } else { 1110 out.writeInt(0); 1111 } 1112 if (route.getGateway() != null) { 1113 out.writeInt(1); 1114 out.writeUTF(route.getGateway().getHostAddress()); 1115 } else { 1116 out.writeInt(0); 1117 } 1118 } 1119 for (InetAddress inetAddr : linkProperties.getDnses()) { 1120 out.writeUTF(DNS_KEY); 1121 out.writeUTF(inetAddr.getHostAddress()); 1122 } 1123 writeToFile = true; 1124 break; 1125 case DHCP: 1126 out.writeUTF(IP_ASSIGNMENT_KEY); 1127 out.writeUTF(config.ipAssignment.toString()); 1128 writeToFile = true; 1129 break; 1130 case UNASSIGNED: 1131 /* Ignore */ 1132 break; 1133 default: 1134 loge("Ignore invalid ip assignment while writing"); 1135 break; 1136 } 1137 1138 switch (config.proxySettings) { 1139 case STATIC: 1140 ProxyInfo proxyProperties = linkProperties.getHttpProxy(); 1141 String exclusionList = proxyProperties.getExclusionListAsString(); 1142 out.writeUTF(PROXY_SETTINGS_KEY); 1143 out.writeUTF(config.proxySettings.toString()); 1144 out.writeUTF(PROXY_HOST_KEY); 1145 out.writeUTF(proxyProperties.getHost()); 1146 out.writeUTF(PROXY_PORT_KEY); 1147 out.writeInt(proxyProperties.getPort()); 1148 out.writeUTF(EXCLUSION_LIST_KEY); 1149 out.writeUTF(exclusionList); 1150 writeToFile = true; 1151 break; 1152 case PAC: 1153 ProxyInfo proxyPacProperties = linkProperties.getHttpProxy(); 1154 out.writeUTF(PROXY_SETTINGS_KEY); 1155 out.writeUTF(config.proxySettings.toString()); 1156 out.writeUTF(PROXY_PAC_FILE); 1157 out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); 1158 writeToFile = true; 1159 break; 1160 case NONE: 1161 out.writeUTF(PROXY_SETTINGS_KEY); 1162 out.writeUTF(config.proxySettings.toString()); 1163 writeToFile = true; 1164 break; 1165 case UNASSIGNED: 1166 /* Ignore */ 1167 break; 1168 default: 1169 loge("Ignore invalid proxy settings while writing"); 1170 break; 1171 } 1172 if (writeToFile) { 1173 out.writeUTF(ID_KEY); 1174 out.writeInt(configKey(config)); 1175 } 1176 } catch (NullPointerException e) { 1177 loge("Failure in writing " + config.linkProperties + e); 1178 } 1179 out.writeUTF(EOS); 1180 } 1181 } else { 1182 1183 for (WifiConfiguration config : networks) { 1184 //loge("onWriteCalled write SSID: " + config.SSID); 1185 /* if (config.linkProperties != null) 1186 loge(" lp " + config.linkProperties.toString()); 1187 else 1188 loge("attempt config w/o lp"); 1189 */ 1190 1191 if (DBG) { 1192 loge("saving network history: " + config.SSID + " gw: " + 1193 config.defaultGwMacAddress + " autojoin status: " + 1194 config.autoJoinStatus + " ephemeral=" + config.ephemeral); 1195 } 1196 if (config.ephemeral == true) 1197 continue; 1198 1199 out.writeChars(CONFIG_KEY); 1200 out.writeChars(config.configKey()); 1201 out.writeChars(SEPARATOR_KEY); 1202 1203 out.writeChars(SSID_KEY); 1204 out.writeChars(config.SSID); 1205 out.writeChars(SEPARATOR_KEY); 1206 1207 out.writeChars(PRIORITY_KEY); 1208 out.writeChars(Integer.toString(config.priority)); 1209 out.writeChars(SEPARATOR_KEY); 1210 out.writeChars(STATUS_KEY); 1211 out.writeChars(Integer.toString(config.autoJoinStatus)); 1212 out.writeChars(SEPARATOR_KEY); 1213 out.writeChars(NETWORK_ID_KEY); 1214 out.writeChars(Integer.toString(config.networkId)); 1215 out.writeChars(SEPARATOR_KEY); 1216 1217 String allowedKeyManagementString = 1218 makeString(config.allowedKeyManagement, 1219 WifiConfiguration.KeyMgmt.strings); 1220 out.writeChars(AUTH_KEY); 1221 out.writeChars(allowedKeyManagementString); 1222 out.writeChars(SEPARATOR_KEY); 1223 1224 if (config.connectChoices != null) { 1225 for (String key : config.connectChoices.keySet()) { 1226 out.writeChars(CHOICE_KEY); 1227 out.writeChars(key); 1228 out.writeChars(SEPARATOR_KEY); 1229 } 1230 } 1231 if (config.linkedConfigurations != null) { 1232 for (String key : config.linkedConfigurations.keySet()) { 1233 out.writeChars(LINK_KEY); 1234 out.writeChars(key); 1235 out.writeChars(SEPARATOR_KEY); 1236 } 1237 } 1238 1239 if (config.linkProperties != null) { 1240 String macAddress = config.defaultGwMacAddress; 1241 if (macAddress != null) { 1242 out.writeChars(DEFAULT_GW_KEY); 1243 out.writeChars(macAddress); 1244 out.writeChars(SEPARATOR_KEY); 1245 } 1246 } 1247 1248 if (config.scanResultCache != null) { 1249 for (ScanResult result : config.scanResultCache.values()) { 1250 out.writeChars(BSSID_KEY); 1251 out.writeChars(result.BSSID); 1252 out.writeChars(SEPARATOR_KEY); 1253 1254 out.writeChars(FREQ_KEY); 1255 out.writeChars(Integer.toString(result.frequency)); 1256 out.writeChars(SEPARATOR_KEY); 1257 1258 out.writeChars(RSSI_KEY); 1259 out.writeChars(Integer.toString(result.level)); 1260 out.writeChars(SEPARATOR_KEY); 1261 1262 if (result.seen != 0) { 1263 out.writeChars(MILLI_KEY); 1264 out.writeChars(Long.toString(result.seen)); 1265 out.writeChars(SEPARATOR_KEY); 1266 } 1267 out.writeChars(BSSID_KEY_END); 1268 out.writeChars(SEPARATOR_KEY); 1269 } 1270 } 1271 out.writeChars(SEPARATOR_KEY); 1272 } 1273 } 1274 1275 } catch (IOException e) { 1276 loge("Error writing data file"); 1277 } finally { 1278 if (out != null) { 1279 try { 1280 out.close(); 1281 } catch (Exception e) {} 1282 } 1283 1284 //Quit if no more writes sent 1285 synchronized (DelayedDiskWrite.class) { 1286 if (--sWriteSequence == 0) { 1287 sDiskWriteHandler.getLooper().quit(); 1288 sDiskWriteHandler = null; 1289 sDiskWriteHandlerThread = null; 1290 } 1291 } 1292 } 1293 } 1294 1295 private static void loge(String s) { 1296 Log.e(TAG, s); 1297 } 1298 } 1299 1300 1301 private void readNetworkHistory() { 1302 DataInputStream in = null; 1303 try { 1304 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 1305 networkHistoryConfigFile))); 1306 WifiConfiguration config = null; 1307 while (true) { 1308 int id = -1; 1309 String key = in.readUTF(); 1310 1311 String bssid = null; 1312 String ssid = null; 1313 1314 int freq = 0; 1315 long seen = 0; 1316 int rssi = -128; 1317 String caps = null; 1318 if (key.startsWith(CONFIG_KEY)) { 1319 1320 if (config != null) { 1321 config = null; 1322 } 1323 String configKey = key.replace(CONFIG_KEY, ""); 1324 // get the networkId for that config Key 1325 Integer n = mNetworkIds.get(configKey.hashCode()); 1326 // skip reading that configuration data 1327 // since we don't have a corresponding network ID 1328 if (n == null) continue; 1329 config = mConfiguredNetworks.get(n); 1330 ssid = null; 1331 bssid = null; 1332 freq = 0; 1333 seen = 0; 1334 rssi = -128; 1335 caps = null; 1336 1337 } else if (config != null) { 1338 if (key.startsWith(SSID_KEY)) { 1339 ssid = key.replace(SSID_KEY, ""); 1340 if (config.SSID != ssid) { 1341 loge("Error parsing network history file"); 1342 config = null; //error 1343 ssid = null; 1344 } 1345 } 1346 1347 if (key.startsWith(DEFAULT_GW_KEY)) { 1348 String gateway = key.replace(DEFAULT_GW_KEY, ""); 1349 config.defaultGwMacAddress = gateway; 1350 1351 } 1352 1353 if (key.startsWith(STATUS_KEY)) { 1354 String status = key.replace(STATUS_KEY, ""); 1355 config.autoJoinStatus = Integer.getInteger(status); 1356 } 1357 1358 if (key.startsWith(CHOICE_KEY)) { 1359 String configKey = key.replace(CHOICE_KEY, ""); 1360 if (config.connectChoices == null) { 1361 config.connectChoices = new HashMap<String, Integer>(); 1362 } 1363 if (config.connectChoices != null) { 1364 config.connectChoices.put(configKey, -1); 1365 } 1366 } 1367 1368 if (key.startsWith(LINK_KEY)) { 1369 String configKey = key.replace(LINK_KEY, ""); 1370 if (config.linkedConfigurations == null) { 1371 config.linkedConfigurations = new HashMap<String, Integer>(); 1372 } 1373 if (config.linkedConfigurations != null) { 1374 config.linkedConfigurations.put(configKey, -1); 1375 } 1376 } 1377 1378 if (key.startsWith(BSSID_KEY)) { 1379 if (key.startsWith(BSSID_KEY)) { 1380 bssid = key.replace(BSSID_KEY, ""); 1381 freq = 0; 1382 seen = 0; 1383 rssi = -127; 1384 caps = ""; 1385 } 1386 1387 if (key.startsWith(RSSI_KEY)) { 1388 String lvl = key.replace(RSSI_KEY, ""); 1389 rssi = Integer.getInteger(lvl); 1390 } 1391 if (key.startsWith(FREQ_KEY)) { 1392 String lvl = key.replace(FREQ_KEY, ""); 1393 freq = Integer.getInteger(lvl); 1394 } 1395 if (key.startsWith(DATE_KEY)) { 1396 /* 1397 * when reading the configuration from file we don't update the date 1398 * so as to avoid reading back stale or non-sensical data that would 1399 * depend on network time. 1400 * The date of a WifiConfiguration should only come from actual scan result. 1401 * 1402 String s = key.replace(FREQ_KEY, ""); 1403 seen = Integer.getInteger(s); 1404 */ 1405 } 1406 1407 if (key.startsWith(BSSID_KEY_END)) { 1408 1409 if ((bssid != null) && (ssid != null)) { 1410 1411 if (config.scanResultCache == null) { 1412 config.scanResultCache = new HashMap<String, ScanResult>(); 1413 } 1414 1415 WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid); 1416 ScanResult result = new ScanResult(wssid, bssid, 1417 caps, rssi, freq, (long) 0); 1418 result.seen = seen; 1419 config.scanResultCache.put(bssid, result); 1420 } 1421 } 1422 } 1423 } 1424 } 1425 } catch (EOFException ignore) { 1426 if (in != null) { 1427 try { 1428 in.close(); 1429 } catch (Exception e) { 1430 } 1431 } 1432 } catch (IOException e) { 1433 loge("Error parsing configuration" + e); 1434 } 1435 1436 if(in!=null) { 1437 try { 1438 in.close(); 1439 } catch (Exception e) { 1440 } 1441 } 1442 } 1443 1444 1445 private void readIpAndProxyConfigurations() { 1446 1447 DataInputStream in = null; 1448 try { 1449 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 1450 ipConfigFile))); 1451 1452 int version = in.readInt(); 1453 if (version != 2 && version != 1) { 1454 loge("Bad version on IP configuration file, ignore read"); 1455 return; 1456 } 1457 1458 while (true) { 1459 int id = -1; 1460 // Default is DHCP with no proxy 1461 IpAssignment ipAssignment = IpAssignment.DHCP; 1462 ProxySettings proxySettings = ProxySettings.NONE; 1463 LinkProperties linkProperties = new LinkProperties(); 1464 String proxyHost = null; 1465 String pacFileUrl = null; 1466 int proxyPort = -1; 1467 String exclusionList = null; 1468 String key; 1469 1470 do { 1471 key = in.readUTF(); 1472 try { 1473 if (key.equals(ID_KEY)) { 1474 id = in.readInt(); 1475 } else if (key.equals(IP_ASSIGNMENT_KEY)) { 1476 ipAssignment = IpAssignment.valueOf(in.readUTF()); 1477 } else if (key.equals(LINK_ADDRESS_KEY)) { 1478 LinkAddress linkAddr = new LinkAddress( 1479 NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); 1480 linkProperties.addLinkAddress(linkAddr); 1481 } else if (key.equals(GATEWAY_KEY)) { 1482 LinkAddress dest = null; 1483 InetAddress gateway = null; 1484 if (version == 1) { 1485 // only supported default gateways - leave the dest/prefix empty 1486 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 1487 } else { 1488 if (in.readInt() == 1) { 1489 dest = new LinkAddress( 1490 NetworkUtils.numericToInetAddress(in.readUTF()), 1491 in.readInt()); 1492 } 1493 if (in.readInt() == 1) { 1494 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 1495 } 1496 } 1497 linkProperties.addRoute(new RouteInfo(dest, gateway)); 1498 } else if (key.equals(DNS_KEY)) { 1499 linkProperties.addDns( 1500 NetworkUtils.numericToInetAddress(in.readUTF())); 1501 } else if (key.equals(PROXY_SETTINGS_KEY)) { 1502 proxySettings = ProxySettings.valueOf(in.readUTF()); 1503 } else if (key.equals(PROXY_HOST_KEY)) { 1504 proxyHost = in.readUTF(); 1505 } else if (key.equals(PROXY_PORT_KEY)) { 1506 proxyPort = in.readInt(); 1507 } else if (key.equals(PROXY_PAC_FILE)) { 1508 pacFileUrl = in.readUTF(); 1509 } else if (key.equals(EXCLUSION_LIST_KEY)) { 1510 exclusionList = in.readUTF(); 1511 } else if (key.equals(EOS)) { 1512 break; 1513 } else { 1514 loge("Ignore unknown key " + key + "while reading"); 1515 } 1516 } catch (IllegalArgumentException e) { 1517 loge("Ignore invalid address while reading" + e); 1518 } 1519 } while (true); 1520 1521 if (id != -1) { 1522 WifiConfiguration config = null; 1523 Integer n = mNetworkIds.get(id); 1524 if (n != null) config = mConfiguredNetworks.get(n); 1525 if (config == null) { 1526 loge("configuration found for missing network, ignored"); 1527 } else { 1528 config.linkProperties = linkProperties; 1529 switch (ipAssignment) { 1530 case STATIC: 1531 case DHCP: 1532 config.ipAssignment = ipAssignment; 1533 break; 1534 case UNASSIGNED: 1535 loge("BUG: Found UNASSIGNED IP on file, use DHCP"); 1536 config.ipAssignment = IpAssignment.DHCP; 1537 break; 1538 default: 1539 loge("Ignore invalid ip assignment while reading"); 1540 break; 1541 } 1542 1543 switch (proxySettings) { 1544 case STATIC: 1545 config.proxySettings = proxySettings; 1546 ProxyInfo proxyProperties = 1547 new ProxyInfo(proxyHost, proxyPort, exclusionList); 1548 linkProperties.setHttpProxy(proxyProperties); 1549 break; 1550 case PAC: 1551 config.proxySettings = proxySettings; 1552 ProxyInfo proxyPacProperties = 1553 new ProxyInfo(pacFileUrl); 1554 linkProperties.setHttpProxy(proxyPacProperties); 1555 break; 1556 case NONE: 1557 config.proxySettings = proxySettings; 1558 break; 1559 case UNASSIGNED: 1560 loge("BUG: Found UNASSIGNED proxy on file, use NONE"); 1561 config.proxySettings = ProxySettings.NONE; 1562 break; 1563 default: 1564 loge("Ignore invalid proxy settings while reading"); 1565 break; 1566 } 1567 } 1568 } else { 1569 if (DBG) log("Missing id while parsing configuration"); 1570 } 1571 } 1572 } catch (EOFException ignore) { 1573 } catch (IOException e) { 1574 loge("Error parsing configuration" + e); 1575 } finally { 1576 if (in != null) { 1577 try { 1578 in.close(); 1579 } catch (Exception e) {} 1580 } 1581 } 1582 } 1583 1584 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { 1585 /* 1586 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1587 * network configuration. Otherwise, the networkId should 1588 * refer to an existing configuration. 1589 */ 1590 1591 if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 1592 1593 int netId = config.networkId; 1594 boolean newNetwork = false; 1595 // networkId of INVALID_NETWORK_ID means we want to create a new network 1596 if (netId == INVALID_NETWORK_ID) { 1597 Integer savedNetId = mNetworkIds.get(configKey(config)); 1598 if (savedNetId != null) { 1599 netId = savedNetId; 1600 } else { 1601 newNetwork = true; 1602 netId = mWifiNative.addNetwork(); 1603 if (netId < 0) { 1604 loge("Failed to add a network!"); 1605 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1606 } else { 1607 loge("addOrUpdateNetworkNative created netId=" + netId); 1608 } 1609 } 1610 } 1611 1612 boolean updateFailed = true; 1613 1614 setVariables: { 1615 1616 if (config.SSID != null && 1617 !mWifiNative.setNetworkVariable( 1618 netId, 1619 WifiConfiguration.ssidVarName, 1620 config.SSID)) { 1621 loge("failed to set SSID: "+config.SSID); 1622 break setVariables; 1623 } 1624 1625 if (config.BSSID != null && 1626 !mWifiNative.setNetworkVariable( 1627 netId, 1628 WifiConfiguration.bssidVarName, 1629 config.BSSID)) { 1630 loge("failed to set BSSID: "+config.BSSID); 1631 break setVariables; 1632 } 1633 1634 String allowedKeyManagementString = 1635 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 1636 if (config.allowedKeyManagement.cardinality() != 0 && 1637 !mWifiNative.setNetworkVariable( 1638 netId, 1639 WifiConfiguration.KeyMgmt.varName, 1640 allowedKeyManagementString)) { 1641 loge("failed to set key_mgmt: "+ 1642 allowedKeyManagementString); 1643 break setVariables; 1644 } 1645 1646 String allowedProtocolsString = 1647 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 1648 if (config.allowedProtocols.cardinality() != 0 && 1649 !mWifiNative.setNetworkVariable( 1650 netId, 1651 WifiConfiguration.Protocol.varName, 1652 allowedProtocolsString)) { 1653 loge("failed to set proto: "+ 1654 allowedProtocolsString); 1655 break setVariables; 1656 } 1657 1658 String allowedAuthAlgorithmsString = 1659 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 1660 if (config.allowedAuthAlgorithms.cardinality() != 0 && 1661 !mWifiNative.setNetworkVariable( 1662 netId, 1663 WifiConfiguration.AuthAlgorithm.varName, 1664 allowedAuthAlgorithmsString)) { 1665 loge("failed to set auth_alg: "+ 1666 allowedAuthAlgorithmsString); 1667 break setVariables; 1668 } 1669 1670 String allowedPairwiseCiphersString = 1671 makeString(config.allowedPairwiseCiphers, 1672 WifiConfiguration.PairwiseCipher.strings); 1673 if (config.allowedPairwiseCiphers.cardinality() != 0 && 1674 !mWifiNative.setNetworkVariable( 1675 netId, 1676 WifiConfiguration.PairwiseCipher.varName, 1677 allowedPairwiseCiphersString)) { 1678 loge("failed to set pairwise: "+ 1679 allowedPairwiseCiphersString); 1680 break setVariables; 1681 } 1682 1683 String allowedGroupCiphersString = 1684 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 1685 if (config.allowedGroupCiphers.cardinality() != 0 && 1686 !mWifiNative.setNetworkVariable( 1687 netId, 1688 WifiConfiguration.GroupCipher.varName, 1689 allowedGroupCiphersString)) { 1690 loge("failed to set group: "+ 1691 allowedGroupCiphersString); 1692 break setVariables; 1693 } 1694 1695 // Prevent client screw-up by passing in a WifiConfiguration we gave it 1696 // by preventing "*" as a key. 1697 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 1698 !mWifiNative.setNetworkVariable( 1699 netId, 1700 WifiConfiguration.pskVarName, 1701 config.preSharedKey)) { 1702 loge("failed to set psk"); 1703 break setVariables; 1704 } 1705 1706 boolean hasSetKey = false; 1707 if (config.wepKeys != null) { 1708 for (int i = 0; i < config.wepKeys.length; i++) { 1709 // Prevent client screw-up by passing in a WifiConfiguration we gave it 1710 // by preventing "*" as a key. 1711 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 1712 if (!mWifiNative.setNetworkVariable( 1713 netId, 1714 WifiConfiguration.wepKeyVarNames[i], 1715 config.wepKeys[i])) { 1716 loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); 1717 break setVariables; 1718 } 1719 hasSetKey = true; 1720 } 1721 } 1722 } 1723 1724 if (hasSetKey) { 1725 if (!mWifiNative.setNetworkVariable( 1726 netId, 1727 WifiConfiguration.wepTxKeyIdxVarName, 1728 Integer.toString(config.wepTxKeyIndex))) { 1729 loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); 1730 break setVariables; 1731 } 1732 } 1733 1734 if (!mWifiNative.setNetworkVariable( 1735 netId, 1736 WifiConfiguration.priorityVarName, 1737 Integer.toString(config.priority))) { 1738 loge(config.SSID + ": failed to set priority: " 1739 +config.priority); 1740 break setVariables; 1741 } 1742 1743 if (config.hiddenSSID && !mWifiNative.setNetworkVariable( 1744 netId, 1745 WifiConfiguration.hiddenSSIDVarName, 1746 Integer.toString(config.hiddenSSID ? 1 : 0))) { 1747 loge(config.SSID + ": failed to set hiddenSSID: "+ 1748 config.hiddenSSID); 1749 break setVariables; 1750 } 1751 1752 if (config.enterpriseConfig != null && 1753 config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { 1754 1755 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 1756 1757 if (needsKeyStore(enterpriseConfig)) { 1758 /** 1759 * Keyguard settings may eventually be controlled by device policy. 1760 * We check here if keystore is unlocked before installing 1761 * credentials. 1762 * TODO: Do we need a dialog here ? 1763 */ 1764 if (mKeyStore.state() != KeyStore.State.UNLOCKED) { 1765 loge(config.SSID + ": key store is locked"); 1766 break setVariables; 1767 } 1768 1769 try { 1770 /* config passed may include only fields being updated. 1771 * In order to generate the key id, fetch uninitialized 1772 * fields from the currently tracked configuration 1773 */ 1774 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 1775 String keyId = config.getKeyIdForCredentials(currentConfig); 1776 1777 if (!installKeys(enterpriseConfig, keyId)) { 1778 loge(config.SSID + ": failed to install keys"); 1779 break setVariables; 1780 } 1781 } catch (IllegalStateException e) { 1782 loge(config.SSID + " invalid config for key installation"); 1783 break setVariables; 1784 } 1785 } 1786 1787 HashMap<String, String> enterpriseFields = enterpriseConfig.getFields(); 1788 for (String key : enterpriseFields.keySet()) { 1789 String value = enterpriseFields.get(key); 1790 if (!mWifiNative.setNetworkVariable( 1791 netId, 1792 key, 1793 value)) { 1794 removeKeys(enterpriseConfig); 1795 loge(config.SSID + ": failed to set " + key + 1796 ": " + value); 1797 break setVariables; 1798 } 1799 } 1800 } 1801 updateFailed = false; 1802 } //end of setVariables 1803 1804 if (updateFailed) { 1805 if (newNetwork) { 1806 mWifiNative.removeNetwork(netId); 1807 loge("Failed to set a network variable, removed network: " + netId); 1808 } 1809 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1810 } 1811 1812 /* An update of the network variables requires reading them 1813 * back from the supplicant to update mConfiguredNetworks. 1814 * This is because some of the variables (SSID, wep keys & 1815 * passphrases) reflect different values when read back than 1816 * when written. For example, wep key is stored as * irrespective 1817 * of the value sent to the supplicant 1818 */ 1819 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 1820 if (currentConfig == null) { 1821 currentConfig = new WifiConfiguration(); 1822 currentConfig.ipAssignment = IpAssignment.DHCP; 1823 currentConfig.proxySettings = ProxySettings.NONE; 1824 currentConfig.networkId = netId; 1825 } 1826 1827 if (DBG) loge("will read network variables netId=" + Integer.toString(netId)); 1828 1829 readNetworkVariables(currentConfig); 1830 1831 mConfiguredNetworks.put(netId, currentConfig); 1832 mNetworkIds.put(configKey(currentConfig), netId); 1833 1834 NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); 1835 result.setIsNewNetwork(newNetwork); 1836 result.setNetworkId(netId); 1837 return result; 1838 } 1839 1840 1841 public void linkConfiguration(WifiConfiguration config) { 1842 for (WifiConfiguration link : mConfiguredNetworks.values()) { 1843 boolean doLink = false; 1844 1845 if (link.configKey().equals(config.configKey())) { 1846 continue; 1847 } 1848 1849 if (config.defaultGwMacAddress != null && link.defaultGwMacAddress != null) { 1850 //if both default GW are known, compare based on RSSI only if the GW is equal 1851 if (config.defaultGwMacAddress.equals(link.defaultGwMacAddress)) { 1852 1853 if (VDBG) { 1854 loge("linkConfiguration link due to same gw" + link.SSID + 1855 " and " + config.SSID + " GW " + config.defaultGwMacAddress); 1856 } 1857 doLink = true; 1858 } 1859 } else { 1860 if ((config.scanResultCache != null) && (config.scanResultCache.size() <= 5) 1861 && (link.scanResultCache != null) && (link.scanResultCache.size() <= 5)) { 1862 String abssid = ""; 1863 String bbssid = ""; 1864 for (String key : config.scanResultCache.keySet()) { 1865 abssid = key; 1866 } 1867 for (String key : link.scanResultCache.keySet()) { 1868 bbssid = key; 1869 } 1870 if (VDBG) { 1871 loge("linkConfiguration link due to DBDC BSSID match " + link.SSID + 1872 " and " + config.SSID + " bssida " + abssid + " bssidb " + bbssid); 1873 } 1874 if (abssid.regionMatches(true, 0, bbssid, 0, 16)) { 1875 //if first 16 ascii characters of BSSID matches, we assume this is a DBDC 1876 doLink = true; 1877 } 1878 } 1879 } 1880 1881 if (doLink) { 1882 if (VDBG) 1883 loge("linkConfiguration: will link " + link.SSID + " and " + config.SSID); 1884 if (link.linkedConfigurations == null) { 1885 link.linkedConfigurations = new HashMap<String, Integer>(); 1886 } 1887 if (config.linkedConfigurations == null) { 1888 config.linkedConfigurations = new HashMap<String, Integer>(); 1889 } 1890 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 1891 1892 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 1893 1894 } else { 1895 //todo if they are linked, break the link 1896 } 1897 } 1898 } 1899 1900 /* 1901 * We try to link a scan result with a WifiConfiguration for which SSID and ket management dont match, 1902 * for instance, we try identify the 5GHz SSID of a DBDC AP, even though we know only of the 2.4GHz 1903 * 1904 * Obviously, this function is not optimal since it is used to compare every scan 1905 * result with every Saved WifiConfiguration, with a string.equals operation. 1906 * As a speed up, might be better to implement the mConfiguredNetworks store as a 1907 * <String, WifiConfiguration> object instead of a <Integer, WifiConfiguration> object 1908 * so as to speed this up. Also to prevent the tiny probability of hash collision. 1909 * 1910 */ 1911 public WifiConfiguration associateWithConfiguration(ScanResult result) { 1912 String configKey = WifiConfiguration.configKey(result); 1913 if (configKey == null) { 1914 if (DBG) loge("associateWithConfiguration(): no config key " ); 1915 return null; 1916 } 1917 1918 //need to compare with quoted string 1919 String SSID = "\"" + result.SSID + "\""; 1920 1921 WifiConfiguration config = null; 1922 for (WifiConfiguration link : mConfiguredNetworks.values()) { 1923 boolean doLink = false; 1924 1925 if (configKey.equals(link.configKey())) { 1926 if (VDBG) loge("associateWithConfiguration(): found it!!! " + configKey ); 1927 return link; //found it exactly 1928 } 1929 1930 if ((link.scanResultCache != null) && (link.scanResultCache.size() <= 4)) { 1931 String bssid = ""; 1932 for (String key : link.scanResultCache.keySet()) { 1933 bssid = key; 1934 } 1935 1936 if (result.BSSID.regionMatches(true, 0, bssid, 0, 16) 1937 && SSID.regionMatches(false, 0, link.SSID, 0, 3)) { 1938 // if first 16 ascii characters of BSSID matches, and first 3 1939 // characters of SSID match, we assume this is a home setup 1940 // and thus we will try to transfer the password from the known 1941 // BSSID/SSID to the recently found BSSID/SSID 1942 1943 //if (VDBG) 1944 // loge("associateWithConfiguration OK " ); 1945 doLink = true; 1946 } 1947 } 1948 1949 if (doLink) { 1950 //try to make a non verified WifiConfiguration 1951 if (VDBG) { 1952 loge("associateWithConfiguration: will create " + 1953 result.SSID + " and associate it with: " + link.SSID); 1954 } 1955 config = wifiConfigurationFromScanResult(result); 1956 config.selfAdded = true; 1957 if (config != null) { 1958 if (config.allowedKeyManagement.equals(link.allowedKeyManagement) && 1959 config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1960 1961 //transfer the credentials 1962 1963 String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); 1964 if (psk != null) { 1965 1966 1967 config.preSharedKey = psk; 1968 if (VDBG) { 1969 if (config.preSharedKey != null) 1970 loge(" transfer PSK : " + config.preSharedKey); 1971 } 1972 1973 //link configurations 1974 if (link.linkedConfigurations == null) { 1975 link.linkedConfigurations = new HashMap<String, Integer>(); 1976 } 1977 if (config.linkedConfigurations == null) { 1978 config.linkedConfigurations = new HashMap<String, Integer>(); 1979 } 1980 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 1981 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 1982 } else { 1983 config = null; 1984 } 1985 } 1986 } 1987 } else { 1988 //todo if they are linked, break the link 1989 } 1990 } 1991 return config; 1992 } 1993 1994 1995 public WifiConfiguration updateSavedNetworkHistory(ScanResult scanResult) { 1996 WifiConfiguration found = null; 1997 if (scanResult == null) 1998 return found; 1999 2000 //first step, look for this scan Result by SSID + Key Management 2001 String key = WifiConfiguration.configKey(scanResult); 2002 int hash = key.hashCode(); 2003 2004 Integer netId = mNetworkIds.get(hash); 2005 if (netId == null) return null; 2006 WifiConfiguration config = mConfiguredNetworks.get(netId); 2007 if (config != null) { 2008 if (config.scanResultCache == null) { 2009 config.scanResultCache = new HashMap<String, ScanResult>(); 2010 } 2011 if (config.scanResultCache == null) { 2012 return null; 2013 } 2014 //add the scan result to this WifiConfiguration 2015 config.scanResultCache.put(scanResult.BSSID, scanResult); 2016 mConfiguredNetworks.put(netId, config); 2017 linkConfiguration(config); 2018 found = config; 2019 } 2020 2021 if (VDBG) { 2022 config = mConfiguredNetworks.get(netId); 2023 if (config != null) { 2024 if (config.scanResultCache != null) { 2025 loge(" tested " + scanResult.SSID + " " + 2026 scanResult.BSSID + " key : " + key + " num: " + 2027 Integer.toString(config.scanResultCache.size())); 2028 } else { 2029 loge(" tested " + scanResult.SSID + " " + 2030 scanResult.BSSID + " key : " + key); 2031 } 2032 } 2033 } 2034 return found; 2035 2036 } 2037 2038 /* Compare current and new configuration and write to file on change */ 2039 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 2040 WifiConfiguration currentConfig, 2041 WifiConfiguration newConfig) { 2042 boolean ipChanged = false; 2043 boolean proxyChanged = false; 2044 LinkProperties linkProperties = null; 2045 2046 if (VDBG) { 2047 loge("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " + 2048 newConfig.SSID + " path: " + ipConfigFile); 2049 } 2050 2051 2052 switch (newConfig.ipAssignment) { 2053 case STATIC: 2054 Collection<LinkAddress> currentLinkAddresses = currentConfig.linkProperties 2055 .getLinkAddresses(); 2056 Collection<LinkAddress> newLinkAddresses = newConfig.linkProperties 2057 .getLinkAddresses(); 2058 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses(); 2059 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses(); 2060 Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes(); 2061 Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes(); 2062 2063 boolean linkAddressesDiffer = 2064 (currentLinkAddresses.size() != newLinkAddresses.size()) || 2065 !currentLinkAddresses.containsAll(newLinkAddresses); 2066 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || 2067 !currentDnses.containsAll(newDnses); 2068 boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || 2069 !currentRoutes.containsAll(newRoutes); 2070 2071 if ((currentConfig.ipAssignment != newConfig.ipAssignment) || 2072 linkAddressesDiffer || 2073 dnsesDiffer || 2074 routesDiffer) { 2075 ipChanged = true; 2076 } 2077 break; 2078 case DHCP: 2079 if (currentConfig.ipAssignment != newConfig.ipAssignment) { 2080 ipChanged = true; 2081 } 2082 break; 2083 case UNASSIGNED: 2084 /* Ignore */ 2085 break; 2086 default: 2087 loge("Ignore invalid ip assignment during write"); 2088 break; 2089 } 2090 2091 switch (newConfig.proxySettings) { 2092 case STATIC: 2093 case PAC: 2094 ProxyInfo newHttpProxy = newConfig.linkProperties.getHttpProxy(); 2095 ProxyInfo currentHttpProxy = currentConfig.linkProperties.getHttpProxy(); 2096 2097 if (newHttpProxy != null) { 2098 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 2099 } else { 2100 proxyChanged = (currentHttpProxy != null); 2101 } 2102 break; 2103 case NONE: 2104 if (currentConfig.proxySettings != newConfig.proxySettings) { 2105 proxyChanged = true; 2106 } 2107 break; 2108 case UNASSIGNED: 2109 /* Ignore */ 2110 break; 2111 default: 2112 loge("Ignore invalid proxy configuration during write"); 2113 break; 2114 } 2115 2116 if (!ipChanged) { 2117 linkProperties = copyIpSettingsFromConfig(currentConfig); 2118 } else { 2119 currentConfig.ipAssignment = newConfig.ipAssignment; 2120 linkProperties = copyIpSettingsFromConfig(newConfig); 2121 log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " + 2122 linkProperties.toString()); 2123 } 2124 2125 2126 if (!proxyChanged) { 2127 linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy()); 2128 } else { 2129 currentConfig.proxySettings = newConfig.proxySettings; 2130 linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy()); 2131 log("proxy changed SSID = " + currentConfig.SSID); 2132 if (linkProperties.getHttpProxy() != null) { 2133 log(" proxyProperties: " + linkProperties.getHttpProxy().toString()); 2134 } 2135 } 2136 2137 if (ipChanged || proxyChanged) { 2138 currentConfig.linkProperties = linkProperties; 2139 writeIpAndProxyConfigurations(); 2140 sendConfiguredNetworksChangedBroadcast(currentConfig, 2141 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 2142 } 2143 return new NetworkUpdateResult(ipChanged, proxyChanged); 2144 } 2145 2146 private LinkProperties copyIpSettingsFromConfig(WifiConfiguration config) { 2147 LinkProperties linkProperties = new LinkProperties(); 2148 linkProperties.setInterfaceName(config.linkProperties.getInterfaceName()); 2149 for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { 2150 linkProperties.addLinkAddress(linkAddr); 2151 } 2152 for (RouteInfo route : config.linkProperties.getRoutes()) { 2153 linkProperties.addRoute(route); 2154 } 2155 for (InetAddress dns : config.linkProperties.getDnses()) { 2156 linkProperties.addDns(dns); 2157 } 2158 return linkProperties; 2159 } 2160 2161 /** 2162 * Read the variables from the supplicant daemon that are needed to 2163 * fill in the WifiConfiguration object. 2164 * 2165 * @param config the {@link WifiConfiguration} object to be filled in. 2166 */ 2167 private void readNetworkVariables(WifiConfiguration config) { 2168 2169 int netId = config.networkId; 2170 if (netId < 0) 2171 return; 2172 2173 /* 2174 * TODO: maybe should have a native method that takes an array of 2175 * variable names and returns an array of values. But we'd still 2176 * be doing a round trip to the supplicant daemon for each variable. 2177 */ 2178 String value; 2179 2180 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 2181 if (!TextUtils.isEmpty(value)) { 2182 if (value.charAt(0) != '"') { 2183 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 2184 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 2185 //supplicant string 2186 } else { 2187 config.SSID = value; 2188 } 2189 } else { 2190 config.SSID = null; 2191 } 2192 2193 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 2194 if (!TextUtils.isEmpty(value)) { 2195 config.BSSID = value; 2196 } else { 2197 config.BSSID = null; 2198 } 2199 2200 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 2201 config.priority = -1; 2202 if (!TextUtils.isEmpty(value)) { 2203 try { 2204 config.priority = Integer.parseInt(value); 2205 } catch (NumberFormatException ignore) { 2206 } 2207 } 2208 2209 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 2210 config.hiddenSSID = false; 2211 if (!TextUtils.isEmpty(value)) { 2212 try { 2213 config.hiddenSSID = Integer.parseInt(value) != 0; 2214 } catch (NumberFormatException ignore) { 2215 } 2216 } 2217 2218 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 2219 config.wepTxKeyIndex = -1; 2220 if (!TextUtils.isEmpty(value)) { 2221 try { 2222 config.wepTxKeyIndex = Integer.parseInt(value); 2223 } catch (NumberFormatException ignore) { 2224 } 2225 } 2226 2227 for (int i = 0; i < 4; i++) { 2228 value = mWifiNative.getNetworkVariable(netId, 2229 WifiConfiguration.wepKeyVarNames[i]); 2230 if (!TextUtils.isEmpty(value)) { 2231 config.wepKeys[i] = value; 2232 } else { 2233 config.wepKeys[i] = null; 2234 } 2235 } 2236 2237 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 2238 if (!TextUtils.isEmpty(value)) { 2239 config.preSharedKey = value; 2240 } else { 2241 config.preSharedKey = null; 2242 } 2243 2244 value = mWifiNative.getNetworkVariable(config.networkId, 2245 WifiConfiguration.Protocol.varName); 2246 if (!TextUtils.isEmpty(value)) { 2247 String vals[] = value.split(" "); 2248 for (String val : vals) { 2249 int index = 2250 lookupString(val, WifiConfiguration.Protocol.strings); 2251 if (0 <= index) { 2252 config.allowedProtocols.set(index); 2253 } 2254 } 2255 } 2256 2257 value = mWifiNative.getNetworkVariable(config.networkId, 2258 WifiConfiguration.KeyMgmt.varName); 2259 if (!TextUtils.isEmpty(value)) { 2260 String vals[] = value.split(" "); 2261 for (String val : vals) { 2262 int index = 2263 lookupString(val, WifiConfiguration.KeyMgmt.strings); 2264 if (0 <= index) { 2265 config.allowedKeyManagement.set(index); 2266 } 2267 } 2268 } 2269 2270 value = mWifiNative.getNetworkVariable(config.networkId, 2271 WifiConfiguration.AuthAlgorithm.varName); 2272 if (!TextUtils.isEmpty(value)) { 2273 String vals[] = value.split(" "); 2274 for (String val : vals) { 2275 int index = 2276 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 2277 if (0 <= index) { 2278 config.allowedAuthAlgorithms.set(index); 2279 } 2280 } 2281 } 2282 2283 value = mWifiNative.getNetworkVariable(config.networkId, 2284 WifiConfiguration.PairwiseCipher.varName); 2285 if (!TextUtils.isEmpty(value)) { 2286 String vals[] = value.split(" "); 2287 for (String val : vals) { 2288 int index = 2289 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 2290 if (0 <= index) { 2291 config.allowedPairwiseCiphers.set(index); 2292 } 2293 } 2294 } 2295 2296 value = mWifiNative.getNetworkVariable(config.networkId, 2297 WifiConfiguration.GroupCipher.varName); 2298 if (!TextUtils.isEmpty(value)) { 2299 String vals[] = value.split(" "); 2300 for (String val : vals) { 2301 int index = 2302 lookupString(val, WifiConfiguration.GroupCipher.strings); 2303 if (0 <= index) { 2304 config.allowedGroupCiphers.set(index); 2305 } 2306 } 2307 } 2308 2309 if (config.enterpriseConfig == null) { 2310 config.enterpriseConfig = new WifiEnterpriseConfig(); 2311 } 2312 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 2313 for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { 2314 value = mWifiNative.getNetworkVariable(netId, key); 2315 if (!TextUtils.isEmpty(value)) { 2316 enterpriseFields.put(key, removeDoubleQuotes(value)); 2317 } else { 2318 enterpriseFields.put(key, EMPTY_VALUE); 2319 } 2320 } 2321 2322 if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { 2323 saveConfig(); 2324 } 2325 2326 migrateCerts(config.enterpriseConfig); 2327 // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); 2328 } 2329 2330 private static String removeDoubleQuotes(String string) { 2331 int length = string.length(); 2332 if ((length > 1) && (string.charAt(0) == '"') 2333 && (string.charAt(length - 1) == '"')) { 2334 return string.substring(1, length - 1); 2335 } 2336 return string; 2337 } 2338 2339 private static String convertToQuotedString(String string) { 2340 return "\"" + string + "\""; 2341 } 2342 2343 private static String makeString(BitSet set, String[] strings) { 2344 StringBuffer buf = new StringBuffer(); 2345 int nextSetBit = -1; 2346 2347 /* Make sure all set bits are in [0, strings.length) to avoid 2348 * going out of bounds on strings. (Shouldn't happen, but...) */ 2349 set = set.get(0, strings.length); 2350 2351 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 2352 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 2353 } 2354 2355 // remove trailing space 2356 if (set.cardinality() > 0) { 2357 buf.setLength(buf.length() - 1); 2358 } 2359 2360 return buf.toString(); 2361 } 2362 2363 private int lookupString(String string, String[] strings) { 2364 int size = strings.length; 2365 2366 string = string.replace('-', '_'); 2367 2368 for (int i = 0; i < size; i++) 2369 if (string.equals(strings[i])) 2370 return i; 2371 2372 // if we ever get here, we should probably add the 2373 // value to WifiConfiguration to reflect that it's 2374 // supported by the WPA supplicant 2375 loge("Failed to look-up a string: " + string); 2376 2377 return -1; 2378 } 2379 2380 /* return the allowed key management based on a scan result */ 2381 2382 public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) { 2383 WifiConfiguration config = new WifiConfiguration(); 2384 2385 config.SSID = "\"" + result.SSID + "\""; 2386 2387 if (VDBG) { 2388 loge("WifiConfiguration from scan results " + 2389 config.SSID + " cap " + result.capabilities); 2390 } 2391 if (result.capabilities.contains("WEP")) { 2392 config.allowedKeyManagement.set(KeyMgmt.NONE); 2393 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); //? 2394 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 2395 } 2396 2397 if (result.capabilities.contains("PSK")) { 2398 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 2399 } 2400 2401 if (result.capabilities.contains("EAP")) { 2402 //this is probably wrong, as we don't have a way to enter the enterprise config 2403 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 2404 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 2405 } 2406 2407 config.scanResultCache = new HashMap<String, ScanResult>(); 2408 if (config.scanResultCache == null) 2409 return null; 2410 config.scanResultCache.put(result.BSSID, result); 2411 2412 return config; 2413 } 2414 2415 2416 /* Returns a unique for a given configuration */ 2417 private static int configKey(WifiConfiguration config) { 2418 String key = config.configKey(); 2419 return key.hashCode(); 2420 } 2421 2422 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2423 pw.println("WifiConfigStore"); 2424 pw.println("mLastPriority " + mLastPriority); 2425 pw.println("Configured networks"); 2426 for (WifiConfiguration conf : getConfiguredNetworks()) { 2427 pw.println(conf); 2428 } 2429 pw.println(); 2430 2431 if (mLocalLog != null) { 2432 pw.println("WifiConfigStore - Log Begin ----"); 2433 mLocalLog.dump(fd, pw, args); 2434 pw.println("WifiConfigStore - Log End ----"); 2435 } 2436 } 2437 2438 public String getConfigFile() { 2439 return ipConfigFile; 2440 } 2441 2442 private void loge(String s) { 2443 long now = SystemClock.elapsedRealtimeNanos(); 2444 String ts = String.format("[%,d us] ", now/1000); 2445 Log.e(TAG, ts+s+ " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2446 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2447 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2448 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2449 } 2450 2451 private void log(String s) { 2452 Log.d(TAG, s); 2453 } 2454 2455 private void localLog(String s) { 2456 if (mLocalLog != null) { 2457 mLocalLog.log(s); 2458 } 2459 } 2460 2461 private void localLog(String s, int netId) { 2462 if (mLocalLog == null) { 2463 return; 2464 } 2465 2466 WifiConfiguration config; 2467 synchronized(mConfiguredNetworks) { 2468 config = mConfiguredNetworks.get(netId); 2469 } 2470 2471 if (config != null) { 2472 mLocalLog.log(s + " " + config.getPrintableSsid()); 2473 } else { 2474 mLocalLog.log(s + " " + netId); 2475 } 2476 } 2477 2478 // Certificate and private key management for EnterpriseConfig 2479 static boolean needsKeyStore(WifiEnterpriseConfig config) { 2480 // Has no keys to be installed 2481 if (config.getClientCertificate() == null && config.getCaCertificate() == null) 2482 return false; 2483 return true; 2484 } 2485 2486 static boolean isHardwareBackedKey(PrivateKey key) { 2487 return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 2488 } 2489 2490 static boolean hasHardwareBackedKey(Certificate certificate) { 2491 return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 2492 } 2493 2494 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 2495 String client = config.getClientCertificateAlias(); 2496 if (!TextUtils.isEmpty(client)) { 2497 // a valid client certificate is configured 2498 2499 // BUGBUG: keyStore.get() never returns certBytes; because it is not 2500 // taking WIFI_UID as a parameter. It always looks for certificate 2501 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 2502 // all certificates need software keystore until we get the get() API 2503 // fixed. 2504 2505 return true; 2506 } 2507 2508 /* 2509 try { 2510 2511 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 2512 .USER_CERTIFICATE + client); 2513 2514 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 2515 if (factory == null) { 2516 Slog.e(TAG, "Error getting certificate factory"); 2517 return; 2518 } 2519 2520 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 2521 if (certBytes != null) { 2522 Certificate cert = (X509Certificate) factory.generateCertificate( 2523 new ByteArrayInputStream(certBytes)); 2524 2525 if (cert != null) { 2526 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 2527 2528 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 2529 .USER_CERTIFICATE + client); 2530 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 2531 "does not need" ) + " software key store"); 2532 } else { 2533 Slog.d(TAG, "could not generate certificate"); 2534 } 2535 } else { 2536 Slog.e(TAG, "Could not load client certificate " + Credentials 2537 .USER_CERTIFICATE + client); 2538 mNeedsSoftwareKeystore = true; 2539 } 2540 2541 } catch(CertificateException e) { 2542 Slog.e(TAG, "Could not read certificates"); 2543 mCaCert = null; 2544 mClientCertificate = null; 2545 } 2546 */ 2547 2548 return false; 2549 } 2550 2551 void handleAuthenticationFailure(int netId) { 2552 WifiConfiguration config = mConfiguredNetworks.get(netId); 2553 if (config != null && config.selfAdded) { 2554 loge("Authentication failure for " + config.configKey() + 2555 " had autoJoinstatus=" + Integer.toString(config.autoJoinStatus) 2556 + " self added " + config.selfAdded + " ephemeral " + config.ephemeral); 2557 if (config.selfAdded) { 2558 disableNetwork(config.networkId, WifiConfiguration.DISABLED_AUTH_FAILURE); 2559 config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE; 2560 } 2561 } 2562 } 2563 2564 boolean installKeys(WifiEnterpriseConfig config, String name) { 2565 boolean ret = true; 2566 String privKeyName = Credentials.USER_PRIVATE_KEY + name; 2567 String userCertName = Credentials.USER_CERTIFICATE + name; 2568 String caCertName = Credentials.CA_CERTIFICATE + name; 2569 if (config.getClientCertificate() != null) { 2570 byte[] privKeyData = config.getClientPrivateKey().getEncoded(); 2571 if (isHardwareBackedKey(config.getClientPrivateKey())) { 2572 // Hardware backed key store is secure enough to store keys un-encrypted, this 2573 // removes the need for user to punch a PIN to get access to these keys 2574 if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); 2575 ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, 2576 KeyStore.FLAG_NONE); 2577 } else { 2578 // Software backed key store is NOT secure enough to store keys un-encrypted. 2579 // Save keys encrypted so they are protected with user's PIN. User will 2580 // have to unlock phone before being able to use these keys and connect to 2581 // networks. 2582 if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); 2583 ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 2584 KeyStore.FLAG_ENCRYPTED); 2585 } 2586 if (ret == false) { 2587 return ret; 2588 } 2589 2590 ret = putCertInKeyStore(userCertName, config.getClientCertificate()); 2591 if (ret == false) { 2592 // Remove private key installed 2593 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 2594 return ret; 2595 } 2596 } 2597 2598 if (config.getCaCertificate() != null) { 2599 ret = putCertInKeyStore(caCertName, config.getCaCertificate()); 2600 if (ret == false) { 2601 if (config.getClientCertificate() != null) { 2602 // Remove client key+cert 2603 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 2604 mKeyStore.delete(userCertName, Process.WIFI_UID); 2605 } 2606 return ret; 2607 } 2608 } 2609 2610 // Set alias names 2611 if (config.getClientCertificate() != null) { 2612 config.setClientCertificateAlias(name); 2613 config.resetClientKeyEntry(); 2614 } 2615 2616 if (config.getCaCertificate() != null) { 2617 config.setCaCertificateAlias(name); 2618 config.resetCaCertificate(); 2619 } 2620 2621 return ret; 2622 } 2623 2624 private boolean putCertInKeyStore(String name, Certificate cert) { 2625 try { 2626 byte[] certData = Credentials.convertToPem(cert); 2627 if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); 2628 return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 2629 2630 } catch (IOException e1) { 2631 return false; 2632 } catch (CertificateException e2) { 2633 return false; 2634 } 2635 } 2636 2637 void removeKeys(WifiEnterpriseConfig config) { 2638 String client = config.getClientCertificateAlias(); 2639 // a valid client certificate is configured 2640 if (!TextUtils.isEmpty(client)) { 2641 if (DBG) Log.d(TAG, "removing client private key and user cert"); 2642 mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 2643 mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 2644 } 2645 2646 String ca = config.getCaCertificateAlias(); 2647 // a valid ca certificate is configured 2648 if (!TextUtils.isEmpty(ca)) { 2649 if (DBG) Log.d(TAG, "removing CA cert"); 2650 mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 2651 } 2652 } 2653 2654 2655 /** Migrates the old style TLS config to the new config style. This should only be used 2656 * when restoring an old wpa_supplicant.conf or upgrading from a previous 2657 * platform version. 2658 * @return true if the config was updated 2659 * @hide 2660 */ 2661 boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { 2662 String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 2663 /* 2664 * If the old configuration value is not present, then there is nothing 2665 * to do. 2666 */ 2667 if (TextUtils.isEmpty(oldPrivateKey)) { 2668 return false; 2669 } else { 2670 // Also ignore it if it's empty quotes. 2671 oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 2672 if (TextUtils.isEmpty(oldPrivateKey)) { 2673 return false; 2674 } 2675 } 2676 2677 config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE); 2678 config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, 2679 WifiEnterpriseConfig.ENGINE_ID_KEYSTORE); 2680 2681 /* 2682 * The old key started with the keystore:// URI prefix, but we don't 2683 * need that anymore. Trim it off if it exists. 2684 */ 2685 final String keyName; 2686 if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) { 2687 keyName = new String( 2688 oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length())); 2689 } else { 2690 keyName = oldPrivateKey; 2691 } 2692 config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName); 2693 2694 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY, 2695 config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 2696 2697 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY, 2698 config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 2699 2700 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, 2701 config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 2702 2703 // Remove old private_key string so we don't run this again. 2704 mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 2705 2706 return true; 2707 } 2708 2709 /** Migrate certs from global pool to wifi UID if not already done */ 2710 void migrateCerts(WifiEnterpriseConfig config) { 2711 String client = config.getClientCertificateAlias(); 2712 // a valid client certificate is configured 2713 if (!TextUtils.isEmpty(client)) { 2714 if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 2715 mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 2716 Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 2717 mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 2718 Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 2719 } 2720 } 2721 2722 String ca = config.getCaCertificateAlias(); 2723 // a valid ca certificate is configured 2724 if (!TextUtils.isEmpty(ca)) { 2725 if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 2726 mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 2727 Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 2728 } 2729 } 2730 } 2731 2732} 2733 2734