| // 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_common = ::fuchsia::wlan::common; |
| 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 = 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_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_mlme::BSSTypes::ANY_BSS; |
| std::memcpy(req->bssid.mutable_data(), kBroadcastBssid, sizeof(kBroadcastBssid)); |
| req->ssid = {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 = 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::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_MLMEStopReqOrdinal}; |
| } |
| |
| 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 = {12, 24, 48}; |
| req->phy = wlan::common::ToFidl(kBssPhy); |
| req->cbw = wlan::common::ToFidl(kBssChannel).cbw; |
| req->selected_bss = CreateBssDescription(rsn); |
| req->selected_bss.op_rate_set = {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 = 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 = 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 = std::move(keylist); |
| |
| return {std::move(*req), fuchsia_wlan_mlme_MLMESetKeysReqOrdinal}; |
| } |
| |
| 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.mutable_data(), peer_addr.byte, sizeof(peer_addr)); |
| req->state = state; |
| |
| 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; |
| } |
| |
| fbl::unique_ptr<Packet> CreateDataFrame(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_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; |
| w.Write(payload); |
| |
| packet->set_len(w.WrittenBytes()); |
| |
| wlan_rx_info_t rx_info{.rx_flags = 0}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return packet; |
| } |
| |
| fbl::unique_ptr<Packet> CreateAmsduDataFramePacket( |
| const std::vector<Span<const uint8_t>>& payloads) { |
| common::MacAddr bssid(kBssid1); |
| common::MacAddr client(kClientAddress); |
| const uint8_t padding[]{0, 0, 0}; |
| 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_from_ds(1); |
| data_hdr->addr1 = bssid; |
| data_hdr->addr2 = bssid; |
| data_hdr->addr3 = client; |
| 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 = 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}; |
| 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}; |
| packet->CopyCtrlFrom(rx_info); |
| |
| return DataFrame<>(std::move(packet)); |
| } |
| |
| fbl::unique_ptr<Packet> CreateEthFrame(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 = 2; |
| w.Write(payload); |
| |
| return packet; |
| } |
| |
| } // namespace wlan |