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