Use ht operation element class decoder (#41)

This commit is contained in:
RockyMandayam2
2022-08-18 13:08:42 -07:00
committed by GitHub
parent 1daed90aa1
commit c27712cf90
4 changed files with 44 additions and 92 deletions

View File

@@ -10,7 +10,6 @@ package com.facebook.openwifirrm.optimizers.channel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -26,6 +25,8 @@ import com.facebook.openwifirrm.modules.Modeler.DataModel;
import com.facebook.openwifirrm.ucentral.UCentralConstants;
import com.facebook.openwifirrm.ucentral.UCentralUtils.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifirrm.ucentral.operationelement.HTOperationElement;
import com.facebook.openwifirrm.ucentral.operationelement.VHTOperationElement;
/**
* Channel optimizer base class.
@@ -179,15 +180,6 @@ public abstract class ChannelOptimizer {
}
}
/** Convert the input string into a byte array. */
private static byte[] decodeBase64(String s) {
try {
return Base64.getDecoder().decode(s);
} catch (IllegalArgumentException e) {
return null;
}
}
/**
* Get the channel width based on the HT operation and VHT operation in wifi scan.
* @param channel the current channel (from the scan result)
@@ -209,76 +201,33 @@ public abstract class ChannelOptimizer {
return MIN_CHANNEL_WIDTH;
}
// Decode HT operation information element
byte[] htOperDecode = decodeBase64(htOper);
if (htOperDecode == null) {
return MIN_CHANNEL_WIDTH;
}
// The second byte of HT operation contains the channel width information.
// The third bit (so we & 4 = 100 below) in the second byte is STA channel width.
// 0 for a 20 MHz channel width, 1 for any other channel widths.
int htChannelWidth = htOperDecode[1] & 4;
HTOperationElement htOperObj = new HTOperationElement(htOper);
if (vhtOper == null) {
// HT mode, it only supports 20/40 MHz
// Therefore, htChannelWidth > 0 means 40 MHz, htChannelWidth = 0 means 20 MHz.
if (htChannelWidth == 0) {
return 20;
// HT mode only supports 20/40 MHz
return htOperObj.staChannelWidth ? 40 : 20;
} else {
return 40;
}
} else {
// VHT/HE mode, it supports 20/40/160/8080 MHz
// Decode VHT operation information element
byte[] vhtOperDecode = decodeBase64(vhtOper);
if (vhtOperDecode == null) {
return MIN_CHANNEL_WIDTH;
}
// The first byte of VHT operation is channel width, which takes values 0-3.
// 0 for 20 MHz or 40 MHz
// 1 for 80 MHz, 160 MHz , or 80+80 MHz BSS bandwidth
// 2 and 3 are deprecated
int vhtChannelWidth = vhtOperDecode[0] & 255;
// The second byte of VHT operation is channel center frequency segment 0.
// For 80 MHz BSS bandwidth, indicates the channel center frequency index
// for the 80 MHz channel on which the VHT BSS operates.
// For 160 MHz or 80+80 MHz BSS bandwidth, it contains the channel center
// frequency index for the first 80 MHz channel.
int channelOffset1 = vhtOperDecode[1] & 255;
// The third byte of VHT operation is channel center frequency segment 1.
// For a 20, 40, or 80 MHz BSS bandwidth, this subfield is set to 0.
// For 160 MHz or 80+80 MHz BSS bandwidth, it contains the channel center
// frequency index for the second 80 MHz channel.
int channelOffset2 = vhtOperDecode[2] & 255;
if (htChannelWidth == 0 && vhtChannelWidth == 0) {
// VHT/HE mode supports 20/40/160/80+80 MHz
VHTOperationElement vhtOperObj = new VHTOperationElement(vhtOper);
if (!htOperObj.staChannelWidth && vhtOperObj.channelWidth == 0) {
return 20;
} else if (htChannelWidth > 0 && vhtChannelWidth == 0) {
} else if (htOperObj.staChannelWidth && vhtOperObj.channelWidth == 0) {
return 40;
} else if (
htChannelWidth > 0 &&
vhtChannelWidth == 1 &&
channelOffset2 == 0
) {
} else if (htOperObj.staChannelWidth && vhtOperObj.channelWidth == 1 && vhtOperObj.channel2 == 0) {
return 80;
} else if (
htChannelWidth > 0 &&
vhtChannelWidth == 1 &&
channelOffset2 != 0
htOperObj.staChannelWidth
&& vhtOperObj.channelWidth == 1
&& vhtOperObj.channel2 != 0
) {
// if it is 160 MHz, it use two consecutive 80 MHz bands
// the difference of 8 means it is consecutive
if (Math.abs(channelOffset1 - channelOffset2) == 8) {
return 160;
} else {
return 8080;
}
int channelDiff = Math.abs(vhtOperObj.channel1 - vhtOperObj.channel2);
// the "8080" below does not mean 8080 MHz wide, it refers to 80+80 MHz channel
return channelDiff == 8 ? 160 : 8080;
} else {
return MIN_CHANNEL_WIDTH;
}
}
}
/**

View File

@@ -20,7 +20,7 @@ import org.apache.commons.codec.binary.Base64;
public class HTOperationElement {
/** Channel number of the primary channel. */
private final byte primaryChannel;
public final byte primaryChannel;
/**
* Indicates the offset of the secondary channel relative to the primary
* channel. A 1 indicates that the secondary channel is above the primary
@@ -28,48 +28,48 @@ public class HTOperationElement {
* channel. A 0 indicates that there is no secondary channel present. The value
* 2 is reserved.
*/
private final byte secondaryChannelOffset;
public final byte secondaryChannelOffset;
/**
* Defines the channel widths that can be used to transmit to the STA. With
* exceptions, false allows a 20 MHz channel width. True allows use of any
* channel width in the supported channel width set. See 802.11 for exceptions.
*/
private final boolean staChannelWidth;
public final boolean staChannelWidth;
/** True if RIFS is permitted; false otherwise. */
private final boolean rifsMode;
public final boolean rifsMode;
/**
* A 0 indicates no protection mode. A 1 indicates nonmember protection mode. A
* 2 indicates 20 MHz protection mode. A 3 indicates non-HT mixed mode.
*/
private final byte htProtection;
public final byte htProtection;
/**
* False if all HT STAs that are associated are HT-greenfield capable or all HT
* peer mesh STAs are HT-greenfield capable; true otherwise.
*/
private final boolean nongreenfieldHtStasPresent;
public final boolean nongreenfieldHtStasPresent;
/**
* Indicates if the use of protection for non-HT STAs by overlapping BSSs is
* determined to be desirable. See 802.11 for details.
*/
private final boolean obssNonHtStasPresent;
public final boolean obssNonHtStasPresent;
/**
* Defines the channel center frequency for a 160 or 80+80 MHz BSS bandwidth
* with NSS support less than Max VHT NSS. This is 0 for non-VHT STAs. See
* 802.11 for details.
*/
private final byte channelCenterFrequencySegment2;
public final byte channelCenterFrequencySegment2;
/** False if no STBC beacon is transmitted; true otherwise. */
private final boolean dualBeacon;
public final boolean dualBeacon;
/** False if dual CTS protection is not required; true otherwise. */
private final boolean dualCtsProtection;
public final boolean dualCtsProtection;
/** False in a primary beacon. True in an STBC beacon. */
private final boolean stbcBeacon;
public final boolean stbcBeacon;
/**
* Indicates the HT-MCS values that are supported by all HT STAs in the BSS. A
* bitmap where a bit is set to 1 to indicate support for that MCS and 0
* otherwise, where bit 0 corresponds to MCS 0.
*/
private final byte[] basicHtMcsSet;
public final byte[] basicHtMcsSet;
/**
* Constructs an {@code HTOperationElement} using the given field values. See

View File

@@ -19,8 +19,11 @@ import org.apache.commons.codec.binary.Base64;
*/
public class VHTOperationElement {
/** False if the channel width is 20 MHz or 40 MHz; true otherwise. */
private final boolean channelWidthIndicator;
/**
* 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
@@ -28,14 +31,14 @@ public class VHTOperationElement {
* channel that contains the primary channel. For a 80+80 MHz wide channel, this
* parameter is the channel number of the primary channel.
*/
private final byte channel1;
public final byte 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.
*/
private final byte channel2;
public final byte 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
@@ -46,7 +49,7 @@ public class VHTOperationElement {
* 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".
*/
private final byte[] vhtMcsForNss;
public final byte[] vhtMcsForNss;
/**
* Constructs a {@code VHTOperationElement} by decoding {@code vhtOper}.
@@ -56,7 +59,7 @@ public class VHTOperationElement {
*/
public VHTOperationElement(String vhtOper) {
byte[] bytes = Base64.decodeBase64(vhtOper);
this.channelWidthIndicator = bytes[0] == 1;
this.channelWidth = bytes[0];
this.channel1 = bytes[1];
this.channel2 = bytes[2];
byte[] vhtMcsForNss = new byte[8];
@@ -78,13 +81,13 @@ public class VHTOperationElement {
* For details about the parameters, see the javadocs for the corresponding
* member variables.
*/
public VHTOperationElement(boolean channelWidthIndicator, byte channel1, byte channel2, byte[] vhtMcsForNss) {
public VHTOperationElement(byte channelWidth, byte channel1, byte 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.channelWidthIndicator = channelWidthIndicator;
this.channelWidth = channelWidth;
this.channel1 = channel1;
this.channel2 = channel2;
this.vhtMcsForNss = vhtMcsForNss;
@@ -101,7 +104,7 @@ public class VHTOperationElement {
public boolean matchesForAggregation(VHTOperationElement other) {
// check everything except vhtMcsForNss
return other != null && channel1 == other.channel1 && channel2 == other.channel2
&& channelWidthIndicator == other.channelWidthIndicator;
&& channelWidth == other.channelWidth;
}
/**
@@ -133,7 +136,7 @@ public class VHTOperationElement {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(vhtMcsForNss);
result = prime * result + Objects.hash(channel1, channel2, channelWidthIndicator);
result = prime * result + Objects.hash(channel1, channel2, channelWidth);
return result;
}
@@ -150,7 +153,7 @@ public class VHTOperationElement {
}
VHTOperationElement other = (VHTOperationElement) obj;
return channel1 == other.channel1 && channel2 == other.channel2
&& channelWidthIndicator == other.channelWidthIndicator
&& channelWidth == other.channelWidth
&& Arrays.equals(vhtMcsForNss, other.vhtMcsForNss);
}
}

View File

@@ -18,7 +18,7 @@ public class VHTOperationElementTest {
void testGetVhtOper() {
String vhtOper = "ACQAAAA=";
VHTOperationElement vhtOperObj = new VHTOperationElement(vhtOper);
boolean expectedChannelWidthIndicator = false; // 20 MHz channel width
byte expectedChannelWidthIndicator = 0; // 20 MHz channel width
byte expectedChannel1 = 36;
byte expectedChannel2 = 0;
byte[] expectedVhtMcsForNss = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -27,7 +27,7 @@ public class VHTOperationElementTest {
vhtOper = "AToAUAE=";
vhtOperObj = new VHTOperationElement(vhtOper);
expectedChannelWidthIndicator = true; // 80 MHz channel width
expectedChannelWidthIndicator = 1; // 80 MHz channel width
expectedChannel1 = 58;
// same channel2
expectedVhtMcsForNss = new byte[] { 1, 1, 0, 0, 0, 0, 0, 1 };