| // 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 "src/connectivity/wlan/lib/mlme/cpp/tests/test_bss.h" |
| |
| #include <fuchsia/wlan/ieee80211/cpp/fidl.h> |
| #include <fuchsia/wlan/internal/cpp/fidl.h> |
| #include <fuchsia/wlan/mlme/cpp/fidl.h> |
| |
| #include <memory> |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/connectivity/wlan/lib/common/cpp/include/wlan/common/buffer_writer.h" |
| #include "src/connectivity/wlan/lib/common/cpp/include/wlan/common/channel.h" |
| #include "src/connectivity/wlan/lib/common/cpp/include/wlan/common/write_element.h" |
| #include "src/connectivity/wlan/lib/mlme/cpp/include/wlan/mlme/mac_frame.h" |
| #include "src/connectivity/wlan/lib/mlme/cpp/include/wlan/mlme/packet.h" |
| #include "src/connectivity/wlan/lib/mlme/cpp/include/wlan/mlme/ps_cfg.h" |
| #include "src/connectivity/wlan/lib/mlme/cpp/include/wlan/mlme/rates_elements.h" |
| #include "src/connectivity/wlan/lib/mlme/cpp/include/wlan/mlme/service.h" |
| #include "src/connectivity/wlan/lib/mlme/cpp/tests/mock_device.h" |
| |
| namespace wlan { |
| |
| namespace wlan_common = ::fuchsia::wlan::common; |
| namespace wlan_ieee80211 = ::fuchsia::wlan::ieee80211; |
| namespace wlan_internal = ::fuchsia::wlan::internal; |
| 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_internal::BssDescription CreateBssDescription(bool rsne, wlan_channel_t chan) { |
| common::MacAddr bssid(kBssid1); |
| |
| wlan_internal::BssDescription bss_desc; |
| std::memcpy(bss_desc.bssid.data(), bssid.byte, common::kMacAddrLen); |
| std::vector<uint8_t> ssid(kSsid, kSsid + sizeof(kSsid)); |
| bss_desc.bss_type = wlan_internal::BssTypes::INFRASTRUCTURE; |
| bss_desc.beacon_period = kBeaconPeriodTu; |
| bss_desc.timestamp = 0; |
| bss_desc.local_time = 0; |
| |
| CapabilityInfo cap{}; |
| cap.set_ess(true); |
| cap.set_short_preamble(true); |
| bss_desc.cap = cap.val(); |
| |
| if (rsne) { |
| bss_desc.ies = std::vector<uint8_t>(kIes, kIes + sizeof(kIes)); |
| } else { |
| bss_desc.ies = std::vector<uint8_t>(kIes_NoRsne, kIes_NoRsne + sizeof(kIes_NoRsne)); |
| } |
| |
| bss_desc.chan.cbw = static_cast<wlan_common::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_internal::BssTypes::ANY_BSS; |
| std::memcpy(req->bssid.data(), kBroadcastBssid, sizeof(kBroadcastBssid)); |
| req->ssid = {0}; |
| req->scan_type = wlan_mlme::ScanTypes::PASSIVE; |
| req->channel_list.emplace({11}); |
| req->max_channel_time = max_channel_time; |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_StartScan_Ordinal}; |
| } |
| |
| 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 = std::move(ssid); |
| req->bss_type = wlan_internal::BssTypes::INFRASTRUCTURE; |
| req->beacon_period = kBeaconPeriodTu; |
| req->dtim_period = kDtimPeriodTu; |
| req->channel = kBssChannel.primary; |
| req->rates = {0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c}; |
| req->mesh_id.resize(0); |
| req->phy = wlan_common::PHY::ERP; |
| if (protected_ap) { |
| req->rsne.emplace(std::vector<uint8_t>(kRsne, kRsne + sizeof(kRsne))); |
| } |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_StartReq_Ordinal}; |
| } |
| |
| MlmeMsg<wlan_mlme::StopRequest> CreateStopRequest() { |
| auto req = wlan_mlme::StopRequest::New(); |
| req->ssid = std::vector<uint8_t>(kSsid, kSsid + sizeof(kSsid)); |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_StopReq_Ordinal}; |
| } |
| |
| 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_rates = {12, 24, 48}; |
| req->phy = wlan::common::ToFidl(kBssPhy); |
| req->cbw = wlan::common::ToFidl(kBssChannel).cbw; |
| req->selected_bss = CreateBssDescription(rsn); |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_JoinReq_Ordinal}; |
| } |
| |
| MlmeMsg<wlan_mlme::AuthenticateRequest> CreateAuthRequest() { |
| common::MacAddr bssid(kBssid1); |
| |
| auto req = wlan_mlme::AuthenticateRequest::New(); |
| std::memcpy(req->peer_sta_address.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::internal::kMLME_AuthenticateReq_Ordinal}; |
| } |
| |
| 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.data(), peer_addr.byte, common::kMacAddrLen); |
| req->reason_code = reason_code; |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_DeauthenticateReq_Ordinal}; |
| } |
| |
| 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.data(), client_addr.byte, common::kMacAddrLen); |
| resp->result_code = result_code; |
| |
| return {std::move(*resp), fuchsia::wlan::mlme::internal::kMLME_AuthenticateResp_Ordinal}; |
| } |
| |
| MlmeMsg<wlan_mlme::AssociateRequest> CreateAssocRequest(bool rsne) { |
| common::MacAddr bssid(kBssid1); |
| |
| auto req = wlan_mlme::AssociateRequest::New(); |
| std::memcpy(req->peer_sta_address.data(), bssid.byte, common::kMacAddrLen); |
| req->rates = {std::cbegin(kRates), std::cend(kRates)}; |
| if (rsne) { |
| req->rsne.emplace(std::vector<uint8_t>(kRsne, kRsne + sizeof(kRsne))); |
| } else { |
| req->rsne.reset(); |
| } |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_AssociateReq_Ordinal}; |
| } |
| |
| 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.data(), client_addr.byte, common::kMacAddrLen); |
| resp->result_code = result_code; |
| resp->association_id = aid; |
| resp->rates = {0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c}; |
| |
| return {std::move(*resp), fuchsia::wlan::mlme::internal::kMLME_AssociateResp_Ordinal}; |
| } |
| |
| MlmeMsg<wlan_mlme::NegotiatedCapabilities> CreateFinalizeAssociationRequest( |
| const wlan_assoc_ctx& ac, wlan_channel_t chan) { |
| auto cap = wlan_mlme::NegotiatedCapabilities::New(); |
| cap->channel.primary = chan.primary; |
| cap->channel.cbw = static_cast<wlan_common::CBW>(chan.cbw); |
| cap->channel.secondary80 = chan.secondary80; |
| |
| cap->cap_info = ac.cap_info; |
| cap->rates.assign(ac.rates, ac.rates + ac.rates_cnt); |
| if (ac.has_ht_cap) { |
| cap->ht_cap = wlan_internal::HtCapabilities::New(); |
| static_assert(sizeof(cap->ht_cap->bytes) == sizeof(ac.ht_cap)); |
| memcpy(cap->ht_cap->bytes.data(), &ac.ht_cap, sizeof(ac.ht_cap)); |
| } |
| |
| if (ac.has_vht_cap) { |
| cap->vht_cap = wlan_internal::VhtCapabilities::New(); |
| static_assert(sizeof(cap->vht_cap->bytes) == sizeof(ac.vht_cap)); |
| memcpy(cap->vht_cap->bytes.data(), &ac.vht_cap, sizeof(ac.vht_cap)); |
| } |
| |
| return {std::move(*cap), fuchsia::wlan::mlme::internal::kMLME_FinalizeAssociationReq_Ordinal}; |
| } |
| |
| MlmeMsg<wlan_mlme::EapolRequest> CreateEapolRequest(common::MacAddr src_addr, |
| common::MacAddr dst_addr) { |
| auto req = wlan_mlme::EapolRequest::New(); |
| std::memcpy(req->src_addr.data(), src_addr.byte, common::kMacAddrLen); |
| std::memcpy(req->dst_addr.data(), dst_addr.byte, common::kMacAddrLen); |
| std::vector<uint8_t> eapol_pdu(kEapolPdu, kEapolPdu + sizeof(kEapolPdu)); |
| req->data = std::move(eapol_pdu); |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_EapolReq_Ordinal}; |
| } |
| |
| 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 = key_data; |
| key.key_id = 1; |
| key.key_type = key_type; |
| std::memcpy(key.address.data(), addr.byte, sizeof(addr)); |
| std::memcpy(key.cipher_suite_oui.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 = std::move(keylist); |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_SetKeysReq_Ordinal}; |
| } |
| |
| MlmeMsg<wlan_mlme::SetControlledPortRequest> CreateSetCtrlPortRequest( |
| common::MacAddr peer_addr, wlan_mlme::ControlledPortState state) { |
| auto req = wlan_mlme::SetControlledPortRequest::New(); |
| std::memcpy(req->peer_sta_address.data(), peer_addr.byte, sizeof(peer_addr)); |
| req->state = state; |
| |
| return {std::move(*req), fuchsia::wlan::mlme::internal::kMLME_SetControlledPort_Ordinal}; |
| } |
| |
| std::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, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::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::kProbeRequest); |
| mgmt_hdr->addr1 = bssid; |
| mgmt_hdr->addr2 = client; |
| 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, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::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, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::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 = static_cast<uint16_t>(wlan_ieee80211::StatusCode::SUCCESS); |
| |
| packet->set_len(w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::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 = |
| static_cast<uint16_t>(wlan_ieee80211::ReasonCode::LEAVING_NETWORK_DEAUTH); |
| |
| packet->set_len(w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::unique_ptr<Packet> CreateAssocReqFrame(common::MacAddr client_addr, |
| fbl::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, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::unique_ptr<Packet> CreateAssocRespFrame(const wlan_assoc_ctx_t& 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(fxbug.dev/29264): 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 = static_cast<uint16_t>(wlan_ieee80211::StatusCode::SUCCESS); |
| |
| BufferWriter elem_w(w.RemainingBuffer()); |
| if (ap_assoc_ctx.has_ht_cap) { |
| common::WriteHtCapabilities(&elem_w, HtCapabilities::FromDdk(ap_assoc_ctx.ht_cap)); |
| } |
| if (ap_assoc_ctx.has_ht_op) { |
| common::WriteHtOperation(&elem_w, HtOperation::FromDdk(ap_assoc_ctx.ht_op)); |
| } |
| if (ap_assoc_ctx.has_vht_cap) { |
| common::WriteVhtCapabilities(&elem_w, VhtCapabilities::FromDdk(ap_assoc_ctx.vht_cap)); |
| } |
| if (ap_assoc_ctx.has_vht_op) { |
| common::WriteVhtOperation(&elem_w, VhtOperation::FromDdk(ap_assoc_ctx.vht_op)); |
| } |
| |
| packet->set_len(w.WrittenBytes() + elem_w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::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 = |
| static_cast<uint16_t>(wlan_ieee80211::ReasonCode::LEAVING_NETWORK_DISASSOC); |
| |
| packet->set_len(w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::unique_ptr<Packet> CreateDataFrame(fbl::Span<const uint8_t> payload) { |
| common::MacAddr bssid(kBssid1); |
| common::MacAddr client(kClientAddress); |
| |
| const size_t buf_len = DataFrameHeader::max_len() + LlcHeader::max_len() + payload.size_bytes(); |
| 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_to_ds(0); |
| 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); |
| |
| 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_be = 42; |
| w.Write(payload); |
| |
| packet->set_len(w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| std::unique_ptr<Packet> CreateAmsduDataFramePacket( |
| const std::vector<fbl::Span<const uint8_t>>& payloads) { |
| common::MacAddr bssid(kBssid1); |
| common::MacAddr client(kClientAddress); |
| const uint8_t padding[]{0, 0, 0}; |
| fbl::Span<const uint8_t> padding_span(padding); |
| |
| size_t buf_len = DataFrameHeader::max_len(); |
| for (auto span : payloads) { |
| buf_len += AmsduSubframeHeader::max_len() + LlcHeader::max_len() + span.size_bytes() + 3; |
| }; |
| 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::kQosdata); |
| data_hdr->fc.set_to_ds(0); |
| 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); |
| auto qos_control = w.Write<QosControl>(); |
| qos_control->set_amsdu_present(1); |
| |
| for (auto i = 0ULL; i < payloads.size(); ++i) { |
| auto msdu_hdr = w.Write<AmsduSubframeHeader>(); |
| msdu_hdr->da = client; |
| msdu_hdr->sa = bssid; |
| msdu_hdr->msdu_len_be = htobe16(LlcHeader::max_len() + payloads[i].size_bytes()); |
| |
| 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_be = 42; |
| w.Write(payloads[i]); |
| if (i != payloads.size() - 1) { |
| w.Write(padding_span.subspan(0, (6 - payloads[i].size_bytes()) % 4)); |
| } |
| } |
| |
| packet->set_len(w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return 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, .chan = kBssChannel}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return DataFrame<>(std::move(packet)); |
| } |
| |
| std::unique_ptr<Packet> CreateEthFrame(fbl::Span<const uint8_t> payload) { |
| common::MacAddr bssid(kBssid1); |
| common::MacAddr client(kClientAddress); |
| |
| size_t buf_len = EthernetII::max_len() + payload.size_bytes(); |
| 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_be = 2; |
| w.Write(payload); |
| |
| return packet; |
| } |
| |
| } // namespace wlan |