• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.server.wifi.hotspot2;
2 
3 import android.net.MacAddress;
4 import android.net.wifi.MloLink;
5 import android.net.wifi.ScanResult;
6 import android.util.Log;
7 
8 import com.android.server.wifi.hotspot2.anqp.ANQPElement;
9 import com.android.server.wifi.hotspot2.anqp.Constants;
10 import com.android.server.wifi.hotspot2.anqp.RawByteElement;
11 import com.android.server.wifi.util.InformationElementUtil;
12 
13 import java.nio.BufferUnderflowException;
14 import java.nio.ByteBuffer;
15 import java.nio.CharBuffer;
16 import java.nio.charset.CharacterCodingException;
17 import java.nio.charset.CharsetDecoder;
18 import java.nio.charset.StandardCharsets;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 
24 public class NetworkDetail {
25 
26     private static final boolean DBG = false;
27 
28     private static final String TAG = "NetworkDetail";
29 
30     public enum Ant {
31         Private,
32         PrivateWithGuest,
33         ChargeablePublic,
34         FreePublic,
35         Personal,
36         EmergencyOnly,
37         Resvd6,
38         Resvd7,
39         Resvd8,
40         Resvd9,
41         Resvd10,
42         Resvd11,
43         Resvd12,
44         Resvd13,
45         TestOrExperimental,
46         Wildcard
47     }
48 
49     public enum HSRelease {
50         R1,
51         R2,
52         R3,
53         Unknown
54     }
55 
56     // General identifiers:
57     private final String mSSID;
58     private final long mHESSID;
59     private final long mBSSID;
60     // True if the SSID is potentially from a hidden network
61     private final boolean mIsHiddenSsid;
62 
63     // BSS Load element:
64     private final int mStationCount;
65     private final int mChannelUtilization;
66     private final int mCapacity;
67 
68     //channel detailed information
69    /*
70     * 0 -- 20 MHz
71     * 1 -- 40 MHz
72     * 2 -- 80 MHz
73     * 3 -- 160 MHz
74     * 4 -- 80 + 80 MHz
75     */
76     private final int mChannelWidth;
77     private final int mPrimaryFreq;
78     private final int mCenterfreq0;
79     private final int mCenterfreq1;
80 
81     /*
82      * 802.11 Standard (calculated from Capabilities and Supported Rates)
83      * 0 -- Unknown
84      * 1 -- 802.11a
85      * 2 -- 802.11b
86      * 3 -- 802.11g
87      * 4 -- 802.11n
88      * 7 -- 802.11ac
89      */
90     private final int mWifiMode;
91     private final int mMaxRate;
92     private final int mMaxNumberSpatialStreams;
93 
94     /*
95      * From Interworking element:
96      * mAnt non null indicates the presence of Interworking, i.e. 802.11u
97      */
98     private final Ant mAnt;
99     private final boolean mInternet;
100 
101     /*
102      * From HS20 Indication element:
103      * mHSRelease is null only if the HS20 Indication element was not present.
104      * mAnqpDomainID is set to -1 if not present in the element.
105      */
106     private final HSRelease mHSRelease;
107     private final int mAnqpDomainID;
108 
109     /*
110      * From beacon:
111      * mAnqpOICount is how many additional OIs are available through ANQP.
112      * mRoamingConsortiums is either null, if the element was not present, or is an array of
113      * 1, 2 or 3 longs in which the roaming consortium values occupy the LSBs.
114      */
115     private final int mAnqpOICount;
116     private final long[] mRoamingConsortiums;
117     private int mDtimInterval = -1;
118     private String mCountryCode;
119 
120     private final InformationElementUtil.ExtendedCapabilities mExtendedCapabilities;
121 
122     private final Map<Constants.ANQPElementType, ANQPElement> mANQPElements;
123 
124     /*
125      * From Wi-Fi Alliance MBO-OCE Information element.
126      * mMboAssociationDisallowedReasonCode is the reason code for AP not accepting new connections
127      * and is set to -1 if association disallowed attribute is not present in the element.
128      */
129     private final int mMboAssociationDisallowedReasonCode;
130     private final boolean mMboSupported;
131     private final boolean mMboCellularDataAware;
132     private final boolean mOceSupported;
133 
134     // MLO Attributes
135     private MacAddress mMldMacAddress = null;
136     private int mMloLinkId = MloLink.INVALID_MLO_LINK_ID;
137     private List<MloLink> mAffiliatedMloLinks = Collections.emptyList();
138 
NetworkDetail(String bssid, ScanResult.InformationElement[] infoElements, List<String> anqpLines, int freq)139     public NetworkDetail(String bssid, ScanResult.InformationElement[] infoElements,
140             List<String> anqpLines, int freq) {
141         if (infoElements == null) {
142             infoElements = new ScanResult.InformationElement[0];
143         }
144 
145         mBSSID = Utils.parseMac(bssid);
146 
147         String ssid = null;
148         boolean isHiddenSsid = false;
149         byte[] ssidOctets = null;
150 
151         InformationElementUtil.BssLoad bssLoad = new InformationElementUtil.BssLoad();
152 
153         InformationElementUtil.Interworking interworking =
154                 new InformationElementUtil.Interworking();
155 
156         InformationElementUtil.RoamingConsortium roamingConsortium =
157                 new InformationElementUtil.RoamingConsortium();
158 
159         InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
160 
161         InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation();
162         InformationElementUtil.VhtOperation vhtOperation =
163                 new InformationElementUtil.VhtOperation();
164         InformationElementUtil.HeOperation heOperation = new InformationElementUtil.HeOperation();
165         InformationElementUtil.EhtOperation ehtOperation =
166                 new InformationElementUtil.EhtOperation();
167 
168         InformationElementUtil.HtCapabilities htCapabilities =
169                 new InformationElementUtil.HtCapabilities();
170         InformationElementUtil.VhtCapabilities vhtCapabilities =
171                 new InformationElementUtil.VhtCapabilities();
172         InformationElementUtil.HeCapabilities heCapabilities =
173                 new InformationElementUtil.HeCapabilities();
174         InformationElementUtil.EhtCapabilities ehtCapabilities =
175                 new InformationElementUtil.EhtCapabilities();
176         InformationElementUtil.Rnr rnr =
177                 new InformationElementUtil.Rnr();
178         InformationElementUtil.MultiLink multiLink =
179                 new InformationElementUtil.MultiLink();
180         InformationElementUtil.ExtendedCapabilities extendedCapabilities =
181                 new InformationElementUtil.ExtendedCapabilities();
182 
183         InformationElementUtil.Country country =
184                 new InformationElementUtil.Country();
185 
186         InformationElementUtil.TrafficIndicationMap trafficIndicationMap =
187                 new InformationElementUtil.TrafficIndicationMap();
188 
189         InformationElementUtil.SupportedRates supportedRates =
190                 new InformationElementUtil.SupportedRates();
191         InformationElementUtil.SupportedRates extendedSupportedRates =
192                 new InformationElementUtil.SupportedRates();
193 
194         RuntimeException exception = null;
195 
196         ArrayList<Integer> iesFound = new ArrayList<Integer>();
197         try {
198             for (ScanResult.InformationElement ie : infoElements) {
199                 iesFound.add(ie.id);
200                 switch (ie.id) {
201                     case ScanResult.InformationElement.EID_SSID:
202                         ssidOctets = ie.bytes;
203                         break;
204                     case ScanResult.InformationElement.EID_BSS_LOAD:
205                         bssLoad.from(ie);
206                         break;
207                     case ScanResult.InformationElement.EID_HT_OPERATION:
208                         htOperation.from(ie);
209                         break;
210                     case ScanResult.InformationElement.EID_VHT_OPERATION:
211                         vhtOperation.from(ie);
212                         break;
213                     case ScanResult.InformationElement.EID_HT_CAPABILITIES:
214                         htCapabilities.from(ie);
215                         break;
216                     case ScanResult.InformationElement.EID_VHT_CAPABILITIES:
217                         vhtCapabilities.from(ie);
218                         break;
219                     case ScanResult.InformationElement.EID_INTERWORKING:
220                         interworking.from(ie);
221                         break;
222                     case ScanResult.InformationElement.EID_ROAMING_CONSORTIUM:
223                         roamingConsortium.from(ie);
224                         break;
225                     case ScanResult.InformationElement.EID_VSA:
226                         vsa.from(ie);
227                         break;
228                     case ScanResult.InformationElement.EID_EXTENDED_CAPS:
229                         extendedCapabilities.from(ie);
230                         break;
231                     case ScanResult.InformationElement.EID_COUNTRY:
232                         country.from(ie);
233                         break;
234                     case ScanResult.InformationElement.EID_TIM:
235                         trafficIndicationMap.from(ie);
236                         break;
237                     case ScanResult.InformationElement.EID_SUPPORTED_RATES:
238                         supportedRates.from(ie);
239                         break;
240                     case ScanResult.InformationElement.EID_EXTENDED_SUPPORTED_RATES:
241                         extendedSupportedRates.from(ie);
242                         break;
243                     case ScanResult.InformationElement.EID_RNR:
244                         rnr.from(ie);
245                         break;
246                     case ScanResult.InformationElement.EID_EXTENSION_PRESENT:
247                         switch(ie.idExt) {
248                             case ScanResult.InformationElement.EID_EXT_HE_OPERATION:
249                                 heOperation.from(ie);
250                                 break;
251                             case ScanResult.InformationElement.EID_EXT_HE_CAPABILITIES:
252                                 heCapabilities.from(ie);
253                                 break;
254                             case ScanResult.InformationElement.EID_EXT_EHT_OPERATION:
255                                 ehtOperation.from(ie);
256                                 break;
257                             case ScanResult.InformationElement.EID_EXT_EHT_CAPABILITIES:
258                                 ehtCapabilities.from(ie);
259                                 break;
260                             case ScanResult.InformationElement.EID_EXT_MULTI_LINK:
261                                 multiLink.from(ie);
262                                 break;
263                             default:
264                                 break;
265                         }
266                         break;
267                     default:
268                         break;
269                 }
270             }
271         }
272         catch (IllegalArgumentException | BufferUnderflowException | ArrayIndexOutOfBoundsException e) {
273             Log.d(Utils.hs2LogTag(getClass()), "Caught " + e);
274             if (ssidOctets == null) {
275                 throw new IllegalArgumentException("Malformed IE string (no SSID)", e);
276             }
277             exception = e;
278         }
279         if (ssidOctets != null) {
280             /*
281              * Strict use of the "UTF-8 SSID" bit by APs appears to be spotty at best even if the
282              * encoding truly is in UTF-8. An unconditional attempt to decode the SSID as UTF-8 is
283              * therefore always made with a fall back to 8859-1 under normal circumstances.
284              * If, however, a previous exception was detected and the UTF-8 bit is set, failure to
285              * decode the SSID will be used as an indication that the whole frame is malformed and
286              * an exception will be triggered.
287              */
288             CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
289             try {
290                 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(ssidOctets));
291                 ssid = decoded.toString();
292             }
293             catch (CharacterCodingException cce) {
294                 ssid = null;
295             }
296 
297             if (ssid == null) {
298                 if (extendedCapabilities.isStrictUtf8() && exception != null) {
299                     throw new IllegalArgumentException("Failed to decode SSID in dubious IE string");
300                 }
301                 else {
302                     ssid = new String(ssidOctets, StandardCharsets.ISO_8859_1);
303                 }
304             }
305             isHiddenSsid = true;
306             for (byte byteVal : ssidOctets) {
307                 if (byteVal != 0) {
308                     isHiddenSsid = false;
309                     break;
310                 }
311             }
312         }
313 
314         mSSID = ssid;
315         mHESSID = interworking.hessid;
316         mIsHiddenSsid = isHiddenSsid;
317         mStationCount = bssLoad.stationCount;
318         mChannelUtilization = bssLoad.channelUtilization;
319         mCapacity = bssLoad.capacity;
320         mAnt = interworking.ant;
321         mInternet = interworking.internet;
322         mHSRelease = vsa.hsRelease;
323         mAnqpDomainID = vsa.anqpDomainID;
324         mMboSupported = vsa.IsMboCapable;
325         mMboCellularDataAware = vsa.IsMboApCellularDataAware;
326         mOceSupported = vsa.IsOceCapable;
327         mMboAssociationDisallowedReasonCode = vsa.mboAssociationDisallowedReasonCode;
328         mAnqpOICount = roamingConsortium.anqpOICount;
329         mRoamingConsortiums = roamingConsortium.getRoamingConsortiums();
330         mExtendedCapabilities = extendedCapabilities;
331         mANQPElements = null;
332         //set up channel info
333         mPrimaryFreq = freq;
334         int channelWidth = ScanResult.UNSPECIFIED;
335         int centerFreq0 = mPrimaryFreq;
336         int centerFreq1 = 0;
337 
338         if (ehtOperation.isPresent()) {
339             //TODO: include parsing of EHT_Operation to collect BW and center freq.
340         }
341 
342         if (ehtOperation.isPresent()) {
343             //TODO Add impact for using info from EHT capabilities and EHT operation IEs
344         }
345 
346         // Check if HE Operation IE is present
347         if (heOperation.isPresent()) {
348             // If 6GHz info is present, then parameters should be acquired from HE Operation IE
349             if (heOperation.is6GhzInfoPresent()) {
350                 channelWidth = heOperation.getChannelWidth();
351                 centerFreq0 = heOperation.getCenterFreq0();
352                 centerFreq1 = heOperation.getCenterFreq1();
353             } else if (heOperation.isVhtInfoPresent()) {
354                 // VHT Operation Info could be included inside the HE Operation IE
355                 vhtOperation.from(heOperation.getVhtInfoElement());
356             }
357         }
358 
359         // Proceed to VHT Operation IE if parameters were not obtained from HE Operation IE
360         // Not operating in 6GHz
361         if (channelWidth == ScanResult.UNSPECIFIED) {
362             if (vhtOperation.isPresent()) {
363                 channelWidth = vhtOperation.getChannelWidth();
364                 if (channelWidth != ScanResult.UNSPECIFIED) {
365                     centerFreq0 = vhtOperation.getCenterFreq0();
366                     centerFreq1 = vhtOperation.getCenterFreq1();
367                 }
368             }
369         }
370 
371         // Proceed to HT Operation IE if parameters were not obtained from VHT/HE Operation IEs
372         // Apply to operating in 2.4/5GHz with 20/40MHz channels
373         if (channelWidth == ScanResult.UNSPECIFIED) {
374             //Either no vht, or vht shows BW is 40/20 MHz
375             if (htOperation.isPresent()) {
376                 channelWidth = htOperation.getChannelWidth();
377                 centerFreq0 = htOperation.getCenterFreq0(mPrimaryFreq);
378             }
379         }
380 
381         if (channelWidth == ScanResult.UNSPECIFIED) {
382             // Failed to obtain channel info from HE, VHT, HT IEs (possibly a 802.11a/b/g legacy AP)
383             channelWidth = ScanResult.CHANNEL_WIDTH_20MHZ;
384         }
385 
386         mChannelWidth = channelWidth;
387         mCenterfreq0 = centerFreq0;
388         mCenterfreq1 = centerFreq1;
389 
390         if (country.isValid()) {
391             mCountryCode = country.getCountryCode();
392         }
393 
394         // If trafficIndicationMap is not valid, mDtimPeriod will be negative
395         if (trafficIndicationMap.isValid()) {
396             mDtimInterval = trafficIndicationMap.mDtimPeriod;
397         }
398 
399         mMaxNumberSpatialStreams = Math.max(heCapabilities.getMaxNumberSpatialStreams(),
400                 Math.max(vhtCapabilities.getMaxNumberSpatialStreams(),
401                 htCapabilities.getMaxNumberSpatialStreams()));
402 
403         int maxRateA = 0;
404         int maxRateB = 0;
405         // If we got some Extended supported rates, consider them, if not default to 0
406         if (extendedSupportedRates.isValid()) {
407             // rates are sorted from smallest to largest in InformationElement
408             maxRateB = extendedSupportedRates.mRates.get(extendedSupportedRates.mRates.size() - 1);
409         }
410         // Only process the determination logic if we got a 'SupportedRates'
411         if (supportedRates.isValid()) {
412             maxRateA = supportedRates.mRates.get(supportedRates.mRates.size() - 1);
413             mMaxRate = maxRateA > maxRateB ? maxRateA : maxRateB;
414             mWifiMode = InformationElementUtil.WifiMode.determineMode(mPrimaryFreq, mMaxRate,
415                     ehtOperation.isPresent(), heOperation.isPresent(), vhtOperation.isPresent(),
416                     htOperation.isPresent(),
417                     iesFound.contains(ScanResult.InformationElement.EID_ERP));
418         } else {
419             mWifiMode = 0;
420             mMaxRate = 0;
421         }
422 
423         if (multiLink.isPresent()) {
424             mMldMacAddress = multiLink.getMldMacAddress();
425             mMloLinkId = multiLink.getLinkId();
426             if (rnr.isPresent()) {
427                 if (!rnr.getAffiliatedMloLinks().isEmpty()) {
428                     mAffiliatedMloLinks = new ArrayList<>(rnr.getAffiliatedMloLinks());
429                 } else if (!multiLink.getAffiliatedLinks().isEmpty()) {
430                     mAffiliatedMloLinks = new ArrayList<>(multiLink.getAffiliatedLinks());
431                 }
432             }
433 
434             // Add the current link to the list of links if not empty
435             if (!mAffiliatedMloLinks.isEmpty()) {
436                 MloLink link = new MloLink();
437                 link.setApMacAddress(MacAddress.fromString(bssid));
438                 link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported(mPrimaryFreq));
439                 link.setBand(ScanResult.toBand(mPrimaryFreq));
440                 link.setLinkId(mMloLinkId);
441                 mAffiliatedMloLinks.add(link);
442             }
443         }
444 
445         if (DBG) {
446             Log.d(TAG, mSSID + "ChannelWidth is: " + mChannelWidth + " PrimaryFreq: "
447                     + mPrimaryFreq + " Centerfreq0: " + mCenterfreq0 + " Centerfreq1: "
448                     + mCenterfreq1 + (extendedCapabilities.is80211McRTTResponder()
449                     ? " Support RTT responder" : " Do not support RTT responder")
450                     + " MaxNumberSpatialStreams: " + mMaxNumberSpatialStreams
451                     + " MboAssociationDisallowedReasonCode: "
452                     + mMboAssociationDisallowedReasonCode);
453             Log.v("WifiMode", mSSID
454                     + ", WifiMode: " + InformationElementUtil.WifiMode.toString(mWifiMode)
455                     + ", Freq: " + mPrimaryFreq
456                     + ", MaxRate: " + mMaxRate
457                     + ", EHT: " + String.valueOf(ehtOperation.isPresent())
458                     + ", HE: " + String.valueOf(heOperation.isPresent())
459                     + ", VHT: " + String.valueOf(vhtOperation.isPresent())
460                     + ", HT: " + String.valueOf(htOperation.isPresent())
461                     + ", ERP: " + String.valueOf(
462                     iesFound.contains(ScanResult.InformationElement.EID_ERP))
463                     + ", SupportedRates: " + supportedRates.toString()
464                     + " ExtendedSupportedRates: " + extendedSupportedRates.toString());
465         }
466     }
467 
468     /**
469      * Copy constructor
470      */
NetworkDetail(NetworkDetail networkDetail)471     public NetworkDetail(NetworkDetail networkDetail) {
472         this(networkDetail, networkDetail.mANQPElements);
473     }
474 
getAndAdvancePayload(ByteBuffer data, int plLength)475     private static ByteBuffer getAndAdvancePayload(ByteBuffer data, int plLength) {
476         ByteBuffer payload = data.duplicate().order(data.order());
477         payload.limit(payload.position() + plLength);
478         data.position(data.position() + plLength);
479         return payload;
480     }
481 
NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements)482     private NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
483         mSSID = base.mSSID;
484         mIsHiddenSsid = base.mIsHiddenSsid;
485         mBSSID = base.mBSSID;
486         mHESSID = base.mHESSID;
487         mStationCount = base.mStationCount;
488         mChannelUtilization = base.mChannelUtilization;
489         mCapacity = base.mCapacity;
490         mAnt = base.mAnt;
491         mInternet = base.mInternet;
492         mHSRelease = base.mHSRelease;
493         mAnqpDomainID = base.mAnqpDomainID;
494         mAnqpOICount = base.mAnqpOICount;
495         mRoamingConsortiums = base.mRoamingConsortiums;
496         mExtendedCapabilities =
497                 new InformationElementUtil.ExtendedCapabilities(base.mExtendedCapabilities);
498         mANQPElements = anqpElements;
499         mChannelWidth = base.mChannelWidth;
500         mPrimaryFreq = base.mPrimaryFreq;
501         mCenterfreq0 = base.mCenterfreq0;
502         mCenterfreq1 = base.mCenterfreq1;
503         mDtimInterval = base.mDtimInterval;
504         mCountryCode = base.mCountryCode;
505         mWifiMode = base.mWifiMode;
506         mMaxRate = base.mMaxRate;
507         mMaxNumberSpatialStreams = base.mMaxNumberSpatialStreams;
508         mMboSupported = base.mMboSupported;
509         mMboCellularDataAware = base.mMboCellularDataAware;
510         mOceSupported = base.mOceSupported;
511         mMboAssociationDisallowedReasonCode = base.mMboAssociationDisallowedReasonCode;
512     }
513 
complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements)514     public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
515         return new NetworkDetail(this, anqpElements);
516     }
517 
queriable(List<Constants.ANQPElementType> queryElements)518     public boolean queriable(List<Constants.ANQPElementType> queryElements) {
519         return mAnt != null &&
520                 (Constants.hasBaseANQPElements(queryElements) ||
521                  Constants.hasR2Elements(queryElements) && mHSRelease == HSRelease.R2);
522     }
523 
has80211uInfo()524     public boolean has80211uInfo() {
525         return mAnt != null || mRoamingConsortiums != null || mHSRelease != null;
526     }
527 
hasInterworking()528     public boolean hasInterworking() {
529         return mAnt != null;
530     }
531 
getSSID()532     public String getSSID() {
533         return mSSID;
534     }
535 
getTrimmedSSID()536     public String getTrimmedSSID() {
537         if (mSSID != null) {
538             for (int n = 0; n < mSSID.length(); n++) {
539                 if (mSSID.charAt(n) != 0) {
540                     return mSSID;
541                 }
542             }
543         }
544         return "";
545     }
546 
getHESSID()547     public long getHESSID() {
548         return mHESSID;
549     }
550 
getBSSID()551     public long getBSSID() {
552         return mBSSID;
553     }
554 
getStationCount()555     public int getStationCount() {
556         return mStationCount;
557     }
558 
getChannelUtilization()559     public int getChannelUtilization() {
560         return mChannelUtilization;
561     }
562 
getCapacity()563     public int getCapacity() {
564         return mCapacity;
565     }
566 
isInterworking()567     public boolean isInterworking() {
568         return mAnt != null;
569     }
570 
getAnt()571     public Ant getAnt() {
572         return mAnt;
573     }
574 
isInternet()575     public boolean isInternet() {
576         return mInternet;
577     }
578 
getHSRelease()579     public HSRelease getHSRelease() {
580         return mHSRelease;
581     }
582 
getAnqpDomainID()583     public int getAnqpDomainID() {
584         return mAnqpDomainID;
585     }
586 
getOsuProviders()587     public byte[] getOsuProviders() {
588         if (mANQPElements == null) {
589             return null;
590         }
591         ANQPElement osuProviders = mANQPElements.get(Constants.ANQPElementType.HSOSUProviders);
592         return osuProviders != null ? ((RawByteElement) osuProviders).getPayload() : null;
593     }
594 
getAnqpOICount()595     public int getAnqpOICount() {
596         return mAnqpOICount;
597     }
598 
getRoamingConsortiums()599     public long[] getRoamingConsortiums() {
600         return mRoamingConsortiums;
601     }
602 
getANQPElements()603     public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() {
604         return mANQPElements;
605     }
606 
getChannelWidth()607     public int getChannelWidth() {
608         return mChannelWidth;
609     }
610 
getCenterfreq0()611     public int getCenterfreq0() {
612         return mCenterfreq0;
613     }
614 
getCenterfreq1()615     public int getCenterfreq1() {
616         return mCenterfreq1;
617     }
618 
getWifiMode()619     public int getWifiMode() {
620         return mWifiMode;
621     }
622 
getMaxNumberSpatialStreams()623     public int getMaxNumberSpatialStreams() {
624         return mMaxNumberSpatialStreams;
625     }
626 
getDtimInterval()627     public int getDtimInterval() {
628         return mDtimInterval;
629     }
630 
getCountryCode()631     public String getCountryCode() {
632         return mCountryCode;
633     }
634 
is80211McResponderSupport()635     public boolean is80211McResponderSupport() {
636         return mExtendedCapabilities.is80211McRTTResponder();
637     }
638 
isSSID_UTF8()639     public boolean isSSID_UTF8() {
640         return mExtendedCapabilities.isStrictUtf8();
641     }
642 
getMldMacAddress()643     public MacAddress getMldMacAddress() {
644         return mMldMacAddress;
645     }
646 
getMloLinkId()647     public int getMloLinkId() {
648         return mMloLinkId;
649     }
650 
getAffiliatedMloLinks()651     public List<MloLink> getAffiliatedMloLinks() {
652         return mAffiliatedMloLinks;
653     }
654 
655     @Override
equals(Object thatObject)656     public boolean equals(Object thatObject) {
657         if (this == thatObject) {
658             return true;
659         }
660         if (thatObject == null || getClass() != thatObject.getClass()) {
661             return false;
662         }
663 
664         NetworkDetail that = (NetworkDetail)thatObject;
665 
666         return getSSID().equals(that.getSSID()) && getBSSID() == that.getBSSID();
667     }
668 
669     @Override
hashCode()670     public int hashCode() {
671         return ((mSSID.hashCode() * 31) + (int)(mBSSID >>> 32)) * 31 + (int)mBSSID;
672     }
673 
674     @Override
toString()675     public String toString() {
676         return "NetworkInfo{SSID='" + mSSID
677                 + "', HESSID=" + Utils.macToSimpleString(mHESSID)
678                 + ", BSSID=" + Utils.macToSimpleString(mBSSID)
679                 + ", StationCount=" + mStationCount
680                 + ", ChannelUtilization=" + mChannelUtilization
681                 + ", Capacity=" + mCapacity
682                 + ", Ant=" + mAnt + ", Internet=" + mInternet + ", HSRelease="
683                 + mHSRelease + ", AnqpDomainID" + mAnqpDomainID + ", AnqpOICount" + mAnqpOICount
684                 + ", RoamingConsortiums=" + Utils.roamingConsortiumsToString(mRoamingConsortiums)
685                 + "}";
686     }
687 
toKeyString()688     public String toKeyString() {
689         return mHESSID != 0 ?
690                 "'" + mSSID + "':" + Utils.macToSimpleString(mBSSID) + " ("
691                         + Utils.macToSimpleString(mHESSID) + ")"
692                 : "'" + mSSID + "':" + Utils.macToSimpleString(mBSSID);
693     }
694 
getBSSIDString()695     public String getBSSIDString() {
696         return Utils.macToString(mBSSID);
697     }
698 
699     /**
700      * Evaluates the ScanResult this NetworkDetail is built from
701      * returns true if built from a Beacon Frame
702      * returns false if built from a Probe Response
703      */
isBeaconFrame()704     public boolean isBeaconFrame() {
705         // Beacon frames have a 'Traffic Indication Map' Information element
706         // Probe Responses do not. This is indicated by a DTIM period > 0
707         return mDtimInterval > 0;
708     }
709 
710     /**
711      * Evaluates the ScanResult this NetworkDetail is built from
712      * returns true if built from a hidden Beacon Frame
713      * returns false if not hidden or not a Beacon
714      */
isHiddenBeaconFrame()715     public boolean isHiddenBeaconFrame() {
716         // Hidden networks are not 80211 standard, but it is common for a hidden network beacon
717         // frame to either send zero-value bytes as the SSID, or to send no bytes at all.
718         return isBeaconFrame() && mIsHiddenSsid;
719     }
720 
getMboAssociationDisallowedReasonCode()721     public int getMboAssociationDisallowedReasonCode() {
722         return mMboAssociationDisallowedReasonCode;
723     }
724 
isMboSupported()725     public boolean isMboSupported() {
726         return mMboSupported;
727     }
728 
isMboCellularDataAware()729     public boolean isMboCellularDataAware() {
730         return mMboCellularDataAware;
731     }
732 
isOceSupported()733     public boolean isOceSupported() {
734         return mOceSupported;
735     }
736 }
737