blob: 22e659e000a7d51de484568da3970470eece0eef [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <wlan/mlme/mesh/parse_mp_action.h>
#include <wlan/common/element_splitter.h>
#include <wlan/common/mac_frame.h>
#include <wlan/common/parse_element.h>
namespace wlan_mlme = ::fuchsia::wlan::mlme;
namespace wlan {
struct RequiredIes {
bool have_supp_rates = false;
bool have_mesh_id = false;
bool have_mesh_config = false;
bool have_mpm = false;
bool have_all() const {
return have_supp_rates && have_mesh_id && have_mesh_config && have_mpm;
}
};
static void HandleCommonMpElement(element_id::ElementId id, Span<const uint8_t> raw_body,
wlan_mlme::MeshPeeringCommon* out, RequiredIes* required_ies) {
switch (id) {
case element_id::kSuppRates:
if (auto rates = common::ParseSupportedRates(raw_body)) {
out->rates.insert(out->rates.end(), rates->begin(), rates->end());
required_ies->have_supp_rates = true;
}
break;
case element_id::kExtSuppRates:
if (auto rates = common::ParseExtendedSupportedRates(raw_body)) {
out->rates.insert(out->rates.end(), rates->begin(), rates->end());
}
break;
case element_id::kMeshId:
if (auto mesh_id = common::ParseMeshId(raw_body)) {
out->mesh_id.resize(0);
out->mesh_id.assign(mesh_id->begin(), mesh_id->end());
required_ies->have_mesh_id = true;
}
break;
case element_id::kMeshConfiguration:
if (auto mesh_config = common::ParseMeshConfiguration(raw_body)) {
out->mesh_config = mesh_config->ToFidl();
required_ies->have_mesh_config = true;
}
break;
case element_id::kHtCapabilities:
if (auto ht_cap = common::ParseHtCapabilities(raw_body)) {
out->ht_cap = std::make_unique<wlan_mlme::HtCapabilities>(ht_cap->ToFidl());
}
break;
case element_id::kHtOperation:
if (auto ht_op = common::ParseHtOperation(raw_body)) {
out->ht_op = std::make_unique<wlan_mlme::HtOperation>(ht_op->ToFidl());
}
break;
case element_id::kVhtCapabilities:
if (auto vht_cap = common::ParseVhtCapabilities(raw_body)) {
out->vht_cap = std::make_unique<wlan_mlme::VhtCapabilities>(vht_cap->ToFidl());
}
break;
case element_id::kVhtOperation:
if (auto vht_op = common::ParseVhtOperation(raw_body)) {
out->vht_op = std::make_unique<wlan_mlme::VhtOperation>(vht_op->ToFidl());
}
break;
default:
break;
}
}
// IEEE Std 802.11-2016, 9.6.16.2.2
bool ParseMpOpenAction(BufferReader* r, wlan_mlme::MeshPeeringOpenAction* out) {
auto cap_info = r->Read<CapabilityInfo>();
if (cap_info == nullptr) { return false; }
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_open = common::ParseMpmOpen(raw_body)) {
out->common.protocol_id = mpm_open->header.protocol;
out->common.local_link_id = mpm_open->header.local_link_id;
required_ies.have_mpm = true;
}
} else {
HandleCommonMpElement(id, raw_body, &out->common, &required_ies);
}
}
return required_ies.have_all();
}
} // namespace wlan