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