• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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