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