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