blob: fad70b00981a01664eda339f87df955c076c7a8b [file] [log] [blame]
// Copyright 2017 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_WLAN_DEVICE_H_
#define SRC_CONNECTIVITY_WLAN_DRIVERS_WLAN_DEVICE_H_
#include <fuchsia/hardware/ethernet/cpp/banjo.h>
#include <fuchsia/hardware/wlan/mac/cpp/banjo.h>
#include <fuchsia/wlan/minstrel/cpp/fidl.h>
#include <lib/zx/channel.h>
#include <lib/zx/port.h>
#include <zircon/compiler.h>
#include <memory>
#include <mutex>
#include <thread>
#include <tuple>
#include <unordered_set>
#include <ddk/driver.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_ptr.h>
#include <fbl/slab_allocator.h>
#include <wlan/common/macaddr.h>
#include <wlan/mlme/device_interface.h>
#include <wlan/mlme/dispatcher.h>
#include <wlan/mlme/packet.h>
#include <wlan/mlme/timer.h>
#include <wlan/protocol/mac.h>
#include "minstrel.h"
typedef struct zx_port_packet zx_port_packet_t;
namespace wlan {
class Device : public DeviceInterface {
public:
Device(zx_device_t* device, wlanmac_protocol_t wlanmac_proto);
~Device();
zx_status_t Bind();
// ddk device methods
void EthUnbind();
void EthRelease();
// ddk wlanmac_ifc_t methods
void WlanmacStatus(uint32_t status);
void WlanmacRecv(uint32_t flags, const void* data, size_t length, const wlan_rx_info_t* info);
void WlanmacCompleteTx(wlan_tx_packet_t* pkt, zx_status_t status);
void WlanmacIndication(uint32_t ind);
void WlanmacReportTxStatus(const wlan_tx_status_t* tx_status);
void WlanmacHwScanComplete(const wlan_hw_scan_result_t* result);
// ddk ethernet_impl_protocol_ops methods
zx_status_t EthernetImplQuery(uint32_t options, ethernet_info_t* info);
zx_status_t EthernetImplStart(const ethernet_ifc_protocol_t* ifc) __TA_EXCLUDES(lock_);
void EthernetImplStop() __TA_EXCLUDES(lock_);
void EthernetImplQueueTx(uint32_t options, ethernet_netbuf_t* netbuf,
ethernet_impl_queue_tx_callback completion_cb, void* cookie);
zx_status_t EthernetImplSetParam(uint32_t param, int32_t value, const void* data,
size_t data_size);
// DeviceInterface methods
zx_handle_t GetSmeChannelRef() final;
zx_status_t GetTimer(uint64_t id, std::unique_ptr<Timer>* timer) final;
zx_status_t DeliverEthernet(fbl::Span<const uint8_t> eth_frame) final;
zx_status_t SendWlan(std::unique_ptr<Packet> packet, uint32_t flags) final;
zx_status_t SendService(fbl::Span<const uint8_t> span) final;
zx_status_t SetChannel(wlan_channel_t chan) final;
zx_status_t SetStatus(uint32_t status) final;
zx_status_t ConfigureBss(wlan_bss_config_t* cfg) final;
zx_status_t EnableBeaconing(wlan_bcn_config_t* bcn_cfg) final;
zx_status_t ConfigureBeacon(std::unique_ptr<Packet> beacon) final;
zx_status_t SetKey(wlan_key_config_t* key_config) final;
zx_status_t StartHwScan(const wlan_hw_scan_config_t* scan_config) final;
zx_status_t ConfigureAssoc(wlan_assoc_ctx_t* assoc_ctx) final;
fbl::RefPtr<DeviceState> GetState() final;
zx_status_t ClearAssoc(const common::MacAddr& peer_addr) final;
const wlanmac_info_t& GetWlanMacInfo() const final;
zx_status_t GetMinstrelPeers(::fuchsia::wlan::minstrel::Peers* peers_fidl) final;
zx_status_t GetMinstrelStats(const common::MacAddr& addr,
::fuchsia::wlan::minstrel::Peer* peer_fidl) final;
private:
struct TimerSchedulerImpl : public TimerScheduler {
Device* device_;
std::unordered_set<uint64_t> scheduled_timers_ = {};
explicit TimerSchedulerImpl(Device* device) : device_(device) {}
zx_status_t Schedule(Timer* timer, zx::time deadline) override;
zx_status_t Cancel(Timer*) override;
};
enum class DevicePacket : uint64_t {
kShutdown,
kPacketQueued,
kIndication,
kHwScanComplete,
};
zx_status_t AddEthDevice();
std::unique_ptr<Packet> PreparePacket(const void* data, size_t length, Packet::Peer peer);
template <typename T>
std::unique_ptr<Packet> PreparePacket(const void* data, size_t length, Packet::Peer peer,
const T& ctrl_data) {
auto packet = PreparePacket(data, length, peer);
if (packet != nullptr) {
packet->CopyCtrlFrom(ctrl_data);
}
return packet;
}
// Establishes a connection with this interface's SME on the given channel.
zx_status_t Connect(zx::channel request);
zx_status_t QueuePacket(std::unique_ptr<Packet> packet) __TA_EXCLUDES(packet_queue_lock_);
// Waits the main loop to finish and frees itself afterwards.
void DestroySelf();
void MainLoop();
// Informs the message loop to shut down. Calling this function more than once
// has no effect.
void ShutdownMainLoop();
void ProcessChannelPacketLocked(uint64_t signal_count) __TA_REQUIRES(lock_);
zx_status_t RegisterChannelWaitLocked() __TA_REQUIRES(lock_);
// Queue a packet that does not contain user data, either there is no user
// data or user data is too large and needs to be enqueued into packet_queue_
// separately.
zx_status_t QueueDevicePortPacket(DevicePacket id, uint32_t status = 0);
void SetStatusLocked(uint32_t status);
bool ShouldEnableMinstrel();
zx_status_t CreateMinstrel(uint32_t features);
void AddMinstrelPeer(const wlan_assoc_ctx_t& assoc_ctx);
zx_device_t* parent_ = nullptr;
zx_device_t* ethdev_ = nullptr;
ddk::WlanmacProtocolClient wlanmac_proxy_;
ddk::EthernetIfcProtocolClient ethernet_proxy_;
wlanmac_info_t wlanmac_info_ = {};
fbl::RefPtr<DeviceState> state_;
std::mutex lock_;
std::thread work_thread_;
zx::port port_;
std::unique_ptr<MinstrelRateSelector> minstrel_;
std::unique_ptr<Dispatcher> dispatcher_ __TA_GUARDED(lock_);
bool dead_ __TA_GUARDED(lock_) = false;
zx::channel channel_ __TA_GUARDED(lock_);
std::mutex packet_queue_lock_;
PacketQueue packet_queue_ __TA_GUARDED(packet_queue_lock_);
std::vector<uint8_t> fidl_msg_buf_ __TA_GUARDED(lock_);
TimerSchedulerImpl timer_scheduler_;
};
zx_status_t ValidateWlanMacInfo(const wlanmac_info& wlanmac_info);
} // namespace wlan
#endif // SRC_CONNECTIVITY_WLAN_DRIVERS_WLAN_DEVICE_H_