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