aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Services/Nifm
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.HLE/HOS/Services/Nifm
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Services/Nifm')
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs30
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/ResultCode.cs15
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs30
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs8
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs203
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs142
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/DnsSetting.cs31
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionState.cs11
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionStatus.cs12
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionType.cs9
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs24
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpSettingData.cs13
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpV4Address.cs24
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/NetworkProfileData.cs17
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/ProxySetting.cs27
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/WirelessSettingData.cs15
16 files changed, 611 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs
new file mode 100644
index 00000000..d6a4a29f
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs
@@ -0,0 +1,30 @@
+using Ryujinx.HLE.HOS.Services.Nifm.StaticService;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm
+{
+ [Service("nifm:a")] // Max sessions: 2
+ [Service("nifm:s")] // Max sessions: 16
+ [Service("nifm:u")] // Max sessions: 5
+ class IStaticService : IpcService
+ {
+ public IStaticService(ServiceCtx context) { }
+
+ [CommandCmif(4)]
+ // CreateGeneralServiceOld() -> object<nn::nifm::detail::IGeneralService>
+ public ResultCode CreateGeneralServiceOld(ServiceCtx context)
+ {
+ MakeObject(context, new IGeneralService());
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(5)] // 3.0.0+
+ // CreateGeneralService(u64, pid) -> object<nn::nifm::detail::IGeneralService>
+ public ResultCode CreateGeneralService(ServiceCtx context)
+ {
+ MakeObject(context, new IGeneralService());
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/ResultCode.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/ResultCode.cs
new file mode 100644
index 00000000..73cadb11
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/ResultCode.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.HLE.HOS.Services.Nifm
+{
+ enum ResultCode
+ {
+ ModuleId = 110,
+ ErrorCodeShift = 9,
+
+ Success = 0,
+
+ Unknown112 = (112 << ErrorCodeShift) | ModuleId, // IRequest::GetResult
+ Unknown180 = (180 << ErrorCodeShift) | ModuleId, // IRequest::GetAppletInfo
+ NoInternetConnection = (300 << ErrorCodeShift) | ModuleId,
+ ObjectIsNull = (350 << ErrorCodeShift) | ModuleId
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs
new file mode 100644
index 00000000..bbb218bb
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService
+{
+ static class GeneralServiceManager
+ {
+ private static List<GeneralServiceDetail> _generalServices = new List<GeneralServiceDetail>();
+
+ public static int Count
+ {
+ get => _generalServices.Count;
+ }
+
+ public static void Add(GeneralServiceDetail generalServiceDetail)
+ {
+ _generalServices.Add(generalServiceDetail);
+ }
+
+ public static void Remove(int index)
+ {
+ _generalServices.RemoveAt(index);
+ }
+
+ public static GeneralServiceDetail Get(int clientId)
+ {
+ return _generalServices.First(item => item.ClientId == clientId);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs
new file mode 100644
index 00000000..3cf55345
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService
+{
+ class GeneralServiceDetail
+ {
+ public int ClientId;
+ public bool IsAnyInternetRequestAccepted;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
new file mode 100644
index 00000000..e9712e92
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
@@ -0,0 +1,203 @@
+using Ryujinx.Common;
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService;
+using Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types;
+using System;
+using System.Net.NetworkInformation;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
+{
+ class IGeneralService : DisposableIpcService
+ {
+ private GeneralServiceDetail _generalServiceDetail;
+
+ private IPInterfaceProperties _targetPropertiesCache = null;
+ private UnicastIPAddressInformation _targetAddressInfoCache = null;
+ private string _cacheChosenInterface = null;
+
+ public IGeneralService()
+ {
+ _generalServiceDetail = new GeneralServiceDetail
+ {
+ ClientId = GeneralServiceManager.Count,
+ IsAnyInternetRequestAccepted = true // NOTE: Why not accept any internet request?
+ };
+
+ NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(LocalInterfaceCacheHandler);
+
+ GeneralServiceManager.Add(_generalServiceDetail);
+ }
+
+ [CommandCmif(1)]
+ // GetClientId() -> buffer<nn::nifm::ClientId, 0x1a, 4>
+ public ResultCode GetClientId(ServiceCtx context)
+ {
+ ulong position = context.Request.RecvListBuff[0].Position;
+
+ context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(sizeof(int));
+
+ context.Memory.Write(position, _generalServiceDetail.ClientId);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(4)]
+ // CreateRequest(u32 version) -> object<nn::nifm::detail::IRequest>
+ public ResultCode CreateRequest(ServiceCtx context)
+ {
+ uint version = context.RequestData.ReadUInt32();
+
+ MakeObject(context, new IRequest(context.Device.System, version));
+
+ // Doesn't occur in our case.
+ // return ResultCode.ObjectIsNull;
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { version });
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(5)]
+ // GetCurrentNetworkProfile() -> buffer<nn::nifm::detail::sf::NetworkProfileData, 0x1a, 0x17c>
+ public ResultCode GetCurrentNetworkProfile(ServiceCtx context)
+ {
+ ulong networkProfileDataPosition = context.Request.RecvListBuff[0].Position;
+
+ (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface(context);
+
+ if (interfaceProperties == null || unicastAddress == null)
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
+
+ context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<NetworkProfileData>());
+
+ NetworkProfileData networkProfile = new NetworkProfileData
+ {
+ Uuid = UInt128Utils.CreateRandom()
+ };
+
+ networkProfile.IpSettingData.IpAddressSetting = new IpAddressSetting(interfaceProperties, unicastAddress);
+ networkProfile.IpSettingData.DnsSetting = new DnsSetting(interfaceProperties);
+
+ "RyujinxNetwork"u8.CopyTo(networkProfile.Name.AsSpan());
+
+ context.Memory.Write(networkProfileDataPosition, networkProfile);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(12)]
+ // GetCurrentIpAddress() -> nn::nifm::IpV4Address
+ public ResultCode GetCurrentIpAddress(ServiceCtx context)
+ {
+ (_, UnicastIPAddressInformation unicastAddress) = GetLocalInterface(context);
+
+ if (unicastAddress == null)
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ context.ResponseData.WriteStruct(new IpV4Address(unicastAddress.Address));
+
+ Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(15)]
+ // GetCurrentIpConfigInfo() -> (nn::nifm::IpAddressSetting, nn::nifm::DnsSetting)
+ public ResultCode GetCurrentIpConfigInfo(ServiceCtx context)
+ {
+ (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface(context);
+
+ if (interfaceProperties == null || unicastAddress == null)
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
+
+ context.ResponseData.WriteStruct(new IpAddressSetting(interfaceProperties, unicastAddress));
+ context.ResponseData.WriteStruct(new DnsSetting(interfaceProperties));
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(18)]
+ // GetInternetConnectionStatus() -> nn::nifm::detail::sf::InternetConnectionStatus
+ public ResultCode GetInternetConnectionStatus(ServiceCtx context)
+ {
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ InternetConnectionStatus internetConnectionStatus = new InternetConnectionStatus
+ {
+ Type = InternetConnectionType.WiFi,
+ WifiStrength = 3,
+ State = InternetConnectionState.Connected,
+ };
+
+ context.ResponseData.WriteStruct(internetConnectionStatus);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(21)]
+ // IsAnyInternetRequestAccepted(buffer<nn::nifm::ClientId, 0x19, 4>) -> bool
+ public ResultCode IsAnyInternetRequestAccepted(ServiceCtx context)
+ {
+ ulong position = context.Request.PtrBuff[0].Position;
+ ulong size = context.Request.PtrBuff[0].Size;
+
+ int clientId = context.Memory.Read<int>(position);
+
+ context.ResponseData.Write(GeneralServiceManager.Get(clientId).IsAnyInternetRequestAccepted);
+
+ return ResultCode.Success;
+ }
+
+ private (IPInterfaceProperties, UnicastIPAddressInformation) GetLocalInterface(ServiceCtx context)
+ {
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ {
+ return (null, null);
+ }
+
+ string chosenInterface = context.Device.Configuration.MultiplayerLanInterfaceId;
+
+ if (_targetPropertiesCache == null || _targetAddressInfoCache == null || _cacheChosenInterface != chosenInterface)
+ {
+ _cacheChosenInterface = chosenInterface;
+
+ (_targetPropertiesCache, _targetAddressInfoCache) = NetworkHelpers.GetLocalInterface(chosenInterface);
+ }
+
+ return (_targetPropertiesCache, _targetAddressInfoCache);
+ }
+
+ private void LocalInterfaceCacheHandler(object sender, EventArgs e)
+ {
+ Logger.Info?.Print(LogClass.ServiceNifm, $"NetworkAddress changed, invalidating cached data.");
+
+ _targetPropertiesCache = null;
+ _targetAddressInfoCache = null;
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ if (isDisposing)
+ {
+ NetworkChange.NetworkAddressChanged -= LocalInterfaceCacheHandler;
+
+ GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
new file mode 100644
index 00000000..87aad30b
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
@@ -0,0 +1,142 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
+{
+ class IRequest : IpcService
+ {
+ private enum RequestState
+ {
+ Error = 1,
+ OnHold = 2,
+ Available = 3
+ }
+
+ private KEvent _event0;
+ private KEvent _event1;
+
+ private int _event0Handle;
+ private int _event1Handle;
+
+ private uint _version;
+
+ public IRequest(Horizon system, uint version)
+ {
+ _event0 = new KEvent(system.KernelContext);
+ _event1 = new KEvent(system.KernelContext);
+
+ _version = version;
+ }
+
+ [CommandCmif(0)]
+ // GetRequestState() -> u32
+ public ResultCode GetRequestState(ServiceCtx context)
+ {
+ RequestState requestState = context.Device.Configuration.EnableInternetAccess
+ ? RequestState.Available
+ : RequestState.Error;
+
+ context.ResponseData.Write((int)requestState);
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(1)]
+ // GetResult()
+ public ResultCode GetResult(ServiceCtx context)
+ {
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm);
+
+ return GetResultImpl();
+ }
+
+ private ResultCode GetResultImpl()
+ {
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(2)]
+ // GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
+ public ResultCode GetSystemEventReadableHandles(ServiceCtx context)
+ {
+ if (_event0Handle == 0)
+ {
+ if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != Result.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+ }
+
+ if (_event1Handle == 0)
+ {
+ if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != Result.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_event0Handle, _event1Handle);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(3)]
+ // Cancel()
+ public ResultCode Cancel(ServiceCtx context)
+ {
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(4)]
+ // Submit()
+ public ResultCode Submit(ServiceCtx context)
+ {
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(11)]
+ // SetConnectionConfirmationOption(i8)
+ public ResultCode SetConnectionConfirmationOption(ServiceCtx context)
+ {
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(21)]
+ // GetAppletInfo(u32) -> (u32, u32, u32, buffer<bytes, 6>)
+ public ResultCode GetAppletInfo(ServiceCtx context)
+ {
+ uint themeColor = context.RequestData.ReadUInt32();
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm);
+
+ ResultCode result = GetResultImpl();
+
+ if (result == ResultCode.Success || (ResultCode)((int)result & 0x3fffff) == ResultCode.Unknown112)
+ {
+ return ResultCode.Unknown180;
+ }
+
+ // Returns appletId, libraryAppletMode, outSize and a buffer.
+ // Returned applet ids- (0x19, 0xf, 0xe)
+ // libraryAppletMode seems to be 0 for all applets supported.
+
+ // TODO: check order
+ context.ResponseData.Write(0xe); // Use error applet as default for now
+ context.ResponseData.Write(0); // libraryAppletMode
+ context.ResponseData.Write(0); // outSize
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/DnsSetting.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/DnsSetting.cs
new file mode 100644
index 00000000..374558ea
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/DnsSetting.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Net.NetworkInformation;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 9)]
+ struct DnsSetting
+ {
+ [MarshalAs(UnmanagedType.U1)]
+ public bool IsDynamicDnsEnabled;
+ public IpV4Address PrimaryDns;
+ public IpV4Address SecondaryDns;
+
+ public DnsSetting(IPInterfaceProperties interfaceProperties)
+ {
+ IsDynamicDnsEnabled = OperatingSystem.IsWindows() && interfaceProperties.IsDynamicDnsEnabled;
+
+ if (interfaceProperties.DnsAddresses.Count == 0)
+ {
+ PrimaryDns = new IpV4Address();
+ SecondaryDns = new IpV4Address();
+ }
+ else
+ {
+ PrimaryDns = new IpV4Address(interfaceProperties.DnsAddresses[0]);
+ SecondaryDns = new IpV4Address(interfaceProperties.DnsAddresses[interfaceProperties.DnsAddresses.Count > 1 ? 1 : 0]);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionState.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionState.cs
new file mode 100644
index 00000000..dfb8f76c
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionState.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ enum InternetConnectionState : byte
+ {
+ ConnectingType0 = 0,
+ ConnectingType1 = 1,
+ ConnectingType2 = 2,
+ ConnectingType3 = 3,
+ Connected = 4,
+ }
+}
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionStatus.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionStatus.cs
new file mode 100644
index 00000000..ff944eca
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionStatus.cs
@@ -0,0 +1,12 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential)]
+ struct InternetConnectionStatus
+ {
+ public InternetConnectionType Type;
+ public byte WifiStrength;
+ public InternetConnectionState State;
+ }
+}
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionType.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionType.cs
new file mode 100644
index 00000000..af2bcfa1
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/InternetConnectionType.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ enum InternetConnectionType : byte
+ {
+ Invalid = 0,
+ WiFi = 1,
+ Ethernet = 2,
+ }
+}
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs
new file mode 100644
index 00000000..59c1f6a7
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Net.NetworkInformation;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0xd)]
+ struct IpAddressSetting
+ {
+ [MarshalAs(UnmanagedType.U1)]
+ public bool IsDhcpEnabled;
+ public IpV4Address Address;
+ public IpV4Address IPv4Mask;
+ public IpV4Address GatewayAddress;
+
+ public IpAddressSetting(IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastIPAddressInformation)
+ {
+ IsDhcpEnabled = OperatingSystem.IsMacOS() || interfaceProperties.DhcpServerAddresses.Count != 0;
+ Address = new IpV4Address(unicastIPAddressInformation.Address);
+ IPv4Mask = new IpV4Address(unicastIPAddressInformation.IPv4Mask);
+ GatewayAddress = (interfaceProperties.GatewayAddresses.Count == 0) ? new IpV4Address() : new IpV4Address(interfaceProperties.GatewayAddresses[0].Address);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpSettingData.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpSettingData.cs
new file mode 100644
index 00000000..8ffe824c
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpSettingData.cs
@@ -0,0 +1,13 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0xc2)]
+ struct IpSettingData
+ {
+ public IpAddressSetting IpAddressSetting;
+ public DnsSetting DnsSetting;
+ public ProxySetting ProxySetting;
+ public short Mtu;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpV4Address.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpV4Address.cs
new file mode 100644
index 00000000..e5c2f39a
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpV4Address.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Net;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential)]
+ struct IpV4Address
+ {
+ public uint Address;
+
+ public IpV4Address(IPAddress address)
+ {
+ if (address == null)
+ {
+ Address = 0;
+ }
+ else
+ {
+ Address = BitConverter.ToUInt32(address.GetAddressBytes());
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/NetworkProfileData.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/NetworkProfileData.cs
new file mode 100644
index 00000000..e270c10a
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/NetworkProfileData.cs
@@ -0,0 +1,17 @@
+using Ryujinx.Common.Memory;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x17C)]
+ struct NetworkProfileData
+ {
+ public IpSettingData IpSettingData;
+ public UInt128 Uuid;
+ public Array64<byte> Name;
+ public Array4<byte> Unknown;
+ public WirelessSettingData WirelessSettingData;
+ public byte Padding;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/ProxySetting.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/ProxySetting.cs
new file mode 100644
index 00000000..6e534fe1
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/ProxySetting.cs
@@ -0,0 +1,27 @@
+using Ryujinx.Common.Memory;
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0xaa)]
+ public struct ProxySetting
+ {
+ [MarshalAs(UnmanagedType.I1)]
+ public bool Enabled;
+ private byte _padding;
+ public short Port;
+ private NameStruct _name;
+ [MarshalAs(UnmanagedType.I1)]
+ public bool AutoAuthEnabled;
+ public Array32<byte> User;
+ public Array32<byte> Pass;
+ private byte _padding2;
+
+ [StructLayout(LayoutKind.Sequential, Size = 0x64)]
+ private struct NameStruct { }
+
+ public Span<byte> Name => SpanHelpers.AsSpan<NameStruct, byte>(ref _name);
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/WirelessSettingData.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/WirelessSettingData.cs
new file mode 100644
index 00000000..8aa122c7
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/WirelessSettingData.cs
@@ -0,0 +1,15 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x65)]
+ struct WirelessSettingData
+ {
+ public byte SsidLength;
+ public Array32<byte> Ssid;
+ public Array3<byte> Unknown;
+ public Array64<byte> Passphrase1;
+ public byte Passphrase2;
+ }
+} \ No newline at end of file