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