summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/hotspot2/NetworkDetail.java37
-rw-r--r--service/java/com/android/server/wifi/util/InformationElementUtil.java125
-rw-r--r--tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java163
3 files changed, 285 insertions, 40 deletions
diff --git a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
index edee2da1a..36ed8592e 100644
--- a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
+++ b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
@@ -258,17 +258,28 @@ public class NetworkDetail {
mANQPElements = null;
//set up channel info
mPrimaryFreq = freq;
+ int channelWidth = ScanResult.UNSPECIFIED;
+ int centerFreq0 = 0;
+ int centerFreq1 = 0;
+
+ if (vhtOperation.isPresent()) {
+ channelWidth = vhtOperation.getChannelWidth();
+ if (channelWidth != ScanResult.UNSPECIFIED) {
+ centerFreq0 = vhtOperation.getCenterFreq0();
+ centerFreq1 = vhtOperation.getCenterFreq1();
+ }
+ }
- if (vhtOperation.isValid()) {
- // 80 or 160 MHz
- mChannelWidth = vhtOperation.getChannelWidth();
- mCenterfreq0 = vhtOperation.getCenterFreq0();
- mCenterfreq1 = vhtOperation.getCenterFreq1();
- } else {
- mChannelWidth = htOperation.getChannelWidth();
- mCenterfreq0 = htOperation.getCenterFreq0(mPrimaryFreq);
- mCenterfreq1 = 0;
+ if (channelWidth == ScanResult.UNSPECIFIED) {
+ //Either no vht, or vht shows BW is 40/20 MHz
+ if (htOperation.isPresent()) {
+ channelWidth = htOperation.getChannelWidth();
+ centerFreq0 = htOperation.getCenterFreq0(mPrimaryFreq);
+ }
}
+ mChannelWidth = channelWidth;
+ mCenterfreq0 = centerFreq0;
+ mCenterfreq1 = centerFreq1;
// If trafficIndicationMap is not valid, mDtimPeriod will be negative
if (trafficIndicationMap.isValid()) {
@@ -287,8 +298,7 @@ public class NetworkDetail {
maxRateA = supportedRates.mRates.get(supportedRates.mRates.size() - 1);
mMaxRate = maxRateA > maxRateB ? maxRateA : maxRateB;
mWifiMode = InformationElementUtil.WifiMode.determineMode(mPrimaryFreq, mMaxRate,
- vhtOperation.isValid(),
- iesFound.contains(ScanResult.InformationElement.EID_HT_OPERATION),
+ vhtOperation.isPresent(), htOperation.isPresent(),
iesFound.contains(ScanResult.InformationElement.EID_ERP));
} else {
mWifiMode = 0;
@@ -303,9 +313,8 @@ public class NetworkDetail {
+ ", WifiMode: " + InformationElementUtil.WifiMode.toString(mWifiMode)
+ ", Freq: " + mPrimaryFreq
+ ", mMaxRate: " + mMaxRate
- + ", VHT: " + String.valueOf(vhtOperation.isValid())
- + ", HT: " + String.valueOf(
- iesFound.contains(ScanResult.InformationElement.EID_HT_OPERATION))
+ + ", VHT: " + String.valueOf(vhtOperation.isPresent())
+ + ", HT: " + String.valueOf(htOperation.isPresent())
+ ", ERP: " + String.valueOf(
iesFound.contains(ScanResult.InformationElement.EID_ERP))
+ ", SupportedRates: " + supportedRates.toString()
diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java
index 3ed829d8c..61b600b97 100644
--- a/service/java/com/android/server/wifi/util/InformationElementUtil.java
+++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java
@@ -151,73 +151,148 @@ public class InformationElementUtil {
}
public static class HtOperation {
- public int secondChannelOffset = 0;
+ private static final int HT_OPERATION_IE_LEN = 22;
+ private boolean mPresent = false;
+ private int mSecondChannelOffset = 0;
+ /**
+ * returns if HT Operation IE present in the message.
+ */
+ public boolean isPresent() {
+ return mPresent;
+ }
+
+ /**
+ * Returns channel width if it is 20 or 40MHz
+ * Results will be invalid if channel width greater than 40MHz
+ * So caller should only call this method if VHT Operation IE is not present,
+ * or if VhtOperation.getChannelWidth() returns ScanResult.UNSPECIFIED.
+ */
public int getChannelWidth() {
- if (secondChannelOffset != 0) {
- return 1;
+ if (mSecondChannelOffset != 0) {
+ return ScanResult.CHANNEL_WIDTH_40MHZ;
} else {
- return 0;
+ return ScanResult.CHANNEL_WIDTH_20MHZ;
}
}
+ /**
+ * Returns channel Center frequency (for 20/40 MHz channels only)
+ * Results will be invalid for larger channel width,
+ * So, caller should only call this method if VHT Operation IE is not present,
+ * or if VhtOperation.getChannelWidth() returns ScanResult.UNSPECIFIED.
+ */
public int getCenterFreq0(int primaryFrequency) {
- //40 MHz
- if (secondChannelOffset != 0) {
- if (secondChannelOffset == 1) {
+ if (mSecondChannelOffset != 0) {
+ //40 MHz
+ if (mSecondChannelOffset == 1) {
return primaryFrequency + 10;
- } else if (secondChannelOffset == 3) {
+ } else if (mSecondChannelOffset == 3) {
return primaryFrequency - 10;
} else {
- Log.e("HtOperation", "Error on secondChannelOffset: " + secondChannelOffset);
+ Log.e("HtOperation", "Error on secondChannelOffset: " + mSecondChannelOffset);
return 0;
}
} else {
- return 0;
+ //20 MHz
+ return primaryFrequency;
}
}
+ /**
+ * Parse the HT Operation IE to read the fields of interest.
+ */
public void from(InformationElement ie) {
if (ie.id != InformationElement.EID_HT_OPERATION) {
throw new IllegalArgumentException("Element id is not HT_OPERATION, : " + ie.id);
}
- secondChannelOffset = ie.bytes[1] & 0x3;
+ if (ie.bytes.length < HT_OPERATION_IE_LEN) {
+ throw new IllegalArgumentException("Invalid HT_OPERATION len: " + ie.bytes.length);
+ }
+ mPresent = true;
+ mSecondChannelOffset = ie.bytes[1] & 0x3;
}
}
public static class VhtOperation {
- public int channelMode = 0;
- public int centerFreqIndex1 = 0;
- public int centerFreqIndex2 = 0;
+ private static final int VHT_OPERATION_IE_LEN = 5;
+ private boolean mPresent = false;
+ private int mChannelMode = 0;
+ private int mCenterFreqIndex1 = 0;
+ private int mCenterFreqIndex2 = 0;
- public boolean isValid() {
- return channelMode != 0;
+ /**
+ * returns if VHT Operation IE present in the message.
+ */
+ public boolean isPresent() {
+ return mPresent;
}
+ /**
+ * Returns channel width if it is above 40MHz,
+ * otherwise, returns {@link ScanResult.UNSPECIFIED} to indicate that
+ * channel width should be obtained from the HT Operation IE via
+ * HtOperation.getChannelWidth().
+ */
public int getChannelWidth() {
- return channelMode + 1;
+ if (mChannelMode == 0) {
+ // 20 or 40MHz
+ return ScanResult.UNSPECIFIED;
+ } else if (mCenterFreqIndex2 == 0) {
+ // No secondary channel
+ return ScanResult.CHANNEL_WIDTH_80MHZ;
+ } else if (Math.abs(mCenterFreqIndex2 - mCenterFreqIndex1) == 8) {
+ // Primary and secondary channels adjacent
+ return ScanResult.CHANNEL_WIDTH_160MHZ;
+ } else {
+ // Primary and secondary channels not adjacent
+ return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
+ }
}
+ /**
+ * Returns center frequency of primary channel (if channel width greater than 40MHz),
+ * otherwise, it returns zero to indicate that center frequency should be obtained from
+ * the HT Operation IE via HtOperation.getCenterFreq0().
+ */
public int getCenterFreq0() {
- //convert channel index to frequency in MHz, channel 36 is 5180MHz
- return (centerFreqIndex1 - 36) * 5 + 5180;
+ if (mCenterFreqIndex1 == 0 || mChannelMode == 0) {
+ return 0;
+ } else {
+ //convert channel index to frequency in MHz, channel 36 is 5180MHz
+ return (mCenterFreqIndex1 - 36) * 5 + 5180;
+ }
}
+ /**
+ * Returns center frequency of secondary channel if exists (channel width greater than
+ * 40MHz), otherwise, it returns zero.
+ * Note that the secondary channel center frequency only applies to 80+80 or 160 MHz
+ * channels.
+ */
public int getCenterFreq1() {
- if (channelMode > 1) { //160MHz
- return (centerFreqIndex2 - 36) * 5 + 5180;
- } else {
+ if (mCenterFreqIndex2 == 0 || mChannelMode == 0) {
return 0;
+ } else {
+ //convert channel index to frequency in MHz, channel 36 is 5180MHz
+ return (mCenterFreqIndex2 - 36) * 5 + 5180;
}
}
+ /**
+ * Parse the VHT Operation IE to read the fields of interest.
+ */
public void from(InformationElement ie) {
if (ie.id != InformationElement.EID_VHT_OPERATION) {
throw new IllegalArgumentException("Element id is not VHT_OPERATION, : " + ie.id);
}
- channelMode = ie.bytes[0] & Constants.BYTE_MASK;
- centerFreqIndex1 = ie.bytes[1] & Constants.BYTE_MASK;
- centerFreqIndex2 = ie.bytes[2] & Constants.BYTE_MASK;
+ if (ie.bytes.length < VHT_OPERATION_IE_LEN) {
+ throw new IllegalArgumentException("Invalid VHT_OPERATION len: " + ie.bytes.length);
+ }
+ mPresent = true;
+ mChannelMode = ie.bytes[0] & Constants.BYTE_MASK;
+ mCenterFreqIndex1 = ie.bytes[1] & Constants.BYTE_MASK;
+ mCenterFreqIndex2 = ie.bytes[2] & Constants.BYTE_MASK;
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
index f46dd915f..c11b300e5 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,12 +21,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.net.wifi.ScanResult;
import android.net.wifi.ScanResult.InformationElement;
import androidx.test.filters.SmallTest;
import com.android.server.wifi.WifiBaseTest;
import com.android.server.wifi.hotspot2.NetworkDetail;
+import com.android.server.wifi.util.InformationElementUtil.HtOperation;
+import com.android.server.wifi.util.InformationElementUtil.VhtOperation;
import org.junit.Test;
@@ -1009,5 +1012,163 @@ public class InformationElementUtilTest extends WifiBaseTest {
assertEquals(0x112233445566L, interworking.hessid);
}
+ /**
+ * Verify that the expected HT Operation information element is parsed and retrieved from the
+ * list of IEs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getHtOperationElement() throws Exception {
+ final int primaryFreq = 2467;
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_HT_OPERATION;
+ /**
+ * HT Operation Format:
+ * | Primary Channel | HT Operation Info | Basic HT-MCS Set |
+ * 1 5 16
+ *
+ * HT Operation Info Format (relevant parts only):
+ *
+ * B0 B1 B2 -----
+ * | Secondary Channel Offset | STA Channel Width | Other |
+ */
+ ie.bytes = new byte[22];
+ ie.bytes[0] = (byte) 11;
+ ie.bytes[1] = (byte) 0x83; //Setting Secondary channel offset = 3
+ // Remaining bytes are not relevant
+
+ HtOperation htOperation = new HtOperation();
+ htOperation.from(ie);
+
+ assertTrue(htOperation.isPresent());
+ assertEquals(ScanResult.CHANNEL_WIDTH_40MHZ, htOperation.getChannelWidth());
+ assertEquals(primaryFreq - 10, htOperation.getCenterFreq0(primaryFreq));
+ }
+
+ /**
+ * Verify that the expected VHT Operation information element is parsed and retrieved from the
+ * list of IEs.
+ * In this test case Channel BW is set to be 20/40 MHz
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getVhtOperationElement20_40Mhz() throws Exception {
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_VHT_OPERATION;
+ /**
+ * VHT Operation Format:
+ * | VHT Operation Info | Basic HT-MCS Set |
+ * 3 2
+ *
+ * VHT Operation Info Format:
+ * | Channel Width | Channel Center Freq Seg 0 | Channel Center Freq Seg 1 |
+ * 1 1 1
+ */
+ ie.bytes = new byte[]{(byte) 0x00, (byte) 0xF0, (byte) 0xF1, (byte) 0x00, (byte) 0x00};
+
+ VhtOperation vhtOperation = new VhtOperation();
+ vhtOperation.from(ie);
+
+ assertTrue(vhtOperation.isPresent());
+ assertEquals(ScanResult.UNSPECIFIED, vhtOperation.getChannelWidth());
+ assertEquals(0, vhtOperation.getCenterFreq0());
+ assertEquals(0, vhtOperation.getCenterFreq1());
+ }
+
+ /**
+ * Verify that the expected VHT Operation information element is parsed and retrieved from the
+ * list of IEs.
+ * In this test case Channel BW is set to be 80 MHz
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getVhtOperationElement80Mhz() throws Exception {
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_VHT_OPERATION;
+ /**
+ * VHT Operation Format:
+ * | VHT Operation Info | Basic HT-MCS Set |
+ * 3 2
+ *
+ * VHT Operation Info Format:
+ * | Channel Width | Channel Center Freq Seg 0 | Channel Center Freq Seg 1 |
+ * 1 1 1
+ */
+ ie.bytes = new byte[]{(byte) 0x01, (byte) 36, (byte) 0x00, (byte) 0x00, (byte) 0x00};
+
+ VhtOperation vhtOperation = new VhtOperation();
+ vhtOperation.from(ie);
+
+ assertTrue(vhtOperation.isPresent());
+ assertEquals(ScanResult.CHANNEL_WIDTH_80MHZ, vhtOperation.getChannelWidth());
+ assertEquals(5180, vhtOperation.getCenterFreq0());
+ assertEquals(0, vhtOperation.getCenterFreq1());
+ }
+
+ /**
+ * Verify that the expected VHT Operation information element is parsed and retrieved from the
+ * list of IEs.
+ * In this test case Channel BW is set to be 160 MHz
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getVhtOperationElement160Mhz() throws Exception {
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_VHT_OPERATION;
+ /**
+ * VHT Operation Format:
+ * | VHT Operation Info | Basic HT-MCS Set |
+ * 3 2
+ *
+ * VHT Operation Info Format:
+ * | Channel Width | Channel Center Freq Seg 0 | Channel Center Freq Seg 1 |
+ * 1 1 1
+ */
+ ie.bytes = new byte[]{(byte) 0x01, (byte) 44, (byte) 36, (byte) 0x00, (byte) 0x00};
+
+ VhtOperation vhtOperation = new VhtOperation();
+ vhtOperation.from(ie);
+
+ assertTrue(vhtOperation.isPresent());
+ assertEquals(ScanResult.CHANNEL_WIDTH_160MHZ, vhtOperation.getChannelWidth());
+ assertEquals(5220, vhtOperation.getCenterFreq0());
+ assertEquals(5180, vhtOperation.getCenterFreq1());
+ }
+
+ /**
+ * Verify that the expected VHT Operation information element is parsed and retrieved from the
+ * list of IEs.
+ * In this test case Channel BW is set to be 80+80 MHz
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getVhtOperationElement80PlusMhz() throws Exception {
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_VHT_OPERATION;
+ /**
+ * VHT Operation Format:
+ * | VHT Operation Info | Basic HT-MCS Set |
+ * 3 2
+ *
+ * VHT Operation Info Format:
+ * | Channel Width | Channel Center Freq Seg 0 | Channel Center Freq Seg 1 |
+ * 1 1 1
+ */
+ ie.bytes = new byte[]{(byte) 0x01, (byte) 54, (byte) 36, (byte) 0x00, (byte) 0x00};
+
+ VhtOperation vhtOperation = new VhtOperation();
+ vhtOperation.from(ie);
+
+ assertTrue(vhtOperation.isPresent());
+ assertEquals(ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ, vhtOperation.getChannelWidth());
+ assertEquals(5270, vhtOperation.getCenterFreq0());
+ assertEquals(5180, vhtOperation.getCenterFreq1());
+ }
+
// TODO: SAE, OWN, SUITE_B
}