diff --git a/agent/src/beerocks/slave/CMakeLists.txt b/agent/src/beerocks/slave/CMakeLists.txt index 72d6752d78..eda458d175 100644 --- a/agent/src/beerocks/slave/CMakeLists.txt +++ b/agent/src/beerocks/slave/CMakeLists.txt @@ -11,6 +11,7 @@ file(GLOB beerocks_agent_sources ${MODULE_PATH}/link_metrics/*.c* ${MODULE_PATH}/platform_manager/*.c* ${MODULE_PATH}/gate/*.c* + ${MODULE_PATH}/backhaul_manager/internal/*.c* ${MODULE_PATH}/*.c* ) diff --git a/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.cpp b/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.cpp index 45f6ab875a..feef1c6ad4 100644 --- a/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.cpp +++ b/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.cpp @@ -29,19 +29,17 @@ */ #include "backhaul_manager_thread.h" - #include "../link_metrics/ieee802_11_link_metrics_collector.h" #include "../link_metrics/ieee802_3_link_metrics_collector.h" #include "../tlvf_utils.h" - +#include "internal/expected_ap_metrics_response.h" #include #include -#include - #include #include #include #include +#include /* * TODO: @@ -1023,21 +1021,16 @@ bool backhaul_manager::backhaul_fsm_main(bool &skip_select) for (const auto &socket : slaves_sockets) { if (socket) { for (int i = 0; i < beerocks::IFACE_TOTAL_VAPS; ++i) { - if (socket->vaps_list.vaps[i].mac != network_utils::ZERO_MAC) { + if ((socket->vaps_list.vaps[i].mac != network_utils::ZERO_MAC) && + (socket->vaps_list.vaps[i].ssid[0] != '\0')) { bssid_list.push_back(socket->vaps_list.vaps[i].mac); } } } } - // We must generate a new MID for the periodic AP Metrics Response messages that - // do not correspond to an AP Metrics Query message. - // We cannot set MID to 0 here because we must also differentiate periodic - // AP Metrics Response messages and messages received from monitor thread - // due to channel utilization crossed configured threshold value. - // As a temporary solution, set MID to UINT16_MAX here. - // TODO: to be fixed as part of #1328 + if (!bssid_list.empty()) { - send_slave_ap_metric_query_message(UINT16_MAX, bssid_list); + send_slave_ap_metric_query_message(0, bssid_list); } else { LOG(DEBUG) << "Skipping AP_METRICS_QUERY for slave, empty BSSID list"; } @@ -1258,49 +1251,81 @@ bool backhaul_manager::send_autoconfig_search_message(std::shared_ptr &bssid_list) { - bool ret = false; + // save mid and clear previous query + m_expected_ap_metrics_response.reset_to_new_mid(mid); + + // compare two mac addresses using string compare on their octets + auto mac_comp = [](const sMacAddr &addr1, const sMacAddr &addr2) -> bool { + return memcmp((char *)addr1.oct, (char *)addr2.oct, sizeof(sMacAddr)) < 0; + }; + + // sort the given bssid list + std::vector given_bssid_list = bssid_list; + std::sort(given_bssid_list.begin(), given_bssid_list.end(), mac_comp); + + // for each socket - send only relevant bssids + auto ret = true; for (auto socket : slaves_sockets) { - for (const auto &mac : bssid_list) { - int i = 0; - if (mac == socket->vaps_list.vaps[i].mac) { - LOG(DEBUG) << "Forwarding AP_METRICS_QUERY_MESSAGE message to son_slave, bssid: " - << std::hex << tlvf::mac_to_string(mac); - - auto forward = - cmdu_tx.create(mid, ieee1905_1::eMessageType::AP_METRICS_QUERY_MESSAGE); - if (!forward) { - LOG(ERROR) << "Failed to create AP_METRICS_QUERY_MESSAGE"; - return false; - } - auto query = cmdu_tx.addClass(); - if (!query) { - LOG(ERROR) << "Failed addClass"; - return false; - } + // create the message to forward to current slaves + auto forward = cmdu_tx.create(mid, ieee1905_1::eMessageType::AP_METRICS_QUERY_MESSAGE); + if (!forward) { + LOG(ERROR) << "Failed to create AP_METRICS_QUERY_MESSAGE"; + return false; + } - if (!query->alloc_bssid_list(1)) { - LOG(ERROR) << "Failed allocate memory for bssid_list"; - return false; - } + // copy current vaps bssid + std::vector current_socket_bssids; + std::transform(socket->vaps_list.vaps, socket->vaps_list.vaps + beerocks::IFACE_TOTAL_VAPS, + std::back_inserter(current_socket_bssids), + [](const beerocks_message::sVapInfo &vap_info) { return vap_info.mac; }); - auto list = query->bssid_list(0); - std::get<0>(list) = true; - std::get<1>(list) = mac; + // sort current vaps bssid + std::sort(current_socket_bssids.begin(), current_socket_bssids.end(), mac_comp); - if (!message_com::send_cmdu(socket->slave, cmdu_tx)) { - LOG(ERROR) << "Failed forwarding AP_METRICS_QUERY_MESSAGE message to son_slave"; - ret = false; - continue; - } else { - ret = true; - // Fill a query vector - m_ap_metric_query.push_back({socket->slave, mac}); - } - } + // fill a list of the common bssids: given list with current vaps + std::vector required_bssids; + std::set_intersection(given_bssid_list.begin(), given_bssid_list.end(), + current_socket_bssids.begin(), current_socket_bssids.end(), + std::back_inserter(required_bssids), mac_comp); + + if (required_bssids.empty()) { + // skip if there is nothing to do + LOG(DEBUG) << "empty required bssid list, skipping"; + continue; + } + + // add metric query tlv + auto query = cmdu_tx.addClass(); + if (!query) { + LOG(ERROR) << "Failed addClass"; + return false; + } + + // alocate memory + if (!query->alloc_bssid_list(required_bssids.size())) { + LOG(ERROR) << "Failed allocate memory for bssid_list, size: " << bssid_list.size(); + return false; + } + + int i = 0; + for (const auto &mac : required_bssids) { + auto list = query->bssid_list(i); + std::get<0>(list) = true; + std::get<1>(list) = mac; i++; } + + // save the required list + m_expected_ap_metrics_response.add_expected_bssid(required_bssids.begin(), + required_bssids.end()); + + if (!message_com::send_cmdu(socket->slave, cmdu_tx)) { + LOG(ERROR) << "Failed forwarding AP_METRICS_QUERY_MESSAGE message to son_slave"; + ret = false; + } } + return ret; } @@ -2554,8 +2579,12 @@ bool backhaul_manager::handle_ap_capability_query(ieee1905_1::CmduMessageRx &cmd bool backhaul_manager::handle_ap_metrics_query(ieee1905_1::CmduMessageRx &cmdu_rx, const std::string &src_mac) { - std::vector bssid; - const auto mid = cmdu_rx.getMessageId(); + + const auto mid = cmdu_rx.getMessageId(); + + // save mid and erase data for previous query and response + m_expected_ap_metrics_response.reset_to_new_mid(mid); + auto ap_metric_query_tlv = cmdu_rx.getClass(); if (!ap_metric_query_tlv) { LOG(ERROR) << "AP Metrics Query CMDU mid=" << mid << " does not have AP Metric Query TLV"; @@ -2567,16 +2596,29 @@ bool backhaul_manager::handle_ap_metrics_query(ieee1905_1::CmduMessageRx &cmdu_r LOG(ERROR) << "Failed to get bssid " << bssid_idx << " from AP_METRICS_QUERY"; return false; } - bssid.push_back(std::get<1>(bssid_tuple)); + + m_expected_ap_metrics_response.add_expected_bssid(std::get<1>(bssid_tuple)); + LOG(DEBUG) << "Received AP_METRICS_QUERY_MESSAGE, mid=" << std::hex << int(mid) << " bssid " << std::get<1>(bssid_tuple); } - if (!send_slave_ap_metric_query_message(mid, bssid)) { - LOG(ERROR) << "Failed to forward AP_METRICS_RESPONSE to the son_slave_thread"; + LOG(DEBUG) << "Forwarding AP_METRICS_QUERY_MESSAGE to all slaves, mid=" << std::hex << int(mid); + auto header = message_com::get_uds_header(cmdu_rx); + if (!header) { + LOG(ERROR) << "Failed to extract header from rx message"; return false; } + uint16_t length = header->length; + cmdu_rx.swap(); // swap back before forwarding + for (const auto &soc : slaves_sockets) { + if (!message_com::forward_cmdu_to_uds(soc->slave, cmdu_rx, length)) { + LOG(ERROR) << "Failed forwarding AP_METRICS_QUERY_MESSAGE message to slave: " + << tlvf::mac_to_string(soc->radio_mac); + } + } + return true; } @@ -2584,33 +2626,23 @@ bool backhaul_manager::handle_slave_ap_metrics_response(ieee1905_1::CmduMessageR const std::string &src_mac) { auto mid = cmdu_rx.getMessageId(); - LOG(DEBUG) << "Received AP_METRICS_RESPONSE_MESSAGE, mid=" << std::hex << int(mid); - /** - * If AP Metrics Response message does not correspond to a previously received and forwarded - * AP Metrics Query message (which we know because message id is not set), then forward message - * to controller. - * This might happen when channel utilization value has crossed configured threshold or when - * periodic metrics reporting interval has elapsed. - */ if (0 == mid) { - uint16_t length = message_com::get_uds_header(cmdu_rx)->length; - cmdu_rx.swap(); //swap back before forwarding - return send_cmdu_to_bus(cmdu_rx, controller_bridge_mac, bridge_info.mac, length); + LOG(DEBUG) << "AP_METRICS_RESPONSE_MESSAGE. mid is zero (0), forwarding to controller " + "unconditionaly."; + cmdu_rx.swap(); + return send_cmdu_to_bus(cmdu_rx, controller_bridge_mac, bridge_info.mac, + cmdu_rx.getMessageLength()); } - /** - * When periodic metrics reporting interval has elapsed, we emulate that we have received an - * AP Metrics Query message from controller. To differentiate real queries from emulated ones, - * we use a "special" mid value. - * Note that this design is flaw as a real query might also have this special mid value. This - * is just a quick and dirty fix to pass 4.7.5 and 4.7.6 for M1 - * TODO: to be fixed as part of #1328 - */ - if (UINT16_MAX == mid) { - mid = 0; + if (m_expected_ap_metrics_response.get_mid() != mid) { + LOG(ERROR) << "Received AP_METRICS_RESPONSE_MESSAGE with bad mid: existing:" << std::hex + << m_expected_ap_metrics_response.get_mid() << " received: " << int(mid); + return false; } + LOG(DEBUG) << "Received AP_METRICS_RESPONSE_MESSAGE, mid=" << std::hex << int(mid); + auto ap_metrics_tlv = cmdu_rx.getClass(); if (!ap_metrics_tlv) { LOG(ERROR) << "Failed cmdu_rx.getClass(), mid=" << std::hex @@ -2618,44 +2650,64 @@ bool backhaul_manager::handle_slave_ap_metrics_response(ieee1905_1::CmduMessageR return false; } - auto bssid_tlv = ap_metrics_tlv->bssid(); - auto mac = std::find_if( - m_ap_metric_query.begin(), m_ap_metric_query.end(), - [&bssid_tlv](sApMetricsQuery const &query) { return query.bssid == bssid_tlv; }); - - if (mac == m_ap_metric_query.end()) { - LOG(ERROR) << "Failed search in ap_metric_query for bssid: " << bssid_tlv + if (!m_expected_ap_metrics_response.find_expected_bssid(ap_metrics_tlv->bssid())) { + LOG(ERROR) << "Failed search in ap_metric_query for bssid: " << ap_metrics_tlv->bssid() << " from mid=" << std::hex << int(mid); return false; } - sApMetrics metric; - // Copy data to the response vector - metric.bssid = ap_metrics_tlv->bssid(); - metric.channel_utilization = ap_metrics_tlv->channel_utilization(); - metric.number_of_stas_currently_associated = + // prepare ap metrics tlv + auto &ap_metrics_tx_message = m_expected_ap_metrics_response.create_tx_message(); + auto ap_metrics_response_tlv = ap_metrics_tx_message.addClass(); + if (!ap_metrics_response_tlv) { + LOG(ERROR) << "Failed addClass"; + return false; + } + ap_metrics_response_tlv->bssid() = ap_metrics_tlv->bssid(); + ap_metrics_response_tlv->channel_utilization() = ap_metrics_tlv->channel_utilization(); + ap_metrics_response_tlv->number_of_stas_currently_associated() = ap_metrics_tlv->number_of_stas_currently_associated(); - metric.estimated_service_parameters = ap_metrics_tlv->estimated_service_parameters(); - auto info = ap_metrics_tlv->estimated_service_info_field(); + ap_metrics_response_tlv->estimated_service_parameters() = + ap_metrics_tlv->estimated_service_parameters(); + + if (!ap_metrics_response_tlv->alloc_estimated_service_info_field( + ap_metrics_tlv->estimated_service_info_field_length())) { + LOG(ERROR) << "Couldn't allocate " + "ap_metrics_response_tlv->alloc_estimated_service_info_field"; + return false; + } + auto rx_info = ap_metrics_tlv->estimated_service_info_field(); + auto tx_info = ap_metrics_response_tlv->estimated_service_info_field(); for (size_t i = 0; i < ap_metrics_tlv->estimated_service_info_field_length(); i++) { - metric.estimated_service_info_field.push_back(info[i]); + tx_info[i] = rx_info[i]; } - std::vector traffic_stats_response; + // Prepare STA Traffic Stats TLV's for (auto &sta_traffic : cmdu_rx.getClassList()) { if (!sta_traffic) { LOG(ERROR) << "Failed to get class list for tlvAssociatedStaTrafficStats"; continue; } - traffic_stats_response.push_back( - {sta_traffic->sta_mac(), sta_traffic->byte_sent(), sta_traffic->byte_recived(), - sta_traffic->packets_sent(), sta_traffic->packets_recived(), - sta_traffic->tx_packets_error(), sta_traffic->rx_packets_error(), - sta_traffic->retransmission_count()}); + auto sta_traffic_response_tlv = + ap_metrics_tx_message.addClass(); + + if (!sta_traffic_response_tlv) { + LOG(ERROR) << "Failed addClass"; + continue; + } + + sta_traffic_response_tlv->sta_mac() = sta_traffic->sta_mac(); + sta_traffic_response_tlv->byte_sent() = sta_traffic->byte_sent(); + sta_traffic_response_tlv->byte_recived() = sta_traffic->byte_recived(); + sta_traffic_response_tlv->packets_sent() = sta_traffic->packets_sent(); + sta_traffic_response_tlv->packets_recived() = sta_traffic->packets_recived(); + sta_traffic_response_tlv->tx_packets_error() = sta_traffic->tx_packets_error(); + sta_traffic_response_tlv->rx_packets_error() = sta_traffic->rx_packets_error(); + sta_traffic_response_tlv->retransmission_count() = sta_traffic->retransmission_count(); } - std::vector link_metrics_response; + // Prepare STA Link Metrics TLV's for (auto &sta_link_metric : cmdu_rx.getClassList()) { if (!sta_link_metric) { LOG(ERROR) << "Failed getClassList"; @@ -2666,98 +2718,35 @@ bool backhaul_manager::handle_slave_ap_metrics_response(ieee1905_1::CmduMessageR continue; } auto response_list = sta_link_metric->bssid_info_list(0); - link_metrics_response.push_back({sta_link_metric->sta_mac(), std::get<1>(response_list)}); - } - - // Fill a response vector - m_ap_metric_response.push_back({metric, traffic_stats_response, link_metrics_response}); - - // Remove an entry from the processed query - m_ap_metric_query.erase( - std::remove_if(m_ap_metric_query.begin(), m_ap_metric_query.end(), - [&](sApMetricsQuery const &query) { return mac->bssid == query.bssid; }), - m_ap_metric_query.end()); - - if (!m_ap_metric_query.empty()) { - return true; - } - - // We received all responses - prepare and send response message to the controller - auto cmdu_header = cmdu_tx.create(mid, ieee1905_1::eMessageType::AP_METRICS_RESPONSE_MESSAGE); - - if (!cmdu_header) { - LOG(ERROR) << "Failed building IEEE1905 AP_METRICS_RESPONSE_MESSAGE"; - return false; - } - // Prepare tlvApMetrics for each processed query - for (const auto &response : m_ap_metric_response) { - auto ap_metrics_response_tlv = cmdu_tx.addClass(); - if (!ap_metrics_response_tlv) { - LOG(ERROR) << "Failed addClass"; - return false; - } + auto sta_link_metric_response_tlv = + ap_metrics_tx_message.addClass(); - ap_metrics_response_tlv->bssid() = response.metric.bssid; - ap_metrics_response_tlv->channel_utilization() = response.metric.channel_utilization; - ap_metrics_response_tlv->number_of_stas_currently_associated() = - response.metric.number_of_stas_currently_associated; - ap_metrics_response_tlv->estimated_service_parameters() = - response.metric.estimated_service_parameters; - if (!ap_metrics_response_tlv->alloc_estimated_service_info_field( - response.metric.estimated_service_info_field.size())) { - LOG(ERROR) << "Couldn't allocate " - "ap_metrics_response_tlv->alloc_estimated_service_info_field"; - return false; + if (!sta_link_metric_response_tlv) { + LOG(ERROR) << "Failed addClass"; + continue; } - std::copy_n(response.metric.estimated_service_info_field.begin(), - response.metric.estimated_service_info_field.size(), - ap_metrics_response_tlv->estimated_service_info_field()); - - for (auto &stat : response.sta_traffic_stats) { - auto sta_traffic_response_tlv = - cmdu_tx.addClass(); - - if (!sta_traffic_response_tlv) { - LOG(ERROR) << "Failed addClass"; - continue; - } - sta_traffic_response_tlv->sta_mac() = stat.sta_mac; - sta_traffic_response_tlv->byte_sent() = stat.byte_sent; - sta_traffic_response_tlv->byte_recived() = stat.byte_recived; - sta_traffic_response_tlv->packets_sent() = stat.packets_sent; - sta_traffic_response_tlv->packets_recived() = stat.packets_recived; - sta_traffic_response_tlv->tx_packets_error() = stat.tx_packets_error; - sta_traffic_response_tlv->rx_packets_error() = stat.rx_packets_error; - sta_traffic_response_tlv->retransmission_count() = stat.retransmission_count; + sta_link_metric_response_tlv->sta_mac() = sta_link_metric->sta_mac(); + if (!sta_link_metric_response_tlv->alloc_bssid_info_list(1)) { + LOG(ERROR) << "Failed alloc_bssid_info_list"; + continue; } + auto &sta_link_metric_response = + std::get<1>(sta_link_metric_response_tlv->bssid_info_list(0)); + sta_link_metric_response = std::get<1>(response_list); + } - for (auto &link_metric : response.sta_link_metrics) { - auto sta_link_metric_response_tlv = - cmdu_tx.addClass(); - - if (!sta_link_metric_response_tlv) { - LOG(ERROR) << "Failed addClass"; - continue; - } + // remove an entry from the processed query + m_expected_ap_metrics_response.remove_expected_bssid(ap_metrics_tlv->bssid()); - sta_link_metric_response_tlv->sta_mac() = link_metric.sta_mac; - if (!sta_link_metric_response_tlv->alloc_bssid_info_list(1)) { - LOG(ERROR) << "Failed alloc_bssid_info_list"; - continue; - } - auto &sta_link_metric_response = - std::get<1>(sta_link_metric_response_tlv->bssid_info_list(0)); - sta_link_metric_response = link_metric.bssid_info; - } + // waiting for all responses before sending the response + if (!m_expected_ap_metrics_response.is_expected_bssid_empty()) { + return true; } - // Clear the m_ap_metric_response vector after preparing response to the controller - m_ap_metric_response.clear(); - LOG(DEBUG) << "Sending AP_METRICS_RESPONSE_MESSAGE, mid=" << std::hex << int(mid); - return send_cmdu_to_bus(cmdu_tx, controller_bridge_mac, bridge_info.mac); + return send_cmdu_to_bus(ap_metrics_tx_message, controller_bridge_mac, bridge_info.mac); } /** diff --git a/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.h b/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.h index 165e10c5fd..8ec11a2f08 100644 --- a/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.h +++ b/agent/src/beerocks/slave/backhaul_manager/backhaul_manager_thread.h @@ -9,6 +9,7 @@ #ifndef _BACKHAUL_MANAGER_THREAD_H #define _BACKHAUL_MANAGER_THREAD_H +#include "internal/expected_ap_metrics_response.h" #include "wan_monitor.h" #include @@ -24,6 +25,7 @@ #include #include +#include #include #include #include @@ -544,43 +546,7 @@ class backhaul_manager : public btl::transport_socket_thread { const sLinkNeighbor &link_neighbor, const sLinkMetrics &link_metrics, ieee1905_1::eLinkMetricsType link_metrics_type); - struct sStaTrafficStats { - sMacAddr sta_mac; - uint32_t byte_sent; - uint32_t byte_recived; - uint32_t packets_sent; - uint32_t packets_recived; - uint32_t tx_packets_error; - uint32_t rx_packets_error; - uint32_t retransmission_count; - }; - - struct sStaLinkMetrics { - sMacAddr sta_mac; - wfa_map::tlvAssociatedStaLinkMetrics::sBssidInfo bssid_info; - }; - - struct sApMetricsQuery { - Socket *soc; - sMacAddr bssid; - }; - - struct sApMetrics { - sMacAddr bssid; - uint8_t channel_utilization; - uint16_t number_of_stas_currently_associated; - wfa_map::tlvApMetrics::sEstimatedService estimated_service_parameters; - std::vector estimated_service_info_field; - }; - - struct sApMetricsResponse { - sApMetrics metric; - std::vector sta_traffic_stats; - std::vector sta_link_metrics; - }; - - std::vector m_ap_metric_query; - std::vector m_ap_metric_response; + ExpectedApMetricsResponse m_expected_ap_metrics_response; struct sChannelSelectionResponse { sMacAddr radio_mac; diff --git a/agent/src/beerocks/slave/backhaul_manager/internal/expected_ap_metrics_response.cpp b/agent/src/beerocks/slave/backhaul_manager/internal/expected_ap_metrics_response.cpp new file mode 100644 index 0000000000..e90aae749a --- /dev/null +++ b/agent/src/beerocks/slave/backhaul_manager/internal/expected_ap_metrics_response.cpp @@ -0,0 +1,46 @@ + +#include "expected_ap_metrics_response.h" + +namespace beerocks { + +// mid +void ExpectedApMetricsResponse::reset_to_new_mid(uint16_t mid) +{ + m_mid = mid; + m_expected_bssid_list.clear(); + m_response.reset(); + memset(m_response_buffer, 0, sizeof(m_response_buffer)); +} + +uint16_t ExpectedApMetricsResponse::get_mid() const { return m_mid; } + +// bssid +void ExpectedApMetricsResponse::add_expected_bssid(const sMacAddr &bssid) +{ + m_expected_bssid_list.insert(bssid); +} + +void ExpectedApMetricsResponse::remove_expected_bssid(const sMacAddr &bssid) +{ + m_expected_bssid_list.erase(bssid); +} + +bool ExpectedApMetricsResponse::is_expected_bssid_empty() const +{ + return m_expected_bssid_list.empty(); +} + +bool ExpectedApMetricsResponse::find_expected_bssid(const sMacAddr &bssid) const +{ + return m_expected_bssid_list.find(bssid) != m_expected_bssid_list.end(); +} + +// cmdu message +ieee1905_1::CmduMessageTx &ExpectedApMetricsResponse::create_tx_message() +{ + m_response.create(m_mid, ieee1905_1::eMessageType::AP_METRICS_RESPONSE_MESSAGE); + + return m_response; +} + +} // namespace beerocks diff --git a/agent/src/beerocks/slave/backhaul_manager/internal/expected_ap_metrics_response.h b/agent/src/beerocks/slave/backhaul_manager/internal/expected_ap_metrics_response.h new file mode 100644 index 0000000000..994a984cda --- /dev/null +++ b/agent/src/beerocks/slave/backhaul_manager/internal/expected_ap_metrics_response.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent + * + * SPDX-FileCopyrightText: 2016-2020 the prplMesh contributors (see AUTHORS.md) + * + * This code is subject to the terms of the BSD+Patent license. + * See LICENSE file for more details. + */ + +#ifndef _EXPECTED_AP_METRICS_RESPONSE_H +#define _EXPECTED_AP_METRICS_RESPONSE_H + +#include +#include +#include +#include +#include + +namespace beerocks { + +class ExpectedApMetricsResponse { +public: + /** + * @brief resets this object with a new mid + * @details resets all members of this object to its empty initial state except for the mid + * that is set as was given bt the parameter (mid default value is zero (0)) + * @param mid the new mid value + * @return radio mac of the found slave if found, otherwise empty string + */ + void reset_to_new_mid(uint16_t mid = 0); + + /** + * @brief returns the mid of this object + * @return mid + */ + uint16_t get_mid() const; + + /** + * @brief creates and returns a AP-RESPONSE-METRICS Tx message + * @return a fresh new CmduMessage with the correct type and mid + */ + ieee1905_1::CmduMessageTx &create_tx_message(); + + // bssid related operations + + /** + * @brief stores expected bssids + * @details adds the bssids in the range [first,last) to the already existing internal list + * @param first iterator to the source begin + * @param last iterator to the source last + * @return - nothing + */ + template void add_expected_bssid(FirstIt first, LastIt last); + + /** + * @brief stores expected bssid + * @details adds the input bssid to the already existing internal list + * @param bssid the bssid to store + * @return nothing + */ + void add_expected_bssid(const sMacAddr &bssid); + + /** + * @brief removes the given bssid from the internal list + * @param bssid the bssid to remove + * @return - nothing + */ + void remove_expected_bssid(const sMacAddr &); + + /** + * @brief search for the given bssid in the internal list + * @param bssid the bssid to search + * @return bool exists / does not exists + */ + bool find_expected_bssid(const sMacAddr &) const; + + /** + * @brief checks if the internal list is empty + * @return bool empty / not empty + */ + bool is_expected_bssid_empty() const; + +private: + uint16_t m_mid = 0; + std::unordered_set m_expected_bssid_list; + uint8_t m_response_buffer[beerocks::message::MESSAGE_BUFFER_LENGTH] = {0}; + ieee1905_1::CmduMessageTx m_response = {m_response_buffer, sizeof(m_response_buffer)}; +}; + +template +void ExpectedApMetricsResponse::add_expected_bssid(FirstIt first, LastIt last) +{ + m_expected_bssid_list.insert(first, last); +} + +} // namespace beerocks + +#endif diff --git a/tests/test_flows.py b/tests/test_flows.py index 065e806d22..4c54acbc38 100755 --- a/tests/test_flows.py +++ b/tests/test_flows.py @@ -908,7 +908,7 @@ def test_client_association_dummy(self): if sta.mac in map_vap0.clients: self.fail("client {} still in conn_map, clients: {}".format(sta.mac, map_vap0.clients)) - # Associate with other radio implies disassociate from first + env.agents[0].radios[1].vaps[0].disassociate(sta) env.agents[0].radios[0].vaps[0].associate(sta) time.sleep(1) # Wait for conn_map to be updated conn_map = connmap.get_conn_map() @@ -1189,6 +1189,68 @@ def test_beacon_report_query(self): # r"inserting 1 RRM_EVENT_BEACON_REP_RXED event(s) to the pending list") env.agents[0].radios[0].vaps[0].disassociate(sta) + def test_ap_metrics_interval_response(self): + # Trigger( + # DEV_SEND_1905,DestAL id, + # WTS_REPLACE_DEST_A LID, + # MessageTypeValue,0x8003, + # tlv_type,0x8A, + # tlv_length,0x000C, + # tlv_value,{0x05 0x01 {WTS_REPLACE_MAUT_RUID 0x00 0x00 0x00 0xC0}) + + # set vaps for both agents + for agent in range(0, 2): + env.beerocks_cli_command('bml_clear_wifi_credentials {}'.format(env.agents[agent].mac)) + env.beerocks_cli_command('bml_set_wifi_credentials {} {} {} {} {}' + .format(env.agents[agent].mac, + "Multi-AP-24G-3-cli", "maprocks1", "24g", "fronthaul")) + env.beerocks_cli_command('bml_update_wifi_credentials {}'.format(env.agents[agent].mac)) + + # create and associate stations + + sta1 = env.Station.create() + debug("Connect dummy STA (" + sta1.mac + ") to wlan0") + env.agents[0].radios[0].vaps[0].associate(sta1) + + sta2 = env.Station.create() + debug("Connect dummy STA (" + sta2.mac + ") to wlan2") + env.agents[1].radios[1].vaps[0].associate(sta2) + + debug("sending multi-ap policy config request") + + # in seconds + interval_time = 5 + tlv_value = '0x{:02} 0x01 0x{ruid} 0x00 0x00 0x00 0xC0'.format( + interval_time, ruid=env.agents[0].radios[0].mac.replace(':', '')) + + debug(tlv_value) + + # sending two commands to the controller, for each agent + env.controller.dev_send_1905(env.agents[0].mac, 0x8003, + tlv(0x8A, 0x000C, "{" + tlv_value + "}")) + + env.controller.dev_send_1905(env.agents[1].mac, 0x8003, + tlv(0x8A, 0x000C, "{" + tlv_value + "}")) + + # wait for ACK + time.sleep(1) + self.check_cmdu_type_single("ACK", 0x8000, env.agents[0].mac, env.controller.mac) + self.check_cmdu_type_single("ACK", 0x8000, env.agents[1].mac, env.controller.mac) + + # wait for report + # since it is a periodic report and we want to verify that + # we have only _one_ response, we wait for a time correlated with the request itself + time.sleep(interval_time + interval_time/2) + + # expect two single reports + self.check_cmdu_type_single("ap metrics response agent1", 0x800C, + env.agents[0].mac, env.controller.mac) + self.check_cmdu_type_single("ap metrics response agent2", 0x800C, + env.agents[1].mac, env.controller.mac) + + env.agents[0].radios[0].vaps[0].disassociate(sta1) + env.agents[1].radios[1].vaps[0].disassociate(sta2) + if __name__ == '__main__': t = TestFlows()