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 // Target wake time (TWT) allows an AP to manage activity in the BSS in order to minimize 135 // contention between STAs and to reduce the required amount of time that a STA utilizing a 136 // power management mode needs to be awake. 137 138 // The HE AP requests that STAs participate in TWT by setting the TWT Required subfield to 1 139 // in HE Operation elements. STAs that support TWT and receive an HE Operation element with 140 // the TWT Required subfield set to 1 must either negotiate individual TWT agreements or 141 // participate in broadcast TWT operation. 142 private final boolean mTwtRequired; 143 // With Individual TWT operation, a STA negotiate a wake schedule with an access point, allowing 144 // it to wake up only when required. 145 private final boolean mIndividualTwtSupported; 146 // In Broadcast TWT operation, an AP can set up a shared TWT session for a group of stations 147 // and specify the TWT parameters periodically in Beacon frames. 148 private final boolean mBroadcastTwtSupported; 149 // Restricted Target Wake Time (TWT) is a feature that allows an access point to allocate 150 // exclusive access to a medium at specified times. 151 private final boolean mRestrictedTwtSupported; 152 153 // EPCS priority access is a mechanism that provides prioritized access to the wireless 154 // medium for authorized users to increase their probability of successful communication 155 // during periods of network congestion. 156 private final boolean mEpcsPriorityAccessSupported; 157 158 // Fast Initial Link Setup (FILS) 159 private final boolean mFilsCapable; 160 161 // 6 GHz Access Point Type 162 private final InformationElementUtil.ApType6GHz mApType6GHz; 163 164 // IEEE 802.11az non-trigger based & trigger based 165 private final boolean mIs11azNtbResponder; 166 private final boolean mIs11azTbResponder; 167 168 // MLO Attributes 169 private MacAddress mMldMacAddress = null; 170 private int mMloLinkId = MloLink.INVALID_MLO_LINK_ID; 171 private List<MloLink> mAffiliatedMloLinks = Collections.emptyList(); 172 private byte[] mDisabledSubchannelBitmap; 173 NetworkDetail(String bssid, ScanResult.InformationElement[] infoElements, List<String> anqpLines, int freq)174 public NetworkDetail(String bssid, ScanResult.InformationElement[] infoElements, 175 List<String> anqpLines, int freq) { 176 if (infoElements == null) { 177 infoElements = new ScanResult.InformationElement[0]; 178 } 179 180 mBSSID = Utils.parseMac(bssid); 181 182 String ssid = null; 183 boolean isHiddenSsid = false; 184 byte[] ssidOctets = null; 185 186 InformationElementUtil.BssLoad bssLoad = new InformationElementUtil.BssLoad(); 187 188 InformationElementUtil.Interworking interworking = 189 new InformationElementUtil.Interworking(); 190 191 InformationElementUtil.RoamingConsortium roamingConsortium = 192 new InformationElementUtil.RoamingConsortium(); 193 194 InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa(); 195 196 InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation(); 197 InformationElementUtil.VhtOperation vhtOperation = 198 new InformationElementUtil.VhtOperation(); 199 InformationElementUtil.HeOperation heOperation = new InformationElementUtil.HeOperation(); 200 InformationElementUtil.EhtOperation ehtOperation = 201 new InformationElementUtil.EhtOperation(); 202 203 InformationElementUtil.HtCapabilities htCapabilities = 204 new InformationElementUtil.HtCapabilities(); 205 InformationElementUtil.VhtCapabilities vhtCapabilities = 206 new InformationElementUtil.VhtCapabilities(); 207 InformationElementUtil.HeCapabilities heCapabilities = 208 new InformationElementUtil.HeCapabilities(); 209 InformationElementUtil.EhtCapabilities ehtCapabilities = 210 new InformationElementUtil.EhtCapabilities(); 211 InformationElementUtil.Rnr rnr = 212 new InformationElementUtil.Rnr(); 213 InformationElementUtil.MultiLink multiLink = 214 new InformationElementUtil.MultiLink(); 215 InformationElementUtil.ExtendedCapabilities extendedCapabilities = 216 new InformationElementUtil.ExtendedCapabilities(); 217 218 InformationElementUtil.Country country = 219 new InformationElementUtil.Country(); 220 221 InformationElementUtil.TrafficIndicationMap trafficIndicationMap = 222 new InformationElementUtil.TrafficIndicationMap(); 223 224 InformationElementUtil.SupportedRates supportedRates = 225 new InformationElementUtil.SupportedRates(); 226 InformationElementUtil.SupportedRates extendedSupportedRates = 227 new InformationElementUtil.SupportedRates(); 228 229 RuntimeException exception = null; 230 231 ArrayList<Integer> iesFound = new ArrayList<Integer>(); 232 try { 233 for (ScanResult.InformationElement ie : infoElements) { 234 iesFound.add(ie.id); 235 switch (ie.id) { 236 case ScanResult.InformationElement.EID_SSID: 237 ssidOctets = ie.bytes; 238 break; 239 case ScanResult.InformationElement.EID_BSS_LOAD: 240 bssLoad.from(ie); 241 break; 242 case ScanResult.InformationElement.EID_HT_OPERATION: 243 htOperation.from(ie); 244 break; 245 case ScanResult.InformationElement.EID_VHT_OPERATION: 246 vhtOperation.from(ie); 247 break; 248 case ScanResult.InformationElement.EID_HT_CAPABILITIES: 249 htCapabilities.from(ie); 250 break; 251 case ScanResult.InformationElement.EID_VHT_CAPABILITIES: 252 vhtCapabilities.from(ie); 253 break; 254 case ScanResult.InformationElement.EID_INTERWORKING: 255 interworking.from(ie); 256 break; 257 case ScanResult.InformationElement.EID_ROAMING_CONSORTIUM: 258 roamingConsortium.from(ie); 259 break; 260 case ScanResult.InformationElement.EID_VSA: 261 vsa.from(ie); 262 break; 263 case ScanResult.InformationElement.EID_EXTENDED_CAPS: 264 extendedCapabilities.from(ie); 265 break; 266 case ScanResult.InformationElement.EID_COUNTRY: 267 country.from(ie); 268 break; 269 case ScanResult.InformationElement.EID_TIM: 270 trafficIndicationMap.from(ie); 271 break; 272 case ScanResult.InformationElement.EID_SUPPORTED_RATES: 273 supportedRates.from(ie); 274 break; 275 case ScanResult.InformationElement.EID_EXTENDED_SUPPORTED_RATES: 276 extendedSupportedRates.from(ie); 277 break; 278 case ScanResult.InformationElement.EID_RNR: 279 rnr.from(ie); 280 break; 281 case ScanResult.InformationElement.EID_EXTENSION_PRESENT: 282 switch(ie.idExt) { 283 case ScanResult.InformationElement.EID_EXT_HE_OPERATION: 284 heOperation.from(ie); 285 break; 286 case ScanResult.InformationElement.EID_EXT_HE_CAPABILITIES: 287 heCapabilities.from(ie); 288 break; 289 case ScanResult.InformationElement.EID_EXT_EHT_OPERATION: 290 ehtOperation.from(ie); 291 break; 292 case ScanResult.InformationElement.EID_EXT_EHT_CAPABILITIES: 293 ehtCapabilities.from(ie); 294 break; 295 case ScanResult.InformationElement.EID_EXT_MULTI_LINK: 296 multiLink.from(ie); 297 break; 298 default: 299 break; 300 } 301 break; 302 default: 303 break; 304 } 305 } 306 } 307 catch (IllegalArgumentException | BufferUnderflowException | ArrayIndexOutOfBoundsException e) { 308 Log.d(TAG, "Caught " + e); 309 if (ssidOctets == null) { 310 throw new IllegalArgumentException("Malformed IE string (no SSID)", e); 311 } 312 exception = e; 313 } 314 if (ssidOctets != null) { 315 /* 316 * Strict use of the "UTF-8 SSID" bit by APs appears to be spotty at best even if the 317 * encoding truly is in UTF-8. An unconditional attempt to decode the SSID as UTF-8 is 318 * therefore always made with a fall back to 8859-1 under normal circumstances. 319 * If, however, a previous exception was detected and the UTF-8 bit is set, failure to 320 * decode the SSID will be used as an indication that the whole frame is malformed and 321 * an exception will be triggered. 322 */ 323 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 324 try { 325 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(ssidOctets)); 326 ssid = decoded.toString(); 327 } 328 catch (CharacterCodingException cce) { 329 ssid = null; 330 } 331 332 if (ssid == null) { 333 if (extendedCapabilities.isStrictUtf8() && exception != null) { 334 throw new IllegalArgumentException("Failed to decode SSID in dubious IE string"); 335 } 336 else { 337 ssid = new String(ssidOctets, StandardCharsets.ISO_8859_1); 338 } 339 } 340 isHiddenSsid = true; 341 for (byte byteVal : ssidOctets) { 342 if (byteVal != 0) { 343 isHiddenSsid = false; 344 break; 345 } 346 } 347 } 348 349 mSSID = ssid; 350 mHESSID = interworking.hessid; 351 mIsHiddenSsid = isHiddenSsid; 352 mStationCount = bssLoad.stationCount; 353 mChannelUtilization = bssLoad.channelUtilization; 354 mCapacity = bssLoad.capacity; 355 mAnt = interworking.ant; 356 mInternet = interworking.internet; 357 mHSRelease = vsa.hsRelease; 358 mAnqpDomainID = vsa.anqpDomainID; 359 mMboSupported = vsa.IsMboCapable; 360 mMboCellularDataAware = vsa.IsMboApCellularDataAware; 361 mOceSupported = vsa.IsOceCapable; 362 mMboAssociationDisallowedReasonCode = vsa.mboAssociationDisallowedReasonCode; 363 mAnqpOICount = roamingConsortium.anqpOICount; 364 mRoamingConsortiums = roamingConsortium.getRoamingConsortiums(); 365 mExtendedCapabilities = extendedCapabilities; 366 mANQPElements = null; 367 //set up channel info 368 mPrimaryFreq = freq; 369 mTwtRequired = heOperation.isTwtRequired(); 370 mIndividualTwtSupported = heCapabilities.isTwtResponderSupported(); 371 mBroadcastTwtSupported = heCapabilities.isBroadcastTwtSupported(); 372 mRestrictedTwtSupported = ehtCapabilities.isRestrictedTwtSupported(); 373 mEpcsPriorityAccessSupported = ehtCapabilities.isEpcsPriorityAccessSupported(); 374 mFilsCapable = extendedCapabilities.isFilsCapable(); 375 mApType6GHz = heOperation.getApType6GHz(); 376 mIs11azNtbResponder = extendedCapabilities.is80211azNtbResponder(); 377 mIs11azTbResponder = extendedCapabilities.is80211azTbResponder(); 378 int channelWidth = ScanResult.UNSPECIFIED; 379 int centerFreq0 = mPrimaryFreq; 380 int centerFreq1 = 0; 381 382 // Check if EHT Operation Info is present in EHT operation IE. 383 if (ehtOperation.isEhtOperationInfoPresent()) { 384 int operatingBand = ScanResult.toBand(mPrimaryFreq); 385 channelWidth = ehtOperation.getChannelWidth(); 386 centerFreq0 = ehtOperation.getCenterFreq0(operatingBand); 387 centerFreq1 = ehtOperation.getCenterFreq1(operatingBand); 388 mDisabledSubchannelBitmap = ehtOperation.getDisabledSubchannelBitmap(); 389 } 390 391 // Proceed to HE Operation IE if channel width and center frequencies were not obtained 392 // from EHT Operation IE 393 if (channelWidth == ScanResult.UNSPECIFIED) { 394 // Check if HE Operation IE is present 395 if (heOperation.isPresent()) { 396 // If 6GHz info is present, then parameters should be acquired from HE Operation IE 397 if (heOperation.is6GhzInfoPresent()) { 398 channelWidth = heOperation.getChannelWidth(); 399 centerFreq0 = heOperation.getCenterFreq0(); 400 centerFreq1 = heOperation.getCenterFreq1(); 401 } else if (heOperation.isVhtInfoPresent()) { 402 // VHT Operation Info could be included inside the HE Operation IE 403 vhtOperation.from(heOperation.getVhtInfoElement()); 404 } 405 } 406 } 407 408 // Proceed to VHT Operation IE if parameters were not obtained from HE Operation IE 409 // Not operating in 6GHz 410 if (channelWidth == ScanResult.UNSPECIFIED) { 411 if (vhtOperation.isPresent()) { 412 channelWidth = vhtOperation.getChannelWidth(); 413 if (channelWidth != ScanResult.UNSPECIFIED) { 414 centerFreq0 = vhtOperation.getCenterFreq0(); 415 centerFreq1 = vhtOperation.getCenterFreq1(); 416 } 417 } 418 } 419 420 // Proceed to HT Operation IE if parameters were not obtained from VHT/HE Operation IEs 421 // Apply to operating in 2.4/5GHz with 20/40MHz channels 422 if (channelWidth == ScanResult.UNSPECIFIED) { 423 //Either no vht, or vht shows BW is 40/20 MHz 424 if (htOperation.isPresent()) { 425 channelWidth = htOperation.getChannelWidth(); 426 centerFreq0 = htOperation.getCenterFreq0(mPrimaryFreq); 427 } 428 } 429 430 if (channelWidth == ScanResult.UNSPECIFIED) { 431 // Failed to obtain channel info from HE, VHT, HT IEs (possibly a 802.11a/b/g legacy AP) 432 channelWidth = ScanResult.CHANNEL_WIDTH_20MHZ; 433 } 434 435 mChannelWidth = channelWidth; 436 mCenterfreq0 = centerFreq0; 437 mCenterfreq1 = centerFreq1; 438 439 if (country.isValid()) { 440 mCountryCode = country.getCountryCode(); 441 } 442 443 // If trafficIndicationMap is not valid, mDtimPeriod will be negative 444 if (trafficIndicationMap.isValid()) { 445 mDtimInterval = trafficIndicationMap.mDtimPeriod; 446 } 447 448 mMaxNumberSpatialStreams = Math.max(heCapabilities.getMaxNumberSpatialStreams(), 449 Math.max(vhtCapabilities.getMaxNumberSpatialStreams(), 450 htCapabilities.getMaxNumberSpatialStreams())); 451 452 int maxRateA = 0; 453 int maxRateB = 0; 454 // If we got some Extended supported rates, consider them, if not default to 0 455 if (extendedSupportedRates.isValid()) { 456 // rates are sorted from smallest to largest in InformationElement 457 maxRateB = extendedSupportedRates.mRates.get(extendedSupportedRates.mRates.size() - 1); 458 } 459 // Only process the determination logic if we got a 'SupportedRates' 460 if (supportedRates.isValid()) { 461 maxRateA = supportedRates.mRates.get(supportedRates.mRates.size() - 1); 462 mMaxRate = maxRateA > maxRateB ? maxRateA : maxRateB; 463 mWifiMode = InformationElementUtil.WifiMode.determineMode(mPrimaryFreq, mMaxRate, 464 ehtOperation.isPresent(), heOperation.isPresent(), vhtOperation.isPresent(), 465 htOperation.isPresent(), 466 iesFound.contains(ScanResult.InformationElement.EID_ERP)); 467 } else { 468 mWifiMode = 0; 469 mMaxRate = 0; 470 } 471 472 if (multiLink.isPresent()) { 473 mMldMacAddress = multiLink.getMldMacAddress(); 474 mMloLinkId = multiLink.getLinkId(); 475 if (rnr.isPresent()) { 476 if (!rnr.getAffiliatedMloLinks().isEmpty()) { 477 mAffiliatedMloLinks = new ArrayList<>(rnr.getAffiliatedMloLinks()); 478 } else if (!multiLink.getAffiliatedLinks().isEmpty()) { 479 mAffiliatedMloLinks = new ArrayList<>(multiLink.getAffiliatedLinks()); 480 } 481 } 482 483 // Add the current link to the list of links if not empty 484 if (!mAffiliatedMloLinks.isEmpty()) { 485 MloLink link = new MloLink(); 486 link.setApMacAddress(MacAddress.fromString(bssid)); 487 link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported(mPrimaryFreq)); 488 link.setBand(ScanResult.toBand(mPrimaryFreq)); 489 link.setLinkId(mMloLinkId); 490 mAffiliatedMloLinks.add(link); 491 } 492 } 493 494 if (DBG) { 495 Log.d(TAG, mSSID + "ChannelWidth is: " + mChannelWidth + " PrimaryFreq: " 496 + mPrimaryFreq + " Centerfreq0: " + mCenterfreq0 + " Centerfreq1: " 497 + mCenterfreq1 + (extendedCapabilities.is80211McRTTResponder() 498 ? " Support RTT responder" : " Do not support RTT responder") 499 + " MaxNumberSpatialStreams: " + mMaxNumberSpatialStreams 500 + " MboAssociationDisallowedReasonCode: " 501 + mMboAssociationDisallowedReasonCode); 502 Log.v("WifiMode", mSSID 503 + ", WifiMode: " + InformationElementUtil.WifiMode.toString(mWifiMode) 504 + ", Freq: " + mPrimaryFreq 505 + ", MaxRate: " + mMaxRate 506 + ", EHT: " + String.valueOf(ehtOperation.isPresent()) 507 + ", HE: " + String.valueOf(heOperation.isPresent()) 508 + ", VHT: " + String.valueOf(vhtOperation.isPresent()) 509 + ", HT: " + String.valueOf(htOperation.isPresent()) 510 + ", ERP: " + String.valueOf( 511 iesFound.contains(ScanResult.InformationElement.EID_ERP)) 512 + ", SupportedRates: " + supportedRates.toString() 513 + " ExtendedSupportedRates: " + extendedSupportedRates.toString()); 514 } 515 } 516 517 /** 518 * Copy constructor 519 */ NetworkDetail(NetworkDetail networkDetail)520 public NetworkDetail(NetworkDetail networkDetail) { 521 this(networkDetail, networkDetail.mANQPElements); 522 } 523 getAndAdvancePayload(ByteBuffer data, int plLength)524 private static ByteBuffer getAndAdvancePayload(ByteBuffer data, int plLength) { 525 ByteBuffer payload = data.duplicate().order(data.order()); 526 payload.limit(payload.position() + plLength); 527 data.position(data.position() + plLength); 528 return payload; 529 } 530 NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements)531 private NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 532 mSSID = base.mSSID; 533 mIsHiddenSsid = base.mIsHiddenSsid; 534 mBSSID = base.mBSSID; 535 mHESSID = base.mHESSID; 536 mStationCount = base.mStationCount; 537 mChannelUtilization = base.mChannelUtilization; 538 mCapacity = base.mCapacity; 539 mAnt = base.mAnt; 540 mInternet = base.mInternet; 541 mHSRelease = base.mHSRelease; 542 mAnqpDomainID = base.mAnqpDomainID; 543 mAnqpOICount = base.mAnqpOICount; 544 mRoamingConsortiums = base.mRoamingConsortiums; 545 mExtendedCapabilities = 546 new InformationElementUtil.ExtendedCapabilities(base.mExtendedCapabilities); 547 mANQPElements = anqpElements; 548 mChannelWidth = base.mChannelWidth; 549 mPrimaryFreq = base.mPrimaryFreq; 550 mCenterfreq0 = base.mCenterfreq0; 551 mCenterfreq1 = base.mCenterfreq1; 552 mDtimInterval = base.mDtimInterval; 553 mCountryCode = base.mCountryCode; 554 mWifiMode = base.mWifiMode; 555 mMaxRate = base.mMaxRate; 556 mMaxNumberSpatialStreams = base.mMaxNumberSpatialStreams; 557 mMboSupported = base.mMboSupported; 558 mMboCellularDataAware = base.mMboCellularDataAware; 559 mOceSupported = base.mOceSupported; 560 mMboAssociationDisallowedReasonCode = base.mMboAssociationDisallowedReasonCode; 561 mTwtRequired = base.mTwtRequired; 562 mIndividualTwtSupported = base.mIndividualTwtSupported; 563 mBroadcastTwtSupported = base.mBroadcastTwtSupported; 564 mRestrictedTwtSupported = base.mRestrictedTwtSupported; 565 mEpcsPriorityAccessSupported = base.mEpcsPriorityAccessSupported; 566 mFilsCapable = base.mFilsCapable; 567 mApType6GHz = base.mApType6GHz; 568 mIs11azNtbResponder = base.mIs11azNtbResponder; 569 mIs11azTbResponder = base.mIs11azTbResponder; 570 } 571 complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements)572 public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 573 return new NetworkDetail(this, anqpElements); 574 } 575 queriable(List<Constants.ANQPElementType> queryElements)576 public boolean queriable(List<Constants.ANQPElementType> queryElements) { 577 return mAnt != null && 578 (Constants.hasBaseANQPElements(queryElements) || 579 Constants.hasR2Elements(queryElements) && mHSRelease == HSRelease.R2); 580 } 581 has80211uInfo()582 public boolean has80211uInfo() { 583 return mAnt != null || mRoamingConsortiums != null || mHSRelease != null; 584 } 585 hasInterworking()586 public boolean hasInterworking() { 587 return mAnt != null; 588 } 589 getSSID()590 public String getSSID() { 591 return mSSID; 592 } 593 getTrimmedSSID()594 public String getTrimmedSSID() { 595 if (mSSID != null) { 596 for (int n = 0; n < mSSID.length(); n++) { 597 if (mSSID.charAt(n) != 0) { 598 return mSSID; 599 } 600 } 601 } 602 return ""; 603 } 604 getHESSID()605 public long getHESSID() { 606 return mHESSID; 607 } 608 getBSSID()609 public long getBSSID() { 610 return mBSSID; 611 } 612 getStationCount()613 public int getStationCount() { 614 return mStationCount; 615 } 616 getChannelUtilization()617 public int getChannelUtilization() { 618 return mChannelUtilization; 619 } 620 getCapacity()621 public int getCapacity() { 622 return mCapacity; 623 } 624 isInterworking()625 public boolean isInterworking() { 626 return mAnt != null; 627 } 628 getAnt()629 public Ant getAnt() { 630 return mAnt; 631 } 632 isInternet()633 public boolean isInternet() { 634 return mInternet; 635 } 636 getHSRelease()637 public HSRelease getHSRelease() { 638 return mHSRelease; 639 } 640 getAnqpDomainID()641 public int getAnqpDomainID() { 642 return mAnqpDomainID; 643 } 644 getOsuProviders()645 public byte[] getOsuProviders() { 646 if (mANQPElements == null) { 647 return null; 648 } 649 ANQPElement osuProviders = mANQPElements.get(Constants.ANQPElementType.HSOSUProviders); 650 return osuProviders != null ? ((RawByteElement) osuProviders).getPayload() : null; 651 } 652 getAnqpOICount()653 public int getAnqpOICount() { 654 return mAnqpOICount; 655 } 656 getRoamingConsortiums()657 public long[] getRoamingConsortiums() { 658 return mRoamingConsortiums; 659 } 660 getANQPElements()661 public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() { 662 return mANQPElements; 663 } 664 getChannelWidth()665 public int getChannelWidth() { 666 return mChannelWidth; 667 } 668 getCenterfreq0()669 public int getCenterfreq0() { 670 return mCenterfreq0; 671 } 672 getCenterfreq1()673 public int getCenterfreq1() { 674 return mCenterfreq1; 675 } 676 getWifiMode()677 public int getWifiMode() { 678 return mWifiMode; 679 } 680 getMaxNumberSpatialStreams()681 public int getMaxNumberSpatialStreams() { 682 return mMaxNumberSpatialStreams; 683 } 684 getDtimInterval()685 public int getDtimInterval() { 686 return mDtimInterval; 687 } 688 getCountryCode()689 public String getCountryCode() { 690 return mCountryCode; 691 } 692 is80211McResponderSupport()693 public boolean is80211McResponderSupport() { 694 return mExtendedCapabilities.is80211McRTTResponder(); 695 } 696 isSSID_UTF8()697 public boolean isSSID_UTF8() { 698 return mExtendedCapabilities.isStrictUtf8(); 699 } 700 getMldMacAddress()701 public MacAddress getMldMacAddress() { 702 return mMldMacAddress; 703 } 704 getMloLinkId()705 public int getMloLinkId() { 706 return mMloLinkId; 707 } 708 getAffiliatedMloLinks()709 public List<MloLink> getAffiliatedMloLinks() { 710 return mAffiliatedMloLinks; 711 } 712 getDisabledSubchannelBitmap()713 public byte[] getDisabledSubchannelBitmap() { 714 return mDisabledSubchannelBitmap; 715 } 716 717 @Override equals(Object thatObject)718 public boolean equals(Object thatObject) { 719 if (this == thatObject) { 720 return true; 721 } 722 if (thatObject == null || getClass() != thatObject.getClass()) { 723 return false; 724 } 725 726 NetworkDetail that = (NetworkDetail)thatObject; 727 728 return getSSID().equals(that.getSSID()) && getBSSID() == that.getBSSID(); 729 } 730 731 @Override hashCode()732 public int hashCode() { 733 return ((mSSID.hashCode() * 31) + (int)(mBSSID >>> 32)) * 31 + (int)mBSSID; 734 } 735 736 @Override toString()737 public String toString() { 738 return "NetworkInfo{SSID='" + mSSID 739 + "', HESSID=" + Utils.macToString(mHESSID) 740 + ", BSSID=" + Utils.macToString(mBSSID) 741 + ", StationCount=" + mStationCount 742 + ", ChannelUtilization=" + mChannelUtilization 743 + ", Capacity=" + mCapacity 744 + ", Ant=" + mAnt + ", Internet=" + mInternet + ", HSRelease=" 745 + mHSRelease + ", AnqpDomainID" + mAnqpDomainID + ", AnqpOICount" + mAnqpOICount 746 + ", RoamingConsortiums=" + Utils.roamingConsortiumsToString(mRoamingConsortiums) 747 + "}"; 748 } 749 toKeyString()750 public String toKeyString() { 751 return mHESSID != 0 ? 752 "'" + mSSID + "':" + Utils.macToString(mBSSID) + " (" 753 + Utils.macToString(mHESSID) + ")" 754 : "'" + mSSID + "':" + Utils.macToString(mBSSID); 755 } 756 getBSSIDString()757 public String getBSSIDString() { 758 return Utils.macToString(mBSSID); 759 } 760 761 /** 762 * Evaluates the ScanResult this NetworkDetail is built from 763 * returns true if built from a Beacon Frame 764 * returns false if built from a Probe Response 765 */ isBeaconFrame()766 public boolean isBeaconFrame() { 767 // Beacon frames have a 'Traffic Indication Map' Information element 768 // Probe Responses do not. This is indicated by a DTIM period > 0 769 return mDtimInterval > 0; 770 } 771 772 /** 773 * Evaluates the ScanResult this NetworkDetail is built from 774 * returns true if built from a hidden Beacon Frame 775 * returns false if not hidden or not a Beacon 776 */ isHiddenBeaconFrame()777 public boolean isHiddenBeaconFrame() { 778 // Hidden networks are not 80211 standard, but it is common for a hidden network beacon 779 // frame to either send zero-value bytes as the SSID, or to send no bytes at all. 780 return isBeaconFrame() && mIsHiddenSsid; 781 } 782 getMboAssociationDisallowedReasonCode()783 public int getMboAssociationDisallowedReasonCode() { 784 return mMboAssociationDisallowedReasonCode; 785 } 786 isMboSupported()787 public boolean isMboSupported() { 788 return mMboSupported; 789 } 790 isMboCellularDataAware()791 public boolean isMboCellularDataAware() { 792 return mMboCellularDataAware; 793 } 794 isOceSupported()795 public boolean isOceSupported() { 796 return mOceSupported; 797 } 798 799 /** Return whether the AP supports IEEE 802.11az non-trigger based ranging **/ is80211azNtbResponder()800 public boolean is80211azNtbResponder() { 801 return mIs11azNtbResponder; 802 } 803 804 /** Return whether the AP supports IEEE 802.11az trigger based ranging **/ is80211azTbResponder()805 public boolean is80211azTbResponder() { 806 return mIs11azTbResponder; 807 } 808 809 /** 810 * Return whether the AP requires HE stations to participate either in individual TWT 811 * agreements or Broadcast TWT operation. 812 **/ isTwtRequired()813 public boolean isTwtRequired() { 814 return mTwtRequired; 815 } 816 817 /** Return whether individual TWT is supported. */ isIndividualTwtSupported()818 public boolean isIndividualTwtSupported() { 819 return mIndividualTwtSupported; 820 } 821 822 /** Return whether broadcast TWT is supported */ isBroadcastTwtSupported()823 public boolean isBroadcastTwtSupported() { 824 return mBroadcastTwtSupported; 825 } 826 827 /** 828 * Returns whether restricted TWT is supported or not. It enables enhanced medium access 829 * protection and resource reservation mechanisms for delivery of latency sensitive 830 * traffic. 831 */ isRestrictedTwtSupported()832 public boolean isRestrictedTwtSupported() { 833 return mRestrictedTwtSupported; 834 } 835 836 /** 837 * Returns whether EPCS priority access supported or not. EPCS priority access is a 838 * mechanism that provides prioritized access to the wireless medium for authorized users to 839 * increase their probability of successful communication during periods of network 840 * congestion. 841 */ isEpcsPriorityAccessSupported()842 public boolean isEpcsPriorityAccessSupported() { 843 return mEpcsPriorityAccessSupported; 844 } 845 846 /** 847 * @return true if Fast Initial Link Setup (FILS) capable 848 */ isFilsCapable()849 public boolean isFilsCapable() { 850 return mFilsCapable; 851 } 852 853 /** 854 * Return 6Ghz AP type as defined in {@link InformationElementUtil.ApType6GHz} 855 **/ getApType6GHz()856 public InformationElementUtil.ApType6GHz getApType6GHz() { 857 return mApType6GHz; 858 } 859 } 860