blob: 77715b0b6b2d8937c542541aafa7a2bc62bbec6f [file] [log] [blame] [edit]
// 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.
#ifndef SRC_CONNECTIVITY_WLAN_DRIVERS_WLANIF_DEVICE_H_
#define SRC_CONNECTIVITY_WLAN_DRIVERS_WLANIF_DEVICE_H_
#include <fidl/fuchsia.driver.framework/cpp/fidl.h>
#include <fuchsia/wlan/mlme/cpp/fidl.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/component/cpp/node_add_args.h>
#include <lib/driver/outgoing/cpp/outgoing_directory.h>
#include <lib/sync/cpp/completion.h>
#include <lib/zx/result.h>
#include <zircon/types.h>
#include <memory>
#include <sdk/lib/driver/logging/cpp/logger.h>
#include "src/connectivity/wlan/lib/mlme/fullmac/c-binding/bindings.h"
namespace fdf {
using namespace fuchsia_driver_framework;
}
namespace wlanif {
class Device final : public fdf::DriverBase {
public:
explicit Device(fdf::DriverStartArgs start_args,
fdf::UnownedSynchronizedDispatcher driver_dispatcher);
~Device();
static constexpr const char* Name() { return "wlanif"; }
zx::result<> Start() override;
void PrepareStop(fdf::PrepareStopCompleter completer) override;
fdf::Logger* Logger() { return logger_.get(); }
protected:
void Shutdown();
private:
using RustFullmacMlme =
std::unique_ptr<wlan_fullmac_mlme_handle_t, void (*)(wlan_fullmac_mlme_handle_t*)>;
// Called by the Rust MLME on the Rust MLME thread when it exits.
// This is static so that we can pass it to the Rust MLME over the C FFI.
static void MlmeShutdownCallback(void* self_ptr, zx_status_t status);
std::unique_ptr<fdf::Logger> logger_;
// |rust_mlme_| is only accessed by the default dispatcher to start and shutdown MLME in
// |Device::Start| and |Device::PrepareStop| respectively.
// Since it's only accessed by the default dispatcher, locking is not required.
RustFullmacMlme rust_mlme_;
// The following members manage wlanif::Device shutdown.
//
// wlanif::Device can shutdown in one of two ways:
//
// 1. The driver framework begins the unbind process due to an external request (e.g., brcmfmac
// calls DestroyIface and removes wlanif::Device's node). In this case, wlanif::Device must
// stop the Rust MLME before completing shutdown. This is the expected shutdown sequence.
//
// 2. The Rust MLME thread has exited before the driver framework has requested
// that wlanif::Device shuts down. For example, if the Generic SME channel or
// WlanFullmacImplIfc channel is dropped early, then the Rust MLME will exit. When the Rust
// MLME exits, it will request that wlanif::Device begins shutting down by calling
// `node().reset()`. This is considered an error in the shutdown sequence.
// |lock_| protects members that are shared between the Rust MLME thread and the default
// dispatcher thread.
std::mutex lock_;
// |prepare_stop_completer_| is populated if |PrepareStop| is called and |mlme_exit_status_| does
// not contain a value. If |prepare_stop_completer_| contains a value when MLME calls the shutdown
// callback, it completes the call with its exit status.
std::optional<fdf::PrepareStopCompleter> prepare_stop_completer_ __TA_GUARDED(lock_);
// |mlme_exit_status_| is populated if MLME calls its shutdown callback but
// |prepare_stop_completer_| does not have a value.
std::optional<zx_status_t> mlme_exit_status_ __TA_GUARDED(lock_);
};
} // namespace wlanif
#endif // SRC_CONNECTIVITY_WLAN_DRIVERS_WLANIF_DEVICE_H_