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 177 /** 178 * The ID number that the supplicant uses to identify this 179 * network configuration entry. This must be passed as an argument 180 * to most calls into the supplicant. 181 */ 182 public int networkId; 183 184 /** 185 * The current status of this network configuration entry. 186 * @see Status 187 */ 188 public int status; 189 190 /** 191 * The code referring to a reason for disabling the network 192 * Valid when {@link #status} == Status.DISABLED 193 * @hide 194 */ 195 public int disableReason; 196 197 /** 198 * The network's SSID. Can either be an ASCII string, 199 * which must be enclosed in double quotation marks 200 * (e.g., {@code "MyNetwork"}, or a string of 201 * hex digits,which are not enclosed in quotes 202 * (e.g., {@code 01a243f405}). 203 */ 204 public String SSID; 205 /** 206 * When set, this network configuration entry should only be used when 207 * associating with the AP having the specified BSSID. The value is 208 * a string in the format of an Ethernet MAC address, e.g., 209 * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit. 210 */ 211 public String BSSID; 212 213 /** 214 * Pre-shared key for use with WPA-PSK. 215 * <p/> 216 * When the value of this key is read, the actual key is 217 * not returned, just a "*" if the key has a value, or the null 218 * string otherwise. 219 */ 220 public String preSharedKey; 221 /** 222 * Up to four WEP keys. Either an ASCII string enclosed in double 223 * quotation marks (e.g., {@code "abcdef"} or a string 224 * of hex digits (e.g., {@code 0102030405}). 225 * <p/> 226 * When the value of one of these keys is read, the actual key is 227 * not returned, just a "*" if the key has a value, or the null 228 * string otherwise. 229 */ 230 public String[] wepKeys; 231 232 /** Default WEP key index, ranging from 0 to 3. */ 233 public int wepTxKeyIndex; 234 235 /** 236 * Priority determines the preference given to a network by {@code wpa_supplicant} 237 * when choosing an access point with which to associate. 238 */ 239 public int priority; 240 241 /** 242 * This is a network that does not broadcast its SSID, so an 243 * SSID-specific probe request must be used for scans. 244 */ 245 public boolean hiddenSSID; 246 247 /** 248 * The set of key management protocols supported by this configuration. 249 * See {@link KeyMgmt} for descriptions of the values. 250 * Defaults to WPA-PSK WPA-EAP. 251 */ 252 public BitSet allowedKeyManagement; 253 /** 254 * The set of security protocols supported by this configuration. 255 * See {@link Protocol} for descriptions of the values. 256 * Defaults to WPA RSN. 257 */ 258 public BitSet allowedProtocols; 259 /** 260 * The set of authentication protocols supported by this configuration. 261 * See {@link AuthAlgorithm} for descriptions of the values. 262 * Defaults to automatic selection. 263 */ 264 public BitSet allowedAuthAlgorithms; 265 /** 266 * The set of pairwise ciphers for WPA supported by this configuration. 267 * See {@link PairwiseCipher} for descriptions of the values. 268 * Defaults to CCMP TKIP. 269 */ 270 public BitSet allowedPairwiseCiphers; 271 /** 272 * The set of group ciphers supported by this configuration. 273 * See {@link GroupCipher} for descriptions of the values. 274 * Defaults to CCMP TKIP WEP104 WEP40. 275 */ 276 public BitSet allowedGroupCiphers; 277 /** 278 * The enterprise configuration details specifying the EAP method, 279 * certificates and other settings associated with the EAP. 280 */ 281 public WifiEnterpriseConfig enterpriseConfig; 282 283 /** 284 * @hide 285 */ 286 public enum IpAssignment { 287 /* Use statically configured IP settings. Configuration can be accessed 288 * with linkProperties */ 289 STATIC, 290 /* Use dynamically configured IP settigns */ 291 DHCP, 292 /* no IP details are assigned, this is used to indicate 293 * that any existing IP settings should be retained */ 294 UNASSIGNED 295 } 296 /** 297 * @hide 298 */ 299 public IpAssignment ipAssignment; 300 301 /** 302 * @hide 303 */ 304 public enum ProxySettings { 305 /* No proxy is to be used. Any existing proxy settings 306 * should be cleared. */ 307 NONE, 308 /* Use statically configured proxy. Configuration can be accessed 309 * with linkProperties */ 310 STATIC, 311 /* no proxy details are assigned, this is used to indicate 312 * that any existing proxy settings should be retained */ 313 UNASSIGNED 314 } 315 /** 316 * @hide 317 */ 318 public ProxySettings proxySettings; 319 /** 320 * @hide 321 */ 322 public LinkProperties linkProperties; 323 324 public WifiConfiguration() { 325 networkId = INVALID_NETWORK_ID; 326 SSID = null; 327 BSSID = null; 328 priority = 0; 329 hiddenSSID = false; 330 disableReason = DISABLED_UNKNOWN_REASON; 331 allowedKeyManagement = new BitSet(); 332 allowedProtocols = new BitSet(); 333 allowedAuthAlgorithms = new BitSet(); 334 allowedPairwiseCiphers = new BitSet(); 335 allowedGroupCiphers = new BitSet(); 336 wepKeys = new String[4]; 337 for (int i = 0; i < wepKeys.length; i++) { 338 wepKeys[i] = null; 339 } 340 enterpriseConfig = new WifiEnterpriseConfig(); 341 ipAssignment = IpAssignment.UNASSIGNED; 342 proxySettings = ProxySettings.UNASSIGNED; 343 linkProperties = new LinkProperties(); 344 } 345 346 @Override 347 public String toString() { 348 StringBuilder sbuf = new StringBuilder(); 349 if (this.status == WifiConfiguration.Status.CURRENT) { 350 sbuf.append("* "); 351 } else if (this.status == WifiConfiguration.Status.DISABLED) { 352 sbuf.append("- DSBLE: ").append(this.disableReason).append(" "); 353 } 354 sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID). 355 append(" BSSID: ").append(this.BSSID).append(" PRIO: ").append(this.priority). 356 append('\n'); 357 sbuf.append(" KeyMgmt:"); 358 for (int k = 0; k < this.allowedKeyManagement.size(); k++) { 359 if (this.allowedKeyManagement.get(k)) { 360 sbuf.append(" "); 361 if (k < KeyMgmt.strings.length) { 362 sbuf.append(KeyMgmt.strings[k]); 363 } else { 364 sbuf.append("??"); 365 } 366 } 367 } 368 sbuf.append(" Protocols:"); 369 for (int p = 0; p < this.allowedProtocols.size(); p++) { 370 if (this.allowedProtocols.get(p)) { 371 sbuf.append(" "); 372 if (p < Protocol.strings.length) { 373 sbuf.append(Protocol.strings[p]); 374 } else { 375 sbuf.append("??"); 376 } 377 } 378 } 379 sbuf.append('\n'); 380 sbuf.append(" AuthAlgorithms:"); 381 for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) { 382 if (this.allowedAuthAlgorithms.get(a)) { 383 sbuf.append(" "); 384 if (a < AuthAlgorithm.strings.length) { 385 sbuf.append(AuthAlgorithm.strings[a]); 386 } else { 387 sbuf.append("??"); 388 } 389 } 390 } 391 sbuf.append('\n'); 392 sbuf.append(" PairwiseCiphers:"); 393 for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) { 394 if (this.allowedPairwiseCiphers.get(pc)) { 395 sbuf.append(" "); 396 if (pc < PairwiseCipher.strings.length) { 397 sbuf.append(PairwiseCipher.strings[pc]); 398 } else { 399 sbuf.append("??"); 400 } 401 } 402 } 403 sbuf.append('\n'); 404 sbuf.append(" GroupCiphers:"); 405 for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) { 406 if (this.allowedGroupCiphers.get(gc)) { 407 sbuf.append(" "); 408 if (gc < GroupCipher.strings.length) { 409 sbuf.append(GroupCipher.strings[gc]); 410 } else { 411 sbuf.append("??"); 412 } 413 } 414 } 415 sbuf.append('\n').append(" PSK: "); 416 if (this.preSharedKey != null) { 417 sbuf.append('*'); 418 } 419 420 sbuf.append(enterpriseConfig); 421 sbuf.append('\n'); 422 423 sbuf.append("IP assignment: " + ipAssignment.toString()); 424 sbuf.append("\n"); 425 sbuf.append("Proxy settings: " + proxySettings.toString()); 426 sbuf.append("\n"); 427 sbuf.append(linkProperties.toString()); 428 sbuf.append("\n"); 429 430 return sbuf.toString(); 431 } 432 433 /** 434 * Construct a WifiConfiguration from a scanned network 435 * @param scannedAP the scan result used to construct the config entry 436 * TODO: figure out whether this is a useful way to construct a new entry. 437 * 438 public WifiConfiguration(ScanResult scannedAP) { 439 networkId = -1; 440 SSID = scannedAP.SSID; 441 BSSID = scannedAP.BSSID; 442 } 443 */ 444 445 /** {@hide} */ 446 public String getPrintableSsid() { 447 if (SSID == null) return ""; 448 final int length = SSID.length(); 449 if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') { 450 return SSID.substring(1, length - 1); 451 } 452 453 /** The ascii-encoded string format is P"<ascii-encoded-string>" 454 * The decoding is implemented in the supplicant for a newly configured 455 * network. 456 */ 457 if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') && 458 (SSID.charAt(length-1) == '"')) { 459 WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded( 460 SSID.substring(2, length - 1)); 461 return wifiSsid.toString(); 462 } 463 return SSID; 464 } 465 466 /** 467 * Get an identifier for associating credentials with this config 468 * @param current configuration contains values for additional fields 469 * that are not part of this configuration. Used 470 * when a config with some fields is passed by an application. 471 * @throws IllegalStateException if config is invalid for key id generation 472 * @hide 473 */ 474 String getKeyIdForCredentials(WifiConfiguration current) { 475 String keyMgmt = null; 476 477 try { 478 // Get current config details for fields that are not initialized 479 if (TextUtils.isEmpty(SSID)) SSID = current.SSID; 480 if (allowedKeyManagement.cardinality() == 0) { 481 allowedKeyManagement = current.allowedKeyManagement; 482 } 483 if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { 484 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP]; 485 } 486 if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 487 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X]; 488 } 489 490 if (TextUtils.isEmpty(keyMgmt)) { 491 throw new IllegalStateException("Not an EAP network"); 492 } 493 494 return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" + 495 trimStringForKeyId(enterpriseConfig.getKeyId(current != null ? 496 current.enterpriseConfig : null)); 497 } catch (NullPointerException e) { 498 throw new IllegalStateException("Invalid config details"); 499 } 500 } 501 502 private String trimStringForKeyId(String string) { 503 // Remove quotes and spaces 504 return string.replace("\"", "").replace(" ", ""); 505 } 506 507 private static BitSet readBitSet(Parcel src) { 508 int cardinality = src.readInt(); 509 510 BitSet set = new BitSet(); 511 for (int i = 0; i < cardinality; i++) { 512 set.set(src.readInt()); 513 } 514 515 return set; 516 } 517 518 private static void writeBitSet(Parcel dest, BitSet set) { 519 int nextSetBit = -1; 520 521 dest.writeInt(set.cardinality()); 522 523 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 524 dest.writeInt(nextSetBit); 525 } 526 } 527 528 /** @hide */ 529 public int getAuthType() { 530 if (allowedKeyManagement.cardinality() > 1) { 531 throw new IllegalStateException("More than one auth type set"); 532 } 533 if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 534 return KeyMgmt.WPA_PSK; 535 } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) { 536 return KeyMgmt.WPA2_PSK; 537 } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { 538 return KeyMgmt.WPA_EAP; 539 } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 540 return KeyMgmt.IEEE8021X; 541 } 542 return KeyMgmt.NONE; 543 } 544 545 /** Implement the Parcelable interface {@hide} */ 546 public int describeContents() { 547 return 0; 548 } 549 550 /** copy constructor {@hide} */ 551 public WifiConfiguration(WifiConfiguration source) { 552 if (source != null) { 553 networkId = source.networkId; 554 status = source.status; 555 disableReason = source.disableReason; 556 SSID = source.SSID; 557 BSSID = source.BSSID; 558 preSharedKey = source.preSharedKey; 559 560 wepKeys = new String[4]; 561 for (int i = 0; i < wepKeys.length; i++) { 562 wepKeys[i] = source.wepKeys[i]; 563 } 564 565 wepTxKeyIndex = source.wepTxKeyIndex; 566 priority = source.priority; 567 hiddenSSID = source.hiddenSSID; 568 allowedKeyManagement = (BitSet) source.allowedKeyManagement.clone(); 569 allowedProtocols = (BitSet) source.allowedProtocols.clone(); 570 allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone(); 571 allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone(); 572 allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone(); 573 574 enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig); 575 576 ipAssignment = source.ipAssignment; 577 proxySettings = source.proxySettings; 578 linkProperties = new LinkProperties(source.linkProperties); 579 } 580 } 581 582 /** Implement the Parcelable interface {@hide} */ 583 public void writeToParcel(Parcel dest, int flags) { 584 dest.writeInt(networkId); 585 dest.writeInt(status); 586 dest.writeInt(disableReason); 587 dest.writeString(SSID); 588 dest.writeString(BSSID); 589 dest.writeString(preSharedKey); 590 for (String wepKey : wepKeys) { 591 dest.writeString(wepKey); 592 } 593 dest.writeInt(wepTxKeyIndex); 594 dest.writeInt(priority); 595 dest.writeInt(hiddenSSID ? 1 : 0); 596 597 writeBitSet(dest, allowedKeyManagement); 598 writeBitSet(dest, allowedProtocols); 599 writeBitSet(dest, allowedAuthAlgorithms); 600 writeBitSet(dest, allowedPairwiseCiphers); 601 writeBitSet(dest, allowedGroupCiphers); 602 603 dest.writeParcelable(enterpriseConfig, flags); 604 605 dest.writeString(ipAssignment.name()); 606 dest.writeString(proxySettings.name()); 607 dest.writeParcelable(linkProperties, flags); 608 } 609 610 /** Implement the Parcelable interface {@hide} */ 611 public static final Creator<WifiConfiguration> CREATOR = 612 new Creator<WifiConfiguration>() { 613 public WifiConfiguration createFromParcel(Parcel in) { 614 WifiConfiguration config = new WifiConfiguration(); 615 config.networkId = in.readInt(); 616 config.status = in.readInt(); 617 config.disableReason = in.readInt(); 618 config.SSID = in.readString(); 619 config.BSSID = in.readString(); 620 config.preSharedKey = in.readString(); 621 for (int i = 0; i < config.wepKeys.length; i++) { 622 config.wepKeys[i] = in.readString(); 623 } 624 config.wepTxKeyIndex = in.readInt(); 625 config.priority = in.readInt(); 626 config.hiddenSSID = in.readInt() != 0; 627 config.allowedKeyManagement = readBitSet(in); 628 config.allowedProtocols = readBitSet(in); 629 config.allowedAuthAlgorithms = readBitSet(in); 630 config.allowedPairwiseCiphers = readBitSet(in); 631 config.allowedGroupCiphers = readBitSet(in); 632 633 config.enterpriseConfig = in.readParcelable(null); 634 635 config.ipAssignment = IpAssignment.valueOf(in.readString()); 636 config.proxySettings = ProxySettings.valueOf(in.readString()); 637 config.linkProperties = in.readParcelable(null); 638 639 return config; 640 } 641 642 public WifiConfiguration[] newArray(int size) { 643 return new WifiConfiguration[size]; 644 } 645 }; 646 } 647