diff options
Diffstat (limited to 'src/core/hle/service/ldn/ldn.cpp')
-rw-r--r-- | src/core/hle/service/ldn/ldn.cpp | 227 |
1 files changed, 128 insertions, 99 deletions
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index c11daff54..ea3e7e55a 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -4,11 +4,13 @@ #include <memory> #include "core/core.h" +#include "core/hle/service/ldn/lan_discovery.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/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 @@ -105,13 +107,13 @@ class IUserLocalCommunicationService final public: explicit IUserLocalCommunicationService(Core::System& system_) : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew}, - service_context{system, "IUserLocalCommunicationService"}, room_network{ - system_.GetRoomNetwork()} { + 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, nullptr, "GetIpv4Address"}, + {2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"}, {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"}, {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"}, {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"}, @@ -119,7 +121,7 @@ public: {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"}, {102, &IUserLocalCommunicationService::Scan, "Scan"}, {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"}, - {104, nullptr, "SetWirelessControllerRestriction"}, + {104, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"}, {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, @@ -148,16 +150,30 @@ public: } ~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->GetWritableEvent().Signal(); } void GetState(Kernel::HLERequestContext& ctx) { State state = State::Error; - LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state); + + if (is_initialized) { + state = lan_discovery.GetState(); + } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -175,7 +191,7 @@ public: } NetworkInfo network_info{}; - const auto rc = ResultSuccess; + 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}; @@ -183,28 +199,50 @@ public: return; } - LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", - network_info.common.ssid.GetStringValue(), network_info.ldn.node_count); - ctx.WriteBuffer<NetworkInfo>(network_info); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(rc); + rb.Push(ResultSuccess); } - void GetDisconnectReason(Kernel::HLERequestContext& ctx) { - const auto disconnect_reason = DisconnectReason::None; + void GetIpv4Address(Kernel::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; + } - LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason); + 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(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(disconnect_reason); + rb.PushEnum(lan_discovery.GetDisconnectReason()); } void GetSecurityParameter(Kernel::HLERequestContext& ctx) { SecurityParameter security_parameter{}; NetworkInfo info{}; - const Result rc = ResultSuccess; + const Result rc = lan_discovery.GetNetworkInfo(info); if (rc.IsError()) { LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); @@ -217,8 +255,6 @@ public: 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); @@ -227,7 +263,7 @@ public: void GetNetworkConfig(Kernel::HLERequestContext& ctx) { NetworkConfig config{}; NetworkInfo info{}; - const Result rc = ResultSuccess; + const Result rc = lan_discovery.GetNetworkInfo(info); if (rc.IsError()) { LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw); @@ -241,12 +277,6 @@ public: 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); @@ -265,17 +295,17 @@ public: 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, + 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; + NetworkInfo info{}; std::vector<NodeLatestUpdate> latest_update(node_buffer_count); - const auto rc = ResultSuccess; + 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}; @@ -283,9 +313,6 @@ public: 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); @@ -317,92 +344,78 @@ public: u16 count = 0; std::vector<NetworkInfo> network_infos(network_info_size); + Result rc = lan_discovery.Scan(network_infos, count, scan_filter); - LOG_WARNING(Service_LDN, - "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}", - channel, scan_filter.flag, scan_filter.network_type); + 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(ResultSuccess); + rb.Push(rc); rb.Push<u32>(count); } - void OpenAccessPoint(Kernel::HLERequestContext& ctx) { + void SetWirelessControllerRestriction(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_LDN, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } + void OpenAccessPoint(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_LDN, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(lan_discovery.OpenAccessPoint()); + } + void CloseAccessPoint(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + LOG_INFO(Service_LDN, "called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.CloseAccessPoint()); } void CreateNetwork(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - SecurityConfig security_config; - UserConfig user_config; - INSERT_PADDING_WORDS_NOINIT(1); - NetworkConfig network_config; - }; - static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size."); + LOG_INFO(Service_LDN, "called"); - const auto parameters{rp.PopRaw<Parameters>()}; + CreateNetworkImpl(ctx); + } - LOG_WARNING(Service_LDN, - "(STUBBED) called, passphrase_size={}, security_mode={}, " - "local_communication_version={}", - parameters.security_config.passphrase_size, - parameters.security_config.security_mode, - parameters.network_config.local_communication_version); + void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_LDN, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + CreateNetworkImpl(ctx, true); } - void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { + void CreateNetworkImpl(Kernel::HLERequestContext& ctx, bool is_private = false) { IPC::RequestParser rp{ctx}; - struct Parameters { - SecurityConfig security_config; - SecurityParameter security_parameter; - UserConfig user_config; - NetworkConfig network_config; - }; - static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - LOG_WARNING(Service_LDN, - "(STUBBED) called, passphrase_size={}, security_mode={}, " - "local_communication_version={}", - parameters.security_config.passphrase_size, - parameters.security_config.security_mode, - parameters.network_config.local_communication_version); + 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); + rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config)); } void DestroyNetwork(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + LOG_INFO(Service_LDN, "called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.DestroyNetwork()); } void 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); + rb.Push(lan_discovery.SetAdvertiseData(read_buffer)); } void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) { @@ -420,17 +433,17 @@ public: } void OpenStation(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + LOG_INFO(Service_LDN, "called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.OpenStation()); } void CloseStation(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + LOG_INFO(Service_LDN, "called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.CloseStation()); } void Connect(Kernel::HLERequestContext& ctx) { @@ -445,16 +458,13 @@ public: const auto parameters{rp.PopRaw<Parameters>()}; - LOG_WARNING(Service_LDN, - "(STUBBED) called, passphrase_size={}, security_mode={}, " - "local_communication_version={}", - parameters.security_config.passphrase_size, - parameters.security_config.security_mode, - parameters.local_communication_version); + 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 std::vector<u8> read_buffer = ctx.ReadBuffer(); - NetworkInfo network_info{}; - if (read_buffer.size() != sizeof(NetworkInfo)) { LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); IPC::ResponseBuilder rb{ctx, 2}; @@ -462,40 +472,47 @@ public: return; } + NetworkInfo network_info{}; std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.Connect(network_info, parameters.user_config, + static_cast<u16>(parameters.local_communication_version))); } void Disconnect(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + LOG_INFO(Service_LDN, "called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.Disconnect()); } - void Initialize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + void Initialize(Kernel::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(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); + if (auto room_member = room_network.GetRoomMember().lock()) { + room_member->Unbind(ldn_packet_received); + } is_initialized = false; IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(lan_discovery.Finalize()); } void 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); @@ -508,14 +525,26 @@ public: 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; - // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented - return ResultAirplaneModeEnabled; + 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<Network::LDNPacket> ldn_packet_received; bool is_initialized{}; }; |