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