ldn: Add better stubs and more data types

Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com>
Co-Authored-By: Morph <39850852+Morph1984@users.noreply.github.com>
This commit is contained in:
FearlessTobi 2022-08-07 23:54:51 +02:00
parent 9dc8d02acc
commit 12dc05032b
6 changed files with 774 additions and 73 deletions

View file

@ -504,9 +504,10 @@ add_library(core STATIC
hle/service/jit/jit.h
hle/service/lbl/lbl.cpp
hle/service/lbl/lbl.h
hle/service/ldn/errors.h
hle/service/ldn/ldn_results.h
hle/service/ldn/ldn.cpp
hle/service/ldn/ldn.h
hle/service/ldn/ldn_types.h
hle/service/ldr/ldr.cpp
hle/service/ldr/ldr.h
hle/service/lm/lm.cpp

View file

@ -1,12 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::LDN {
constexpr Result ERROR_DISABLED{ErrorModule::LDN, 22};
} // namespace Service::LDN

View file

@ -3,11 +3,12 @@
#include <memory>
#include "core/hle/ipc_helpers.h"
#include "core/hle/result.h"
#include "core/hle/service/ldn/errors.h"
#include "core/core.h"
#include "core/hle/service/ldn/ldn.h"
#include "core/hle/service/sm/sm.h"
#include "core/internal_network/network.h"
#include "core/internal_network/network_interface.h"
#undef CreateEvent
namespace Service::LDN {
@ -96,81 +97,393 @@ public:
}
};
class IUserLocalCommunicationService final
: public ServiceFramework<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_)
: ServiceFramework{system_, "IUserLocalCommunicationService"} {
IUserLocalCommunicationService::IUserLocalCommunicationService(Core::System& system_)
: ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew},
service_context{system, "IUserLocalCommunicationService"}, room_network{
system_.GetRoomNetwork()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IUserLocalCommunicationService::GetState, "GetState"},
{1, nullptr, "GetNetworkInfo"},
{1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
{2, nullptr, "GetIpv4Address"},
{3, nullptr, "GetDisconnectReason"},
{4, nullptr, "GetSecurityParameter"},
{5, nullptr, "GetNetworkConfig"},
{100, nullptr, "AttachStateChangeEvent"},
{101, nullptr, "GetNetworkInfoLatestUpdate"},
{102, nullptr, "Scan"},
{103, nullptr, "ScanPrivate"},
{3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
{4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
{5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
{100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
{101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
{102, &IUserLocalCommunicationService::Scan, "Scan"},
{103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
{104, nullptr, "SetWirelessControllerRestriction"},
{200, nullptr, "OpenAccessPoint"},
{201, nullptr, "CloseAccessPoint"},
{202, nullptr, "CreateNetwork"},
{203, nullptr, "CreateNetworkPrivate"},
{204, nullptr, "DestroyNetwork"},
{200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
{201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
{202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
{203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
{204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
{205, nullptr, "Reject"},
{206, nullptr, "SetAdvertiseData"},
{207, nullptr, "SetStationAcceptPolicy"},
{208, nullptr, "AddAcceptFilterEntry"},
{206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
{207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
{208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
{209, nullptr, "ClearAcceptFilter"},
{300, nullptr, "OpenStation"},
{301, nullptr, "CloseStation"},
{302, nullptr, "Connect"},
{300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
{301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
{302, &IUserLocalCommunicationService::Connect, "Connect"},
{303, nullptr, "ConnectPrivate"},
{304, nullptr, "Disconnect"},
{400, nullptr, "Initialize"},
{401, nullptr, "Finalize"},
{402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+
{304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
{400, &IUserLocalCommunicationService::Initialize, "Initialize"},
{401, &IUserLocalCommunicationService::Finalize, "Finalize"},
{402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
};
// clang-format on
RegisterHandlers(functions);
state_change_event =
service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
}
void GetState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IUserLocalCommunicationService::~IUserLocalCommunicationService() {
service_context.CloseEvent(state_change_event);
}
void IUserLocalCommunicationService::OnEventFired() {
state_change_event->GetWritableEvent().Signal();
}
void IUserLocalCommunicationService::GetState(Kernel::HLERequestContext& ctx) {
State state = State::Error;
LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
// Indicate a network error, as we do not actually emulate LDN
rb.Push(static_cast<u32>(State::Error));
void IUserLocalCommunicationService::GetNetworkInfo(Kernel::HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferSize();
if (write_buffer_size != sizeof(NetworkInfo)) {
LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
NetworkInfo networkInfo{};
const auto rc = ResultSuccess;
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
networkInfo.common.ssid.GetStringValue(), networkInfo.ldn.node_count);
ctx.WriteBuffer<NetworkInfo>(networkInfo);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
}
void IUserLocalCommunicationService::GetDisconnectReason(Kernel::HLERequestContext& ctx) {
const auto disconnect_reason = DisconnectReason::None;
LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(disconnect_reason);
}
void IUserLocalCommunicationService::GetSecurityParameter(Kernel::HLERequestContext& ctx) {
SecurityParameter security_parameter;
NetworkInfo info;
const Result rc = ResultSuccess;
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
security_parameter.session_id = info.network_id.session_id;
std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
sizeof(SecurityParameter::data));
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(rc);
rb.PushRaw<SecurityParameter>(security_parameter);
}
void IUserLocalCommunicationService::GetNetworkConfig(Kernel::HLERequestContext& ctx) {
NetworkConfig config;
NetworkInfo info;
const Result rc = ResultSuccess;
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
config.intent_id = info.network_id.intent_id;
config.channel = info.common.channel;
config.node_count_max = info.ldn.node_count_max;
config.local_communication_version = info.ldn.nodes[0].local_communication_version;
LOG_WARNING(Service_LDN,
"(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, "
"local_communication_version={}",
config.intent_id.local_communication_id, config.intent_id.scene_id, config.channel,
config.node_count_max, config.local_communication_version);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(rc);
rb.PushRaw<NetworkConfig>(config);
}
void IUserLocalCommunicationService::AttachStateChangeEvent(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(state_change_event->GetReadableEvent());
}
void IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) {
const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate);
if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size,
node_buffer_count);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
NetworkInfo info;
std::vector<NodeLatestUpdate> latest_update{};
latest_update.resize(node_buffer_count);
const auto rc = ResultSuccess;
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
info.common.ssid.GetStringValue(), info.ldn.node_count);
ctx.WriteBuffer(info, 0);
ctx.WriteBuffer(latest_update, 1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Initialize2(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDN, "called");
is_initialized = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_DISABLED);
void IUserLocalCommunicationService::Scan(Kernel::HLERequestContext& ctx) {
ScanImpl(ctx);
}
private:
enum class State {
None,
Initialized,
AccessPointOpened,
AccessPointCreated,
StationOpened,
StationConnected,
Error,
};
void IUserLocalCommunicationService::ScanPrivate(Kernel::HLERequestContext& ctx) {
ScanImpl(ctx, true);
}
bool is_initialized{};
};
void IUserLocalCommunicationService::ScanImpl(Kernel::HLERequestContext& ctx, bool is_private) {
IPC::RequestParser rp{ctx};
const auto channel{rp.PopEnum<WifiChannel>()};
const auto scan_filter{rp.PopRaw<ScanFilter>()};
const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo);
if (network_info_size == 0) {
LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
u16 count = 0;
std::vector<NetworkInfo> networks_info{};
networks_info.resize(network_info_size);
LOG_WARNING(Service_LDN,
"(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}",
channel, scan_filter.flag, scan_filter.network_type);
ctx.WriteBuffer(networks_info);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(count);
}
void IUserLocalCommunicationService::OpenAccessPoint(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::CloseAccessPoint(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::CreateNetwork(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
CreateNetworkImpl(ctx, false);
}
void IUserLocalCommunicationService::CreateNetworkPrivate(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
CreateNetworkImpl(ctx, true);
}
void IUserLocalCommunicationService::CreateNetworkImpl(Kernel::HLERequestContext& ctx,
bool is_private) {
IPC::RequestParser rp{ctx};
const auto security_config{rp.PopRaw<SecurityConfig>()};
[[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw<SecurityParameter>()
: SecurityParameter{}};
const auto user_config{rp.PopRaw<UserConfig>()};
rp.Pop<u32>(); // Padding
const auto network_Config{rp.PopRaw<NetworkConfig>()};
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::DestroyNetwork(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::SetAdvertiseData(Kernel::HLERequestContext& ctx) {
std::vector<u8> read_buffer = ctx.ReadBuffer();
LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::OpenStation(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::CloseStation(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::Connect(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::RequestParser rp{ctx};
[[maybe_unused]] const auto securityConfig{rp.PopRaw<SecurityConfig>()};
const auto user_config{rp.PopRaw<UserConfig>()};
const auto local_communication_version{rp.Pop<u32>()};
[[maybe_unused]] const auto option{rp.Pop<u32>()};
std::vector<u8> read_buffer = ctx.ReadBuffer();
NetworkInfo networkInfo{};
if (read_buffer.size() != sizeof(NetworkInfo)) {
LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
std::memcpy(&networkInfo, read_buffer.data(), read_buffer.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::Disconnect(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
const auto rc = InitializeImpl(ctx);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
}
void IUserLocalCommunicationService::Finalize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
is_initialized = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IUserLocalCommunicationService::Initialize2(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
const auto rc = InitializeImpl(ctx);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
}
Result IUserLocalCommunicationService::InitializeImpl(Kernel::HLERequestContext& ctx) {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface) {
return ResultAirplaneModeEnabled;
}
is_initialized = true;
// TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented
return ResultAirplaneModeEnabled;
}
class LDNS final : public ServiceFramework<LDNS> {
public:
@ -273,7 +586,7 @@ public:
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_DISABLED);
rb.Push(ResultDisabled);
}
};

View file

@ -3,6 +3,14 @@
#pragma once
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/ldn/ldn_results.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/sm/sm.h"
namespace Core {
class System;
}
@ -16,4 +24,69 @@ namespace Service::LDN {
/// Registers all LDN services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
class IUserLocalCommunicationService final
: public ServiceFramework<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_);
~IUserLocalCommunicationService() override;
void GetState(Kernel::HLERequestContext& ctx);
void GetNetworkInfo(Kernel::HLERequestContext& ctx);
void GetDisconnectReason(Kernel::HLERequestContext& ctx);
void GetSecurityParameter(Kernel::HLERequestContext& ctx);
void GetNetworkConfig(Kernel::HLERequestContext& ctx);
void AttachStateChangeEvent(Kernel::HLERequestContext& ctx);
void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx);
void Scan(Kernel::HLERequestContext& ctx);
void ScanPrivate(Kernel::HLERequestContext& ctx);
void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false);
void OpenAccessPoint(Kernel::HLERequestContext& ctx);
void CloseAccessPoint(Kernel::HLERequestContext& ctx);
void CreateNetwork(Kernel::HLERequestContext& ctx);
void CreateNetworkPrivate(Kernel::HLERequestContext& ctx);
void CreateNetworkImpl(Kernel::HLERequestContext& ctx, bool is_private);
void DestroyNetwork(Kernel::HLERequestContext& ctx);
void SetAdvertiseData(Kernel::HLERequestContext& ctx);
void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx);
void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx);
void OpenStation(Kernel::HLERequestContext& ctx);
void CloseStation(Kernel::HLERequestContext& ctx);
void Disconnect(Kernel::HLERequestContext& ctx);
void Connect(Kernel::HLERequestContext& ctx);
void Initialize(Kernel::HLERequestContext& ctx);
void Finalize(Kernel::HLERequestContext& ctx);
void Initialize2(Kernel::HLERequestContext& ctx);
Result InitializeImpl(Kernel::HLERequestContext& ctx);
private:
void OnEventFired();
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* state_change_event;
Network::RoomNetwork& room_network;
bool is_initialized{};
};
} // namespace Service::LDN

View file

@ -0,0 +1,28 @@
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::LDN {
constexpr Result ResultAdvertiseDataTooLarge{ErrorModule::LDN, 10};
constexpr Result ResultAuthenticationFailed{ErrorModule::LDN, 20};
constexpr Result ResultDisabled{ErrorModule::LDN, 22};
constexpr Result ResultAirplaneModeEnabled{ErrorModule::LDN, 23};
constexpr Result ResultInvalidNodeCount{ErrorModule::LDN, 30};
constexpr Result ResultConnectionFailed{ErrorModule::LDN, 31};
constexpr Result ResultBadState{ErrorModule::LDN, 32};
constexpr Result ResultNoIpAddress{ErrorModule::LDN, 33};
constexpr Result ResultInvalidBufferCount{ErrorModule::LDN, 50};
constexpr Result ResultAccessPointConnectionFailed{ErrorModule::LDN, 65};
constexpr Result ResultAuthenticationTimeout{ErrorModule::LDN, 66};
constexpr Result ResultMaximumNodeCount{ErrorModule::LDN, 67};
constexpr Result ResultBadInput{ErrorModule::LDN, 96};
constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97};
constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113};
constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114};
} // namespace Service::LDN

View file

@ -0,0 +1,298 @@
// Copyright 2022 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <fmt/format.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "network/network.h"
namespace Service::LDN {
constexpr size_t SsidLengthMax = 32;
constexpr size_t AdvertiseDataSizeMax = 384;
constexpr size_t UserNameBytesMax = 32;
constexpr int NodeCountMax = 8;
constexpr int StationCountMax = NodeCountMax - 1;
constexpr size_t PassphraseLengthMax = 64;
enum class SecurityMode : u16 {
All,
Retail,
Debug,
};
enum class NodeStateChange : u8 {
None,
Connect,
Disconnect,
DisconnectAndConnect,
};
inline NodeStateChange operator|(NodeStateChange a, NodeStateChange b) {
return static_cast<NodeStateChange>(static_cast<u8>(a) | static_cast<u8>(b));
}
inline NodeStateChange operator|=(NodeStateChange& a, NodeStateChange b) {
return a = a | b;
}
enum class ScanFilterFlag : u32 {
None = 0,
LocalCommunicationId = 1 << 0,
SessionId = 1 << 1,
NetworkType = 1 << 2,
Ssid = 1 << 4,
SceneId = 1 << 5,
IntentId = LocalCommunicationId | SceneId,
NetworkId = IntentId | SessionId,
};
enum class NetworkType : u32 {
None,
General,
Ldn,
All,
};
enum class PackedNetworkType : u8 {
None,
General,
Ldn,
All,
};
enum class State : u32 {
None,
Initialized,
AccessPointOpened,
AccessPointCreated,
StationOpened,
StationConnected,
Error,
};
enum class DisconnectReason : s16 {
Unknown = -1,
None,
DisconnectedByUser,
DisconnectedBySystem,
DestroyedByUser,
DestroyedBySystem,
Rejected,
SignalLost,
};
enum class NetworkError {
Unknown = -1,
None = 0,
PortUnreachable,
TooManyPlayers,
VersionTooLow,
VersionTooHigh,
ConnectFailure,
ConnectNotFound,
ConnectTimeout,
ConnectRejected,
RejectFailed,
};
enum class AcceptPolicy : u8 {
AcceptAll,
RejectAll,
BlackList,
WhiteList,
};
enum class WifiChannel : s16 {
Default = 0,
wifi24_1 = 1,
wifi24_6 = 6,
wifi24_11 = 11,
wifi50_36 = 36,
wifi50_40 = 40,
wifi50_44 = 44,
wifi50_48 = 48,
};
enum class LinkLevel : s8 {
Bad,
Low,
Good,
Excelent,
};
struct NodeLatestUpdate {
NodeStateChange state_change;
INSERT_PADDING_BYTES(0x7); // Unknown
};
static_assert(sizeof(NodeLatestUpdate) == 0x8, "NodeLatestUpdate is an invalid size");
struct SessionId {
u64 high;
u64 low;
public:
bool operator==(const SessionId& b) const {
return (low == b.low) && (high == b.high);
}
};
static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
struct IntentId {
u64 local_communication_id;
INSERT_PADDING_BYTES(0x2); // Reserved
u16 scene_id;
INSERT_PADDING_BYTES(0x4); // Reserved
};
static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
struct NetworkId {
IntentId intent_id;
SessionId session_id;
};
static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
struct Ssid {
u8 length;
std::array<char, SsidLengthMax + 1> raw;
public:
std::string GetStringValue() const {
return std::string(raw.data(), length);
}
};
static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size");
struct Ipv4Address {
union {
u32 raw{};
std::array<u8, 4> bytes;
};
public:
std::string GetStringValue() const {
return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]);
}
};
static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
struct MacAddress {
std::array<u8, 6> raw{};
friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
};
static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size");
struct ScanFilter {
NetworkId network_id;
NetworkType network_type;
MacAddress mac_address;
Ssid ssid;
INSERT_PADDING_BYTES(0x10);
ScanFilterFlag flag;
};
static_assert(sizeof(ScanFilter) == 0x60, "ScanFilter is an invalid size");
struct CommonNetworkInfo {
MacAddress bssid;
Ssid ssid;
WifiChannel channel;
LinkLevel link_level;
PackedNetworkType network_type;
INSERT_PADDING_BYTES(0x4);
};
static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
struct NodeInfo {
Ipv4Address ipv4_address;
MacAddress mac_address;
s8 node_id;
u8 is_connected;
std::array<u8, UserNameBytesMax + 1> user_name;
INSERT_PADDING_BYTES(0x1); // Reserved
s16 local_communication_version;
INSERT_PADDING_BYTES(0x10); // Reserved
};
static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
struct LdnNetworkInfo {
std::array<u8, 0x10> security_parameter;
SecurityMode security_mode;
AcceptPolicy station_accept_policy;
u8 has_action_frame;
INSERT_PADDING_BYTES(0x2); // Padding
u8 node_count_max;
u8 node_count;
std::array<NodeInfo, NodeCountMax> nodes;
INSERT_PADDING_BYTES(0x2); // Reserved
u16 advertise_data_size;
std::array<u8, AdvertiseDataSizeMax> advertise_data;
INSERT_PADDING_BYTES(0x8C); // Reserved
u64 random_authentication_id;
};
static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
struct NetworkInfo {
NetworkId network_id;
CommonNetworkInfo common;
LdnNetworkInfo ldn;
};
static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
struct SecurityConfig {
SecurityMode security_mode;
u16 passphrase_size;
std::array<u8, PassphraseLengthMax> passphrase;
};
static_assert(sizeof(SecurityConfig) == 0x44, "SecurityConfig is an invalid size");
struct UserConfig {
std::array<u8, UserNameBytesMax + 1> user_name;
INSERT_PADDING_BYTES(0xF); // Reserved
};
static_assert(sizeof(UserConfig) == 0x30, "UserConfig is an invalid size");
#pragma pack(push, 4)
struct ConnectRequest {
SecurityConfig security_config;
UserConfig user_config;
u32 local_communication_version;
u32 option_unknown;
NetworkInfo network_info;
};
static_assert(sizeof(ConnectRequest) == 0x4FC, "ConnectRequest is an invalid size");
#pragma pack(pop)
struct SecurityParameter {
std::array<u8, 0x10> data; // Data, used with the same key derivation as SecurityConfig
SessionId session_id;
};
static_assert(sizeof(SecurityParameter) == 0x20, "SecurityParameter is an invalid size");
struct NetworkConfig {
IntentId intent_id;
WifiChannel channel;
u8 node_count_max;
INSERT_PADDING_BYTES(0x1); // Reserved
u16 local_communication_version;
INSERT_PADDING_BYTES(0xA); // Reserved
};
static_assert(sizeof(NetworkConfig) == 0x20, "NetworkConfig is an invalid size");
struct AddressEntry {
Ipv4Address ipv4_address;
MacAddress mac_address;
INSERT_PADDING_BYTES(0x2); // Reserved
};
static_assert(sizeof(AddressEntry) == 0xC, "AddressEntry is an invalid size");
struct AddressList {
std::array<AddressEntry, 0x8> addresses;
};
static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
} // namespace Service::LDN