nifm.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/settings.h"
  5. #include "core/core.h"
  6. #include "core/hle/ipc_helpers.h"
  7. #include "core/hle/kernel/k_event.h"
  8. #include "core/hle/kernel/k_readable_event.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/service/nifm/nifm.h"
  11. #include "core/hle/service/service.h"
  12. #include "core/network/network.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. struct IpAddressSetting {
  21. bool is_automatic{};
  22. Network::IPv4Address current_address{};
  23. Network::IPv4Address subnet_mask{};
  24. Network::IPv4Address gateway{};
  25. };
  26. static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size.");
  27. struct DnsSetting {
  28. bool is_automatic{};
  29. Network::IPv4Address primary_dns{};
  30. Network::IPv4Address secondary_dns{};
  31. };
  32. static_assert(sizeof(DnsSetting) == 0x9, "DnsSetting has incorrect size.");
  33. struct ProxySetting {
  34. bool enabled{};
  35. INSERT_PADDING_BYTES(1);
  36. u16 port{};
  37. std::array<char, 0x64> proxy_server{};
  38. bool automatic_auth_enabled{};
  39. std::array<char, 0x20> user{};
  40. std::array<char, 0x20> password{};
  41. INSERT_PADDING_BYTES(1);
  42. };
  43. static_assert(sizeof(ProxySetting) == 0xAA, "ProxySetting has incorrect size.");
  44. struct IpSettingData {
  45. IpAddressSetting ip_address_setting{};
  46. DnsSetting dns_setting{};
  47. ProxySetting proxy_setting{};
  48. u16 mtu{};
  49. };
  50. static_assert(sizeof(IpSettingData) == 0xC2, "IpSettingData has incorrect size.");
  51. struct SfWirelessSettingData {
  52. u8 ssid_length{};
  53. std::array<char, 0x20> ssid{};
  54. u8 unknown_1{};
  55. u8 unknown_2{};
  56. u8 unknown_3{};
  57. std::array<char, 0x41> passphrase{};
  58. };
  59. static_assert(sizeof(SfWirelessSettingData) == 0x65, "SfWirelessSettingData has incorrect size.");
  60. struct NifmWirelessSettingData {
  61. u8 ssid_length{};
  62. std::array<char, 0x21> ssid{};
  63. u8 unknown_1{};
  64. INSERT_PADDING_BYTES(1);
  65. u32 unknown_2{};
  66. u32 unknown_3{};
  67. std::array<char, 0x41> passphrase{};
  68. INSERT_PADDING_BYTES(3);
  69. };
  70. static_assert(sizeof(NifmWirelessSettingData) == 0x70,
  71. "NifmWirelessSettingData has incorrect size.");
  72. #pragma pack(push, 1)
  73. struct SfNetworkProfileData {
  74. IpSettingData ip_setting_data{};
  75. u128 uuid{};
  76. std::array<char, 0x40> network_name{};
  77. u8 unknown_1{};
  78. u8 unknown_2{};
  79. u8 unknown_3{};
  80. u8 unknown_4{};
  81. SfWirelessSettingData wireless_setting_data{};
  82. INSERT_PADDING_BYTES(1);
  83. };
  84. static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size.");
  85. struct NifmNetworkProfileData {
  86. u128 uuid{};
  87. std::array<char, 0x40> network_name{};
  88. u32 unknown_1{};
  89. u32 unknown_2{};
  90. u8 unknown_3{};
  91. u8 unknown_4{};
  92. INSERT_PADDING_BYTES(2);
  93. NifmWirelessSettingData wireless_setting_data{};
  94. IpSettingData ip_setting_data{};
  95. };
  96. static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
  97. "NifmNetworkProfileData has incorrect size.");
  98. #pragma pack(pop)
  99. class IScanRequest final : public ServiceFramework<IScanRequest> {
  100. public:
  101. explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} {
  102. // clang-format off
  103. static const FunctionInfo functions[] = {
  104. {0, nullptr, "Submit"},
  105. {1, nullptr, "IsProcessing"},
  106. {2, nullptr, "GetResult"},
  107. {3, nullptr, "GetSystemEventReadableHandle"},
  108. {4, nullptr, "SetChannels"},
  109. };
  110. // clang-format on
  111. RegisterHandlers(functions);
  112. }
  113. };
  114. class IRequest final : public ServiceFramework<IRequest> {
  115. public:
  116. explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} {
  117. static const FunctionInfo functions[] = {
  118. {0, &IRequest::GetRequestState, "GetRequestState"},
  119. {1, &IRequest::GetResult, "GetResult"},
  120. {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"},
  121. {3, &IRequest::Cancel, "Cancel"},
  122. {4, &IRequest::Submit, "Submit"},
  123. {5, nullptr, "SetRequirement"},
  124. {6, nullptr, "SetRequirementPreset"},
  125. {8, nullptr, "SetPriority"},
  126. {9, nullptr, "SetNetworkProfileId"},
  127. {10, nullptr, "SetRejectable"},
  128. {11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"},
  129. {12, nullptr, "SetPersistent"},
  130. {13, nullptr, "SetInstant"},
  131. {14, nullptr, "SetSustainable"},
  132. {15, nullptr, "SetRawPriority"},
  133. {16, nullptr, "SetGreedy"},
  134. {17, nullptr, "SetSharable"},
  135. {18, nullptr, "SetRequirementByRevision"},
  136. {19, nullptr, "GetRequirement"},
  137. {20, nullptr, "GetRevision"},
  138. {21, &IRequest::GetAppletInfo, "GetAppletInfo"},
  139. {22, nullptr, "GetAdditionalInfo"},
  140. {23, nullptr, "SetKeptInSleep"},
  141. {24, nullptr, "RegisterSocketDescriptor"},
  142. {25, nullptr, "UnregisterSocketDescriptor"},
  143. };
  144. RegisterHandlers(functions);
  145. auto& kernel = system.Kernel();
  146. event1 = Kernel::KEvent::Create(kernel, "IRequest:Event1");
  147. event1->Initialize();
  148. event2 = Kernel::KEvent::Create(kernel, "IRequest:Event2");
  149. event2->Initialize();
  150. }
  151. private:
  152. void Submit(Kernel::HLERequestContext& ctx) {
  153. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  154. IPC::ResponseBuilder rb{ctx, 2};
  155. rb.Push(RESULT_SUCCESS);
  156. }
  157. void GetRequestState(Kernel::HLERequestContext& ctx) {
  158. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  159. IPC::ResponseBuilder rb{ctx, 3};
  160. rb.Push(RESULT_SUCCESS);
  161. if (Settings::values.bcat_backend == "none") {
  162. rb.PushEnum(RequestState::NotSubmitted);
  163. } else {
  164. rb.PushEnum(RequestState::Connected);
  165. }
  166. }
  167. void GetResult(Kernel::HLERequestContext& ctx) {
  168. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  169. IPC::ResponseBuilder rb{ctx, 2};
  170. rb.Push(RESULT_SUCCESS);
  171. }
  172. void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
  173. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  174. IPC::ResponseBuilder rb{ctx, 2, 2};
  175. rb.Push(RESULT_SUCCESS);
  176. rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent());
  177. }
  178. void Cancel(Kernel::HLERequestContext& ctx) {
  179. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  180. IPC::ResponseBuilder rb{ctx, 2};
  181. rb.Push(RESULT_SUCCESS);
  182. }
  183. void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
  184. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  185. IPC::ResponseBuilder rb{ctx, 2};
  186. rb.Push(RESULT_SUCCESS);
  187. }
  188. void GetAppletInfo(Kernel::HLERequestContext& ctx) {
  189. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  190. std::vector<u8> out_buffer(ctx.GetWriteBufferSize());
  191. ctx.WriteBuffer(out_buffer);
  192. IPC::ResponseBuilder rb{ctx, 5};
  193. rb.Push(RESULT_SUCCESS);
  194. rb.Push<u32>(0);
  195. rb.Push<u32>(0);
  196. rb.Push<u32>(0);
  197. }
  198. std::shared_ptr<Kernel::KEvent> event1, event2;
  199. };
  200. class INetworkProfile final : public ServiceFramework<INetworkProfile> {
  201. public:
  202. explicit INetworkProfile(Core::System& system_) : ServiceFramework{system_, "INetworkProfile"} {
  203. static const FunctionInfo functions[] = {
  204. {0, nullptr, "Update"},
  205. {1, nullptr, "PersistOld"},
  206. {2, nullptr, "Persist"},
  207. };
  208. RegisterHandlers(functions);
  209. }
  210. };
  211. class IGeneralService final : public ServiceFramework<IGeneralService> {
  212. public:
  213. explicit IGeneralService(Core::System& system_);
  214. private:
  215. void GetClientId(Kernel::HLERequestContext& ctx) {
  216. static constexpr u32 client_id = 1;
  217. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  218. IPC::ResponseBuilder rb{ctx, 4};
  219. rb.Push(RESULT_SUCCESS);
  220. rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
  221. }
  222. void CreateScanRequest(Kernel::HLERequestContext& ctx) {
  223. LOG_DEBUG(Service_NIFM, "called");
  224. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  225. rb.Push(RESULT_SUCCESS);
  226. rb.PushIpcInterface<IScanRequest>(system);
  227. }
  228. void CreateRequest(Kernel::HLERequestContext& ctx) {
  229. LOG_DEBUG(Service_NIFM, "called");
  230. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  231. rb.Push(RESULT_SUCCESS);
  232. rb.PushIpcInterface<IRequest>(system);
  233. }
  234. void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
  235. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  236. const SfNetworkProfileData network_profile_data{
  237. .ip_setting_data{
  238. .ip_address_setting{
  239. .is_automatic{true},
  240. .current_address{192, 168, 1, 100},
  241. .subnet_mask{255, 255, 255, 0},
  242. .gateway{192, 168, 1, 1},
  243. },
  244. .dns_setting{
  245. .is_automatic{true},
  246. .primary_dns{1, 1, 1, 1},
  247. .secondary_dns{1, 0, 0, 1},
  248. },
  249. .proxy_setting{
  250. .enabled{false},
  251. .port{},
  252. .proxy_server{},
  253. .automatic_auth_enabled{},
  254. .user{},
  255. .password{},
  256. },
  257. .mtu{1500},
  258. },
  259. .uuid{0xdeadbeef, 0xdeadbeef},
  260. .network_name{"yuzu Network"},
  261. .wireless_setting_data{
  262. .ssid_length{12},
  263. .ssid{"yuzu Network"},
  264. .passphrase{"yuzupassword"},
  265. },
  266. };
  267. ctx.WriteBuffer(network_profile_data);
  268. IPC::ResponseBuilder rb{ctx, 2};
  269. rb.Push(RESULT_SUCCESS);
  270. }
  271. void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
  272. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  273. IPC::ResponseBuilder rb{ctx, 2};
  274. rb.Push(RESULT_SUCCESS);
  275. }
  276. void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
  277. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  278. const auto [ipv4, error] = Network::GetHostIPv4Address();
  279. UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
  280. IPC::ResponseBuilder rb{ctx, 3};
  281. rb.Push(RESULT_SUCCESS);
  282. rb.PushRaw(ipv4);
  283. }
  284. void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
  285. LOG_DEBUG(Service_NIFM, "called");
  286. ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c,
  287. "SfNetworkProfileData is not the correct size");
  288. u128 uuid{};
  289. auto buffer = ctx.ReadBuffer();
  290. std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
  291. IPC::ResponseBuilder rb{ctx, 6, 0, 1};
  292. rb.Push(RESULT_SUCCESS);
  293. rb.PushIpcInterface<INetworkProfile>(system);
  294. rb.PushRaw<u128>(uuid);
  295. }
  296. void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
  297. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  298. struct IpConfigInfo {
  299. IpAddressSetting ip_address_setting;
  300. DnsSetting dns_setting;
  301. };
  302. static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
  303. "IpConfigInfo has incorrect size.");
  304. const IpConfigInfo ip_config_info{
  305. .ip_address_setting{
  306. .is_automatic{true},
  307. .current_address{192, 168, 1, 100},
  308. .subnet_mask{255, 255, 255, 0},
  309. .gateway{192, 168, 1, 1},
  310. },
  311. .dns_setting{
  312. .is_automatic{true},
  313. .primary_dns{1, 1, 1, 1},
  314. .secondary_dns{1, 0, 0, 1},
  315. },
  316. };
  317. IPC::ResponseBuilder rb{ctx, 2 + sizeof(IpConfigInfo) / sizeof(u32)};
  318. rb.Push(RESULT_SUCCESS);
  319. rb.PushRaw<IpConfigInfo>(ip_config_info);
  320. }
  321. void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
  322. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  323. IPC::ResponseBuilder rb{ctx, 3};
  324. rb.Push(RESULT_SUCCESS);
  325. rb.Push<u8>(0);
  326. }
  327. void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
  328. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  329. IPC::ResponseBuilder rb{ctx, 3};
  330. rb.Push(RESULT_SUCCESS);
  331. if (Settings::values.bcat_backend == "none") {
  332. rb.Push<u8>(0);
  333. } else {
  334. rb.Push<u8>(1);
  335. }
  336. }
  337. void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
  338. LOG_WARNING(Service_NIFM, "(STUBBED) called");
  339. IPC::ResponseBuilder rb{ctx, 3};
  340. rb.Push(RESULT_SUCCESS);
  341. if (Settings::values.bcat_backend == "none") {
  342. rb.Push<u8>(0);
  343. } else {
  344. rb.Push<u8>(1);
  345. }
  346. }
  347. };
  348. IGeneralService::IGeneralService(Core::System& system_)
  349. : ServiceFramework{system_, "IGeneralService"} {
  350. // clang-format off
  351. static const FunctionInfo functions[] = {
  352. {1, &IGeneralService::GetClientId, "GetClientId"},
  353. {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
  354. {4, &IGeneralService::CreateRequest, "CreateRequest"},
  355. {5, &IGeneralService::GetCurrentNetworkProfile, "GetCurrentNetworkProfile"},
  356. {6, nullptr, "EnumerateNetworkInterfaces"},
  357. {7, nullptr, "EnumerateNetworkProfiles"},
  358. {8, nullptr, "GetNetworkProfile"},
  359. {9, nullptr, "SetNetworkProfile"},
  360. {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"},
  361. {11, nullptr, "GetScanDataOld"},
  362. {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
  363. {13, nullptr, "GetCurrentAccessPointOld"},
  364. {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
  365. {15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"},
  366. {16, nullptr, "SetWirelessCommunicationEnabled"},
  367. {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
  368. {18, nullptr, "GetInternetConnectionStatus"},
  369. {19, nullptr, "SetEthernetCommunicationEnabled"},
  370. {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
  371. {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
  372. {22, nullptr, "IsAnyForegroundRequestAccepted"},
  373. {23, nullptr, "PutToSleep"},
  374. {24, nullptr, "WakeUp"},
  375. {25, nullptr, "GetSsidListVersion"},
  376. {26, nullptr, "SetExclusiveClient"},
  377. {27, nullptr, "GetDefaultIpSetting"},
  378. {28, nullptr, "SetDefaultIpSetting"},
  379. {29, nullptr, "SetWirelessCommunicationEnabledForTest"},
  380. {30, nullptr, "SetEthernetCommunicationEnabledForTest"},
  381. {31, nullptr, "GetTelemetorySystemEventReadableHandle"},
  382. {32, nullptr, "GetTelemetryInfo"},
  383. {33, nullptr, "ConfirmSystemAvailability"},
  384. {34, nullptr, "SetBackgroundRequestEnabled"},
  385. {35, nullptr, "GetScanData"},
  386. {36, nullptr, "GetCurrentAccessPoint"},
  387. {37, nullptr, "Shutdown"},
  388. {38, nullptr, "GetAllowedChannels"},
  389. {39, nullptr, "NotifyApplicationSuspended"},
  390. {40, nullptr, "SetAcceptableNetworkTypeFlag"},
  391. {41, nullptr, "GetAcceptableNetworkTypeFlag"},
  392. {42, nullptr, "NotifyConnectionStateChanged"},
  393. {43, nullptr, "SetWowlDelayedWakeTime"},
  394. };
  395. // clang-format on
  396. RegisterHandlers(functions);
  397. }
  398. class NetworkInterface final : public ServiceFramework<NetworkInterface> {
  399. public:
  400. explicit NetworkInterface(const char* name, Core::System& system_)
  401. : ServiceFramework{system_, name} {
  402. static const FunctionInfo functions[] = {
  403. {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"},
  404. {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"},
  405. };
  406. RegisterHandlers(functions);
  407. }
  408. private:
  409. void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
  410. LOG_DEBUG(Service_NIFM, "called");
  411. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  412. rb.Push(RESULT_SUCCESS);
  413. rb.PushIpcInterface<IGeneralService>(system);
  414. }
  415. void CreateGeneralService(Kernel::HLERequestContext& ctx) {
  416. LOG_DEBUG(Service_NIFM, "called");
  417. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  418. rb.Push(RESULT_SUCCESS);
  419. rb.PushIpcInterface<IGeneralService>(system);
  420. }
  421. };
  422. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  423. std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager);
  424. std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager);
  425. std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager);
  426. }
  427. } // namespace Service::NIFM