| // 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 |