_wlansoftmac_c_rustc_static/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
// Copyright 2022 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.
//! C bindings for wlansoftmac-rust crate.
#![deny(unsafe_op_in_unsafe_fn)]
use diagnostics_log::PublishOptions;
use fuchsia_async::LocalExecutor;
use std::ffi::c_void;
use std::sync::Once;
use tracing::info;
use wlan_ffi_transport::completers::Completer;
use wlan_ffi_transport::{EthernetRx, FfiEthernetRx, FfiWlanTx, WlanTx};
use wlan_mlme::device::Device;
use {fidl_fuchsia_wlan_softmac as fidl_softmac, wlan_trace as wtrace};
use fdf::DispatcherBuilder;
static LOGGER_ONCE: Once = Once::new();
/// Start and run a bridged wlansoftmac driver hosting an MLME server and an SME server.
///
/// The driver is "bridged" in the sense that it requires a bridge to a Fuchsia driver to
/// communicate with other Fuchsia drivers over the FDF transport. After the bridged
/// driver starts successfully, `run_start_completer` will be called with `start_completer`.
/// If the bridged driver does not start successfully, this function will return a
/// non-`ZX_OK` status.
///
/// This function returns `ZX_OK` only if shutdown completes successfully. A successful
/// shutdown only occurs if the bridged driver receives a
/// `fuchsia.wlan.softmac/WlanSoftmacIfcBridge.StopBridgedDriver` message and the subsequent
/// teardown of the hosted server succeeds.
///
/// In all other scenarios, e.g., failure during startup, while running, or during shutdown,
/// this function will return a non-`ZX_OK` value.
///
/// # Safety
///
/// This function is unsafe for the following reasons:
///
/// - This function cannot guarantee `run_start_completer` is thread-safe.
/// - This function cannot guarantee `start_completer` points to a valid object when
/// `run_start_completer` is called.
/// - This function cannot guarantee `run_shutdown_completer` is thread-safe.
/// - This function cannot guarantee `shutdown_completer` points to a valid object when
/// `run_shutdown_completer` is called.
/// - This function cannot guarantee `wlan_softmac_bridge_client_handle` is a valid handle.
///
/// By calling this function, the caller promises the following:
///
/// - The `run_start_completer` function is thread-safe.
/// - The `start_completer` pointer will point to a valid object at least until
/// `run_start_completer` is called.
/// - The `run_shutdown_completer` function is thread-safe.
/// - The `shutdown_completer` pointer will point to a valid object at least until
/// `run_shutdown_completer` is called.
/// - The `wlan_softmac_bridge_client_handle` is a valid handle.
#[no_mangle]
pub unsafe extern "C" fn start_bridged_wlansoftmac(
start_completer: *mut c_void,
run_start_completer: unsafe extern "C" fn(
start_completer: *mut c_void,
status: zx::sys::zx_status_t,
),
shutdown_completer: *mut c_void,
run_shutdown_completer: unsafe extern "C" fn(
shutdown_completer: *mut c_void,
status: zx::sys::zx_status_t,
),
ethernet_rx: FfiEthernetRx,
wlan_tx: FfiWlanTx,
wlan_softmac_bridge_client_handle: zx::sys::zx_handle_t,
) -> zx::sys::zx_status_t {
// The Fuchsia syslog must not be initialized from Rust more than once per process. In the case
// of MLME, that means we can only call it once for both the client and ap modules. Ensure this
// by using a shared `Once::call_once()`.
LOGGER_ONCE.call_once(|| {
// Initialize logging with a tag that can be used to filter for forwarding to console
diagnostics_log::initialize_sync(
PublishOptions::default()
.tags(&["wlan"])
.enable_metatag(diagnostics_log::Metatag::Target),
);
});
// Safety: The provided closure is safe to send to another thread because start_completer
// and run_start_completer are thread-safe.
let start_completer = unsafe {
Completer::new_unchecked(move |status| {
// Safety: This is safe because the caller of this function promised
// `run_start_completer` is thread-safe and `start_completer` is valid until
// its called.
run_start_completer(start_completer, status);
})
};
let dispatcher = match DispatcherBuilder::new()
.name("bridged-wlansoftmac")
.allow_thread_blocking()
.shutdown_observer(|_dispatcher| {
wtrace::duration!(c"bridged-wlansoftmac dispatcher shutdown_handler");
info!("Completed bridged-wlansoftmac dispatcher shutdown");
})
// Create a released dispatcher to defer destruction until driver
// shutdown. The framework will shutdown the dispatcher
// despite its release here because the framework tagged this
// driver as the owner of the dispatcher upon creation. The
// framework always automatically shuts down all dispatchers
// owned by a driver during the driver's shut down.
.create_released()
{
Ok(dispatcher) => dispatcher,
Err(status) => {
info!("Failed to create dispatcher for MLME: {}", status);
start_completer.reply(status.into());
return status.into_raw();
}
};
let ethernet_rx = EthernetRx::new(ethernet_rx);
let wlan_tx = WlanTx::new(wlan_tx);
// Safety: The provided closure is safe to send to another thread because shutdown_completer
// and run_shutdown_completer are thread-safe.
let shutdown_completer = unsafe {
Completer::new_unchecked(move |status| {
// Safety: This is safe because the caller of this function promised
// `run_shutdown_completer` is thread-safe and `shutdown_completer` is valid until
// its called.
run_shutdown_completer(shutdown_completer, status);
})
};
let task = dispatcher.spawn_task(async move {
wtrace::duration!(c"Rust MLME dispatcher");
let mut executor = LocalExecutor::new();
let wlan_softmac_bridge_proxy = {
// Safety: This is safe because the caller promises `wlan_softmac_bridge_client_handle`
// is a valid handle.
let handle = unsafe { fidl::Handle::from_raw(wlan_softmac_bridge_client_handle) };
let channel = fidl::Channel::from(handle);
let channel = fidl::AsyncChannel::from_channel(channel);
fidl_softmac::WlanSoftmacBridgeProxy::new(channel)
};
let device = Device::new(wlan_softmac_bridge_proxy, ethernet_rx, wlan_tx);
let result =
executor.run_singlethreaded(wlansoftmac_rust::start_and_serve(start_completer, device));
shutdown_completer.reply(result);
});
zx::Status::from(task).into_raw()
}