nifm.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "core/core.h"
  5. #include "core/hle/ipc_helpers.h"
  6. #include "core/hle/kernel/kernel.h"
  7. #include "core/hle/kernel/readable_event.h"
  8. #include "core/hle/kernel/writable_event.h"
  9. #include "core/hle/service/nifm/nifm.h"
  10. #include "core/hle/service/service.h"
  11. #include "core/network/network.h"
  12. #include "core/settings.h"
  13. namespace Service::NIFM {
  14. enum class RequestState : u32 {
  15. NotSubmitted = 1,
  16. Error = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW.
  17. Pending = 2,
  18. Connected = 3,
  19. };
  20. class IScanRequest final : public ServiceFramework<IScanRequest> {
  21. public:
  22. explicit IScanRequest() : ServiceFramework("IScanRequest") {
  23. // clang-format off
  24. static const FunctionInfo functions[] = {
  25. {0, nullptr, "Submit"},
  26. {1, nullptr, "IsProcessing"},
  27. {2, nullptr, "GetResult"},
  28. {3, nullptr, "GetSystemEventReadableHandle"},
  29. {4, nullptr, "SetChannels"},
  30. };
  31. // clang-format on
  32. RegisterHandlers(functions);
  33. }
  34. };
  35. class IRequest final : public ServiceFramework<IRequest> {
  36. public:
  37. explicit IRequest(Core::System& system) : ServiceFramework("IRequest") {
  38. static const FunctionInfo functions[] = {
  39. {0, &IRequest::GetRequestState, "GetRequestState"},
  40. {1, &IRequest::GetResult, "GetResult"},
  41. {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"},
  42. {3, &IRequest::Cancel, "Cancel"},
  43. {4, &IRequest::Submit, "Submit"},
  44. {5, nullptr, "SetRequirement"},
  45. {6, nullptr, "SetRequirementPreset"},
  46. {8, nullptr, "SetPriority"},
  47. {9, nullptr, "SetNetworkProfileId"},
  48. {10, nullptr, "SetRejectable"},
  49. {11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"},
  50. {12, nullptr, "SetPersistent"},
  51. {13, nullptr, "SetInstant"},
  52. {14, nullptr, "SetSustainable"},
  53. {15, nullptr, "SetRawPriority"},
  54. {16, nullptr, "SetGreedy"},
  55. {17, nullptr, "SetSharable"},
  56. {18, nullptr, "SetRequirementByRevision"},
  57. {19, nullptr, "GetRequirement"},
  58. {20, nullptr, "GetRevision"},
  59. {21, &IRequest::GetAppletInfo, "GetAppletInfo"},
  60. {22, nullptr, "GetAdditionalInfo"},
  61. {23, nullptr, "SetKeptInSleep"},
  62. {24, nullptr, "RegisterSocketDescriptor"},
  63. {25, nullptr, "UnregisterSocketDescriptor"},
  64. };
  65. RegisterHandlers(functions);
  66. auto& kernel = system.Kernel();
  67. event1 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event1");
  68. event2 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event2");
  69. }
  70. private:
  71. void Submit(Kernel::HLERequestContext& ctx) {
  72. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  73. IPC::ResponseBuilder rb{ctx, 2};
  74. rb.Push(RESULT_SUCCESS);
  75. }
  76. void GetRequestState(Kernel::HLERequestContext& ctx) {
  77. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  78. IPC::ResponseBuilder rb{ctx, 3};
  79. rb.Push(RESULT_SUCCESS);
  80. if (Settings::values.bcat_backend == "none") {
  81. rb.PushEnum(RequestState::NotSubmitted);
  82. } else {
  83. rb.PushEnum(RequestState::Connected);
  84. }
  85. }
  86. void GetResult(Kernel::HLERequestContext& ctx) {
  87. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  88. IPC::ResponseBuilder rb{ctx, 2};
  89. rb.Push(RESULT_SUCCESS);
  90. }
  91. void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
  92. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  93. IPC::ResponseBuilder rb{ctx, 2, 2};
  94. rb.Push(RESULT_SUCCESS);
  95. rb.PushCopyObjects(event1.readable, event2.readable);
  96. }
  97. void Cancel(Kernel::HLERequestContext& ctx) {
  98. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  99. IPC::ResponseBuilder rb{ctx, 2};
  100. rb.Push(RESULT_SUCCESS);
  101. }
  102. void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
  103. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  104. IPC::ResponseBuilder rb{ctx, 2};
  105. rb.Push(RESULT_SUCCESS);
  106. }
  107. void GetAppletInfo(Kernel::HLERequestContext& ctx) {
  108. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  109. IPC::ResponseBuilder rb{ctx, 8};
  110. rb.Push(RESULT_SUCCESS);
  111. rb.Push<u32>(0);
  112. rb.Push<u32>(0);
  113. rb.Push<u32>(0);
  114. }
  115. Kernel::EventPair event1, event2;
  116. };
  117. class INetworkProfile final : public ServiceFramework<INetworkProfile> {
  118. public:
  119. explicit INetworkProfile() : ServiceFramework("INetworkProfile") {
  120. static const FunctionInfo functions[] = {
  121. {0, nullptr, "Update"},
  122. {1, nullptr, "PersistOld"},
  123. {2, nullptr, "Persist"},
  124. };
  125. RegisterHandlers(functions);
  126. }
  127. };
  128. class IGeneralService final : public ServiceFramework<IGeneralService> {
  129. public:
  130. IGeneralService(Core::System& system);
  131. private:
  132. void GetClientId(Kernel::HLERequestContext& ctx) {
  133. static constexpr u32 client_id = 1;
  134. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  135. IPC::ResponseBuilder rb{ctx, 4};
  136. rb.Push(RESULT_SUCCESS);
  137. rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
  138. }
  139. void CreateScanRequest(Kernel::HLERequestContext& ctx) {
  140. LOG_DEBUG(Service_NIFM, "called");
  141. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  142. rb.Push(RESULT_SUCCESS);
  143. rb.PushIpcInterface<IScanRequest>();
  144. }
  145. void CreateRequest(Kernel::HLERequestContext& ctx) {
  146. LOG_DEBUG(Service_NIFM, "called");
  147. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  148. rb.Push(RESULT_SUCCESS);
  149. rb.PushIpcInterface<IRequest>(system);
  150. }
  151. void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
  152. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  153. IPC::ResponseBuilder rb{ctx, 2};
  154. rb.Push(RESULT_SUCCESS);
  155. }
  156. void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
  157. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  158. const auto [ipv4, error] = Network::GetHostIPv4Address();
  159. UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
  160. IPC::ResponseBuilder rb{ctx, 3};
  161. rb.Push(RESULT_SUCCESS);
  162. rb.PushRaw(ipv4);
  163. }
  164. void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
  165. LOG_DEBUG(Service_NIFM, "called");
  166. ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c,
  167. "SfNetworkProfileData is not the correct size");
  168. u128 uuid{};
  169. auto buffer = ctx.ReadBuffer();
  170. std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
  171. IPC::ResponseBuilder rb{ctx, 6, 0, 1};
  172. rb.Push(RESULT_SUCCESS);
  173. rb.PushIpcInterface<INetworkProfile>();
  174. rb.PushRaw<u128>(uuid);
  175. }
  176. void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
  177. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  178. IPC::ResponseBuilder rb{ctx, 3};
  179. rb.Push(RESULT_SUCCESS);
  180. rb.Push<u8>(0);
  181. }
  182. void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
  183. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  184. IPC::ResponseBuilder rb{ctx, 3};
  185. rb.Push(RESULT_SUCCESS);
  186. if (Settings::values.bcat_backend == "none") {
  187. rb.Push<u8>(0);
  188. } else {
  189. rb.Push<u8>(1);
  190. }
  191. }
  192. void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
  193. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  194. IPC::ResponseBuilder rb{ctx, 3};
  195. rb.Push(RESULT_SUCCESS);
  196. if (Settings::values.bcat_backend == "none") {
  197. rb.Push<u8>(0);
  198. } else {
  199. rb.Push<u8>(1);
  200. }
  201. }
  202. Core::System& system;
  203. };
  204. IGeneralService::IGeneralService(Core::System& system)
  205. : ServiceFramework("IGeneralService"), system(system) {
  206. // clang-format off
  207. static const FunctionInfo functions[] = {
  208. {1, &IGeneralService::GetClientId, "GetClientId"},
  209. {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
  210. {4, &IGeneralService::CreateRequest, "CreateRequest"},
  211. {5, nullptr, "GetCurrentNetworkProfile"},
  212. {6, nullptr, "EnumerateNetworkInterfaces"},
  213. {7, nullptr, "EnumerateNetworkProfiles"},
  214. {8, nullptr, "GetNetworkProfile"},
  215. {9, nullptr, "SetNetworkProfile"},
  216. {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"},
  217. {11, nullptr, "GetScanDataOld"},
  218. {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
  219. {13, nullptr, "GetCurrentAccessPointOld"},
  220. {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
  221. {15, nullptr, "GetCurrentIpConfigInfo"},
  222. {16, nullptr, "SetWirelessCommunicationEnabled"},
  223. {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
  224. {18, nullptr, "GetInternetConnectionStatus"},
  225. {19, nullptr, "SetEthernetCommunicationEnabled"},
  226. {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
  227. {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
  228. {22, nullptr, "IsAnyForegroundRequestAccepted"},
  229. {23, nullptr, "PutToSleep"},
  230. {24, nullptr, "WakeUp"},
  231. {25, nullptr, "GetSsidListVersion"},
  232. {26, nullptr, "SetExclusiveClient"},
  233. {27, nullptr, "GetDefaultIpSetting"},
  234. {28, nullptr, "SetDefaultIpSetting"},
  235. {29, nullptr, "SetWirelessCommunicationEnabledForTest"},
  236. {30, nullptr, "SetEthernetCommunicationEnabledForTest"},
  237. {31, nullptr, "GetTelemetorySystemEventReadableHandle"},
  238. {32, nullptr, "GetTelemetryInfo"},
  239. {33, nullptr, "ConfirmSystemAvailability"},
  240. {34, nullptr, "SetBackgroundRequestEnabled"},
  241. {35, nullptr, "GetScanData"},
  242. {36, nullptr, "GetCurrentAccessPoint"},
  243. {37, nullptr, "Shutdown"},
  244. {38, nullptr, "GetAllowedChannels"},
  245. {39, nullptr, "NotifyApplicationSuspended"},
  246. {40, nullptr, "SetAcceptableNetworkTypeFlag"},
  247. {41, nullptr, "GetAcceptableNetworkTypeFlag"},
  248. {42, nullptr, "NotifyConnectionStateChanged"},
  249. {43, nullptr, "SetWowlDelayedWakeTime"},
  250. };
  251. // clang-format on
  252. RegisterHandlers(functions);
  253. }
  254. class NetworkInterface final : public ServiceFramework<NetworkInterface> {
  255. public:
  256. explicit NetworkInterface(const char* name, Core::System& system)
  257. : ServiceFramework{name}, system(system) {
  258. static const FunctionInfo functions[] = {
  259. {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"},
  260. {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"},
  261. };
  262. RegisterHandlers(functions);
  263. }
  264. void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
  265. LOG_DEBUG(Service_NIFM, "called");
  266. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  267. rb.Push(RESULT_SUCCESS);
  268. rb.PushIpcInterface<IGeneralService>(system);
  269. }
  270. void CreateGeneralService(Kernel::HLERequestContext& ctx) {
  271. LOG_DEBUG(Service_NIFM, "called");
  272. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  273. rb.Push(RESULT_SUCCESS);
  274. rb.PushIpcInterface<IGeneralService>(system);
  275. }
  276. private:
  277. Core::System& system;
  278. };
  279. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  280. std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager);
  281. std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager);
  282. std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager);
  283. }
  284. } // namespace Service::NIFM