| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.wifi.rtt; |
| |
| import static android.net.wifi.ScanResult.InformationElement.EID_HT_CAPABILITIES; |
| import static android.net.wifi.ScanResult.InformationElement.EID_VHT_CAPABILITIES; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.SystemApi; |
| import android.net.MacAddress; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.aware.PeerHandle; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.util.Log; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.Objects; |
| |
| /** |
| * Defines the configuration of an IEEE 802.11mc Responder. The Responder may be an Access Point |
| * (AP), a Wi-Fi Aware device, or a manually configured Responder. |
| * <p> |
| * A Responder configuration may be constructed from a {@link ScanResult} or manually (with the |
| * data obtained out-of-band from a peer). |
| * |
| * @hide |
| */ |
| @SystemApi |
| public final class ResponderConfig implements Parcelable { |
| private static final String TAG = "ResponderConfig"; |
| private static final int AWARE_BAND_2_DISCOVERY_CHANNEL = 2437; |
| |
| /** @hide */ |
| @IntDef({RESPONDER_AP, RESPONDER_STA, RESPONDER_P2P_GO, RESPONDER_P2P_CLIENT, RESPONDER_AWARE}) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface ResponderType { |
| } |
| |
| /** |
| * Responder is an AP. |
| */ |
| public static final int RESPONDER_AP = 0; |
| /** |
| * Responder is a STA. |
| */ |
| public static final int RESPONDER_STA = 1; |
| /** |
| * Responder is a Wi-Fi Direct Group Owner (GO). |
| */ |
| public static final int RESPONDER_P2P_GO = 2; |
| /** |
| * Responder is a Wi-Fi Direct Group Client. |
| */ |
| public static final int RESPONDER_P2P_CLIENT = 3; |
| /** |
| * Responder is a Wi-Fi Aware device. |
| */ |
| public static final int RESPONDER_AWARE = 4; |
| |
| |
| /** @hide */ |
| @IntDef({ |
| CHANNEL_WIDTH_20MHZ, CHANNEL_WIDTH_40MHZ, CHANNEL_WIDTH_80MHZ, CHANNEL_WIDTH_160MHZ, |
| CHANNEL_WIDTH_80MHZ_PLUS_MHZ}) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface ChannelWidth { |
| } |
| |
| /** |
| * Channel bandwidth is 20 MHZ |
| */ |
| public static final int CHANNEL_WIDTH_20MHZ = 0; |
| /** |
| * Channel bandwidth is 40 MHZ |
| */ |
| public static final int CHANNEL_WIDTH_40MHZ = 1; |
| /** |
| * Channel bandwidth is 80 MHZ |
| */ |
| public static final int CHANNEL_WIDTH_80MHZ = 2; |
| /** |
| * Channel bandwidth is 160 MHZ |
| */ |
| public static final int CHANNEL_WIDTH_160MHZ = 3; |
| /** |
| * Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ |
| */ |
| public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; |
| |
| /** @hide */ |
| @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT}) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface PreambleType { |
| } |
| |
| /** |
| * Preamble type: Legacy. |
| */ |
| public static final int PREAMBLE_LEGACY = 0; |
| |
| /** |
| * Preamble type: HT. |
| */ |
| public static final int PREAMBLE_HT = 1; |
| |
| /** |
| * Preamble type: VHT. |
| */ |
| public static final int PREAMBLE_VHT = 2; |
| |
| |
| /** |
| * The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the |
| * peerHandle field) ise used to identify the Responder. |
| */ |
| public final MacAddress macAddress; |
| |
| /** |
| * The peer identifier of a Wi-Fi Aware Responder. Will be null if a MAC Address (the macAddress |
| * field) is used to identify the Responder. |
| */ |
| public final PeerHandle peerHandle; |
| |
| /** |
| * The device type of the Responder. |
| */ |
| public final int responderType; |
| |
| /** |
| * Indicates whether the Responder device supports IEEE 802.11mc. |
| */ |
| public final boolean supports80211mc; |
| |
| /** |
| * Responder channel bandwidth, specified using {@link ChannelWidth}. |
| */ |
| public final int channelWidth; |
| |
| /** |
| * The primary 20 MHz frequency (in MHz) of the channel of the Responder. |
| */ |
| public final int frequency; |
| |
| /** |
| * Not used if the {@link #channelWidth} is 20 MHz. If the Responder uses 40, 80 or 160 MHz, |
| * this is the center frequency (in MHz), if the Responder uses 80 + 80 MHz, this is the |
| * center frequency of the first segment (in MHz). |
| */ |
| public final int centerFreq0; |
| |
| /** |
| * Only used if the {@link #channelWidth} is 80 + 80 MHz. If the Responder uses 80 + 80 MHz, |
| * this is the center frequency of the second segment (in MHz). |
| */ |
| public final int centerFreq1; |
| |
| /** |
| * The preamble used by the Responder, specified using {@link PreambleType}. |
| */ |
| public final int preamble; |
| |
| /** |
| * Constructs Responder configuration, using a MAC address to identify the Responder. |
| * |
| * @param macAddress The MAC address of the Responder. |
| * @param responderType The type of the responder device, specified using |
| * {@link ResponderType}. |
| * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. |
| * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. |
| * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. |
| * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses |
| * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the |
| * Responder uses 80 + 80 MHz, this is the center frequency of the first |
| * segment (in MHz). |
| * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the |
| * Responder |
| * uses 80 + 80 MHz, this is the center frequency of the second segment |
| * (in |
| * MHz). |
| * @param preamble The preamble used by the Responder, specified using |
| * {@link PreambleType}. |
| */ |
| public ResponderConfig(@NonNull MacAddress macAddress, @ResponderType int responderType, |
| boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, |
| int centerFreq1, @PreambleType int preamble) { |
| if (macAddress == null) { |
| throw new IllegalArgumentException( |
| "Invalid ResponderConfig - must specify a MAC address"); |
| } |
| this.macAddress = macAddress; |
| this.peerHandle = null; |
| this.responderType = responderType; |
| this.supports80211mc = supports80211mc; |
| this.channelWidth = channelWidth; |
| this.frequency = frequency; |
| this.centerFreq0 = centerFreq0; |
| this.centerFreq1 = centerFreq1; |
| this.preamble = preamble; |
| } |
| |
| /** |
| * Constructs Responder configuration, using a Wi-Fi Aware PeerHandle to identify the Responder. |
| * |
| * @param peerHandle The Wi-Fi Aware peer identifier of the Responder. |
| * @param responderType The type of the responder device, specified using |
| * {@link ResponderType}. |
| * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. |
| * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. |
| * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. |
| * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses |
| * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the |
| * Responder uses 80 + 80 MHz, this is the center frequency of the first |
| * segment (in MHz). |
| * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the |
| * Responder |
| * uses 80 + 80 MHz, this is the center frequency of the second segment |
| * (in |
| * MHz). |
| * @param preamble The preamble used by the Responder, specified using |
| * {@link PreambleType}. |
| */ |
| public ResponderConfig(@NonNull PeerHandle peerHandle, @ResponderType int responderType, |
| boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, |
| int centerFreq1, @PreambleType int preamble) { |
| this.macAddress = null; |
| this.peerHandle = peerHandle; |
| this.responderType = responderType; |
| this.supports80211mc = supports80211mc; |
| this.channelWidth = channelWidth; |
| this.frequency = frequency; |
| this.centerFreq0 = centerFreq0; |
| this.centerFreq1 = centerFreq1; |
| this.preamble = preamble; |
| } |
| |
| /** |
| * Constructs Responder configuration. This is an internal-only constructor which specifies both |
| * a MAC address and a Wi-Fi PeerHandle to identify the Responder. |
| * |
| * @param macAddress The MAC address of the Responder. |
| * @param peerHandle The Wi-Fi Aware peer identifier of the Responder. |
| * @param responderType The type of the responder device, specified using |
| * {@link ResponderType}. |
| * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. |
| * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. |
| * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. |
| * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses |
| * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the |
| * Responder uses 80 + 80 MHz, this is the center frequency of the first |
| * segment (in MHz). |
| * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the |
| * Responder |
| * uses 80 + 80 MHz, this is the center frequency of the second segment |
| * (in |
| * MHz). |
| * @param preamble The preamble used by the Responder, specified using |
| * {@link PreambleType}. |
| * @hide |
| */ |
| public ResponderConfig(@NonNull MacAddress macAddress, @NonNull PeerHandle peerHandle, |
| @ResponderType int responderType, boolean supports80211mc, |
| @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1, |
| @PreambleType int preamble) { |
| this.macAddress = macAddress; |
| this.peerHandle = peerHandle; |
| this.responderType = responderType; |
| this.supports80211mc = supports80211mc; |
| this.channelWidth = channelWidth; |
| this.frequency = frequency; |
| this.centerFreq0 = centerFreq0; |
| this.centerFreq1 = centerFreq1; |
| this.preamble = preamble; |
| } |
| |
| /** |
| * Creates a Responder configuration from a {@link ScanResult} corresponding to an Access |
| * Point (AP), which can be obtained from {@link android.net.wifi.WifiManager#getScanResults()}. |
| */ |
| public static ResponderConfig fromScanResult(ScanResult scanResult) { |
| MacAddress macAddress = MacAddress.fromString(scanResult.BSSID); |
| int responderType = RESPONDER_AP; |
| boolean supports80211mc = scanResult.is80211mcResponder(); |
| int channelWidth = translateScanResultChannelWidth(scanResult.channelWidth); |
| int frequency = scanResult.frequency; |
| int centerFreq0 = scanResult.centerFreq0; |
| int centerFreq1 = scanResult.centerFreq1; |
| |
| int preamble; |
| if (scanResult.informationElements != null && scanResult.informationElements.length != 0) { |
| boolean htCapabilitiesPresent = false; |
| boolean vhtCapabilitiesPresent = false; |
| for (ScanResult.InformationElement ie : scanResult.informationElements) { |
| if (ie.id == EID_HT_CAPABILITIES) { |
| htCapabilitiesPresent = true; |
| } else if (ie.id == EID_VHT_CAPABILITIES) { |
| vhtCapabilitiesPresent = true; |
| } |
| } |
| if (vhtCapabilitiesPresent) { |
| preamble = PREAMBLE_VHT; |
| } else if (htCapabilitiesPresent) { |
| preamble = PREAMBLE_HT; |
| } else { |
| preamble = PREAMBLE_LEGACY; |
| } |
| } else { |
| Log.e(TAG, "Scan Results do not contain IEs - using backup method to select preamble"); |
| if (channelWidth == CHANNEL_WIDTH_80MHZ || channelWidth == CHANNEL_WIDTH_160MHZ) { |
| preamble = PREAMBLE_VHT; |
| } else { |
| preamble = PREAMBLE_HT; |
| } |
| } |
| |
| return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, |
| frequency, centerFreq0, centerFreq1, preamble); |
| } |
| |
| /** |
| * Creates a Responder configuration from a MAC address corresponding to a Wi-Fi Aware |
| * Responder. The Responder parameters are set to defaults. |
| */ |
| public static ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(MacAddress macAddress) { |
| /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder |
| * is expected to be brought up and available to negotiate a maximum accuracy channel |
| * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware |
| * Unsolicited Publisher with Ranging enabled. |
| */ |
| return new ResponderConfig(macAddress, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, |
| AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); |
| } |
| |
| /** |
| * Creates a Responder configuration from a {@link PeerHandle} corresponding to a Wi-Fi Aware |
| * Responder. The Responder parameters are set to defaults. |
| */ |
| public static ResponderConfig fromWifiAwarePeerHandleWithDefaults(PeerHandle peerHandle) { |
| /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder |
| * is expected to be brought up and available to negotiate a maximum accuracy channel |
| * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware |
| * Unsolicited Publisher with Ranging enabled. |
| */ |
| return new ResponderConfig(peerHandle, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, |
| AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); |
| } |
| |
| /** |
| * Check whether the Responder configuration is valid. |
| * |
| * @return true if valid, false otherwise. |
| * @hide |
| */ |
| public boolean isValid(boolean awareSupported) { |
| if (macAddress == null && peerHandle == null || macAddress != null && peerHandle != null) { |
| return false; |
| } |
| if (!awareSupported && responderType == RESPONDER_AWARE) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| if (macAddress == null) { |
| dest.writeBoolean(false); |
| } else { |
| dest.writeBoolean(true); |
| macAddress.writeToParcel(dest, flags); |
| } |
| if (peerHandle == null) { |
| dest.writeBoolean(false); |
| } else { |
| dest.writeBoolean(true); |
| dest.writeInt(peerHandle.peerId); |
| } |
| dest.writeInt(responderType); |
| dest.writeInt(supports80211mc ? 1 : 0); |
| dest.writeInt(channelWidth); |
| dest.writeInt(frequency); |
| dest.writeInt(centerFreq0); |
| dest.writeInt(centerFreq1); |
| dest.writeInt(preamble); |
| } |
| |
| public static final Creator<ResponderConfig> CREATOR = new Creator<ResponderConfig>() { |
| @Override |
| public ResponderConfig[] newArray(int size) { |
| return new ResponderConfig[size]; |
| } |
| |
| @Override |
| public ResponderConfig createFromParcel(Parcel in) { |
| boolean macAddressPresent = in.readBoolean(); |
| MacAddress macAddress = null; |
| if (macAddressPresent) { |
| macAddress = MacAddress.CREATOR.createFromParcel(in); |
| } |
| boolean peerHandlePresent = in.readBoolean(); |
| PeerHandle peerHandle = null; |
| if (peerHandlePresent) { |
| peerHandle = new PeerHandle(in.readInt()); |
| } |
| int responderType = in.readInt(); |
| boolean supports80211mc = in.readInt() == 1; |
| int channelWidth = in.readInt(); |
| int frequency = in.readInt(); |
| int centerFreq0 = in.readInt(); |
| int centerFreq1 = in.readInt(); |
| int preamble = in.readInt(); |
| |
| if (peerHandle == null) { |
| return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, |
| frequency, centerFreq0, centerFreq1, preamble); |
| } else { |
| return new ResponderConfig(peerHandle, responderType, supports80211mc, channelWidth, |
| frequency, centerFreq0, centerFreq1, preamble); |
| } |
| } |
| }; |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| |
| if (!(o instanceof ResponderConfig)) { |
| return false; |
| } |
| |
| ResponderConfig lhs = (ResponderConfig) o; |
| |
| return Objects.equals(macAddress, lhs.macAddress) && Objects.equals(peerHandle, |
| lhs.peerHandle) && responderType == lhs.responderType |
| && supports80211mc == lhs.supports80211mc && channelWidth == lhs.channelWidth |
| && frequency == lhs.frequency && centerFreq0 == lhs.centerFreq0 |
| && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble; |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(macAddress, peerHandle, responderType, supports80211mc, channelWidth, |
| frequency, centerFreq0, centerFreq1, preamble); |
| } |
| |
| /** @hide */ |
| @Override |
| public String toString() { |
| return new StringBuffer("ResponderConfig: macAddress=").append(macAddress).append( |
| ", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId).append( |
| ", responderType=").append(responderType).append(", supports80211mc=").append( |
| supports80211mc).append(", channelWidth=").append(channelWidth).append( |
| ", frequency=").append(frequency).append(", centerFreq0=").append( |
| centerFreq0).append(", centerFreq1=").append(centerFreq1).append( |
| ", preamble=").append(preamble).toString(); |
| } |
| |
| /** @hide */ |
| static int translateScanResultChannelWidth(int scanResultChannelWidth) { |
| switch (scanResultChannelWidth) { |
| case ScanResult.CHANNEL_WIDTH_20MHZ: |
| return CHANNEL_WIDTH_20MHZ; |
| case ScanResult.CHANNEL_WIDTH_40MHZ: |
| return CHANNEL_WIDTH_40MHZ; |
| case ScanResult.CHANNEL_WIDTH_80MHZ: |
| return CHANNEL_WIDTH_80MHZ; |
| case ScanResult.CHANNEL_WIDTH_160MHZ: |
| return CHANNEL_WIDTH_160MHZ; |
| case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: |
| return CHANNEL_WIDTH_80MHZ_PLUS_MHZ; |
| default: |
| throw new IllegalArgumentException( |
| "translateScanResultChannelWidth: bad " + scanResultChannelWidth); |
| } |
| } |
| } |