WifiConfigStore.java revision e095675c872f40f630aa3f9189eb5c02f3cfee6d
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 android.net.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.ProxyProperties; 26import android.net.RouteInfo; 27import android.net.wifi.WifiConfiguration.IpAssignment; 28import android.net.wifi.WifiConfiguration.KeyMgmt; 29import android.net.wifi.WifiConfiguration.ProxySettings; 30import android.net.wifi.WifiConfiguration.Status; 31import android.net.wifi.NetworkUpdateResult; 32import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 33import android.os.Environment; 34import android.os.Message; 35import android.os.Handler; 36import android.os.HandlerThread; 37import android.os.UserHandle; 38import android.text.TextUtils; 39import android.util.Log; 40 41import java.io.BufferedInputStream; 42import java.io.BufferedOutputStream; 43import java.io.DataInputStream; 44import java.io.DataOutputStream; 45import java.io.EOFException; 46import java.io.FileDescriptor; 47import java.io.FileInputStream; 48import java.io.FileOutputStream; 49import java.io.IOException; 50import java.io.PrintWriter; 51import java.net.InetAddress; 52import java.net.UnknownHostException; 53import java.util.ArrayList; 54import java.util.BitSet; 55import java.util.Collection; 56import java.util.HashMap; 57import java.util.Iterator; 58import java.util.List; 59import java.util.concurrent.atomic.AtomicInteger; 60 61/** 62 * This class provides the API to manage configured 63 * wifi networks. The API is not thread safe is being 64 * used only from WifiStateMachine. 65 * 66 * It deals with the following 67 * - Add/update/remove a WifiConfiguration 68 * The configuration contains two types of information. 69 * = IP and proxy configuration that is handled by WifiConfigStore and 70 * is saved to disk on any change. 71 * 72 * The format of configuration file is as follows: 73 * <version> 74 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 75 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 76 * .. 77 * 78 * (key, value) pairs for a given network are grouped together and can 79 * be in any order. A EOS at the end of a set of (key, value) pairs 80 * indicates that the next set of (key, value) pairs are for a new 81 * network. A network is identified by a unique ID_KEY. If there is no 82 * ID_KEY in the (key, value) pairs, the data is discarded. 83 * 84 * An invalid version on read would result in discarding the contents of 85 * the file. On the next write, the latest version is written to file. 86 * 87 * Any failures during read or write to the configuration file are ignored 88 * without reporting to the user since the likelihood of these errors are 89 * low and the impact on connectivity is low. 90 * 91 * = SSID & security details that is pushed to the supplicant. 92 * supplicant saves these details to the disk on calling 93 * saveConfigCommand(). 94 * 95 * We have two kinds of APIs exposed: 96 * > public API calls that provide fine grained control 97 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 98 * removeNetwork(). For these calls, the config is not persisted 99 * to the disk. (TODO: deprecate these calls in WifiManager) 100 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 101 * These calls persist the supplicant config to disk. 102 * 103 * - Maintain a list of configured networks for quick access 104 * 105 */ 106class WifiConfigStore { 107 108 private Context mContext; 109 private static final String TAG = "WifiConfigStore"; 110 private static final boolean DBG = false; 111 112 /* configured networks with network id as the key */ 113 private HashMap<Integer, WifiConfiguration> mConfiguredNetworks = 114 new HashMap<Integer, WifiConfiguration>(); 115 116 /* A network id is a unique identifier for a network configured in the 117 * supplicant. Network ids are generated when the supplicant reads 118 * the configuration file at start and can thus change for networks. 119 * We store the IP configuration for networks along with a unique id 120 * that is generated from SSID and security type of the network. A mapping 121 * from the generated unique id to network id of the network is needed to 122 * map supplicant config to IP configuration. */ 123 private HashMap<Integer, Integer> mNetworkIds = 124 new HashMap<Integer, Integer>(); 125 126 /* Tracks the highest priority of configured networks */ 127 private int mLastPriority = -1; 128 129 private static final String ipConfigFile = Environment.getDataDirectory() + 130 "/misc/wifi/ipconfig.txt"; 131 132 private static final int IPCONFIG_FILE_VERSION = 2; 133 134 /* IP and proxy configuration keys */ 135 private static final String ID_KEY = "id"; 136 private static final String IP_ASSIGNMENT_KEY = "ipAssignment"; 137 private static final String LINK_ADDRESS_KEY = "linkAddress"; 138 private static final String GATEWAY_KEY = "gateway"; 139 private static final String DNS_KEY = "dns"; 140 private static final String PROXY_SETTINGS_KEY = "proxySettings"; 141 private static final String PROXY_HOST_KEY = "proxyHost"; 142 private static final String PROXY_PORT_KEY = "proxyPort"; 143 private static final String EXCLUSION_LIST_KEY = "exclusionList"; 144 private static final String EOS = "eos"; 145 146 private WifiNative mWifiNative; 147 148 WifiConfigStore(Context c, WifiNative wn) { 149 mContext = c; 150 mWifiNative = wn; 151 } 152 153 /** 154 * Fetch the list of configured networks 155 * and enable all stored networks in supplicant. 156 */ 157 void initialize() { 158 if (DBG) log("Loading config and enabling all networks"); 159 loadConfiguredNetworks(); 160 enableAllNetworks(); 161 } 162 163 /** 164 * Fetch the list of currently configured networks 165 * @return List of networks 166 */ 167 List<WifiConfiguration> getConfiguredNetworks() { 168 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 169 for(WifiConfiguration config : mConfiguredNetworks.values()) { 170 networks.add(new WifiConfiguration(config)); 171 } 172 return networks; 173 } 174 175 /** 176 * enable all networks and save config. This will be a no-op if the list 177 * of configured networks indicates all networks as being enabled 178 */ 179 void enableAllNetworks() { 180 boolean networkEnabledStateChanged = false; 181 for(WifiConfiguration config : mConfiguredNetworks.values()) { 182 if(config != null && config.status == Status.DISABLED) { 183 if(mWifiNative.enableNetwork(config.networkId, false)) { 184 networkEnabledStateChanged = true; 185 config.status = Status.ENABLED; 186 } else { 187 loge("Enable network failed on " + config.networkId); 188 } 189 } 190 } 191 192 if (networkEnabledStateChanged) { 193 mWifiNative.saveConfig(); 194 sendConfiguredNetworksChangedBroadcast(); 195 } 196 } 197 198 199 /** 200 * Selects the specified network for connection. This involves 201 * updating the priority of all the networks and enabling the given 202 * network while disabling others. 203 * 204 * Selecting a network will leave the other networks disabled and 205 * a call to enableAllNetworks() needs to be issued upon a connection 206 * or a failure event from supplicant 207 * 208 * @param netId network to select for connection 209 * @return false if the network id is invalid 210 */ 211 boolean selectNetwork(int netId) { 212 if (netId == INVALID_NETWORK_ID) return false; 213 214 // Reset the priority of each network at start or if it goes too high. 215 if (mLastPriority == -1 || mLastPriority > 1000000) { 216 for(WifiConfiguration config : mConfiguredNetworks.values()) { 217 if (config.networkId != INVALID_NETWORK_ID) { 218 config.priority = 0; 219 addOrUpdateNetworkNative(config); 220 } 221 } 222 mLastPriority = 0; 223 } 224 225 // Set to the highest priority and save the configuration. 226 WifiConfiguration config = new WifiConfiguration(); 227 config.networkId = netId; 228 config.priority = ++mLastPriority; 229 230 addOrUpdateNetworkNative(config); 231 mWifiNative.saveConfig(); 232 233 /* Enable the given network while disabling all other networks */ 234 enableNetworkWithoutBroadcast(netId, true); 235 236 /* Avoid saving the config & sending a broadcast to prevent settings 237 * from displaying a disabled list of networks */ 238 return true; 239 } 240 241 /** 242 * Add/update the specified configuration and save config 243 * 244 * @param config WifiConfiguration to be saved 245 * @return network update result 246 */ 247 NetworkUpdateResult saveNetwork(WifiConfiguration config) { 248 // A new network cannot have null SSID 249 if (config == null || (config.networkId == INVALID_NETWORK_ID && 250 config.SSID == null)) { 251 return new NetworkUpdateResult(INVALID_NETWORK_ID); 252 } 253 254 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 255 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 256 int netId = result.getNetworkId(); 257 /* enable a new network */ 258 if (newNetwork && netId != INVALID_NETWORK_ID) { 259 mWifiNative.enableNetwork(netId, false); 260 mConfiguredNetworks.get(netId).status = Status.ENABLED; 261 } 262 mWifiNative.saveConfig(); 263 sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ? 264 WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 265 return result; 266 } 267 268 void updateStatus(int netId, DetailedState state) { 269 if (netId != INVALID_NETWORK_ID) { 270 WifiConfiguration config = mConfiguredNetworks.get(netId); 271 if (config == null) return; 272 switch (state) { 273 case CONNECTED: 274 config.status = Status.CURRENT; 275 break; 276 case DISCONNECTED: 277 //If network is already disabled, keep the status 278 if (config.status == Status.CURRENT) { 279 config.status = Status.ENABLED; 280 } 281 break; 282 default: 283 //do nothing, retain the existing state 284 break; 285 } 286 } 287 } 288 289 /** 290 * Forget the specified network and save config 291 * 292 * @param netId network to forget 293 * @return {@code true} if it succeeds, {@code false} otherwise 294 */ 295 boolean forgetNetwork(int netId) { 296 if (mWifiNative.removeNetwork(netId)) { 297 mWifiNative.saveConfig(); 298 WifiConfiguration target = null; 299 WifiConfiguration config = mConfiguredNetworks.get(netId); 300 if (config != null) { 301 target = mConfiguredNetworks.remove(netId); 302 mNetworkIds.remove(configKey(config)); 303 } 304 if (target != null) { 305 writeIpAndProxyConfigurations(); 306 sendConfiguredNetworksChangedBroadcast(target, WifiManager.CHANGE_REASON_REMOVED); 307 } 308 return true; 309 } else { 310 loge("Failed to remove network " + netId); 311 return false; 312 } 313 } 314 315 /** 316 * Add/update a network. Note that there is no saveConfig operation. 317 * This function is retained for compatibility with the public 318 * API. The more powerful saveNetwork() is used by the 319 * state machine 320 * 321 * @param config wifi configuration to add/update 322 * @return network Id 323 */ 324 int addOrUpdateNetwork(WifiConfiguration config) { 325 NetworkUpdateResult result = addOrUpdateNetworkNative(config); 326 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 327 sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()), 328 result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : 329 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 330 } 331 return result.getNetworkId(); 332 } 333 334 /** 335 * Remove a network. Note that there is no saveConfig operation. 336 * This function is retained for compatibility with the public 337 * API. The more powerful forgetNetwork() is used by the 338 * state machine for network removal 339 * 340 * @param netId network to be removed 341 * @return {@code true} if it succeeds, {@code false} otherwise 342 */ 343 boolean removeNetwork(int netId) { 344 boolean ret = mWifiNative.removeNetwork(netId); 345 WifiConfiguration config = null; 346 if (ret) { 347 config = mConfiguredNetworks.get(netId); 348 if (config != null) { 349 config = mConfiguredNetworks.remove(netId); 350 mNetworkIds.remove(configKey(config)); 351 } 352 } 353 if (config != null) { 354 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 355 } 356 return ret; 357 } 358 359 /** 360 * Enable a network. Note that there is no saveConfig operation. 361 * This function is retained for compatibility with the public 362 * API. The more powerful selectNetwork()/saveNetwork() is used by the 363 * state machine for connecting to a network 364 * 365 * @param netId network to be enabled 366 * @return {@code true} if it succeeds, {@code false} otherwise 367 */ 368 boolean enableNetwork(int netId, boolean disableOthers) { 369 boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); 370 if (disableOthers) { 371 sendConfiguredNetworksChangedBroadcast(); 372 } else { 373 WifiConfiguration enabledNetwork = null; 374 synchronized(mConfiguredNetworks) { 375 enabledNetwork = mConfiguredNetworks.get(netId); 376 } 377 // check just in case the network was removed by someone else. 378 if (enabledNetwork != null) { 379 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 380 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 381 } 382 } 383 return ret; 384 } 385 386 boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { 387 boolean ret = mWifiNative.enableNetwork(netId, disableOthers); 388 389 WifiConfiguration config = mConfiguredNetworks.get(netId); 390 if (config != null) config.status = Status.ENABLED; 391 392 if (disableOthers) { 393 markAllNetworksDisabledExcept(netId); 394 } 395 return ret; 396 } 397 398 /** 399 * Disable a network. Note that there is no saveConfig operation. 400 * @param netId network to be disabled 401 * @return {@code true} if it succeeds, {@code false} otherwise 402 */ 403 boolean disableNetwork(int netId) { 404 return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); 405 } 406 407 /** 408 * Disable a network. Note that there is no saveConfig operation. 409 * @param netId network to be disabled 410 * @param reason reason code network was disabled 411 * @return {@code true} if it succeeds, {@code false} otherwise 412 */ 413 boolean disableNetwork(int netId, int reason) { 414 boolean ret = mWifiNative.disableNetwork(netId); 415 WifiConfiguration network = null; 416 WifiConfiguration config = mConfiguredNetworks.get(netId); 417 /* Only change the reason if the network was not previously disabled */ 418 if (config != null && config.status != Status.DISABLED) { 419 config.status = Status.DISABLED; 420 config.disableReason = reason; 421 network = config; 422 } 423 if (network != null) { 424 sendConfiguredNetworksChangedBroadcast(network, 425 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 426 } 427 return ret; 428 } 429 430 /** 431 * Save the configured networks in supplicant to disk 432 * @return {@code true} if it succeeds, {@code false} otherwise 433 */ 434 boolean saveConfig() { 435 return mWifiNative.saveConfig(); 436 } 437 438 /** 439 * Start WPS pin method configuration with pin obtained 440 * from the access point 441 * @param config WPS configuration 442 * @return Wps result containing status and pin 443 */ 444 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 445 WpsResult result = new WpsResult(); 446 if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { 447 /* WPS leaves all networks disabled */ 448 markAllNetworksDisabled(); 449 result.status = WpsResult.Status.SUCCESS; 450 } else { 451 loge("Failed to start WPS pin method configuration"); 452 result.status = WpsResult.Status.FAILURE; 453 } 454 return result; 455 } 456 457 /** 458 * Start WPS pin method configuration with pin obtained 459 * from the device 460 * @return WpsResult indicating status and pin 461 */ 462 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 463 WpsResult result = new WpsResult(); 464 result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); 465 /* WPS leaves all networks disabled */ 466 if (!TextUtils.isEmpty(result.pin)) { 467 markAllNetworksDisabled(); 468 result.status = WpsResult.Status.SUCCESS; 469 } else { 470 loge("Failed to start WPS pin method configuration"); 471 result.status = WpsResult.Status.FAILURE; 472 } 473 return result; 474 } 475 476 /** 477 * Start WPS push button configuration 478 * @param config WPS configuration 479 * @return WpsResult indicating status and pin 480 */ 481 WpsResult startWpsPbc(WpsInfo config) { 482 WpsResult result = new WpsResult(); 483 if (mWifiNative.startWpsPbc(config.BSSID)) { 484 /* WPS leaves all networks disabled */ 485 markAllNetworksDisabled(); 486 result.status = WpsResult.Status.SUCCESS; 487 } else { 488 loge("Failed to start WPS push button configuration"); 489 result.status = WpsResult.Status.FAILURE; 490 } 491 return result; 492 } 493 494 /** 495 * Fetch the link properties for a given network id 496 * @return LinkProperties for the given network id 497 */ 498 LinkProperties getLinkProperties(int netId) { 499 WifiConfiguration config = mConfiguredNetworks.get(netId); 500 if (config != null) return new LinkProperties(config.linkProperties); 501 return null; 502 } 503 504 /** 505 * set IP configuration for a given network id 506 */ 507 void setLinkProperties(int netId, LinkProperties linkProperties) { 508 WifiConfiguration config = mConfiguredNetworks.get(netId); 509 if (config != null) { 510 // add old proxy details - TODO - is this still needed? 511 if(config.linkProperties != null) { 512 linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); 513 } 514 config.linkProperties = linkProperties; 515 } 516 } 517 518 /** 519 * clear IP configuration for a given network id 520 * @param network id 521 */ 522 void clearLinkProperties(int netId) { 523 WifiConfiguration config = mConfiguredNetworks.get(netId); 524 if (config != null && config.linkProperties != null) { 525 // Clear everything except proxy 526 ProxyProperties proxy = config.linkProperties.getHttpProxy(); 527 config.linkProperties.clear(); 528 config.linkProperties.setHttpProxy(proxy); 529 } 530 } 531 532 533 /** 534 * Fetch the proxy properties for a given network id 535 * @param network id 536 * @return ProxyProperties for the network id 537 */ 538 ProxyProperties getProxyProperties(int netId) { 539 LinkProperties linkProperties = getLinkProperties(netId); 540 if (linkProperties != null) { 541 return new ProxyProperties(linkProperties.getHttpProxy()); 542 } 543 return null; 544 } 545 546 /** 547 * Return if the specified network is using static IP 548 * @param network id 549 * @return {@code true} if using static ip for netId 550 */ 551 boolean isUsingStaticIp(int netId) { 552 WifiConfiguration config = mConfiguredNetworks.get(netId); 553 if (config != null && config.ipAssignment == IpAssignment.STATIC) { 554 return true; 555 } 556 return false; 557 } 558 559 /** 560 * Should be called when a single network configuration is made. 561 * @param network The network configuration that changed. 562 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 563 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 564 */ 565 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 566 int reason) { 567 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 568 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 569 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 570 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 571 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 572 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 573 } 574 575 /** 576 * Should be called when multiple network configuration changes are made. 577 */ 578 private void sendConfiguredNetworksChangedBroadcast() { 579 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 580 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 581 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 582 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 583 } 584 585 void loadConfiguredNetworks() { 586 String listStr = mWifiNative.listNetworks(); 587 mLastPriority = 0; 588 589 mConfiguredNetworks.clear(); 590 mNetworkIds.clear(); 591 592 if (listStr == null) 593 return; 594 595 String[] lines = listStr.split("\n"); 596 // Skip the first line, which is a header 597 for (int i = 1; i < lines.length; i++) { 598 String[] result = lines[i].split("\t"); 599 // network-id | ssid | bssid | flags 600 WifiConfiguration config = new WifiConfiguration(); 601 try { 602 config.networkId = Integer.parseInt(result[0]); 603 } catch(NumberFormatException e) { 604 continue; 605 } 606 if (result.length > 3) { 607 if (result[3].indexOf("[CURRENT]") != -1) 608 config.status = WifiConfiguration.Status.CURRENT; 609 else if (result[3].indexOf("[DISABLED]") != -1) 610 config.status = WifiConfiguration.Status.DISABLED; 611 else 612 config.status = WifiConfiguration.Status.ENABLED; 613 } else { 614 config.status = WifiConfiguration.Status.ENABLED; 615 } 616 readNetworkVariables(config); 617 if (config.priority > mLastPriority) { 618 mLastPriority = config.priority; 619 } 620 mConfiguredNetworks.put(config.networkId, config); 621 mNetworkIds.put(configKey(config), config.networkId); 622 } 623 624 readIpAndProxyConfigurations(); 625 sendConfiguredNetworksChangedBroadcast(); 626 } 627 628 /* Mark all networks except specified netId as disabled */ 629 private void markAllNetworksDisabledExcept(int netId) { 630 for(WifiConfiguration config : mConfiguredNetworks.values()) { 631 if(config != null && config.networkId != netId) { 632 if (config.status != Status.DISABLED) { 633 config.status = Status.DISABLED; 634 config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; 635 } 636 } 637 } 638 } 639 640 private void markAllNetworksDisabled() { 641 markAllNetworksDisabledExcept(INVALID_NETWORK_ID); 642 } 643 644 private void writeIpAndProxyConfigurations() { 645 646 /* Make a copy */ 647 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 648 for(WifiConfiguration config : mConfiguredNetworks.values()) { 649 networks.add(new WifiConfiguration(config)); 650 } 651 652 DelayedDiskWrite.write(networks); 653 } 654 655 private static class DelayedDiskWrite { 656 657 private static HandlerThread sDiskWriteHandlerThread; 658 private static Handler sDiskWriteHandler; 659 /* Tracks multiple writes on the same thread */ 660 private static int sWriteSequence = 0; 661 private static final String TAG = "DelayedDiskWrite"; 662 663 static void write (final List<WifiConfiguration> networks) { 664 665 /* Do a delayed write to disk on a seperate handler thread */ 666 synchronized (DelayedDiskWrite.class) { 667 if (++sWriteSequence == 1) { 668 sDiskWriteHandlerThread = new HandlerThread("WifiConfigThread"); 669 sDiskWriteHandlerThread.start(); 670 sDiskWriteHandler = new Handler(sDiskWriteHandlerThread.getLooper()); 671 } 672 } 673 674 sDiskWriteHandler.post(new Runnable() { 675 @Override 676 public void run() { 677 onWriteCalled(networks); 678 } 679 }); 680 } 681 682 private static void onWriteCalled(List<WifiConfiguration> networks) { 683 684 DataOutputStream out = null; 685 try { 686 out = new DataOutputStream(new BufferedOutputStream( 687 new FileOutputStream(ipConfigFile))); 688 689 out.writeInt(IPCONFIG_FILE_VERSION); 690 691 for(WifiConfiguration config : networks) { 692 boolean writeToFile = false; 693 694 try { 695 LinkProperties linkProperties = config.linkProperties; 696 switch (config.ipAssignment) { 697 case STATIC: 698 out.writeUTF(IP_ASSIGNMENT_KEY); 699 out.writeUTF(config.ipAssignment.toString()); 700 for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { 701 out.writeUTF(LINK_ADDRESS_KEY); 702 out.writeUTF(linkAddr.getAddress().getHostAddress()); 703 out.writeInt(linkAddr.getNetworkPrefixLength()); 704 } 705 for (RouteInfo route : linkProperties.getRoutes()) { 706 out.writeUTF(GATEWAY_KEY); 707 LinkAddress dest = route.getDestination(); 708 if (dest != null) { 709 out.writeInt(1); 710 out.writeUTF(dest.getAddress().getHostAddress()); 711 out.writeInt(dest.getNetworkPrefixLength()); 712 } else { 713 out.writeInt(0); 714 } 715 if (route.getGateway() != null) { 716 out.writeInt(1); 717 out.writeUTF(route.getGateway().getHostAddress()); 718 } else { 719 out.writeInt(0); 720 } 721 } 722 for (InetAddress inetAddr : linkProperties.getDnses()) { 723 out.writeUTF(DNS_KEY); 724 out.writeUTF(inetAddr.getHostAddress()); 725 } 726 writeToFile = true; 727 break; 728 case DHCP: 729 out.writeUTF(IP_ASSIGNMENT_KEY); 730 out.writeUTF(config.ipAssignment.toString()); 731 writeToFile = true; 732 break; 733 case UNASSIGNED: 734 /* Ignore */ 735 break; 736 default: 737 loge("Ignore invalid ip assignment while writing"); 738 break; 739 } 740 741 switch (config.proxySettings) { 742 case STATIC: 743 ProxyProperties proxyProperties = linkProperties.getHttpProxy(); 744 String exclusionList = proxyProperties.getExclusionList(); 745 out.writeUTF(PROXY_SETTINGS_KEY); 746 out.writeUTF(config.proxySettings.toString()); 747 out.writeUTF(PROXY_HOST_KEY); 748 out.writeUTF(proxyProperties.getHost()); 749 out.writeUTF(PROXY_PORT_KEY); 750 out.writeInt(proxyProperties.getPort()); 751 out.writeUTF(EXCLUSION_LIST_KEY); 752 out.writeUTF(exclusionList); 753 writeToFile = true; 754 break; 755 case NONE: 756 out.writeUTF(PROXY_SETTINGS_KEY); 757 out.writeUTF(config.proxySettings.toString()); 758 writeToFile = true; 759 break; 760 case UNASSIGNED: 761 /* Ignore */ 762 break; 763 default: 764 loge("Ignthisore invalid proxy settings while writing"); 765 break; 766 } 767 if (writeToFile) { 768 out.writeUTF(ID_KEY); 769 out.writeInt(configKey(config)); 770 } 771 } catch (NullPointerException e) { 772 loge("Failure in writing " + config.linkProperties + e); 773 } 774 out.writeUTF(EOS); 775 } 776 777 } catch (IOException e) { 778 loge("Error writing data file"); 779 } finally { 780 if (out != null) { 781 try { 782 out.close(); 783 } catch (Exception e) {} 784 } 785 786 //Quit if no more writes sent 787 synchronized (DelayedDiskWrite.class) { 788 if (--sWriteSequence == 0) { 789 sDiskWriteHandler.getLooper().quit(); 790 sDiskWriteHandler = null; 791 sDiskWriteHandlerThread = null; 792 } 793 } 794 } 795 } 796 797 private static void loge(String s) { 798 Log.e(TAG, s); 799 } 800 } 801 802 private void readIpAndProxyConfigurations() { 803 804 DataInputStream in = null; 805 try { 806 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 807 ipConfigFile))); 808 809 int version = in.readInt(); 810 if (version != 2 && version != 1) { 811 loge("Bad version on IP configuration file, ignore read"); 812 return; 813 } 814 815 while (true) { 816 int id = -1; 817 IpAssignment ipAssignment = IpAssignment.UNASSIGNED; 818 ProxySettings proxySettings = ProxySettings.UNASSIGNED; 819 LinkProperties linkProperties = new LinkProperties(); 820 String proxyHost = null; 821 int proxyPort = -1; 822 String exclusionList = null; 823 String key; 824 825 do { 826 key = in.readUTF(); 827 try { 828 if (key.equals(ID_KEY)) { 829 id = in.readInt(); 830 } else if (key.equals(IP_ASSIGNMENT_KEY)) { 831 ipAssignment = IpAssignment.valueOf(in.readUTF()); 832 } else if (key.equals(LINK_ADDRESS_KEY)) { 833 LinkAddress linkAddr = new LinkAddress( 834 NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); 835 linkProperties.addLinkAddress(linkAddr); 836 } else if (key.equals(GATEWAY_KEY)) { 837 LinkAddress dest = null; 838 InetAddress gateway = null; 839 if (version == 1) { 840 // only supported default gateways - leave the dest/prefix empty 841 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 842 } else { 843 if (in.readInt() == 1) { 844 dest = new LinkAddress( 845 NetworkUtils.numericToInetAddress(in.readUTF()), 846 in.readInt()); 847 } 848 if (in.readInt() == 1) { 849 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 850 } 851 } 852 linkProperties.addRoute(new RouteInfo(dest, gateway)); 853 } else if (key.equals(DNS_KEY)) { 854 linkProperties.addDns( 855 NetworkUtils.numericToInetAddress(in.readUTF())); 856 } else if (key.equals(PROXY_SETTINGS_KEY)) { 857 proxySettings = ProxySettings.valueOf(in.readUTF()); 858 } else if (key.equals(PROXY_HOST_KEY)) { 859 proxyHost = in.readUTF(); 860 } else if (key.equals(PROXY_PORT_KEY)) { 861 proxyPort = in.readInt(); 862 } else if (key.equals(EXCLUSION_LIST_KEY)) { 863 exclusionList = in.readUTF(); 864 } else if (key.equals(EOS)) { 865 break; 866 } else { 867 loge("Ignore unknown key " + key + "while reading"); 868 } 869 } catch (IllegalArgumentException e) { 870 loge("Ignore invalid address while reading" + e); 871 } 872 } while (true); 873 874 if (id != -1) { 875 WifiConfiguration config = mConfiguredNetworks.get( 876 mNetworkIds.get(id)); 877 878 if (config == null) { 879 loge("configuration found for missing network, ignored"); 880 } else { 881 config.linkProperties = linkProperties; 882 switch (ipAssignment) { 883 case STATIC: 884 case DHCP: 885 config.ipAssignment = ipAssignment; 886 break; 887 case UNASSIGNED: 888 //Ignore 889 break; 890 default: 891 loge("Ignore invalid ip assignment while reading"); 892 break; 893 } 894 895 switch (proxySettings) { 896 case STATIC: 897 config.proxySettings = proxySettings; 898 ProxyProperties proxyProperties = 899 new ProxyProperties(proxyHost, proxyPort, exclusionList); 900 linkProperties.setHttpProxy(proxyProperties); 901 break; 902 case NONE: 903 config.proxySettings = proxySettings; 904 break; 905 case UNASSIGNED: 906 //Ignore 907 break; 908 default: 909 loge("Ignore invalid proxy settings while reading"); 910 break; 911 } 912 } 913 } else { 914 if (DBG) log("Missing id while parsing configuration"); 915 } 916 } 917 } catch (EOFException ignore) { 918 } catch (IOException e) { 919 loge("Error parsing configuration" + e); 920 } finally { 921 if (in != null) { 922 try { 923 in.close(); 924 } catch (Exception e) {} 925 } 926 } 927 } 928 929 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { 930 /* 931 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 932 * network configuration. Otherwise, the networkId should 933 * refer to an existing configuration. 934 */ 935 int netId = config.networkId; 936 boolean newNetwork = false; 937 // networkId of INVALID_NETWORK_ID means we want to create a new network 938 if (netId == INVALID_NETWORK_ID) { 939 Integer savedNetId = mNetworkIds.get(configKey(config)); 940 if (savedNetId != null) { 941 netId = savedNetId; 942 } else { 943 newNetwork = true; 944 netId = mWifiNative.addNetwork(); 945 if (netId < 0) { 946 loge("Failed to add a network!"); 947 return new NetworkUpdateResult(INVALID_NETWORK_ID); 948 } 949 } 950 } 951 952 boolean updateFailed = true; 953 954 setVariables: { 955 956 if (config.SSID != null && 957 !mWifiNative.setNetworkVariable( 958 netId, 959 WifiConfiguration.ssidVarName, 960 config.SSID)) { 961 loge("failed to set SSID: "+config.SSID); 962 break setVariables; 963 } 964 965 if (config.BSSID != null && 966 !mWifiNative.setNetworkVariable( 967 netId, 968 WifiConfiguration.bssidVarName, 969 config.BSSID)) { 970 loge("failed to set BSSID: "+config.BSSID); 971 break setVariables; 972 } 973 974 String allowedKeyManagementString = 975 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 976 if (config.allowedKeyManagement.cardinality() != 0 && 977 !mWifiNative.setNetworkVariable( 978 netId, 979 WifiConfiguration.KeyMgmt.varName, 980 allowedKeyManagementString)) { 981 loge("failed to set key_mgmt: "+ 982 allowedKeyManagementString); 983 break setVariables; 984 } 985 986 String allowedProtocolsString = 987 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 988 if (config.allowedProtocols.cardinality() != 0 && 989 !mWifiNative.setNetworkVariable( 990 netId, 991 WifiConfiguration.Protocol.varName, 992 allowedProtocolsString)) { 993 loge("failed to set proto: "+ 994 allowedProtocolsString); 995 break setVariables; 996 } 997 998 String allowedAuthAlgorithmsString = 999 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 1000 if (config.allowedAuthAlgorithms.cardinality() != 0 && 1001 !mWifiNative.setNetworkVariable( 1002 netId, 1003 WifiConfiguration.AuthAlgorithm.varName, 1004 allowedAuthAlgorithmsString)) { 1005 loge("failed to set auth_alg: "+ 1006 allowedAuthAlgorithmsString); 1007 break setVariables; 1008 } 1009 1010 String allowedPairwiseCiphersString = 1011 makeString(config.allowedPairwiseCiphers, 1012 WifiConfiguration.PairwiseCipher.strings); 1013 if (config.allowedPairwiseCiphers.cardinality() != 0 && 1014 !mWifiNative.setNetworkVariable( 1015 netId, 1016 WifiConfiguration.PairwiseCipher.varName, 1017 allowedPairwiseCiphersString)) { 1018 loge("failed to set pairwise: "+ 1019 allowedPairwiseCiphersString); 1020 break setVariables; 1021 } 1022 1023 String allowedGroupCiphersString = 1024 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 1025 if (config.allowedGroupCiphers.cardinality() != 0 && 1026 !mWifiNative.setNetworkVariable( 1027 netId, 1028 WifiConfiguration.GroupCipher.varName, 1029 allowedGroupCiphersString)) { 1030 loge("failed to set group: "+ 1031 allowedGroupCiphersString); 1032 break setVariables; 1033 } 1034 1035 // Prevent client screw-up by passing in a WifiConfiguration we gave it 1036 // by preventing "*" as a key. 1037 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 1038 !mWifiNative.setNetworkVariable( 1039 netId, 1040 WifiConfiguration.pskVarName, 1041 config.preSharedKey)) { 1042 loge("failed to set psk"); 1043 break setVariables; 1044 } 1045 1046 boolean hasSetKey = false; 1047 if (config.wepKeys != null) { 1048 for (int i = 0; i < config.wepKeys.length; i++) { 1049 // Prevent client screw-up by passing in a WifiConfiguration we gave it 1050 // by preventing "*" as a key. 1051 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 1052 if (!mWifiNative.setNetworkVariable( 1053 netId, 1054 WifiConfiguration.wepKeyVarNames[i], 1055 config.wepKeys[i])) { 1056 loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); 1057 break setVariables; 1058 } 1059 hasSetKey = true; 1060 } 1061 } 1062 } 1063 1064 if (hasSetKey) { 1065 if (!mWifiNative.setNetworkVariable( 1066 netId, 1067 WifiConfiguration.wepTxKeyIdxVarName, 1068 Integer.toString(config.wepTxKeyIndex))) { 1069 loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); 1070 break setVariables; 1071 } 1072 } 1073 1074 if (!mWifiNative.setNetworkVariable( 1075 netId, 1076 WifiConfiguration.priorityVarName, 1077 Integer.toString(config.priority))) { 1078 loge(config.SSID + ": failed to set priority: " 1079 +config.priority); 1080 break setVariables; 1081 } 1082 1083 if (config.hiddenSSID && !mWifiNative.setNetworkVariable( 1084 netId, 1085 WifiConfiguration.hiddenSSIDVarName, 1086 Integer.toString(config.hiddenSSID ? 1 : 0))) { 1087 loge(config.SSID + ": failed to set hiddenSSID: "+ 1088 config.hiddenSSID); 1089 break setVariables; 1090 } 1091 1092 if (config.enterpriseConfig != null) { 1093 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 1094 for (String key : enterpriseFields.keySet()) { 1095 String value = enterpriseFields.get(key); 1096 if (!mWifiNative.setNetworkVariable( 1097 netId, 1098 key, 1099 value)) { 1100 loge(config.SSID + ": failed to set " + key + 1101 ": " + value); 1102 break setVariables; 1103 } 1104 } 1105 } 1106 updateFailed = false; 1107 } 1108 1109 if (updateFailed) { 1110 if (newNetwork) { 1111 mWifiNative.removeNetwork(netId); 1112 loge("Failed to set a network variable, removed network: " + netId); 1113 } 1114 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1115 } 1116 1117 /* An update of the network variables requires reading them 1118 * back from the supplicant to update mConfiguredNetworks. 1119 * This is because some of the variables (SSID, wep keys & 1120 * passphrases) reflect different values when read back than 1121 * when written. For example, wep key is stored as * irrespective 1122 * of the value sent to the supplicant 1123 */ 1124 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 1125 if (currentConfig == null) { 1126 currentConfig = new WifiConfiguration(); 1127 currentConfig.networkId = netId; 1128 } 1129 1130 readNetworkVariables(currentConfig); 1131 1132 mConfiguredNetworks.put(netId, currentConfig); 1133 mNetworkIds.put(configKey(currentConfig), netId); 1134 1135 NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); 1136 result.setIsNewNetwork(newNetwork); 1137 result.setNetworkId(netId); 1138 return result; 1139 } 1140 1141 /* Compare current and new configuration and write to file on change */ 1142 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 1143 WifiConfiguration currentConfig, 1144 WifiConfiguration newConfig) { 1145 boolean ipChanged = false; 1146 boolean proxyChanged = false; 1147 LinkProperties linkProperties = new LinkProperties(); 1148 1149 switch (newConfig.ipAssignment) { 1150 case STATIC: 1151 Collection<LinkAddress> currentLinkAddresses = currentConfig.linkProperties 1152 .getLinkAddresses(); 1153 Collection<LinkAddress> newLinkAddresses = newConfig.linkProperties 1154 .getLinkAddresses(); 1155 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses(); 1156 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses(); 1157 Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes(); 1158 Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes(); 1159 1160 boolean linkAddressesDiffer = 1161 (currentLinkAddresses.size() != newLinkAddresses.size()) || 1162 !currentLinkAddresses.containsAll(newLinkAddresses); 1163 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || 1164 !currentDnses.containsAll(newDnses); 1165 boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || 1166 !currentRoutes.containsAll(newRoutes); 1167 1168 if ((currentConfig.ipAssignment != newConfig.ipAssignment) || 1169 linkAddressesDiffer || 1170 dnsesDiffer || 1171 routesDiffer) { 1172 ipChanged = true; 1173 } 1174 break; 1175 case DHCP: 1176 if (currentConfig.ipAssignment != newConfig.ipAssignment) { 1177 ipChanged = true; 1178 } 1179 break; 1180 case UNASSIGNED: 1181 /* Ignore */ 1182 break; 1183 default: 1184 loge("Ignore invalid ip assignment during write"); 1185 break; 1186 } 1187 1188 switch (newConfig.proxySettings) { 1189 case STATIC: 1190 ProxyProperties newHttpProxy = newConfig.linkProperties.getHttpProxy(); 1191 ProxyProperties currentHttpProxy = currentConfig.linkProperties.getHttpProxy(); 1192 1193 if (newHttpProxy != null) { 1194 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 1195 } else { 1196 proxyChanged = (currentHttpProxy != null); 1197 } 1198 break; 1199 case NONE: 1200 if (currentConfig.proxySettings != newConfig.proxySettings) { 1201 proxyChanged = true; 1202 } 1203 break; 1204 case UNASSIGNED: 1205 /* Ignore */ 1206 break; 1207 default: 1208 loge("Ignore invalid proxy configuration during write"); 1209 break; 1210 } 1211 1212 if (!ipChanged) { 1213 addIpSettingsFromConfig(linkProperties, currentConfig); 1214 } else { 1215 currentConfig.ipAssignment = newConfig.ipAssignment; 1216 addIpSettingsFromConfig(linkProperties, newConfig); 1217 log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " + 1218 linkProperties.toString()); 1219 } 1220 1221 1222 if (!proxyChanged) { 1223 linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy()); 1224 } else { 1225 currentConfig.proxySettings = newConfig.proxySettings; 1226 linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy()); 1227 log("proxy changed SSID = " + currentConfig.SSID); 1228 if (linkProperties.getHttpProxy() != null) { 1229 log(" proxyProperties: " + linkProperties.getHttpProxy().toString()); 1230 } 1231 } 1232 1233 if (ipChanged || proxyChanged) { 1234 currentConfig.linkProperties = linkProperties; 1235 writeIpAndProxyConfigurations(); 1236 sendConfiguredNetworksChangedBroadcast(currentConfig, 1237 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1238 } 1239 return new NetworkUpdateResult(ipChanged, proxyChanged); 1240 } 1241 1242 private void addIpSettingsFromConfig(LinkProperties linkProperties, 1243 WifiConfiguration config) { 1244 for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { 1245 linkProperties.addLinkAddress(linkAddr); 1246 } 1247 for (RouteInfo route : config.linkProperties.getRoutes()) { 1248 linkProperties.addRoute(route); 1249 } 1250 for (InetAddress dns : config.linkProperties.getDnses()) { 1251 linkProperties.addDns(dns); 1252 } 1253 } 1254 1255 /** 1256 * Read the variables from the supplicant daemon that are needed to 1257 * fill in the WifiConfiguration object. 1258 * 1259 * @param config the {@link WifiConfiguration} object to be filled in. 1260 */ 1261 private void readNetworkVariables(WifiConfiguration config) { 1262 1263 int netId = config.networkId; 1264 if (netId < 0) 1265 return; 1266 1267 /* 1268 * TODO: maybe should have a native method that takes an array of 1269 * variable names and returns an array of values. But we'd still 1270 * be doing a round trip to the supplicant daemon for each variable. 1271 */ 1272 String value; 1273 1274 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 1275 if (!TextUtils.isEmpty(value)) { 1276 if (value.charAt(0) != '"') { 1277 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 1278 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 1279 //supplicant string 1280 } else { 1281 config.SSID = value; 1282 } 1283 } else { 1284 config.SSID = null; 1285 } 1286 1287 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 1288 if (!TextUtils.isEmpty(value)) { 1289 config.BSSID = value; 1290 } else { 1291 config.BSSID = null; 1292 } 1293 1294 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 1295 config.priority = -1; 1296 if (!TextUtils.isEmpty(value)) { 1297 try { 1298 config.priority = Integer.parseInt(value); 1299 } catch (NumberFormatException ignore) { 1300 } 1301 } 1302 1303 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 1304 config.hiddenSSID = false; 1305 if (!TextUtils.isEmpty(value)) { 1306 try { 1307 config.hiddenSSID = Integer.parseInt(value) != 0; 1308 } catch (NumberFormatException ignore) { 1309 } 1310 } 1311 1312 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 1313 config.wepTxKeyIndex = -1; 1314 if (!TextUtils.isEmpty(value)) { 1315 try { 1316 config.wepTxKeyIndex = Integer.parseInt(value); 1317 } catch (NumberFormatException ignore) { 1318 } 1319 } 1320 1321 for (int i = 0; i < 4; i++) { 1322 value = mWifiNative.getNetworkVariable(netId, 1323 WifiConfiguration.wepKeyVarNames[i]); 1324 if (!TextUtils.isEmpty(value)) { 1325 config.wepKeys[i] = value; 1326 } else { 1327 config.wepKeys[i] = null; 1328 } 1329 } 1330 1331 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 1332 if (!TextUtils.isEmpty(value)) { 1333 config.preSharedKey = value; 1334 } else { 1335 config.preSharedKey = null; 1336 } 1337 1338 value = mWifiNative.getNetworkVariable(config.networkId, 1339 WifiConfiguration.Protocol.varName); 1340 if (!TextUtils.isEmpty(value)) { 1341 String vals[] = value.split(" "); 1342 for (String val : vals) { 1343 int index = 1344 lookupString(val, WifiConfiguration.Protocol.strings); 1345 if (0 <= index) { 1346 config.allowedProtocols.set(index); 1347 } 1348 } 1349 } 1350 1351 value = mWifiNative.getNetworkVariable(config.networkId, 1352 WifiConfiguration.KeyMgmt.varName); 1353 if (!TextUtils.isEmpty(value)) { 1354 String vals[] = value.split(" "); 1355 for (String val : vals) { 1356 int index = 1357 lookupString(val, WifiConfiguration.KeyMgmt.strings); 1358 if (0 <= index) { 1359 config.allowedKeyManagement.set(index); 1360 } 1361 } 1362 } 1363 1364 value = mWifiNative.getNetworkVariable(config.networkId, 1365 WifiConfiguration.AuthAlgorithm.varName); 1366 if (!TextUtils.isEmpty(value)) { 1367 String vals[] = value.split(" "); 1368 for (String val : vals) { 1369 int index = 1370 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 1371 if (0 <= index) { 1372 config.allowedAuthAlgorithms.set(index); 1373 } 1374 } 1375 } 1376 1377 value = mWifiNative.getNetworkVariable(config.networkId, 1378 WifiConfiguration.PairwiseCipher.varName); 1379 if (!TextUtils.isEmpty(value)) { 1380 String vals[] = value.split(" "); 1381 for (String val : vals) { 1382 int index = 1383 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 1384 if (0 <= index) { 1385 config.allowedPairwiseCiphers.set(index); 1386 } 1387 } 1388 } 1389 1390 value = mWifiNative.getNetworkVariable(config.networkId, 1391 WifiConfiguration.GroupCipher.varName); 1392 if (!TextUtils.isEmpty(value)) { 1393 String vals[] = value.split(" "); 1394 for (String val : vals) { 1395 int index = 1396 lookupString(val, WifiConfiguration.GroupCipher.strings); 1397 if (0 <= index) { 1398 config.allowedGroupCiphers.set(index); 1399 } 1400 } 1401 } 1402 1403 if (config.enterpriseConfig == null) { 1404 config.enterpriseConfig = new WifiEnterpriseConfig(); 1405 } 1406 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 1407 for (String key : WifiEnterpriseConfig.getSupplicantKeys()) { 1408 value = mWifiNative.getNetworkVariable(netId, key); 1409 if (!TextUtils.isEmpty(value)) { 1410 enterpriseFields.put(key, removeDoubleQuotes(value)); 1411 } else { 1412 enterpriseFields.put(key, WifiEnterpriseConfig.EMPTY_VALUE); 1413 } 1414 } 1415 1416 if (config.enterpriseConfig.migrateOldEapTlsNative(mWifiNative, netId)) { 1417 saveConfig(); 1418 } 1419 } 1420 1421 private String removeDoubleQuotes(String string) { 1422 int length = string.length(); 1423 if ((length > 1) && (string.charAt(0) == '"') 1424 && (string.charAt(length - 1) == '"')) { 1425 return string.substring(1, length - 1); 1426 } 1427 return string; 1428 } 1429 1430 private String convertToQuotedString(String string) { 1431 return "\"" + string + "\""; 1432 } 1433 1434 private String makeString(BitSet set, String[] strings) { 1435 StringBuffer buf = new StringBuffer(); 1436 int nextSetBit = -1; 1437 1438 /* Make sure all set bits are in [0, strings.length) to avoid 1439 * going out of bounds on strings. (Shouldn't happen, but...) */ 1440 set = set.get(0, strings.length); 1441 1442 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 1443 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 1444 } 1445 1446 // remove trailing space 1447 if (set.cardinality() > 0) { 1448 buf.setLength(buf.length() - 1); 1449 } 1450 1451 return buf.toString(); 1452 } 1453 1454 private int lookupString(String string, String[] strings) { 1455 int size = strings.length; 1456 1457 string = string.replace('-', '_'); 1458 1459 for (int i = 0; i < size; i++) 1460 if (string.equals(strings[i])) 1461 return i; 1462 1463 // if we ever get here, we should probably add the 1464 // value to WifiConfiguration to reflect that it's 1465 // supported by the WPA supplicant 1466 loge("Failed to look-up a string: " + string); 1467 1468 return -1; 1469 } 1470 1471 /* Returns a unique for a given configuration */ 1472 private static int configKey(WifiConfiguration config) { 1473 String key; 1474 1475 if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1476 key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK]; 1477 } else if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || 1478 config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 1479 key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP]; 1480 } else if (config.wepKeys[0] != null) { 1481 key = config.SSID + "WEP"; 1482 } else { 1483 key = config.SSID + KeyMgmt.strings[KeyMgmt.NONE]; 1484 } 1485 1486 return key.hashCode(); 1487 } 1488 1489 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1490 pw.println("WifiConfigStore"); 1491 pw.println("mLastPriority " + mLastPriority); 1492 pw.println("Configured networks"); 1493 for (WifiConfiguration conf : getConfiguredNetworks()) { 1494 pw.println(conf); 1495 } 1496 pw.println(); 1497 } 1498 1499 public String getConfigFile() { 1500 return ipConfigFile; 1501 } 1502 1503 private void loge(String s) { 1504 Log.e(TAG, s); 1505 } 1506 1507 private void log(String s) { 1508 Log.d(TAG, s); 1509 } 1510} 1511