feat(service/nifm): implement missing network interface services

Specifically:
- Add 11 missing methods to IGeneralService including network profile, scan, and WoWL functionality
- Implement 14 missing methods for IRequest class
- Complete implementation of IScanRequest class with all 5 required methods
- Update copyright notices to include citron Emulator Project

These additions should prevent games from crashing when accessing previously unimplemented network interface functions.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-05-11 18:29:55 +10:00
parent 54f2b4442e
commit 62f40d8b82
2 changed files with 295 additions and 33 deletions

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h" #include "core/core.h"
@@ -159,19 +160,67 @@ constexpr Result ResultNetworkCommunicationDisabled{ErrorModule::NIFM, 1111};
class IScanRequest final : public ServiceFramework<IScanRequest> { class IScanRequest final : public ServiceFramework<IScanRequest> {
public: public:
explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"},
service_context{system_, "IScanRequest"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "Submit"}, {0, &IScanRequest::Submit, "Submit"},
{1, nullptr, "IsProcessing"}, {1, &IScanRequest::IsProcessing, "IsProcessing"},
{2, nullptr, "GetResult"}, {2, &IScanRequest::GetResult, "GetResult"},
{3, nullptr, "GetSystemEventReadableHandle"}, {3, &IScanRequest::GetSystemEventReadableHandle, "GetSystemEventReadableHandle"},
{4, nullptr, "SetChannels"}, {4, &IScanRequest::SetChannels, "SetChannels"},
}; };
// clang-format on // clang-format on
RegisterHandlers(functions); RegisterHandlers(functions);
event = CreateKEvent(service_context, "IScanRequest:Event");
} }
~IScanRequest() override {
service_context.CloseEvent(event);
}
private:
void Submit(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IsProcessing(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(0); // Not processing
}
void GetResult(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetSystemEventReadableHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(event->GetReadableEvent());
}
void SetChannels(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
}; };
class IRequest final : public ServiceFramework<IRequest> { class IRequest final : public ServiceFramework<IRequest> {
@@ -184,26 +233,26 @@ public:
{2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"}, {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"},
{3, &IRequest::Cancel, "Cancel"}, {3, &IRequest::Cancel, "Cancel"},
{4, &IRequest::Submit, "Submit"}, {4, &IRequest::Submit, "Submit"},
{5, nullptr, "SetRequirement"}, {5, &IRequest::SetRequirement, "SetRequirement"},
{6, &IRequest::SetRequirementPreset, "SetRequirementPreset"}, {6, &IRequest::SetRequirementPreset, "SetRequirementPreset"},
{8, nullptr, "SetPriority"}, {8, &IRequest::SetPriority, "SetPriority"},
{9, nullptr, "SetNetworkProfileId"}, {9, &IRequest::SetNetworkProfileId, "SetNetworkProfileId"},
{10, nullptr, "SetRejectable"}, {10, &IRequest::SetRejectable, "SetRejectable"},
{11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"}, {11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"},
{12, nullptr, "SetPersistent"}, {12, &IRequest::SetPersistent, "SetPersistent"},
{13, nullptr, "SetInstant"}, {13, &IRequest::SetInstant, "SetInstant"},
{14, nullptr, "SetSustainable"}, {14, &IRequest::SetSustainable, "SetSustainable"},
{15, nullptr, "SetRawPriority"}, {15, &IRequest::SetRawPriority, "SetRawPriority"},
{16, nullptr, "SetGreedy"}, {16, &IRequest::SetGreedy, "SetGreedy"},
{17, nullptr, "SetSharable"}, {17, &IRequest::SetSharable, "SetSharable"},
{18, nullptr, "SetRequirementByRevision"}, {18, &IRequest::SetRequirementByRevision, "SetRequirementByRevision"},
{19, nullptr, "GetRequirement"}, {19, &IRequest::GetRequirement, "GetRequirement"},
{20, nullptr, "GetRevision"}, {20, &IRequest::GetRevision, "GetRevision"},
{21, &IRequest::GetAppletInfo, "GetAppletInfo"}, {21, &IRequest::GetAppletInfo, "GetAppletInfo"},
{22, nullptr, "GetAdditionalInfo"}, {22, &IRequest::GetAdditionalInfo, "GetAdditionalInfo"},
{23, nullptr, "SetKeptInSleep"}, {23, &IRequest::SetKeptInSleep, "SetKeptInSleep"},
{24, nullptr, "RegisterSocketDescriptor"}, {24, &IRequest::RegisterSocketDescriptor, "RegisterSocketDescriptor"},
{25, nullptr, "UnregisterSocketDescriptor"}, {25, &IRequest::UnregisterSocketDescriptor, "UnregisterSocketDescriptor"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
@@ -313,6 +362,127 @@ private:
event1->Signal(); event1->Signal();
} }
void SetRequirement(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetPriority(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetNetworkProfileId(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetRejectable(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetPersistent(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetInstant(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetSustainable(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetRawPriority(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetGreedy(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetSharable(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetRequirementByRevision(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetRequirement(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetRevision(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(1); // Arbitrary revision number
}
void GetAdditionalInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0); // No additional info
}
void SetKeptInSleep(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void RegisterSocketDescriptor(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void UnregisterSocketDescriptor(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
RequestState state; RequestState state;
@@ -565,6 +735,85 @@ void IGeneralService::IsAnyForegroundRequestAccepted(HLERequestContext& ctx) {
rb.Push<u8>(is_accepted); rb.Push<u8>(is_accepted);
} }
void IGeneralService::GetNetworkProfile(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::SetNetworkProfile(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::GetScanData(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::GetCurrentAccessPoint(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::Shutdown(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::GetAllowedChannels(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0); // No channels explicitly allowed (bitmap of allowed channels)
}
void IGeneralService::SetAcceptableNetworkTypeFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::GetAcceptableNetworkTypeFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(3); // Accept both WiFi and Ethernet
}
void IGeneralService::NotifyConnectionStateChanged(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::SetWowlDelayedWakeTime(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IGeneralService::SetWowlTcpKeepAliveTimeout(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
IGeneralService::IGeneralService(Core::System& system_) IGeneralService::IGeneralService(Core::System& system_)
: ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} { : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
// clang-format off // clang-format off
@@ -575,8 +824,8 @@ IGeneralService::IGeneralService(Core::System& system_)
{5, &IGeneralService::GetCurrentNetworkProfile, "GetCurrentNetworkProfile"}, {5, &IGeneralService::GetCurrentNetworkProfile, "GetCurrentNetworkProfile"},
{6, nullptr, "EnumerateNetworkInterfaces"}, {6, nullptr, "EnumerateNetworkInterfaces"},
{7, nullptr, "EnumerateNetworkProfiles"}, {7, nullptr, "EnumerateNetworkProfiles"},
{8, nullptr, "GetNetworkProfile"}, {8, &IGeneralService::GetNetworkProfile, "GetNetworkProfile"},
{9, nullptr, "SetNetworkProfile"}, {9, &IGeneralService::SetNetworkProfile, "SetNetworkProfile"},
{10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"},
{11, nullptr, "GetScanDataOld"}, {11, nullptr, "GetScanDataOld"},
{12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"}, {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
@@ -602,15 +851,16 @@ IGeneralService::IGeneralService(Core::System& system_)
{32, nullptr, "GetTelemetryInfo"}, {32, nullptr, "GetTelemetryInfo"},
{33, nullptr, "ConfirmSystemAvailability"}, {33, nullptr, "ConfirmSystemAvailability"},
{34, nullptr, "SetBackgroundRequestEnabled"}, {34, nullptr, "SetBackgroundRequestEnabled"},
{35, nullptr, "GetScanData"}, {35, &IGeneralService::GetScanData, "GetScanData"},
{36, nullptr, "GetCurrentAccessPoint"}, {36, &IGeneralService::GetCurrentAccessPoint, "GetCurrentAccessPoint"},
{37, nullptr, "Shutdown"}, {37, &IGeneralService::Shutdown, "Shutdown"},
{38, nullptr, "GetAllowedChannels"}, {38, &IGeneralService::GetAllowedChannels, "GetAllowedChannels"},
{39, nullptr, "NotifyApplicationSuspended"}, {39, nullptr, "NotifyApplicationSuspended"},
{40, nullptr, "SetAcceptableNetworkTypeFlag"}, {40, &IGeneralService::SetAcceptableNetworkTypeFlag, "SetAcceptableNetworkTypeFlag"},
{41, nullptr, "GetAcceptableNetworkTypeFlag"}, {41, &IGeneralService::GetAcceptableNetworkTypeFlag, "GetAcceptableNetworkTypeFlag"},
{42, nullptr, "NotifyConnectionStateChanged"}, {42, &IGeneralService::NotifyConnectionStateChanged, "NotifyConnectionStateChanged"},
{43, nullptr, "SetWowlDelayedWakeTime"}, {43, &IGeneralService::SetWowlDelayedWakeTime, "SetWowlDelayedWakeTime"},
{57, &IGeneralService::SetWowlTcpKeepAliveTimeout, "SetWowlTcpKeepAliveTimeout"},
}; };
// clang-format on // clang-format on

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -36,6 +37,17 @@ private:
void IsEthernetCommunicationEnabled(HLERequestContext& ctx); void IsEthernetCommunicationEnabled(HLERequestContext& ctx);
void IsAnyInternetRequestAccepted(HLERequestContext& ctx); void IsAnyInternetRequestAccepted(HLERequestContext& ctx);
void IsAnyForegroundRequestAccepted(HLERequestContext& ctx); void IsAnyForegroundRequestAccepted(HLERequestContext& ctx);
void SetWowlDelayedWakeTime(HLERequestContext& ctx);
void GetNetworkProfile(HLERequestContext& ctx);
void SetNetworkProfile(HLERequestContext& ctx);
void GetScanData(HLERequestContext& ctx);
void GetCurrentAccessPoint(HLERequestContext& ctx);
void Shutdown(HLERequestContext& ctx);
void GetAllowedChannels(HLERequestContext& ctx);
void SetAcceptableNetworkTypeFlag(HLERequestContext& ctx);
void GetAcceptableNetworkTypeFlag(HLERequestContext& ctx);
void NotifyConnectionStateChanged(HLERequestContext& ctx);
void SetWowlTcpKeepAliveTimeout(HLERequestContext& ctx);
Network::RoomNetwork& network; Network::RoomNetwork& network;
}; };