Files
wlan-cloud-rrm/src/main/java/com/facebook/openwifirrm/ucentral/operationelement/VHTOperationElement.java
2022-09-27 14:11:32 -04:00

176 lines
6.2 KiB
Java

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.operationelement;
import java.util.Arrays;
import java.util.Objects;
import org.apache.commons.codec.binary.Base64;
/**
* Very High Throughput (VHT) Operation Element, which is potentially present in
* wifiscan entries. Introduced in 802.11ac (2013).
*/
public class VHTOperationElement {
/**
* This field is 0 if the channel width is 20 MHz or 40 MHz, and 1 otherwise.
* Values of 2 and 3 are deprecated.
*/
public final byte channelWidth;
/**
* If the channel is 20 MHz, 40 MHz, or 80 MHz wide, this parameter is the
* channel number. E.g., the channel centered at 5180 MHz is channel 36. For a
* 160 MHz wide channel, this parameter is the channel number of the 80MHz
* channel that contains the primary channel. For a 80+80 MHz wide channel, this
* parameter is the channel number of the primary channel.
* <p>
* This field is an unsigned byte in the specification (i.e., with values
* between 0 and 255). But because Java only supports signed bytes, a short
* data type is used to store the value.
*/
public final short channel1;
/**
* This should be zero unless the channel is 160MHz or 80+80 MHz wide. If the
* channel is 160 MHz wide, this parameter is the channel number of the 160 MHz
* wide channel. If the channel is 80+80 MHz wide, this parameter is the channel
* index of the secondary 80 MHz wide channel.
* <p>
* This field is an unsigned byte in the specification (i.e., with values
* between 0 and 255). But because Java only supports signed bytes, a short
* data type is used to store the value.
*/
public final short channel2;
/**
* An 8-element array where each element is between 0 and 4 inclusive. MCS means
* Modulation and Coding Scheme. NSS means Number of Spatial Streams. There can
* be 1, 2, ..., or 8 spatial streams. For each NSS, the corresponding element
* in the array should specify which MCSs are supported for that NSS in the
* following manner: 0 indicates support for VHT-MCS 0-7, 1 indicates support
* for VHT-MCS 0-8, 2 indicates support for VHT-MCS 0-9, and 3 indicates that no
* VHT-MCS is supported for that NSS. For the specifics of what each VHT-MCS is,
* see IEEE 802.11-2020, Table "21-29" through Table "21-60".
*/
public final byte[] vhtMcsForNss;
/**
* Constructs a {@code VHTOperationElement} by decoding {@code vhtOper}.
*
* @param vhtOper a base64 encoded properly formatted VHT operation element (see
* 802.11 standard)
*/
public VHTOperationElement(String vhtOper) {
byte[] bytes = Base64.decodeBase64(vhtOper);
this.channelWidth = bytes[0];
this.channel1 = (short) (bytes[1] & 0xff); // read as unsigned value
this.channel2 = (short) (bytes[2] & 0xff); // read as unsigned value
byte[] vhtMcsForNss = new byte[8];
vhtMcsForNss[0] = (byte) (bytes[3] >>> 6);
vhtMcsForNss[1] = (byte) ((bytes[3] & 0b00110000) >>> 4);
vhtMcsForNss[2] = (byte) ((bytes[3] & 0b00001100) >>> 2);
vhtMcsForNss[3] = (byte) (bytes[3] & 0b00000011);
vhtMcsForNss[4] = (byte) (bytes[4] >>> 6);
vhtMcsForNss[5] = (byte) ((bytes[4] & 0b00110000) >>> 4);
vhtMcsForNss[6] = (byte) ((bytes[4] & 0b00001100) >>> 2);
vhtMcsForNss[7] = (byte) (bytes[4] & 0b00000011);
this.vhtMcsForNss = vhtMcsForNss;
}
/**
* Constructs an {@code HTOperationElement} using the given field values. See
* 802.11 for more details.
* <p>
* For details about the parameters, see the javadocs for the corresponding
* member variables.
*/
public VHTOperationElement(
byte channelWidth,
short channel1,
short channel2,
byte[] vhtMcsForNss
) {
/*
* XXX some combinations of channelWidth, channel, channel2, and vhtMcsAtNss are
* invalid, but this is not checked here. If fidelity to 802.11 is required, the
* caller of this method must make sure to pass in valid parameters.
*/
this.channelWidth = channelWidth;
this.channel1 = channel1;
this.channel2 = channel2;
this.vhtMcsForNss = vhtMcsForNss;
}
/**
* Determine whether {@code this} and {@code other} "match" for the purpose of
* aggregating statistics.
*
* @param other another VHT operation element
* @return true if the the operation elements "match" for the purpose of
* aggregating statistics; false otherwise.
*/
public boolean matchesForAggregation(VHTOperationElement other) {
// check everything except vhtMcsForNss
return other != null && channel1 == other.channel1 &&
channel2 == other.channel2 && channelWidth == other.channelWidth;
}
/**
* Determines whether two VHT operation elements should have their statistics
* aggregated.
*
* @param vhtOper1 a base64 encoded properly formatted VHT operation element
* (see 802.11 standard)
*
* @param vhtOper2 a base64 encoded properly formatted VHT operation element
* (see 802.11 standard)
* @return true if the two inputs should have their statistics aggregated; false
* otherwise.
*/
public static boolean matchesVhtForAggregation(
String vhtOper1,
String vhtOper2
) {
if (Objects.equals(vhtOper1, vhtOper2)) {
return true; // true if both are null or they are equal
}
if (vhtOper1 == null || vhtOper2 == null) {
return false; // false if exactly one is null
}
VHTOperationElement vhtOperObj1 = new VHTOperationElement(vhtOper1);
VHTOperationElement vhtOperObj2 = new VHTOperationElement(vhtOper2);
return vhtOperObj1.matchesForAggregation(vhtOperObj2);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(vhtMcsForNss);
result =
prime * result + Objects.hash(channel1, channel2, channelWidth);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
VHTOperationElement other = (VHTOperationElement) obj;
return channel1 == other.channel1 && channel2 == other.channel2 &&
channelWidth == other.channelWidth &&
Arrays.equals(vhtMcsForNss, other.vhtMcsForNss);
}
}