blob: a38b5a6216774f361bbd93b4b055dfc03ed2a771 [file] [log] [blame]
// 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.
#include "test_bss.h"
#include "mock_device.h"
#include <wlan/common/buffer_writer.h>
#include <wlan/common/channel.h>
#include <wlan/common/write_element.h>
#include <wlan/mlme/ap/bss_interface.h>
#include <wlan/mlme/debug.h>
#include <wlan/mlme/mac_frame.h>
#include <wlan/mlme/packet.h>
#include <wlan/mlme/rates_elements.h>
#include <wlan/mlme/service.h>
#include <fbl/unique_ptr.h>
#include <fuchsia/wlan/mlme/c/fidl.h>
#include <fuchsia/wlan/mlme/cpp/fidl.h>
#include <gtest/gtest.h>
namespace wlan {
namespace wlan_mlme = ::fuchsia::wlan::mlme;
void WriteTim(BufferWriter* w, const PsCfg& ps_cfg) {
size_t bitmap_len = ps_cfg.GetTim()->BitmapLen();
uint8_t bitmap_offset = ps_cfg.GetTim()->BitmapOffset();
TimHeader hdr;
hdr.dtim_count = ps_cfg.dtim_count();
hdr.dtim_period = ps_cfg.dtim_period();
ZX_DEBUG_ASSERT(hdr.dtim_count != hdr.dtim_period);
if (hdr.dtim_count == hdr.dtim_period) { warnf("illegal DTIM state"); }
hdr.bmp_ctrl.set_offset(bitmap_offset);
if (ps_cfg.IsDtim()) { hdr.bmp_ctrl.set_group_traffic_ind(ps_cfg.GetTim()->HasGroupTraffic()); }
common::WriteTim(w, hdr, {ps_cfg.GetTim()->BitmapData(), bitmap_len});
}
void WriteCountry(BufferWriter* w, const wlan_channel_t chan) {
const Country kCountry = {{'U', 'S', ' '}};
std::vector<SubbandTriplet> subbands;
// TODO(porce): Read from the AP's regulatory domain
if (wlan::common::Is2Ghz(chan)) {
subbands.push_back({1, 11, 36});
} else {
subbands.push_back({36, 4, 36});
subbands.push_back({52, 4, 30});
subbands.push_back({100, 12, 30});
subbands.push_back({149, 5, 36});
}
common::WriteCountry(w, kCountry, subbands);
}
wlan_mlme::BSSDescription CreateBssDescription(bool rsn, wlan_channel_t chan) {
common::MacAddr bssid(kBssid1);
wlan_mlme::BSSDescription bss_desc;
std::memcpy(bss_desc.bssid.mutable_data(), bssid.byte, common::kMacAddrLen);
std::vector<uint8_t> ssid(kSsid, kSsid + sizeof(kSsid));
bss_desc.ssid.reset(std::move(ssid));
bss_desc.bss_type = wlan_mlme::BSSTypes::INFRASTRUCTURE;
bss_desc.beacon_period = kBeaconPeriodTu;
bss_desc.dtim_period = kDtimPeriodTu;
bss_desc.timestamp = 0;
bss_desc.local_time = 0;
bss_desc.basic_rate_set.resize(0);
bss_desc.op_rate_set.resize(0);
wlan_mlme::CapabilityInfo cap;
cap.ess = true;
cap.short_preamble = true;
bss_desc.cap = cap;
if (rsn) {
bss_desc.rsn.reset(std::vector<uint8_t>(kRsne, kRsne + sizeof(kRsne)));
} else {
bss_desc.rsn.reset();
}
bss_desc.rcpi_dbmh = 0;
bss_desc.rsni_dbh = 0;
bss_desc.ht_cap.reset();
bss_desc.ht_op.reset();
bss_desc.vht_cap.reset();
bss_desc.vht_op.reset();
bss_desc.chan.cbw = static_cast<wlan_mlme::CBW>(chan.cbw);
bss_desc.chan.primary = chan.primary;
bss_desc.rssi_dbm = -35;
return bss_desc;
}
MlmeMsg<wlan_mlme::ScanRequest> CreateScanRequest(uint32_t max_channel_time) {
auto req = wlan_mlme::ScanRequest::New();
req->txn_id = 0;
req->bss_type = wlan_mlme::BSSTypes::ANY_BSS;
std::memcpy(req->bssid.mutable_data(), kBroadcastBssid, sizeof(kBroadcastBssid));
req->ssid.reset({0});
req->scan_type = wlan_mlme::ScanTypes::PASSIVE;
req->channel_list.reset({11});
req->max_channel_time = max_channel_time;
return {std::move(*req), fuchsia_wlan_mlme_MLMEStartScanOrdinal};
}
MlmeMsg<wlan_mlme::StartRequest> CreateStartRequest(bool protected_ap) {
auto req = wlan_mlme::StartRequest::New();
std::vector<uint8_t> ssid(kSsid, kSsid + sizeof(kSsid));
req->ssid.reset(std::move(ssid));
req->bss_type = wlan_mlme::BSSTypes::INFRASTRUCTURE;
req->beacon_period = kBeaconPeriodTu;
req->dtim_period = kDtimPeriodTu;
req->channel = kBssChannel.primary;
req->mesh_id.resize(0);
if (protected_ap) { req->rsne.reset(std::vector<uint8_t>(kRsne, kRsne + sizeof(kRsne))); }
return {std::move(*req), fuchsia_wlan_mlme_MLMEStartReqOrdinal};
}
MlmeMsg<wlan_mlme::JoinRequest> CreateJoinRequest(bool rsn) {
auto req = wlan_mlme::JoinRequest::New();
req->join_failure_timeout = kJoinTimeout;
req->nav_sync_delay = 20;
req->op_rate_set.reset({12, 24, 48});
req->phy = wlan_mlme::PHY::HR;
req->cbw = wlan_mlme::CBW::CBW20;
req->selected_bss = CreateBssDescription(rsn);
req->selected_bss.op_rate_set.reset({12, 24, 48});
return {std::move(*req), fuchsia_wlan_mlme_MLMEJoinReqOrdinal};
}
MlmeMsg<wlan_mlme::AuthenticateRequest> CreateAuthRequest() {
common::MacAddr bssid(kBssid1);
auto req = wlan_mlme::AuthenticateRequest::New();
std::memcpy(req->peer_sta_address.mutable_data(), bssid.byte, common::kMacAddrLen);
req->auth_failure_timeout = kAuthTimeout;
req->auth_type = wlan_mlme::AuthenticationTypes::OPEN_SYSTEM;
return {std::move(*req), fuchsia_wlan_mlme_MLMEAuthenticateReqOrdinal};
}
MlmeMsg<wlan_mlme::DeauthenticateRequest> CreateDeauthRequest(common::MacAddr peer_addr,
wlan_mlme::ReasonCode reason_code) {
auto req = wlan_mlme::DeauthenticateRequest::New();
std::memcpy(req->peer_sta_address.mutable_data(), peer_addr.byte, common::kMacAddrLen);
req->reason_code = reason_code;
return {std::move(*req), fuchsia_wlan_mlme_MLMEDeauthenticateReqOrdinal};
}
MlmeMsg<wlan_mlme::AuthenticateResponse> CreateAuthResponse(
common::MacAddr client_addr, wlan_mlme::AuthenticateResultCodes result_code) {
auto resp = wlan_mlme::AuthenticateResponse::New();
std::memcpy(resp->peer_sta_address.mutable_data(), client_addr.byte, common::kMacAddrLen);
resp->result_code = result_code;
return {std::move(*resp), fuchsia_wlan_mlme_MLMEAuthenticateRespOrdinal};
}
MlmeMsg<wlan_mlme::AssociateRequest> CreateAssocRequest(bool rsn) {
common::MacAddr bssid(kBssid1);
auto req = wlan_mlme::AssociateRequest::New();
std::memcpy(req->peer_sta_address.mutable_data(), bssid.byte, common::kMacAddrLen);
if (rsn) {
req->rsn.reset(std::vector<uint8_t>(kRsne, kRsne + sizeof(kRsne)));
} else {
req->rsn.reset();
}
return {std::move(*req), fuchsia_wlan_mlme_MLMEAssociateReqOrdinal};
}
MlmeMsg<wlan_mlme::AssociateResponse> CreateAssocResponse(
common::MacAddr client_addr, wlan_mlme::AssociateResultCodes result_code, uint16_t aid) {
auto resp = wlan_mlme::AssociateResponse::New();
std::memcpy(resp->peer_sta_address.mutable_data(), client_addr.byte, common::kMacAddrLen);
resp->result_code = result_code;
resp->association_id = aid;
return {std::move(*resp), fuchsia_wlan_mlme_MLMEAssociateRespOrdinal};
}
MlmeMsg<wlan_mlme::EapolRequest> CreateEapolRequest(common::MacAddr src_addr,
common::MacAddr dst_addr) {
auto req = wlan_mlme::EapolRequest::New();
std::memcpy(req->src_addr.mutable_data(), src_addr.byte, common::kMacAddrLen);
std::memcpy(req->dst_addr.mutable_data(), dst_addr.byte, common::kMacAddrLen);
std::vector<uint8_t> eapol_pdu(kEapolPdu, kEapolPdu + sizeof(kEapolPdu));
req->data.reset(std::move(eapol_pdu));
return {std::move(*req), fuchsia_wlan_mlme_MLMEEapolReqOrdinal};
}
MlmeMsg<wlan_mlme::SetKeysRequest> CreateSetKeysRequest(common::MacAddr addr,
std::vector<uint8_t> key_data,
wlan_mlme::KeyType key_type) {
wlan_mlme::SetKeyDescriptor key;
key.key.reset(key_data);
key.key_id = 1;
key.key_type = key_type;
std::memcpy(key.address.mutable_data(), addr.byte, sizeof(addr));
std::memcpy(key.cipher_suite_oui.mutable_data(), kCipherOui, sizeof(kCipherOui));
key.cipher_suite_type = kCipherSuiteType;
std::vector<wlan_mlme::SetKeyDescriptor> keylist;
keylist.emplace_back(std::move(key));
auto req = wlan_mlme::SetKeysRequest::New();
req->keylist.reset(std::move(keylist));
return {std::move(*req), fuchsia_wlan_mlme_MLMESetKeysReqOrdinal};
}
fbl::unique_ptr<Packet> CreateBeaconFrame(common::MacAddr bssid) {
constexpr size_t ie_len = 256;
constexpr size_t max_frame_len = MgmtFrameHeader::max_len() + Beacon::max_len() + ie_len;
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kBeacon);
mgmt_hdr->addr1 = common::kBcastMac;
mgmt_hdr->addr2 = bssid;
mgmt_hdr->addr3 = bssid;
auto bcn = w.Write<Beacon>();
bcn->beacon_interval = kBeaconPeriodTu;
bcn->timestamp = 0;
bcn->cap.set_ess(1);
bcn->cap.set_short_preamble(1);
BufferWriter elem_w(w.RemainingBuffer());
common::WriteSsid(&elem_w, kSsid);
RatesWriter rates_writer{kSupportedRates};
rates_writer.WriteSupportedRates(&elem_w);
common::WriteDsssParamSet(&elem_w, kBssChannel.primary);
WriteCountry(&elem_w, kBssChannel);
rates_writer.WriteExtendedSupportedRates(&elem_w);
packet->set_len(w.WrittenBytes() + elem_w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateProbeRequest() {
common::MacAddr bssid(kBssid1);
common::MacAddr client(kClientAddress);
constexpr size_t ie_len = 256;
constexpr size_t max_frame_len = MgmtFrameHeader::max_len() + ProbeRequest::max_len() + ie_len;
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kBeacon);
mgmt_hdr->addr1 = client;
mgmt_hdr->addr2 = bssid;
mgmt_hdr->addr3 = bssid;
w.Write<ProbeRequest>();
BufferWriter elem_w(w.RemainingBuffer());
common::WriteSsid(&elem_w, kSsid);
RatesWriter rates_writer{kSupportedRates};
rates_writer.WriteSupportedRates(&elem_w);
rates_writer.WriteExtendedSupportedRates(&elem_w);
common::WriteDsssParamSet(&elem_w, kBssChannel.primary);
packet->set_len(w.WrittenBytes() + elem_w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateAuthReqFrame(common::MacAddr client_addr) {
common::MacAddr bssid(kBssid1);
constexpr size_t max_frame_len = MgmtFrameHeader::max_len() + Authentication::max_len();
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kAuthentication);
mgmt_hdr->addr1 = bssid;
mgmt_hdr->addr2 = client_addr;
mgmt_hdr->addr3 = bssid;
auto auth = w.Write<Authentication>();
auth->auth_algorithm_number = AuthAlgorithm::kOpenSystem;
auth->auth_txn_seq_number = 1;
auth->status_code = 0; // Reserved: explicitly set to 0
packet->set_len(w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateAuthRespFrame(AuthAlgorithm auth_algo) {
common::MacAddr bssid(kBssid1);
common::MacAddr client(kClientAddress);
constexpr size_t max_frame_len = MgmtFrameHeader::max_len() + Authentication::max_len();
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kAuthentication);
mgmt_hdr->addr1 = client;
mgmt_hdr->addr2 = bssid;
mgmt_hdr->addr3 = bssid;
auto auth = w.Write<Authentication>();
auth->auth_algorithm_number = auth_algo;
auth->auth_txn_seq_number = 2;
auth->status_code = status_code::kSuccess;
packet->set_len(w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateDeauthFrame(common::MacAddr client_addr) {
common::MacAddr bssid(kBssid1);
constexpr size_t max_frame_len = MgmtFrameHeader::max_len() + Deauthentication::max_len();
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kDeauthentication);
mgmt_hdr->addr1 = bssid;
mgmt_hdr->addr2 = client_addr;
mgmt_hdr->addr3 = bssid;
w.Write<Deauthentication>()->reason_code = reason_code::ReasonCode::kLeavingNetworkDeauth;
packet->set_len(w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateAssocReqFrame(common::MacAddr client_addr, Span<const uint8_t> ssid,
bool rsn) {
common::MacAddr bssid(kBssid1);
// arbitrarily large reserved len; will shrink down later
constexpr size_t ie_len = 1024;
constexpr size_t max_frame_len =
MgmtFrameHeader::max_len() + AssociationRequest::max_len() + ie_len;
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kAssociationRequest);
mgmt_hdr->addr1 = bssid;
mgmt_hdr->addr2 = client_addr;
mgmt_hdr->addr3 = bssid;
auto assoc = w.Write<AssociationRequest>();
CapabilityInfo cap = {};
cap.set_short_preamble(1);
cap.set_ess(1);
assoc->cap = cap;
assoc->listen_interval = kListenInterval;
BufferWriter elem_w(w.RemainingBuffer());
if (!ssid.empty()) { common::WriteSsid(&w, ssid); }
if (rsn) { w.Write(kRsne); }
packet->set_len(w.WrittenBytes() + elem_w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateAssocRespFrame(const AssocContext& ap_assoc_ctx) {
common::MacAddr bssid(kBssid1);
common::MacAddr client(kClientAddress);
constexpr size_t reserved_ie_len = 256;
constexpr size_t max_frame_len =
MgmtFrameHeader::max_len() + AssociationResponse::max_len() + reserved_ie_len;
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
// TODO(NET-2007): Implement a common frame builder
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kAssociationResponse);
mgmt_hdr->addr1 = client;
mgmt_hdr->addr2 = bssid;
mgmt_hdr->addr3 = bssid;
auto assoc = w.Write<AssociationResponse>();
assoc->aid = kAid;
CapabilityInfo cap = {};
cap.set_short_preamble(1);
cap.set_ess(1);
assoc->cap = cap;
assoc->status_code = status_code::kSuccess;
BufferWriter elem_w(w.RemainingBuffer());
if (ap_assoc_ctx.ht_cap.has_value()) {
common::WriteHtCapabilities(&elem_w, ap_assoc_ctx.ht_cap.value());
}
if (ap_assoc_ctx.ht_op.has_value()) {
common::WriteHtOperation(&elem_w, ap_assoc_ctx.ht_op.value());
}
if (ap_assoc_ctx.vht_cap.has_value()) {
common::WriteVhtCapabilities(&elem_w, ap_assoc_ctx.vht_cap.value());
}
if (ap_assoc_ctx.vht_op.has_value()) {
common::WriteVhtOperation(&elem_w, ap_assoc_ctx.vht_op.value());
}
packet->set_len(w.WrittenBytes() + elem_w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
fbl::unique_ptr<Packet> CreateDisassocFrame(common::MacAddr client_addr) {
common::MacAddr bssid(kBssid1);
constexpr size_t max_frame_len = MgmtFrameHeader::max_len() + Disassociation::max_len();
auto packet = GetWlanPacket(max_frame_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto mgmt_hdr = w.Write<MgmtFrameHeader>();
mgmt_hdr->fc.set_type(FrameType::kManagement);
mgmt_hdr->fc.set_subtype(ManagementSubtype::kDisassociation);
mgmt_hdr->addr1 = bssid;
mgmt_hdr->addr2 = client_addr;
mgmt_hdr->addr3 = bssid;
w.Write<Disassociation>()->reason_code = reason_code::ReasonCode::kLeavingNetworkDisassoc;
packet->set_len(w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return packet;
}
DataFrame<LlcHeader> CreateDataFrame(const uint8_t* payload, size_t len) {
common::MacAddr bssid(kBssid1);
common::MacAddr client(kClientAddress);
const size_t buf_len = DataFrameHeader::max_len() + LlcHeader::max_len() + len;
auto packet = GetWlanPacket(buf_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto data_hdr = w.Write<DataFrameHeader>();
data_hdr->fc.set_type(FrameType::kData);
data_hdr->fc.set_subtype(DataSubtype::kDataSubtype);
data_hdr->fc.set_from_ds(1);
data_hdr->addr1 = bssid;
data_hdr->addr2 = bssid;
data_hdr->addr3 = client;
data_hdr->sc.set_val(42);
auto llc_hdr = w.Write<LlcHeader>();
llc_hdr->dsap = kLlcSnapExtension;
llc_hdr->ssap = kLlcSnapExtension;
llc_hdr->control = kLlcUnnumberedInformation;
std::memcpy(llc_hdr->oui, kLlcOui, sizeof(llc_hdr->oui));
llc_hdr->protocol_id = 42;
if (len > 0) { w.Write({payload, len}); }
packet->set_len(w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return DataFrame<LlcHeader>(std::move(packet));
}
DataFrame<> CreateNullDataFrame() {
common::MacAddr bssid(kBssid1);
common::MacAddr client(kClientAddress);
auto packet = GetWlanPacket(DataFrameHeader::max_len());
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto data_hdr = w.Write<DataFrameHeader>();
data_hdr->fc.set_type(FrameType::kData);
data_hdr->fc.set_subtype(DataSubtype::kNull);
data_hdr->fc.set_from_ds(1);
data_hdr->addr1 = client;
data_hdr->addr2 = bssid;
data_hdr->addr3 = bssid;
data_hdr->sc.set_val(42);
packet->set_len(w.WrittenBytes());
wlan_rx_info_t rx_info{.rx_flags = 0};
packet->CopyCtrlFrom(rx_info);
return DataFrame<>(std::move(packet));
}
EthFrame CreateEthFrame(const uint8_t* payload, size_t len) {
common::MacAddr bssid(kBssid1);
common::MacAddr client(kClientAddress);
size_t buf_len = EthernetII::max_len() + len;
auto packet = GetEthPacket(buf_len);
ZX_DEBUG_ASSERT(packet != nullptr);
BufferWriter w(*packet);
auto eth_hdr = w.Write<EthernetII>();
eth_hdr->src = client;
eth_hdr->dest = bssid;
eth_hdr->ether_type = 2;
w.Write({payload, len});
return EthFrame(std::move(packet));
}
} // namespace wlan