WifiConfiguration.java revision adae06be9bfd8cb756e1793b52e682eb87258968
1/* 2 * Copyright (C) 2008 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.annotation.SystemApi; 20import android.net.IpConfiguration; 21import android.net.IpConfiguration.ProxySettings; 22import android.net.IpConfiguration.IpAssignment; 23import android.net.ProxyInfo; 24import android.net.LinkProperties; 25import android.os.Parcel; 26import android.os.Parcelable; 27import android.text.TextUtils; 28 29import java.util.HashMap; 30import java.util.BitSet; 31 32/** 33 * A class representing a configured Wi-Fi network, including the 34 * security configuration. 35 */ 36public class WifiConfiguration implements Parcelable { 37 private static final String TAG = "WifiConfiguration"; 38 /** {@hide} */ 39 public static final String ssidVarName = "ssid"; 40 /** {@hide} */ 41 public static final String bssidVarName = "bssid"; 42 /** {@hide} */ 43 public static final String pskVarName = "psk"; 44 /** {@hide} */ 45 public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" }; 46 /** {@hide} */ 47 public static final String wepTxKeyIdxVarName = "wep_tx_keyidx"; 48 /** {@hide} */ 49 public static final String priorityVarName = "priority"; 50 /** {@hide} */ 51 public static final String hiddenSSIDVarName = "scan_ssid"; 52 /** {@hide} */ 53 public static final String pmfVarName = "ieee80211w"; 54 /** {@hide} */ 55 public static final String updateIdentiferVarName = "update_identifier"; 56 /** {@hide} */ 57 public static final int INVALID_NETWORK_ID = -1; 58 /** 59 * Recognized key management schemes. 60 */ 61 public static class KeyMgmt { 62 private KeyMgmt() { } 63 64 /** WPA is not used; plaintext or static WEP could be used. */ 65 public static final int NONE = 0; 66 /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */ 67 public static final int WPA_PSK = 1; 68 /** WPA using EAP authentication. Generally used with an external authentication server. */ 69 public static final int WPA_EAP = 2; 70 /** IEEE 802.1X using EAP authentication and (optionally) dynamically 71 * generated WEP keys. */ 72 public static final int IEEE8021X = 3; 73 74 /** WPA2 pre-shared key for use with soft access point 75 * (requires {@code preSharedKey} to be specified). 76 * @hide 77 */ 78 public static final int WPA2_PSK = 4; 79 80 public static final String varName = "key_mgmt"; 81 82 public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X", 83 "WPA2_PSK" }; 84 } 85 86 /** 87 * Recognized security protocols. 88 */ 89 public static class Protocol { 90 private Protocol() { } 91 92 /** WPA/IEEE 802.11i/D3.0 */ 93 public static final int WPA = 0; 94 /** WPA2/IEEE 802.11i */ 95 public static final int RSN = 1; 96 97 public static final String varName = "proto"; 98 99 public static final String[] strings = { "WPA", "RSN" }; 100 } 101 102 /** 103 * Recognized IEEE 802.11 authentication algorithms. 104 */ 105 public static class AuthAlgorithm { 106 private AuthAlgorithm() { } 107 108 /** Open System authentication (required for WPA/WPA2) */ 109 public static final int OPEN = 0; 110 /** Shared Key authentication (requires static WEP keys) */ 111 public static final int SHARED = 1; 112 /** LEAP/Network EAP (only used with LEAP) */ 113 public static final int LEAP = 2; 114 115 public static final String varName = "auth_alg"; 116 117 public static final String[] strings = { "OPEN", "SHARED", "LEAP" }; 118 } 119 120 /** 121 * Recognized pairwise ciphers for WPA. 122 */ 123 public static class PairwiseCipher { 124 private PairwiseCipher() { } 125 126 /** Use only Group keys (deprecated) */ 127 public static final int NONE = 0; 128 /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */ 129 public static final int TKIP = 1; 130 /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ 131 public static final int CCMP = 2; 132 133 public static final String varName = "pairwise"; 134 135 public static final String[] strings = { "NONE", "TKIP", "CCMP" }; 136 } 137 138 /** 139 * Recognized group ciphers. 140 * <pre> 141 * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] 142 * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] 143 * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key 144 * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) 145 * </pre> 146 */ 147 public static class GroupCipher { 148 private GroupCipher() { } 149 150 /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */ 151 public static final int WEP40 = 0; 152 /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */ 153 public static final int WEP104 = 1; 154 /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */ 155 public static final int TKIP = 2; 156 /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ 157 public static final int CCMP = 3; 158 159 public static final String varName = "group"; 160 161 public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" }; 162 } 163 164 /** Possible status of a network configuration. */ 165 public static class Status { 166 private Status() { } 167 168 /** this is the network we are currently connected to */ 169 public static final int CURRENT = 0; 170 /** supplicant will not attempt to use this network */ 171 public static final int DISABLED = 1; 172 /** supplicant will consider this network available for association */ 173 public static final int ENABLED = 2; 174 175 public static final String[] strings = { "current", "disabled", "enabled" }; 176 } 177 178 /** @hide */ 179 public static final int DISABLED_UNKNOWN_REASON = 0; 180 /** @hide */ 181 public static final int DISABLED_DNS_FAILURE = 1; 182 /** @hide */ 183 public static final int DISABLED_DHCP_FAILURE = 2; 184 /** @hide */ 185 public static final int DISABLED_AUTH_FAILURE = 3; 186 /** @hide */ 187 public static final int DISABLED_ASSOCIATION_REJECT = 4; 188 189 /** 190 * The ID number that the supplicant uses to identify this 191 * network configuration entry. This must be passed as an argument 192 * to most calls into the supplicant. 193 */ 194 public int networkId; 195 196 /** 197 * The current status of this network configuration entry. 198 * @see Status 199 */ 200 public int status; 201 202 /** 203 * The code referring to a reason for disabling the network 204 * Valid when {@link #status} == Status.DISABLED 205 * @hide 206 */ 207 public int disableReason; 208 209 /** 210 * The network's SSID. Can either be an ASCII string, 211 * which must be enclosed in double quotation marks 212 * (e.g., {@code "MyNetwork"}, or a string of 213 * hex digits,which are not enclosed in quotes 214 * (e.g., {@code 01a243f405}). 215 */ 216 public String SSID; 217 /** 218 * When set, this network configuration entry should only be used when 219 * associating with the AP having the specified BSSID. The value is 220 * a string in the format of an Ethernet MAC address, e.g., 221 * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit. 222 */ 223 public String BSSID; 224 /** 225 * Fully qualified domain name (FQDN), for Passpoint credential. 226 * e.g. {@code "mail.example.com"}. 227 * @hide 228 */ 229 public String FQDN; 230 /** 231 * Network access identifier (NAI) realm, for Passpoint credential. 232 * e.g. {@code "myhost.example.com"}. 233 * @hide 234 */ 235 public String naiRealm; 236 237 /** 238 * Pre-shared key for use with WPA-PSK. 239 * <p/> 240 * When the value of this key is read, the actual key is 241 * not returned, just a "*" if the key has a value, or the null 242 * string otherwise. 243 */ 244 public String preSharedKey; 245 /** 246 * Up to four WEP keys. Either an ASCII string enclosed in double 247 * quotation marks (e.g., {@code "abcdef"} or a string 248 * of hex digits (e.g., {@code 0102030405}). 249 * <p/> 250 * When the value of one of these keys is read, the actual key is 251 * not returned, just a "*" if the key has a value, or the null 252 * string otherwise. 253 */ 254 public String[] wepKeys; 255 256 /** Default WEP key index, ranging from 0 to 3. */ 257 public int wepTxKeyIndex; 258 259 /** 260 * Priority determines the preference given to a network by {@code wpa_supplicant} 261 * when choosing an access point with which to associate. 262 */ 263 public int priority; 264 265 /** 266 * This is a network that does not broadcast its SSID, so an 267 * SSID-specific probe request must be used for scans. 268 */ 269 public boolean hiddenSSID; 270 271 /** 272 * This is a network that requries Protected Management Frames (PMF). 273 * @hide 274 */ 275 public boolean requirePMF; 276 277 /** 278 * Update identifier, for Passpoint network. 279 * @hide 280 */ 281 public String updateIdentifier; 282 283 /** 284 * The set of key management protocols supported by this configuration. 285 * See {@link KeyMgmt} for descriptions of the values. 286 * Defaults to WPA-PSK WPA-EAP. 287 */ 288 public BitSet allowedKeyManagement; 289 /** 290 * The set of security protocols supported by this configuration. 291 * See {@link Protocol} for descriptions of the values. 292 * Defaults to WPA RSN. 293 */ 294 public BitSet allowedProtocols; 295 /** 296 * The set of authentication protocols supported by this configuration. 297 * See {@link AuthAlgorithm} for descriptions of the values. 298 * Defaults to automatic selection. 299 */ 300 public BitSet allowedAuthAlgorithms; 301 /** 302 * The set of pairwise ciphers for WPA supported by this configuration. 303 * See {@link PairwiseCipher} for descriptions of the values. 304 * Defaults to CCMP TKIP. 305 */ 306 public BitSet allowedPairwiseCiphers; 307 /** 308 * The set of group ciphers supported by this configuration. 309 * See {@link GroupCipher} for descriptions of the values. 310 * Defaults to CCMP TKIP WEP104 WEP40. 311 */ 312 public BitSet allowedGroupCiphers; 313 /** 314 * The enterprise configuration details specifying the EAP method, 315 * certificates and other settings associated with the EAP. 316 */ 317 public WifiEnterpriseConfig enterpriseConfig; 318 319 /** 320 * @hide 321 */ 322 private IpConfiguration mIpConfiguration; 323 324 /** 325 * @hide 326 * dhcp server MAC address if known 327 */ 328 public String dhcpServer; 329 330 /** 331 * @hide 332 * default Gateway MAC address if known 333 */ 334 public String defaultGwMacAddress; 335 336 /** 337 * @hide 338 * last failure 339 */ 340 public String lastFailure; 341 342 /** 343 * @hide 344 * Uid of app creating the configuration 345 */ 346 @SystemApi 347 public int creatorUid; 348 349 /** 350 * @hide 351 * Uid of last app issuing a connection related command 352 */ 353 public int lastConnectUid; 354 355 /** 356 * @hide 357 * Uid of last app modifying the configuration 358 */ 359 public int lastUpdateUid; 360 361 /** 362 * @hide 363 * Uid of app owning the BSSID 364 */ 365 public int bssidOwnerUid; 366 367 /** 368 * @hide 369 * BSSID list on which this configuration was seen. 370 * TODO: prevent this list to grow infinitely, age-out the results 371 */ 372 public HashMap<String, ScanResult> scanResultCache; 373 374 /** The Below RSSI thresholds are used to configure AutoJoin 375 * - GOOD/LOW/BAD thresholds are used so as to calculate link score 376 * - UNWANTED_SOFT are used by the blacklisting logic so as to handle the unwanted network message coming from CS 377 * - UNBLACKLIST thresholds are used so as to tweak the speed at which the network is unblacklisted (i.e. if 378 * it is seen with good RSSI, it is blacklisted faster) 379 * - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from the network we need to be before autojoin kicks in 380 */ 381 /** @hide **/ 382 public static int INVALID_RSSI = -127; 383 384 /** @hide **/ 385 public static int UNWANTED_BLACKLIST_SOFT_RSSI_24 = -80; 386 387 /** @hide **/ 388 public static int UNWANTED_BLACKLIST_SOFT_RSSI_5 = -70; 389 390 /** @hide **/ 391 public static int GOOD_RSSI_24 = -65; 392 393 /** @hide **/ 394 public static int LOW_RSSI_24 = -77; 395 396 /** @hide **/ 397 public static int BAD_RSSI_24 = -87; 398 399 /** @hide **/ 400 public static int GOOD_RSSI_5 = -60; 401 402 /** @hide **/ 403 public static int LOW_RSSI_5 = -72; 404 405 /** @hide **/ 406 public static int BAD_RSSI_5 = -82; 407 408 /** @hide **/ 409 public static int UNWANTED_BLACKLIST_SOFT_BUMP = 4; 410 411 /** @hide **/ 412 public static int UNWANTED_BLACKLIST_HARD_BUMP = 8; 413 414 /** @hide **/ 415 public static int UNBLACKLIST_THRESHOLD_24_SOFT = -77; 416 417 /** @hide **/ 418 public static int UNBLACKLIST_THRESHOLD_24_HARD = -68; 419 420 /** @hide **/ 421 public static int UNBLACKLIST_THRESHOLD_5_SOFT = -63; 422 423 /** @hide **/ 424 public static int UNBLACKLIST_THRESHOLD_5_HARD = -56; 425 426 /** @hide **/ 427 public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_24 = -80; 428 429 /** @hide **/ 430 public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70; 431 432 /** @hide 433 * 5GHz band is prefered over 2.4 if the 5GHz RSSI is higher than this threshold **/ 434 public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65; 435 436 /** @hide 437 * 5GHz band is penalized if the 5GHz RSSI is lower than this threshold **/ 438 public static int G_BAND_PREFERENCE_RSSI_THRESHOLD = -75; 439 440 /** @hide 441 * Boost given to RSSI on a home network for the purpose of calculating the score 442 * This adds stickiness to home networks, as defined by: 443 * - less than 4 known BSSIDs 444 * - PSK only 445 * - TODO: add a test to verify that all BSSIDs are behind same gateway 446 ***/ 447 public static int HOME_NETWORK_RSSI_BOOST = 5; 448 449 /** 450 * @hide 451 * A summary of the RSSI and Band status for that configuration 452 * This is used as a temporary value by the auto-join controller 453 */ 454 public final class Visibility { 455 public int rssi5; // strongest 5GHz RSSI 456 public int rssi24; // strongest 2.4GHz RSSI 457 public int num5; // number of BSSIDs on 5GHz 458 public int num24; // number of BSSIDs on 2.4GHz 459 public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen) 460 public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen) 461 462 public Visibility() { 463 rssi5 = INVALID_RSSI; 464 rssi24 = INVALID_RSSI; 465 } 466 467 public Visibility(Visibility source) { 468 rssi5 = source.rssi5; 469 rssi24 = source.rssi24; 470 age24 = source.age24; 471 age5 = source.age5; 472 num24 = source.num24; 473 num5 = source.num5; 474 } 475 476 @Override 477 public String toString() { 478 StringBuilder sbuf = new StringBuilder(); 479 sbuf.append("["); 480 if (rssi24 > INVALID_RSSI) { 481 sbuf.append(Integer.toString(rssi24)); 482 sbuf.append(","); 483 sbuf.append(Integer.toString(num24)); 484 } else { 485 sbuf.append("*"); 486 } 487 sbuf.append(" - "); 488 if (rssi5 > INVALID_RSSI) { 489 sbuf.append(Integer.toString(rssi5)); 490 sbuf.append(","); 491 sbuf.append(Integer.toString(num5)); 492 } 493 sbuf.append("]"); 494 return sbuf.toString(); 495 } 496 } 497 498 /** @hide 499 * Cache the visibility status of this configuration. 500 * Visibility can change at any time depending on scan results availability. 501 * Owner of the WifiConfiguration is responsible to set this field based on 502 * recent scan results. 503 ***/ 504 public Visibility visibility; 505 506 /** @hide 507 * calculate and set Visibility for that configuration. 508 * 509 * age in milliseconds: we will consider only ScanResults that are more recent, 510 * i.e. younger. 511 ***/ 512 public Visibility setVisibility(long age) { 513 if (scanResultCache == null) { 514 visibility = null; 515 return null; 516 } 517 518 Visibility status = new Visibility(); 519 520 long now_ms = System.currentTimeMillis(); 521 for(ScanResult result : scanResultCache.values()) { 522 if (result.seen == 0) 523 continue; 524 525 if (result.is5GHz()) { 526 //strictly speaking: [4915, 5825] 527 //number of known BSSID on 5GHz band 528 status.num5 = status.num5 + 1; 529 } else if (result.is24GHz()) { 530 //strictly speaking: [2412, 2482] 531 //number of known BSSID on 2.4Ghz band 532 status.num24 = status.num24 + 1; 533 } 534 535 if ((now_ms - result.seen) > age) continue; 536 537 if (result.is5GHz()) { 538 if (result.level > status.rssi5) { 539 status.rssi5 = result.level; 540 status.age5 = result.seen; 541 } 542 } else if (result.is24GHz()) { 543 if (result.level > status.rssi24) { 544 status.rssi24 = result.level; 545 status.age24 = result.seen; 546 } 547 } 548 } 549 visibility = status; 550 return status; 551 } 552 553 /** @hide */ 554 public static final int AUTO_JOIN_ENABLED = 0; 555 /** 556 * if this is set, the WifiConfiguration cannot use linkages so as to bump 557 * it's relative priority. 558 * - status between and 128 indicate various level of blacklisting depending 559 * on the severity or frequency of the connection error 560 * - deleted status indicates that the user is deleting the configuration, and so 561 * although it may have been self added we will not re-self-add it, ignore it, 562 * not return it to applications, and not connect to it 563 * */ 564 565 /** @hide 566 * network was temporary disabled due to bad connection, most likely due 567 * to weak RSSI */ 568 public static final int AUTO_JOIN_TEMPORARY_DISABLED = 1; 569 /** @hide 570 * network was temporary disabled due to bad connection, which cant be attributed 571 * to weak RSSI */ 572 public static final int AUTO_JOIN_TEMPORARY_DISABLED_LINK_ERRORS = 32; 573 /** @hide */ 574 public static final int AUTO_JOIN_TEMPORARY_DISABLED_AT_SUPPLICANT = 64; 575 /** @hide */ 576 public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE = 128; 577 /** @hide */ 578 public static final int AUTO_JOIN_DELETED = 200; 579 580 /** 581 * @hide 582 */ 583 public int autoJoinStatus; 584 585 586 /** 587 * @hide 588 */ 589 public long blackListTimestamp; 590 591 /** 592 * @hide 593 * last time the system was connected to this configuration. 594 */ 595 public long lastConnected; 596 597 /** 598 * @hide 599 * last time the system was disconnected to this configuration. 600 */ 601 public long lastDisconnected; 602 603 /** 604 * Set if the configuration was self added by the framework 605 * This boolean is cleared if we get a connect/save/ update or 606 * any wifiManager command that indicate the user interacted with the configuration 607 * since we will now consider that the configuration belong to him. 608 * @hide 609 */ 610 public boolean selfAdded; 611 612 /** 613 * Set if the configuration was self added by the framework 614 * This boolean is set once and never cleared. It is used 615 * so as we never loose track of who created the 616 * configuration in the first place. 617 * @hide 618 */ 619 public boolean didSelfAdd; 620 621 /** 622 * peer WifiConfiguration this WifiConfiguration was added for 623 * @hide 624 */ 625 public String peerWifiConfiguration; 626 627 /** 628 * @hide 629 * Indicate that a WifiConfiguration is temporary and should not be saved 630 * nor considered by AutoJoin. 631 */ 632 public boolean ephemeral; 633 634 /** 635 * @hide 636 * Connect choices 637 * 638 * remember the keys identifying the known WifiConfiguration over which this configuration 639 * was preferred by user or a "WiFi Network Management app", that is, 640 * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration 641 * was visible to the user: 642 * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP 643 * 644 * The integer represents the configuration's RSSI at that time (useful?) 645 * 646 * The overall auto-join algorithm make use of past connect choice so as to sort configuration, 647 * the exact algorithm still fluctuating as of 5/7/2014 648 * 649 */ 650 public HashMap<String, Integer> connectChoices; 651 652 /** 653 * @hide 654 * Linked Configurations: represent the set of Wificonfigurations that are equivalent 655 * regarding roaming and auto-joining. 656 * The linked configuration may or may not have same SSID, and may or may not have same 657 * credentials. 658 * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server. 659 */ 660 public HashMap<String, Integer> linkedConfigurations; 661 662 public WifiConfiguration() { 663 networkId = INVALID_NETWORK_ID; 664 SSID = null; 665 BSSID = null; 666 FQDN = null; 667 naiRealm = null; 668 priority = 0; 669 hiddenSSID = false; 670 disableReason = DISABLED_UNKNOWN_REASON; 671 allowedKeyManagement = new BitSet(); 672 allowedProtocols = new BitSet(); 673 allowedAuthAlgorithms = new BitSet(); 674 allowedPairwiseCiphers = new BitSet(); 675 allowedGroupCiphers = new BitSet(); 676 wepKeys = new String[4]; 677 for (int i = 0; i < wepKeys.length; i++) { 678 wepKeys[i] = null; 679 } 680 enterpriseConfig = new WifiEnterpriseConfig(); 681 autoJoinStatus = AUTO_JOIN_ENABLED; 682 selfAdded = false; 683 didSelfAdd = false; 684 ephemeral = false; 685 mIpConfiguration = new IpConfiguration(); 686 } 687 688 /** 689 * indicates whether the configuration is valid 690 * @return true if valid, false otherwise 691 * @hide 692 */ 693 public boolean isValid() { 694 695 if (allowedKeyManagement == null) 696 return false; 697 698 if (allowedKeyManagement.cardinality() > 1) { 699 if (allowedKeyManagement.cardinality() != 2) { 700 return false; 701 } 702 if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) { 703 return false; 704 } 705 if ((allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false) 706 && (allowedKeyManagement.get(KeyMgmt.WPA_PSK) == false)) { 707 return false; 708 } 709 } 710 711 // TODO: Add more checks 712 return true; 713 } 714 715 /** 716 * Helper function, identify if a configuration is linked 717 * @hide 718 */ 719 public boolean isLinked(WifiConfiguration config) { 720 if (config.linkedConfigurations != null && linkedConfigurations != null) { 721 if (config.linkedConfigurations.get(configKey()) != null 722 && linkedConfigurations.get(config.configKey()) != null) { 723 return true; 724 } 725 } 726 return false; 727 } 728 729 /** 730 * most recent time we have seen this configuration 731 * @return most recent scanResult 732 * @hide 733 */ 734 public ScanResult lastSeen() { 735 ScanResult mostRecent = null; 736 737 if (scanResultCache == null) { 738 return null; 739 } 740 741 for (ScanResult result : scanResultCache.values()) { 742 if (mostRecent == null) { 743 if (result.seen != 0) 744 mostRecent = result; 745 } else { 746 if (result.seen > mostRecent.seen) { 747 mostRecent = result; 748 } 749 } 750 } 751 return mostRecent; 752 } 753 754 /** @hide **/ 755 public void setAutoJoinStatus(int status) { 756 if (status < 0) status = 0; 757 if (status == 0) { 758 blackListTimestamp = 0; 759 } else if (status > autoJoinStatus) { 760 blackListTimestamp = System.currentTimeMillis(); 761 } 762 autoJoinStatus = status; 763 } 764 765 @Override 766 public String toString() { 767 StringBuilder sbuf = new StringBuilder(); 768 if (this.status == WifiConfiguration.Status.CURRENT) { 769 sbuf.append("* "); 770 } else if (this.status == WifiConfiguration.Status.DISABLED) { 771 sbuf.append("- DSBLE: ").append(this.disableReason).append(" "); 772 } 773 sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID). 774 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN). 775 append(" REALM: ").append(this.naiRealm).append(" PRIO: ").append(this.priority). 776 append('\n'); 777 sbuf.append(" KeyMgmt:"); 778 for (int k = 0; k < this.allowedKeyManagement.size(); k++) { 779 if (this.allowedKeyManagement.get(k)) { 780 sbuf.append(" "); 781 if (k < KeyMgmt.strings.length) { 782 sbuf.append(KeyMgmt.strings[k]); 783 } else { 784 sbuf.append("??"); 785 } 786 } 787 } 788 sbuf.append(" Protocols:"); 789 for (int p = 0; p < this.allowedProtocols.size(); p++) { 790 if (this.allowedProtocols.get(p)) { 791 sbuf.append(" "); 792 if (p < Protocol.strings.length) { 793 sbuf.append(Protocol.strings[p]); 794 } else { 795 sbuf.append("??"); 796 } 797 } 798 } 799 sbuf.append('\n'); 800 sbuf.append(" AuthAlgorithms:"); 801 for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) { 802 if (this.allowedAuthAlgorithms.get(a)) { 803 sbuf.append(" "); 804 if (a < AuthAlgorithm.strings.length) { 805 sbuf.append(AuthAlgorithm.strings[a]); 806 } else { 807 sbuf.append("??"); 808 } 809 } 810 } 811 sbuf.append('\n'); 812 sbuf.append(" PairwiseCiphers:"); 813 for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) { 814 if (this.allowedPairwiseCiphers.get(pc)) { 815 sbuf.append(" "); 816 if (pc < PairwiseCipher.strings.length) { 817 sbuf.append(PairwiseCipher.strings[pc]); 818 } else { 819 sbuf.append("??"); 820 } 821 } 822 } 823 sbuf.append('\n'); 824 sbuf.append(" GroupCiphers:"); 825 for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) { 826 if (this.allowedGroupCiphers.get(gc)) { 827 sbuf.append(" "); 828 if (gc < GroupCipher.strings.length) { 829 sbuf.append(GroupCipher.strings[gc]); 830 } else { 831 sbuf.append("??"); 832 } 833 } 834 } 835 sbuf.append('\n').append(" PSK: "); 836 if (this.preSharedKey != null) { 837 sbuf.append('*'); 838 } 839 840 sbuf.append(enterpriseConfig); 841 sbuf.append('\n'); 842 843 sbuf.append(mIpConfiguration.toString()); 844 845 if (selfAdded) sbuf.append("selfAdded"); 846 if (creatorUid != 0) sbuf.append("uid=" + Integer.toString(creatorUid)); 847 848 if (blackListTimestamp != 0) { 849 long now_ms = System.currentTimeMillis(); 850 long diff = now_ms - blackListTimestamp; 851 if (diff <= 0) { 852 sbuf.append("blackListed since <incorrect>"); 853 } else { 854 sbuf.append("blackListed since ").append(Long.toString(diff/1000)).append( "sec"); 855 } 856 } 857 858 return sbuf.toString(); 859 } 860 861 /** 862 * Construct a WifiConfiguration from a scanned network 863 * @param scannedAP the scan result used to construct the config entry 864 * TODO: figure out whether this is a useful way to construct a new entry. 865 * 866 public WifiConfiguration(ScanResult scannedAP) { 867 networkId = -1; 868 SSID = scannedAP.SSID; 869 BSSID = scannedAP.BSSID; 870 } 871 */ 872 873 /** {@hide} */ 874 public String getPrintableSsid() { 875 if (SSID == null) return ""; 876 final int length = SSID.length(); 877 if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') { 878 return SSID.substring(1, length - 1); 879 } 880 881 /** The ascii-encoded string format is P"<ascii-encoded-string>" 882 * The decoding is implemented in the supplicant for a newly configured 883 * network. 884 */ 885 if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') && 886 (SSID.charAt(length-1) == '"')) { 887 WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded( 888 SSID.substring(2, length - 1)); 889 return wifiSsid.toString(); 890 } 891 return SSID; 892 } 893 894 /** 895 * Get an identifier for associating credentials with this config 896 * @param current configuration contains values for additional fields 897 * that are not part of this configuration. Used 898 * when a config with some fields is passed by an application. 899 * @throws IllegalStateException if config is invalid for key id generation 900 * @hide 901 */ 902 public String getKeyIdForCredentials(WifiConfiguration current) { 903 String keyMgmt = null; 904 905 try { 906 // Get current config details for fields that are not initialized 907 if (TextUtils.isEmpty(SSID)) SSID = current.SSID; 908 if (allowedKeyManagement.cardinality() == 0) { 909 allowedKeyManagement = current.allowedKeyManagement; 910 } 911 if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { 912 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP]; 913 } 914 if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 915 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X]; 916 } 917 918 if (TextUtils.isEmpty(keyMgmt)) { 919 throw new IllegalStateException("Not an EAP network"); 920 } 921 922 return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" + 923 trimStringForKeyId(enterpriseConfig.getKeyId(current != null ? 924 current.enterpriseConfig : null)); 925 } catch (NullPointerException e) { 926 throw new IllegalStateException("Invalid config details"); 927 } 928 } 929 930 private String trimStringForKeyId(String string) { 931 // Remove quotes and spaces 932 return string.replace("\"", "").replace(" ", ""); 933 } 934 935 private static BitSet readBitSet(Parcel src) { 936 int cardinality = src.readInt(); 937 938 BitSet set = new BitSet(); 939 for (int i = 0; i < cardinality; i++) { 940 set.set(src.readInt()); 941 } 942 943 return set; 944 } 945 946 private static void writeBitSet(Parcel dest, BitSet set) { 947 int nextSetBit = -1; 948 949 dest.writeInt(set.cardinality()); 950 951 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 952 dest.writeInt(nextSetBit); 953 } 954 } 955 956 /** @hide */ 957 public int getAuthType() { 958 if (isValid() == false) { 959 throw new IllegalStateException("Invalid configuration"); 960 } 961 if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 962 return KeyMgmt.WPA_PSK; 963 } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) { 964 return KeyMgmt.WPA2_PSK; 965 } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { 966 return KeyMgmt.WPA_EAP; 967 } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 968 return KeyMgmt.IEEE8021X; 969 } 970 return KeyMgmt.NONE; 971 } 972 973 /* @hide 974 * Cache the config key, this seems useful as a speed up since a lot of 975 * lookups in the config store are done and based on this key. 976 */ 977 String mCachedConfigKey; 978 979 /** @hide 980 * return the string used to calculate the hash in WifiConfigStore 981 * and uniquely identify this WifiConfiguration 982 */ 983 public String configKey(boolean allowCached) { 984 String key; 985 if (allowCached && mCachedConfigKey != null) { 986 key = mCachedConfigKey; 987 } else { 988 key = this.SSID; 989 if (key == null) 990 key = ""; 991 if (this.wepKeys[0] != null) { 992 key = key + "-WEP"; 993 } 994 if (this.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 995 key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK]; 996 } 997 if (this.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || 998 this.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 999 key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP]; 1000 } 1001 mCachedConfigKey = key; 1002 } 1003 return key; 1004 } 1005 1006 /** @hide 1007 * get configKey, force calculating the config string 1008 */ 1009 public String configKey() { 1010 return configKey(false); 1011 } 1012 1013 /** @hide 1014 * return the config key string based on a scan result 1015 */ 1016 static public String configKey(ScanResult result) { 1017 String key = "\"" + result.SSID + "\""; 1018 1019 if (result.capabilities.contains("WEP")) { 1020 key = key + "-WEP"; 1021 } 1022 1023 if (result.capabilities.contains("PSK")) { 1024 key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK]; 1025 } 1026 1027 if (result.capabilities.contains("EAP")) { 1028 key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP]; 1029 } 1030 1031 return key; 1032 } 1033 1034 /** @hide */ 1035 public IpConfiguration getIpConfiguration() { 1036 return mIpConfiguration; 1037 } 1038 1039 /** @hide */ 1040 public void setIpConfiguration(IpConfiguration ipConfiguration) { 1041 mIpConfiguration = ipConfiguration; 1042 } 1043 1044 /** @hide */ 1045 public LinkProperties getLinkProperties() { 1046 return mIpConfiguration.linkProperties; 1047 } 1048 1049 /** @hide */ 1050 public void setLinkProperties(LinkProperties linkProperties) { 1051 mIpConfiguration.linkProperties = linkProperties; 1052 } 1053 1054 /** @hide */ 1055 public IpConfiguration.IpAssignment getIpAssignment() { 1056 return mIpConfiguration.ipAssignment; 1057 } 1058 1059 /** @hide */ 1060 public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) { 1061 mIpConfiguration.ipAssignment = ipAssignment; 1062 } 1063 1064 /** @hide */ 1065 public IpConfiguration.ProxySettings getProxySettings() { 1066 return mIpConfiguration.proxySettings; 1067 } 1068 1069 /** @hide */ 1070 public void setProxySettings(IpConfiguration.ProxySettings proxySettings) { 1071 mIpConfiguration.proxySettings = proxySettings; 1072 } 1073 1074 /** @hide */ 1075 public void setProxy(ProxySettings settings, ProxyInfo proxy) { 1076 mIpConfiguration.proxySettings = settings; 1077 mIpConfiguration.linkProperties.setHttpProxy(proxy); 1078 } 1079 1080 /** Implement the Parcelable interface {@hide} */ 1081 public int describeContents() { 1082 return 0; 1083 } 1084 1085 /** copy constructor {@hide} */ 1086 public WifiConfiguration(WifiConfiguration source) { 1087 if (source != null) { 1088 networkId = source.networkId; 1089 status = source.status; 1090 disableReason = source.disableReason; 1091 disableReason = source.disableReason; 1092 SSID = source.SSID; 1093 BSSID = source.BSSID; 1094 FQDN = source.FQDN; 1095 naiRealm = source.naiRealm; 1096 preSharedKey = source.preSharedKey; 1097 1098 wepKeys = new String[4]; 1099 for (int i = 0; i < wepKeys.length; i++) { 1100 wepKeys[i] = source.wepKeys[i]; 1101 } 1102 1103 wepTxKeyIndex = source.wepTxKeyIndex; 1104 priority = source.priority; 1105 hiddenSSID = source.hiddenSSID; 1106 allowedKeyManagement = (BitSet) source.allowedKeyManagement.clone(); 1107 allowedProtocols = (BitSet) source.allowedProtocols.clone(); 1108 allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone(); 1109 allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone(); 1110 allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone(); 1111 1112 enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig); 1113 1114 defaultGwMacAddress = source.defaultGwMacAddress; 1115 1116 mIpConfiguration = new IpConfiguration(source.mIpConfiguration); 1117 1118 if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) { 1119 scanResultCache = new HashMap<String, ScanResult>(); 1120 scanResultCache.putAll(source.scanResultCache); 1121 } 1122 1123 if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) { 1124 connectChoices = new HashMap<String, Integer>(); 1125 connectChoices.putAll(source.connectChoices); 1126 } 1127 1128 if ((source.linkedConfigurations != null) 1129 && (source.linkedConfigurations.size() > 0)) { 1130 linkedConfigurations = new HashMap<String, Integer>(); 1131 linkedConfigurations.putAll(source.linkedConfigurations); 1132 } 1133 mCachedConfigKey = null; //force null configKey 1134 autoJoinStatus = source.autoJoinStatus; 1135 selfAdded = source.selfAdded; 1136 1137 if (source.visibility != null) { 1138 visibility = new Visibility(source.visibility); 1139 } 1140 1141 lastFailure = source.lastFailure; 1142 didSelfAdd = source.didSelfAdd; 1143 lastConnectUid = source.lastConnectUid; 1144 lastUpdateUid = source.lastUpdateUid; 1145 bssidOwnerUid = source.bssidOwnerUid; 1146 creatorUid = source.creatorUid; 1147 peerWifiConfiguration = source.peerWifiConfiguration; 1148 blackListTimestamp = source.blackListTimestamp; 1149 lastConnected = source.lastConnected; 1150 lastDisconnected = source.lastDisconnected; 1151 } 1152 } 1153 1154 /** {@hide} */ 1155 //public static final int NOTHING_TAG = 0; 1156 /** {@hide} */ 1157 //public static final int SCAN_CACHE_TAG = 1; 1158 1159 /** Implement the Parcelable interface {@hide} */ 1160 @Override 1161 public void writeToParcel(Parcel dest, int flags) { 1162 dest.writeInt(networkId); 1163 dest.writeInt(status); 1164 dest.writeInt(disableReason); 1165 dest.writeString(SSID); 1166 dest.writeString(BSSID); 1167 dest.writeString(FQDN); 1168 dest.writeString(naiRealm); 1169 dest.writeString(preSharedKey); 1170 for (String wepKey : wepKeys) { 1171 dest.writeString(wepKey); 1172 } 1173 dest.writeInt(wepTxKeyIndex); 1174 dest.writeInt(priority); 1175 dest.writeInt(hiddenSSID ? 1 : 0); 1176 dest.writeInt(requirePMF ? 1 : 0); 1177 dest.writeString(updateIdentifier); 1178 1179 writeBitSet(dest, allowedKeyManagement); 1180 writeBitSet(dest, allowedProtocols); 1181 writeBitSet(dest, allowedAuthAlgorithms); 1182 writeBitSet(dest, allowedPairwiseCiphers); 1183 writeBitSet(dest, allowedGroupCiphers); 1184 1185 dest.writeParcelable(enterpriseConfig, flags); 1186 1187 dest.writeParcelable(mIpConfiguration, flags); 1188 dest.writeString(dhcpServer); 1189 dest.writeString(defaultGwMacAddress); 1190 dest.writeInt(autoJoinStatus); 1191 dest.writeInt(selfAdded ? 1 : 0); 1192 dest.writeInt(didSelfAdd ? 1 : 0); 1193 dest.writeInt(creatorUid); 1194 dest.writeInt(lastConnectUid); 1195 dest.writeInt(lastUpdateUid); 1196 dest.writeInt(bssidOwnerUid); 1197 dest.writeLong(blackListTimestamp); 1198 } 1199 1200 /** Implement the Parcelable interface {@hide} */ 1201 public static final Creator<WifiConfiguration> CREATOR = 1202 new Creator<WifiConfiguration>() { 1203 public WifiConfiguration createFromParcel(Parcel in) { 1204 WifiConfiguration config = new WifiConfiguration(); 1205 config.networkId = in.readInt(); 1206 config.status = in.readInt(); 1207 config.disableReason = in.readInt(); 1208 config.SSID = in.readString(); 1209 config.BSSID = in.readString(); 1210 config.FQDN = in.readString(); 1211 config.naiRealm = in.readString(); 1212 config.preSharedKey = in.readString(); 1213 for (int i = 0; i < config.wepKeys.length; i++) { 1214 config.wepKeys[i] = in.readString(); 1215 } 1216 config.wepTxKeyIndex = in.readInt(); 1217 config.priority = in.readInt(); 1218 config.hiddenSSID = in.readInt() != 0; 1219 config.requirePMF = in.readInt() != 0; 1220 config.updateIdentifier = in.readString(); 1221 1222 config.allowedKeyManagement = readBitSet(in); 1223 config.allowedProtocols = readBitSet(in); 1224 config.allowedAuthAlgorithms = readBitSet(in); 1225 config.allowedPairwiseCiphers = readBitSet(in); 1226 config.allowedGroupCiphers = readBitSet(in); 1227 1228 config.enterpriseConfig = in.readParcelable(null); 1229 1230 config.mIpConfiguration = in.readParcelable(null); 1231 config.dhcpServer = in.readString(); 1232 config.defaultGwMacAddress = in.readString(); 1233 config.autoJoinStatus = in.readInt(); 1234 config.selfAdded = in.readInt() != 0; 1235 config.didSelfAdd = in.readInt() != 0; 1236 config.creatorUid = in.readInt(); 1237 config.lastConnectUid = in.readInt(); 1238 config.lastUpdateUid = in.readInt(); 1239 config.bssidOwnerUid = in.readInt(); 1240 config.blackListTimestamp = in.readLong(); 1241 return config; 1242 } 1243 1244 public WifiConfiguration[] newArray(int size) { 1245 return new WifiConfiguration[size]; 1246 } 1247 }; 1248} 1249