WifiConfigStore.java revision 439935a9ec391392a1aea323d7f18c328fea2490
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import android.content.Context; 20import android.content.Intent; 21import android.net.LinkAddress; 22import android.net.LinkProperties; 23import android.net.NetworkUtils; 24import android.net.NetworkInfo.DetailedState; 25import android.net.ProxyInfo; 26import android.net.RouteInfo; 27import android.net.wifi.WifiConfiguration; 28import android.net.wifi.WifiConfiguration.IpAssignment; 29import android.net.wifi.WifiConfiguration.KeyMgmt; 30import android.net.wifi.WifiConfiguration.ProxySettings; 31import android.net.wifi.WifiConfiguration.Status; 32import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 33 34import android.net.wifi.WifiEnterpriseConfig; 35import android.net.wifi.WifiManager; 36import android.net.wifi.WifiSsid; 37import android.net.wifi.WpsInfo; 38import android.net.wifi.WpsResult; 39import android.os.Environment; 40import android.os.FileObserver; 41import android.os.Handler; 42import android.os.HandlerThread; 43import android.os.Process; 44import android.os.UserHandle; 45import android.security.Credentials; 46import android.security.KeyChain; 47import android.security.KeyStore; 48import android.text.TextUtils; 49import android.util.LocalLog; 50import android.util.Log; 51 52import java.io.BufferedInputStream; 53import java.io.BufferedOutputStream; 54import java.io.BufferedReader; 55import java.io.DataInputStream; 56import java.io.DataOutputStream; 57import java.io.EOFException; 58import java.io.File; 59import java.io.FileDescriptor; 60import java.io.FileInputStream; 61import java.io.FileNotFoundException; 62import java.io.FileOutputStream; 63import java.io.FileReader; 64import java.io.IOException; 65import java.io.PrintWriter; 66import java.net.InetAddress; 67import java.security.PrivateKey; 68import java.security.cert.Certificate; 69import java.security.cert.CertificateException; 70import java.util.ArrayList; 71import java.util.BitSet; 72import java.util.Collection; 73import java.util.HashMap; 74import java.util.List; 75 76/** 77 * This class provides the API to manage configured 78 * wifi networks. The API is not thread safe is being 79 * used only from WifiStateMachine. 80 * 81 * It deals with the following 82 * - Add/update/remove a WifiConfiguration 83 * The configuration contains two types of information. 84 * = IP and proxy configuration that is handled by WifiConfigStore and 85 * is saved to disk on any change. 86 * 87 * The format of configuration file is as follows: 88 * <version> 89 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 90 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 91 * .. 92 * 93 * (key, value) pairs for a given network are grouped together and can 94 * be in any order. A EOS at the end of a set of (key, value) pairs 95 * indicates that the next set of (key, value) pairs are for a new 96 * network. A network is identified by a unique ID_KEY. If there is no 97 * ID_KEY in the (key, value) pairs, the data is discarded. 98 * 99 * An invalid version on read would result in discarding the contents of 100 * the file. On the next write, the latest version is written to file. 101 * 102 * Any failures during read or write to the configuration file are ignored 103 * without reporting to the user since the likelihood of these errors are 104 * low and the impact on connectivity is low. 105 * 106 * = SSID & security details that is pushed to the supplicant. 107 * supplicant saves these details to the disk on calling 108 * saveConfigCommand(). 109 * 110 * We have two kinds of APIs exposed: 111 * > public API calls that provide fine grained control 112 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 113 * removeNetwork(). For these calls, the config is not persisted 114 * to the disk. (TODO: deprecate these calls in WifiManager) 115 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 116 * These calls persist the supplicant config to disk. 117 * 118 * - Maintain a list of configured networks for quick access 119 * 120 */ 121public class WifiConfigStore { 122 123 private Context mContext; 124 private static final String TAG = "WifiConfigStore"; 125 private static final boolean DBG = true; 126 private static final boolean VDBG = false; 127 128 private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf"; 129 130 /* configured networks with network id as the key */ 131 private HashMap<Integer, WifiConfiguration> mConfiguredNetworks = 132 new HashMap<Integer, WifiConfiguration>(); 133 134 /* A network id is a unique identifier for a network configured in the 135 * supplicant. Network ids are generated when the supplicant reads 136 * the configuration file at start and can thus change for networks. 137 * We store the IP configuration for networks along with a unique id 138 * that is generated from SSID and security type of the network. A mapping 139 * from the generated unique id to network id of the network is needed to 140 * map supplicant config to IP configuration. */ 141 private HashMap<Integer, Integer> mNetworkIds = 142 new HashMap<Integer, Integer>(); 143 144 /* Tracks the highest priority of configured networks */ 145 private int mLastPriority = -1; 146 147 private static final String ipConfigFile = Environment.getDataDirectory() + 148 "/misc/wifi/ipconfig.txt"; 149 150 private static final int IPCONFIG_FILE_VERSION = 2; 151 152 /* IP and proxy configuration keys */ 153 private static final String ID_KEY = "id"; 154 private static final String IP_ASSIGNMENT_KEY = "ipAssignment"; 155 private static final String LINK_ADDRESS_KEY = "linkAddress"; 156 private static final String GATEWAY_KEY = "gateway"; 157 private static final String DNS_KEY = "dns"; 158 private static final String PROXY_SETTINGS_KEY = "proxySettings"; 159 private static final String PROXY_HOST_KEY = "proxyHost"; 160 private static final String PROXY_PORT_KEY = "proxyPort"; 161 private static final String PROXY_PAC_FILE = "proxyPac"; 162 private static final String EXCLUSION_LIST_KEY = "exclusionList"; 163 private static final String EOS = "eos"; 164 165 166 /* Enterprise configuration keys */ 167 /** 168 * In old configurations, the "private_key" field was used. However, newer 169 * configurations use the key_id field with the engine_id set to "keystore". 170 * If this field is found in the configuration, the migration code is 171 * triggered. 172 */ 173 public static final String OLD_PRIVATE_KEY_NAME = "private_key"; 174 175 /** This represents an empty value of an enterprise field. 176 * NULL is used at wpa_supplicant to indicate an empty value 177 */ 178 static final String EMPTY_VALUE = "NULL"; 179 180 /** Internal use only */ 181 private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { 182 WifiEnterpriseConfig.EAP_KEY, WifiEnterpriseConfig.PHASE2_KEY, 183 WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.ANON_IDENTITY_KEY, 184 WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY, 185 WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY, 186 WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY, 187 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY }; 188 189 private final LocalLog mLocalLog; 190 private final WpaConfigFileObserver mFileObserver; 191 192 private WifiNative mWifiNative; 193 private final KeyStore mKeyStore = KeyStore.getInstance(); 194 195 WifiConfigStore(Context c, WifiNative wn) { 196 mContext = c; 197 mWifiNative = wn; 198 199 if (VDBG) { 200 mLocalLog = mWifiNative.getLocalLog(); 201 mFileObserver = new WpaConfigFileObserver(); 202 mFileObserver.startWatching(); 203 } else { 204 mLocalLog = null; 205 mFileObserver = null; 206 } 207 } 208 209 class WpaConfigFileObserver extends FileObserver { 210 211 public WpaConfigFileObserver() { 212 super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE); 213 } 214 215 @Override 216 public void onEvent(int event, String path) { 217 if (event == CLOSE_WRITE) { 218 File file = new File(SUPPLICANT_CONFIG_FILE); 219 if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length()); 220 } 221 } 222 } 223 224 225 /** 226 * Fetch the list of configured networks 227 * and enable all stored networks in supplicant. 228 */ 229 void loadAndEnableAllNetworks() { 230 if (DBG) log("Loading config and enabling all networks"); 231 loadConfiguredNetworks(); 232 enableAllNetworks(); 233 } 234 235 /** 236 * Fetch the list of currently configured networks 237 * @return List of networks 238 */ 239 List<WifiConfiguration> getConfiguredNetworks() { 240 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 241 for(WifiConfiguration config : mConfiguredNetworks.values()) { 242 networks.add(new WifiConfiguration(config)); 243 } 244 return networks; 245 } 246 247 /** 248 * enable all networks and save config. This will be a no-op if the list 249 * of configured networks indicates all networks as being enabled 250 */ 251 void enableAllNetworks() { 252 boolean networkEnabledStateChanged = false; 253 for(WifiConfiguration config : mConfiguredNetworks.values()) { 254 if(config != null && config.status == Status.DISABLED) { 255 if(mWifiNative.enableNetwork(config.networkId, false)) { 256 networkEnabledStateChanged = true; 257 config.status = Status.ENABLED; 258 } else { 259 loge("Enable network failed on " + config.networkId); 260 } 261 } 262 } 263 264 if (networkEnabledStateChanged) { 265 mWifiNative.saveConfig(); 266 sendConfiguredNetworksChangedBroadcast(); 267 } 268 } 269 270 271 /** 272 * Selects the specified network for connection. This involves 273 * updating the priority of all the networks and enabling the given 274 * network while disabling others. 275 * 276 * Selecting a network will leave the other networks disabled and 277 * a call to enableAllNetworks() needs to be issued upon a connection 278 * or a failure event from supplicant 279 * 280 * @param netId network to select for connection 281 * @return false if the network id is invalid 282 */ 283 boolean selectNetwork(int netId) { 284 if (VDBG) localLog("selectNetwork", netId); 285 if (netId == INVALID_NETWORK_ID) return false; 286 287 // Reset the priority of each network at start or if it goes too high. 288 if (mLastPriority == -1 || mLastPriority > 1000000) { 289 for(WifiConfiguration config : mConfiguredNetworks.values()) { 290 if (config.networkId != INVALID_NETWORK_ID) { 291 config.priority = 0; 292 addOrUpdateNetworkNative(config); 293 } 294 } 295 mLastPriority = 0; 296 } 297 298 // Set to the highest priority and save the configuration. 299 WifiConfiguration config = new WifiConfiguration(); 300 config.networkId = netId; 301 config.priority = ++mLastPriority; 302 303 addOrUpdateNetworkNative(config); 304 mWifiNative.saveConfig(); 305 306 /* Enable the given network while disabling all other networks */ 307 enableNetworkWithoutBroadcast(netId, true); 308 309 /* Avoid saving the config & sending a broadcast to prevent settings 310 * from displaying a disabled list of networks */ 311 return true; 312 } 313 314 /** 315 * Add/update the specified configuration and save config 316 * 317 * @param config WifiConfiguration to be saved 318 * @return network update result 319 */ 320 NetworkUpdateResult saveNetwork(WifiConfiguration config) { 321 if (VDBG) localLog("saveNetwork", config.networkId); 322 // A new network cannot have null SSID 323 if (config == null || (config.networkId == INVALID_NETWORK_ID && 324 config.SSID == null)) { 325 return new NetworkUpdateResult(INVALID_NETWORK_ID); 326 } 327 328 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 329 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 330 int netId = result.getNetworkId(); 331 /* enable a new network */ 332 if (newNetwork && netId != INVALID_NETWORK_ID) { 333 mWifiNative.enableNetwork(netId, false); 334 mConfiguredNetworks.get(netId).status = Status.ENABLED; 335 } 336 mWifiNative.saveConfig(); 337 sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ? 338 WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 339 return result; 340 } 341 342 void updateStatus(int netId, DetailedState state) { 343 if (netId != INVALID_NETWORK_ID) { 344 WifiConfiguration config = mConfiguredNetworks.get(netId); 345 if (config == null) return; 346 switch (state) { 347 case CONNECTED: 348 config.status = Status.CURRENT; 349 break; 350 case DISCONNECTED: 351 //If network is already disabled, keep the status 352 if (config.status == Status.CURRENT) { 353 config.status = Status.ENABLED; 354 } 355 break; 356 default: 357 //do nothing, retain the existing state 358 break; 359 } 360 } 361 } 362 363 /** 364 * Forget the specified network and save config 365 * 366 * @param netId network to forget 367 * @return {@code true} if it succeeds, {@code false} otherwise 368 */ 369 boolean forgetNetwork(int netId) { 370 if (VDBG) localLog("forgetNetwork", netId); 371 if (mWifiNative.removeNetwork(netId)) { 372 mWifiNative.saveConfig(); 373 removeConfigAndSendBroadcastIfNeeded(netId); 374 return true; 375 } else { 376 loge("Failed to remove network " + netId); 377 return false; 378 } 379 } 380 381 /** 382 * Add/update a network. Note that there is no saveConfig operation. 383 * This function is retained for compatibility with the public 384 * API. The more powerful saveNetwork() is used by the 385 * state machine 386 * 387 * @param config wifi configuration to add/update 388 * @return network Id 389 */ 390 int addOrUpdateNetwork(WifiConfiguration config) { 391 if (VDBG) localLog("addOrUpdateNetwork", config.networkId); 392 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 393 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 394 sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()), 395 result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : 396 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 397 } 398 return result.getNetworkId(); 399 } 400 401 /** 402 * Remove a network. Note that there is no saveConfig operation. 403 * This function is retained for compatibility with the public 404 * API. The more powerful forgetNetwork() is used by the 405 * state machine for network removal 406 * 407 * @param netId network to be removed 408 * @return {@code true} if it succeeds, {@code false} otherwise 409 */ 410 boolean removeNetwork(int netId) { 411 if (VDBG) localLog("removeNetwork", netId); 412 boolean ret = mWifiNative.removeNetwork(netId); 413 if (ret) { 414 removeConfigAndSendBroadcastIfNeeded(netId); 415 } 416 return ret; 417 } 418 419 private void removeConfigAndSendBroadcastIfNeeded(int netId) { 420 WifiConfiguration config = mConfiguredNetworks.get(netId); 421 if (config != null) { 422 // Remove any associated keys 423 if (config.enterpriseConfig != null) { 424 removeKeys(config.enterpriseConfig); 425 } 426 mConfiguredNetworks.remove(netId); 427 mNetworkIds.remove(configKey(config)); 428 429 writeIpAndProxyConfigurations(); 430 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 431 } 432 } 433 434 /** 435 * Enable a network. Note that there is no saveConfig operation. 436 * This function is retained for compatibility with the public 437 * API. The more powerful selectNetwork()/saveNetwork() is used by the 438 * state machine for connecting to a network 439 * 440 * @param netId network to be enabled 441 * @return {@code true} if it succeeds, {@code false} otherwise 442 */ 443 boolean enableNetwork(int netId, boolean disableOthers) { 444 boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); 445 if (disableOthers) { 446 if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId); 447 sendConfiguredNetworksChangedBroadcast(); 448 } else { 449 if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId); 450 WifiConfiguration enabledNetwork = null; 451 synchronized(mConfiguredNetworks) { 452 enabledNetwork = mConfiguredNetworks.get(netId); 453 } 454 // check just in case the network was removed by someone else. 455 if (enabledNetwork != null) { 456 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 457 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 458 } 459 } 460 return ret; 461 } 462 463 boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { 464 boolean ret = mWifiNative.enableNetwork(netId, disableOthers); 465 466 WifiConfiguration config = mConfiguredNetworks.get(netId); 467 if (config != null) config.status = Status.ENABLED; 468 469 if (disableOthers) { 470 markAllNetworksDisabledExcept(netId); 471 } 472 return ret; 473 } 474 475 void disableAllNetworks() { 476 if (VDBG) localLog("disableAllNetworks"); 477 boolean networkDisabled = false; 478 for(WifiConfiguration config : mConfiguredNetworks.values()) { 479 if(config != null && config.status != Status.DISABLED) { 480 if(mWifiNative.disableNetwork(config.networkId)) { 481 networkDisabled = true; 482 config.status = Status.DISABLED; 483 } else { 484 loge("Disable network failed on " + config.networkId); 485 } 486 } 487 } 488 489 if (networkDisabled) { 490 sendConfiguredNetworksChangedBroadcast(); 491 } 492 } 493 /** 494 * Disable a network. Note that there is no saveConfig operation. 495 * @param netId network to be disabled 496 * @return {@code true} if it succeeds, {@code false} otherwise 497 */ 498 boolean disableNetwork(int netId) { 499 return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); 500 } 501 502 /** 503 * Disable a network. Note that there is no saveConfig operation. 504 * @param netId network to be disabled 505 * @param reason reason code network was disabled 506 * @return {@code true} if it succeeds, {@code false} otherwise 507 */ 508 boolean disableNetwork(int netId, int reason) { 509 if (VDBG) localLog("disableNetwork", netId); 510 boolean ret = mWifiNative.disableNetwork(netId); 511 WifiConfiguration network = null; 512 WifiConfiguration config = mConfiguredNetworks.get(netId); 513 /* Only change the reason if the network was not previously disabled */ 514 if (config != null && config.status != Status.DISABLED) { 515 config.status = Status.DISABLED; 516 config.disableReason = reason; 517 network = config; 518 } 519 if (network != null) { 520 sendConfiguredNetworksChangedBroadcast(network, 521 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 522 } 523 return ret; 524 } 525 526 /** 527 * Save the configured networks in supplicant to disk 528 * @return {@code true} if it succeeds, {@code false} otherwise 529 */ 530 boolean saveConfig() { 531 return mWifiNative.saveConfig(); 532 } 533 534 /** 535 * Start WPS pin method configuration with pin obtained 536 * from the access point 537 * @param config WPS configuration 538 * @return Wps result containing status and pin 539 */ 540 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 541 WpsResult result = new WpsResult(); 542 if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { 543 /* WPS leaves all networks disabled */ 544 markAllNetworksDisabled(); 545 result.status = WpsResult.Status.SUCCESS; 546 } else { 547 loge("Failed to start WPS pin method configuration"); 548 result.status = WpsResult.Status.FAILURE; 549 } 550 return result; 551 } 552 553 /** 554 * Start WPS pin method configuration with pin obtained 555 * from the device 556 * @return WpsResult indicating status and pin 557 */ 558 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 559 WpsResult result = new WpsResult(); 560 result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); 561 /* WPS leaves all networks disabled */ 562 if (!TextUtils.isEmpty(result.pin)) { 563 markAllNetworksDisabled(); 564 result.status = WpsResult.Status.SUCCESS; 565 } else { 566 loge("Failed to start WPS pin method configuration"); 567 result.status = WpsResult.Status.FAILURE; 568 } 569 return result; 570 } 571 572 /** 573 * Start WPS push button configuration 574 * @param config WPS configuration 575 * @return WpsResult indicating status and pin 576 */ 577 WpsResult startWpsPbc(WpsInfo config) { 578 WpsResult result = new WpsResult(); 579 if (mWifiNative.startWpsPbc(config.BSSID)) { 580 /* WPS leaves all networks disabled */ 581 markAllNetworksDisabled(); 582 result.status = WpsResult.Status.SUCCESS; 583 } else { 584 loge("Failed to start WPS push button configuration"); 585 result.status = WpsResult.Status.FAILURE; 586 } 587 return result; 588 } 589 590 /** 591 * Fetch the link properties for a given network id 592 * @return LinkProperties for the given network id 593 */ 594 LinkProperties getLinkProperties(int netId) { 595 WifiConfiguration config = mConfiguredNetworks.get(netId); 596 if (config != null) return new LinkProperties(config.linkProperties); 597 return null; 598 } 599 600 /** 601 * set IP configuration for a given network id 602 */ 603 void setLinkProperties(int netId, LinkProperties linkProperties) { 604 WifiConfiguration config = mConfiguredNetworks.get(netId); 605 if (config != null) { 606 // add old proxy details - TODO - is this still needed? 607 if(config.linkProperties != null) { 608 linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); 609 } 610 config.linkProperties = linkProperties; 611 } 612 } 613 614 /** 615 * clear IP configuration for a given network id 616 * @param network id 617 */ 618 void clearLinkProperties(int netId) { 619 WifiConfiguration config = mConfiguredNetworks.get(netId); 620 if (config != null && config.linkProperties != null) { 621 // Clear everything except proxy 622 ProxyInfo proxy = config.linkProperties.getHttpProxy(); 623 config.linkProperties.clear(); 624 config.linkProperties.setHttpProxy(proxy); 625 } 626 } 627 628 629 /** 630 * Fetch the proxy properties for a given network id 631 * @param network id 632 * @return ProxyInfo for the network id 633 */ 634 ProxyInfo getProxyProperties(int netId) { 635 LinkProperties linkProperties = getLinkProperties(netId); 636 if (linkProperties != null) { 637 return new ProxyInfo(linkProperties.getHttpProxy()); 638 } 639 return null; 640 } 641 642 /** 643 * Return if the specified network is using static IP 644 * @param network id 645 * @return {@code true} if using static ip for netId 646 */ 647 boolean isUsingStaticIp(int netId) { 648 WifiConfiguration config = mConfiguredNetworks.get(netId); 649 if (config != null && config.ipAssignment == IpAssignment.STATIC) { 650 return true; 651 } 652 return false; 653 } 654 655 /** 656 * Should be called when a single network configuration is made. 657 * @param network The network configuration that changed. 658 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 659 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 660 */ 661 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 662 int reason) { 663 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 664 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 665 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 666 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 667 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 668 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 669 } 670 671 /** 672 * Should be called when multiple network configuration changes are made. 673 */ 674 private void sendConfiguredNetworksChangedBroadcast() { 675 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 676 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 677 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 678 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 679 } 680 681 void loadConfiguredNetworks() { 682 String listStr = mWifiNative.listNetworks(); 683 mLastPriority = 0; 684 685 mConfiguredNetworks.clear(); 686 mNetworkIds.clear(); 687 688 if (listStr == null) 689 return; 690 691 String[] lines = listStr.split("\n"); 692 // Skip the first line, which is a header 693 for (int i = 1; i < lines.length; i++) { 694 String[] result = lines[i].split("\t"); 695 // network-id | ssid | bssid | flags 696 WifiConfiguration config = new WifiConfiguration(); 697 try { 698 config.networkId = Integer.parseInt(result[0]); 699 } catch(NumberFormatException e) { 700 loge("Failed to read network-id '" + result[0] + "'"); 701 continue; 702 } 703 if (result.length > 3) { 704 if (result[3].indexOf("[CURRENT]") != -1) 705 config.status = WifiConfiguration.Status.CURRENT; 706 else if (result[3].indexOf("[DISABLED]") != -1) 707 config.status = WifiConfiguration.Status.DISABLED; 708 else 709 config.status = WifiConfiguration.Status.ENABLED; 710 } else { 711 config.status = WifiConfiguration.Status.ENABLED; 712 } 713 readNetworkVariables(config); 714 if (config.priority > mLastPriority) { 715 mLastPriority = config.priority; 716 } 717 config.ipAssignment = IpAssignment.DHCP; 718 config.proxySettings = ProxySettings.NONE; 719 720 if (mNetworkIds.containsKey(configKey(config))) { 721 // That SSID is already known, just ignore this duplicate entry 722 if (VDBG) localLog("discarded duplicate network", config.networkId); 723 } else { 724 mConfiguredNetworks.put(config.networkId, config); 725 mNetworkIds.put(configKey(config), config.networkId); 726 if (VDBG) localLog("loaded configured network", config.networkId); 727 } 728 } 729 730 readIpAndProxyConfigurations(); 731 sendConfiguredNetworksChangedBroadcast(); 732 733 if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks"); 734 735 if (mNetworkIds.size() == 0) { 736 // no networks? Lets log if the wpa_supplicant.conf file contents 737 BufferedReader reader = null; 738 try { 739 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 740 if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---"); 741 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 742 if (VDBG) localLog(line); 743 } 744 if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---"); 745 } catch (FileNotFoundException e) { 746 if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 747 } catch (IOException e) { 748 if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 749 } finally { 750 try { 751 if (reader != null) { 752 reader.close(); 753 } 754 } catch (IOException e) { 755 // Just ignore the fact that we couldn't close 756 } 757 } 758 } 759 } 760 761 /* Mark all networks except specified netId as disabled */ 762 private void markAllNetworksDisabledExcept(int netId) { 763 for(WifiConfiguration config : mConfiguredNetworks.values()) { 764 if(config != null && config.networkId != netId) { 765 if (config.status != Status.DISABLED) { 766 config.status = Status.DISABLED; 767 config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; 768 } 769 } 770 } 771 } 772 773 private void markAllNetworksDisabled() { 774 markAllNetworksDisabledExcept(INVALID_NETWORK_ID); 775 } 776 777 boolean needsUnlockedKeyStore() { 778 779 // Any network using certificates to authenticate access requires 780 // unlocked key store; unless the certificates can be stored with 781 // hardware encryption 782 783 for(WifiConfiguration config : mConfiguredNetworks.values()) { 784 785 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 786 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 787 788 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 789 return true; 790 } 791 } 792 } 793 794 return false; 795 } 796 797 private void writeIpAndProxyConfigurations() { 798 799 /* Make a copy */ 800 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 801 for(WifiConfiguration config : mConfiguredNetworks.values()) { 802 networks.add(new WifiConfiguration(config)); 803 } 804 805 DelayedDiskWrite.write(networks); 806 } 807 808 private static class DelayedDiskWrite { 809 810 private static HandlerThread sDiskWriteHandlerThread; 811 private static Handler sDiskWriteHandler; 812 /* Tracks multiple writes on the same thread */ 813 private static int sWriteSequence = 0; 814 private static final String TAG = "DelayedDiskWrite"; 815 816 static void write (final List<WifiConfiguration> networks) { 817 818 /* Do a delayed write to disk on a seperate handler thread */ 819 synchronized (DelayedDiskWrite.class) { 820 if (++sWriteSequence == 1) { 821 sDiskWriteHandlerThread = new HandlerThread("WifiConfigThread"); 822 sDiskWriteHandlerThread.start(); 823 sDiskWriteHandler = new Handler(sDiskWriteHandlerThread.getLooper()); 824 } 825 } 826 827 sDiskWriteHandler.post(new Runnable() { 828 @Override 829 public void run() { 830 onWriteCalled(networks); 831 } 832 }); 833 } 834 835 private static void onWriteCalled(List<WifiConfiguration> networks) { 836 837 DataOutputStream out = null; 838 try { 839 out = new DataOutputStream(new BufferedOutputStream( 840 new FileOutputStream(ipConfigFile))); 841 842 out.writeInt(IPCONFIG_FILE_VERSION); 843 844 for(WifiConfiguration config : networks) { 845 boolean writeToFile = false; 846 847 try { 848 LinkProperties linkProperties = config.linkProperties; 849 switch (config.ipAssignment) { 850 case STATIC: 851 out.writeUTF(IP_ASSIGNMENT_KEY); 852 out.writeUTF(config.ipAssignment.toString()); 853 for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { 854 out.writeUTF(LINK_ADDRESS_KEY); 855 out.writeUTF(linkAddr.getAddress().getHostAddress()); 856 out.writeInt(linkAddr.getNetworkPrefixLength()); 857 } 858 for (RouteInfo route : linkProperties.getRoutes()) { 859 out.writeUTF(GATEWAY_KEY); 860 LinkAddress dest = route.getDestination(); 861 if (dest != null) { 862 out.writeInt(1); 863 out.writeUTF(dest.getAddress().getHostAddress()); 864 out.writeInt(dest.getNetworkPrefixLength()); 865 } else { 866 out.writeInt(0); 867 } 868 if (route.getGateway() != null) { 869 out.writeInt(1); 870 out.writeUTF(route.getGateway().getHostAddress()); 871 } else { 872 out.writeInt(0); 873 } 874 } 875 for (InetAddress inetAddr : linkProperties.getDnses()) { 876 out.writeUTF(DNS_KEY); 877 out.writeUTF(inetAddr.getHostAddress()); 878 } 879 writeToFile = true; 880 break; 881 case DHCP: 882 out.writeUTF(IP_ASSIGNMENT_KEY); 883 out.writeUTF(config.ipAssignment.toString()); 884 writeToFile = true; 885 break; 886 case UNASSIGNED: 887 /* Ignore */ 888 break; 889 default: 890 loge("Ignore invalid ip assignment while writing"); 891 break; 892 } 893 894 switch (config.proxySettings) { 895 case STATIC: 896 ProxyInfo proxyProperties = linkProperties.getHttpProxy(); 897 String exclusionList = proxyProperties.getExclusionList(); 898 out.writeUTF(PROXY_SETTINGS_KEY); 899 out.writeUTF(config.proxySettings.toString()); 900 out.writeUTF(PROXY_HOST_KEY); 901 out.writeUTF(proxyProperties.getHost()); 902 out.writeUTF(PROXY_PORT_KEY); 903 out.writeInt(proxyProperties.getPort()); 904 out.writeUTF(EXCLUSION_LIST_KEY); 905 out.writeUTF(exclusionList); 906 writeToFile = true; 907 break; 908 case PAC: 909 ProxyInfo proxyPacProperties = linkProperties.getHttpProxy(); 910 out.writeUTF(PROXY_SETTINGS_KEY); 911 out.writeUTF(config.proxySettings.toString()); 912 out.writeUTF(PROXY_PAC_FILE); 913 out.writeUTF(proxyPacProperties.getPacFileUrl()); 914 writeToFile = true; 915 break; 916 case NONE: 917 out.writeUTF(PROXY_SETTINGS_KEY); 918 out.writeUTF(config.proxySettings.toString()); 919 writeToFile = true; 920 break; 921 case UNASSIGNED: 922 /* Ignore */ 923 break; 924 default: 925 loge("Ignthisore invalid proxy settings while writing"); 926 break; 927 } 928 if (writeToFile) { 929 out.writeUTF(ID_KEY); 930 out.writeInt(configKey(config)); 931 } 932 } catch (NullPointerException e) { 933 loge("Failure in writing " + config.linkProperties + e); 934 } 935 out.writeUTF(EOS); 936 } 937 938 } catch (IOException e) { 939 loge("Error writing data file"); 940 } finally { 941 if (out != null) { 942 try { 943 out.close(); 944 } catch (Exception e) {} 945 } 946 947 //Quit if no more writes sent 948 synchronized (DelayedDiskWrite.class) { 949 if (--sWriteSequence == 0) { 950 sDiskWriteHandler.getLooper().quit(); 951 sDiskWriteHandler = null; 952 sDiskWriteHandlerThread = null; 953 } 954 } 955 } 956 } 957 958 private static void loge(String s) { 959 Log.e(TAG, s); 960 } 961 } 962 963 private void readIpAndProxyConfigurations() { 964 965 DataInputStream in = null; 966 try { 967 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 968 ipConfigFile))); 969 970 int version = in.readInt(); 971 if (version != 2 && version != 1) { 972 loge("Bad version on IP configuration file, ignore read"); 973 return; 974 } 975 976 while (true) { 977 int id = -1; 978 // Default is DHCP with no proxy 979 IpAssignment ipAssignment = IpAssignment.DHCP; 980 ProxySettings proxySettings = ProxySettings.NONE; 981 LinkProperties linkProperties = new LinkProperties(); 982 String proxyHost = null; 983 String pacFileUrl = null; 984 int proxyPort = -1; 985 String exclusionList = null; 986 String key; 987 988 do { 989 key = in.readUTF(); 990 try { 991 if (key.equals(ID_KEY)) { 992 id = in.readInt(); 993 } else if (key.equals(IP_ASSIGNMENT_KEY)) { 994 ipAssignment = IpAssignment.valueOf(in.readUTF()); 995 } else if (key.equals(LINK_ADDRESS_KEY)) { 996 LinkAddress linkAddr = new LinkAddress( 997 NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); 998 linkProperties.addLinkAddress(linkAddr); 999 } else if (key.equals(GATEWAY_KEY)) { 1000 LinkAddress dest = null; 1001 InetAddress gateway = null; 1002 if (version == 1) { 1003 // only supported default gateways - leave the dest/prefix empty 1004 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 1005 } else { 1006 if (in.readInt() == 1) { 1007 dest = new LinkAddress( 1008 NetworkUtils.numericToInetAddress(in.readUTF()), 1009 in.readInt()); 1010 } 1011 if (in.readInt() == 1) { 1012 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 1013 } 1014 } 1015 linkProperties.addRoute(new RouteInfo(dest, gateway)); 1016 } else if (key.equals(DNS_KEY)) { 1017 linkProperties.addDns( 1018 NetworkUtils.numericToInetAddress(in.readUTF())); 1019 } else if (key.equals(PROXY_SETTINGS_KEY)) { 1020 proxySettings = ProxySettings.valueOf(in.readUTF()); 1021 } else if (key.equals(PROXY_HOST_KEY)) { 1022 proxyHost = in.readUTF(); 1023 } else if (key.equals(PROXY_PORT_KEY)) { 1024 proxyPort = in.readInt(); 1025 } else if (key.equals(PROXY_PAC_FILE)) { 1026 pacFileUrl = in.readUTF(); 1027 } else if (key.equals(EXCLUSION_LIST_KEY)) { 1028 exclusionList = in.readUTF(); 1029 } else if (key.equals(EOS)) { 1030 break; 1031 } else { 1032 loge("Ignore unknown key " + key + "while reading"); 1033 } 1034 } catch (IllegalArgumentException e) { 1035 loge("Ignore invalid address while reading" + e); 1036 } 1037 } while (true); 1038 1039 if (id != -1) { 1040 WifiConfiguration config = mConfiguredNetworks.get( 1041 mNetworkIds.get(id)); 1042 1043 if (config == null) { 1044 loge("configuration found for missing network, ignored"); 1045 } else { 1046 config.linkProperties = linkProperties; 1047 switch (ipAssignment) { 1048 case STATIC: 1049 case DHCP: 1050 config.ipAssignment = ipAssignment; 1051 break; 1052 case UNASSIGNED: 1053 loge("BUG: Found UNASSIGNED IP on file, use DHCP"); 1054 config.ipAssignment = IpAssignment.DHCP; 1055 break; 1056 default: 1057 loge("Ignore invalid ip assignment while reading"); 1058 break; 1059 } 1060 1061 switch (proxySettings) { 1062 case STATIC: 1063 config.proxySettings = proxySettings; 1064 ProxyInfo proxyProperties = 1065 new ProxyInfo(proxyHost, proxyPort, exclusionList); 1066 linkProperties.setHttpProxy(proxyProperties); 1067 break; 1068 case PAC: 1069 config.proxySettings = proxySettings; 1070 ProxyInfo proxyPacProperties = 1071 new ProxyInfo(pacFileUrl); 1072 linkProperties.setHttpProxy(proxyPacProperties); 1073 break; 1074 case NONE: 1075 config.proxySettings = proxySettings; 1076 break; 1077 case UNASSIGNED: 1078 loge("BUG: Found UNASSIGNED proxy on file, use NONE"); 1079 config.proxySettings = ProxySettings.NONE; 1080 break; 1081 default: 1082 loge("Ignore invalid proxy settings while reading"); 1083 break; 1084 } 1085 } 1086 } else { 1087 if (DBG) log("Missing id while parsing configuration"); 1088 } 1089 } 1090 } catch (EOFException ignore) { 1091 } catch (IOException e) { 1092 loge("Error parsing configuration" + e); 1093 } finally { 1094 if (in != null) { 1095 try { 1096 in.close(); 1097 } catch (Exception e) {} 1098 } 1099 } 1100 } 1101 1102 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { 1103 /* 1104 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1105 * network configuration. Otherwise, the networkId should 1106 * refer to an existing configuration. 1107 */ 1108 1109 if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 1110 1111 int netId = config.networkId; 1112 boolean newNetwork = false; 1113 // networkId of INVALID_NETWORK_ID means we want to create a new network 1114 if (netId == INVALID_NETWORK_ID) { 1115 Integer savedNetId = mNetworkIds.get(configKey(config)); 1116 if (savedNetId != null) { 1117 netId = savedNetId; 1118 } else { 1119 newNetwork = true; 1120 netId = mWifiNative.addNetwork(); 1121 if (netId < 0) { 1122 loge("Failed to add a network!"); 1123 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1124 } 1125 } 1126 } 1127 1128 boolean updateFailed = true; 1129 1130 setVariables: { 1131 1132 if (config.SSID != null && 1133 !mWifiNative.setNetworkVariable( 1134 netId, 1135 WifiConfiguration.ssidVarName, 1136 config.SSID)) { 1137 loge("failed to set SSID: "+config.SSID); 1138 break setVariables; 1139 } 1140 1141 if (config.BSSID != null && 1142 !mWifiNative.setNetworkVariable( 1143 netId, 1144 WifiConfiguration.bssidVarName, 1145 config.BSSID)) { 1146 loge("failed to set BSSID: "+config.BSSID); 1147 break setVariables; 1148 } 1149 1150 String allowedKeyManagementString = 1151 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 1152 if (config.allowedKeyManagement.cardinality() != 0 && 1153 !mWifiNative.setNetworkVariable( 1154 netId, 1155 WifiConfiguration.KeyMgmt.varName, 1156 allowedKeyManagementString)) { 1157 loge("failed to set key_mgmt: "+ 1158 allowedKeyManagementString); 1159 break setVariables; 1160 } 1161 1162 String allowedProtocolsString = 1163 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 1164 if (config.allowedProtocols.cardinality() != 0 && 1165 !mWifiNative.setNetworkVariable( 1166 netId, 1167 WifiConfiguration.Protocol.varName, 1168 allowedProtocolsString)) { 1169 loge("failed to set proto: "+ 1170 allowedProtocolsString); 1171 break setVariables; 1172 } 1173 1174 String allowedAuthAlgorithmsString = 1175 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 1176 if (config.allowedAuthAlgorithms.cardinality() != 0 && 1177 !mWifiNative.setNetworkVariable( 1178 netId, 1179 WifiConfiguration.AuthAlgorithm.varName, 1180 allowedAuthAlgorithmsString)) { 1181 loge("failed to set auth_alg: "+ 1182 allowedAuthAlgorithmsString); 1183 break setVariables; 1184 } 1185 1186 String allowedPairwiseCiphersString = 1187 makeString(config.allowedPairwiseCiphers, 1188 WifiConfiguration.PairwiseCipher.strings); 1189 if (config.allowedPairwiseCiphers.cardinality() != 0 && 1190 !mWifiNative.setNetworkVariable( 1191 netId, 1192 WifiConfiguration.PairwiseCipher.varName, 1193 allowedPairwiseCiphersString)) { 1194 loge("failed to set pairwise: "+ 1195 allowedPairwiseCiphersString); 1196 break setVariables; 1197 } 1198 1199 String allowedGroupCiphersString = 1200 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 1201 if (config.allowedGroupCiphers.cardinality() != 0 && 1202 !mWifiNative.setNetworkVariable( 1203 netId, 1204 WifiConfiguration.GroupCipher.varName, 1205 allowedGroupCiphersString)) { 1206 loge("failed to set group: "+ 1207 allowedGroupCiphersString); 1208 break setVariables; 1209 } 1210 1211 // Prevent client screw-up by passing in a WifiConfiguration we gave it 1212 // by preventing "*" as a key. 1213 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 1214 !mWifiNative.setNetworkVariable( 1215 netId, 1216 WifiConfiguration.pskVarName, 1217 config.preSharedKey)) { 1218 loge("failed to set psk"); 1219 break setVariables; 1220 } 1221 1222 boolean hasSetKey = false; 1223 if (config.wepKeys != null) { 1224 for (int i = 0; i < config.wepKeys.length; i++) { 1225 // Prevent client screw-up by passing in a WifiConfiguration we gave it 1226 // by preventing "*" as a key. 1227 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 1228 if (!mWifiNative.setNetworkVariable( 1229 netId, 1230 WifiConfiguration.wepKeyVarNames[i], 1231 config.wepKeys[i])) { 1232 loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); 1233 break setVariables; 1234 } 1235 hasSetKey = true; 1236 } 1237 } 1238 } 1239 1240 if (hasSetKey) { 1241 if (!mWifiNative.setNetworkVariable( 1242 netId, 1243 WifiConfiguration.wepTxKeyIdxVarName, 1244 Integer.toString(config.wepTxKeyIndex))) { 1245 loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); 1246 break setVariables; 1247 } 1248 } 1249 1250 if (!mWifiNative.setNetworkVariable( 1251 netId, 1252 WifiConfiguration.priorityVarName, 1253 Integer.toString(config.priority))) { 1254 loge(config.SSID + ": failed to set priority: " 1255 +config.priority); 1256 break setVariables; 1257 } 1258 1259 if (config.hiddenSSID && !mWifiNative.setNetworkVariable( 1260 netId, 1261 WifiConfiguration.hiddenSSIDVarName, 1262 Integer.toString(config.hiddenSSID ? 1 : 0))) { 1263 loge(config.SSID + ": failed to set hiddenSSID: "+ 1264 config.hiddenSSID); 1265 break setVariables; 1266 } 1267 1268 if (config.enterpriseConfig != null && 1269 config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { 1270 1271 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 1272 1273 if (needsKeyStore(enterpriseConfig)) { 1274 /** 1275 * Keyguard settings may eventually be controlled by device policy. 1276 * We check here if keystore is unlocked before installing 1277 * credentials. 1278 * TODO: Do we need a dialog here ? 1279 */ 1280 if (mKeyStore.state() != KeyStore.State.UNLOCKED) { 1281 loge(config.SSID + ": key store is locked"); 1282 break setVariables; 1283 } 1284 1285 try { 1286 /* config passed may include only fields being updated. 1287 * In order to generate the key id, fetch uninitialized 1288 * fields from the currently tracked configuration 1289 */ 1290 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 1291 String keyId = config.getKeyIdForCredentials(currentConfig); 1292 1293 if (!installKeys(enterpriseConfig, keyId)) { 1294 loge(config.SSID + ": failed to install keys"); 1295 break setVariables; 1296 } 1297 } catch (IllegalStateException e) { 1298 loge(config.SSID + " invalid config for key installation"); 1299 break setVariables; 1300 } 1301 } 1302 1303 HashMap<String, String> enterpriseFields = enterpriseConfig.getFields(); 1304 for (String key : enterpriseFields.keySet()) { 1305 String value = enterpriseFields.get(key); 1306 if (!mWifiNative.setNetworkVariable( 1307 netId, 1308 key, 1309 value)) { 1310 removeKeys(enterpriseConfig); 1311 loge(config.SSID + ": failed to set " + key + 1312 ": " + value); 1313 break setVariables; 1314 } 1315 } 1316 } 1317 updateFailed = false; 1318 } //end of setVariables 1319 1320 if (updateFailed) { 1321 if (newNetwork) { 1322 mWifiNative.removeNetwork(netId); 1323 loge("Failed to set a network variable, removed network: " + netId); 1324 } 1325 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1326 } 1327 1328 /* An update of the network variables requires reading them 1329 * back from the supplicant to update mConfiguredNetworks. 1330 * This is because some of the variables (SSID, wep keys & 1331 * passphrases) reflect different values when read back than 1332 * when written. For example, wep key is stored as * irrespective 1333 * of the value sent to the supplicant 1334 */ 1335 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 1336 if (currentConfig == null) { 1337 currentConfig = new WifiConfiguration(); 1338 currentConfig.ipAssignment = IpAssignment.DHCP; 1339 currentConfig.proxySettings = ProxySettings.NONE; 1340 currentConfig.networkId = netId; 1341 } 1342 1343 readNetworkVariables(currentConfig); 1344 1345 mConfiguredNetworks.put(netId, currentConfig); 1346 mNetworkIds.put(configKey(currentConfig), netId); 1347 1348 NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); 1349 result.setIsNewNetwork(newNetwork); 1350 result.setNetworkId(netId); 1351 return result; 1352 } 1353 1354 /* Compare current and new configuration and write to file on change */ 1355 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 1356 WifiConfiguration currentConfig, 1357 WifiConfiguration newConfig) { 1358 boolean ipChanged = false; 1359 boolean proxyChanged = false; 1360 LinkProperties linkProperties = null; 1361 1362 switch (newConfig.ipAssignment) { 1363 case STATIC: 1364 Collection<LinkAddress> currentLinkAddresses = currentConfig.linkProperties 1365 .getLinkAddresses(); 1366 Collection<LinkAddress> newLinkAddresses = newConfig.linkProperties 1367 .getLinkAddresses(); 1368 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses(); 1369 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses(); 1370 Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes(); 1371 Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes(); 1372 1373 boolean linkAddressesDiffer = 1374 (currentLinkAddresses.size() != newLinkAddresses.size()) || 1375 !currentLinkAddresses.containsAll(newLinkAddresses); 1376 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || 1377 !currentDnses.containsAll(newDnses); 1378 boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || 1379 !currentRoutes.containsAll(newRoutes); 1380 1381 if ((currentConfig.ipAssignment != newConfig.ipAssignment) || 1382 linkAddressesDiffer || 1383 dnsesDiffer || 1384 routesDiffer) { 1385 ipChanged = true; 1386 } 1387 break; 1388 case DHCP: 1389 if (currentConfig.ipAssignment != newConfig.ipAssignment) { 1390 ipChanged = true; 1391 } 1392 break; 1393 case UNASSIGNED: 1394 /* Ignore */ 1395 break; 1396 default: 1397 loge("Ignore invalid ip assignment during write"); 1398 break; 1399 } 1400 1401 switch (newConfig.proxySettings) { 1402 case STATIC: 1403 case PAC: 1404 ProxyInfo newHttpProxy = newConfig.linkProperties.getHttpProxy(); 1405 ProxyInfo currentHttpProxy = currentConfig.linkProperties.getHttpProxy(); 1406 1407 if (newHttpProxy != null) { 1408 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 1409 } else { 1410 proxyChanged = (currentHttpProxy != null); 1411 } 1412 break; 1413 case NONE: 1414 if (currentConfig.proxySettings != newConfig.proxySettings) { 1415 proxyChanged = true; 1416 } 1417 break; 1418 case UNASSIGNED: 1419 /* Ignore */ 1420 break; 1421 default: 1422 loge("Ignore invalid proxy configuration during write"); 1423 break; 1424 } 1425 1426 if (!ipChanged) { 1427 linkProperties = copyIpSettingsFromConfig(currentConfig); 1428 } else { 1429 currentConfig.ipAssignment = newConfig.ipAssignment; 1430 linkProperties = copyIpSettingsFromConfig(newConfig); 1431 log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " + 1432 linkProperties.toString()); 1433 } 1434 1435 1436 if (!proxyChanged) { 1437 linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy()); 1438 } else { 1439 currentConfig.proxySettings = newConfig.proxySettings; 1440 linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy()); 1441 log("proxy changed SSID = " + currentConfig.SSID); 1442 if (linkProperties.getHttpProxy() != null) { 1443 log(" proxyProperties: " + linkProperties.getHttpProxy().toString()); 1444 } 1445 } 1446 1447 if (ipChanged || proxyChanged) { 1448 currentConfig.linkProperties = linkProperties; 1449 writeIpAndProxyConfigurations(); 1450 sendConfiguredNetworksChangedBroadcast(currentConfig, 1451 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1452 } 1453 return new NetworkUpdateResult(ipChanged, proxyChanged); 1454 } 1455 1456 private LinkProperties copyIpSettingsFromConfig(WifiConfiguration config) { 1457 LinkProperties linkProperties = new LinkProperties(); 1458 linkProperties.setInterfaceName(config.linkProperties.getInterfaceName()); 1459 for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { 1460 linkProperties.addLinkAddress(linkAddr); 1461 } 1462 for (RouteInfo route : config.linkProperties.getRoutes()) { 1463 linkProperties.addRoute(route); 1464 } 1465 for (InetAddress dns : config.linkProperties.getDnses()) { 1466 linkProperties.addDns(dns); 1467 } 1468 return linkProperties; 1469 } 1470 1471 /** 1472 * Read the variables from the supplicant daemon that are needed to 1473 * fill in the WifiConfiguration object. 1474 * 1475 * @param config the {@link WifiConfiguration} object to be filled in. 1476 */ 1477 private void readNetworkVariables(WifiConfiguration config) { 1478 1479 int netId = config.networkId; 1480 if (netId < 0) 1481 return; 1482 1483 /* 1484 * TODO: maybe should have a native method that takes an array of 1485 * variable names and returns an array of values. But we'd still 1486 * be doing a round trip to the supplicant daemon for each variable. 1487 */ 1488 String value; 1489 1490 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 1491 if (!TextUtils.isEmpty(value)) { 1492 if (value.charAt(0) != '"') { 1493 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 1494 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 1495 //supplicant string 1496 } else { 1497 config.SSID = value; 1498 } 1499 } else { 1500 config.SSID = null; 1501 } 1502 1503 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 1504 if (!TextUtils.isEmpty(value)) { 1505 config.BSSID = value; 1506 } else { 1507 config.BSSID = null; 1508 } 1509 1510 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 1511 config.priority = -1; 1512 if (!TextUtils.isEmpty(value)) { 1513 try { 1514 config.priority = Integer.parseInt(value); 1515 } catch (NumberFormatException ignore) { 1516 } 1517 } 1518 1519 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 1520 config.hiddenSSID = false; 1521 if (!TextUtils.isEmpty(value)) { 1522 try { 1523 config.hiddenSSID = Integer.parseInt(value) != 0; 1524 } catch (NumberFormatException ignore) { 1525 } 1526 } 1527 1528 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 1529 config.wepTxKeyIndex = -1; 1530 if (!TextUtils.isEmpty(value)) { 1531 try { 1532 config.wepTxKeyIndex = Integer.parseInt(value); 1533 } catch (NumberFormatException ignore) { 1534 } 1535 } 1536 1537 for (int i = 0; i < 4; i++) { 1538 value = mWifiNative.getNetworkVariable(netId, 1539 WifiConfiguration.wepKeyVarNames[i]); 1540 if (!TextUtils.isEmpty(value)) { 1541 config.wepKeys[i] = value; 1542 } else { 1543 config.wepKeys[i] = null; 1544 } 1545 } 1546 1547 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 1548 if (!TextUtils.isEmpty(value)) { 1549 config.preSharedKey = value; 1550 } else { 1551 config.preSharedKey = null; 1552 } 1553 1554 value = mWifiNative.getNetworkVariable(config.networkId, 1555 WifiConfiguration.Protocol.varName); 1556 if (!TextUtils.isEmpty(value)) { 1557 String vals[] = value.split(" "); 1558 for (String val : vals) { 1559 int index = 1560 lookupString(val, WifiConfiguration.Protocol.strings); 1561 if (0 <= index) { 1562 config.allowedProtocols.set(index); 1563 } 1564 } 1565 } 1566 1567 value = mWifiNative.getNetworkVariable(config.networkId, 1568 WifiConfiguration.KeyMgmt.varName); 1569 if (!TextUtils.isEmpty(value)) { 1570 String vals[] = value.split(" "); 1571 for (String val : vals) { 1572 int index = 1573 lookupString(val, WifiConfiguration.KeyMgmt.strings); 1574 if (0 <= index) { 1575 config.allowedKeyManagement.set(index); 1576 } 1577 } 1578 } 1579 1580 value = mWifiNative.getNetworkVariable(config.networkId, 1581 WifiConfiguration.AuthAlgorithm.varName); 1582 if (!TextUtils.isEmpty(value)) { 1583 String vals[] = value.split(" "); 1584 for (String val : vals) { 1585 int index = 1586 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 1587 if (0 <= index) { 1588 config.allowedAuthAlgorithms.set(index); 1589 } 1590 } 1591 } 1592 1593 value = mWifiNative.getNetworkVariable(config.networkId, 1594 WifiConfiguration.PairwiseCipher.varName); 1595 if (!TextUtils.isEmpty(value)) { 1596 String vals[] = value.split(" "); 1597 for (String val : vals) { 1598 int index = 1599 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 1600 if (0 <= index) { 1601 config.allowedPairwiseCiphers.set(index); 1602 } 1603 } 1604 } 1605 1606 value = mWifiNative.getNetworkVariable(config.networkId, 1607 WifiConfiguration.GroupCipher.varName); 1608 if (!TextUtils.isEmpty(value)) { 1609 String vals[] = value.split(" "); 1610 for (String val : vals) { 1611 int index = 1612 lookupString(val, WifiConfiguration.GroupCipher.strings); 1613 if (0 <= index) { 1614 config.allowedGroupCiphers.set(index); 1615 } 1616 } 1617 } 1618 1619 if (config.enterpriseConfig == null) { 1620 config.enterpriseConfig = new WifiEnterpriseConfig(); 1621 } 1622 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 1623 for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { 1624 value = mWifiNative.getNetworkVariable(netId, key); 1625 if (!TextUtils.isEmpty(value)) { 1626 enterpriseFields.put(key, removeDoubleQuotes(value)); 1627 } else { 1628 enterpriseFields.put(key, EMPTY_VALUE); 1629 } 1630 } 1631 1632 if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { 1633 saveConfig(); 1634 } 1635 1636 migrateCerts(config.enterpriseConfig); 1637 // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); 1638 } 1639 1640 private static String removeDoubleQuotes(String string) { 1641 int length = string.length(); 1642 if ((length > 1) && (string.charAt(0) == '"') 1643 && (string.charAt(length - 1) == '"')) { 1644 return string.substring(1, length - 1); 1645 } 1646 return string; 1647 } 1648 1649 private static String convertToQuotedString(String string) { 1650 return "\"" + string + "\""; 1651 } 1652 1653 private static String makeString(BitSet set, String[] strings) { 1654 StringBuffer buf = new StringBuffer(); 1655 int nextSetBit = -1; 1656 1657 /* Make sure all set bits are in [0, strings.length) to avoid 1658 * going out of bounds on strings. (Shouldn't happen, but...) */ 1659 set = set.get(0, strings.length); 1660 1661 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 1662 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 1663 } 1664 1665 // remove trailing space 1666 if (set.cardinality() > 0) { 1667 buf.setLength(buf.length() - 1); 1668 } 1669 1670 return buf.toString(); 1671 } 1672 1673 private int lookupString(String string, String[] strings) { 1674 int size = strings.length; 1675 1676 string = string.replace('-', '_'); 1677 1678 for (int i = 0; i < size; i++) 1679 if (string.equals(strings[i])) 1680 return i; 1681 1682 // if we ever get here, we should probably add the 1683 // value to WifiConfiguration to reflect that it's 1684 // supported by the WPA supplicant 1685 loge("Failed to look-up a string: " + string); 1686 1687 return -1; 1688 } 1689 1690 /* Returns a unique for a given configuration */ 1691 private static int configKey(WifiConfiguration config) { 1692 String key; 1693 1694 if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1695 key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK]; 1696 } else if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || 1697 config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 1698 key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP]; 1699 } else if (config.wepKeys[0] != null) { 1700 key = config.SSID + "WEP"; 1701 } else { 1702 key = config.SSID + KeyMgmt.strings[KeyMgmt.NONE]; 1703 } 1704 1705 return key.hashCode(); 1706 } 1707 1708 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1709 pw.println("WifiConfigStore"); 1710 pw.println("mLastPriority " + mLastPriority); 1711 pw.println("Configured networks"); 1712 for (WifiConfiguration conf : getConfiguredNetworks()) { 1713 pw.println(conf); 1714 } 1715 pw.println(); 1716 1717 if (mLocalLog != null) { 1718 pw.println("WifiConfigStore - Log Begin ----"); 1719 mLocalLog.dump(fd, pw, args); 1720 pw.println("WifiConfigStore - Log End ----"); 1721 } 1722 } 1723 1724 public String getConfigFile() { 1725 return ipConfigFile; 1726 } 1727 1728 private void loge(String s) { 1729 Log.e(TAG, s); 1730 } 1731 1732 private void log(String s) { 1733 Log.d(TAG, s); 1734 } 1735 1736 private void localLog(String s) { 1737 if (mLocalLog != null) { 1738 mLocalLog.log(s); 1739 } 1740 } 1741 1742 private void localLog(String s, int netId) { 1743 if (mLocalLog == null) { 1744 return; 1745 } 1746 1747 WifiConfiguration config; 1748 synchronized(mConfiguredNetworks) { 1749 config = mConfiguredNetworks.get(netId); 1750 } 1751 1752 if (config != null) { 1753 mLocalLog.log(s + " " + config.getPrintableSsid()); 1754 } else { 1755 mLocalLog.log(s + " " + netId); 1756 } 1757 } 1758 1759 // Certificate and private key management for EnterpriseConfig 1760 static boolean needsKeyStore(WifiEnterpriseConfig config) { 1761 // Has no keys to be installed 1762 if (config.getClientCertificate() == null && config.getCaCertificate() == null) 1763 return false; 1764 return true; 1765 } 1766 1767 static boolean isHardwareBackedKey(PrivateKey key) { 1768 return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 1769 } 1770 1771 static boolean hasHardwareBackedKey(Certificate certificate) { 1772 return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 1773 } 1774 1775 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 1776 String client = config.getClientCertificateAlias(); 1777 if (!TextUtils.isEmpty(client)) { 1778 // a valid client certificate is configured 1779 1780 // BUGBUG: keyStore.get() never returns certBytes; because it is not 1781 // taking WIFI_UID as a parameter. It always looks for certificate 1782 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 1783 // all certificates need software keystore until we get the get() API 1784 // fixed. 1785 1786 return true; 1787 } 1788 1789 /* 1790 try { 1791 1792 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 1793 .USER_CERTIFICATE + client); 1794 1795 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 1796 if (factory == null) { 1797 Slog.e(TAG, "Error getting certificate factory"); 1798 return; 1799 } 1800 1801 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 1802 if (certBytes != null) { 1803 Certificate cert = (X509Certificate) factory.generateCertificate( 1804 new ByteArrayInputStream(certBytes)); 1805 1806 if (cert != null) { 1807 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 1808 1809 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 1810 .USER_CERTIFICATE + client); 1811 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 1812 "does not need" ) + " software key store"); 1813 } else { 1814 Slog.d(TAG, "could not generate certificate"); 1815 } 1816 } else { 1817 Slog.e(TAG, "Could not load client certificate " + Credentials 1818 .USER_CERTIFICATE + client); 1819 mNeedsSoftwareKeystore = true; 1820 } 1821 1822 } catch(CertificateException e) { 1823 Slog.e(TAG, "Could not read certificates"); 1824 mCaCert = null; 1825 mClientCertificate = null; 1826 } 1827 */ 1828 1829 return false; 1830 } 1831 1832 boolean installKeys(WifiEnterpriseConfig config, String name) { 1833 boolean ret = true; 1834 String privKeyName = Credentials.USER_PRIVATE_KEY + name; 1835 String userCertName = Credentials.USER_CERTIFICATE + name; 1836 String caCertName = Credentials.CA_CERTIFICATE + name; 1837 if (config.getClientCertificate() != null) { 1838 byte[] privKeyData = config.getClientPrivateKey().getEncoded(); 1839 if (isHardwareBackedKey(config.getClientPrivateKey())) { 1840 // Hardware backed key store is secure enough to store keys un-encrypted, this 1841 // removes the need for user to punch a PIN to get access to these keys 1842 if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); 1843 ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, 1844 KeyStore.FLAG_NONE); 1845 } else { 1846 // Software backed key store is NOT secure enough to store keys un-encrypted. 1847 // Save keys encrypted so they are protected with user's PIN. User will 1848 // have to unlock phone before being able to use these keys and connect to 1849 // networks. 1850 if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); 1851 ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 1852 KeyStore.FLAG_ENCRYPTED); 1853 } 1854 if (ret == false) { 1855 return ret; 1856 } 1857 1858 ret = putCertInKeyStore(userCertName, config.getClientCertificate()); 1859 if (ret == false) { 1860 // Remove private key installed 1861 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 1862 return ret; 1863 } 1864 } 1865 1866 if (config.getCaCertificate() != null) { 1867 ret = putCertInKeyStore(caCertName, config.getCaCertificate()); 1868 if (ret == false) { 1869 if (config.getClientCertificate() != null) { 1870 // Remove client key+cert 1871 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 1872 mKeyStore.delete(userCertName, Process.WIFI_UID); 1873 } 1874 return ret; 1875 } 1876 } 1877 1878 // Set alias names 1879 if (config.getClientCertificate() != null) { 1880 config.setClientCertificateAlias(name); 1881 config.resetClientKeyEntry(); 1882 } 1883 1884 if (config.getCaCertificate() != null) { 1885 config.setCaCertificateAlias(name); 1886 config.resetCaCertificate(); 1887 } 1888 1889 return ret; 1890 } 1891 1892 private boolean putCertInKeyStore(String name, Certificate cert) { 1893 try { 1894 byte[] certData = Credentials.convertToPem(cert); 1895 if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); 1896 return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 1897 1898 } catch (IOException e1) { 1899 return false; 1900 } catch (CertificateException e2) { 1901 return false; 1902 } 1903 } 1904 1905 void removeKeys(WifiEnterpriseConfig config) { 1906 String client = config.getClientCertificateAlias(); 1907 // a valid client certificate is configured 1908 if (!TextUtils.isEmpty(client)) { 1909 if (DBG) Log.d(TAG, "removing client private key and user cert"); 1910 mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 1911 mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 1912 } 1913 1914 String ca = config.getCaCertificateAlias(); 1915 // a valid ca certificate is configured 1916 if (!TextUtils.isEmpty(ca)) { 1917 if (DBG) Log.d(TAG, "removing CA cert"); 1918 mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 1919 } 1920 } 1921 1922 1923 /** Migrates the old style TLS config to the new config style. This should only be used 1924 * when restoring an old wpa_supplicant.conf or upgrading from a previous 1925 * platform version. 1926 * @return true if the config was updated 1927 * @hide 1928 */ 1929 boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { 1930 String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 1931 /* 1932 * If the old configuration value is not present, then there is nothing 1933 * to do. 1934 */ 1935 if (TextUtils.isEmpty(oldPrivateKey)) { 1936 return false; 1937 } else { 1938 // Also ignore it if it's empty quotes. 1939 oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 1940 if (TextUtils.isEmpty(oldPrivateKey)) { 1941 return false; 1942 } 1943 } 1944 1945 config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE); 1946 config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, 1947 WifiEnterpriseConfig.ENGINE_ID_KEYSTORE); 1948 1949 /* 1950 * The old key started with the keystore:// URI prefix, but we don't 1951 * need that anymore. Trim it off if it exists. 1952 */ 1953 final String keyName; 1954 if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) { 1955 keyName = new String( 1956 oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length())); 1957 } else { 1958 keyName = oldPrivateKey; 1959 } 1960 config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName); 1961 1962 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY, 1963 config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 1964 1965 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY, 1966 config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 1967 1968 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, 1969 config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 1970 1971 // Remove old private_key string so we don't run this again. 1972 mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 1973 1974 return true; 1975 } 1976 1977 /** Migrate certs from global pool to wifi UID if not already done */ 1978 void migrateCerts(WifiEnterpriseConfig config) { 1979 String client = config.getClientCertificateAlias(); 1980 // a valid client certificate is configured 1981 if (!TextUtils.isEmpty(client)) { 1982 if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 1983 mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 1984 Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 1985 mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 1986 Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 1987 } 1988 } 1989 1990 String ca = config.getCaCertificateAlias(); 1991 // a valid ca certificate is configured 1992 if (!TextUtils.isEmpty(ca)) { 1993 if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 1994 mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 1995 Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 1996 } 1997 } 1998 } 1999 2000} 2001 2002