diff options
| author | Subv <subv2112@gmail.com> | 2017-03-19 21:36:51 -0500 | 
|---|---|---|
| committer | Subv <subv2112@gmail.com> | 2017-05-15 13:05:15 -0500 | 
| commit | 528dea988c9f8012a2872e78f168eac1b3161c57 (patch) | |
| tree | cd690d01edb47cef0877b104e56e485d971c6686 | |
| parent | 26745f28ea00f1f085ef030cc4be4a4eae44e5a6 (diff) | |
Services/UDS: Generate the UDS beacons when the beacon callback fires.
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.cpp | 31 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.h | 5 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_beacon.cpp | 333 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_beacon.h | 173 | 
5 files changed, 537 insertions, 7 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 61a0b1cc3..ee03567e0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -140,6 +140,7 @@ set(SRCS              hle/service/nwm/nwm_soc.cpp              hle/service/nwm/nwm_tst.cpp              hle/service/nwm/nwm_uds.cpp +            hle/service/nwm/uds_beacon.cpp              hle/service/pm_app.cpp              hle/service/ptm/ptm.cpp              hle/service/ptm/ptm_gets.cpp @@ -328,6 +329,7 @@ set(HEADERS              hle/service/nwm/nwm_soc.h              hle/service/nwm/nwm_tst.h              hle/service/nwm/nwm_uds.h +            hle/service/nwm/uds_beacon.h              hle/service/pm_app.h              hle/service/ptm/ptm.h              hle/service/ptm/ptm_gets.h diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index ef6c5ebe3..f016550b5 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <array>  #include <cstring>  #include <unordered_map>  #include <vector> @@ -12,6 +13,7 @@  #include "core/hle/kernel/shared_memory.h"  #include "core/hle/result.h"  #include "core/hle/service/nwm/nwm_uds.h" +#include "core/hle/service/nwm/uds_beacon.h"  #include "core/memory.h"  namespace Service { @@ -27,10 +29,12 @@ static Kernel::SharedPtr<Kernel::SharedMemory> recv_buffer_memory;  // Connection status of this 3DS.  static ConnectionStatus connection_status{}; -// Node information about the current 3DS. -// TODO(Subv): Keep an array of all nodes connected to the network, -// that data has to be retransmitted in every beacon frame. -static NodeInfo node_info; +/* Node information about the current network. + * The amount of elements in this vector is always the maximum number + * of nodes specified in the network configuration. + * The first node is always the host, so this always contains at least 1 entry. + */ +static NodeList node_info(1);  // Mapping of bind node ids to their respective events.  static std::unordered_map<u32, Kernel::SharedPtr<Kernel::Event>> bind_node_events; @@ -127,7 +131,7 @@ static void InitializeWithVersion(Interface* self) {      u32 sharedmem_size = rp.Pop<u32>();      // Update the node information with the data the game gave us. -    rp.PopRaw(node_info); +    rp.PopRaw(node_info[0]);      u16 version;      rp.PopRaw(version); @@ -251,13 +255,25 @@ static void BeginHostingNetwork(Interface* self) {      ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member.");      connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost); + +    // Ensure the application data size is less than the maximum value. +    ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, "Data size is too big."); + +    // Set up basic information for this network. +    network_info.oui_value = NintendoOUI; +    network_info.oui_type = static_cast<u8>(NintendoTagId::NetworkInfo); +      connection_status.max_nodes = network_info.max_nodes; +    // Resize the nodes list to hold max_nodes. +    node_info.resize(network_info.max_nodes); +      // There's currently only one node in the network (the host).      connection_status.total_nodes = 1; +    network_info.total_nodes = 1;      // The host is always the first node      connection_status.network_node_id = 1; -    node_info.network_node_id = 1; +    node_info[0].network_node_id = 1;      // Set the bit 0 in the nodes bitmask to indicate that node 1 is already taken.      connection_status.node_bitmask |= 1; @@ -373,7 +389,8 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {      if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))          return; -    // TODO(Subv): Actually generate the beacon and send it. +    // TODO(Subv): Actually send the beacon. +    std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info);      // Start broadcasting the network, send a beacon frame every 102.4ms.      CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late, diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index 65349f9fd..29b146569 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -6,6 +6,7 @@  #include <array>  #include <cstddef> +#include <vector>  #include "common/common_types.h"  #include "common/swap.h"  #include "core/hle/service/service.h" @@ -33,6 +34,8 @@ struct NodeInfo {  static_assert(sizeof(NodeInfo) == 40, "NodeInfo has incorrect size."); +using NodeList = std::vector<NodeInfo>; +  enum class NetworkStatus {      NotConnected = 3,      ConnectedAsHost = 6, @@ -75,6 +78,8 @@ struct NetworkInfo {      std::array<u8, ApplicationDataSize> application_data;  }; +static_assert(offsetof(NetworkInfo, oui_value) == 0xC, "oui_value is at the wrong offset."); +static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset.");  static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size.");  class NWM_UDS final : public Interface { diff --git a/src/core/hle/service/nwm/uds_beacon.cpp b/src/core/hle/service/nwm/uds_beacon.cpp new file mode 100644 index 000000000..c6e5bc5f1 --- /dev/null +++ b/src/core/hle/service/nwm/uds_beacon.cpp @@ -0,0 +1,333 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> + +#include "core/hle/service/nwm/nwm_uds.h" +#include "core/hle/service/nwm/uds_beacon.h" + +#include <cryptopp/aes.h> +#include <cryptopp/md5.h> +#include <cryptopp/modes.h> +#include <cryptopp/sha.h> + +namespace Service { +namespace NWM { + +// 802.11 broadcast MAC address +constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds. + +// Note: These values were taken from a packet capture of an o3DS XL +// broadcasting a Super Smash Bros. 4 lobby. +constexpr u16 DefaultExtraCapabilities = 0x0431; + +// Size of the SSID broadcast by an UDS beacon frame. +constexpr u8 UDSBeaconSSIDSize = 8; + +// The maximum size of the data stored in the EncryptedData0 tag (24). +constexpr u32 EncryptedDataSizeCutoff = 0xFA; + +/** + * NWM Beacon data encryption key, taken from the NWM module code. + * We stub this with an all-zeros key as that is enough for Citra's purpose. + * The real key can be used here to generate beacons that will be accepted by + * a real 3ds. + */ +constexpr std::array<u8, CryptoPP::AES::BLOCKSIZE> nwm_beacon_key = {}; + +/** + * Generates a buffer with the fixed parameters of an 802.11 Beacon frame + * using dummy values. + * @returns A buffer with the fixed parameters of the beacon frame. + */ +std::vector<u8> GenerateFixedParameters() { +    std::vector<u8> buffer(sizeof(BeaconFrameHeader)); + +    BeaconFrameHeader header{}; +    // Use a fixed default time for now. +    // TODO(Subv): Perhaps use the difference between now and the time the network was started? +    header.timestamp = DefaultNetworkUptime; +    header.beacon_interval = DefaultBeaconInterval; +    header.capabilities = DefaultExtraCapabilities; + +    std::memcpy(buffer.data(), &header, sizeof(header)); + +    return buffer; +} + +/** + * Generates an SSID tag of an 802.11 Beacon frame with an 8-byte all-zero SSID value. + * @returns A buffer with the SSID tag. + */ +std::vector<u8> GenerateSSIDTag() { +    std::vector<u8> buffer(sizeof(TagHeader) + UDSBeaconSSIDSize); + +    TagHeader tag_header{}; +    tag_header.tag_id = static_cast<u8>(TagId::SSID); +    tag_header.length = UDSBeaconSSIDSize; + +    std::memcpy(buffer.data(), &tag_header, sizeof(TagHeader)); + +    // The rest of the buffer is already filled with zeros. + +    return buffer; +} + +/** + * Generates a buffer with the basic tagged parameters of an 802.11 Beacon frame + * such as SSID, Rate Information, Country Information, etc. + * @returns A buffer with the tagged parameters of the beacon frame. + */ +std::vector<u8> GenerateBasicTaggedParameters() { +    // Append the SSID tag +    std::vector<u8> buffer = GenerateSSIDTag(); + +    // TODO(Subv): Add the SupportedRates tag. +    // TODO(Subv): Add the DSParameterSet tag. +    // TODO(Subv): Add the TrafficIndicationMap tag. +    // TODO(Subv): Add the CountryInformation tag. +    // TODO(Subv): Add the ERPInformation tag. + +    return buffer; +} + +/** + * Generates a buffer with the Dummy Nintendo tag. + * It is currently unknown what this tag does. + * TODO(Subv): Figure out if this is needed and what it does. + * @returns A buffer with the Nintendo tagged parameters of the beacon frame. + */ +std::vector<u8> GenerateNintendoDummyTag() { +    // Note: These values were taken from a packet capture of an o3DS XL +    // broadcasting a Super Smash Bros. 4 lobby. +    constexpr std::array<u8, 3> dummy_data = {0x0A, 0x00, 0x00}; + +    DummyTag tag{}; +    tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); +    tag.header.length = sizeof(DummyTag) - sizeof(TagHeader); +    tag.oui_type = static_cast<u8>(NintendoTagId::Dummy); +    tag.oui = NintendoOUI; +    tag.data = dummy_data; + +    std::vector<u8> buffer(sizeof(DummyTag)); +    std::memcpy(buffer.data(), &tag, sizeof(DummyTag)); + +    return buffer; +} + +/** + * Generates a buffer with the Network Info Nintendo tag. + * This tag contains the network information of the network that is being broadcast. + * It also contains the application data provided by the application that opened the network. + * @returns A buffer with the Nintendo network info parameter of the beacon frame. + */ +std::vector<u8> GenerateNintendoNetworkInfoTag(const NetworkInfo& network_info) { +    NetworkInfoTag tag{}; +    tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); +    tag.header.length = +        sizeof(NetworkInfoTag) - sizeof(TagHeader) + network_info.application_data_size; +    tag.appdata_size = network_info.application_data_size; +    // Set the hash to zero initially, it will be updated once we calculate it. +    tag.sha_hash = {}; + +    // Ensure the network structure has the correct OUI and OUI type. +    ASSERT(network_info.oui_type == static_cast<u8>(NintendoTagId::NetworkInfo)); +    ASSERT(network_info.oui_value == NintendoOUI); + +    // Ensure the application data size is less than the maximum value. +    ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, "Data size is too big."); + +    // This tag contains the network info structure starting at the OUI. +    std::memcpy(tag.network_info.data(), &network_info.oui_value, tag.network_info.size()); + +    // Copy the tag and the data so we can calculate the SHA1 over it. +    std::vector<u8> buffer(sizeof(tag) + network_info.application_data_size); +    std::memcpy(buffer.data(), &tag, sizeof(tag)); +    std::memcpy(buffer.data() + sizeof(tag), network_info.application_data.data(), +                network_info.application_data_size); + +    // Calculate the SHA1 of the contents of the tag. +    std::array<u8, CryptoPP::SHA1::DIGESTSIZE> hash; +    CryptoPP::SHA1().CalculateDigest(hash.data(), +                                     buffer.data() + offsetof(NetworkInfoTag, network_info), +                                     buffer.size() - sizeof(TagHeader)); + +    // Copy it directly into the buffer, overwriting the zeros that we had previously placed there. +    std::memcpy(buffer.data() + offsetof(NetworkInfoTag, sha_hash), hash.data(), hash.size()); + +    return buffer; +} + +/* + * Calculates the CTR used for the AES-CTR encryption of the data stored in the + * EncryptedDataTags. + * @returns The CTR used for beacon crypto. + */ +std::array<u8, CryptoPP::AES::BLOCKSIZE> GetBeaconCryptoCTR(const NetworkInfo& network_info) { +    BeaconDataCryptoCTR data{}; + +    data.host_mac = network_info.host_mac_address; +    data.wlan_comm_id = network_info.wlan_comm_id; +    data.id = network_info.id; +    data.network_id = network_info.network_id; + +    std::array<u8, CryptoPP::AES::BLOCKSIZE> hash; +    std::memcpy(hash.data(), &data, sizeof(data)); + +    return hash; +} + +/* + * Serializes the node information into the format needed for network transfer, + * and then encrypts it with the NWM key. + * @returns The serialized and encrypted node information. + */ +std::vector<u8> GeneratedEncryptedData(const NetworkInfo& network_info, const NodeList& nodes) { +    std::vector<u8> buffer(sizeof(BeaconData)); + +    BeaconData data{}; +    std::memcpy(buffer.data(), &data, sizeof(BeaconData)); + +    for (const NodeInfo& node : nodes) { +        // Serialize each node and convert the data from +        // host byte-order to Big Endian. +        BeaconNodeInfo info{}; +        info.friend_code_seed = node.friend_code_seed; +        info.network_node_id = node.network_node_id; +        for (int i = 0; i < info.username.size(); ++i) +            info.username[i] = node.username[i]; + +        buffer.insert(buffer.end(), reinterpret_cast<u8*>(&info), +                      reinterpret_cast<u8*>(&info) + sizeof(info)); +    } + +    // Calculate the MD5 hash of the data in the buffer, not including the hash field. +    std::array<u8, CryptoPP::MD5::DIGESTSIZE> hash; +    CryptoPP::MD5().CalculateDigest(hash.data(), buffer.data() + offsetof(BeaconData, bitmask), +                                    buffer.size() - sizeof(data.md5_hash)); + +    // Copy the hash into the buffer. +    std::memcpy(buffer.data(), hash.data(), hash.size()); + +    // Encrypt the data using AES-CTR and the NWM beacon key. +    using CryptoPP::AES; +    std::array<u8, AES::BLOCKSIZE> counter = GetBeaconCryptoCTR(network_info); +    CryptoPP::CTR_Mode<AES>::Encryption aes; +    aes.SetKeyWithIV(nwm_beacon_key.data(), AES::BLOCKSIZE, counter.data()); +    aes.ProcessData(buffer.data(), buffer.data(), buffer.size()); + +    return buffer; +} + +void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer) { +    // Decrypt the data using AES-CTR and the NWM beacon key. +    using CryptoPP::AES; +    std::array<u8, AES::BLOCKSIZE> counter = GetBeaconCryptoCTR(network_info); +    CryptoPP::CTR_Mode<AES>::Decryption aes; +    aes.SetKeyWithIV(nwm_beacon_key.data(), AES::BLOCKSIZE, counter.data()); +    aes.ProcessData(buffer.data(), buffer.data(), buffer.size()); +} + +/** + * Generates a buffer with the Network Info Nintendo tag. + * This tag contains the first portion of the encrypted payload in the 802.11 beacon frame. + * The encrypted payload contains information about the nodes currently connected to the network. + * @returns A buffer with the first Nintendo encrypted data parameters of the beacon frame. + */ +std::vector<u8> GenerateNintendoFirstEncryptedDataTag(const NetworkInfo& network_info, +                                                      const NodeList& nodes) { +    const size_t payload_size = +        std::min<size_t>(EncryptedDataSizeCutoff, nodes.size() * sizeof(NodeInfo)); + +    EncryptedDataTag tag{}; +    tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); +    tag.header.length = sizeof(tag) - sizeof(TagHeader) + payload_size; +    tag.oui_type = static_cast<u8>(NintendoTagId::EncryptedData0); +    tag.oui = NintendoOUI; + +    std::vector<u8> buffer(sizeof(tag) + payload_size); +    std::memcpy(buffer.data(), &tag, sizeof(tag)); + +    std::vector<u8> encrypted_data = GeneratedEncryptedData(network_info, nodes); +    std::memcpy(buffer.data() + sizeof(tag), encrypted_data.data(), payload_size); + +    return buffer; +} + +/** + * Generates a buffer with the Network Info Nintendo tag. + * This tag contains the second portion of the encrypted payload in the 802.11 beacon frame. + * The encrypted payload contains information about the nodes currently connected to the network. + * This tag is only present if the payload size is greater than EncryptedDataSizeCutoff (0xFA) + * bytes. + * @returns A buffer with the second Nintendo encrypted data parameters of the beacon frame. + */ +std::vector<u8> GenerateNintendoSecondEncryptedDataTag(const NetworkInfo& network_info, +                                                       const NodeList& nodes) { +    // This tag is only present if the payload is larger than EncryptedDataSizeCutoff (0xFA). +    if (nodes.size() * sizeof(NodeInfo) <= EncryptedDataSizeCutoff) +        return {}; + +    const size_t payload_size = nodes.size() * sizeof(NodeInfo) - EncryptedDataSizeCutoff; + +    const size_t tag_length = sizeof(EncryptedDataTag) - sizeof(TagHeader) + payload_size; + +    // TODO(Subv): What does the 3DS do when a game has too much data to fit into the tag? +    ASSERT_MSG(tag_length <= 255, "Data is too big."); + +    EncryptedDataTag tag{}; +    tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); +    tag.header.length = tag_length; +    tag.oui_type = static_cast<u8>(NintendoTagId::EncryptedData1); +    tag.oui = NintendoOUI; + +    std::vector<u8> buffer(sizeof(tag) + payload_size); +    std::memcpy(buffer.data(), &tag, sizeof(tag)); + +    std::vector<u8> encrypted_data = GeneratedEncryptedData(network_info, nodes); +    std::memcpy(buffer.data() + sizeof(tag), encrypted_data.data() + EncryptedDataSizeCutoff, +                payload_size); + +    return buffer; +} + +/** + * Generates a buffer with the Nintendo tagged parameters of an 802.11 Beacon frame + * for UDS communication. + * @returns A buffer with the Nintendo tagged parameters of the beacon frame. + */ +std::vector<u8> GenerateNintendoTaggedParameters(const NetworkInfo& network_info, +                                                 const NodeList& nodes) { +    ASSERT_MSG(network_info.max_nodes == nodes.size(), "Inconsistent network state."); + +    std::vector<u8> buffer = GenerateNintendoDummyTag(); +    std::vector<u8> network_info_tag = GenerateNintendoNetworkInfoTag(network_info); +    std::vector<u8> first_data_tag = GenerateNintendoFirstEncryptedDataTag(network_info, nodes); +    std::vector<u8> second_data_tag = GenerateNintendoSecondEncryptedDataTag(network_info, nodes); + +    buffer.insert(buffer.end(), network_info_tag.begin(), network_info_tag.end()); +    buffer.insert(buffer.end(), first_data_tag.begin(), first_data_tag.end()); +    buffer.insert(buffer.end(), second_data_tag.begin(), second_data_tag.end()); + +    return buffer; +} + +std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes) { +    std::vector<u8> buffer = GenerateFixedParameters(); +    std::vector<u8> basic_tags = GenerateBasicTaggedParameters(); +    std::vector<u8> nintendo_tags = GenerateNintendoTaggedParameters(network_info, nodes); + +    buffer.insert(buffer.end(), basic_tags.begin(), basic_tags.end()); +    buffer.insert(buffer.end(), nintendo_tags.begin(), nintendo_tags.end()); + +    return buffer; +} + +std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender) { +    return {}; +} +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/uds_beacon.h b/src/core/hle/service/nwm/uds_beacon.h new file mode 100644 index 000000000..6df4c4f47 --- /dev/null +++ b/src/core/hle/service/nwm/uds_beacon.h @@ -0,0 +1,173 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <deque> +#include <vector> +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +using MacAddress = std::array<u8, 6>; + +/// The maximum number of nodes that can exist in an UDS session. +constexpr u32 UDSMaxNodes = 16; +constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32}; + +/// Additional block tag ids in the Beacon frames +enum class TagId : u8 { +    SSID = 0, +    SupportedRates = 1, +    DSParameterSet = 2, +    TrafficIndicationMap = 5, +    CountryInformation = 7, +    ERPInformation = 42, +    VendorSpecific = 221 +}; + +/** + * Internal vendor-specific tag ids as stored inside + * VendorSpecific blocks in the Beacon frames. + */ +enum class NintendoTagId : u8 { +    Dummy = 20, +    NetworkInfo = 21, +    EncryptedData0 = 24, +    EncryptedData1 = 25, +}; + +struct BeaconEntryHeader { +    u32_le total_size; +    INSERT_PADDING_BYTES(1); +    u8 wifi_channel; +    INSERT_PADDING_BYTES(2); +    MacAddress mac_address; +    INSERT_PADDING_BYTES(6); +    u32_le unk_size; +    u32_le header_size; +}; + +static_assert(sizeof(BeaconEntryHeader) == 0x1C, "BeaconEntryHeader has incorrect size."); + +struct BeaconDataReplyHeader { +    u32_le max_output_size; +    u32_le total_size; +    u32_le total_entries; +}; + +static_assert(sizeof(BeaconDataReplyHeader) == 12, "BeaconDataReplyHeader has incorrect size."); + +#pragma pack(push, 1) +struct BeaconFrameHeader { +    // Number of microseconds the AP has been active. +    u64_le timestamp; +    // Interval between beacon transmissions, expressed in TU. +    u16_le beacon_interval; +    // Indicates the presence of optional capabilities. +    u16_le capabilities; +}; +#pragma pack(pop) + +static_assert(sizeof(BeaconFrameHeader) == 12, "BeaconFrameHeader has incorrect size."); + +struct TagHeader { +    u8 tag_id; +    u8 length; +}; + +static_assert(sizeof(TagHeader) == 2, "TagHeader has incorrect size."); + +struct DummyTag { +    TagHeader header; +    std::array<u8, 3> oui; +    u8 oui_type; +    std::array<u8, 3> data; +}; + +static_assert(sizeof(DummyTag) == 9, "DummyTag has incorrect size."); + +struct NetworkInfoTag { +    TagHeader header; +    std::array<u8, 0x1F> network_info; +    std::array<u8, 0x14> sha_hash; +    u8 appdata_size; +}; + +static_assert(sizeof(NetworkInfoTag) == 54, "NetworkInfoTag has incorrect size."); + +struct EncryptedDataTag { +    TagHeader header; +    std::array<u8, 3> oui; +    u8 oui_type; +}; + +static_assert(sizeof(EncryptedDataTag) == 6, "EncryptedDataTag has incorrect size."); + +#pragma pack(push, 1) +// The raw bytes of this structure are the CTR used in the encryption (AES-CTR) +// of the beacon data stored in the EncryptedDataTags. +struct BeaconDataCryptoCTR { +    MacAddress host_mac; +    u32_le wlan_comm_id; +    u8 id; +    INSERT_PADDING_BYTES(1); +    u32_le network_id; +}; + +static_assert(sizeof(BeaconDataCryptoCTR) == 0x10, "BeaconDataCryptoCTR has incorrect size."); + +struct BeaconNodeInfo { +    u64_be friend_code_seed; +    std::array<u16_be, 10> username; +    u16_be network_node_id; +}; + +static_assert(sizeof(BeaconNodeInfo) == 0x1E, "BeaconNodeInfo has incorrect size."); + +struct BeaconData { +    std::array<u8, 0x10> md5_hash; +    u16_be bitmask; +}; +#pragma pack(pop) + +static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size."); + +/// Information about a received WiFi packet. +/// Acts as our own 802.11 header. +struct WifiPacket { +    enum class PacketType { Beacon, Data }; + +    PacketType type; ///< The type of 802.11 frame, Beacon / Data. + +    /// Raw 802.11 frame data, starting at the management frame header for management frames. +    std::vector<u8> data; +    MacAddress transmitter_address; ///< Mac address of the transmitter. +    MacAddress destination_address; ///< Mac address of the receiver. +    u8 channel;                     ///< WiFi channel where this frame was transmitted. +}; + +/** + * Decrypts the beacon data buffer for the network described by `network_info`. + */ +void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer); + +/** + * Generates an 802.11 beacon frame starting at the management frame header. + * This frame contains information about the network and its connected clients. + * @returns The generated frame. + */ +std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes); + +/** + * Returns a list of received 802.11 frames from the specified sender + * matching the type since the last call. + */ +std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender); +} // namespace NWM +} // namespace Service  | 
