[wlan][common] Channel utilities for CBW80 and beyond
Check wlan_channel_t validity for CBW80, CBW80P80, CBW160.
Calculate center frequency in MHz and in channel index
Test: Unit test included
Change-Id: I69e81f8e625d7b889a219fca598ee38713994ddd
diff --git a/lib/wlan/common/channel.cpp b/lib/wlan/common/channel.cpp
index e32256a..3d88c7d 100644
--- a/lib/wlan/common/channel.cpp
+++ b/lib/wlan/common/channel.cpp
@@ -72,6 +72,12 @@
bool IsValidChan5Ghz(const wlan_channel_t& chan) {
uint8_t p = chan.primary;
+ uint8_t s = chan.secondary80;
+
+ // See IEEE Std 802.11-2016, Table 9-252, 9-253
+ // TODO(porce): Augment wlan_channel_t to carry
+ // "channel width" subfield of VHT Operation Info of VHT Operation IE.
+ // Test the validity of CCFS1, and the relation to the CCFS0.
if (p < 36 || p > 173) { return false; }
if (p > 64 && p < 100) { return false; }
@@ -93,6 +99,19 @@
case CBW80:
if (p == 165) { return false; }
break;
+ case CBW80P80: {
+ if (!(s == 42 || s == 58 || s == 106 || s == 122 || s == 138 || s == 155)) { return false; }
+
+ uint8_t ccfs0 = GetCenterChanIdx(chan);
+ uint8_t ccfs1 = s;
+ uint8_t gap = (ccfs0 >= ccfs1) ? (ccfs0 - ccfs1) : (ccfs1 - ccfs0);
+ if (gap <= 16) { return false; }
+ break;
+ }
+ case CBW160: {
+ if (p >= 132) { return false; }
+ break;
+ }
default:
return false;
}
@@ -117,26 +136,55 @@
if (Is2Ghz(chan)) {
channel_starting_frequency = kBaseFreq2Ghz;
} else {
- // 5Ghz
+ // 5 GHz
channel_starting_frequency = kBaseFreq5Ghz;
}
// IEEE Std 802.11-2016, 21.3.14
- return channel_starting_frequency + spacing * chan.primary;
+ return channel_starting_frequency + spacing * GetCenterChanIdx(chan);
}
+// Returns the channel index corresponding to the first frequency segment's center frequency
uint8_t GetCenterChanIdx(const wlan_channel_t& chan) {
- ZX_DEBUG_ASSERT(IsValidChan(chan));
-
+ uint8_t p = chan.primary;
switch (chan.cbw) {
case CBW20:
- return chan.primary;
+ return p;
case CBW40ABOVE:
- return chan.primary + 2;
+ return p + 2;
case CBW40BELOW:
- return chan.primary - 2;
+ return p - 2;
+ case CBW80:
+ case CBW80P80:
+ if (p <= 48) {
+ return 42;
+ } else if (p <= 64) {
+ return 58;
+ } else if (p <= 112) {
+ return 106;
+ } else if (p <= 128) {
+ return 122;
+ } else if (p <= 144) {
+ return 138;
+ } else if (p <= 161) {
+ return 155;
+ } else {
+ // Not reachable
+ return p;
+ }
+ case CBW160:
+ // See IEEE Std 802.11-2016 Table 9-252 and 9-253.
+ // Note CBW160 has only one frequency segment, regardless of
+ // encodings on CCFS0 and CCFS1 in VHT Operation Information IE.
+ if (p <= 64) {
+ return 50;
+ } else if (p <= 128) {
+ return 114;
+ } else {
+ // Not reachable
+ return p;
+ }
default:
- // TODO(porce): Support CBW80 and beyond
return chan.primary;
}
}
diff --git a/lib/wlan/mlme/tests/channel_unittest.cpp b/lib/wlan/mlme/tests/channel_unittest.cpp
index c15eace..0cc519b 100644
--- a/lib/wlan/mlme/tests/channel_unittest.cpp
+++ b/lib/wlan/mlme/tests/channel_unittest.cpp
@@ -17,50 +17,38 @@
protected:
};
-struct TestVector {
- uint8_t primary;
- uint8_t cbw;
- bool want;
-};
-
-struct TestVectorCbw {
- uint8_t primary;
- uint8_t cbw;
- uint8_t want;
-};
-
TEST_F(ChannelTest, ValidCombo) {
- TestVector tvs[] = {
+ std::vector<wlan_channel_t> tvs = {
// clang-format off
- {1, CBW20, true},
- {11, CBW20, true},
- {1, CBW40ABOVE, true},
- {6, CBW40ABOVE, true},
- {6, CBW40BELOW, true},
- {11, CBW40BELOW, true},
- {36, CBW40ABOVE, true},
- {40, CBW40BELOW, true},
- {100, CBW40ABOVE, true},
- {104, CBW40BELOW, true},
- {149, CBW40ABOVE, true},
- {153, CBW40BELOW, true},
- {36, CBW80, true},
- {40, CBW80, true},
- {100, CBW80, true},
- {149, CBW80, true},
- {161, CBW80, true},
- // Add more interesting cases
+ { 1, CBW20, 0},
+ { 11, CBW20, 0},
+ { 1, CBW40ABOVE, 0},
+ { 6, CBW40ABOVE, 0},
+ { 6, CBW40BELOW, 0},
+ { 11, CBW40BELOW, 0},
+ { 36, CBW40ABOVE, 0},
+ { 40, CBW40BELOW, 0},
+ {100, CBW40ABOVE, 0},
+ {104, CBW40BELOW, 0},
+ {149, CBW40ABOVE, 0},
+ {153, CBW40BELOW, 0},
+ { 36, CBW80, 0},
+ { 40, CBW80, 0},
+ {100, CBW80, 0},
+ {149, CBW80, 0},
+ {161, CBW80, 0},
+ { 36, CBW80P80, 106},
+ { 52, CBW80P80, 106},
+ {100, CBW80P80, 42},
+ {149, CBW80P80, 42},
+ {161, CBW80P80, 42},
+ { 36, CBW160, 0},
+ {100, CBW160, 0},
// clang-format on
};
- for (uint32_t i = 0; i < sizeof(tvs) / sizeof(TestVector); i++) {
- wlan_channel_t chan = {
- .primary = tvs[i].primary,
- .cbw = tvs[i].cbw,
- };
- bool want = tvs[i].want;
-
- EXPECT_EQ(want, IsValidChan(chan));
+ for (auto tv : tvs) {
+ EXPECT_TRUE(IsValidChan(tv));
}
}
@@ -90,38 +78,46 @@
}
TEST_F(ChannelTest, InvalidCombo) {
- std::vector<TestVector> tvs = {
+ std::vector<wlan_channel_t> tvs = {
// clang-format off
- {0, CBW20, false},
- {15, CBW20, false},
- {8, CBW40ABOVE, false},
- {4, CBW40BELOW, false},
- {32, CBW20, false},
- {68, CBW20, false},
- {96, CBW20, false},
- {148, CBW20, false},
- {169, CBW20, true},
- {183, CBW20, false},
- {36, CBW40BELOW, false},
- {40, CBW40ABOVE, false},
- {149, CBW40BELOW, false},
- {153, CBW40ABOVE, false},
- {165, CBW80, false},
+ { 0, CBW20, 0},
+ { 15, CBW20, 0},
+ { 8, CBW40ABOVE, 0},
+ { 4, CBW40BELOW, 0},
+ { 32, CBW20, 0},
+ { 68, CBW20, 0},
+ { 96, CBW20, 0},
+ {148, CBW20, 0},
+ {183, CBW20, 0},
+ { 36, CBW40BELOW, 0},
+ { 40, CBW40ABOVE, 0},
+ {149, CBW40BELOW, 0},
+ {153, CBW40ABOVE, 0},
+ {165, CBW80, 0},
+ { 36, CBW80P80, 0},
+ { 48, CBW80P80, 42},
+ {149, CBW80P80, 155},
+ {132, CBW160, 50},
// Add more interesting cases
// clang-format on
};
- for (TestVector tv : tvs) {
- wlan_channel_t chan = {
- .primary = tv.primary,
- .cbw = tv.cbw,
- };
-
- EXPECT_EQ(tv.want, IsValidChan(chan));
+ for (auto tv : tvs) {
+ if (IsValidChan(tv)) {
+ printf("Test failed: Should treat this channel invalid:: %s\n",
+ wlan::common::ChanStrLong(tv).c_str());
+ }
+ EXPECT_FALSE(IsValidChan(tv));
}
}
TEST_F(ChannelTest, GetValidCbw) {
+ struct TestVectorCbw {
+ uint8_t primary;
+ uint8_t cbw;
+ uint8_t want;
+ };
+
std::vector<TestVectorCbw> tvs = {
// clang-format off
{1, CBW20, CBW20},
@@ -179,6 +175,65 @@
}
}
+TEST_F(ChannelTest, GetCenterChanIdx) {
+ struct TestVector {
+ wlan_channel_t ddk;
+ uint8_t want;
+ };
+
+ std::vector<TestVector> tvs = {
+ // clang-format off
+ {{ 1, CBW20, 0}, 1},
+ {{ 11, CBW20, 0}, 11},
+ {{ 36, CBW20, 0}, 36},
+ {{161, CBW20, 0}, 161},
+ {{ 1, CBW40ABOVE, 0}, 3},
+ {{ 5, CBW40ABOVE, 0}, 7},
+ {{ 5, CBW40BELOW, 0}, 3},
+ {{ 11, CBW40BELOW, 0}, 9},
+ {{ 36, CBW40ABOVE, 0}, 38},
+ {{ 36, CBW80, 0}, 42},
+ {{104, CBW80, 0}, 106},
+ {{ 36, CBW80P80, 122}, 42},
+ {{ 36, CBW160, 0}, 50},
+ {{100, CBW160, 0}, 114}
+ // clang-format on
+ };
+
+ for (auto tv : tvs) {
+ auto got = GetCenterChanIdx(tv.ddk);
+ EXPECT_EQ(tv.want, got);
+ }
+}
+
+TEST_F(ChannelTest, GetCenterFreq) {
+ struct TestVector {
+ wlan_channel_t ddk;
+ Mhz want;
+ };
+
+ std::vector<TestVector> tvs = {
+ // clang-format off
+ {{ 1, CBW20, 0}, 2412},
+ {{ 1, CBW40ABOVE, 0}, 2422},
+ {{ 6, CBW40ABOVE, 0}, 2447},
+ {{ 6, CBW40BELOW, 0}, 2427},
+ {{ 11, CBW20, 0}, 2462},
+ {{ 11, CBW40BELOW, 0}, 2452},
+ {{ 36, CBW20, 0}, 5180},
+ {{ 36, CBW40ABOVE, 0}, 5190},
+ {{ 36, CBW80, 0}, 5210},
+ {{ 36, CBW160, 0}, 5250},
+ {{161, CBW20, 0}, 5805},
+ // clang-format on
+ };
+
+ for (auto tv : tvs) {
+ auto got = GetCenterFreq(tv.ddk);
+ EXPECT_EQ(tv.want, got);
+ }
+}
+
} // namespace
} // namespace common
} // namespace wlan
diff --git a/lib/wlan/protocol/include/wlan/protocol/info.h b/lib/wlan/protocol/include/wlan/protocol/info.h
index 48a1ca1..c30201c 100644
--- a/lib/wlan/protocol/include/wlan/protocol/info.h
+++ b/lib/wlan/protocol/include/wlan/protocol/info.h
@@ -38,8 +38,9 @@
typedef struct wlan_channel {
uint8_t primary;
- uint8_t cbw; // Channel band width. See enum CBW.
- uint8_t secondary80;
+ uint8_t cbw; // Channel Bandwidth
+ uint8_t secondary80; // Channel index corresponding to the center frequency
+ // of the secondary frequency segment
} wlan_channel_t;
enum {