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