1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.wifi; 18 19 import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; 20 import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ; 21 import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ; 22 23 import android.annotation.IntDef; 24 import android.annotation.IntRange; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.net.MacAddress; 28 import android.net.NetworkCapabilities; 29 import android.os.Parcel; 30 import android.os.Parcelable; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.util.Objects; 35 36 /** 37 * Data structure class representing a Wi-Fi Multi-Link Operation (MLO) link 38 * This is only used by 802.11be capable devices 39 */ 40 public final class MloLink implements Parcelable { 41 42 /** 43 * Invalid link id. Used in {link #getLinkId()} 44 */ 45 public static final int INVALID_MLO_LINK_ID = -1; 46 47 /** 48 * Lower limit for MLO link id 49 * As described in IEEE 802.11be Specification, section 9.4.2.295b.2. 50 * 51 * @hide 52 */ 53 public static final int MIN_MLO_LINK_ID = 0; 54 55 /** 56 * Upper limit for MLO link id 57 * As described in IEEE 802.11be Specification, section 9.4.2.295b.2. 58 * 59 * @hide 60 */ 61 public static final int MAX_MLO_LINK_ID = 15; 62 63 /** 64 * MLO link state: Invalid link state. Used in {link #getState()} 65 */ 66 public static final int MLO_LINK_STATE_INVALID = 0; 67 /** 68 * MLO link state: Link is not associated with the access point. Used in {link #getState()} 69 */ 70 public static final int MLO_LINK_STATE_UNASSOCIATED = 1; 71 /** 72 * MLO link state: Link is associated to the access point but not mapped to any traffic stream. 73 * Used in {link #getState()} 74 */ 75 public static final int MLO_LINK_STATE_IDLE = 2; 76 /** 77 * MLO link state: Link is associated to the access point and mapped to at least one traffic 78 * stream. {link #getState()} 79 * Note that an MLO link could be in that state but in power save mode. 80 */ 81 public static final int MLO_LINK_STATE_ACTIVE = 3; 82 83 /** 84 * @hide 85 */ 86 @Retention(RetentionPolicy.SOURCE) 87 @IntDef(prefix = {"MLO_LINK_STATE_"}, value = { 88 MLO_LINK_STATE_INVALID, 89 MLO_LINK_STATE_UNASSOCIATED, 90 MLO_LINK_STATE_IDLE, 91 MLO_LINK_STATE_ACTIVE}) 92 public @interface MloLinkState {}; 93 94 private int mLinkId; 95 private MacAddress mApMacAddress; 96 private MacAddress mStaMacAddress; 97 private @MloLinkState int mState; 98 private @WifiAnnotations.WifiBandBasic int mBand; 99 private int mChannel; 100 101 /** 102 * Received Signal Strength Indicator 103 */ 104 private int mRssi; 105 106 /** 107 * Rx(receive) Link speed in Mbps 108 */ 109 private int mRxLinkSpeed; 110 111 /** 112 * Tx(transmit) Link speed in Mbps 113 */ 114 private int mTxLinkSpeed; 115 116 /** 117 * Constructor for a MloLInk. 118 */ MloLink()119 public MloLink() { 120 mBand = WifiScanner.WIFI_BAND_UNSPECIFIED; 121 mChannel = 0; 122 mState = MLO_LINK_STATE_UNASSOCIATED; 123 mApMacAddress = null; 124 mStaMacAddress = null; 125 mLinkId = INVALID_MLO_LINK_ID; 126 mRssi = WifiInfo.INVALID_RSSI; 127 mRxLinkSpeed = WifiInfo.LINK_SPEED_UNKNOWN; 128 mTxLinkSpeed = WifiInfo.LINK_SPEED_UNKNOWN; 129 } 130 131 /** 132 * Copy Constructor 133 * 134 * @hide 135 */ MloLink(MloLink source, long redactions)136 public MloLink(MloLink source, long redactions) { 137 mBand = source.mBand; 138 mChannel = source.mChannel; 139 mLinkId = source.mLinkId; 140 mState = source.mState; 141 mRssi = source.mRssi; 142 mRxLinkSpeed = source.mRxLinkSpeed; 143 mTxLinkSpeed = source.mTxLinkSpeed; 144 mLostTxPacketsPerSecond = source.mLostTxPacketsPerSecond; 145 mTxRetriedTxPacketsPerSecond = source.mTxRetriedTxPacketsPerSecond; 146 mSuccessfulRxPacketsPerSecond = source.mSuccessfulRxPacketsPerSecond; 147 mSuccessfulTxPacketsPerSecond = source.mSuccessfulTxPacketsPerSecond; 148 txBad = source.txBad; 149 txRetries = source.txRetries; 150 txSuccess = source.txSuccess; 151 rxSuccess = source.rxSuccess; 152 153 mStaMacAddress = ((redactions & NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS) != 0) 154 || source.mStaMacAddress == null 155 ? null : MacAddress.fromString(source.mStaMacAddress.toString()); 156 157 mApMacAddress = ((redactions & NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION) != 0) 158 || source.mApMacAddress == null 159 ? null : MacAddress.fromString(source.mApMacAddress.toString()); 160 } 161 162 /** Returns the Wi-Fi band of this link. */ 163 @ScanResult.WifiBand getBand()164 public int getBand() { 165 return mBand; 166 } 167 168 /** 169 * Returns the channel number of this link. 170 * A valid value is based on the 802.11 specification in sections 19.3.15 and 27.3.23 171 */ 172 @IntRange(from = 1) getChannel()173 public int getChannel() { 174 return mChannel; 175 } 176 177 /** 178 * Returns the link id of this link. 179 * Valid values are 0-15, as described in IEEE 802.11be Specification, section 9.4.2.295b.2. 180 * 181 * @return {@link #INVALID_MLO_LINK_ID} or a valid value (0-15). 182 */ 183 @IntRange(from = INVALID_MLO_LINK_ID, to = MAX_MLO_LINK_ID) getLinkId()184 public int getLinkId() { 185 return mLinkId; 186 } 187 188 /** Returns the state of this link as one of: 189 * {@link #MLO_LINK_STATE_INVALID} 190 * {@link #MLO_LINK_STATE_UNASSOCIATED} 191 * {@link #MLO_LINK_STATE_IDLE} 192 * {@link #MLO_LINK_STATE_ACTIVE} 193 */ getState()194 public @MloLinkState int getState() { 195 return mState; 196 } 197 198 /** 199 * Returns the AP MAC address of this link. 200 * 201 * @return AP MAC address for this link or null when the caller has insufficient 202 * permissions to access the access point MAC Address. 203 */ getApMacAddress()204 public @Nullable MacAddress getApMacAddress() { 205 return mApMacAddress; 206 } 207 208 /** 209 * Returns the STA MAC address of this link. 210 * 211 * @return STA MAC address assigned for this link, or null in the following cases: 212 * <ul> 213 * <li> The caller has insufficient permissions to access the STA MAC Address </li> 214 * <li> Link is not associated, hence no MAC address is assigned to it by STA </li> 215 * </ul> 216 */ getStaMacAddress()217 public @Nullable MacAddress getStaMacAddress() { 218 return mStaMacAddress; 219 } 220 221 /** 222 * Sets the channel number of this link. 223 * 224 * @hide 225 */ setChannel(int channel)226 public void setChannel(int channel) { 227 mChannel = channel; 228 } 229 230 /** 231 * Sets the band for this link 232 * 233 * @hide 234 */ setBand(@ifiAnnotations.WifiBandBasic int band)235 public void setBand(@WifiAnnotations.WifiBandBasic int band) { 236 mBand = band; 237 } 238 239 /** 240 * Sets the linkId of this link 241 * 242 * @hide 243 */ setLinkId(int linkId)244 public void setLinkId(int linkId) { 245 mLinkId = linkId; 246 } 247 248 /** 249 * Sets the state of this link 250 * 251 * @hide 252 */ setState(@loLinkState int state)253 public void setState(@MloLinkState int state) { 254 mState = state; 255 } 256 257 /** 258 * set the AP MAC Address for this link 259 * 260 * @hide 261 */ setApMacAddress(MacAddress address)262 public void setApMacAddress(MacAddress address) { 263 mApMacAddress = address; 264 } 265 266 /** 267 * set the STA MAC Address for this link 268 * 269 * @hide 270 */ setStaMacAddress(MacAddress address)271 public void setStaMacAddress(MacAddress address) { 272 mStaMacAddress = address; 273 } 274 275 /** 276 * Update the last received packet bit rate in Mbps. 277 * @hide 278 */ setRxLinkSpeedMbps(int rxLinkSpeed)279 public void setRxLinkSpeedMbps(int rxLinkSpeed) { 280 mRxLinkSpeed = rxLinkSpeed; 281 } 282 283 /** 284 * Returns the current receive link speed in Mbps. 285 * @return the Rx link speed or {@link WifiInfo#LINK_SPEED_UNKNOWN} if link speed is unknown. 286 * @see WifiInfo#LINK_SPEED_UNKNOWN 287 */ 288 @IntRange(from = -1) getRxLinkSpeedMbps()289 public int getRxLinkSpeedMbps() { 290 return mRxLinkSpeed; 291 } 292 293 /** 294 * Update the last transmitted packet bit rate in Mbps. 295 * @hide 296 */ setTxLinkSpeedMbps(int txLinkSpeed)297 public void setTxLinkSpeedMbps(int txLinkSpeed) { 298 mTxLinkSpeed = txLinkSpeed; 299 } 300 301 /** 302 * Returns the current transmit link speed in Mbps. 303 * @return the Tx link speed or {@link WifiInfo#LINK_SPEED_UNKNOWN} if link speed is unknown. 304 * @see WifiInfo#LINK_SPEED_UNKNOWN 305 */ 306 @IntRange(from = -1) getTxLinkSpeedMbps()307 public int getTxLinkSpeedMbps() { 308 return mTxLinkSpeed; 309 } 310 311 /** 312 * Sets the RSSI of the link. 313 * 314 * @param rssi RSSI in dBM. 315 * @hide 316 */ setRssi(int rssi)317 public void setRssi(int rssi) { 318 if (rssi < WifiInfo.INVALID_RSSI) rssi = WifiInfo.INVALID_RSSI; 319 if (rssi > WifiInfo.MAX_RSSI) rssi = WifiInfo.MAX_RSSI; 320 mRssi = rssi; 321 } 322 323 /** 324 * Returns the RSSI of the link. 325 * 326 * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into 327 * an absolute signal level which can be displayed to a user. 328 * 329 * @return RSSI in dBM. 330 */ getRssi()331 public int getRssi() { 332 return mRssi; 333 } 334 335 /** 336 * Running total count of lost (not ACKed) transmitted unicast data packets. 337 * 338 * @hide 339 */ 340 public long txBad; 341 /** 342 * Running total count of transmitted unicast data retry packets. 343 * 344 * @hide 345 */ 346 public long txRetries; 347 /** 348 * Running total count of successfully transmitted (ACKed) unicast data packets. 349 * 350 * @hide 351 */ 352 public long txSuccess; 353 /** 354 * Running total count of received unicast data packets. 355 * 356 * @hide 357 */ 358 public long rxSuccess; 359 /** 360 * Time stamp when packet counts are last updated. 361 * 362 * @hide 363 */ 364 public long lastPacketCountUpdateTimeStamp = Long.MIN_VALUE; 365 366 private double mLostTxPacketsPerSecond; 367 368 /** 369 * Average rate of lost transmitted packets, in units of packets per second. 370 * 371 * @hide 372 */ getLostTxPacketsPerSecond()373 public double getLostTxPacketsPerSecond() { 374 return mLostTxPacketsPerSecond; 375 } 376 377 /** @hide */ setLostTxPacketsPerSecond(double lostTxPacketsPerSecond)378 public void setLostTxPacketsPerSecond(double lostTxPacketsPerSecond) { 379 mLostTxPacketsPerSecond = lostTxPacketsPerSecond; 380 } 381 382 private double mTxRetriedTxPacketsPerSecond; 383 384 /** 385 * Average rate of transmitted retry packets, in units of packets per second. 386 * 387 * @hide 388 */ getRetriedTxPacketsPerSecond()389 public double getRetriedTxPacketsPerSecond() { 390 return mTxRetriedTxPacketsPerSecond; 391 } 392 393 /** @hide */ setRetriedTxPacketsRate(double txRetriedTxPacketsPerSecond)394 public void setRetriedTxPacketsRate(double txRetriedTxPacketsPerSecond) { 395 mTxRetriedTxPacketsPerSecond = txRetriedTxPacketsPerSecond; 396 } 397 398 private double mSuccessfulTxPacketsPerSecond; 399 400 /** 401 * Average rate of successfully transmitted unicast packets, in units of packets per second. 402 * 403 * @hide 404 */ getSuccessfulTxPacketsPerSecond()405 public double getSuccessfulTxPacketsPerSecond() { 406 return mSuccessfulTxPacketsPerSecond; 407 } 408 409 /** @hide */ setSuccessfulTxPacketsPerSecond(double successfulTxPacketsPerSecond)410 public void setSuccessfulTxPacketsPerSecond(double successfulTxPacketsPerSecond) { 411 mSuccessfulTxPacketsPerSecond = successfulTxPacketsPerSecond; 412 } 413 414 private double mSuccessfulRxPacketsPerSecond; 415 416 /** 417 * Average rate of received unicast data packets, in units of packets per second. 418 * 419 * @hide 420 */ getSuccessfulRxPacketsPerSecond()421 public double getSuccessfulRxPacketsPerSecond() { 422 return mSuccessfulRxPacketsPerSecond; 423 } 424 425 /** @hide */ setSuccessfulRxPacketsPerSecond(double successfulRxPacketsPerSecond)426 public void setSuccessfulRxPacketsPerSecond(double successfulRxPacketsPerSecond) { 427 mSuccessfulRxPacketsPerSecond = successfulRxPacketsPerSecond; 428 } 429 430 @Override equals(@ullable Object o)431 public boolean equals(@Nullable Object o) { 432 if (this == o) return true; 433 if (o == null || getClass() != o.getClass()) return false; 434 MloLink that = (MloLink) o; 435 return mBand == that.mBand 436 && mChannel == that.mChannel 437 && mLinkId == that.mLinkId 438 && Objects.equals(mApMacAddress, that.mApMacAddress) 439 && Objects.equals(mStaMacAddress, that.mStaMacAddress) 440 && mState == that.mState 441 && mRssi == that.mRssi 442 && mRxLinkSpeed == that.mRxLinkSpeed 443 && mTxLinkSpeed == that.mTxLinkSpeed 444 && mTxRetriedTxPacketsPerSecond == that.mTxRetriedTxPacketsPerSecond 445 && mSuccessfulTxPacketsPerSecond == that.mSuccessfulTxPacketsPerSecond 446 && mLostTxPacketsPerSecond == that.mLostTxPacketsPerSecond 447 && mSuccessfulRxPacketsPerSecond == that.mSuccessfulRxPacketsPerSecond 448 && txBad == that.txBad 449 && txRetries == that.txRetries 450 && txSuccess == that.txSuccess 451 && rxSuccess == that.rxSuccess; 452 } 453 454 @Override hashCode()455 public int hashCode() { 456 return Objects.hash( 457 mBand, 458 mChannel, 459 mLinkId, 460 mApMacAddress, 461 mStaMacAddress, 462 mState, 463 mRssi, 464 mRxLinkSpeed, 465 mTxLinkSpeed, 466 mTxRetriedTxPacketsPerSecond, 467 mSuccessfulTxPacketsPerSecond, 468 mLostTxPacketsPerSecond, 469 mSuccessfulRxPacketsPerSecond, 470 txBad, 471 txRetries, 472 txSuccess, 473 rxSuccess); 474 } 475 476 /** @hide */ getStateString(@loLinkState int state)477 public static String getStateString(@MloLinkState int state) { 478 switch(state) { 479 case MLO_LINK_STATE_INVALID: 480 return "MLO_LINK_STATE_INVALID"; 481 case MLO_LINK_STATE_UNASSOCIATED: 482 return "MLO_LINK_STATE_UNASSOCIATED"; 483 case MLO_LINK_STATE_IDLE: 484 return "MLO_LINK_STATE_IDLE"; 485 case MLO_LINK_STATE_ACTIVE: 486 return "MLO_LINK_STATE_ACTIVE"; 487 default: 488 return "Unknown MLO link state"; 489 } 490 } 491 492 /** 493 * @hide 494 */ isValidState(@loLinkState int state)495 public static boolean isValidState(@MloLinkState int state) { 496 switch(state) { 497 case MLO_LINK_STATE_INVALID: 498 case MLO_LINK_STATE_UNASSOCIATED: 499 case MLO_LINK_STATE_IDLE: 500 case MLO_LINK_STATE_ACTIVE: 501 return true; 502 } 503 return false; 504 } 505 506 @Override toString()507 public String toString() { 508 StringBuilder sb = new StringBuilder("MloLink{"); 509 if (mBand == WIFI_BAND_24_GHZ) { 510 sb.append("2.4GHz"); 511 } else if (mBand == WIFI_BAND_5_GHZ) { 512 sb.append("5GHz"); 513 } else if (mBand == WIFI_BAND_6_GHZ) { 514 sb.append("6GHz"); 515 } else { 516 sb.append("UNKNOWN BAND"); 517 } 518 sb.append(", channel: ").append(mChannel); 519 sb.append(", id: ").append(mLinkId); 520 sb.append(", state: ").append(getStateString(mState)); 521 sb.append(", RSSI: ").append(getRssi()); 522 sb.append(", Rx Link speed: ").append(getRxLinkSpeedMbps()).append( 523 WifiInfo.LINK_SPEED_UNITS); 524 sb.append(", Tx Link speed: ").append(getTxLinkSpeedMbps()).append( 525 WifiInfo.LINK_SPEED_UNITS); 526 if (mApMacAddress != null) { 527 sb.append(", AP MAC Address: ").append(mApMacAddress.toString()); 528 } 529 if (mStaMacAddress != null) { 530 sb.append(", STA MAC Address: ").append(mStaMacAddress.toString()); 531 } 532 sb.append('}'); 533 return sb.toString(); 534 } 535 536 /** Implement the Parcelable interface */ 537 @Override describeContents()538 public int describeContents() { 539 return 0; 540 } 541 542 /** Implement the Parcelable interface */ 543 @Override writeToParcel(@onNull Parcel dest, int flags)544 public void writeToParcel(@NonNull Parcel dest, int flags) { 545 dest.writeInt(mBand); 546 dest.writeInt(mChannel); 547 dest.writeInt(mLinkId); 548 dest.writeInt(mState); 549 dest.writeInt(mRssi); 550 dest.writeInt(mRxLinkSpeed); 551 dest.writeInt(mTxLinkSpeed); 552 dest.writeParcelable(mApMacAddress, flags); 553 dest.writeParcelable(mStaMacAddress, flags); 554 dest.writeDouble(mLostTxPacketsPerSecond); 555 dest.writeDouble(mSuccessfulTxPacketsPerSecond); 556 dest.writeDouble(mSuccessfulRxPacketsPerSecond); 557 dest.writeDouble(mTxRetriedTxPacketsPerSecond); 558 dest.writeLong(txBad); 559 dest.writeLong(txRetries); 560 dest.writeLong(txSuccess); 561 dest.writeLong(rxSuccess); 562 } 563 564 /** Implement the Parcelable interface */ 565 public static final @NonNull Creator<MloLink> CREATOR = 566 new Creator<MloLink>() { 567 public MloLink createFromParcel(Parcel in) { 568 MloLink link = new MloLink(); 569 link.mBand = in.readInt(); 570 link.mChannel = in.readInt(); 571 link.mLinkId = in.readInt(); 572 link.mState = in.readInt(); 573 link.mRssi = in.readInt(); 574 link.mRxLinkSpeed = in.readInt(); 575 link.mTxLinkSpeed = in.readInt(); 576 link.mApMacAddress = in.readParcelable(MacAddress.class.getClassLoader()); 577 link.mStaMacAddress = in.readParcelable(MacAddress.class.getClassLoader()); 578 link.mLostTxPacketsPerSecond = in.readDouble(); 579 link.mSuccessfulTxPacketsPerSecond = in.readDouble(); 580 link.mSuccessfulRxPacketsPerSecond = in.readDouble(); 581 link.mTxRetriedTxPacketsPerSecond = in.readDouble(); 582 link.txBad = in.readLong(); 583 link.txRetries = in.readLong(); 584 link.txSuccess = in.readLong(); 585 link.rxSuccess = in.readLong(); 586 return link; 587 } 588 589 public MloLink[] newArray(int size) { 590 return new MloLink[size]; 591 } 592 }; 593 } 594