blob: 471accb62046f2d5413097d2f7da7695c6aaf063 [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 <wlan/mlme/ap/ap_mlme.h>
#include <wlan/mlme/service.h>
#include <wlan/common/logging.h>
#include <wlan/protocol/mac.h>
#include <zircon/status.h>
namespace wlan {
namespace wlan_mlme = ::fuchsia::wlan::mlme;
ApMlme::ApMlme(DeviceInterface* device) : device_(device) {}
ApMlme::~ApMlme() {
// Ensure the BSS is correctly stopped and terminated when destroying the
// MLME.
if (bss_ != nullptr && bss_->IsStarted()) { bss_->Stop(); }
}
zx_status_t ApMlme::Init() {
debugfn();
return ZX_OK;
}
zx_status_t ApMlme::HandleTimeout(const ObjectId id) {
debugfn();
switch (id.target()) {
case to_enum_type(ObjectTarget::kBss): {
return bss_->HandleTimeout();
}
default:
ZX_DEBUG_ASSERT(false);
break;
}
return ZX_OK;
}
zx_status_t ApMlme::HandleMlmeMsg(const BaseMlmeMsg& msg) {
if (auto start_req = msg.As<wlan_mlme::StartRequest>()) {
return HandleMlmeStartReq(*start_req);
} else if (auto stop_req = msg.As<wlan_mlme::StopRequest>()) {
return HandleMlmeStopReq(*stop_req);
}
return bss_->HandleMlmeMsg(msg);
}
zx_status_t ApMlme::HandleFramePacket(fbl::unique_ptr<Packet> pkt) {
if (bss_ != nullptr) { bss_->HandleAnyFrame(std::move(pkt)); }
return ZX_OK;
}
zx_status_t ApMlme::HandleMlmeStartReq(const MlmeMsg<wlan_mlme::StartRequest>& req) {
debugfn();
// Only one BSS can be started at a time.
if (bss_ != nullptr) {
debugf("BSS %s already running but received MLME-START.request\n",
device_->GetState()->address().ToString().c_str());
return service::SendStartConfirm(
device_, wlan_mlme::StartResultCodes::BSS_ALREADY_STARTED_OR_JOINED);
}
ObjectId timer_id;
timer_id.set_subtype(to_enum_type(ObjectSubtype::kTimer));
timer_id.set_target(to_enum_type(ObjectTarget::kBss));
fbl::unique_ptr<Timer> timer;
zx_status_t status = device_->GetTimer(ToPortKey(PortKeyType::kMlme, timer_id.val()), &timer);
if (status != ZX_OK) {
errorf("Could not create bss timer: %s\n", zx_status_get_string(status));
return service::SendStartConfirm(device_, wlan_mlme::StartResultCodes::INTERNAL_ERROR);
}
// Configure BSS in driver.
auto& bssid = device_->GetState()->address();
wlan_bss_config_t cfg{
.bss_type = WLAN_BSS_TYPE_INFRASTRUCTURE,
.remote = false,
};
bssid.CopyTo(cfg.bssid);
device_->ConfigureBss(&cfg);
// Create and start BSS.
auto bcn_sender = fbl::make_unique<BeaconSender>(device_);
bss_.reset(new InfraBss(device_, std::move(bcn_sender), bssid, std::move(timer)));
bss_->Start(req);
return service::SendStartConfirm(device_, wlan_mlme::StartResultCodes::SUCCESS);
}
zx_status_t ApMlme::HandleMlmeStopReq(const MlmeMsg<wlan_mlme::StopRequest>& req) {
debugfn();
if (bss_ == nullptr) {
errorf("received MLME-STOP.request but no BSS is running on device: %s\n",
device_->GetState()->address().ToString().c_str());
return ZX_OK;
}
// Stop and destroy BSS.
bss_->Stop();
bss_.reset();
return ZX_OK;
}
void ApMlme::HwIndication(uint32_t ind) {
if (ind == WLAN_INDICATION_PRE_TBTT) {
bss_->OnPreTbtt();
} else if (ind == WLAN_INDICATION_BCN_TX_COMPLETE) {
bss_->OnBcnTxComplete();
}
}
HtConfig ApMlme::Ht() const {
return bss_->Ht();
}
const Span<const SupportedRate> ApMlme::Rates() const {
return bss_->Rates();
}
} // namespace wlan