blob: ea95f09edd1fa3adaf75ef3eec65f9a8ee0814a9 [file] [log] [blame] [edit]
// 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 "softmac_ifc_bridge.h"
#include <fidl/fuchsia.driver.framework/cpp/driver/fidl.h>
#include <fidl/fuchsia.wlan.softmac/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/fdf/cpp/dispatcher.h>
#include <lib/fidl/cpp/wire_natural_conversions.h>
#include <lib/fidl_driver/cpp/transport.h>
#include <lib/operation/ethernet.h>
#include <lib/sync/cpp/completion.h>
#include <lib/trace-engine/types.h>
#include <lib/zx/result.h>
#include <zircon/errors.h>
#include <wlan/drivers/fidl_bridge.h>
#include <wlan/drivers/log.h>
#include "src/connectivity/wlan/drivers/wlansoftmac/rust_driver/c-binding/bindings.h"
namespace wlan::drivers::wlansoftmac {
using ::wlan::drivers::fidl_bridge::ForwardWireResult;
zx::result<std::unique_ptr<SoftmacIfcBridge>> SoftmacIfcBridge::New(
fidl::SharedClient<fuchsia_driver_framework::Node> node_client,
const ethernet_tx_t* ethernet_tx, const wlan_rx_t* wlan_rx,
fdf::ServerEnd<fuchsia_wlan_softmac::WlanSoftmacIfc>&& server_endpoint,
fidl::ClientEnd<fuchsia_wlan_softmac::WlanSoftmacIfcBridge>&&
softmac_ifc_bridge_client_endpoint) {
WLAN_TRACE_DURATION();
auto softmac_ifc_bridge =
std::unique_ptr<SoftmacIfcBridge>(new SoftmacIfcBridge(ethernet_tx, wlan_rx));
{
WLAN_LAMBDA_TRACE_DURATION("WlanSoftmacIfc server binding");
softmac_ifc_bridge->softmac_ifc_server_binding_ =
std::make_unique<fdf::ServerBinding<fuchsia_wlan_softmac::WlanSoftmacIfc>>(
fdf::Dispatcher::GetCurrent()->get(), std::move(server_endpoint),
softmac_ifc_bridge.get(),
[node_client = std::move(node_client)](fidl::UnbindInfo info) mutable {
WLAN_LAMBDA_TRACE_DURATION("WlanSoftmacIfc close_handler");
if (info.is_user_initiated()) {
FDF_LOG(INFO, "WlanSoftmacIfc server closed.");
} else {
FDF_LOG(ERROR, "WlanSoftmacIfc unexpectedly closed: %s", info.lossy_description());
// Initiate asynchronous teardown of the fuchsia.driver.framework/Node proxy
// to cause the driver framework to stop this driver. Stopping this driver is
// appropriate when this binding has an abnormal shutdown because otherwise this
// driver would be in an unusable state.
node_client.AsyncTeardown();
}
});
}
softmac_ifc_bridge->softmac_ifc_bridge_client_ =
std::make_unique<fidl::Client<fuchsia_wlan_softmac::WlanSoftmacIfcBridge>>(
std::move(softmac_ifc_bridge_client_endpoint),
fdf::Dispatcher::GetCurrent()->async_dispatcher());
return fit::ok(std::move(softmac_ifc_bridge));
}
void SoftmacIfcBridge::Recv(RecvRequestView fdf_request, fdf::Arena& arena,
RecvCompleter::Sync& completer) {
trace_async_id_t async_id = TRACE_NONCE();
WLAN_TRACE_ASYNC_BEGIN_RX(async_id);
WLAN_TRACE_DURATION();
auto raw_arena = arena.release();
// Add a reference to the arena so the arena can be reused for the reply as well.
fdf_arena_add_ref(raw_arena);
fdf::Arena reply_arena(raw_arena);
fuchsia_wlan_softmac::WlanRxTransferRequest fidl_request;
fidl_request.packet_address(reinterpret_cast<uint64_t>(fdf_request->packet.mac_frame.data()));
fidl_request.packet_size(reinterpret_cast<uint64_t>(fdf_request->packet.mac_frame.size()));
fidl_request.packet_info(fidl::ToNatural(fdf_request->packet.info));
fidl_request.async_id(async_id);
fidl_request.arena(reinterpret_cast<uint64_t>(raw_arena));
auto fidl_request_persisted = ::fidl::Persist(fidl_request);
if (fidl_request_persisted.is_ok()) {
wlan_rx_.transfer(wlan_rx_.ctx, fidl_request_persisted.value().data(),
fidl_request_persisted.value().size());
} else {
FDF_LOG(ERROR, "Failed to persist WlanRx.Tranfer fidl_request (FIDL error %s)",
fidl_request_persisted.error_value().status_string());
}
completer.buffer(reply_arena).Reply();
}
// Safety: This function type matches the requirement of
// fuchsia.wlan.softmac/EthernetTx.complete_borrowed_operation.
void complete_borrowed_operation(eth::BorrowedOperation<>* op, zx_status_t status) {
op->Complete(status);
delete op;
}
zx::result<> SoftmacIfcBridge::EthernetTx(std::unique_ptr<eth::BorrowedOperation<>> op,
trace_async_id_t async_id) const {
WLAN_TRACE_DURATION();
fuchsia_wlan_softmac::EthernetTxTransferRequest request;
request.packet_address(reinterpret_cast<uint64_t>(op->operation()->data_buffer));
request.packet_size(reinterpret_cast<uint64_t>(op->operation()->data_size));
request.async_id(async_id);
// Safety: These fields are properly set according to the requirements of
// fuchsia.wlan.softmac/EthernetTx.
auto op_ptr = op.release();
request.borrowed_operation(reinterpret_cast<uint64_t>(op_ptr));
request.complete_borrowed_operation(reinterpret_cast<uint64_t>(complete_borrowed_operation));
auto fidl_request_persisted = ::fidl::Persist(request);
if (!fidl_request_persisted.is_ok()) {
FDF_LOG(ERROR, "Failed to persist EthernetTx.Transfer request (FIDL error %s)",
fidl_request_persisted.error_value().status_string());
}
auto result =
zx::make_result(ethernet_tx_.transfer(ethernet_tx_.ctx, fidl_request_persisted.value().data(),
fidl_request_persisted.value().size()));
// wlan_ffi_transport::EthernetTx::ethernet_tx_transfer returns ZX_ERR_BAD_STATE if and only if
// it did not take ownership of the BorrowedOperation before returning.
if (result.status_value() == ZX_ERR_BAD_STATE) {
complete_borrowed_operation(op_ptr, result.status_value());
}
return result;
}
void SoftmacIfcBridge::ReportTxResult(ReportTxResultRequestView request, fdf::Arena& arena,
ReportTxResultCompleter::Sync& completer) {
WLAN_TRACE_DURATION();
(*softmac_ifc_bridge_client_)
->ReportTxResult(fidl::ToNatural(*request))
.Then(ForwardWireResult<fuchsia_wlan_softmac::WlanSoftmacIfcBridge::ReportTxResult>(
completer.ToAsync(), fdf::Arena(arena.release())));
}
void SoftmacIfcBridge::NotifyScanComplete(NotifyScanCompleteRequestView request, fdf::Arena& arena,
NotifyScanCompleteCompleter::Sync& completer) {
WLAN_TRACE_DURATION();
(*softmac_ifc_bridge_client_)
->NotifyScanComplete(fidl::ToNatural(*request))
.Then(ForwardWireResult<fuchsia_wlan_softmac::WlanSoftmacIfcBridge::NotifyScanComplete>(
completer.ToAsync(), fdf::Arena(arena.release())));
}
void SoftmacIfcBridge::StopBridgedDriver(fit::callback<void()> stop_completer) {
WLAN_TRACE_DURATION();
(*softmac_ifc_bridge_client_)
->StopBridgedDriver()
.Then([stop_completer = std::move(stop_completer)](
fidl::Result<fuchsia_wlan_softmac::WlanSoftmacIfcBridge::StopBridgedDriver>&
result) mutable {
if (result.is_error()) {
FDF_LOG(ERROR, "FIDL error calling StopBridgeDriver: %s",
result.error_value().status_string());
}
stop_completer();
});
}
} // namespace wlan::drivers::wlansoftmac