Merge pull request #12974 from german77/ldn-interface

service: ldn: Migrate and refractor service to new IPC
This commit is contained in:
liamwhite 2024-02-13 08:18:31 -05:00 committed by GitHub
commit 95d96cfe66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 911 additions and 779 deletions

View File

@ -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

View File

@ -85,15 +85,14 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const {
}
Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network,
std::vector<NodeLatestUpdate>& out_updates,
std::size_t buffer_count) {
if (buffer_count > NodeCountMax) {
std::span<NodeLatestUpdate> 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<NetworkInfo>& networks, u16& count,
Result LANDiscovery::Scan(std::span<NetworkInfo> 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<NetworkInfo>& 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<s16>(out_networks.size())) {
break;
}
@ -159,7 +151,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
}
}
networks[count++] = info;
out_networks[out_count++] = info;
}
return ResultSuccess;

View File

@ -54,11 +54,10 @@ public:
void SetState(State new_state);
Result GetNetworkInfo(NetworkInfo& out_network) const;
Result GetNetworkInfo(NetworkInfo& out_network, std::vector<NodeLatestUpdate>& out_updates,
std::size_t buffer_count);
Result GetNetworkInfo(NetworkInfo& out_network, std::span<NodeLatestUpdate> out_updates);
DisconnectReason GetDisconnectReason() const;
Result Scan(std::vector<NetworkInfo>& networks, u16& count, const ScanFilter& filter);
Result Scan(std::span<NetworkInfo> out_networks, s16& out_count, const ScanFilter& filter);
Result SetAdvertiseData(std::span<const u8> data);
Result OpenAccessPoint();

View File

@ -1,36 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <memory>
#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<IMonitorService> {
class IMonitorServiceCreator final : public ServiceFramework<IMonitorServiceCreator> {
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<LDNM> {
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<IMonitorService> out_interface) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IMonitorService>(system);
*out_interface = std::make_shared<IMonitorService>(system);
R_SUCCEED();
}
};
class ISystemLocalCommunicationService final
: public ServiceFramework<ISystemLocalCommunicationService> {
class ISystemServiceCreator final : public ServiceFramework<ISystemServiceCreator> {
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<IUserLocalCommunicationService> {
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<NetworkInfo>(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<SecurityParameter>(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<NetworkConfig>(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<NodeLatestUpdate>(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<NodeLatestUpdate> 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<WifiChannel>()};
const auto scan_filter{rp.PopRaw<ScanFilter>()};
const std::size_t network_info_size = ctx.GetWriteBufferNumElements<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> 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<u32>(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<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(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<Parameters>()};
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<u16>(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<Network::LDNPacket> ldn_packet_received;
bool is_initialized{};
};
class LDNS final : public ServiceFramework<LDNS> {
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<ISystemLocalCommunicationService> out_interface) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemLocalCommunicationService>(system);
*out_interface = std::make_shared<ISystemLocalCommunicationService>(system);
R_SUCCEED();
}
};
class LDNU final : public ServiceFramework<LDNU> {
class IUserServiceCreator final : public ServiceFramework<IUserServiceCreator> {
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<IUserLocalCommunicationService> out_interface) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IUserLocalCommunicationService>(system);
*out_interface = std::make_shared<IUserLocalCommunicationService>(system);
R_SUCCEED();
}
};
class INetworkService final : public ServiceFramework<INetworkService> {
class ISfServiceCreator final : public ServiceFramework<ISfServiceCreator> {
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<INetworkServiceMonitor> {
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<LP2PAPP> {
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<u64>();
const u32 input = rp.Pop<u32>();
private:
Result CreateNetworkService(OutInterface<ISfService> 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<INetworkService>(system);
*out_interface = std::make_shared<ISfService>(system);
R_SUCCEED();
}
void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
Result CreateNetworkServiceMonitor(OutInterface<ISfServiceMonitor> 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<INetworkServiceMonitor>(system);
*out_interface = std::make_shared<ISfServiceMonitor>(system);
R_SUCCEED();
}
bool is_system{};
};
class LP2PSYS final : public ServiceFramework<LP2PSYS> {
class ISfMonitorServiceCreator final : public ServiceFramework<ISfMonitorServiceCreator> {
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<u64>();
const u32 input = rp.Pop<u32>();
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INetworkService>(system);
}
void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INetworkServiceMonitor>(system);
}
};
class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
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<u8, 0x200> info;
};
GroupInfo group_info{};
ctx.WriteBuffer(group_info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
class LP2PM final : public ServiceFramework<LP2PM> {
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<u64>();
Result CreateMonitorService(OutInterface<ISfMonitorService> 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<ISfMonitorService>(system);
*out_interface = std::make_shared<ISfMonitorService>(system);
R_SUCCEED();
}
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system));
server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system));
server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system));
server_manager->RegisterNamedService("ldn:m", std::make_shared<IMonitorServiceCreator>(system));
server_manager->RegisterNamedService("ldn:s", std::make_shared<ISystemServiceCreator>(system));
server_manager->RegisterNamedService("ldn:u", std::make_shared<IUserServiceCreator>(system));
server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system));
server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system));
server_manager->RegisterNamedService("lp2p:m", std::make_shared<LP2PM>(system));
server_manager->RegisterNamedService(
"lp2p:app", std::make_shared<ISfServiceCreator>(system, false, "lp2p:app"));
server_manager->RegisterNamedService(
"lp2p:sys", std::make_shared<ISfServiceCreator>(system, true, "lp2p:sys"));
server_manager->RegisterNamedService("lp2p:m",
std::make_shared<ISfMonitorServiceCreator>(system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -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;
}

View File

@ -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<char, SsidLengthMax + 1> raw{};
u8 length;
std::array<char, SsidLengthMax + 1> raw;
Ssid() = default;
constexpr explicit Ssid(std::string_view data) {
length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
raw = {};
data.copy(raw.data(), length);
raw[length] = 0;
}
@ -181,7 +194,7 @@ using Ipv4Address = std::array<u8, 4>;
static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
struct MacAddress {
std::array<u8, 6> raw{};
std::array<u8, 6> 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<u8, UserNameBytesMax + 1> 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<NodeInfo, NodeCountMax> nodes;
INSERT_PADDING_BYTES(0x2); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
u16 advertise_data_size;
std::array<u8, AdvertiseDataSizeMax> 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>, "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<u8, 0x200> 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

View File

@ -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<State> 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

View File

@ -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<IMonitorService> {
public:
explicit IMonitorService(Core::System& system_);
~IMonitorService() override;
private:
Result GetStateForMonitor(Out<State> out_state);
Result InitializeMonitor();
State state{State::None};
};
} // namespace Service::LDN

View File

@ -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<u32> out_value) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_value = 0;
R_SUCCEED();
}
Result ISfMonitorService::GetGroupInfo(
OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_group_info = GroupInfo{};
R_SUCCEED();
}
} // namespace Service::LDN

View File

@ -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<ISfMonitorService> {
public:
explicit ISfMonitorService(Core::System& system_);
~ISfMonitorService() override;
private:
Result Initialize(Out<u32> out_value);
Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
};
} // namespace Service::LDN

View File

@ -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

View File

@ -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<ISfService> {
public:
explicit ISfService(Core::System& system_);
~ISfService() override;
};
} // namespace Service::LDN

View File

@ -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<u32> out_value) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_value = 0;
R_SUCCEED();
}
Result ISfServiceMonitor::GetGroupInfo(
OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_group_info = GroupInfo{};
R_SUCCEED();
}
} // namespace Service::LDN

View File

@ -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<ISfServiceMonitor> {
public:
explicit ISfServiceMonitor(Core::System& system_);
~ISfServiceMonitor() override;
private:
Result Initialize(Out<u32> out_value);
Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
};
} // namespace Service::LDN

View File

@ -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

View File

@ -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<ISystemLocalCommunicationService> {
public:
explicit ISystemLocalCommunicationService(Core::System& system_);
~ISystemLocalCommunicationService() override;
private:
Result InitializeSystem2();
};
} // namespace Service::LDN

View File

@ -0,0 +1,320 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <memory>
#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<State> 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<NetworkInfo, BufferAttr_HipcPointer> out_network_info) {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info));
}
Result IUserLocalCommunicationService::GetIpv4Address(Out<Ipv4Address> out_current_address,
Out<Ipv4Address> 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<DisconnectReason> out_disconnect_reason) {
LOG_INFO(Service_LDN, "called");
*out_disconnect_reason = lan_discovery.GetDisconnectReason();
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetSecurityParameter(
Out<SecurityParameter> 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<NetworkConfig> 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<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_LDN, "called");
*out_event = &state_change_event->GetReadableEvent();
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> 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<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> 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<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> 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<AddressEntry, BufferAttr_HipcPointer> 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<BufferAttr_HipcAutoSelect> 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<NetworkInfo, BufferAttr_HipcPointer> 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<u16>(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

View File

@ -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<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_);
~IUserLocalCommunicationService() override;
private:
Result GetState(Out<State> out_state);
Result GetNetworkInfo(OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info);
Result GetIpv4Address(Out<Ipv4Address> out_current_address, Out<Ipv4Address> out_subnet_mask);
Result GetDisconnectReason(Out<DisconnectReason> out_disconnect_reason);
Result GetSecurityParameter(Out<SecurityParameter> out_security_parameter);
Result GetNetworkConfig(Out<NetworkConfig> out_network_config);
Result AttachStateChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetNetworkInfoLatestUpdate(
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update);
Result Scan(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
Result ScanPrivate(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> 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<AddressEntry, BufferAttr_HipcPointer> address_list);
Result DestroyNetwork();
Result SetAdvertiseData(InBuffer<BufferAttr_HipcAutoSelect> buffer_data);
Result SetStationAcceptPolicy(AcceptPolicy accept_policy);
Result AddAcceptFilterEntry(MacAddress mac_address);
Result OpenStation();
Result CloseStation();
Result Connect(const ConnectNetworkData& connect_data,
InLargeData<NetworkInfo, BufferAttr_HipcPointer> 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<Network::LDNPacket> ldn_packet_received;
bool is_initialized{};
};
} // namespace Service::LDN