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 17 package android.net.wifi; 18 19 import android.net.LinkProperties; 20 import android.os.Parcelable; 21 import android.os.Parcel; 22 import android.text.TextUtils; 23 24 import java.util.BitSet; 25 26 /** 27 * A class representing a configured Wi-Fi network, including the 28 * security configuration. 29 */ 30 public class WifiConfiguration implements Parcelable { 31 private static final String TAG = "WifiConfiguration"; 32 /** {@hide} */ 33 public static final String ssidVarName = "ssid"; 34 /** {@hide} */ 35 public static final String bssidVarName = "bssid"; 36 /** {@hide} */ 37 public static final String pskVarName = "psk"; 38 /** {@hide} */ 39 public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" }; 40 /** {@hide} */ 41 public static final String wepTxKeyIdxVarName = "wep_tx_keyidx"; 42 /** {@hide} */ 43 public static final String priorityVarName = "priority"; 44 /** {@hide} */ 45 public static final String hiddenSSIDVarName = "scan_ssid"; 46 /** {@hide} */ 47 public static final int INVALID_NETWORK_ID = -1; 48 /** 49 * Recognized key management schemes. 50 */ 51 public static class KeyMgmt { 52 private KeyMgmt() { } 53 54 /** WPA is not used; plaintext or static WEP could be used. */ 55 public static final int NONE = 0; 56 /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */ 57 public static final int WPA_PSK = 1; 58 /** WPA using EAP authentication. Generally used with an external authentication server. */ 59 public static final int WPA_EAP = 2; 60 /** IEEE 802.1X using EAP authentication and (optionally) dynamically 61 * generated WEP keys. */ 62 public static final int IEEE8021X = 3; 63 64 /** WPA2 pre-shared key for use with soft access point 65 * (requires {@code preSharedKey} to be specified). 66 * @hide 67 */ 68 public static final int WPA2_PSK = 4; 69 70 public static final String varName = "key_mgmt"; 71 72 public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X", 73 "WPA2_PSK" }; 74 } 75 76 /** 77 * Recognized security protocols. 78 */ 79 public static class Protocol { 80 private Protocol() { } 81 82 /** WPA/IEEE 802.11i/D3.0 */ 83 public static final int WPA = 0; 84 /** WPA2/IEEE 802.11i */ 85 public static final int RSN = 1; 86 87 public static final String varName = "proto"; 88 89 public static final String[] strings = { "WPA", "RSN" }; 90 } 91 92 /** 93 * Recognized IEEE 802.11 authentication algorithms. 94 */ 95 public static class AuthAlgorithm { 96 private AuthAlgorithm() { } 97 98 /** Open System authentication (required for WPA/WPA2) */ 99 public static final int OPEN = 0; 100 /** Shared Key authentication (requires static WEP keys) */ 101 public static final int SHARED = 1; 102 /** LEAP/Network EAP (only used with LEAP) */ 103 public static final int LEAP = 2; 104 105 public static final String varName = "auth_alg"; 106 107 public static final String[] strings = { "OPEN", "SHARED", "LEAP" }; 108 } 109 110 /** 111 * Recognized pairwise ciphers for WPA. 112 */ 113 public static class PairwiseCipher { 114 private PairwiseCipher() { } 115 116 /** Use only Group keys (deprecated) */ 117 public static final int NONE = 0; 118 /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */ 119 public static final int TKIP = 1; 120 /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ 121 public static final int CCMP = 2; 122 123 public static final String varName = "pairwise"; 124 125 public static final String[] strings = { "NONE", "TKIP", "CCMP" }; 126 } 127 128 /** 129 * Recognized group ciphers. 130 * <pre> 131 * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] 132 * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] 133 * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key 134 * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) 135 * </pre> 136 */ 137 public static class GroupCipher { 138 private GroupCipher() { } 139 140 /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */ 141 public static final int WEP40 = 0; 142 /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */ 143 public static final int WEP104 = 1; 144 /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */ 145 public static final int TKIP = 2; 146 /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ 147 public static final int CCMP = 3; 148 149 public static final String varName = "group"; 150 151 public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" }; 152 } 153 154 /** Possible status of a network configuration. */ 155 public static class Status { 156 private Status() { } 157 158 /** this is the network we are currently connected to */ 159 public static final int CURRENT = 0; 160 /** supplicant will not attempt to use this network */ 161 public static final int DISABLED = 1; 162 /** supplicant will consider this network available for association */ 163 public static final int ENABLED = 2; 164 165 public static final String[] strings = { "current", "disabled", "enabled" }; 166 } 167 168 /** @hide */ 169 public static final int DISABLED_UNKNOWN_REASON = 0; 170 /** @hide */ 171 public static final int DISABLED_DNS_FAILURE = 1; 172 /** @hide */ 173 public static final int DISABLED_DHCP_FAILURE = 2; 174 /** @hide */ 175 public static final int DISABLED_AUTH_FAILURE = 3; 176 /** @hide */ 177 public static final int DISABLED_ASSOCIATION_REJECT = 4; 178 179 /** 180 * The ID number that the supplicant uses to identify this 181 * network configuration entry. This must be passed as an argument 182 * to most calls into the supplicant. 183 */ 184 public int networkId; 185 186 /** 187 * The current status of this network configuration entry. 188 * @see Status 189 */ 190 public int status; 191 192 /** 193 * The code referring to a reason for disabling the network 194 * Valid when {@link #status} == Status.DISABLED 195 * @hide 196 */ 197 public int disableReason; 198 199 /** 200 * The network's SSID. Can either be an ASCII string, 201 * which must be enclosed in double quotation marks 202 * (e.g., {@code "MyNetwork"}, or a string of 203 * hex digits,which are not enclosed in quotes 204 * (e.g., {@code 01a243f405}). 205 */ 206 public String SSID; 207 /** 208 * When set, this network configuration entry should only be used when 209 * associating with the AP having the specified BSSID. The value is 210 * a string in the format of an Ethernet MAC address, e.g., 211 * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit. 212 */ 213 public String BSSID; 214 215 /** 216 * Pre-shared key for use with WPA-PSK. 217 * <p/> 218 * When the value of this key is read, the actual key is 219 * not returned, just a "*" if the key has a value, or the null 220 * string otherwise. 221 */ 222 public String preSharedKey; 223 /** 224 * Up to four WEP keys. Either an ASCII string enclosed in double 225 * quotation marks (e.g., {@code "abcdef"} or a string 226 * of hex digits (e.g., {@code 0102030405}). 227 * <p/> 228 * When the value of one of these keys is read, the actual key is 229 * not returned, just a "*" if the key has a value, or the null 230 * string otherwise. 231 */ 232 public String[] wepKeys; 233 234 /** Default WEP key index, ranging from 0 to 3. */ 235 public int wepTxKeyIndex; 236 237 /** 238 * Priority determines the preference given to a network by {@code wpa_supplicant} 239 * when choosing an access point with which to associate. 240 */ 241 public int priority; 242 243 /** 244 * This is a network that does not broadcast its SSID, so an 245 * SSID-specific probe request must be used for scans. 246 */ 247 public boolean hiddenSSID; 248 249 /** 250 * The set of key management protocols supported by this configuration. 251 * See {@link KeyMgmt} for descriptions of the values. 252 * Defaults to WPA-PSK WPA-EAP. 253 */ 254 public BitSet allowedKeyManagement; 255 /** 256 * The set of security protocols supported by this configuration. 257 * See {@link Protocol} for descriptions of the values. 258 * Defaults to WPA RSN. 259 */ 260 public BitSet allowedProtocols; 261 /** 262 * The set of authentication protocols supported by this configuration. 263 * See {@link AuthAlgorithm} for descriptions of the values. 264 * Defaults to automatic selection. 265 */ 266 public BitSet allowedAuthAlgorithms; 267 /** 268 * The set of pairwise ciphers for WPA supported by this configuration. 269 * See {@link PairwiseCipher} for descriptions of the values. 270 * Defaults to CCMP TKIP. 271 */ 272 public BitSet allowedPairwiseCiphers; 273 /** 274 * The set of group ciphers supported by this configuration. 275 * See {@link GroupCipher} for descriptions of the values. 276 * Defaults to CCMP TKIP WEP104 WEP40. 277 */ 278 public BitSet allowedGroupCiphers; 279 /** 280 * The enterprise configuration details specifying the EAP method, 281 * certificates and other settings associated with the EAP. 282 */ 283 public WifiEnterpriseConfig enterpriseConfig; 284 285 /** 286 * @hide 287 */ 288 public enum IpAssignment { 289 /* Use statically configured IP settings. Configuration can be accessed 290 * with linkProperties */ 291 STATIC, 292 /* Use dynamically configured IP settigns */ 293 DHCP, 294 /* no IP details are assigned, this is used to indicate 295 * that any existing IP settings should be retained */ 296 UNASSIGNED 297 } 298 /** 299 * @hide 300 */ 301 public IpAssignment ipAssignment; 302 303 /** 304 * @hide 305 */ 306 public enum ProxySettings { 307 /* No proxy is to be used. Any existing proxy settings 308 * should be cleared. */ 309 NONE, 310 /* Use statically configured proxy. Configuration can be accessed 311 * with linkProperties */ 312 STATIC, 313 /* no proxy details are assigned, this is used to indicate 314 * that any existing proxy settings should be retained */ 315 UNASSIGNED, 316 /* Use a Pac based proxy. 317 */ 318 PAC 319 } 320 /** 321 * @hide 322 */ 323 public ProxySettings proxySettings; 324 /** 325 * @hide 326 */ 327 public LinkProperties linkProperties; 328 329 public WifiConfiguration() { 330 networkId = INVALID_NETWORK_ID; 331 SSID = null; 332 BSSID = null; 333 priority = 0; 334 hiddenSSID = false; 335 disableReason = DISABLED_UNKNOWN_REASON; 336 allowedKeyManagement = new BitSet(); 337 allowedProtocols = new BitSet(); 338 allowedAuthAlgorithms = new BitSet(); 339 allowedPairwiseCiphers = new BitSet(); 340 allowedGroupCiphers = new BitSet(); 341 wepKeys = new String[4]; 342 for (int i = 0; i < wepKeys.length; i++) { 343 wepKeys[i] = null; 344 } 345 enterpriseConfig = new WifiEnterpriseConfig(); 346 ipAssignment = IpAssignment.UNASSIGNED; 347 proxySettings = ProxySettings.UNASSIGNED; 348 linkProperties = new LinkProperties(); 349 } 350 351 /** 352 * indicates whether the configuration is valid 353 * @return true if valid, false otherwise 354 * @hide 355 */ 356 public boolean isValid() { 357 if (allowedKeyManagement.cardinality() > 1) { 358 if (allowedKeyManagement.cardinality() != 2) { 359 return false; 360 } 361 if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) { 362 return false; 363 } 364 if ((allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false) 365 && (allowedKeyManagement.get(KeyMgmt.WPA_PSK) == false)) { 366 return false; 367 } 368 } 369 370 // TODO: Add more checks 371 return true; 372 } 373 374 @Override 375 public String toString() { 376 StringBuilder sbuf = new StringBuilder(); 377 if (this.status == WifiConfiguration.Status.CURRENT) { 378 sbuf.append("* "); 379 } else if (this.status == WifiConfiguration.Status.DISABLED) { 380 sbuf.append("- DSBLE: ").append(this.disableReason).append(" "); 381 } 382 sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID). 383 append(" BSSID: ").append(this.BSSID).append(" PRIO: ").append(this.priority). 384 append('\n'); 385 sbuf.append(" KeyMgmt:"); 386 for (int k = 0; k < this.allowedKeyManagement.size(); k++) { 387 if (this.allowedKeyManagement.get(k)) { 388 sbuf.append(" "); 389 if (k < KeyMgmt.strings.length) { 390 sbuf.append(KeyMgmt.strings[k]); 391 } else { 392 sbuf.append("??"); 393 } 394 } 395 } 396 sbuf.append(" Protocols:"); 397 for (int p = 0; p < this.allowedProtocols.size(); p++) { 398 if (this.allowedProtocols.get(p)) { 399 sbuf.append(" "); 400 if (p < Protocol.strings.length) { 401 sbuf.append(Protocol.strings[p]); 402 } else { 403 sbuf.append("??"); 404 } 405 } 406 } 407 sbuf.append('\n'); 408 sbuf.append(" AuthAlgorithms:"); 409 for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) { 410 if (this.allowedAuthAlgorithms.get(a)) { 411 sbuf.append(" "); 412 if (a < AuthAlgorithm.strings.length) { 413 sbuf.append(AuthAlgorithm.strings[a]); 414 } else { 415 sbuf.append("??"); 416 } 417 } 418 } 419 sbuf.append('\n'); 420 sbuf.append(" PairwiseCiphers:"); 421 for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) { 422 if (this.allowedPairwiseCiphers.get(pc)) { 423 sbuf.append(" "); 424 if (pc < PairwiseCipher.strings.length) { 425 sbuf.append(PairwiseCipher.strings[pc]); 426 } else { 427 sbuf.append("??"); 428 } 429 } 430 } 431 sbuf.append('\n'); 432 sbuf.append(" GroupCiphers:"); 433 for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) { 434 if (this.allowedGroupCiphers.get(gc)) { 435 sbuf.append(" "); 436 if (gc < GroupCipher.strings.length) { 437 sbuf.append(GroupCipher.strings[gc]); 438 } else { 439 sbuf.append("??"); 440 } 441 } 442 } 443 sbuf.append('\n').append(" PSK: "); 444 if (this.preSharedKey != null) { 445 sbuf.append('*'); 446 } 447 448 sbuf.append(enterpriseConfig); 449 sbuf.append('\n'); 450 451 sbuf.append("IP assignment: " + ipAssignment.toString()); 452 sbuf.append("\n"); 453 sbuf.append("Proxy settings: " + proxySettings.toString()); 454 sbuf.append("\n"); 455 sbuf.append(linkProperties.toString()); 456 sbuf.append("\n"); 457 458 return sbuf.toString(); 459 } 460 461 /** 462 * Construct a WifiConfiguration from a scanned network 463 * @param scannedAP the scan result used to construct the config entry 464 * TODO: figure out whether this is a useful way to construct a new entry. 465 * 466 public WifiConfiguration(ScanResult scannedAP) { 467 networkId = -1; 468 SSID = scannedAP.SSID; 469 BSSID = scannedAP.BSSID; 470 } 471 */ 472 473 /** {@hide} */ 474 public String getPrintableSsid() { 475 if (SSID == null) return ""; 476 final int length = SSID.length(); 477 if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') { 478 return SSID.substring(1, length - 1); 479 } 480 481 /** The ascii-encoded string format is P"<ascii-encoded-string>" 482 * The decoding is implemented in the supplicant for a newly configured 483 * network. 484 */ 485 if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') && 486 (SSID.charAt(length-1) == '"')) { 487 WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded( 488 SSID.substring(2, length - 1)); 489 return wifiSsid.toString(); 490 } 491 return SSID; 492 } 493 494 /** 495 * Get an identifier for associating credentials with this config 496 * @param current configuration contains values for additional fields 497 * that are not part of this configuration. Used 498 * when a config with some fields is passed by an application. 499 * @throws IllegalStateException if config is invalid for key id generation 500 * @hide 501 */ 502 String getKeyIdForCredentials(WifiConfiguration current) { 503 String keyMgmt = null; 504 505 try { 506 // Get current config details for fields that are not initialized 507 if (TextUtils.isEmpty(SSID)) SSID = current.SSID; 508 if (allowedKeyManagement.cardinality() == 0) { 509 allowedKeyManagement = current.allowedKeyManagement; 510 } 511 if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { 512 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP]; 513 } 514 if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 515 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X]; 516 } 517 518 if (TextUtils.isEmpty(keyMgmt)) { 519 throw new IllegalStateException("Not an EAP network"); 520 } 521 522 return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" + 523 trimStringForKeyId(enterpriseConfig.getKeyId(current != null ? 524 current.enterpriseConfig : null)); 525 } catch (NullPointerException e) { 526 throw new IllegalStateException("Invalid config details"); 527 } 528 } 529 530 private String trimStringForKeyId(String string) { 531 // Remove quotes and spaces 532 return string.replace("\"", "").replace(" ", ""); 533 } 534 535 private static BitSet readBitSet(Parcel src) { 536 int cardinality = src.readInt(); 537 538 BitSet set = new BitSet(); 539 for (int i = 0; i < cardinality; i++) { 540 set.set(src.readInt()); 541 } 542 543 return set; 544 } 545 546 private static void writeBitSet(Parcel dest, BitSet set) { 547 int nextSetBit = -1; 548 549 dest.writeInt(set.cardinality()); 550 551 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 552 dest.writeInt(nextSetBit); 553 } 554 } 555 556 /** @hide */ 557 public int getAuthType() { 558 if (isValid() == false) { 559 throw new IllegalStateException("Invalid configuration"); 560 } 561 if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 562 return KeyMgmt.WPA_PSK; 563 } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) { 564 return KeyMgmt.WPA2_PSK; 565 } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { 566 return KeyMgmt.WPA_EAP; 567 } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 568 return KeyMgmt.IEEE8021X; 569 } 570 return KeyMgmt.NONE; 571 } 572 573 /** Implement the Parcelable interface {@hide} */ 574 public int describeContents() { 575 return 0; 576 } 577 578 /** copy constructor {@hide} */ 579 public WifiConfiguration(WifiConfiguration source) { 580 if (source != null) { 581 networkId = source.networkId; 582 status = source.status; 583 disableReason = source.disableReason; 584 SSID = source.SSID; 585 BSSID = source.BSSID; 586 preSharedKey = source.preSharedKey; 587 588 wepKeys = new String[4]; 589 for (int i = 0; i < wepKeys.length; i++) { 590 wepKeys[i] = source.wepKeys[i]; 591 } 592 593 wepTxKeyIndex = source.wepTxKeyIndex; 594 priority = source.priority; 595 hiddenSSID = source.hiddenSSID; 596 allowedKeyManagement = (BitSet) source.allowedKeyManagement.clone(); 597 allowedProtocols = (BitSet) source.allowedProtocols.clone(); 598 allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone(); 599 allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone(); 600 allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone(); 601 602 enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig); 603 604 ipAssignment = source.ipAssignment; 605 proxySettings = source.proxySettings; 606 linkProperties = new LinkProperties(source.linkProperties); 607 } 608 } 609 610 /** Implement the Parcelable interface {@hide} */ 611 public void writeToParcel(Parcel dest, int flags) { 612 dest.writeInt(networkId); 613 dest.writeInt(status); 614 dest.writeInt(disableReason); 615 dest.writeString(SSID); 616 dest.writeString(BSSID); 617 dest.writeString(preSharedKey); 618 for (String wepKey : wepKeys) { 619 dest.writeString(wepKey); 620 } 621 dest.writeInt(wepTxKeyIndex); 622 dest.writeInt(priority); 623 dest.writeInt(hiddenSSID ? 1 : 0); 624 625 writeBitSet(dest, allowedKeyManagement); 626 writeBitSet(dest, allowedProtocols); 627 writeBitSet(dest, allowedAuthAlgorithms); 628 writeBitSet(dest, allowedPairwiseCiphers); 629 writeBitSet(dest, allowedGroupCiphers); 630 631 dest.writeParcelable(enterpriseConfig, flags); 632 633 dest.writeString(ipAssignment.name()); 634 dest.writeString(proxySettings.name()); 635 dest.writeParcelable(linkProperties, flags); 636 } 637 638 /** Implement the Parcelable interface {@hide} */ 639 public static final Creator<WifiConfiguration> CREATOR = 640 new Creator<WifiConfiguration>() { 641 public WifiConfiguration createFromParcel(Parcel in) { 642 WifiConfiguration config = new WifiConfiguration(); 643 config.networkId = in.readInt(); 644 config.status = in.readInt(); 645 config.disableReason = in.readInt(); 646 config.SSID = in.readString(); 647 config.BSSID = in.readString(); 648 config.preSharedKey = in.readString(); 649 for (int i = 0; i < config.wepKeys.length; i++) { 650 config.wepKeys[i] = in.readString(); 651 } 652 config.wepTxKeyIndex = in.readInt(); 653 config.priority = in.readInt(); 654 config.hiddenSSID = in.readInt() != 0; 655 config.allowedKeyManagement = readBitSet(in); 656 config.allowedProtocols = readBitSet(in); 657 config.allowedAuthAlgorithms = readBitSet(in); 658 config.allowedPairwiseCiphers = readBitSet(in); 659 config.allowedGroupCiphers = readBitSet(in); 660 661 config.enterpriseConfig = in.readParcelable(null); 662 663 config.ipAssignment = IpAssignment.valueOf(in.readString()); 664 config.proxySettings = ProxySettings.valueOf(in.readString()); 665 config.linkProperties = in.readParcelable(null); 666 667 return config; 668 } 669 670 public WifiConfiguration[] newArray(int size) { 671 return new WifiConfiguration[size]; 672 } 673 }; 674 } 675