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