From 2053ff96fccaf2d8e3472cb370141c6d3252c4e1 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Fri, 9 Feb 2024 23:06:22 -0600 Subject: [PATCH] service: ldn: Migrate and refractor service to new IPC --- src/core/CMakeLists.txt | 12 + src/core/hle/service/ldn/lan_discovery.cpp | 20 +- src/core/hle/service/ldn/lan_discovery.h | 5 +- src/core/hle/service/ldn/ldn.cpp | 804 ++---------------- src/core/hle/service/ldn/ldn.h | 6 - src/core/hle/service/ldn/ldn_types.h | 68 +- src/core/hle/service/ldn/monitor_service.cpp | 43 + src/core/hle/service/ldn/monitor_service.h | 28 + .../hle/service/ldn/sf_monitor_service.cpp | 40 + src/core/hle/service/ldn/sf_monitor_service.h | 26 + src/core/hle/service/ldn/sf_service.cpp | 37 + src/core/hle/service/ldn/sf_service.h | 21 + .../hle/service/ldn/sf_service_monitor.cpp | 50 ++ src/core/hle/service/ldn/sf_service_monitor.h | 26 + .../system_local_communication_service.cpp | 56 ++ .../ldn/system_local_communication_service.h | 25 + .../ldn/user_local_communication_service.cpp | 320 +++++++ .../ldn/user_local_communication_service.h | 103 +++ 18 files changed, 911 insertions(+), 779 deletions(-) create mode 100644 src/core/hle/service/ldn/monitor_service.cpp create mode 100644 src/core/hle/service/ldn/monitor_service.h create mode 100644 src/core/hle/service/ldn/sf_monitor_service.cpp create mode 100644 src/core/hle/service/ldn/sf_monitor_service.h create mode 100644 src/core/hle/service/ldn/sf_service.cpp create mode 100644 src/core/hle/service/ldn/sf_service.h create mode 100644 src/core/hle/service/ldn/sf_service_monitor.cpp create mode 100644 src/core/hle/service/ldn/sf_service_monitor.h create mode 100644 src/core/hle/service/ldn/system_local_communication_service.cpp create mode 100644 src/core/hle/service/ldn/system_local_communication_service.h create mode 100644 src/core/hle/service/ldn/user_local_communication_service.cpp create mode 100644 src/core/hle/service/ldn/user_local_communication_service.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2d54909684..175ff88247 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -668,6 +668,18 @@ add_library(core STATIC hle/service/ldn/ldn.h hle/service/ldn/ldn_results.h hle/service/ldn/ldn_types.h + hle/service/ldn/monitor_service.cpp + hle/service/ldn/monitor_service.h + hle/service/ldn/sf_monitor_service.cpp + hle/service/ldn/sf_monitor_service.h + hle/service/ldn/sf_service.cpp + hle/service/ldn/sf_service.h + hle/service/ldn/sf_service_monitor.cpp + hle/service/ldn/sf_service_monitor.h + hle/service/ldn/system_local_communication_service.cpp + hle/service/ldn/system_local_communication_service.h + hle/service/ldn/user_local_communication_service.cpp + hle/service/ldn/user_local_communication_service.h hle/service/ldr/ldr.cpp hle/service/ldr/ldr.h hle/service/lm/lm.cpp diff --git a/src/core/hle/service/ldn/lan_discovery.cpp b/src/core/hle/service/ldn/lan_discovery.cpp index 8f3c045501..b9db19618a 100644 --- a/src/core/hle/service/ldn/lan_discovery.cpp +++ b/src/core/hle/service/ldn/lan_discovery.cpp @@ -85,15 +85,14 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const { } Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network, - std::vector& out_updates, - std::size_t buffer_count) { - if (buffer_count > NodeCountMax) { + std::span out_updates) { + if (out_updates.size() > NodeCountMax) { return ResultInvalidBufferCount; } if (state == State::AccessPointCreated || state == State::StationConnected) { std::memcpy(&out_network, &network_info, sizeof(network_info)); - for (std::size_t i = 0; i < buffer_count; i++) { + for (std::size_t i = 0; i < out_updates.size(); i++) { out_updates[i].state_change = node_changes[i].state_change; node_changes[i].state_change = NodeStateChange::None; } @@ -107,15 +106,8 @@ DisconnectReason LANDiscovery::GetDisconnectReason() const { return disconnect_reason; } -Result LANDiscovery::Scan(std::vector& networks, u16& count, +Result LANDiscovery::Scan(std::span out_networks, s16& out_count, const ScanFilter& filter) { - if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) || - filter.network_type <= NetworkType::All) { - if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) { - return ResultBadInput; - } - } - { std::scoped_lock lock{packet_mutex}; scan_results.clear(); @@ -128,7 +120,7 @@ Result LANDiscovery::Scan(std::vector& networks, u16& count, std::scoped_lock lock{packet_mutex}; for (const auto& [key, info] : scan_results) { - if (count >= networks.size()) { + if (out_count >= static_cast(out_networks.size())) { break; } @@ -159,7 +151,7 @@ Result LANDiscovery::Scan(std::vector& networks, u16& count, } } - networks[count++] = info; + out_networks[out_count++] = info; } return ResultSuccess; diff --git a/src/core/hle/service/ldn/lan_discovery.h b/src/core/hle/service/ldn/lan_discovery.h index 3833cd764a..8f7a8dfc45 100644 --- a/src/core/hle/service/ldn/lan_discovery.h +++ b/src/core/hle/service/ldn/lan_discovery.h @@ -54,11 +54,10 @@ public: void SetState(State new_state); Result GetNetworkInfo(NetworkInfo& out_network) const; - Result GetNetworkInfo(NetworkInfo& out_network, std::vector& out_updates, - std::size_t buffer_count); + Result GetNetworkInfo(NetworkInfo& out_network, std::span out_updates); DisconnectReason GetDisconnectReason() const; - Result Scan(std::vector& networks, u16& count, const ScanFilter& filter); + Result Scan(std::span out_networks, s16& out_count, const ScanFilter& filter); Result SetAdvertiseData(std::span data); Result OpenAccessPoint(); diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 961f89a14b..f2d638c30e 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -1,36 +1,24 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include - #include "core/core.h" -#include "core/hle/service/ldn/lan_discovery.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ldn/ldn.h" -#include "core/hle/service/ldn/ldn_results.h" -#include "core/hle/service/ldn/ldn_types.h" -#include "core/hle/service/server_manager.h" -#include "core/internal_network/network.h" -#include "core/internal_network/network_interface.h" -#include "network/network.h" - -// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent -#undef CreateEvent +#include "core/hle/service/ldn/monitor_service.h" +#include "core/hle/service/ldn/sf_monitor_service.h" +#include "core/hle/service/ldn/sf_service.h" +#include "core/hle/service/ldn/sf_service_monitor.h" +#include "core/hle/service/ldn/system_local_communication_service.h" +#include "core/hle/service/ldn/user_local_communication_service.h" namespace Service::LDN { -class IMonitorService final : public ServiceFramework { +class IMonitorServiceCreator final : public ServiceFramework { public: - explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} { + explicit IMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:m"} { // clang-format off static const FunctionInfo functions[] = { - {0, &IMonitorService::GetStateForMonitor, "GetStateForMonitor"}, - {1, nullptr, "GetNetworkInfoForMonitor"}, - {2, nullptr, "GetIpv4AddressForMonitor"}, - {3, nullptr, "GetDisconnectReasonForMonitor"}, - {4, nullptr, "GetSecurityParameterForMonitor"}, - {5, nullptr, "GetNetworkConfigForMonitor"}, - {100, &IMonitorService::InitializeMonitor, "InitializeMonitor"}, - {101, nullptr, "FinalizeMonitor"}, + {0, C<&IMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"} }; // clang-format on @@ -38,84 +26,20 @@ public: } private: - void GetStateForMonitor(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(state); - } - - void InitializeMonitor(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - state = State::Initialized; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - State state{State::None}; -}; - -class LDNM final : public ServiceFramework { -public: - explicit LDNM(Core::System& system_) : ServiceFramework{system_, "ldn:m"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &LDNM::CreateMonitorService, "CreateMonitorService"} - }; - // clang-format on - - RegisterHandlers(functions); - } - - void CreateMonitorService(HLERequestContext& ctx) { + Result CreateMonitorService(OutInterface out_interface) { LOG_DEBUG(Service_LDN, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + *out_interface = std::make_shared(system); + R_SUCCEED(); } }; -class ISystemLocalCommunicationService final - : public ServiceFramework { +class ISystemServiceCreator final : public ServiceFramework { public: - explicit ISystemLocalCommunicationService(Core::System& system_) - : ServiceFramework{system_, "ISystemLocalCommunicationService"} { + explicit ISystemServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:s"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetState"}, - {1, nullptr, "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"}, - {104, nullptr, "SetWirelessControllerRestriction"}, - {200, nullptr, "OpenAccessPoint"}, - {201, nullptr, "CloseAccessPoint"}, - {202, nullptr, "CreateNetwork"}, - {203, nullptr, "CreateNetworkPrivate"}, - {204, nullptr, "DestroyNetwork"}, - {205, nullptr, "Reject"}, - {206, nullptr, "SetAdvertiseData"}, - {207, nullptr, "SetStationAcceptPolicy"}, - {208, nullptr, "AddAcceptFilterEntry"}, - {209, nullptr, "ClearAcceptFilter"}, - {300, nullptr, "OpenStation"}, - {301, nullptr, "CloseStation"}, - {302, nullptr, "Connect"}, - {303, nullptr, "ConnectPrivate"}, - {304, nullptr, "Disconnect"}, - {400, nullptr, "InitializeSystem"}, - {401, nullptr, "FinalizeSystem"}, - {402, nullptr, "SetOperationMode"}, - {403, &ISystemLocalCommunicationService::InitializeSystem2, "InitializeSystem2"}, + {0, C<&ISystemServiceCreator::CreateSystemLocalCommunicationService>, "CreateSystemLocalCommunicationService"}, }; // clang-format on @@ -123,651 +47,78 @@ public: } private: - void InitializeSystem2(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } -}; - -class IUserLocalCommunicationService final - : public ServiceFramework { -public: - explicit IUserLocalCommunicationService(Core::System& system_) - : ServiceFramework{system_, "IUserLocalCommunicationService"}, - service_context{system, "IUserLocalCommunicationService"}, - room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IUserLocalCommunicationService::GetState, "GetState"}, - {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"}, - {2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"}, - {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, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"}, - {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, - {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, - {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, - {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"}, - {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"}, - {205, nullptr, "Reject"}, - {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"}, - {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"}, - {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"}, - {209, nullptr, "ClearAcceptFilter"}, - {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"}, - {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"}, - {302, &IUserLocalCommunicationService::Connect, "Connect"}, - {303, nullptr, "ConnectPrivate"}, - {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"); - } - - ~IUserLocalCommunicationService() { - if (is_initialized) { - if (auto room_member = room_network.GetRoomMember().lock()) { - room_member->Unbind(ldn_packet_received); - } - } - - service_context.CloseEvent(state_change_event); - } - - /// Callback to parse and handle a received LDN packet. - void OnLDNPacketReceived(const Network::LDNPacket& packet) { - lan_discovery.ReceivePacket(packet); - } - - void OnEventFired() { - state_change_event->Signal(); - } - - void GetState(HLERequestContext& ctx) { - State state = State::Error; - - if (is_initialized) { - state = lan_discovery.GetState(); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(state); - } - - void GetNetworkInfo(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 network_info{}; - const auto rc = lan_discovery.GetNetworkInfo(network_info); - if (rc.IsError()) { - LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(rc); - return; - } - - ctx.WriteBuffer(network_info); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetIpv4Address(HLERequestContext& ctx) { - const auto network_interface = Network::GetSelectedNetworkInterface(); - - if (!network_interface) { - LOG_ERROR(Service_LDN, "No network interface available"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultNoIpAddress); - return; - } - - Ipv4Address current_address{Network::TranslateIPv4(network_interface->ip_address)}; - Ipv4Address subnet_mask{Network::TranslateIPv4(network_interface->subnet_mask)}; - - // When we're connected to a room, spoof the hosts IP address - if (auto room_member = room_network.GetRoomMember().lock()) { - if (room_member->IsConnected()) { - current_address = room_member->GetFakeIpAddress(); - } - } - - std::reverse(std::begin(current_address), std::end(current_address)); // ntohl - std::reverse(std::begin(subnet_mask), std::end(subnet_mask)); // ntohl - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushRaw(current_address); - rb.PushRaw(subnet_mask); - } - - void GetDisconnectReason(HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(lan_discovery.GetDisconnectReason()); - } - - void GetSecurityParameter(HLERequestContext& ctx) { - SecurityParameter security_parameter{}; - NetworkInfo info{}; - const Result rc = lan_discovery.GetNetworkInfo(info); - - 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)); - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(rc); - rb.PushRaw(security_parameter); - } - - void GetNetworkConfig(HLERequestContext& ctx) { - NetworkConfig config{}; - NetworkInfo info{}; - const Result rc = lan_discovery.GetNetworkInfo(info); - - 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; - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(rc); - rb.PushRaw(config); - } - - void AttachStateChangeEvent(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(state_change_event->GetReadableEvent()); - } - - void GetNetworkInfoLatestUpdate(HLERequestContext& ctx) { - const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0); - const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements(1); - - if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { - LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size, - node_buffer_count); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultBadInput); - return; - } - - NetworkInfo info{}; - std::vector latest_update(node_buffer_count); - - const auto rc = lan_discovery.GetNetworkInfo(info, latest_update, latest_update.size()); - if (rc.IsError()) { - LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(rc); - return; - } - - ctx.WriteBuffer(info, 0); - ctx.WriteBuffer(latest_update, 1); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Scan(HLERequestContext& ctx) { - ScanImpl(ctx); - } - - void ScanPrivate(HLERequestContext& ctx) { - ScanImpl(ctx, true); - } - - void ScanImpl(HLERequestContext& ctx, bool is_private = false) { - IPC::RequestParser rp{ctx}; - const auto channel{rp.PopEnum()}; - const auto scan_filter{rp.PopRaw()}; - - const std::size_t network_info_size = ctx.GetWriteBufferNumElements(); - - 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 network_infos(network_info_size); - Result rc = lan_discovery.Scan(network_infos, count, scan_filter); - - LOG_INFO(Service_LDN, - "called, channel={}, filter_scan_flag={}, filter_network_type={}, is_private={}", - channel, scan_filter.flag, scan_filter.network_type, is_private); - - ctx.WriteBuffer(network_infos); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(rc); - rb.Push(count); - } - - void SetWirelessControllerRestriction(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void OpenAccessPoint(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.OpenAccessPoint()); - } - - void CloseAccessPoint(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.CloseAccessPoint()); - } - - void CreateNetwork(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - CreateNetworkImpl(ctx); - } - - void CreateNetworkPrivate(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - CreateNetworkImpl(ctx, true); - } - - void CreateNetworkImpl(HLERequestContext& ctx, bool is_private = false) { - IPC::RequestParser rp{ctx}; - - const auto security_config{rp.PopRaw()}; - [[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw() - : SecurityParameter{}}; - const auto user_config{rp.PopRaw()}; - rp.Pop(); // Padding - const auto network_Config{rp.PopRaw()}; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config)); - } - - void DestroyNetwork(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.DestroyNetwork()); - } - - void SetAdvertiseData(HLERequestContext& ctx) { - const auto read_buffer = ctx.ReadBuffer(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.SetAdvertiseData(read_buffer)); - } - - void SetStationAcceptPolicy(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void AddAcceptFilterEntry(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void OpenStation(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.OpenStation()); - } - - void CloseStation(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.CloseStation()); - } - - void Connect(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - SecurityConfig security_config; - UserConfig user_config; - u32 local_communication_version; - u32 option; - }; - static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw()}; - - LOG_INFO(Service_LDN, - "called, passphrase_size={}, security_mode={}, " - "local_communication_version={}", - parameters.security_config.passphrase_size, - parameters.security_config.security_mode, parameters.local_communication_version); - - const auto read_buffer = ctx.ReadBuffer(); - 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; - } - - NetworkInfo network_info{}; - std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.Connect(network_info, parameters.user_config, - static_cast(parameters.local_communication_version))); - } - - void Disconnect(HLERequestContext& ctx) { - LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.Disconnect()); - } - - void Initialize(HLERequestContext& ctx) { - 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 Finalize(HLERequestContext& ctx) { - if (auto room_member = room_network.GetRoomMember().lock()) { - room_member->Unbind(ldn_packet_received); - } - - is_initialized = false; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(lan_discovery.Finalize()); - } - - void Initialize2(HLERequestContext& ctx) { - 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 InitializeImpl(HLERequestContext& ctx) { - const auto network_interface = Network::GetSelectedNetworkInterface(); - if (!network_interface) { - LOG_ERROR(Service_LDN, "No network interface is set"); - return ResultAirplaneModeEnabled; - } - - if (auto room_member = room_network.GetRoomMember().lock()) { - ldn_packet_received = room_member->BindOnLdnPacketReceived( - [this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); }); - } else { - LOG_ERROR(Service_LDN, "Couldn't bind callback!"); - return ResultAirplaneModeEnabled; - } - - lan_discovery.Initialize([&]() { OnEventFired(); }); - is_initialized = true; - return ResultSuccess; - } - - KernelHelpers::ServiceContext service_context; - Kernel::KEvent* state_change_event; - Network::RoomNetwork& room_network; - LANDiscovery lan_discovery; - - // Callback identifier for the OnLDNPacketReceived event. - Network::RoomMember::CallbackHandle ldn_packet_received; - - bool is_initialized{}; -}; - -class LDNS final : public ServiceFramework { -public: - explicit LDNS(Core::System& system_) : ServiceFramework{system_, "ldn:s"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - - void CreateSystemLocalCommunicationService(HLERequestContext& ctx) { + Result CreateSystemLocalCommunicationService( + OutInterface out_interface) { LOG_DEBUG(Service_LDN, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + *out_interface = std::make_shared(system); + R_SUCCEED(); } }; -class LDNU final : public ServiceFramework { +class IUserServiceCreator final : public ServiceFramework { public: - explicit LDNU(Core::System& system_) : ServiceFramework{system_, "ldn:u"} { + explicit IUserServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:u"} { // clang-format off static const FunctionInfo functions[] = { - {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"}, + {0, C<&IUserServiceCreator::CreateUserLocalCommunicationService>, "CreateUserLocalCommunicationService"}, }; // clang-format on RegisterHandlers(functions); } - void CreateUserLocalCommunicationService(HLERequestContext& ctx) { +private: + Result CreateUserLocalCommunicationService( + OutInterface out_interface) { LOG_DEBUG(Service_LDN, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + *out_interface = std::make_shared(system); + R_SUCCEED(); } }; -class INetworkService final : public ServiceFramework { +class ISfServiceCreator final : public ServiceFramework { public: - explicit INetworkService(Core::System& system_) : ServiceFramework{system_, "INetworkService"} { + explicit ISfServiceCreator(Core::System& system_, bool is_system_, const char* name_) + : ServiceFramework{system_, name_}, is_system{is_system_} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Initialize"}, - {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"}, - {264, nullptr, "GetNetworkInterfaceLastError"}, - {272, nullptr, "GetRole"}, - {280, nullptr, "GetAdvertiseData"}, - {288, nullptr, "GetGroupInfo"}, - {296, nullptr, "GetGroupInfo2"}, - {304, nullptr, "GetGroupOwner"}, - {312, nullptr, "GetIpConfig"}, - {320, nullptr, "GetLinkLevel"}, - {512, nullptr, "Scan"}, - {768, nullptr, "CreateGroup"}, - {776, nullptr, "DestroyGroup"}, - {784, nullptr, "SetAdvertiseData"}, - {1536, nullptr, "SendToOtherGroup"}, - {1544, nullptr, "RecvFromOtherGroup"}, - {1552, nullptr, "AddAcceptableGroupId"}, - {1560, nullptr, "ClearAcceptableGroupId"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class INetworkServiceMonitor final : public ServiceFramework { -public: - explicit INetworkServiceMonitor(Core::System& system_) - : ServiceFramework{system_, "INetworkServiceMonitor"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &INetworkServiceMonitor::Initialize, "Initialize"}, - {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"}, - {264, nullptr, "GetNetworkInterfaceLastError"}, - {272, nullptr, "GetRole"}, - {280, nullptr, "GetAdvertiseData"}, - {281, nullptr, "GetAdvertiseData2"}, - {288, nullptr, "GetGroupInfo"}, - {296, nullptr, "GetGroupInfo2"}, - {304, nullptr, "GetGroupOwner"}, - {312, nullptr, "GetIpConfig"}, - {320, nullptr, "GetLinkLevel"}, - {328, nullptr, "AttachJoinEvent"}, - {336, nullptr, "GetMembers"}, + {0, C<&ISfServiceCreator::CreateNetworkService>, "CreateNetworkService"}, + {8, C<&ISfServiceCreator::CreateNetworkServiceMonitor>, "CreateNetworkServiceMonitor"}, }; // clang-format on RegisterHandlers(functions); } - void Initialize(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultDisabled); - } -}; - -class LP2PAPP final : public ServiceFramework { -public: - explicit LP2PAPP(Core::System& system_) : ServiceFramework{system_, "lp2p:app"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &LP2PAPP::CreateMonitorService, "CreateNetworkService"}, - {8, &LP2PAPP::CreateMonitorService, "CreateNetworkServiceMonitor"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - - void CreateNetworkervice(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 reserved_input = rp.Pop(); - const u32 input = rp.Pop(); - +private: + Result CreateNetworkService(OutInterface out_interface, u32 input, + u64 reserved_input) { LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input, input); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + *out_interface = std::make_shared(system); + R_SUCCEED(); } - void CreateMonitorService(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 reserved_input = rp.Pop(); - + Result CreateNetworkServiceMonitor(OutInterface out_interface, + u64 reserved_input) { LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + *out_interface = std::make_shared(system); + R_SUCCEED(); } + + bool is_system{}; }; -class LP2PSYS final : public ServiceFramework { +class ISfMonitorServiceCreator final : public ServiceFramework { public: - explicit LP2PSYS(Core::System& system_) : ServiceFramework{system_, "lp2p:sys"} { + explicit ISfMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} { // clang-format off static const FunctionInfo functions[] = { - {0, &LP2PSYS::CreateMonitorService, "CreateNetworkService"}, - {8, &LP2PSYS::CreateMonitorService, "CreateNetworkServiceMonitor"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - - void CreateNetworkervice(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 reserved_input = rp.Pop(); - const u32 input = rp.Pop(); - - LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input, - input); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void CreateMonitorService(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 reserved_input = rp.Pop(); - - LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } -}; - -class ISfMonitorService final : public ServiceFramework { -public: - explicit ISfMonitorService(Core::System& system_) - : ServiceFramework{system_, "ISfMonitorService"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ISfMonitorService::Initialize, "Initialize"}, - {288, &ISfMonitorService::GetGroupInfo, "GetGroupInfo"}, - {320, nullptr, "GetLinkLevel"}, + {0, C<&ISfMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"}, }; // clang-format on @@ -775,64 +126,27 @@ public: } private: - void Initialize(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); - } - - void GetGroupInfo(HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - struct GroupInfo { - std::array info; - }; - - GroupInfo group_info{}; - - ctx.WriteBuffer(group_info); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } -}; - -class LP2PM final : public ServiceFramework { -public: - explicit LP2PM(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &LP2PM::CreateMonitorService, "CreateMonitorService"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void CreateMonitorService(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 reserved_input = rp.Pop(); - + Result CreateMonitorService(OutInterface out_interface, u64 reserved_input) { LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + *out_interface = std::make_shared(system); + R_SUCCEED(); } }; void LoopProcess(Core::System& system) { auto server_manager = std::make_unique(system); - server_manager->RegisterNamedService("ldn:m", std::make_shared(system)); - server_manager->RegisterNamedService("ldn:s", std::make_shared(system)); - server_manager->RegisterNamedService("ldn:u", std::make_shared(system)); + server_manager->RegisterNamedService("ldn:m", std::make_shared(system)); + server_manager->RegisterNamedService("ldn:s", std::make_shared(system)); + server_manager->RegisterNamedService("ldn:u", std::make_shared(system)); - server_manager->RegisterNamedService("lp2p:app", std::make_shared(system)); - server_manager->RegisterNamedService("lp2p:sys", std::make_shared(system)); - server_manager->RegisterNamedService("lp2p:m", std::make_shared(system)); + server_manager->RegisterNamedService( + "lp2p:app", std::make_shared(system, false, "lp2p:app")); + server_manager->RegisterNamedService( + "lp2p:sys", std::make_shared(system, true, "lp2p:sys")); + server_manager->RegisterNamedService("lp2p:m", + std::make_shared(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h index f4a319168d..dae037fa8f 100644 --- a/src/core/hle/service/ldn/ldn.h +++ b/src/core/hle/service/ldn/ldn.h @@ -3,12 +3,6 @@ #pragma once -#include "core/hle/kernel/k_event.h" -#include "core/hle/result.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/sm/sm.h" - namespace Core { class System; } diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h index 44c2c773b0..6198aa07b2 100644 --- a/src/core/hle/service/ldn/ldn_types.h +++ b/src/core/hle/service/ldn/ldn_types.h @@ -123,6 +123,18 @@ enum class NodeStatus : u8 { Connected, }; +enum class WirelessControllerRestriction : u32 { + None, + Default, +}; + +struct ConnectOption { + union { + u32 raw; + }; +}; +static_assert(sizeof(ConnectOption) == 0x4, "ConnectOption is an invalid size"); + struct NodeLatestUpdate { NodeStateChange state_change; INSERT_PADDING_BYTES(0x7); // Unknown @@ -139,9 +151,9 @@ static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size"); struct IntentId { u64 local_communication_id; - INSERT_PADDING_BYTES(0x2); // Reserved + INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved u16 scene_id; - INSERT_PADDING_BYTES(0x4); // Reserved + INSERT_PADDING_BYTES_NOINIT(0x4); // Reserved }; static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size"); @@ -152,13 +164,14 @@ struct NetworkId { static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size"); struct Ssid { - u8 length{}; - std::array raw{}; + u8 length; + std::array raw; Ssid() = default; constexpr explicit Ssid(std::string_view data) { length = static_cast(std::min(data.size(), SsidLengthMax)); + raw = {}; data.copy(raw.data(), length); raw[length] = 0; } @@ -181,7 +194,7 @@ using Ipv4Address = std::array; static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); struct MacAddress { - std::array raw{}; + std::array raw; friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default; }; @@ -211,7 +224,7 @@ struct CommonNetworkInfo { WifiChannel channel; LinkLevel link_level; PackedNetworkType network_type; - INSERT_PADDING_BYTES(0x4); + INSERT_PADDING_BYTES_NOINIT(0x4); }; static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size"); @@ -221,9 +234,9 @@ struct NodeInfo { s8 node_id; u8 is_connected; std::array user_name; - INSERT_PADDING_BYTES(0x1); // Reserved + INSERT_PADDING_BYTES_NOINIT(0x1); // Reserved s16 local_communication_version; - INSERT_PADDING_BYTES(0x10); // Reserved + INSERT_PADDING_BYTES_NOINIT(0x10); // Reserved }; static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size"); @@ -232,14 +245,14 @@ struct LdnNetworkInfo { SecurityMode security_mode; AcceptPolicy station_accept_policy; u8 has_action_frame; - INSERT_PADDING_BYTES(0x2); // Padding + INSERT_PADDING_BYTES_NOINIT(0x2); // Padding u8 node_count_max; u8 node_count; std::array nodes; - INSERT_PADDING_BYTES(0x2); // Reserved + INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved u16 advertise_data_size; std::array advertise_data; - INSERT_PADDING_BYTES(0x8C); // Reserved + INSERT_PADDING_BYTES_NOINIT(0x8C); // Reserved u64 random_authentication_id; }; static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size"); @@ -250,6 +263,7 @@ struct NetworkInfo { LdnNetworkInfo ldn; }; static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size"); +static_assert(std::is_trivial_v, "NetworkInfo type must be trivially copyable."); struct SecurityConfig { SecurityMode security_mode; @@ -303,4 +317,36 @@ struct AddressList { }; static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size"); +struct GroupInfo { + std::array info; +}; + +struct CreateNetworkConfig { + SecurityConfig security_config; + UserConfig user_config; + INSERT_PADDING_BYTES(0x4); + NetworkConfig network_config; +}; +static_assert(sizeof(CreateNetworkConfig) == 0x98, "CreateNetworkConfig is an invalid size"); + +#pragma pack(push, 4) +struct CreateNetworkConfigPrivate { + SecurityConfig security_config; + SecurityParameter security_parameter; + UserConfig user_config; + INSERT_PADDING_BYTES(0x4); + NetworkConfig network_config; +}; +#pragma pack(pop) +static_assert(sizeof(CreateNetworkConfigPrivate) == 0xB8, + "CreateNetworkConfigPrivate is an invalid size"); + +struct ConnectNetworkData { + SecurityConfig security_config; + UserConfig user_config; + s32 local_communication_version; + ConnectOption option; +}; +static_assert(sizeof(ConnectNetworkData) == 0x7c, "ConnectNetworkData is an invalid size"); + } // namespace Service::LDN diff --git a/src/core/hle/service/ldn/monitor_service.cpp b/src/core/hle/service/ldn/monitor_service.cpp new file mode 100644 index 0000000000..3471f69da4 --- /dev/null +++ b/src/core/hle/service/ldn/monitor_service.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ldn/monitor_service.h" + +namespace Service::LDN { + +IMonitorService::IMonitorService(Core::System& system_) + : ServiceFramework{system_, "IMonitorService"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&IMonitorService::GetStateForMonitor>, "GetStateForMonitor"}, + {1, nullptr, "GetNetworkInfoForMonitor"}, + {2, nullptr, "GetIpv4AddressForMonitor"}, + {3, nullptr, "GetDisconnectReasonForMonitor"}, + {4, nullptr, "GetSecurityParameterForMonitor"}, + {5, nullptr, "GetNetworkConfigForMonitor"}, + {100, C<&IMonitorService::InitializeMonitor>, "InitializeMonitor"}, + {101, nullptr, "FinalizeMonitor"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IMonitorService::~IMonitorService() = default; + +Result IMonitorService::GetStateForMonitor(Out out_state) { + LOG_INFO(Service_LDN, "called"); + + *out_state = state; + R_SUCCEED(); +} + +Result IMonitorService::InitializeMonitor() { + LOG_INFO(Service_LDN, "called"); + + state = State::Initialized; + R_SUCCEED(); +} + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/monitor_service.h b/src/core/hle/service/ldn/monitor_service.h new file mode 100644 index 0000000000..61aacef308 --- /dev/null +++ b/src/core/hle/service/ldn/monitor_service.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/ldn/ldn_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::LDN { + +class IMonitorService final : public ServiceFramework { +public: + explicit IMonitorService(Core::System& system_); + ~IMonitorService() override; + +private: + Result GetStateForMonitor(Out out_state); + Result InitializeMonitor(); + + State state{State::None}; +}; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/sf_monitor_service.cpp b/src/core/hle/service/ldn/sf_monitor_service.cpp new file mode 100644 index 0000000000..9e6736ff2c --- /dev/null +++ b/src/core/hle/service/ldn/sf_monitor_service.cpp @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ldn/ldn_types.h" +#include "core/hle/service/ldn/sf_monitor_service.h" + +namespace Service::LDN { + +ISfMonitorService::ISfMonitorService(Core::System& system_) + : ServiceFramework{system_, "ISfMonitorService"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&ISfMonitorService::Initialize>, "Initialize"}, + {288, C<&ISfMonitorService::GetGroupInfo>, "GetGroupInfo"}, + {320, nullptr, "GetLinkLevel"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISfMonitorService::~ISfMonitorService() = default; + +Result ISfMonitorService::Initialize(Out out_value) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + *out_value = 0; + R_SUCCEED(); +} + +Result ISfMonitorService::GetGroupInfo( + OutLargeData out_group_info) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + *out_group_info = GroupInfo{}; + R_SUCCEED(); +} + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/sf_monitor_service.h b/src/core/hle/service/ldn/sf_monitor_service.h new file mode 100644 index 0000000000..d021152010 --- /dev/null +++ b/src/core/hle/service/ldn/sf_monitor_service.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::LDN { +struct GroupInfo; + +class ISfMonitorService final : public ServiceFramework { +public: + explicit ISfMonitorService(Core::System& system_); + ~ISfMonitorService() override; + +private: + Result Initialize(Out out_value); + Result GetGroupInfo(OutLargeData out_group_info); +}; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/sf_service.cpp b/src/core/hle/service/ldn/sf_service.cpp new file mode 100644 index 0000000000..61cabe219a --- /dev/null +++ b/src/core/hle/service/ldn/sf_service.cpp @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/ldn/sf_service.h" + +namespace Service::LDN { + +ISfService::ISfService(Core::System& system_) : ServiceFramework{system_, "ISfService"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"}, + {264, nullptr, "GetNetworkInterfaceLastError"}, + {272, nullptr, "GetRole"}, + {280, nullptr, "GetAdvertiseData"}, + {288, nullptr, "GetGroupInfo"}, + {296, nullptr, "GetGroupInfo2"}, + {304, nullptr, "GetGroupOwner"}, + {312, nullptr, "GetIpConfig"}, + {320, nullptr, "GetLinkLevel"}, + {512, nullptr, "Scan"}, + {768, nullptr, "CreateGroup"}, + {776, nullptr, "DestroyGroup"}, + {784, nullptr, "SetAdvertiseData"}, + {1536, nullptr, "SendToOtherGroup"}, + {1544, nullptr, "RecvFromOtherGroup"}, + {1552, nullptr, "AddAcceptableGroupId"}, + {1560, nullptr, "ClearAcceptableGroupId"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISfService::~ISfService() = default; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/sf_service.h b/src/core/hle/service/ldn/sf_service.h new file mode 100644 index 0000000000..05534b5677 --- /dev/null +++ b/src/core/hle/service/ldn/sf_service.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::LDN { + +class ISfService final : public ServiceFramework { +public: + explicit ISfService(Core::System& system_); + ~ISfService() override; +}; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/sf_service_monitor.cpp b/src/core/hle/service/ldn/sf_service_monitor.cpp new file mode 100644 index 0000000000..33e3c1d69a --- /dev/null +++ b/src/core/hle/service/ldn/sf_service_monitor.cpp @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ldn/ldn_types.h" +#include "core/hle/service/ldn/sf_service_monitor.h" + +namespace Service::LDN { + +ISfServiceMonitor::ISfServiceMonitor(Core::System& system_) + : ServiceFramework{system_, "ISfServiceMonitor"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&ISfServiceMonitor::Initialize>, "Initialize"}, + {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"}, + {264, nullptr, "GetNetworkInterfaceLastError"}, + {272, nullptr, "GetRole"}, + {280, nullptr, "GetAdvertiseData"}, + {281, nullptr, "GetAdvertiseData2"}, + {288, C<&ISfServiceMonitor::GetGroupInfo>, "GetGroupInfo"}, + {296, nullptr, "GetGroupInfo2"}, + {304, nullptr, "GetGroupOwner"}, + {312, nullptr, "GetIpConfig"}, + {320, nullptr, "GetLinkLevel"}, + {328, nullptr, "AttachJoinEvent"}, + {336, nullptr, "GetMembers"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISfServiceMonitor::~ISfServiceMonitor() = default; + +Result ISfServiceMonitor::Initialize(Out out_value) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + *out_value = 0; + R_SUCCEED(); +} + +Result ISfServiceMonitor::GetGroupInfo( + OutLargeData out_group_info) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + *out_group_info = GroupInfo{}; + R_SUCCEED(); +} + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/sf_service_monitor.h b/src/core/hle/service/ldn/sf_service_monitor.h new file mode 100644 index 0000000000..3cfc5005eb --- /dev/null +++ b/src/core/hle/service/ldn/sf_service_monitor.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::LDN { +struct GroupInfo; + +class ISfServiceMonitor final : public ServiceFramework { +public: + explicit ISfServiceMonitor(Core::System& system_); + ~ISfServiceMonitor() override; + +private: + Result Initialize(Out out_value); + Result GetGroupInfo(OutLargeData out_group_info); +}; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/system_local_communication_service.cpp b/src/core/hle/service/ldn/system_local_communication_service.cpp new file mode 100644 index 0000000000..7b52223cdc --- /dev/null +++ b/src/core/hle/service/ldn/system_local_communication_service.cpp @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ldn/system_local_communication_service.h" + +namespace Service::LDN { + +ISystemLocalCommunicationService::ISystemLocalCommunicationService(Core::System& system_) + : ServiceFramework{system_, "ISystemLocalCommunicationService"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetState"}, + {1, nullptr, "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"}, + {104, nullptr, "SetWirelessControllerRestriction"}, + {200, nullptr, "OpenAccessPoint"}, + {201, nullptr, "CloseAccessPoint"}, + {202, nullptr, "CreateNetwork"}, + {203, nullptr, "CreateNetworkPrivate"}, + {204, nullptr, "DestroyNetwork"}, + {205, nullptr, "Reject"}, + {206, nullptr, "SetAdvertiseData"}, + {207, nullptr, "SetStationAcceptPolicy"}, + {208, nullptr, "AddAcceptFilterEntry"}, + {209, nullptr, "ClearAcceptFilter"}, + {300, nullptr, "OpenStation"}, + {301, nullptr, "CloseStation"}, + {302, nullptr, "Connect"}, + {303, nullptr, "ConnectPrivate"}, + {304, nullptr, "Disconnect"}, + {400, nullptr, "InitializeSystem"}, + {401, nullptr, "FinalizeSystem"}, + {402, nullptr, "SetOperationMode"}, + {403, C<&ISystemLocalCommunicationService::InitializeSystem2>, "InitializeSystem2"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISystemLocalCommunicationService::~ISystemLocalCommunicationService() = default; + +Result ISystemLocalCommunicationService::InitializeSystem2() { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + R_SUCCEED(); +} + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/system_local_communication_service.h b/src/core/hle/service/ldn/system_local_communication_service.h new file mode 100644 index 0000000000..a02b097ea7 --- /dev/null +++ b/src/core/hle/service/ldn/system_local_communication_service.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::LDN { + +class ISystemLocalCommunicationService final + : public ServiceFramework { +public: + explicit ISystemLocalCommunicationService(Core::System& system_); + ~ISystemLocalCommunicationService() override; + +private: + Result InitializeSystem2(); +}; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/user_local_communication_service.cpp b/src/core/hle/service/ldn/user_local_communication_service.cpp new file mode 100644 index 0000000000..f28368962f --- /dev/null +++ b/src/core/hle/service/ldn/user_local_communication_service.cpp @@ -0,0 +1,320 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "core/core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ldn/ldn_results.h" +#include "core/hle/service/ldn/ldn_types.h" +#include "core/hle/service/ldn/user_local_communication_service.h" +#include "core/hle/service/server_manager.h" +#include "core/internal_network/network.h" +#include "core/internal_network/network_interface.h" +#include "network/network.h" + +// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent +#undef CreateEvent + +namespace Service::LDN { + +IUserLocalCommunicationService::IUserLocalCommunicationService(Core::System& system_) + : ServiceFramework{system_, "IUserLocalCommunicationService"}, + service_context{system, "IUserLocalCommunicationService"}, + room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&IUserLocalCommunicationService::GetState>, "GetState"}, + {1, C<&IUserLocalCommunicationService::GetNetworkInfo>, "GetNetworkInfo"}, + {2, C<&IUserLocalCommunicationService::GetIpv4Address>, "GetIpv4Address"}, + {3, C<&IUserLocalCommunicationService::GetDisconnectReason>, "GetDisconnectReason"}, + {4, C<&IUserLocalCommunicationService::GetSecurityParameter>, "GetSecurityParameter"}, + {5, C<&IUserLocalCommunicationService::GetNetworkConfig>, "GetNetworkConfig"}, + {100, C<&IUserLocalCommunicationService::AttachStateChangeEvent>, "AttachStateChangeEvent"}, + {101, C<&IUserLocalCommunicationService::GetNetworkInfoLatestUpdate>, "GetNetworkInfoLatestUpdate"}, + {102, C<&IUserLocalCommunicationService::Scan>, "Scan"}, + {103, C<&IUserLocalCommunicationService::ScanPrivate>, "ScanPrivate"}, + {104, C<&IUserLocalCommunicationService::SetWirelessControllerRestriction>, "SetWirelessControllerRestriction"}, + {200, C<&IUserLocalCommunicationService::OpenAccessPoint>, "OpenAccessPoint"}, + {201, C<&IUserLocalCommunicationService::CloseAccessPoint>, "CloseAccessPoint"}, + {202, C<&IUserLocalCommunicationService::CreateNetwork>, "CreateNetwork"}, + {203, C<&IUserLocalCommunicationService::CreateNetworkPrivate>, "CreateNetworkPrivate"}, + {204, C<&IUserLocalCommunicationService::DestroyNetwork>, "DestroyNetwork"}, + {205, nullptr, "Reject"}, + {206, C<&IUserLocalCommunicationService::SetAdvertiseData>, "SetAdvertiseData"}, + {207, C<&IUserLocalCommunicationService::SetStationAcceptPolicy>, "SetStationAcceptPolicy"}, + {208, C<&IUserLocalCommunicationService::AddAcceptFilterEntry>, "AddAcceptFilterEntry"}, + {209, nullptr, "ClearAcceptFilter"}, + {300, C<&IUserLocalCommunicationService::OpenStation>, "OpenStation"}, + {301, C<&IUserLocalCommunicationService::CloseStation>, "CloseStation"}, + {302, C<&IUserLocalCommunicationService::Connect>, "Connect"}, + {303, nullptr, "ConnectPrivate"}, + {304, C<&IUserLocalCommunicationService::Disconnect>, "Disconnect"}, + {400, C<&IUserLocalCommunicationService::Initialize>, "Initialize"}, + {401, C<&IUserLocalCommunicationService::Finalize>, "Finalize"}, + {402, C<&IUserLocalCommunicationService::Initialize2>, "Initialize2"}, + }; + // clang-format on + + RegisterHandlers(functions); + + state_change_event = + service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent"); +} + +IUserLocalCommunicationService::~IUserLocalCommunicationService() { + if (is_initialized) { + if (auto room_member = room_network.GetRoomMember().lock()) { + room_member->Unbind(ldn_packet_received); + } + } + + service_context.CloseEvent(state_change_event); +} + +Result IUserLocalCommunicationService::GetState(Out out_state) { + *out_state = State::Error; + + if (is_initialized) { + *out_state = lan_discovery.GetState(); + } + + LOG_INFO(Service_LDN, "called, state={}", *out_state); + + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::GetNetworkInfo( + OutLargeData out_network_info) { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info)); +} + +Result IUserLocalCommunicationService::GetIpv4Address(Out out_current_address, + Out out_subnet_mask) { + LOG_INFO(Service_LDN, "called"); + const auto network_interface = Network::GetSelectedNetworkInterface(); + + R_UNLESS(network_interface.has_value(), ResultNoIpAddress); + + *out_current_address = {Network::TranslateIPv4(network_interface->ip_address)}; + *out_subnet_mask = {Network::TranslateIPv4(network_interface->subnet_mask)}; + + // When we're connected to a room, spoof the hosts IP address + if (auto room_member = room_network.GetRoomMember().lock()) { + if (room_member->IsConnected()) { + *out_current_address = room_member->GetFakeIpAddress(); + } + } + + std::reverse(std::begin(*out_current_address), std::end(*out_current_address)); // ntohl + std::reverse(std::begin(*out_subnet_mask), std::end(*out_subnet_mask)); // ntohl + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::GetDisconnectReason( + Out out_disconnect_reason) { + LOG_INFO(Service_LDN, "called"); + + *out_disconnect_reason = lan_discovery.GetDisconnectReason(); + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::GetSecurityParameter( + Out out_security_parameter) { + LOG_INFO(Service_LDN, "called"); + + NetworkInfo info{}; + R_TRY(lan_discovery.GetNetworkInfo(info)); + + out_security_parameter->session_id = info.network_id.session_id; + std::memcpy(out_security_parameter->data.data(), info.ldn.security_parameter.data(), + sizeof(SecurityParameter::data)); + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::GetNetworkConfig(Out out_network_config) { + LOG_INFO(Service_LDN, "called"); + + NetworkInfo info{}; + R_TRY(lan_discovery.GetNetworkInfo(info)); + + out_network_config->intent_id = info.network_id.intent_id; + out_network_config->channel = info.common.channel; + out_network_config->node_count_max = info.ldn.node_count_max; + out_network_config->local_communication_version = info.ldn.nodes[0].local_communication_version; + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::AttachStateChangeEvent( + OutCopyHandle out_event) { + LOG_INFO(Service_LDN, "called"); + + *out_event = &state_change_event->GetReadableEvent(); + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate( + OutLargeData out_network_info, + OutArray out_node_latest_update) { + LOG_INFO(Service_LDN, "called"); + + R_UNLESS(!out_node_latest_update.empty(), ResultBadInput); + + R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info, out_node_latest_update)); +} + +Result IUserLocalCommunicationService::Scan( + Out network_count, WifiChannel channel, const ScanFilter& scan_filter, + OutArray out_network_info) { + LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}", + channel, scan_filter.flag, scan_filter.network_type); + + R_UNLESS(!out_network_info.empty(), ResultBadInput); + R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter)); +} + +Result IUserLocalCommunicationService::ScanPrivate( + Out network_count, WifiChannel channel, const ScanFilter& scan_filter, + OutArray out_network_info) { + LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}", + channel, scan_filter.flag, scan_filter.network_type); + + R_UNLESS(out_network_info.empty(), ResultBadInput); + R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter)); +} + +Result IUserLocalCommunicationService::SetWirelessControllerRestriction( + WirelessControllerRestriction wireless_restriction) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::OpenAccessPoint() { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.OpenAccessPoint()); +} + +Result IUserLocalCommunicationService::CloseAccessPoint() { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.CloseAccessPoint()); +} + +Result IUserLocalCommunicationService::CreateNetwork(const CreateNetworkConfig& create_config) { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config, + create_config.network_config)); +} + +Result IUserLocalCommunicationService::CreateNetworkPrivate( + const CreateNetworkConfigPrivate& create_config, + InArray address_list) { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config, + create_config.network_config)); +} + +Result IUserLocalCommunicationService::DestroyNetwork() { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.DestroyNetwork()); +} + +Result IUserLocalCommunicationService::SetAdvertiseData( + InBuffer buffer_data) { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.SetAdvertiseData(buffer_data)); +} + +Result IUserLocalCommunicationService::SetStationAcceptPolicy(AcceptPolicy accept_policy) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::AddAcceptFilterEntry(MacAddress mac_address) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::OpenStation() { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.OpenStation()); +} + +Result IUserLocalCommunicationService::CloseStation() { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.CloseStation()); +} + +Result IUserLocalCommunicationService::Connect( + const ConnectNetworkData& connect_data, + InLargeData network_info) { + LOG_INFO(Service_LDN, + "called, passphrase_size={}, security_mode={}, " + "local_communication_version={}", + connect_data.security_config.passphrase_size, + connect_data.security_config.security_mode, connect_data.local_communication_version); + + R_RETURN(lan_discovery.Connect(*network_info, connect_data.user_config, + static_cast(connect_data.local_communication_version))); +} + +Result IUserLocalCommunicationService::Disconnect() { + LOG_INFO(Service_LDN, "called"); + + R_RETURN(lan_discovery.Disconnect()); +} + +Result IUserLocalCommunicationService::Initialize(ClientProcessId aruid) { + LOG_INFO(Service_LDN, "called, process_id={}", aruid.pid); + + const auto network_interface = Network::GetSelectedNetworkInterface(); + R_UNLESS(network_interface, ResultAirplaneModeEnabled); + + if (auto room_member = room_network.GetRoomMember().lock()) { + ldn_packet_received = room_member->BindOnLdnPacketReceived( + [this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); }); + } else { + LOG_ERROR(Service_LDN, "Couldn't bind callback!"); + R_RETURN(ResultAirplaneModeEnabled); + } + + lan_discovery.Initialize([&]() { OnEventFired(); }); + is_initialized = true; + R_SUCCEED(); +} + +Result IUserLocalCommunicationService::Finalize() { + LOG_INFO(Service_LDN, "called"); + if (auto room_member = room_network.GetRoomMember().lock()) { + room_member->Unbind(ldn_packet_received); + } + + is_initialized = false; + + R_RETURN(lan_discovery.Finalize()); +} + +Result IUserLocalCommunicationService::Initialize2(u32 version, ClientProcessId process_id) { + LOG_INFO(Service_LDN, "called, version={}, process_id={}", version, process_id.pid); + R_RETURN(Initialize(process_id)); +} + +void IUserLocalCommunicationService::OnLDNPacketReceived(const Network::LDNPacket& packet) { + lan_discovery.ReceivePacket(packet); +} + +void IUserLocalCommunicationService::OnEventFired() { + state_change_event->Signal(); +} + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/user_local_communication_service.h b/src/core/hle/service/ldn/user_local_communication_service.h new file mode 100644 index 0000000000..6698d10d22 --- /dev/null +++ b/src/core/hle/service/ldn/user_local_communication_service.h @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/ldn/lan_discovery.h" +#include "core/hle/service/ldn/ldn_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Network { +class RoomNetwork; +} + +namespace Service::LDN { + +class IUserLocalCommunicationService final + : public ServiceFramework { +public: + explicit IUserLocalCommunicationService(Core::System& system_); + ~IUserLocalCommunicationService() override; + +private: + Result GetState(Out out_state); + + Result GetNetworkInfo(OutLargeData out_network_info); + + Result GetIpv4Address(Out out_current_address, Out out_subnet_mask); + + Result GetDisconnectReason(Out out_disconnect_reason); + + Result GetSecurityParameter(Out out_security_parameter); + + Result GetNetworkConfig(Out out_network_config); + + Result AttachStateChangeEvent(OutCopyHandle out_event); + + Result GetNetworkInfoLatestUpdate( + OutLargeData out_network_info, + OutArray out_node_latest_update); + + Result Scan(Out network_count, WifiChannel channel, const ScanFilter& scan_filter, + OutArray out_network_info); + + Result ScanPrivate(Out network_count, WifiChannel channel, const ScanFilter& scan_filter, + OutArray out_network_info); + + Result SetWirelessControllerRestriction(WirelessControllerRestriction wireless_restriction); + + Result OpenAccessPoint(); + + Result CloseAccessPoint(); + + Result CreateNetwork(const CreateNetworkConfig& create_network_Config); + + Result CreateNetworkPrivate(const CreateNetworkConfigPrivate& create_network_Config, + InArray address_list); + + Result DestroyNetwork(); + + Result SetAdvertiseData(InBuffer buffer_data); + + Result SetStationAcceptPolicy(AcceptPolicy accept_policy); + + Result AddAcceptFilterEntry(MacAddress mac_address); + + Result OpenStation(); + + Result CloseStation(); + + Result Connect(const ConnectNetworkData& connect_data, + InLargeData network_info); + + Result Disconnect(); + + Result Initialize(ClientProcessId aruid); + + Result Finalize(); + + Result Initialize2(u32 version, ClientProcessId aruid); + +private: + /// Callback to parse and handle a received LDN packet. + void OnLDNPacketReceived(const Network::LDNPacket& packet); + void OnEventFired(); + + KernelHelpers::ServiceContext service_context; + Kernel::KEvent* state_change_event; + Network::RoomNetwork& room_network; + LANDiscovery lan_discovery; + + // Callback identifier for the OnLDNPacketReceived event. + Network::RoomMember::CallbackHandle ldn_packet_received; + + bool is_initialized{}; +}; + +} // namespace Service::LDN