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