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:
		| @@ -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 | ||||
| @@ -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"} { | ||||
|         // clang-format off | ||||
| 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 | ||||
|     // clang-format on | ||||
|  | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
|     RegisterHandlers(functions); | ||||
|  | ||||
|     void GetState(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||||
|     state_change_event = | ||||
|         service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent"); | ||||
| } | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
| IUserLocalCommunicationService::~IUserLocalCommunicationService() { | ||||
|     service_context.CloseEvent(state_change_event); | ||||
| } | ||||
|  | ||||
|         // Indicate a network error, as we do not actually emulate LDN | ||||
|         rb.Push(static_cast<u32>(State::Error)); | ||||
| void IUserLocalCommunicationService::OnEventFired() { | ||||
|     state_change_event->GetWritableEvent().Signal(); | ||||
| } | ||||
|  | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| void IUserLocalCommunicationService::GetState(Kernel::HLERequestContext& ctx) { | ||||
|     State state = State::Error; | ||||
|     LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state); | ||||
|  | ||||
|     void Initialize2(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_LDN, "called"); | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushEnum(state); | ||||
| } | ||||
|  | ||||
|         is_initialized = true; | ||||
| 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(ERROR_DISABLED); | ||||
|         rb.Push(ResultBadInput); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     enum class State { | ||||
|         None, | ||||
|         Initialized, | ||||
|         AccessPointOpened, | ||||
|         AccessPointCreated, | ||||
|         StationOpened, | ||||
|         StationConnected, | ||||
|         Error, | ||||
|     }; | ||||
|     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; | ||||
|     } | ||||
|  | ||||
|     bool is_initialized{}; | ||||
| }; | ||||
|     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 IUserLocalCommunicationService::Scan(Kernel::HLERequestContext& ctx) { | ||||
|     ScanImpl(ctx); | ||||
| } | ||||
|  | ||||
| void IUserLocalCommunicationService::ScanPrivate(Kernel::HLERequestContext& ctx) { | ||||
|     ScanImpl(ctx, true); | ||||
| } | ||||
|  | ||||
| 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); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										28
									
								
								src/core/hle/service/ldn/ldn_results.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/core/hle/service/ldn/ldn_results.h
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										298
									
								
								src/core/hle/service/ldn/ldn_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								src/core/hle/service/ldn/ldn_types.h
									
									
									
									
									
										Normal 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 | ||||
		Reference in New Issue
	
	Block a user
	 FearlessTobi
					FearlessTobi