1 /* 2 * Copyright (C) 2017 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.rtt; 18 19 import static android.net.wifi.ScanResult.InformationElement.EID_EXTENSION_PRESENT; 20 import static android.net.wifi.ScanResult.InformationElement.EID_EXT_HE_CAPABILITIES; 21 import static android.net.wifi.ScanResult.InformationElement.EID_HT_CAPABILITIES; 22 import static android.net.wifi.ScanResult.InformationElement.EID_VHT_CAPABILITIES; 23 24 import android.annotation.IntDef; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.SystemApi; 28 import android.net.MacAddress; 29 import android.net.wifi.ScanResult; 30 import android.net.wifi.aware.PeerHandle; 31 import android.os.Parcel; 32 import android.os.Parcelable; 33 import android.util.Log; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 import java.util.Objects; 38 39 /** 40 * Defines the configuration of an IEEE 802.11mc Responder. The Responder may be an Access Point 41 * (AP), a Wi-Fi Aware device, or a manually configured Responder. 42 * <p> 43 * A Responder configuration may be constructed from a {@link ScanResult} or manually (with the 44 * data obtained out-of-band from a peer). 45 * 46 * @hide 47 */ 48 @SystemApi 49 public final class ResponderConfig implements Parcelable { 50 private static final String TAG = "ResponderConfig"; 51 private static final int AWARE_BAND_2_DISCOVERY_CHANNEL = 2437; 52 53 /** @hide */ 54 @IntDef({RESPONDER_AP, RESPONDER_STA, RESPONDER_P2P_GO, RESPONDER_P2P_CLIENT, RESPONDER_AWARE}) 55 @Retention(RetentionPolicy.SOURCE) 56 public @interface ResponderType { 57 } 58 59 /** 60 * Responder is an AP. 61 */ 62 public static final int RESPONDER_AP = 0; 63 /** 64 * Responder is a STA. 65 */ 66 public static final int RESPONDER_STA = 1; 67 /** 68 * Responder is a Wi-Fi Direct Group Owner (GO). 69 */ 70 public static final int RESPONDER_P2P_GO = 2; 71 /** 72 * Responder is a Wi-Fi Direct Group Client. 73 */ 74 public static final int RESPONDER_P2P_CLIENT = 3; 75 /** 76 * Responder is a Wi-Fi Aware device. 77 */ 78 public static final int RESPONDER_AWARE = 4; 79 80 81 /** @hide */ 82 @IntDef({ 83 CHANNEL_WIDTH_20MHZ, CHANNEL_WIDTH_40MHZ, CHANNEL_WIDTH_80MHZ, CHANNEL_WIDTH_160MHZ, 84 CHANNEL_WIDTH_80MHZ_PLUS_MHZ}) 85 @Retention(RetentionPolicy.SOURCE) 86 public @interface ChannelWidth { 87 } 88 89 /** 90 * Channel bandwidth is 20 MHZ 91 */ 92 public static final int CHANNEL_WIDTH_20MHZ = 0; 93 /** 94 * Channel bandwidth is 40 MHZ 95 */ 96 public static final int CHANNEL_WIDTH_40MHZ = 1; 97 /** 98 * Channel bandwidth is 80 MHZ 99 */ 100 public static final int CHANNEL_WIDTH_80MHZ = 2; 101 /** 102 * Channel bandwidth is 160 MHZ 103 */ 104 public static final int CHANNEL_WIDTH_160MHZ = 3; 105 /** 106 * Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ 107 */ 108 public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; 109 110 /** @hide */ 111 @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT, PREAMBLE_HE}) 112 @Retention(RetentionPolicy.SOURCE) 113 public @interface PreambleType { 114 } 115 116 /** 117 * Preamble type: Legacy. 118 */ 119 public static final int PREAMBLE_LEGACY = 0; 120 121 /** 122 * Preamble type: HT. 123 */ 124 public static final int PREAMBLE_HT = 1; 125 126 /** 127 * Preamble type: VHT. 128 */ 129 public static final int PREAMBLE_VHT = 2; 130 131 /** 132 * Preamble type: HE. 133 */ 134 public static final int PREAMBLE_HE = 3; 135 136 /** 137 * The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the 138 * peerHandle field) ise used to identify the Responder. 139 */ 140 public final MacAddress macAddress; 141 142 /** 143 * The peer identifier of a Wi-Fi Aware Responder. Will be null if a MAC Address (the macAddress 144 * field) is used to identify the Responder. 145 */ 146 public final PeerHandle peerHandle; 147 148 /** 149 * The device type of the Responder. 150 */ 151 public final int responderType; 152 153 /** 154 * Indicates whether the Responder device supports IEEE 802.11mc. 155 */ 156 public final boolean supports80211mc; 157 158 /** 159 * Responder channel bandwidth, specified using {@link ChannelWidth}. 160 */ 161 public final int channelWidth; 162 163 /** 164 * The primary 20 MHz frequency (in MHz) of the channel of the Responder. 165 */ 166 public final int frequency; 167 168 /** 169 * Not used if the {@link #channelWidth} is 20 MHz. If the Responder uses 40, 80 or 160 MHz, 170 * this is the center frequency (in MHz), if the Responder uses 80 + 80 MHz, this is the 171 * center frequency of the first segment (in MHz). 172 */ 173 public final int centerFreq0; 174 175 /** 176 * Only used if the {@link #channelWidth} is 80 + 80 MHz. If the Responder uses 80 + 80 MHz, 177 * this is the center frequency of the second segment (in MHz). 178 */ 179 public final int centerFreq1; 180 181 /** 182 * The preamble used by the Responder, specified using {@link PreambleType}. 183 */ 184 public final int preamble; 185 186 /** 187 * Constructs Responder configuration, using a MAC address to identify the Responder. 188 * 189 * @param macAddress The MAC address of the Responder. 190 * @param responderType The type of the responder device, specified using 191 * {@link ResponderType}. 192 * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. 193 * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. 194 * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. 195 * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses 196 * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the 197 * Responder uses 80 + 80 MHz, this is the center frequency of the first 198 * segment (in MHz). 199 * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the 200 * Responder 201 * uses 80 + 80 MHz, this is the center frequency of the second segment 202 * (in 203 * MHz). 204 * @param preamble The preamble used by the Responder, specified using 205 * {@link PreambleType}. 206 */ ResponderConfig(@onNull MacAddress macAddress, @ResponderType int responderType, boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1, @PreambleType int preamble)207 public ResponderConfig(@NonNull MacAddress macAddress, @ResponderType int responderType, 208 boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, 209 int centerFreq1, @PreambleType int preamble) { 210 if (macAddress == null) { 211 throw new IllegalArgumentException( 212 "Invalid ResponderConfig - must specify a MAC address"); 213 } 214 this.macAddress = macAddress; 215 this.peerHandle = null; 216 this.responderType = responderType; 217 this.supports80211mc = supports80211mc; 218 this.channelWidth = channelWidth; 219 this.frequency = frequency; 220 this.centerFreq0 = centerFreq0; 221 this.centerFreq1 = centerFreq1; 222 this.preamble = preamble; 223 } 224 225 /** 226 * Constructs Responder configuration, using a Wi-Fi Aware PeerHandle to identify the Responder. 227 * 228 * @param peerHandle The Wi-Fi Aware peer identifier of the Responder. 229 * @param responderType The type of the responder device, specified using 230 * {@link ResponderType}. 231 * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. 232 * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. 233 * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. 234 * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses 235 * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the 236 * Responder uses 80 + 80 MHz, this is the center frequency of the first 237 * segment (in MHz). 238 * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the 239 * Responder 240 * uses 80 + 80 MHz, this is the center frequency of the second segment 241 * (in 242 * MHz). 243 * @param preamble The preamble used by the Responder, specified using 244 * {@link PreambleType}. 245 */ ResponderConfig(@onNull PeerHandle peerHandle, @ResponderType int responderType, boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1, @PreambleType int preamble)246 public ResponderConfig(@NonNull PeerHandle peerHandle, @ResponderType int responderType, 247 boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, 248 int centerFreq1, @PreambleType int preamble) { 249 this.macAddress = null; 250 this.peerHandle = peerHandle; 251 this.responderType = responderType; 252 this.supports80211mc = supports80211mc; 253 this.channelWidth = channelWidth; 254 this.frequency = frequency; 255 this.centerFreq0 = centerFreq0; 256 this.centerFreq1 = centerFreq1; 257 this.preamble = preamble; 258 } 259 260 /** 261 * Constructs Responder configuration. This is an internal-only constructor which specifies both 262 * a MAC address and a Wi-Fi PeerHandle to identify the Responder. 263 * 264 * @param macAddress The MAC address of the Responder. 265 * @param peerHandle The Wi-Fi Aware peer identifier of the Responder. 266 * @param responderType The type of the responder device, specified using 267 * {@link ResponderType}. 268 * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. 269 * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. 270 * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. 271 * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses 272 * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the 273 * Responder uses 80 + 80 MHz, this is the center frequency of the first 274 * segment (in MHz). 275 * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the 276 * Responder 277 * uses 80 + 80 MHz, this is the center frequency of the second segment 278 * (in 279 * MHz). 280 * @param preamble The preamble used by the Responder, specified using 281 * {@link PreambleType}. 282 * @hide 283 */ ResponderConfig(@onNull MacAddress macAddress, @NonNull PeerHandle peerHandle, @ResponderType int responderType, boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1, @PreambleType int preamble)284 public ResponderConfig(@NonNull MacAddress macAddress, @NonNull PeerHandle peerHandle, 285 @ResponderType int responderType, boolean supports80211mc, 286 @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1, 287 @PreambleType int preamble) { 288 this.macAddress = macAddress; 289 this.peerHandle = peerHandle; 290 this.responderType = responderType; 291 this.supports80211mc = supports80211mc; 292 this.channelWidth = channelWidth; 293 this.frequency = frequency; 294 this.centerFreq0 = centerFreq0; 295 this.centerFreq1 = centerFreq1; 296 this.preamble = preamble; 297 } 298 299 /** 300 * Creates a Responder configuration from a {@link ScanResult} corresponding to an Access 301 * Point (AP), which can be obtained from {@link android.net.wifi.WifiManager#getScanResults()}. 302 */ fromScanResult(ScanResult scanResult)303 public static ResponderConfig fromScanResult(ScanResult scanResult) { 304 MacAddress macAddress = MacAddress.fromString(scanResult.BSSID); 305 int responderType = RESPONDER_AP; 306 boolean supports80211mc = scanResult.is80211mcResponder(); 307 int channelWidth = translateScanResultChannelWidth(scanResult.channelWidth); 308 int frequency = scanResult.frequency; 309 int centerFreq0 = scanResult.centerFreq0; 310 int centerFreq1 = scanResult.centerFreq1; 311 312 int preamble; 313 if (scanResult.informationElements != null && scanResult.informationElements.length != 0) { 314 boolean htCapabilitiesPresent = false; 315 boolean vhtCapabilitiesPresent = false; 316 boolean heCapabilitiesPresent = false; 317 318 for (ScanResult.InformationElement ie : scanResult.informationElements) { 319 if (ie.id == EID_HT_CAPABILITIES) { 320 htCapabilitiesPresent = true; 321 } else if (ie.id == EID_VHT_CAPABILITIES) { 322 vhtCapabilitiesPresent = true; 323 } else if (ie.id == EID_EXTENSION_PRESENT && ie.idExt == EID_EXT_HE_CAPABILITIES) { 324 heCapabilitiesPresent = true; 325 } 326 } 327 328 if (heCapabilitiesPresent && ScanResult.is6GHz(frequency)) { 329 preamble = PREAMBLE_HE; 330 } else if (vhtCapabilitiesPresent) { 331 preamble = PREAMBLE_VHT; 332 } else if (htCapabilitiesPresent) { 333 preamble = PREAMBLE_HT; 334 } else { 335 preamble = PREAMBLE_LEGACY; 336 } 337 } else { 338 Log.e(TAG, "Scan Results do not contain IEs - using backup method to select preamble"); 339 if (channelWidth == CHANNEL_WIDTH_80MHZ || channelWidth == CHANNEL_WIDTH_160MHZ) { 340 preamble = PREAMBLE_VHT; 341 } else { 342 preamble = PREAMBLE_HT; 343 } 344 } 345 346 return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, 347 frequency, centerFreq0, centerFreq1, preamble); 348 } 349 350 /** 351 * Creates a Responder configuration from a MAC address corresponding to a Wi-Fi Aware 352 * Responder. The Responder parameters are set to defaults. 353 */ fromWifiAwarePeerMacAddressWithDefaults(MacAddress macAddress)354 public static ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(MacAddress macAddress) { 355 /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder 356 * is expected to be brought up and available to negotiate a maximum accuracy channel 357 * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware 358 * Unsolicited Publisher with Ranging enabled. 359 */ 360 return new ResponderConfig(macAddress, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, 361 AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); 362 } 363 364 /** 365 * Creates a Responder configuration from a {@link PeerHandle} corresponding to a Wi-Fi Aware 366 * Responder. The Responder parameters are set to defaults. 367 */ fromWifiAwarePeerHandleWithDefaults(PeerHandle peerHandle)368 public static ResponderConfig fromWifiAwarePeerHandleWithDefaults(PeerHandle peerHandle) { 369 /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder 370 * is expected to be brought up and available to negotiate a maximum accuracy channel 371 * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware 372 * Unsolicited Publisher with Ranging enabled. 373 */ 374 return new ResponderConfig(peerHandle, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, 375 AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); 376 } 377 378 /** 379 * Check whether the Responder configuration is valid. 380 * 381 * @return true if valid, false otherwise. 382 * @hide 383 */ isValid(boolean awareSupported)384 public boolean isValid(boolean awareSupported) { 385 if (macAddress == null && peerHandle == null || macAddress != null && peerHandle != null) { 386 return false; 387 } 388 if (!awareSupported && responderType == RESPONDER_AWARE) { 389 return false; 390 } 391 392 return true; 393 } 394 395 @Override describeContents()396 public int describeContents() { 397 return 0; 398 } 399 400 @Override writeToParcel(Parcel dest, int flags)401 public void writeToParcel(Parcel dest, int flags) { 402 if (macAddress == null) { 403 dest.writeBoolean(false); 404 } else { 405 dest.writeBoolean(true); 406 macAddress.writeToParcel(dest, flags); 407 } 408 if (peerHandle == null) { 409 dest.writeBoolean(false); 410 } else { 411 dest.writeBoolean(true); 412 dest.writeInt(peerHandle.peerId); 413 } 414 dest.writeInt(responderType); 415 dest.writeInt(supports80211mc ? 1 : 0); 416 dest.writeInt(channelWidth); 417 dest.writeInt(frequency); 418 dest.writeInt(centerFreq0); 419 dest.writeInt(centerFreq1); 420 dest.writeInt(preamble); 421 } 422 423 public static final @android.annotation.NonNull Creator<ResponderConfig> CREATOR = new Creator<ResponderConfig>() { 424 @Override 425 public ResponderConfig[] newArray(int size) { 426 return new ResponderConfig[size]; 427 } 428 429 @Override 430 public ResponderConfig createFromParcel(Parcel in) { 431 boolean macAddressPresent = in.readBoolean(); 432 MacAddress macAddress = null; 433 if (macAddressPresent) { 434 macAddress = MacAddress.CREATOR.createFromParcel(in); 435 } 436 boolean peerHandlePresent = in.readBoolean(); 437 PeerHandle peerHandle = null; 438 if (peerHandlePresent) { 439 peerHandle = new PeerHandle(in.readInt()); 440 } 441 int responderType = in.readInt(); 442 boolean supports80211mc = in.readInt() == 1; 443 int channelWidth = in.readInt(); 444 int frequency = in.readInt(); 445 int centerFreq0 = in.readInt(); 446 int centerFreq1 = in.readInt(); 447 int preamble = in.readInt(); 448 449 if (peerHandle == null) { 450 return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, 451 frequency, centerFreq0, centerFreq1, preamble); 452 } else { 453 return new ResponderConfig(peerHandle, responderType, supports80211mc, channelWidth, 454 frequency, centerFreq0, centerFreq1, preamble); 455 } 456 } 457 }; 458 459 @Override equals(@ullable Object o)460 public boolean equals(@Nullable Object o) { 461 if (this == o) { 462 return true; 463 } 464 465 if (!(o instanceof ResponderConfig)) { 466 return false; 467 } 468 469 ResponderConfig lhs = (ResponderConfig) o; 470 471 return Objects.equals(macAddress, lhs.macAddress) && Objects.equals(peerHandle, 472 lhs.peerHandle) && responderType == lhs.responderType 473 && supports80211mc == lhs.supports80211mc && channelWidth == lhs.channelWidth 474 && frequency == lhs.frequency && centerFreq0 == lhs.centerFreq0 475 && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble; 476 } 477 478 @Override hashCode()479 public int hashCode() { 480 return Objects.hash(macAddress, peerHandle, responderType, supports80211mc, channelWidth, 481 frequency, centerFreq0, centerFreq1, preamble); 482 } 483 484 /** @hide */ 485 @Override toString()486 public String toString() { 487 return new StringBuffer("ResponderConfig: macAddress=").append(macAddress).append( 488 ", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId).append( 489 ", responderType=").append(responderType).append(", supports80211mc=").append( 490 supports80211mc).append(", channelWidth=").append(channelWidth).append( 491 ", frequency=").append(frequency).append(", centerFreq0=").append( 492 centerFreq0).append(", centerFreq1=").append(centerFreq1).append( 493 ", preamble=").append(preamble).toString(); 494 } 495 496 /** @hide */ translateScanResultChannelWidth(int scanResultChannelWidth)497 static int translateScanResultChannelWidth(int scanResultChannelWidth) { 498 switch (scanResultChannelWidth) { 499 case ScanResult.CHANNEL_WIDTH_20MHZ: 500 return CHANNEL_WIDTH_20MHZ; 501 case ScanResult.CHANNEL_WIDTH_40MHZ: 502 return CHANNEL_WIDTH_40MHZ; 503 case ScanResult.CHANNEL_WIDTH_80MHZ: 504 return CHANNEL_WIDTH_80MHZ; 505 case ScanResult.CHANNEL_WIDTH_160MHZ: 506 return CHANNEL_WIDTH_160MHZ; 507 case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: 508 return CHANNEL_WIDTH_80MHZ_PLUS_MHZ; 509 default: 510 throw new IllegalArgumentException( 511 "translateScanResultChannelWidth: bad " + scanResultChannelWidth); 512 } 513 } 514 } 515