// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nwm/uds_beacon.h" #include "core/hle/service/service.h" namespace Service::NWM { enum class SAP : u8 { SNAPExtensionUsed = 0xAA }; enum class PDUControl : u8 { UnnumberedInformation = 3 }; enum class EtherType : u16 { SecureData = 0x876D, EAPoL = 0x888E }; /* * 802.2 header, UDS packets always use SNAP for these headers, * which means the dsap and ssap are always SNAPExtensionUsed (0xAA) * and the OUI is always 0. */ struct LLCHeader { SAP dsap = SAP::SNAPExtensionUsed; SAP ssap = SAP::SNAPExtensionUsed; PDUControl control = PDUControl::UnnumberedInformation; std::array OUI = {}; enum_be protocol; }; static_assert(sizeof(LLCHeader) == 8, "LLCHeader has the wrong size"); /* * Nintendo SecureData header, every UDS packet contains one, * it is used to store metadata about the transmission such as * the source and destination network node ids. */ struct SecureDataHeader { // TODO(Subv): It is likely that the first 4 bytes of this header are // actually part of another container protocol. u16_be protocol_size; INSERT_PADDING_BYTES(2); u16_be securedata_size; u8 is_management; u8 data_channel; u16_be sequence_number; u16_be dest_node_id; u16_be src_node_id; u32 GetActualDataSize() const { return protocol_size - sizeof(SecureDataHeader); } }; static_assert(sizeof(SecureDataHeader) == 14, "SecureDataHeader has the wrong size"); /* * The raw bytes of this structure are the CTR used in the encryption (AES-CTR) * process used to generate the CCMP key for data frame encryption. */ struct DataFrameCryptoCTR { u32_le wlan_comm_id; u32_le network_id; std::array host_mac; u16_le id; }; static_assert(sizeof(DataFrameCryptoCTR) == 16, "DataFrameCryptoCTR has the wrong size"); struct EAPoLNodeInfo { u64_be friend_code_seed; std::array username; INSERT_PADDING_BYTES(4); u16_be network_node_id; INSERT_PADDING_BYTES(6); }; static_assert(sizeof(EAPoLNodeInfo) == 0x28, "EAPoLNodeInfo has the wrong size"); constexpr u16 EAPoLStartMagic = 0x201; /* * Nintendo EAPoLStartPacket, is used to initaliaze a connection between client and host */ struct EAPoLStartPacket { u16_be magic = EAPoLStartMagic; u16_be association_id; // This value is hardcoded to 1 in the NWM module. u16_be unknown = 1; INSERT_PADDING_BYTES(2); EAPoLNodeInfo node; }; static_assert(sizeof(EAPoLStartPacket) == 0x30, "EAPoLStartPacket has the wrong size"); constexpr u16 EAPoLLogoffMagic = 0x202; struct EAPoLLogoffPacket { u16_be magic = EAPoLLogoffMagic; INSERT_PADDING_BYTES(2); u16_be assigned_node_id; MacAddress client_mac_address; INSERT_PADDING_BYTES(6); u8 connected_nodes; u8 max_nodes; INSERT_PADDING_BYTES(4); std::array nodes; }; static_assert(sizeof(EAPoLLogoffPacket) == 0x298, "EAPoLLogoffPacket has the wrong size"); /** * Generates an unencrypted 802.11 data payload. * @returns The generated frame payload. */ std::vector GenerateDataPayload(std::span data, u8 channel, u16 dest_node, u16 src_node, u16 sequence_number); /* * Returns the SecureDataHeader stored in an 802.11 data frame. */ SecureDataHeader ParseSecureDataHeader(std::span data); /* * Generates an unencrypted 802.11 data frame body with the EAPoL-Start format for UDS * communication. * @returns The generated frame body. */ std::vector GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node_info); /* * Returns the EtherType of the specified 802.11 frame. */ EtherType GetFrameEtherType(std::span frame); /* * Returns the EAPoL type (Start / Logoff) of the specified 802.11 frame. * Note: The frame *must* be an EAPoL frame. */ u16 GetEAPoLFrameType(std::span frame); /* * Returns a deserialized NodeInfo structure from the information inside an EAPoL-Start packet * encapsulated in an 802.11 data frame. */ NodeInfo DeserializeNodeInfoFromFrame(std::span frame); /* * Returns a NodeInfo constructed from the data in the specified EAPoLNodeInfo. */ NodeInfo DeserializeNodeInfo(const EAPoLNodeInfo& node); /* * Generates an unencrypted 802.11 data frame body with the EAPoL-Logoff format for UDS * communication. * @returns The generated frame body. */ std::vector GenerateEAPoLLogoffFrame(const MacAddress& mac_address, u16 network_node_id, const NodeList& nodes, u8 max_nodes, u8 total_nodes); /* * Returns a EAPoLLogoffPacket representing the specified 802.11-encapsulated data frame. */ EAPoLLogoffPacket ParseEAPoLLogoffFrame(std::span frame); } // namespace Service::NWM