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