blob: 3052acc942acd9f1d2332beaeac19e1810d1247d [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.
#include <zircon/status.h>
#include <memory>
#include <wlan/common/logging.h>
#include <wlan/mlme/ap/ap_mlme.h>
#include <wlan/mlme/rust_utils.h>
#include <wlan/mlme/service.h>
#include <wlan/protocol/mac.h>
namespace wlan {
namespace wlan_mlme = ::fuchsia::wlan::mlme;
#define MLME(m) static_cast<ApMlme*>(m)
ApMlme::ApMlme(DeviceInterface* device) : device_(device), rust_ap_(nullptr, ap_sta_delete) {
auto rust_device = mlme_device_ops_t{
.device = static_cast<void*>(this),
.deliver_eth_frame = [](void* mlme, const uint8_t* data, size_t len) -> zx_status_t {
return MLME(mlme)->device_->DeliverEthernet({data, len});
},
.send_wlan_frame = [](void* mlme, mlme_out_buf_t buf, uint32_t flags) -> zx_status_t {
return MLME(mlme)->device_->SendWlan(FromRustOutBuf(buf), flags);
},
.get_sme_channel = [](void* mlme) -> zx_handle_t {
return MLME(mlme)->device_->GetSmeChannelRef();
},
.get_wlan_channel = [](void* mlme) -> wlan_channel_t {
return MLME(mlme)->device_->GetState()->channel();
},
.set_wlan_channel = [](void* mlme, wlan_channel_t chan) -> zx_status_t {
return MLME(mlme)->device_->SetChannel(chan);
},
.set_key = [](void* mlme, wlan_key_config_t* key) -> zx_status_t {
return MLME(mlme)->device_->SetKey(key);
},
.get_wlan_info = [](void* mlme) -> wlanmac_info_t {
return MLME(mlme)->device_->GetWlanInfo();
},
.configure_bss = [](void* mlme, wlan_bss_config_t* cfg) -> zx_status_t {
return MLME(mlme)->device_->ConfigureBss(cfg);
},
.enable_beaconing = [](void* mlme, mlme_out_buf_t buf, size_t tim_ele_offset,
uint16_t beacon_interval) -> zx_status_t {
auto pkt = FromRustOutBuf(buf);
wlan_bcn_config_t bcn_cfg = {
.tmpl =
{
.packet_head =
{
.data_buffer = pkt->data(),
.data_size = pkt->size(),
},
},
.tim_ele_offset = tim_ele_offset,
.beacon_interval = beacon_interval,
};
return MLME(mlme)->device_->EnableBeaconing(&bcn_cfg);
},
.disable_beaconing = [](void* mlme) -> zx_status_t {
return MLME(mlme)->device_->EnableBeaconing(nullptr);
},
.configure_beacon = [](void* mlme, mlme_out_buf_t buf) -> zx_status_t {
return MLME(mlme)->device_->ConfigureBeacon(FromRustOutBuf(buf));
},
.set_link_status = [](void* mlme, uint8_t status) -> zx_status_t {
(void)mlme;
(void)status;
return ZX_ERR_NOT_SUPPORTED;
},
.configure_assoc = [](void* mlme, wlan_assoc_ctx_t* assoc_ctx) -> zx_status_t {
return MLME(mlme)->device_->ConfigureAssoc(assoc_ctx);
},
.clear_assoc = [](void* mlme, const uint8_t(*addr)[6]) -> zx_status_t {
return MLME(mlme)->device_->ClearAssoc(common::MacAddr(*addr));
},
};
wlan_scheduler_ops_t scheduler = {
.cookie = this,
.now = [](void* cookie) -> zx_time_t { return MLME(cookie)->timer_mgr_->Now().get(); },
.schedule = [](void* cookie, int64_t deadline) -> wlan_scheduler_event_id_t {
TimeoutId id = {};
MLME(cookie)->timer_mgr_->Schedule(zx::time(deadline), {}, &id);
return {._0 = id.raw()};
},
.cancel =
[](void* cookie, wlan_scheduler_event_id_t id) {
MLME(cookie)->timer_mgr_->Cancel(TimeoutId(id._0));
},
};
rust_ap_ =
NewApStation(rust_device, rust_buffer_provider, scheduler, device_->GetState()->address());
}
zx_status_t ApMlme::Init() {
debugfn();
ObjectId timer_id;
timer_id.set_subtype(to_enum_type(ObjectSubtype::kTimer));
timer_id.set_target(to_enum_type(ObjectTarget::kApMlme));
std::unique_ptr<Timer> timer;
if (zx_status_t status = device_->GetTimer(ToPortKey(PortKeyType::kMlme, timer_id.val()), &timer);
status != ZX_OK) {
errorf("Could not create ap timer: %s\n", zx_status_get_string(status));
return status;
}
timer_mgr_ = std::make_unique<TimerManager<std::tuple<>>>(std::move(timer));
return ZX_OK;
}
zx_status_t ApMlme::HandleTimeout(const ObjectId id) {
debugfn();
if (id.target() != to_enum_type(ObjectTarget::kApMlme)) {
ZX_DEBUG_ASSERT(false);
return ZX_ERR_NOT_SUPPORTED;
}
return timer_mgr_->HandleTimeout([&](auto now, auto target, auto timeout_id) {
ap_sta_timeout_fired(rust_ap_.get(), wlan_scheduler_event_id_t{._0 = timeout_id.raw()});
});
}
zx_status_t ApMlme::HandleEncodedMlmeMsg(fbl::Span<const uint8_t> msg) {
debugfn();
return ap_sta_handle_mlme_msg(rust_ap_.get(), AsWlanSpan(msg));
}
zx_status_t ApMlme::HandleMlmeMsg(const BaseMlmeMsg& msg) {
debugfn();
// We don't handle MLME messages at this level.
(void)msg;
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t ApMlme::HandleFramePacket(std::unique_ptr<Packet> pkt) {
switch (pkt->peer()) {
case Packet::Peer::kEthernet: {
if (auto eth_frame = EthFrameView::CheckType(pkt.get()).CheckLength()) {
return ap_sta_handle_eth_frame(rust_ap_.get(), AsWlanSpan({pkt->data(), pkt->len()}));
}
break;
}
case Packet::Peer::kWlan: {
const wlan_rx_info_t* rx_info = nullptr;
if (pkt->has_ctrl_data<wlan_rx_info_t>()) {
rx_info = pkt->ctrl_data<wlan_rx_info_t>();
}
return ap_sta_handle_mac_frame(rust_ap_.get(),
wlan_span_t{.data = pkt->data(), .size = pkt->len()}, rx_info);
}
default:
errorf("unknown Packet peer: %u\n", pkt->peer());
break;
}
return ZX_OK;
}
void ApMlme::HwIndication(uint32_t ind) {
ap_sta_handle_hw_indication(rust_ap_.get(), static_cast<wlan_indication_t>(ind));
}
} // namespace wlan