WifiConfigStore.java revision 952d359198cb1f04c180fc0f795dc316fe97cb5e
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 = configKeyFromScanResult(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() <= 5)) { 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 if (config != null) { 1957 if (config.allowedKeyManagement.equals(link.allowedKeyManagement) && 1958 config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1959 1960 //transfer the credentials 1961 1962 String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); 1963 if (psk != null) { 1964 1965 1966 config.preSharedKey = psk; 1967 if (VDBG) { 1968 if (config.preSharedKey != null) 1969 loge(" transfer PSK : " + config.preSharedKey); 1970 } 1971 1972 //link configurations 1973 if (link.linkedConfigurations == null) { 1974 link.linkedConfigurations = new HashMap<String, Integer>(); 1975 } 1976 if (config.linkedConfigurations == null) { 1977 config.linkedConfigurations = new HashMap<String, Integer>(); 1978 } 1979 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 1980 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 1981 } else { 1982 config = null; 1983 } 1984 } 1985 } 1986 } else { 1987 //todo if they are linked, break the link 1988 } 1989 } 1990 return config; 1991 } 1992 1993 1994 public WifiConfiguration updateSavedNetworkHistory(ScanResult scanResult) { 1995 WifiConfiguration found = null; 1996 if (scanResult == null) 1997 return found; 1998 1999 //first step, look for this scan Result by SSID + Key Management 2000 String key = configKeyFromScanResult(scanResult); 2001 int hash = key.hashCode(); 2002 2003 Integer netId = mNetworkIds.get(hash); 2004 if (netId == null) return null; 2005 WifiConfiguration config = mConfiguredNetworks.get(netId); 2006 if (config != null) { 2007 if (config.scanResultCache == null) { 2008 config.scanResultCache = new HashMap<String, ScanResult>(); 2009 } 2010 if (config.scanResultCache == null) { 2011 return null; 2012 } 2013 //add the scan result to this WifiConfiguration 2014 config.scanResultCache.put(scanResult.BSSID, scanResult); 2015 mConfiguredNetworks.put(netId, config); 2016 linkConfiguration(config); 2017 found = config; 2018 } 2019 2020 if (VDBG) { 2021 config = mConfiguredNetworks.get(netId); 2022 if (config != null) { 2023 if (config.scanResultCache != null) { 2024 loge(" tested " + scanResult.SSID + " " + 2025 scanResult.BSSID + " key : " + key + " num: " + 2026 Integer.toString(config.scanResultCache.size())); 2027 } else { 2028 loge(" tested " + scanResult.SSID + " " + 2029 scanResult.BSSID + " key : " + key); 2030 } 2031 } 2032 } 2033 return found; 2034 2035 } 2036 2037 /* Compare current and new configuration and write to file on change */ 2038 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 2039 WifiConfiguration currentConfig, 2040 WifiConfiguration newConfig) { 2041 boolean ipChanged = false; 2042 boolean proxyChanged = false; 2043 LinkProperties linkProperties = null; 2044 2045 if (VDBG) { 2046 loge("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " + 2047 newConfig.SSID + " path: " + ipConfigFile); 2048 } 2049 2050 2051 switch (newConfig.ipAssignment) { 2052 case STATIC: 2053 Collection<LinkAddress> currentLinkAddresses = currentConfig.linkProperties 2054 .getLinkAddresses(); 2055 Collection<LinkAddress> newLinkAddresses = newConfig.linkProperties 2056 .getLinkAddresses(); 2057 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses(); 2058 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses(); 2059 Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes(); 2060 Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes(); 2061 2062 boolean linkAddressesDiffer = 2063 (currentLinkAddresses.size() != newLinkAddresses.size()) || 2064 !currentLinkAddresses.containsAll(newLinkAddresses); 2065 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || 2066 !currentDnses.containsAll(newDnses); 2067 boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || 2068 !currentRoutes.containsAll(newRoutes); 2069 2070 if ((currentConfig.ipAssignment != newConfig.ipAssignment) || 2071 linkAddressesDiffer || 2072 dnsesDiffer || 2073 routesDiffer) { 2074 ipChanged = true; 2075 } 2076 break; 2077 case DHCP: 2078 if (currentConfig.ipAssignment != newConfig.ipAssignment) { 2079 ipChanged = true; 2080 } 2081 break; 2082 case UNASSIGNED: 2083 /* Ignore */ 2084 break; 2085 default: 2086 loge("Ignore invalid ip assignment during write"); 2087 break; 2088 } 2089 2090 switch (newConfig.proxySettings) { 2091 case STATIC: 2092 case PAC: 2093 ProxyInfo newHttpProxy = newConfig.linkProperties.getHttpProxy(); 2094 ProxyInfo currentHttpProxy = currentConfig.linkProperties.getHttpProxy(); 2095 2096 if (newHttpProxy != null) { 2097 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 2098 } else { 2099 proxyChanged = (currentHttpProxy != null); 2100 } 2101 break; 2102 case NONE: 2103 if (currentConfig.proxySettings != newConfig.proxySettings) { 2104 proxyChanged = true; 2105 } 2106 break; 2107 case UNASSIGNED: 2108 /* Ignore */ 2109 break; 2110 default: 2111 loge("Ignore invalid proxy configuration during write"); 2112 break; 2113 } 2114 2115 if (!ipChanged) { 2116 linkProperties = copyIpSettingsFromConfig(currentConfig); 2117 } else { 2118 currentConfig.ipAssignment = newConfig.ipAssignment; 2119 linkProperties = copyIpSettingsFromConfig(newConfig); 2120 log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " + 2121 linkProperties.toString()); 2122 } 2123 2124 2125 if (!proxyChanged) { 2126 linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy()); 2127 } else { 2128 currentConfig.proxySettings = newConfig.proxySettings; 2129 linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy()); 2130 log("proxy changed SSID = " + currentConfig.SSID); 2131 if (linkProperties.getHttpProxy() != null) { 2132 log(" proxyProperties: " + linkProperties.getHttpProxy().toString()); 2133 } 2134 } 2135 2136 if (ipChanged || proxyChanged) { 2137 currentConfig.linkProperties = linkProperties; 2138 writeIpAndProxyConfigurations(); 2139 sendConfiguredNetworksChangedBroadcast(currentConfig, 2140 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 2141 } 2142 return new NetworkUpdateResult(ipChanged, proxyChanged); 2143 } 2144 2145 private LinkProperties copyIpSettingsFromConfig(WifiConfiguration config) { 2146 LinkProperties linkProperties = new LinkProperties(); 2147 linkProperties.setInterfaceName(config.linkProperties.getInterfaceName()); 2148 for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { 2149 linkProperties.addLinkAddress(linkAddr); 2150 } 2151 for (RouteInfo route : config.linkProperties.getRoutes()) { 2152 linkProperties.addRoute(route); 2153 } 2154 for (InetAddress dns : config.linkProperties.getDnses()) { 2155 linkProperties.addDns(dns); 2156 } 2157 return linkProperties; 2158 } 2159 2160 /** 2161 * Read the variables from the supplicant daemon that are needed to 2162 * fill in the WifiConfiguration object. 2163 * 2164 * @param config the {@link WifiConfiguration} object to be filled in. 2165 */ 2166 private void readNetworkVariables(WifiConfiguration config) { 2167 2168 int netId = config.networkId; 2169 if (netId < 0) 2170 return; 2171 2172 /* 2173 * TODO: maybe should have a native method that takes an array of 2174 * variable names and returns an array of values. But we'd still 2175 * be doing a round trip to the supplicant daemon for each variable. 2176 */ 2177 String value; 2178 2179 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 2180 if (!TextUtils.isEmpty(value)) { 2181 if (value.charAt(0) != '"') { 2182 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 2183 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 2184 //supplicant string 2185 } else { 2186 config.SSID = value; 2187 } 2188 } else { 2189 config.SSID = null; 2190 } 2191 2192 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 2193 if (!TextUtils.isEmpty(value)) { 2194 config.BSSID = value; 2195 } else { 2196 config.BSSID = null; 2197 } 2198 2199 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 2200 config.priority = -1; 2201 if (!TextUtils.isEmpty(value)) { 2202 try { 2203 config.priority = Integer.parseInt(value); 2204 } catch (NumberFormatException ignore) { 2205 } 2206 } 2207 2208 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 2209 config.hiddenSSID = false; 2210 if (!TextUtils.isEmpty(value)) { 2211 try { 2212 config.hiddenSSID = Integer.parseInt(value) != 0; 2213 } catch (NumberFormatException ignore) { 2214 } 2215 } 2216 2217 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 2218 config.wepTxKeyIndex = -1; 2219 if (!TextUtils.isEmpty(value)) { 2220 try { 2221 config.wepTxKeyIndex = Integer.parseInt(value); 2222 } catch (NumberFormatException ignore) { 2223 } 2224 } 2225 2226 for (int i = 0; i < 4; i++) { 2227 value = mWifiNative.getNetworkVariable(netId, 2228 WifiConfiguration.wepKeyVarNames[i]); 2229 if (!TextUtils.isEmpty(value)) { 2230 config.wepKeys[i] = value; 2231 } else { 2232 config.wepKeys[i] = null; 2233 } 2234 } 2235 2236 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 2237 if (!TextUtils.isEmpty(value)) { 2238 config.preSharedKey = value; 2239 } else { 2240 config.preSharedKey = null; 2241 } 2242 2243 value = mWifiNative.getNetworkVariable(config.networkId, 2244 WifiConfiguration.Protocol.varName); 2245 if (!TextUtils.isEmpty(value)) { 2246 String vals[] = value.split(" "); 2247 for (String val : vals) { 2248 int index = 2249 lookupString(val, WifiConfiguration.Protocol.strings); 2250 if (0 <= index) { 2251 config.allowedProtocols.set(index); 2252 } 2253 } 2254 } 2255 2256 value = mWifiNative.getNetworkVariable(config.networkId, 2257 WifiConfiguration.KeyMgmt.varName); 2258 if (!TextUtils.isEmpty(value)) { 2259 String vals[] = value.split(" "); 2260 for (String val : vals) { 2261 int index = 2262 lookupString(val, WifiConfiguration.KeyMgmt.strings); 2263 if (0 <= index) { 2264 config.allowedKeyManagement.set(index); 2265 } 2266 } 2267 } 2268 2269 value = mWifiNative.getNetworkVariable(config.networkId, 2270 WifiConfiguration.AuthAlgorithm.varName); 2271 if (!TextUtils.isEmpty(value)) { 2272 String vals[] = value.split(" "); 2273 for (String val : vals) { 2274 int index = 2275 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 2276 if (0 <= index) { 2277 config.allowedAuthAlgorithms.set(index); 2278 } 2279 } 2280 } 2281 2282 value = mWifiNative.getNetworkVariable(config.networkId, 2283 WifiConfiguration.PairwiseCipher.varName); 2284 if (!TextUtils.isEmpty(value)) { 2285 String vals[] = value.split(" "); 2286 for (String val : vals) { 2287 int index = 2288 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 2289 if (0 <= index) { 2290 config.allowedPairwiseCiphers.set(index); 2291 } 2292 } 2293 } 2294 2295 value = mWifiNative.getNetworkVariable(config.networkId, 2296 WifiConfiguration.GroupCipher.varName); 2297 if (!TextUtils.isEmpty(value)) { 2298 String vals[] = value.split(" "); 2299 for (String val : vals) { 2300 int index = 2301 lookupString(val, WifiConfiguration.GroupCipher.strings); 2302 if (0 <= index) { 2303 config.allowedGroupCiphers.set(index); 2304 } 2305 } 2306 } 2307 2308 if (config.enterpriseConfig == null) { 2309 config.enterpriseConfig = new WifiEnterpriseConfig(); 2310 } 2311 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 2312 for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { 2313 value = mWifiNative.getNetworkVariable(netId, key); 2314 if (!TextUtils.isEmpty(value)) { 2315 enterpriseFields.put(key, removeDoubleQuotes(value)); 2316 } else { 2317 enterpriseFields.put(key, EMPTY_VALUE); 2318 } 2319 } 2320 2321 if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { 2322 saveConfig(); 2323 } 2324 2325 migrateCerts(config.enterpriseConfig); 2326 // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); 2327 } 2328 2329 private static String removeDoubleQuotes(String string) { 2330 int length = string.length(); 2331 if ((length > 1) && (string.charAt(0) == '"') 2332 && (string.charAt(length - 1) == '"')) { 2333 return string.substring(1, length - 1); 2334 } 2335 return string; 2336 } 2337 2338 private static String convertToQuotedString(String string) { 2339 return "\"" + string + "\""; 2340 } 2341 2342 private static String makeString(BitSet set, String[] strings) { 2343 StringBuffer buf = new StringBuffer(); 2344 int nextSetBit = -1; 2345 2346 /* Make sure all set bits are in [0, strings.length) to avoid 2347 * going out of bounds on strings. (Shouldn't happen, but...) */ 2348 set = set.get(0, strings.length); 2349 2350 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 2351 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 2352 } 2353 2354 // remove trailing space 2355 if (set.cardinality() > 0) { 2356 buf.setLength(buf.length() - 1); 2357 } 2358 2359 return buf.toString(); 2360 } 2361 2362 private int lookupString(String string, String[] strings) { 2363 int size = strings.length; 2364 2365 string = string.replace('-', '_'); 2366 2367 for (int i = 0; i < size; i++) 2368 if (string.equals(strings[i])) 2369 return i; 2370 2371 // if we ever get here, we should probably add the 2372 // value to WifiConfiguration to reflect that it's 2373 // supported by the WPA supplicant 2374 loge("Failed to look-up a string: " + string); 2375 2376 return -1; 2377 } 2378 2379 2380 /* return the config key string based on a scan result */ 2381 2382 public String configKeyFromScanResult(ScanResult result) { 2383 String key = "\"" + result.SSID + "\""; 2384 2385 if (result.capabilities.contains("WEP")) { 2386 key = key + "-WEP"; 2387 } 2388 2389 if (result.capabilities.contains("PSK")) { 2390 key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK]; 2391 } 2392 2393 if (result.capabilities.contains("EAP")) { 2394 key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP]; 2395 } 2396 2397 return key; 2398 } 2399 2400 /* return the allowed key management based on a scan result */ 2401 2402 public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) { 2403 WifiConfiguration config = new WifiConfiguration(); 2404 2405 config.SSID = "\"" + result.SSID + "\""; 2406 2407 if (VDBG) { 2408 loge("WifiConfiguration from scan results " + 2409 config.SSID + " cap " + result.capabilities); 2410 } 2411 if (result.capabilities.contains("WEP")) { 2412 config.allowedKeyManagement.set(KeyMgmt.NONE); 2413 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); //? 2414 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 2415 } 2416 2417 if (result.capabilities.contains("PSK")) { 2418 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 2419 } 2420 2421 if (result.capabilities.contains("EAP")) { 2422 //this is probably wrong, as we don't have a way to enter the enterprise config 2423 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 2424 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 2425 } 2426 2427 config.scanResultCache = new HashMap<String, ScanResult>(); 2428 if (config.scanResultCache == null) 2429 return null; 2430 config.scanResultCache.put(result.BSSID, result); 2431 2432 return config; 2433 } 2434 2435 2436 /* Returns a unique for a given configuration */ 2437 private static int configKey(WifiConfiguration config) { 2438 String key = config.configKey(); 2439 return key.hashCode(); 2440 } 2441 2442 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2443 pw.println("WifiConfigStore"); 2444 pw.println("mLastPriority " + mLastPriority); 2445 pw.println("Configured networks"); 2446 for (WifiConfiguration conf : getConfiguredNetworks()) { 2447 pw.println(conf); 2448 } 2449 pw.println(); 2450 2451 if (mLocalLog != null) { 2452 pw.println("WifiConfigStore - Log Begin ----"); 2453 mLocalLog.dump(fd, pw, args); 2454 pw.println("WifiConfigStore - Log End ----"); 2455 } 2456 } 2457 2458 public String getConfigFile() { 2459 return ipConfigFile; 2460 } 2461 2462 private void loge(String s) { 2463 long now = SystemClock.elapsedRealtimeNanos(); 2464 String ts = String.format("[%,d us] ", now/1000); 2465 Log.e(TAG, ts+s+ " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2466 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2467 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2468 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2469 } 2470 2471 private void log(String s) { 2472 Log.d(TAG, s); 2473 } 2474 2475 private void localLog(String s) { 2476 if (mLocalLog != null) { 2477 mLocalLog.log(s); 2478 } 2479 } 2480 2481 private void localLog(String s, int netId) { 2482 if (mLocalLog == null) { 2483 return; 2484 } 2485 2486 WifiConfiguration config; 2487 synchronized(mConfiguredNetworks) { 2488 config = mConfiguredNetworks.get(netId); 2489 } 2490 2491 if (config != null) { 2492 mLocalLog.log(s + " " + config.getPrintableSsid()); 2493 } else { 2494 mLocalLog.log(s + " " + netId); 2495 } 2496 } 2497 2498 // Certificate and private key management for EnterpriseConfig 2499 static boolean needsKeyStore(WifiEnterpriseConfig config) { 2500 // Has no keys to be installed 2501 if (config.getClientCertificate() == null && config.getCaCertificate() == null) 2502 return false; 2503 return true; 2504 } 2505 2506 static boolean isHardwareBackedKey(PrivateKey key) { 2507 return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 2508 } 2509 2510 static boolean hasHardwareBackedKey(Certificate certificate) { 2511 return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 2512 } 2513 2514 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 2515 String client = config.getClientCertificateAlias(); 2516 if (!TextUtils.isEmpty(client)) { 2517 // a valid client certificate is configured 2518 2519 // BUGBUG: keyStore.get() never returns certBytes; because it is not 2520 // taking WIFI_UID as a parameter. It always looks for certificate 2521 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 2522 // all certificates need software keystore until we get the get() API 2523 // fixed. 2524 2525 return true; 2526 } 2527 2528 /* 2529 try { 2530 2531 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 2532 .USER_CERTIFICATE + client); 2533 2534 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 2535 if (factory == null) { 2536 Slog.e(TAG, "Error getting certificate factory"); 2537 return; 2538 } 2539 2540 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 2541 if (certBytes != null) { 2542 Certificate cert = (X509Certificate) factory.generateCertificate( 2543 new ByteArrayInputStream(certBytes)); 2544 2545 if (cert != null) { 2546 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 2547 2548 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 2549 .USER_CERTIFICATE + client); 2550 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 2551 "does not need" ) + " software key store"); 2552 } else { 2553 Slog.d(TAG, "could not generate certificate"); 2554 } 2555 } else { 2556 Slog.e(TAG, "Could not load client certificate " + Credentials 2557 .USER_CERTIFICATE + client); 2558 mNeedsSoftwareKeystore = true; 2559 } 2560 2561 } catch(CertificateException e) { 2562 Slog.e(TAG, "Could not read certificates"); 2563 mCaCert = null; 2564 mClientCertificate = null; 2565 } 2566 */ 2567 2568 return false; 2569 } 2570 2571 void handleAuthenticationFailure(int netId) { 2572 WifiConfiguration config = mConfiguredNetworks.get(netId); 2573 if (config != null) { 2574 loge("Authentication failure for " + config.configKey() + 2575 " had autoJoinstatus=" + Integer.toString(config.autoJoinStatus)); 2576 disableNetwork(config.networkId, WifiConfiguration.DISABLED_AUTH_FAILURE); 2577 config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE; 2578 } 2579 } 2580 2581 boolean installKeys(WifiEnterpriseConfig config, String name) { 2582 boolean ret = true; 2583 String privKeyName = Credentials.USER_PRIVATE_KEY + name; 2584 String userCertName = Credentials.USER_CERTIFICATE + name; 2585 String caCertName = Credentials.CA_CERTIFICATE + name; 2586 if (config.getClientCertificate() != null) { 2587 byte[] privKeyData = config.getClientPrivateKey().getEncoded(); 2588 if (isHardwareBackedKey(config.getClientPrivateKey())) { 2589 // Hardware backed key store is secure enough to store keys un-encrypted, this 2590 // removes the need for user to punch a PIN to get access to these keys 2591 if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); 2592 ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, 2593 KeyStore.FLAG_NONE); 2594 } else { 2595 // Software backed key store is NOT secure enough to store keys un-encrypted. 2596 // Save keys encrypted so they are protected with user's PIN. User will 2597 // have to unlock phone before being able to use these keys and connect to 2598 // networks. 2599 if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); 2600 ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 2601 KeyStore.FLAG_ENCRYPTED); 2602 } 2603 if (ret == false) { 2604 return ret; 2605 } 2606 2607 ret = putCertInKeyStore(userCertName, config.getClientCertificate()); 2608 if (ret == false) { 2609 // Remove private key installed 2610 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 2611 return ret; 2612 } 2613 } 2614 2615 if (config.getCaCertificate() != null) { 2616 ret = putCertInKeyStore(caCertName, config.getCaCertificate()); 2617 if (ret == false) { 2618 if (config.getClientCertificate() != null) { 2619 // Remove client key+cert 2620 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 2621 mKeyStore.delete(userCertName, Process.WIFI_UID); 2622 } 2623 return ret; 2624 } 2625 } 2626 2627 // Set alias names 2628 if (config.getClientCertificate() != null) { 2629 config.setClientCertificateAlias(name); 2630 config.resetClientKeyEntry(); 2631 } 2632 2633 if (config.getCaCertificate() != null) { 2634 config.setCaCertificateAlias(name); 2635 config.resetCaCertificate(); 2636 } 2637 2638 return ret; 2639 } 2640 2641 private boolean putCertInKeyStore(String name, Certificate cert) { 2642 try { 2643 byte[] certData = Credentials.convertToPem(cert); 2644 if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); 2645 return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 2646 2647 } catch (IOException e1) { 2648 return false; 2649 } catch (CertificateException e2) { 2650 return false; 2651 } 2652 } 2653 2654 void removeKeys(WifiEnterpriseConfig config) { 2655 String client = config.getClientCertificateAlias(); 2656 // a valid client certificate is configured 2657 if (!TextUtils.isEmpty(client)) { 2658 if (DBG) Log.d(TAG, "removing client private key and user cert"); 2659 mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 2660 mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 2661 } 2662 2663 String ca = config.getCaCertificateAlias(); 2664 // a valid ca certificate is configured 2665 if (!TextUtils.isEmpty(ca)) { 2666 if (DBG) Log.d(TAG, "removing CA cert"); 2667 mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 2668 } 2669 } 2670 2671 2672 /** Migrates the old style TLS config to the new config style. This should only be used 2673 * when restoring an old wpa_supplicant.conf or upgrading from a previous 2674 * platform version. 2675 * @return true if the config was updated 2676 * @hide 2677 */ 2678 boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { 2679 String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 2680 /* 2681 * If the old configuration value is not present, then there is nothing 2682 * to do. 2683 */ 2684 if (TextUtils.isEmpty(oldPrivateKey)) { 2685 return false; 2686 } else { 2687 // Also ignore it if it's empty quotes. 2688 oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 2689 if (TextUtils.isEmpty(oldPrivateKey)) { 2690 return false; 2691 } 2692 } 2693 2694 config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE); 2695 config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, 2696 WifiEnterpriseConfig.ENGINE_ID_KEYSTORE); 2697 2698 /* 2699 * The old key started with the keystore:// URI prefix, but we don't 2700 * need that anymore. Trim it off if it exists. 2701 */ 2702 final String keyName; 2703 if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) { 2704 keyName = new String( 2705 oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length())); 2706 } else { 2707 keyName = oldPrivateKey; 2708 } 2709 config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName); 2710 2711 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY, 2712 config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 2713 2714 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY, 2715 config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 2716 2717 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, 2718 config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 2719 2720 // Remove old private_key string so we don't run this again. 2721 mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 2722 2723 return true; 2724 } 2725 2726 /** Migrate certs from global pool to wifi UID if not already done */ 2727 void migrateCerts(WifiEnterpriseConfig config) { 2728 String client = config.getClientCertificateAlias(); 2729 // a valid client certificate is configured 2730 if (!TextUtils.isEmpty(client)) { 2731 if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 2732 mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 2733 Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 2734 mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 2735 Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 2736 } 2737 } 2738 2739 String ca = config.getCaCertificateAlias(); 2740 // a valid ca certificate is configured 2741 if (!TextUtils.isEmpty(ca)) { 2742 if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 2743 mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 2744 Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 2745 } 2746 } 2747 } 2748 2749} 2750 2751