From 2053ff96fccaf2d8e3472cb370141c6d3252c4e1 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Fri, 9 Feb 2024 23:06:22 -0600 Subject: service: ldn: Migrate and refractor service to new IPC --- .../ldn/user_local_communication_service.cpp | 320 +++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 src/core/hle/service/ldn/user_local_communication_service.cpp (limited to 'src/core/hle/service/ldn/user_local_communication_service.cpp') 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 000000000..f28368962 --- /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 -- cgit v1.2.3