[wlan][mesh] Parse MPM Confirm actions and forward to SME
WLAN-844
Change-Id: I6a6fdf94280f17fe8b7c8ff4618efad7d4cc8736
diff --git a/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/mesh_mlme.h b/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/mesh_mlme.h
index 3bada20..43f8f0f 100644
--- a/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/mesh_mlme.h
+++ b/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/mesh_mlme.h
@@ -46,8 +46,9 @@
zx_status_t HandleAnyWlanFrame(fbl::unique_ptr<Packet> pkt);
zx_status_t HandleAnyMgmtFrame(MgmtFrame<>&& frame);
zx_status_t HandleActionFrame(const MgmtFrameHeader& mgmt, BufferReader* r);
- zx_status_t HandleSelfProtectedAction(common::MacAddr src_addr, BufferReader* r);
- zx_status_t HandleMpmOpenAction(common::MacAddr src_addr, BufferReader* r);
+ zx_status_t HandleSelfProtectedAction(const common::MacAddr& src_addr, BufferReader* r);
+ zx_status_t HandleMpmOpenAction(const common::MacAddr& src_addr, BufferReader* r);
+ zx_status_t HandleMpmConfirmAction(const common::MacAddr& src_addr, BufferReader* r);
void HandleMeshAction(const MgmtFrameHeader& mgmt, BufferReader* r);
const MeshPath* QueryPathTable(const common::MacAddr& mesh_dest);
diff --git a/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/parse_mp_action.h b/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/parse_mp_action.h
index d2945eb..bcc78e6 100644
--- a/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/parse_mp_action.h
+++ b/garnet/lib/wlan/mlme/include/wlan/mlme/mesh/parse_mp_action.h
@@ -12,6 +12,8 @@
bool ParseMpOpenAction(BufferReader* r, ::fuchsia::wlan::mlme::MeshPeeringOpenAction* out);
+bool ParseMpConfirmAction(BufferReader* r, ::fuchsia::wlan::mlme::MeshPeeringConfirmAction* out);
+
} // namespace wlan
#endif // GARNET_LIB_WLAN_MLME_INCLUDE_WLAN_MLME_MESH_PARSE_MP_ACTION_H_
diff --git a/garnet/lib/wlan/mlme/mesh/mesh_mlme.cpp b/garnet/lib/wlan/mlme/mesh/mesh_mlme.cpp
index 55e8587..b33bbf7 100644
--- a/garnet/lib/wlan/mlme/mesh/mesh_mlme.cpp
+++ b/garnet/lib/wlan/mlme/mesh/mesh_mlme.cpp
@@ -347,13 +347,15 @@
}
}
-zx_status_t MeshMlme::HandleSelfProtectedAction(common::MacAddr src_addr, BufferReader* r) {
+zx_status_t MeshMlme::HandleSelfProtectedAction(const common::MacAddr& src_addr, BufferReader* r) {
auto self_prot_header = r->Read<SelfProtectedActionHeader>();
if (self_prot_header == nullptr) { return ZX_OK; }
switch (self_prot_header->self_prot_action) {
case action::kMeshPeeringOpen:
return HandleMpmOpenAction(src_addr, r);
+ case action::kMeshPeeringConfirm:
+ return HandleMpmConfirmAction(src_addr, r);
default:
return ZX_OK;
}
@@ -381,7 +383,7 @@
}
}
-zx_status_t MeshMlme::HandleMpmOpenAction(common::MacAddr src_addr, BufferReader* r) {
+zx_status_t MeshMlme::HandleMpmOpenAction(const common::MacAddr& src_addr, BufferReader* r) {
wlan_mlme::MeshPeeringOpenAction action;
if (!ParseMpOpenAction(r, &action)) { return ZX_OK; }
@@ -389,6 +391,14 @@
return SendServiceMsg(device_, &action, fuchsia_wlan_mlme_MLMEIncomingMpOpenActionOrdinal);
}
+zx_status_t MeshMlme::HandleMpmConfirmAction(const common::MacAddr& src_addr, BufferReader* r) {
+ wlan_mlme::MeshPeeringConfirmAction action;
+ if (!ParseMpConfirmAction(r, &action)) { return ZX_OK; }
+
+ src_addr.CopyTo(action.common.peer_sta_address.data());
+ return SendServiceMsg(device_, &action, fuchsia_wlan_mlme_MLMEIncomingMpConfirmActionOrdinal);
+}
+
const MeshPath* MeshMlme::QueryPathTable(const common::MacAddr& mesh_dest) {
ZX_ASSERT(state_);
diff --git a/garnet/lib/wlan/mlme/mesh/parse_mp_action.cpp b/garnet/lib/wlan/mlme/mesh/parse_mp_action.cpp
index 22e659e..1ecc0f9 100644
--- a/garnet/lib/wlan/mlme/mesh/parse_mp_action.cpp
+++ b/garnet/lib/wlan/mlme/mesh/parse_mp_action.cpp
@@ -75,6 +75,11 @@
}
}
+static void ConvertMpmHeader(const MpmHeader& header, wlan_mlme::MeshPeeringCommon* out) {
+ out->protocol_id = header.protocol;
+ out->local_link_id = header.local_link_id;
+}
+
// IEEE Std 802.11-2016, 9.6.16.2.2
bool ParseMpOpenAction(BufferReader* r, wlan_mlme::MeshPeeringOpenAction* out) {
auto cap_info = r->Read<CapabilityInfo>();
@@ -86,8 +91,7 @@
// Handle the MPM element separately since there is no way to handle
// it in a generic fashion
if (auto mpm_open = common::ParseMpmOpen(raw_body)) {
- out->common.protocol_id = mpm_open->header.protocol;
- out->common.local_link_id = mpm_open->header.local_link_id;
+ ConvertMpmHeader(mpm_open->header, &out->common);
required_ies.have_mpm = true;
}
} else {
@@ -97,4 +101,30 @@
return required_ies.have_all();
}
+// IEEE Std 802.11-2016, 9.6.16.3.2
+bool ParseMpConfirmAction(BufferReader* r, wlan_mlme::MeshPeeringConfirmAction* out) {
+ auto cap_info = r->Read<CapabilityInfo>();
+ if (cap_info == nullptr) { return false; }
+
+ auto aid = r->Read<uint16_t>();
+ if (aid == nullptr) { return false; }
+ out->aid = *aid;
+
+ RequiredIes required_ies;
+ for (auto [id, raw_body] : common::ElementSplitter(r->ReadRemaining())) {
+ if (id == element_id::kMeshPeeringManagement) {
+ // Handle the MPM element separately since there is no way to handle
+ // it in a generic fashion
+ if (auto mpm_confirm = common::ParseMpmConfirm(raw_body)) {
+ ConvertMpmHeader(mpm_confirm->header, &out->common);
+ required_ies.have_mpm = true;
+ out->peer_link_id = mpm_confirm->peer_link_id;
+ }
+ } else {
+ HandleCommonMpElement(id, raw_body, &out->common, &required_ies);
+ }
+ }
+ return required_ies.have_all();
+}
+
} // namespace wlan
diff --git a/garnet/lib/wlan/mlme/tests/mesh_mlme_unittest.cpp b/garnet/lib/wlan/mlme/tests/mesh_mlme_unittest.cpp
index 391d43a..a4f36f5 100644
--- a/garnet/lib/wlan/mlme/tests/mesh_mlme_unittest.cpp
+++ b/garnet/lib/wlan/mlme/tests/mesh_mlme_unittest.cpp
@@ -140,6 +140,46 @@
}
}
+TEST_F(MeshMlmeTest, HandleMpmConfirm) {
+ EXPECT_EQ(JoinMesh(), wlan_mlme::StartResultCodes::SUCCESS);
+
+ // clang-format off
+ const uint8_t frame[] = {
+ // Mgmt header
+ 0xd0, 0x00, 0x00, 0x00, // fc, duration
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // addr1
+ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // addr2
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // addr3
+ 0x00, 0x00, // seq ctl
+ // Action
+ 15, // category (self-protected)
+ 2, // action = Mesh Peering Confirm
+ // Body
+ 0xaa, 0xbb, // capability info
+ 0xcc, 0xdd, // aid
+ 1, 1, 0x81, // supported rates
+ 114, 3, 'f', 'o', 'o', // mesh id
+ 113, 7, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // mesh config
+ 117, 6, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, // MPM
+ };
+ // clang-format on
+
+ ASSERT_EQ(mlme.HandleFramePacket(MakeWlanPacket(frame)), ZX_OK);
+
+ auto msgs = device.GetServiceMsgs<wlan_mlme::MeshPeeringConfirmAction>();
+ ASSERT_EQ(msgs.size(), 1ULL);
+
+ {
+ const uint8_t expected[] = {'f', 'o', 'o'};
+ EXPECT_RANGES_EQ(msgs[0].body()->common.mesh_id, expected);
+ }
+
+ {
+ const uint8_t expected[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+ EXPECT_RANGES_EQ(msgs[0].body()->common.peer_sta_address, expected);
+ }
+}
+
TEST_F(MeshMlmeTest, GetPathTable) {
EXPECT_EQ(JoinMesh(), wlan_mlme::StartResultCodes::SUCCESS);
auto path_table_msgs = GetPathTable();
diff --git a/garnet/lib/wlan/mlme/tests/parse_mp_action_unittest.cpp b/garnet/lib/wlan/mlme/tests/parse_mp_action_unittest.cpp
index 55ac4ca..daf6366 100644
--- a/garnet/lib/wlan/mlme/tests/parse_mp_action_unittest.cpp
+++ b/garnet/lib/wlan/mlme/tests/parse_mp_action_unittest.cpp
@@ -187,4 +187,133 @@
ASSERT_FALSE(ParseMpOpenAction(&reader, &action));
}
+TEST(ParseMpConfirm, Full) {
+ // clang-format off
+ const uint8_t data[] = {
+ 0xaa, 0xbb, // capability info
+ 0x12, 0x34, // aid
+ 1, 8, 0x81, 0x82, 0x83, 0x84, 0x05, 0x06, 0x07, 0x08, // supported rates
+ 50, 1, 0x09, // ext supported rates
+ 114, 3, 'f', 'o', 'o', // mesh id
+ 113, 7, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // mesh config
+ 117, 6, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, // MPM
+ 45, 26, // ht capabilities
+ 0xaa, 0xbb, // ht cap info
+ 0x55, // ampdu params
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, // mcs
+ 0xdd, 0xee, // ext caps
+ 0x11, 0x22, 0x33, 0x44, // beamforming
+ 0x77, // asel
+ 61, 22, // ht operation
+ 36, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 191, 12, // vht capabilities
+ 0xaa, 0xbb, 0xcc, 0xdd,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 192, 5, // vht operation
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4
+ };
+ // clang-format on
+
+ wlan_mlme::MeshPeeringConfirmAction action;
+ BufferReader reader { data };
+ ASSERT_TRUE(ParseMpConfirmAction(&reader, &action));
+
+ {
+ // Rates are expected to be a concatenation of Supp Rates and Ext Supp Rates
+ const uint8_t expected[9] = { 0x81, 0x82, 0x83, 0x84, 0x05, 0x06, 0x07, 0x08, 0x09 };
+ EXPECT_RANGES_EQ(action.common.rates, expected);
+ }
+
+ {
+ const uint8_t expected[3] = { 'f', 'o', 'o' };
+ EXPECT_RANGES_EQ(action.common.mesh_id, expected);
+ }
+
+ EXPECT_EQ(action.peer_link_id, 0xb6b5);
+ EXPECT_EQ(action.aid, 0x3412u);
+
+ EXPECT_EQ(action.common.mesh_config.active_path_sel_proto_id, 0xa1u);
+ EXPECT_EQ(action.common.protocol_id, 0xb2b1u);
+ EXPECT_EQ(action.common.local_link_id, 0xb4b3);
+
+ ASSERT_NE(action.common.ht_cap, nullptr);
+ EXPECT_EQ(action.common.ht_cap->mcs_set.rx_mcs_set, 0x0706050403020100ul);
+
+ ASSERT_NE(action.common.ht_op, nullptr);
+ EXPECT_EQ(action.common.ht_op->basic_mcs_set.rx_mcs_set, 0xc7c6c5c4c3c2c1c0ul);
+
+ ASSERT_NE(action.common.vht_cap, nullptr);
+ EXPECT_EQ(action.common.vht_cap->vht_mcs_nss.rx_max_data_rate, 0x0433);
+
+ ASSERT_NE(action.common.vht_op, nullptr);
+ ASSERT_EQ(action.common.vht_op->vht_cbw, 0xd0);
+}
+
+TEST(ParseMpConfirm, Minimal) {
+ // clang-format off
+ const uint8_t data[] = {
+ 0xaa, 0xbb, // capability info
+ 0x12, 0x34, // AID
+ 1, 1, 0x81, // supported rates
+ 114, 3, 'f', 'o', 'o', // mesh id
+ 113, 7, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // mesh config
+ 117, 6, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, // MPM
+ };
+ // clang-format on
+
+ wlan_mlme::MeshPeeringConfirmAction action;
+ BufferReader reader { data };
+ ASSERT_TRUE(ParseMpConfirmAction(&reader, &action));
+
+ {
+ // Rates are expected to be a concatenation of Supp Rates and Ext Supp Rates
+ const uint8_t expected[1] = { 0x81 };
+ EXPECT_RANGES_EQ(action.common.rates, expected);
+ }
+
+ {
+ const uint8_t expected[3] = { 'f', 'o', 'o' };
+ EXPECT_RANGES_EQ(action.common.mesh_id, expected);
+ }
+
+ EXPECT_EQ(action.aid, 0x3412u);
+ EXPECT_EQ(action.peer_link_id, 0xb6b5);
+
+ EXPECT_EQ(action.common.mesh_config.active_path_sel_proto_id, 0xa1u);
+ EXPECT_EQ(action.common.protocol_id, 0xb2b1u);
+}
+
+TEST(ParseMpConfirm, TooShortForCapabilityInfo) {
+ const uint8_t data[] = { 0xaa }; // too short to hold a CapabilityInfo
+ BufferReader reader { data };
+ wlan_mlme::MeshPeeringConfirmAction action;
+ ASSERT_FALSE(ParseMpConfirmAction(&reader, &action));
+}
+
+TEST(ParseMpConfirm, TooShortForAid) {
+ const uint8_t data[] = { 0xaa, 0xbb, 0xcc }; // too short to hold a CapabilityInfo + AID
+ BufferReader reader { data };
+ wlan_mlme::MeshPeeringConfirmAction action;
+ ASSERT_FALSE(ParseMpConfirmAction(&reader, &action));
+}
+
+TEST(ParseMpConfirm, MissingMpm) {
+ // clang-format off
+ const uint8_t data[] = {
+ 0xaa, 0xbb, // capability info
+ 0x12, 0x34, // AID
+ 1, 1, 0x81, // supported rates
+ 114, 3, 'f', 'o', 'o', // mesh id
+ 113, 7, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // mesh config
+ };
+ // clang-format on
+
+ wlan_mlme::MeshPeeringConfirmAction action;
+ BufferReader reader { data };
+ ASSERT_FALSE(ParseMpConfirmAction(&reader, &action));
+}
+
} // namespace wlan
diff --git a/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl b/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl
index 272cc065..1ea78b1 100644
--- a/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl
+++ b/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl
@@ -932,9 +932,10 @@
// The following are extensions to the 802.11 MLME SAP interface.
- // ==== 90xxxx: Mesh ===
+ // ==== Mesh ===
-> IncomingMpOpenAction(MeshPeeringOpenAction action);
SendMpOpenAction(MeshPeeringOpenAction action);
+ -> IncomingMpConfirmAction(MeshPeeringConfirmAction action);
SendMpConfirmAction(MeshPeeringConfirmAction action);
MeshPeeringEstablished(MeshPeeringParams peering);