blob: 7358c6b196f16ed78768b07ddaf78132647af8e8 [file] [log] [blame]
// Copyright 2023 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 <fidl/fuchsia.wlan.fullmac/cpp/driver/fidl.h>
#include <fidl/test.wlan.testcontroller/cpp/fidl.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/component/cpp/driver_export.h>
#include <lib/driver/component/cpp/node_add_args.h>
#include <lib/driver/devfs/cpp/connector.h>
#include <lib/driver/logging/cpp/structured_logger.h>
#include <lib/fdf/cpp/dispatcher.h>
#include <lib/fidl/cpp/wire/channel.h>
#include <lib/stdcompat/source_location.h>
#include <lib/sync/cpp/completion.h>
#include <map>
#include <sstream>
#include <vector>
#include <wlan/drivers/fidl_bridge.h>
namespace wlan_testcontroller {
using ::wlan::drivers::fidl_bridge::FidlErrorToStatus;
using ::wlan::drivers::fidl_bridge::ForwardResult;
// Server that forwards WlanFullmacImplIfc calls from the test suite to wlanif.
class WlanFullmacImplIfcBridgeServer
: public fidl::Server<fuchsia_wlan_fullmac::WlanFullmacImplIfc> {
using WlanFullmacImplIfc = fuchsia_wlan_fullmac::WlanFullmacImplIfc;
public:
explicit WlanFullmacImplIfcBridgeServer(
async_dispatcher_t* async_dispatcher,
fidl::ServerEnd<fuchsia_wlan_fullmac::WlanFullmacImplIfc> server_end,
fidl::ClientEnd<fuchsia_wlan_fullmac::WlanFullmacImplIfc> bridge_client_end)
: binding_(async_dispatcher, std::move(server_end), this, fidl::kIgnoreBindingClosure),
bridge_client_(std::move(bridge_client_end), async_dispatcher) {
WLAN_TRACE_DURATION();
}
void OnScanResult(OnScanResultRequest& request, OnScanResultCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->OnScanResult(request).Then(
ForwardResult<WlanFullmacImplIfc::OnScanResult>(completer.ToAsync()));
}
void OnScanEnd(OnScanEndRequest& request, OnScanEndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->OnScanEnd(request).Then(
ForwardResult<WlanFullmacImplIfc::OnScanEnd>(completer.ToAsync()));
}
void ConnectConf(ConnectConfRequest& request, ConnectConfCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->ConnectConf(request).Then(
ForwardResult<WlanFullmacImplIfc::ConnectConf>(completer.ToAsync()));
}
void RoamConf(RoamConfRequest& request, RoamConfCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->RoamConf(request).Then(
ForwardResult<WlanFullmacImplIfc::RoamConf>(completer.ToAsync()));
}
void RoamStartInd(RoamStartIndRequest& request, RoamStartIndCompleter::Sync& completer) override {
}
void RoamResultInd(RoamResultIndRequest& request,
RoamResultIndCompleter::Sync& completer) override {}
void AuthInd(AuthIndRequest& request, AuthIndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->AuthInd(request).Then(
ForwardResult<WlanFullmacImplIfc::AuthInd>(completer.ToAsync()));
}
void DeauthConf(DeauthConfRequest& request, DeauthConfCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->DeauthConf(request).Then(
ForwardResult<WlanFullmacImplIfc::DeauthConf>(completer.ToAsync()));
}
void DeauthInd(DeauthIndRequest& request, DeauthIndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->DeauthInd(request).Then(
ForwardResult<WlanFullmacImplIfc::DeauthInd>(completer.ToAsync()));
}
void AssocInd(AssocIndRequest& request, AssocIndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->AssocInd(request).Then(
ForwardResult<WlanFullmacImplIfc::AssocInd>(completer.ToAsync()));
}
void DisassocConf(DisassocConfRequest& request, DisassocConfCompleter::Sync& completer) override {
}
void DisassocInd(DisassocIndRequest& request, DisassocIndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->DisassocInd(request).Then(
ForwardResult<WlanFullmacImplIfc::DisassocInd>(completer.ToAsync()));
}
void StartConf(StartConfRequest& request, StartConfCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->StartConf(request).Then(
ForwardResult<WlanFullmacImplIfc::StartConf>(completer.ToAsync()));
}
void StopConf(StopConfRequest& request, StopConfCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->StopConf(request).Then(
ForwardResult<WlanFullmacImplIfc::StopConf>(completer.ToAsync()));
}
void EapolConf(EapolConfRequest& request, EapolConfCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->EapolConf(request).Then(
ForwardResult<WlanFullmacImplIfc::EapolConf>(completer.ToAsync()));
}
void OnChannelSwitch(OnChannelSwitchRequest& request,
OnChannelSwitchCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->OnChannelSwitch(request).Then(
ForwardResult<WlanFullmacImplIfc::OnChannelSwitch>(completer.ToAsync()));
}
void SignalReport(SignalReportRequest& request, SignalReportCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->SignalReport(request).Then(
ForwardResult<WlanFullmacImplIfc::SignalReport>(completer.ToAsync()));
}
void EapolInd(EapolIndRequest& request, EapolIndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->EapolInd(request).Then(
ForwardResult<WlanFullmacImplIfc::EapolInd>(completer.ToAsync()));
}
void OnPmkAvailable(OnPmkAvailableRequest& request,
OnPmkAvailableCompleter::Sync& completer) override {}
void SaeHandshakeInd(SaeHandshakeIndRequest& request,
SaeHandshakeIndCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->SaeHandshakeInd(request).Then(
ForwardResult<WlanFullmacImplIfc::SaeHandshakeInd>(completer.ToAsync()));
}
void SaeFrameRx(SaeFrameRxRequest& request, SaeFrameRxCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->SaeFrameRx(request).Then(
ForwardResult<WlanFullmacImplIfc::SaeFrameRx>(completer.ToAsync()));
}
void OnWmmStatusResp(OnWmmStatusRespRequest& request,
OnWmmStatusRespCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->OnWmmStatusResp(request).Then(
ForwardResult<WlanFullmacImplIfc::OnWmmStatusResp>(completer.ToAsync()));
}
private:
fidl::ServerBinding<fuchsia_wlan_fullmac::WlanFullmacImplIfc> binding_;
fidl::Client<fuchsia_wlan_fullmac::WlanFullmacImplIfc> bridge_client_;
};
// Server that forwards WlanFullmacImpl calls from wlanif to the test suite.
class WlanFullmacImplBridgeServer : public fidl::Server<fuchsia_wlan_fullmac::WlanFullmacImpl> {
private:
using WlanFullmacImpl = fuchsia_wlan_fullmac::WlanFullmacImpl;
public:
explicit WlanFullmacImplBridgeServer(
async_dispatcher_t* async_dispatcher,
fidl::ServerEnd<fuchsia_wlan_fullmac::WlanFullmacImpl> server_end,
fidl::ClientEnd<fuchsia_wlan_fullmac::WlanFullmacImpl> bridge_client_end,
fidl::ClientEnd<fuchsia_driver_framework::NodeController> controller_client_end)
: binding_(async_dispatcher, std::move(server_end), this,
std::mem_fn(&WlanFullmacImplBridgeServer::OnUnbind)),
bridge_client_(std::move(bridge_client_end), async_dispatcher),
async_dispatcher_(async_dispatcher),
controller_(std::move(controller_client_end), async_dispatcher_) {
WLAN_TRACE_DURATION();
}
void OnUnbind(fidl::UnbindInfo info) {
WLAN_TRACE_DURATION();
if (!info.is_peer_closed()) {
FDF_SLOG(WARNING, "WlanFullmacImplBridge unbinding due to unexpected reason",
KV("reason", info.FormatDescription()));
}
if (!unbind_callback_.has_value()) {
FDF_SLOG(
ERROR,
"Unexpected server unbinding: WlanFullmacImplBridge does not have an unbind callback",
KV("reason", info.FormatDescription()));
return;
}
unbind_callback_.value()();
}
void Init(InitRequest& request, InitCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
// Init has to swap out the fdf::ClientEnd and instead pass along a fidl::ClientEnd to the
// bridge server. This is necessary because the test case runs in a non-driver component,
// which cannot use the fdf::ClientEnd.
zx::result endpoints = fidl::CreateEndpoints<fuchsia_wlan_fullmac::WlanFullmacImplIfc>();
if (endpoints.is_error()) {
FDF_LOG(ERROR, "Could not create WlanFullmacImplIfc endpoints: %s",
endpoints.status_string());
completer.Reply(endpoints.take_error());
return;
}
// Create and bind ifc bridge server.
ifc_bridge_server_ = std::make_unique<WlanFullmacImplIfcBridgeServer>(
async_dispatcher_, std::move(endpoints->server), std::move(*request.ifc()));
InitRequest bridge_init;
bridge_init.ifc() = std::move(endpoints->client);
bridge_client_->Init(std::move(bridge_init))
.Then(
[completer = completer.ToAsync()](fidl::Result<WlanFullmacImpl::Init>& result) mutable {
WLAN_LAMBDA_TRACE_DURATION("WlanFullmacImpl::Init callback");
// Unlike all the other methods in WlanFullmacImpl,
// WlanFullmacImpl::Init and WlanFullmacImpl::Init results are
// considered different types by the compiler. So we need to convert between the two
// types manually here.
if (result.is_error()) {
auto& error = result.error_value();
FDF_SLOG(ERROR, "Init failed", KV("status", error.FormatDescription()));
completer.Reply(zx::error(FidlErrorToStatus(error)));
} else {
// Forward the SME channel provided by test suite
fuchsia_wlan_fullmac::WlanFullmacImplInitResponse response;
response.sme_channel() = std::move(result->sme_channel());
completer.Reply(zx::ok(std::move(response)));
}
});
}
void Query(QueryCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->Query().Then(ForwardResult<WlanFullmacImpl::Query>(completer.ToAsync()));
}
void QuerySecuritySupport(QuerySecuritySupportCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->QuerySecuritySupport().Then(
ForwardResult<WlanFullmacImpl::QuerySecuritySupport>(completer.ToAsync()));
}
void QuerySpectrumManagementSupport(
QuerySpectrumManagementSupportCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->QuerySpectrumManagementSupport().Then(
ForwardResult<WlanFullmacImpl::QuerySpectrumManagementSupport>(completer.ToAsync()));
}
void QueryTelemetrySupport(QueryTelemetrySupportCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->QueryTelemetrySupport().Then(
ForwardResult<WlanFullmacImpl::QueryTelemetrySupport>(completer.ToAsync()));
}
void StartScan(StartScanRequest& request, StartScanCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->StartScan(request).Then(
ForwardResult<WlanFullmacImpl::StartScan>(completer.ToAsync()));
}
void Connect(ConnectRequest& request, ConnectCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->Connect(request).Then(
ForwardResult<WlanFullmacImpl::Connect>(completer.ToAsync()));
}
void Reconnect(ReconnectRequest& request, ReconnectCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->Reconnect(request).Then(
ForwardResult<WlanFullmacImpl::Reconnect>(completer.ToAsync()));
}
void Roam(RoamRequest& request, RoamCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->Roam(request).Then(ForwardResult<WlanFullmacImpl::Roam>(completer.ToAsync()));
}
void AuthResp(AuthRespRequest& request, AuthRespCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->AuthResp(request).Then(
ForwardResult<WlanFullmacImpl::AuthResp>(completer.ToAsync()));
}
void Deauth(DeauthRequest& request, DeauthCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->Deauth(request).Then(
ForwardResult<WlanFullmacImpl::Deauth>(completer.ToAsync()));
}
void AssocResp(AssocRespRequest& request, AssocRespCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->AssocResp(request).Then(
ForwardResult<WlanFullmacImpl::AssocResp>(completer.ToAsync()));
}
void Disassoc(DisassocRequest& request, DisassocCompleter::Sync& completer) override {}
void StartBss(StartBssRequest& request, StartBssCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->StartBss(request).Then(
ForwardResult<WlanFullmacImpl::StartBss>(completer.ToAsync()));
}
void StopBss(StopBssRequest& request, StopBssCompleter ::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->StopBss(request).Then(
ForwardResult<WlanFullmacImpl::StopBss>(completer.ToAsync()));
}
void SetKeys(SetKeysRequest& request, SetKeysCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->SetKeys(request).Then(
ForwardResult<WlanFullmacImpl::SetKeys>(completer.ToAsync()));
}
void EapolTx(EapolTxRequest& request, EapolTxCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->EapolTx(request).Then(
ForwardResult<WlanFullmacImpl::EapolTx>(completer.ToAsync()));
}
void GetIfaceStats(GetIfaceStatsCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->GetIfaceStats().Then(
ForwardResult<WlanFullmacImpl::GetIfaceStats>(completer.ToAsync()));
}
void GetIfaceHistogramStats(GetIfaceHistogramStatsCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->GetIfaceHistogramStats().Then(
ForwardResult<WlanFullmacImpl::GetIfaceHistogramStats>(completer.ToAsync()));
}
void GetSignalReport(GetSignalReportCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->GetSignalReport().Then(
ForwardResult<WlanFullmacImpl::GetSignalReport>(completer.ToAsync()));
}
void SaeHandshakeResp(SaeHandshakeRespRequest& request,
SaeHandshakeRespCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->SaeHandshakeResp(request).Then(
ForwardResult<WlanFullmacImpl::SaeHandshakeResp>(completer.ToAsync()));
}
void SaeFrameTx(SaeFrameTxRequest& request, SaeFrameTxCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->SaeFrameTx(request).Then(
ForwardResult<WlanFullmacImpl::SaeFrameTx>(completer.ToAsync()));
}
void WmmStatusReq(WmmStatusReqCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->WmmStatusReq().Then(
ForwardResult<WlanFullmacImpl::WmmStatusReq>(completer.ToAsync()));
}
void OnLinkStateChanged(OnLinkStateChangedRequest& request,
OnLinkStateChangedCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
bridge_client_->OnLinkStateChanged(request).Then(
ForwardResult<WlanFullmacImpl::OnLinkStateChanged>(completer.ToAsync()));
}
// Calling |RemoveChild| will cause this server to eventually unbind.
// |unbind_callback| will run in |OnUnbind|.
zx::result<> RemoveChild(fit::closure unbind_callback) {
WLAN_TRACE_DURATION();
auto result = controller_->Remove();
if (result.is_error()) {
FDF_SLOG(ERROR, "Failed to remove child",
KV("reason", result.error_value().FormatDescription()));
return zx::error(result.error_value().status());
}
ZX_ASSERT(!unbind_callback_.has_value());
unbind_callback_.emplace(std::move(unbind_callback));
return zx::ok();
}
private:
fidl::ServerBinding<fuchsia_wlan_fullmac::WlanFullmacImpl> binding_;
fidl::Client<fuchsia_wlan_fullmac::WlanFullmacImpl> bridge_client_;
async_dispatcher_t* async_dispatcher_{};
std::unique_ptr<WlanFullmacImplIfcBridgeServer> ifc_bridge_server_;
fidl::Client<fuchsia_driver_framework::NodeController> controller_;
// Callback that runs when the bridge server is unbound.
std::optional<fit::closure> unbind_callback_;
};
class TestController : public fdf::DriverBase,
public fidl::Server<test_wlan_testcontroller::TestController> {
static constexpr std::string_view kDriverName = "wlan_testcontroller";
public:
TestController(fdf::DriverStartArgs start_args,
fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: DriverBase(kDriverName, std::move(start_args), std::move(driver_dispatcher)),
devfs_connector_(bindings_.CreateHandler(this, dispatcher(), fidl::kIgnoreBindingClosure)) {
}
zx::result<> Start() override {
WLAN_TRACE_DURATION();
node_.Bind(std::move(node()));
fidl::Arena arena;
zx::result connector = devfs_connector_.Bind(dispatcher());
if (connector.is_error()) {
return connector.take_error();
}
// By calling AddChild with devfs_args, the child driver will be discoverable through devfs.
auto args =
fuchsia_driver_framework::NodeAddArgs({.name = std::string(kDriverName),
.devfs_args = fuchsia_driver_framework::DevfsAddArgs(
{.connector = std::move(connector.value())})});
auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
auto result = node_->AddChild({std::move(args), std::move(controller_endpoints.server), {}});
if (result.is_error()) {
auto& error = result.error_value();
FDF_SLOG(ERROR, "Failed to add child", KV("status", error.FormatDescription()));
// AddChild's domain error is a NodeError, not a zx_status_t
return zx::error(error.is_domain_error() ? ZX_ERR_INTERNAL
: error.framework_error().status());
}
return zx::ok();
}
// Creates a new fullmac driver.
// On success, this is guaranteed to complete only after wlanif has binded.
// The user can expect that the bridge channels are open and wlanif is up and running once this
// completes.
void CreateFullmac(CreateFullmacRequest& request,
CreateFullmacCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
// Generate a unique child name for the new fullmac child.
uint32_t id = next_fullmac_id_++;
std::string child_name = FullmacChildName(id);
zx::result controller_endpoints =
fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
ZX_ASSERT(controller_endpoints.is_ok());
// The async completer is stored in a shared pointer so that we can pass it to the protocol
// handler callback while also retaining a reference to it in CreateFullmac.
// This lets us complete the call in the protocol handler on success and complete the call in
// CreateFullmac on error.
auto async_completer = std::make_shared<CreateFullmacCompleter::Async>(completer.ToAsync());
auto protocol_handler =
[this, async_completer, id, bridge_client = std::move(request.bridge_client()),
controller_client = std::move(controller_endpoints->client)](
fidl::ServerEnd<fuchsia_wlan_fullmac::WlanFullmacImpl> server_end) mutable {
// It's assumed that this protocol handler runs exactly once, meaning that each call to
// CreateFullmac should result in exactly one call to this protocol handler.
// It's also assumed that this protocol handler runs on the same dispatcher as
// CreateFullmac and cannot run concurrently with CreateFullmac.
// Ensure no duplicate bridges and all ids are unique.
ZX_ASSERT(fullmac_bridges_.find(id) == fullmac_bridges_.end());
// Check that async completer exists and that no other references to async_completer
// exist. This ensures that once this callback runs we can drop async_completer.
ZX_ASSERT(async_completer && async_completer.use_count() == 1);
fullmac_bridges_.try_emplace(id, dispatcher(), std::move(server_end),
std::move(bridge_client), std::move(controller_client));
async_completer->Reply(zx::ok(id));
async_completer.reset();
};
fuchsia_wlan_fullmac::Service::InstanceHandler handler(
{.wlan_fullmac_impl = std::move(protocol_handler)});
zx::result result =
outgoing()->AddService<fuchsia_wlan_fullmac::Service>(std::move(handler), child_name);
if (result.is_error()) {
FDF_LOG(ERROR, "Failed to add fullmac service: %s", result.status_string());
async_completer->Reply(result.take_error());
async_completer.reset();
return;
}
auto offers = std::vector{fdf::MakeOffer2<fuchsia_wlan_fullmac::Service>(child_name)};
auto args = fuchsia_driver_framework::NodeAddArgs({
.name = child_name,
.offers2 = std::move(offers),
});
auto add_child_result =
node_->AddChild({std::move(args), std::move(controller_endpoints->server), {}});
if (add_child_result.is_error()) {
auto& error = add_child_result.error_value();
FDF_SLOG(ERROR, "Failed to add child", KV("status", error.FormatDescription()));
// AddChild's domain error is a NodeError, not a zx_status_t
async_completer->Reply(zx::error(
(error.is_domain_error() ? ZX_ERR_INTERNAL : error.framework_error().status())));
async_completer.reset();
return;
}
}
// Removes the WlanFullmacImpl service which initiates teardown of wlanif.
// On success, this is guaranteed to complete only after wlanif has been fully torn down.
// The user can expect that the bridge channels are closed once this call completes.
void DeleteFullmac(DeleteFullmacRequest& request,
DeleteFullmacCompleter::Sync& completer) override {
WLAN_TRACE_DURATION();
auto bridge_iter = fullmac_bridges_.find(request.id());
if (bridge_iter == fullmac_bridges_.end()) {
FDF_SLOG(ERROR, "Fullmac driver does not exist", KV("id", request.id()));
completer.Reply(zx::error(ZX_ERR_NOT_FOUND));
return;
}
WlanFullmacImplBridgeServer& bridge = bridge_iter->second;
auto node_remove_result = bridge.RemoveChild(
// After the bridge server unbinds, we know that wlanif is fully torn down.
// It is then safe to delete the bridge server and reply to the FIDL call.
[this, id = request.id(), completer = completer.ToAsync()]() mutable {
// This callback posts a task on |dispatcher()| because the |completer| has to run on this
// thread. The bridge server's unbind callback does not run on this thread and will
// fail an assert if we reply to the |completer| directly in the unbind callback.
async::PostTask(dispatcher(), [this, id, completer = std::move(completer)]() mutable {
WLAN_LAMBDA_TRACE_DURATION("WlanFullmacImplBridge unbind callback");
ZX_ASSERT(fullmac_bridges_.find(id) != fullmac_bridges_.end());
fullmac_bridges_.erase(id);
completer.Reply(zx::ok());
});
});
if (node_remove_result.is_error()) {
completer.Reply(zx::error(node_remove_result.error_value()));
return;
}
std::string child_name = FullmacChildName(request.id());
auto service_remove_result =
outgoing()->RemoveService<fuchsia_wlan_fullmac::Service>(child_name);
if (service_remove_result.is_error()) {
FDF_SLOG(ERROR, "Could not remove fullmac service", KV("id", request.id()),
KV("status", service_remove_result.status_string()));
completer.Reply(zx::error(service_remove_result.error_value()));
return;
}
}
private:
static std::string FullmacChildName(test_wlan_testcontroller::FullmacId id) {
std::stringstream ss;
ss << "fullmac-child-" << id;
return ss.str();
}
fidl::SyncClient<fuchsia_driver_framework::Node> node_;
// Holds bindings to TestController, which all bind to this class
fidl::ServerBindingGroup<test_wlan_testcontroller::TestController> bindings_;
// devfs_connector_ lets the class serve the TestController protocol over devfs.
driver_devfs::Connector<test_wlan_testcontroller::TestController> devfs_connector_;
// Used to generate a unique ID for each created fullmac driver.
test_wlan_testcontroller::FullmacId next_fullmac_id_ = 0;
// Maps from id -> bridge server.
// This should only be accessed from the default dispatcher.
std::map<test_wlan_testcontroller::FullmacId, WlanFullmacImplBridgeServer> fullmac_bridges_;
};
} // namespace wlan_testcontroller
FUCHSIA_DRIVER_EXPORT(wlan_testcontroller::TestController);