aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAc_K <Acoustik666@gmail.com>2019-11-21 13:24:06 +0100
committerThog <me@thog.eu>2019-11-21 13:24:06 +0100
commitcfcc360d0610c66e9b9986f7aab96f79df0da79e (patch)
tree178fb92d9dcbd7f52be430319f44a01149c4bd23
parentee81ab547ee35c4f5f3342a6f1e0d6bbc60500e8 (diff)
ldn: Implement calls of UserLocalCommunicationService (#829)
* ldn: Implement calls of UserLocalCommunicationService - Implement `IUserServiceCreator: CreateUserLocalCommunicationService` according to RE. - Implement `IUserLocalCommunicationService` calls: - Every calls in this interface are layered to `NetworkInterface`. - `GetState` according to RE. - `InitializeOld`, `Initialize` and `Finalize` stubbed with the appropriate result code and some TODO according to RE. - `AttachStateChangeEvent` according to RE. * Fix var name and TODO comments * Fix review
-rw-r--r--Ryujinx.Common/Logging/LogClass.cs1
-rw-r--r--Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Ldn/NetworkInterface.cs59
-rw-r--r--Ryujinx.HLE/HOS/Services/Ldn/ResultCode.cs16
-rw-r--r--Ryujinx.HLE/HOS/Services/Ldn/Types/NetworkState.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs88
6 files changed, 189 insertions, 1 deletions
diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs
index b056f383..43efd8d5 100644
--- a/Ryujinx.Common/Logging/LogClass.cs
+++ b/Ryujinx.Common/Logging/LogClass.cs
@@ -26,6 +26,7 @@ namespace Ryujinx.Common.Logging
ServiceFs,
ServiceHid,
ServiceIrs,
+ ServiceLdn,
ServiceLdr,
ServiceLm,
ServiceMm,
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs
index 052727dd..3fc9ce1c 100644
--- a/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs
+++ b/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs
@@ -1,8 +1,19 @@
-namespace Ryujinx.HLE.HOS.Services.Ldn
+using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator;
+
+namespace Ryujinx.HLE.HOS.Services.Ldn
{
[Service("ldn:u")]
class IUserServiceCreator : IpcService
{
public IUserServiceCreator(ServiceCtx context) { }
+
+ [Command(0)]
+ // CreateUserLocalCommunicationService() -> object<nn::ldn::detail::IUserLocalCommunicationService>
+ public ResultCode CreateUserLocalCommunicationService(ServiceCtx context)
+ {
+ MakeObject(context, new IUserLocalCommunicationService(context));
+
+ return ResultCode.Success;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/NetworkInterface.cs b/Ryujinx.HLE/HOS/Services/Ldn/NetworkInterface.cs
new file mode 100644
index 00000000..f06c6644
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Ldn/NetworkInterface.cs
@@ -0,0 +1,59 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Ldn.Types;
+using System.Net;
+
+namespace Ryujinx.HLE.HOS.Services.Ldn
+{
+ internal class NetworkInterface
+ {
+ public ResultCode NifmState { get; set; }
+ public KEvent StateChangeEvent { get; private set; }
+
+ private NetworkState _state;
+
+ public NetworkInterface(Horizon system)
+ {
+ // TODO(Ac_K): Determine where the internal state is set.
+ NifmState = ResultCode.Success;
+ StateChangeEvent = new KEvent(system);
+
+ _state = NetworkState.None;
+ }
+
+ public ResultCode Initialize(int unknown, int version, IPAddress ipv4Address, IPAddress subnetMaskAddress)
+ {
+ // TODO(Ac_K): Call nn::nifm::InitializeSystem().
+ // If the call failed, it returns the result code.
+ // If the call succeed, it signal and clear an event then start a new thread named nn.ldn.NetworkInterfaceMonitor.
+
+ Logger.PrintStub(LogClass.ServiceLdn, new { version });
+
+ // NOTE: Since we don't support ldn for now, we can return this following result code to make it disabled.
+ return ResultCode.DeviceDisabled;
+ }
+
+ public ResultCode GetState(out NetworkState state)
+ {
+ // Return ResultCode.InvalidArgument if _state is null, doesn't occur in our case.
+
+ state = _state;
+
+ return ResultCode.Success;
+ }
+
+ public ResultCode Finalize()
+ {
+ // TODO(Ac_K): Finalize nifm service then kill the thread named nn.ldn.NetworkInterfaceMonitor.
+
+ _state = NetworkState.None;
+
+ StateChangeEvent.WritableEvent.Signal();
+ StateChangeEvent.WritableEvent.Clear();
+
+ Logger.PrintStub(LogClass.ServiceLdn);
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Ldn/ResultCode.cs
new file mode 100644
index 00000000..0c9f6209
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Ldn/ResultCode.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.HLE.HOS.Services.Ldn
+{
+ enum ResultCode
+ {
+ ModuleId = 203,
+ ErrorCodeShift = 9,
+
+ Success = 0,
+
+ DeviceDisabled = (22 << ErrorCodeShift) | ModuleId,
+ InvalidState = (32 << ErrorCodeShift) | ModuleId,
+ Unknown1 = (48 << ErrorCodeShift) | ModuleId,
+ InvalidArgument = (96 << ErrorCodeShift) | ModuleId,
+ InvalidOjbect = (97 << ErrorCodeShift) | ModuleId,
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/Types/NetworkState.cs b/Ryujinx.HLE/HOS/Services/Ldn/Types/NetworkState.cs
new file mode 100644
index 00000000..6ac20483
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Ldn/Types/NetworkState.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.HLE.HOS.Services.Ldn.Types
+{
+ enum NetworkState
+ {
+ None,
+ Initialized,
+ AccessPoint,
+ AccessPointCreated,
+ Station,
+ StationConnected,
+ Error
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs b/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
new file mode 100644
index 00000000..b1ae2d6e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
@@ -0,0 +1,88 @@
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Services.Ldn.Types;
+using System;
+using System.Net;
+
+namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
+{
+ class IUserLocalCommunicationService : IpcService
+ {
+ // TODO(Ac_K): Determine what the hardcoded unknown value is.
+ private const int UnknownValue = 90;
+
+ private NetworkInterface _networkInterface;
+
+ private int _stateChangeEventHandle = 0;
+
+ public IUserLocalCommunicationService(ServiceCtx context)
+ {
+ _networkInterface = new NetworkInterface(context.Device.System);
+ }
+
+ [Command(0)]
+ // GetState() -> s32 state
+ public ResultCode GetState(ServiceCtx context)
+ {
+ if (_networkInterface.NifmState != ResultCode.Success)
+ {
+ context.ResponseData.Write((int)NetworkState.Error);
+
+ return ResultCode.Success;
+ }
+
+ ResultCode result = _networkInterface.GetState(out NetworkState state);
+
+ if (result == ResultCode.Success)
+ {
+ context.ResponseData.Write((int)state);
+ }
+
+ return result;
+ }
+
+ [Command(100)]
+ // AttachStateChangeEvent() -> handle<copy>
+ public ResultCode AttachStateChangeEvent(ServiceCtx context)
+ {
+ if (_stateChangeEventHandle == 0)
+ {
+ if (context.Process.HandleTable.GenerateHandle(_networkInterface.StateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangeEventHandle);
+
+ // Return ResultCode.InvalidArgument if handle is null, doesn't occur in our case since we already throw an Exception.
+
+ return ResultCode.Success;
+ }
+
+ [Command(400)]
+ // InitializeOld(u64, pid)
+ public ResultCode InitializeOld(ServiceCtx context)
+ {
+ return _networkInterface.Initialize(UnknownValue, 0, null, null);
+ }
+
+ [Command(401)]
+ // Finalize()
+ public ResultCode Finalize(ServiceCtx context)
+ {
+ return _networkInterface.Finalize();
+ }
+
+ [Command(402)] // 7.0.0+
+ // Initialize(u64 ip_addresses, u64, pid)
+ public ResultCode Initialize(ServiceCtx context)
+ {
+ // TODO(Ac_K): Determine what addresses are.
+ IPAddress unknownAddress1 = new IPAddress(context.RequestData.ReadUInt32());
+ IPAddress unknownAddress2 = new IPAddress(context.RequestData.ReadUInt32());
+
+ return _networkInterface.Initialize(UnknownValue, version: 1, unknownAddress1, unknownAddress2);
+ }
+ }
+} \ No newline at end of file