blob: 0e9a66de6f0582a679fdb7e06a593242a8972ac5 [file] [log] [blame]
// Copyright 2021 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_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_DEVICE_PORT_H_
#define SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_DEVICE_PORT_H_
#include <fuchsia/hardware/network/device/cpp/banjo.h>
#include <fuchsia/hardware/network/mac/cpp/banjo.h>
#include <lib/async/dispatcher.h>
#include <lib/fit/function.h>
#include <lib/stdcompat/optional.h>
#include <fbl/mutex.h>
#include "src/connectivity/network/drivers/network-device/mac/public/network_mac.h"
#include "status_watcher.h"
namespace network::internal {
class DeviceInterface;
class DevicePort : public fidl::WireServer<netdev::Port> {
public:
using TeardownCallback = fit::callback<void(DevicePort&)>;
DevicePort(DeviceInterface* parent, async_dispatcher_t* dispatcher, netdev::wire::PortId id,
ddk::NetworkPortProtocolClient port, std::unique_ptr<MacAddrDeviceInterface> mac,
TeardownCallback on_teardown);
~DevicePort() { port_.Removed(); }
netdev::wire::PortId id() const { return id_; }
ddk::NetworkPortProtocolClient& impl() { return port_; }
// Notifies port of status changes notifications from the network device implementation.
void StatusChanged(const port_status_t& new_status);
// Starts port teardown process.
//
// Once port is torn down and ready to be deleted, the teardown callback passed on construction
// will be called.
// Calling teardown while a teardown is already in progress is a no-op.
void Teardown();
// Notifies the port a session attached to it.
//
// When sessions attach to a port, the port will notify the network port implementation that the
// port is active.
void SessionAttached();
// Notifies the port a session detached from it.
//
// When all sessions are detached from a port, the port will notify the network port
// implementation that the port is inactive.
void SessionDetached();
// Binds a new FIDL request to this port.
void Bind(fidl::ServerEnd<netdev::Port> req);
// Returns true if `frame_type` is a valid inbound frame type for subscription to on this port.
bool IsValidRxFrameType(netdev::wire::FrameType frame_type) const;
// Returns true if `frame_type` is a valid outbound frame type for this port.
bool IsValidTxFrameType(netdev::wire::FrameType frame_type) const;
// FIDL protocol implementation.
void GetInfo(GetInfoRequestView request, GetInfoCompleter::Sync& completer) override;
void GetStatus(GetStatusRequestView request, GetStatusCompleter::Sync& completer) override;
void GetStatusWatcher(GetStatusWatcherRequestView request,
GetStatusWatcherCompleter::Sync& _completer) override;
void GetMac(GetMacRequestView request, GetMacCompleter::Sync& _completer) override;
void GetDevice(GetDeviceRequestView request, GetDeviceCompleter::Sync& _completer) override;
void Clone(CloneRequestView request, CloneCompleter::Sync& _completer) override;
private:
// Helper class to keep track of clients bound to DevicePort.
class Binding : public fbl::DoublyLinkedListable<std::unique_ptr<Binding>> {
public:
Binding() = default;
void Unbind() {
if (binding_.has_value()) {
binding_->Unbind();
}
}
void Bind(fidl::ServerBindingRef<netdev::Port> binding) { binding_ = std::move(binding); }
private:
std::optional<fidl::ServerBindingRef<netdev::Port>> binding_;
};
using BindingList = fbl::DoublyLinkedList<std::unique_ptr<Binding>>;
// Concludes an ongoing teardown if it is ongoing and all internal resources are released.
//
// Returns true if teardown callback was dispatched.
// Callers must assume the port is destroyed immediately if this function returns true.
bool MaybeFinishTeardown() __TA_REQUIRES(lock_);
// Implements session attachment and detachment.
//
// Notifies network port implementation that the port is active when `new_count` is 1.
// Notifies network port implementation that the port is inactive when `new_count` is 0.
// No-op otherwise.
void NotifySessionCount(size_t new_count) __TA_REQUIRES(lock_);
DeviceInterface* const parent_; // Pointer to parent device. Not owned.
async_dispatcher_t* const dispatcher_;
const netdev::wire::PortId id_;
ddk::NetworkPortProtocolClient port_;
std::unique_ptr<MacAddrDeviceInterface> mac_ __TA_GUARDED(lock_);
BindingList bindings_ __TA_GUARDED(lock_);
netdev::wire::DeviceClass port_class_;
std::array<netdev::wire::FrameType, netdev::wire::kMaxFrameTypes> supported_rx_;
size_t supported_rx_count_;
std::array<netdev::wire::FrameTypeSupport, netdev::wire::kMaxFrameTypes> supported_tx_;
size_t supported_tx_count_;
fbl::Mutex lock_;
StatusWatcherList watchers_ __TA_GUARDED(lock_);
TeardownCallback on_teardown_ __TA_GUARDED(lock_);
bool teardown_started_ __TA_GUARDED(lock_) = false;
size_t attached_sessions_count_ __TA_GUARDED(lock_) = 0;
DISALLOW_COPY_ASSIGN_AND_MOVE(DevicePort);
};
} // namespace network::internal
#endif // SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_DEVICE_PORT_H_