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.annotation.SystemApi; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import java.util.ArrayList; 24 import java.util.List; 25 26 /** 27 * Describes information about a detected access point. In addition 28 * to the attributes described here, the supplicant keeps track of 29 * {@code quality}, {@code noise}, and {@code maxbitrate} attributes, 30 * but does not currently report them to external clients. 31 */ 32 public class ScanResult implements Parcelable { 33 /** 34 * The network name. 35 */ 36 public String SSID; 37 38 /** 39 * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide 40 */ 41 public WifiSsid wifiSsid; 42 43 /** 44 * The address of the access point. 45 */ 46 public String BSSID; 47 48 /** 49 * The HESSID from the beacon. 50 * @hide 51 */ 52 public long hessid; 53 54 /** 55 * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present. 56 * @hide 57 */ 58 public int anqpDomainId; 59 60 /* 61 * This field is equivalent to the |flags|, rather than the |capabilities| field 62 * of the per-BSS scan results returned by WPA supplicant. See the definition of 63 * |struct wpa_bss| in wpa_supplicant/bss.h for more details. 64 */ 65 /** 66 * Describes the authentication, key management, and encryption schemes 67 * supported by the access point. 68 */ 69 public String capabilities; 70 71 /** 72 * @hide 73 * No security protocol. 74 */ 75 public static final int PROTOCOL_NONE = 0; 76 /** 77 * @hide 78 * Security protocol type: WPA version 1. 79 */ 80 public static final int PROTOCOL_WPA = 1; 81 /** 82 * @hide 83 * Security protocol type: WPA version 2, also called RSN. 84 */ 85 public static final int PROTOCOL_WPA2 = 2; 86 /** 87 * @hide 88 * Security protocol type: 89 * OSU Server-only authenticated layer 2 Encryption Network. 90 * Used for Hotspot 2.0. 91 */ 92 public static final int PROTOCOL_OSEN = 3; 93 94 /** 95 * @hide 96 * No security key management scheme. 97 */ 98 public static final int KEY_MGMT_NONE = 0; 99 /** 100 * @hide 101 * Security key management scheme: PSK. 102 */ 103 public static final int KEY_MGMT_PSK = 1; 104 /** 105 * @hide 106 * Security key management scheme: EAP. 107 */ 108 public static final int KEY_MGMT_EAP = 2; 109 /** 110 * @hide 111 * Security key management scheme: FT_PSK. 112 */ 113 public static final int KEY_MGMT_FT_PSK = 3; 114 /** 115 * @hide 116 * Security key management scheme: FT_EAP. 117 */ 118 public static final int KEY_MGMT_FT_EAP = 4; 119 /** 120 * @hide 121 * Security key management scheme: PSK_SHA256 122 */ 123 public static final int KEY_MGMT_PSK_SHA256 = 5; 124 /** 125 * @hide 126 * Security key management scheme: EAP_SHA256. 127 */ 128 public static final int KEY_MGMT_EAP_SHA256 = 6; 129 /** 130 * @hide 131 * Security key management scheme: OSEN. 132 * Used for Hotspot 2.0. 133 */ 134 public static final int KEY_MGMT_OSEN = 7; 135 136 /** 137 * @hide 138 * No cipher suite. 139 */ 140 public static final int CIPHER_NONE = 0; 141 /** 142 * @hide 143 * No group addressed, only used for group data cipher. 144 */ 145 public static final int CIPHER_NO_GROUP_ADDRESSED = 1; 146 /** 147 * @hide 148 * Cipher suite: TKIP 149 */ 150 public static final int CIPHER_TKIP = 2; 151 /** 152 * @hide 153 * Cipher suite: CCMP 154 */ 155 public static final int CIPHER_CCMP = 3; 156 157 /** 158 * The detected signal level in dBm, also known as the RSSI. 159 * 160 * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into 161 * an absolute signal level which can be displayed to a user. 162 */ 163 public int level; 164 /** 165 * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating 166 * with the access point. 167 */ 168 public int frequency; 169 170 /** 171 * AP Channel bandwidth is 20 MHZ 172 */ 173 public static final int CHANNEL_WIDTH_20MHZ = 0; 174 /** 175 * AP Channel bandwidth is 40 MHZ 176 */ 177 public static final int CHANNEL_WIDTH_40MHZ = 1; 178 /** 179 * AP Channel bandwidth is 80 MHZ 180 */ 181 public static final int CHANNEL_WIDTH_80MHZ = 2; 182 /** 183 * AP Channel bandwidth is 160 MHZ 184 */ 185 public static final int CHANNEL_WIDTH_160MHZ = 3; 186 /** 187 * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ 188 */ 189 public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; 190 191 /** 192 * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ}, 193 * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ} 194 * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}. 195 */ 196 public int channelWidth; 197 198 /** 199 * Not used if the AP bandwidth is 20 MHz 200 * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz) 201 * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz) 202 */ 203 public int centerFreq0; 204 205 /** 206 * Only used if the AP bandwidth is 80 + 80 MHz 207 * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz) 208 */ 209 public int centerFreq1; 210 211 /** 212 * @deprecated use is80211mcResponder() instead 213 * @hide 214 */ 215 public boolean is80211McRTTResponder; 216 217 /** 218 * timestamp in microseconds (since boot) when 219 * this result was last seen. 220 */ 221 public long timestamp; 222 223 /** 224 * Timestamp representing date when this result was last seen, in milliseconds from 1970 225 * {@hide} 226 */ 227 public long seen; 228 229 /** 230 * @hide 231 * Update RSSI of the scan result 232 * @param previousRssi 233 * @param previousSeen 234 * @param maxAge 235 */ 236 public void averageRssi(int previousRssi, long previousSeen, int maxAge) { 237 238 if (seen == 0) { 239 seen = System.currentTimeMillis(); 240 } 241 long age = seen - previousSeen; 242 243 if (previousSeen > 0 && age > 0 && age < maxAge/2) { 244 // Average the RSSI with previously seen instances of this scan result 245 double alpha = 0.5 - (double) age / (double) maxAge; 246 level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha); 247 } 248 } 249 250 /** 251 * num IP configuration failures 252 * @hide 253 */ 254 public int numIpConfigFailures; 255 256 /** 257 * @hide 258 * Last time we blacklisted the ScanResult 259 */ 260 public long blackListTimestamp; 261 262 /** 263 * Status indicating the scan result does not correspond to a user's saved configuration 264 * @hide 265 */ 266 @SystemApi 267 public boolean untrusted; 268 269 /** 270 * Number of time we connected to it 271 * @hide 272 */ 273 public int numConnection; 274 275 /** 276 * Number of time autojoin used it 277 * @hide 278 */ 279 public int numUsage; 280 281 /** 282 * The approximate distance to the AP in centimeter, if available. Else 283 * {@link UNSPECIFIED}. 284 * {@hide} 285 */ 286 public int distanceCm; 287 288 /** 289 * The standard deviation of the distance to the access point, if available. 290 * Else {@link UNSPECIFIED}. 291 * {@hide} 292 */ 293 public int distanceSdCm; 294 295 /** {@hide} */ 296 public static final long FLAG_PASSPOINT_NETWORK = 0x0000000000000001; 297 298 /** {@hide} */ 299 public static final long FLAG_80211mc_RESPONDER = 0x0000000000000002; 300 301 /* 302 * These flags are specific to the ScanResult class, and are not related to the |flags| 303 * field of the per-BSS scan results from WPA supplicant. 304 */ 305 /** 306 * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}. 307 * {@hide} 308 */ 309 public long flags; 310 311 /** 312 * sets a flag in {@link #flags} field 313 * @param flag flag to set 314 * @hide 315 */ 316 public void setFlag(long flag) { 317 flags |= flag; 318 } 319 320 /** 321 * clears a flag in {@link #flags} field 322 * @param flag flag to set 323 * @hide 324 */ 325 public void clearFlag(long flag) { 326 flags &= ~flag; 327 } 328 329 public boolean is80211mcResponder() { 330 return (flags & FLAG_80211mc_RESPONDER) != 0; 331 } 332 333 public boolean isPasspointNetwork() { 334 return (flags & FLAG_PASSPOINT_NETWORK) != 0; 335 } 336 337 /** 338 * Indicates venue name (such as 'San Francisco Airport') published by access point; only 339 * available on Passpoint network and if published by access point. 340 */ 341 public CharSequence venueName; 342 343 /** 344 * Indicates Passpoint operator name published by access point. 345 */ 346 public CharSequence operatorFriendlyName; 347 348 /** 349 * {@hide} 350 */ 351 public final static int UNSPECIFIED = -1; 352 /** 353 * @hide 354 */ 355 public boolean is24GHz() { 356 return ScanResult.is24GHz(frequency); 357 } 358 359 /** 360 * @hide 361 * TODO: makes real freq boundaries 362 */ 363 public static boolean is24GHz(int freq) { 364 return freq > 2400 && freq < 2500; 365 } 366 367 /** 368 * @hide 369 */ 370 public boolean is5GHz() { 371 return ScanResult.is5GHz(frequency); 372 } 373 374 /** 375 * @hide 376 * TODO: makes real freq boundaries 377 */ 378 public static boolean is5GHz(int freq) { 379 return freq > 4900 && freq < 5900; 380 } 381 382 /** 383 * @hide 384 * anqp lines from supplicant BSS response 385 */ 386 public List<String> anqpLines; 387 388 /** 389 * @hide 390 * storing the raw bytes of full result IEs 391 **/ 392 public byte[] bytes; 393 394 /** information elements from beacon 395 * @hide 396 */ 397 public static class InformationElement { 398 public static final int EID_SSID = 0; 399 public static final int EID_SUPPORTED_RATES = 1; 400 public static final int EID_TIM = 5; 401 public static final int EID_BSS_LOAD = 11; 402 public static final int EID_ERP = 42; 403 public static final int EID_RSN = 48; 404 public static final int EID_EXTENDED_SUPPORTED_RATES = 50; 405 public static final int EID_HT_OPERATION = 61; 406 public static final int EID_INTERWORKING = 107; 407 public static final int EID_ROAMING_CONSORTIUM = 111; 408 public static final int EID_EXTENDED_CAPS = 127; 409 public static final int EID_VHT_OPERATION = 192; 410 public static final int EID_VSA = 221; 411 412 public int id; 413 public byte[] bytes; 414 415 public InformationElement() { 416 } 417 418 public InformationElement(InformationElement rhs) { 419 this.id = rhs.id; 420 this.bytes = rhs.bytes.clone(); 421 } 422 } 423 424 /** information elements found in the beacon 425 * @hide 426 */ 427 public InformationElement[] informationElements; 428 429 /** ANQP response elements. 430 * @hide 431 */ 432 public AnqpInformationElement[] anqpElements; 433 434 /** {@hide} */ 435 public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, 436 byte[] osuProviders, String caps, int level, int frequency, long tsf) { 437 this.wifiSsid = wifiSsid; 438 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 439 this.BSSID = BSSID; 440 this.hessid = hessid; 441 this.anqpDomainId = anqpDomainId; 442 if (osuProviders != null) { 443 this.anqpElements = new AnqpInformationElement[1]; 444 this.anqpElements[0] = 445 new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID, 446 AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders); 447 } 448 this.capabilities = caps; 449 this.level = level; 450 this.frequency = frequency; 451 this.timestamp = tsf; 452 this.distanceCm = UNSPECIFIED; 453 this.distanceSdCm = UNSPECIFIED; 454 this.channelWidth = UNSPECIFIED; 455 this.centerFreq0 = UNSPECIFIED; 456 this.centerFreq1 = UNSPECIFIED; 457 this.flags = 0; 458 } 459 460 /** {@hide} */ 461 public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, 462 long tsf, int distCm, int distSdCm) { 463 this.wifiSsid = wifiSsid; 464 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 465 this.BSSID = BSSID; 466 this.capabilities = caps; 467 this.level = level; 468 this.frequency = frequency; 469 this.timestamp = tsf; 470 this.distanceCm = distCm; 471 this.distanceSdCm = distSdCm; 472 this.channelWidth = UNSPECIFIED; 473 this.centerFreq0 = UNSPECIFIED; 474 this.centerFreq1 = UNSPECIFIED; 475 this.flags = 0; 476 } 477 478 /** {@hide} */ 479 public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, 480 int level, int frequency, 481 long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, 482 boolean is80211McRTTResponder) { 483 this.SSID = Ssid; 484 this.BSSID = BSSID; 485 this.hessid = hessid; 486 this.anqpDomainId = anqpDomainId; 487 this.capabilities = caps; 488 this.level = level; 489 this.frequency = frequency; 490 this.timestamp = tsf; 491 this.distanceCm = distCm; 492 this.distanceSdCm = distSdCm; 493 this.channelWidth = channelWidth; 494 this.centerFreq0 = centerFreq0; 495 this.centerFreq1 = centerFreq1; 496 if (is80211McRTTResponder) { 497 this.flags = FLAG_80211mc_RESPONDER; 498 } else { 499 this.flags = 0; 500 } 501 } 502 503 /** {@hide} */ 504 public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId, 505 String caps, int level, 506 int frequency, long tsf, int distCm, int distSdCm, int channelWidth, 507 int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) { 508 this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm, 509 distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder); 510 this.wifiSsid = wifiSsid; 511 } 512 513 /** copy constructor {@hide} */ 514 public ScanResult(ScanResult source) { 515 if (source != null) { 516 wifiSsid = source.wifiSsid; 517 SSID = source.SSID; 518 BSSID = source.BSSID; 519 hessid = source.hessid; 520 anqpDomainId = source.anqpDomainId; 521 informationElements = source.informationElements; 522 anqpElements = source.anqpElements; 523 capabilities = source.capabilities; 524 level = source.level; 525 frequency = source.frequency; 526 channelWidth = source.channelWidth; 527 centerFreq0 = source.centerFreq0; 528 centerFreq1 = source.centerFreq1; 529 timestamp = source.timestamp; 530 distanceCm = source.distanceCm; 531 distanceSdCm = source.distanceSdCm; 532 seen = source.seen; 533 untrusted = source.untrusted; 534 numConnection = source.numConnection; 535 numUsage = source.numUsage; 536 numIpConfigFailures = source.numIpConfigFailures; 537 venueName = source.venueName; 538 operatorFriendlyName = source.operatorFriendlyName; 539 flags = source.flags; 540 } 541 } 542 543 /** empty scan result 544 * 545 * {@hide} 546 * */ 547 public ScanResult() { 548 } 549 550 @Override 551 public String toString() { 552 StringBuffer sb = new StringBuffer(); 553 String none = "<none>"; 554 555 sb.append("SSID: "). 556 append(wifiSsid == null ? WifiSsid.NONE : wifiSsid). 557 append(", BSSID: "). 558 append(BSSID == null ? none : BSSID). 559 append(", capabilities: "). 560 append(capabilities == null ? none : capabilities). 561 append(", level: "). 562 append(level). 563 append(", frequency: "). 564 append(frequency). 565 append(", timestamp: "). 566 append(timestamp); 567 568 sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")). 569 append("(cm)"); 570 sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")). 571 append("(cm)"); 572 573 sb.append(", passpoint: "); 574 sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no"); 575 sb.append(", ChannelBandwidth: ").append(channelWidth); 576 sb.append(", centerFreq0: ").append(centerFreq0); 577 sb.append(", centerFreq1: ").append(centerFreq1); 578 sb.append(", 80211mcResponder: "); 579 sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported"); 580 return sb.toString(); 581 } 582 583 /** Implement the Parcelable interface {@hide} */ 584 public int describeContents() { 585 return 0; 586 } 587 588 /** Implement the Parcelable interface {@hide} */ 589 public void writeToParcel(Parcel dest, int flags) { 590 if (wifiSsid != null) { 591 dest.writeInt(1); 592 wifiSsid.writeToParcel(dest, flags); 593 } else { 594 dest.writeInt(0); 595 } 596 dest.writeString(SSID); 597 dest.writeString(BSSID); 598 dest.writeLong(hessid); 599 dest.writeInt(anqpDomainId); 600 dest.writeString(capabilities); 601 dest.writeInt(level); 602 dest.writeInt(frequency); 603 dest.writeLong(timestamp); 604 dest.writeInt(distanceCm); 605 dest.writeInt(distanceSdCm); 606 dest.writeInt(channelWidth); 607 dest.writeInt(centerFreq0); 608 dest.writeInt(centerFreq1); 609 dest.writeLong(seen); 610 dest.writeInt(untrusted ? 1 : 0); 611 dest.writeInt(numConnection); 612 dest.writeInt(numUsage); 613 dest.writeInt(numIpConfigFailures); 614 dest.writeString((venueName != null) ? venueName.toString() : ""); 615 dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : ""); 616 dest.writeLong(this.flags); 617 618 if (informationElements != null) { 619 dest.writeInt(informationElements.length); 620 for (int i = 0; i < informationElements.length; i++) { 621 dest.writeInt(informationElements[i].id); 622 dest.writeInt(informationElements[i].bytes.length); 623 dest.writeByteArray(informationElements[i].bytes); 624 } 625 } else { 626 dest.writeInt(0); 627 } 628 629 if (anqpLines != null) { 630 dest.writeInt(anqpLines.size()); 631 for (int i = 0; i < anqpLines.size(); i++) { 632 dest.writeString(anqpLines.get(i)); 633 } 634 } 635 else { 636 dest.writeInt(0); 637 } 638 if (anqpElements != null) { 639 dest.writeInt(anqpElements.length); 640 for (AnqpInformationElement element : anqpElements) { 641 dest.writeInt(element.getVendorId()); 642 dest.writeInt(element.getElementId()); 643 dest.writeInt(element.getPayload().length); 644 dest.writeByteArray(element.getPayload()); 645 } 646 } else { 647 dest.writeInt(0); 648 } 649 } 650 651 /** Implement the Parcelable interface {@hide} */ 652 public static final Creator<ScanResult> CREATOR = 653 new Creator<ScanResult>() { 654 public ScanResult createFromParcel(Parcel in) { 655 WifiSsid wifiSsid = null; 656 if (in.readInt() == 1) { 657 wifiSsid = WifiSsid.CREATOR.createFromParcel(in); 658 } 659 ScanResult sr = new ScanResult( 660 wifiSsid, 661 in.readString(), /* SSID */ 662 in.readString(), /* BSSID */ 663 in.readLong(), /* HESSID */ 664 in.readInt(), /* ANQP Domain ID */ 665 in.readString(), /* capabilities */ 666 in.readInt(), /* level */ 667 in.readInt(), /* frequency */ 668 in.readLong(), /* timestamp */ 669 in.readInt(), /* distanceCm */ 670 in.readInt(), /* distanceSdCm */ 671 in.readInt(), /* channelWidth */ 672 in.readInt(), /* centerFreq0 */ 673 in.readInt(), /* centerFreq1 */ 674 false /* rtt responder, 675 fixed with flags below */ 676 ); 677 678 sr.seen = in.readLong(); 679 sr.untrusted = in.readInt() != 0; 680 sr.numConnection = in.readInt(); 681 sr.numUsage = in.readInt(); 682 sr.numIpConfigFailures = in.readInt(); 683 sr.venueName = in.readString(); 684 sr.operatorFriendlyName = in.readString(); 685 sr.flags = in.readLong(); 686 int n = in.readInt(); 687 if (n != 0) { 688 sr.informationElements = new InformationElement[n]; 689 for (int i = 0; i < n; i++) { 690 sr.informationElements[i] = new InformationElement(); 691 sr.informationElements[i].id = in.readInt(); 692 int len = in.readInt(); 693 sr.informationElements[i].bytes = new byte[len]; 694 in.readByteArray(sr.informationElements[i].bytes); 695 } 696 } 697 698 n = in.readInt(); 699 if (n != 0) { 700 sr.anqpLines = new ArrayList<String>(); 701 for (int i = 0; i < n; i++) { 702 sr.anqpLines.add(in.readString()); 703 } 704 } 705 n = in.readInt(); 706 if (n != 0) { 707 sr.anqpElements = new AnqpInformationElement[n]; 708 for (int i = 0; i < n; i++) { 709 int vendorId = in.readInt(); 710 int elementId = in.readInt(); 711 int len = in.readInt(); 712 byte[] payload = new byte[len]; 713 in.readByteArray(payload); 714 sr.anqpElements[i] = 715 new AnqpInformationElement(vendorId, elementId, payload); 716 } 717 } 718 return sr; 719 } 720 721 public ScanResult[] newArray(int size) { 722 return new ScanResult[size]; 723 } 724 }; 725 } 726