device.cpp 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #ifdef _MSC_VER
  4. #pragma warning(push)
  5. #pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used
  6. #endif
  7. #include <boost/crc.hpp>
  8. #ifdef _MSC_VER
  9. #pragma warning(pop)
  10. #endif
  11. #include <fmt/format.h>
  12. #include "common/fs/file.h"
  13. #include "common/fs/fs.h"
  14. #include "common/fs/path_util.h"
  15. #include "common/input.h"
  16. #include "common/logging/log.h"
  17. #include "common/string_util.h"
  18. #include "common/tiny_mt.h"
  19. #include "core/core.h"
  20. #include "core/hle/kernel/k_event.h"
  21. #include "core/hle/service/ipc_helpers.h"
  22. #include "core/hle/service/mii/mii_manager.h"
  23. #include "core/hle/service/nfc/common/amiibo_crypto.h"
  24. #include "core/hle/service/nfc/common/device.h"
  25. #include "core/hle/service/nfc/mifare_result.h"
  26. #include "core/hle/service/nfc/nfc_result.h"
  27. #include "core/hle/service/time/time_manager.h"
  28. #include "hid_core/frontend/emulated_controller.h"
  29. #include "hid_core/hid_core.h"
  30. #include "hid_core/hid_types.h"
  31. namespace Service::NFC {
  32. NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
  33. KernelHelpers::ServiceContext& service_context_,
  34. Kernel::KEvent* availability_change_event_)
  35. : npad_id{npad_id_}, system{system_}, service_context{service_context_},
  36. availability_change_event{availability_change_event_} {
  37. activate_event = service_context.CreateEvent("NFC:ActivateEvent");
  38. deactivate_event = service_context.CreateEvent("NFC:DeactivateEvent");
  39. npad_device = system.HIDCore().GetEmulatedController(npad_id);
  40. Core::HID::ControllerUpdateCallback engine_callback{
  41. .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
  42. .is_npad_service = false,
  43. };
  44. is_controller_set = true;
  45. callback_key = npad_device->SetCallback(engine_callback);
  46. }
  47. NfcDevice::~NfcDevice() {
  48. service_context.CloseEvent(activate_event);
  49. service_context.CloseEvent(deactivate_event);
  50. if (!is_controller_set) {
  51. return;
  52. }
  53. npad_device->DeleteCallback(callback_key);
  54. is_controller_set = false;
  55. };
  56. void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
  57. if (type == Core::HID::ControllerTriggerType::Connected) {
  58. Initialize();
  59. availability_change_event->Signal();
  60. return;
  61. }
  62. if (type == Core::HID::ControllerTriggerType::Disconnected) {
  63. Finalize();
  64. availability_change_event->Signal();
  65. return;
  66. }
  67. if (!is_initalized) {
  68. return;
  69. }
  70. if (!npad_device->IsConnected()) {
  71. return;
  72. }
  73. // Ensure nfc mode is always active
  74. if (npad_device->GetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex) ==
  75. Common::Input::PollingMode::Active) {
  76. npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
  77. Common::Input::PollingMode::NFC);
  78. }
  79. if (type != Core::HID::ControllerTriggerType::Nfc) {
  80. return;
  81. }
  82. const auto nfc_status = npad_device->GetNfc();
  83. switch (nfc_status.state) {
  84. case Common::Input::NfcState::NewAmiibo:
  85. LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length,
  86. nfc_status.uuid);
  87. break;
  88. case Common::Input::NfcState::AmiiboRemoved:
  89. if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
  90. break;
  91. }
  92. if (device_state != DeviceState::SearchingForTag) {
  93. CloseNfcTag();
  94. }
  95. break;
  96. default:
  97. break;
  98. }
  99. }
  100. bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) {
  101. if (device_state != DeviceState::SearchingForTag) {
  102. LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
  103. return false;
  104. }
  105. if ((protocol & static_cast<u8>(allowed_protocols)) == 0) {
  106. LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol);
  107. return false;
  108. }
  109. real_tag_info = {
  110. .uuid = uuid,
  111. .uuid_length = uuid_length,
  112. .protocol = static_cast<NfcProtocol>(protocol),
  113. .tag_type = static_cast<TagType>(tag_type),
  114. };
  115. device_state = DeviceState::TagFound;
  116. deactivate_event->GetReadableEvent().Clear();
  117. activate_event->Signal();
  118. return true;
  119. }
  120. bool NfcDevice::LoadAmiiboData() {
  121. std::vector<u8> data{};
  122. if (!npad_device->ReadAmiiboData(data)) {
  123. return false;
  124. }
  125. if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
  126. LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
  127. return false;
  128. }
  129. memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
  130. is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
  131. is_write_protected = false;
  132. // Fallback for plain amiibos
  133. if (is_plain_amiibo) {
  134. LOG_INFO(Service_NFP, "Using plain amiibo");
  135. encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
  136. return true;
  137. }
  138. // Fallback for encrypted amiibos without keys
  139. if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
  140. LOG_INFO(Service_NFC, "Loading amiibo without keys");
  141. memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
  142. BuildAmiiboWithoutKeys(tag_data, encrypted_tag_data);
  143. is_plain_amiibo = true;
  144. is_write_protected = true;
  145. return true;
  146. }
  147. LOG_INFO(Service_NFP, "Using encrypted amiibo");
  148. tag_data = {};
  149. memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
  150. return true;
  151. }
  152. void NfcDevice::CloseNfcTag() {
  153. LOG_INFO(Service_NFC, "Remove nfc tag");
  154. if (device_state == DeviceState::TagMounted) {
  155. Unmount();
  156. }
  157. device_state = DeviceState::TagRemoved;
  158. encrypted_tag_data = {};
  159. tag_data = {};
  160. activate_event->GetReadableEvent().Clear();
  161. deactivate_event->Signal();
  162. }
  163. Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
  164. return activate_event->GetReadableEvent();
  165. }
  166. Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
  167. return deactivate_event->GetReadableEvent();
  168. }
  169. void NfcDevice::Initialize() {
  170. device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
  171. encrypted_tag_data = {};
  172. tag_data = {};
  173. if (device_state != DeviceState::Initialized) {
  174. return;
  175. }
  176. is_initalized = npad_device->AddNfcHandle();
  177. }
  178. void NfcDevice::Finalize() {
  179. if (npad_device->IsConnected()) {
  180. if (device_state == DeviceState::TagMounted) {
  181. Unmount();
  182. }
  183. if (device_state == DeviceState::SearchingForTag ||
  184. device_state == DeviceState::TagRemoved) {
  185. StopDetection();
  186. }
  187. }
  188. if (device_state != DeviceState::Unavailable) {
  189. npad_device->RemoveNfcHandle();
  190. }
  191. device_state = DeviceState::Unavailable;
  192. is_initalized = false;
  193. }
  194. Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
  195. if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
  196. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  197. return ResultWrongDeviceState;
  198. }
  199. if (!npad_device->StartNfcPolling()) {
  200. LOG_ERROR(Service_NFC, "Nfc polling not supported");
  201. return ResultNfcDisabled;
  202. }
  203. device_state = DeviceState::SearchingForTag;
  204. allowed_protocols = allowed_protocol;
  205. return ResultSuccess;
  206. }
  207. Result NfcDevice::StopDetection() {
  208. if (device_state == DeviceState::Initialized) {
  209. return ResultSuccess;
  210. }
  211. if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
  212. CloseNfcTag();
  213. }
  214. if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
  215. npad_device->StopNfcPolling();
  216. device_state = DeviceState::Initialized;
  217. return ResultSuccess;
  218. }
  219. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  220. return ResultWrongDeviceState;
  221. }
  222. Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
  223. if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
  224. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  225. if (device_state == DeviceState::TagRemoved) {
  226. return ResultTagRemoved;
  227. }
  228. return ResultWrongDeviceState;
  229. }
  230. tag_info = real_tag_info;
  231. // Generate random UUID to bypass amiibo load limits
  232. if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) {
  233. Common::TinyMT rng{};
  234. rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
  235. rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length);
  236. }
  237. return ResultSuccess;
  238. }
  239. Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
  240. std::span<MifareReadBlockData> read_block_data) const {
  241. if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
  242. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  243. if (device_state == DeviceState::TagRemoved) {
  244. return ResultTagRemoved;
  245. }
  246. return ResultWrongDeviceState;
  247. }
  248. Result result = ResultSuccess;
  249. TagInfo tag_info{};
  250. result = GetTagInfo(tag_info);
  251. if (result.IsError()) {
  252. return result;
  253. }
  254. if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
  255. return ResultInvalidTagType;
  256. }
  257. if (parameters.size() == 0) {
  258. return ResultInvalidArgument;
  259. }
  260. Common::Input::MifareRequest request{};
  261. Common::Input::MifareRequest out_data{};
  262. const auto unknown = parameters[0].sector_key.unknown;
  263. for (std::size_t i = 0; i < parameters.size(); i++) {
  264. if (unknown != parameters[i].sector_key.unknown) {
  265. return ResultInvalidArgument;
  266. }
  267. }
  268. for (std::size_t i = 0; i < parameters.size(); i++) {
  269. if (parameters[i].sector_key.command == MifareCmd::None) {
  270. continue;
  271. }
  272. request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
  273. request.data[i].sector = parameters[i].sector_number;
  274. memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
  275. sizeof(KeyData));
  276. }
  277. if (!npad_device->ReadMifareData(request, out_data)) {
  278. return ResultMifareError288;
  279. }
  280. for (std::size_t i = 0; i < read_block_data.size(); i++) {
  281. if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) {
  282. continue;
  283. }
  284. read_block_data[i] = {
  285. .data = out_data.data[i].data,
  286. .sector_number = out_data.data[i].sector,
  287. };
  288. }
  289. return ResultSuccess;
  290. }
  291. Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
  292. Result result = ResultSuccess;
  293. TagInfo tag_info{};
  294. result = GetTagInfo(tag_info);
  295. if (result.IsError()) {
  296. return result;
  297. }
  298. if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
  299. return ResultInvalidTagType;
  300. }
  301. if (parameters.size() == 0) {
  302. return ResultInvalidArgument;
  303. }
  304. const auto unknown = parameters[0].sector_key.unknown;
  305. for (std::size_t i = 0; i < parameters.size(); i++) {
  306. if (unknown != parameters[i].sector_key.unknown) {
  307. return ResultInvalidArgument;
  308. }
  309. }
  310. Common::Input::MifareRequest request{};
  311. for (std::size_t i = 0; i < parameters.size(); i++) {
  312. if (parameters[i].sector_key.command == MifareCmd::None) {
  313. continue;
  314. }
  315. request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
  316. request.data[i].sector = parameters[i].sector_number;
  317. memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
  318. sizeof(KeyData));
  319. memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData));
  320. }
  321. if (!npad_device->WriteMifareData(request)) {
  322. return ResultMifareError288;
  323. }
  324. return result;
  325. }
  326. Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
  327. std::span<const u8> command_data,
  328. std::span<u8> out_data) {
  329. // Not implemented
  330. return ResultSuccess;
  331. }
  332. Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
  333. bool is_corrupted = false;
  334. if (model_type != NFP::ModelType::Amiibo) {
  335. return ResultInvalidArgument;
  336. }
  337. if (device_state != DeviceState::TagFound) {
  338. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  339. return ResultWrongDeviceState;
  340. }
  341. if (!LoadAmiiboData()) {
  342. LOG_ERROR(Service_NFP, "Not an amiibo");
  343. return ResultInvalidTagType;
  344. }
  345. if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
  346. LOG_ERROR(Service_NFP, "Not an amiibo");
  347. return ResultInvalidTagType;
  348. }
  349. // The loaded amiibo is not encrypted
  350. if (is_plain_amiibo) {
  351. std::vector<u8> data(sizeof(NFP::NTAG215File));
  352. memcpy(data.data(), &tag_data, sizeof(tag_data));
  353. }
  354. if (!is_plain_amiibo && !NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
  355. LOG_ERROR(Service_NFP, "Can't decode amiibo");
  356. is_corrupted = true;
  357. }
  358. if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) {
  359. LOG_ERROR(Service_NFP, "Invalid mii data");
  360. is_corrupted = true;
  361. }
  362. device_state = DeviceState::TagMounted;
  363. mount_target = mount_target_;
  364. if (!is_corrupted && mount_target != NFP::MountTarget::Rom) {
  365. std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
  366. memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
  367. WriteBackupData(encrypted_tag_data.uuid, data);
  368. }
  369. if (is_corrupted && mount_target != NFP::MountTarget::Rom) {
  370. bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
  371. return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
  372. }
  373. return ResultSuccess;
  374. }
  375. Result NfcDevice::Unmount() {
  376. if (device_state != DeviceState::TagMounted) {
  377. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  378. if (device_state == DeviceState::TagRemoved) {
  379. return ResultTagRemoved;
  380. }
  381. return ResultWrongDeviceState;
  382. }
  383. // Save data before unloading the amiibo
  384. if (is_data_moddified) {
  385. Flush();
  386. }
  387. device_state = DeviceState::TagFound;
  388. mount_target = NFP::MountTarget::None;
  389. is_app_area_open = false;
  390. return ResultSuccess;
  391. }
  392. Result NfcDevice::Flush() {
  393. if (device_state != DeviceState::TagMounted) {
  394. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  395. if (device_state == DeviceState::TagRemoved) {
  396. return ResultTagRemoved;
  397. }
  398. return ResultWrongDeviceState;
  399. }
  400. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  401. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  402. return ResultWrongDeviceState;
  403. }
  404. auto& settings = tag_data.settings;
  405. const auto& current_date = GetAmiiboDate(GetCurrentPosixTime());
  406. if (settings.write_date.raw_date != current_date.raw_date) {
  407. settings.write_date = current_date;
  408. UpdateSettingsCrc();
  409. }
  410. tag_data.write_counter++;
  411. const auto result = FlushWithBreak(NFP::BreakType::Normal);
  412. is_data_moddified = false;
  413. return result;
  414. }
  415. Result NfcDevice::FlushDebug() {
  416. if (device_state != DeviceState::TagMounted) {
  417. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  418. if (device_state == DeviceState::TagRemoved) {
  419. return ResultTagRemoved;
  420. }
  421. return ResultWrongDeviceState;
  422. }
  423. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  424. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  425. return ResultWrongDeviceState;
  426. }
  427. tag_data.write_counter++;
  428. const auto result = FlushWithBreak(NFP::BreakType::Normal);
  429. is_data_moddified = false;
  430. return result;
  431. }
  432. Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
  433. if (break_type != NFP::BreakType::Normal) {
  434. LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
  435. return ResultWrongDeviceState;
  436. }
  437. if (is_write_protected) {
  438. LOG_ERROR(Service_NFP, "No keys available skipping write request");
  439. return ResultSuccess;
  440. }
  441. std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
  442. if (is_plain_amiibo) {
  443. memcpy(data.data(), &tag_data, sizeof(tag_data));
  444. WriteBackupData(tag_data.uid, data);
  445. } else {
  446. if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
  447. LOG_ERROR(Service_NFP, "Failed to encode data");
  448. return ResultWriteAmiiboFailed;
  449. }
  450. memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
  451. WriteBackupData(encrypted_tag_data.uuid, data);
  452. }
  453. if (!npad_device->WriteNfc(data)) {
  454. LOG_ERROR(Service_NFP, "Error writing to file");
  455. return ResultWriteAmiiboFailed;
  456. }
  457. return ResultSuccess;
  458. }
  459. Result NfcDevice::Restore() {
  460. if (device_state != DeviceState::TagFound) {
  461. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  462. if (device_state == DeviceState::TagRemoved) {
  463. return ResultTagRemoved;
  464. }
  465. return ResultWrongDeviceState;
  466. }
  467. NFC::TagInfo tag_info{};
  468. std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
  469. Result result = GetTagInfo(tag_info);
  470. if (result.IsError()) {
  471. return result;
  472. }
  473. result = ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
  474. if (result.IsError()) {
  475. return result;
  476. }
  477. NFP::NTAG215File temporary_tag_data{};
  478. NFP::EncryptedNTAG215File temporary_encrypted_tag_data{};
  479. // Fallback for encrypted amiibos without keys
  480. if (is_write_protected) {
  481. return ResultWriteAmiiboFailed;
  482. }
  483. // Fallback for plain amiibos
  484. if (is_plain_amiibo) {
  485. LOG_INFO(Service_NFP, "Restoring backup of plain amiibo");
  486. memcpy(&temporary_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
  487. temporary_encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(temporary_tag_data);
  488. }
  489. if (!is_plain_amiibo) {
  490. LOG_INFO(Service_NFP, "Restoring backup of encrypted amiibo");
  491. temporary_tag_data = {};
  492. memcpy(&temporary_encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
  493. }
  494. if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
  495. return ResultInvalidTagType;
  496. }
  497. if (!is_plain_amiibo) {
  498. if (!NFP::AmiiboCrypto::DecodeAmiibo(temporary_encrypted_tag_data, temporary_tag_data)) {
  499. LOG_ERROR(Service_NFP, "Can't decode amiibo");
  500. return ResultCorruptedData;
  501. }
  502. }
  503. // Restore mii data in case is corrupted by previous instances of yuzu
  504. if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) {
  505. LOG_ERROR(Service_NFP, "Regenerating mii data");
  506. Mii::StoreData new_mii{};
  507. new_mii.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All);
  508. new_mii.SetNickname({u'y', u'u', u'z', u'u', u'\0'});
  509. tag_data.owner_mii.BuildFromStoreData(new_mii);
  510. tag_data.mii_extension.SetFromStoreData(new_mii);
  511. }
  512. // Overwrite tag contents with backup and mount the tag
  513. tag_data = temporary_tag_data;
  514. encrypted_tag_data = temporary_encrypted_tag_data;
  515. device_state = DeviceState::TagMounted;
  516. mount_target = NFP::MountTarget::All;
  517. is_data_moddified = true;
  518. return ResultSuccess;
  519. }
  520. Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
  521. if (device_state != DeviceState::TagMounted) {
  522. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  523. if (device_state == DeviceState::TagRemoved) {
  524. return ResultTagRemoved;
  525. }
  526. return ResultWrongDeviceState;
  527. }
  528. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  529. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  530. return ResultWrongDeviceState;
  531. }
  532. const auto& settings = tag_data.settings;
  533. // TODO: Validate this data
  534. common_info = {
  535. .last_write_date = settings.write_date.GetWriteDate(),
  536. .write_counter = tag_data.application_write_counter,
  537. .version = tag_data.amiibo_version,
  538. .application_area_size = sizeof(NFP::ApplicationArea),
  539. };
  540. return ResultSuccess;
  541. }
  542. Result NfcDevice::GetModelInfo(NFP::ModelInfo& model_info) const {
  543. if (device_state != DeviceState::TagMounted) {
  544. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  545. if (device_state == DeviceState::TagRemoved) {
  546. return ResultTagRemoved;
  547. }
  548. return ResultWrongDeviceState;
  549. }
  550. const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
  551. model_info = {
  552. .character_id = model_info_data.character_id,
  553. .character_variant = model_info_data.character_variant,
  554. .amiibo_type = model_info_data.amiibo_type,
  555. .model_number = model_info_data.model_number,
  556. .series = model_info_data.series,
  557. };
  558. return ResultSuccess;
  559. }
  560. Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
  561. if (device_state != DeviceState::TagMounted) {
  562. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  563. if (device_state == DeviceState::TagRemoved) {
  564. return ResultTagRemoved;
  565. }
  566. return ResultWrongDeviceState;
  567. }
  568. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  569. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  570. return ResultWrongDeviceState;
  571. }
  572. if (tag_data.settings.settings.amiibo_initialized == 0) {
  573. return ResultRegistrationIsNotInitialized;
  574. }
  575. Mii::CharInfo char_info{};
  576. Mii::StoreData store_data{};
  577. tag_data.owner_mii.BuildToStoreData(store_data);
  578. char_info.SetFromStoreData(store_data);
  579. const auto& settings = tag_data.settings;
  580. // TODO: Validate this data
  581. register_info = {
  582. .mii_char_info = char_info,
  583. .creation_date = settings.init_date.GetWriteDate(),
  584. .amiibo_name = GetAmiiboName(settings),
  585. .font_region = settings.settings.font_region,
  586. };
  587. return ResultSuccess;
  588. }
  589. Result NfcDevice::GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const {
  590. if (device_state != DeviceState::TagMounted) {
  591. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  592. if (device_state == DeviceState::TagRemoved) {
  593. return ResultTagRemoved;
  594. }
  595. return ResultWrongDeviceState;
  596. }
  597. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  598. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  599. return ResultWrongDeviceState;
  600. }
  601. if (tag_data.settings.settings.amiibo_initialized == 0) {
  602. return ResultRegistrationIsNotInitialized;
  603. }
  604. Mii::StoreData store_data{};
  605. const auto& settings = tag_data.settings;
  606. tag_data.owner_mii.BuildToStoreData(store_data);
  607. // TODO: Validate and complete this data
  608. register_info = {
  609. .mii_store_data = store_data,
  610. .creation_date = settings.init_date.GetWriteDate(),
  611. .amiibo_name = GetAmiiboName(settings),
  612. .font_region = settings.settings.font_region,
  613. };
  614. return ResultSuccess;
  615. }
  616. Result NfcDevice::GetAdminInfo(NFP::AdminInfo& admin_info) const {
  617. if (device_state != DeviceState::TagMounted) {
  618. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  619. if (device_state == DeviceState::TagRemoved) {
  620. return ResultTagRemoved;
  621. }
  622. return ResultWrongDeviceState;
  623. }
  624. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  625. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  626. return ResultWrongDeviceState;
  627. }
  628. u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4);
  629. if (tag_data.settings.settings.amiibo_initialized == 0) {
  630. flags = flags & 0xfe;
  631. }
  632. u64 application_id = 0;
  633. u32 application_area_id = 0;
  634. NFP::AppAreaVersion app_area_version = NFP::AppAreaVersion::NotSet;
  635. if (tag_data.settings.settings.appdata_initialized != 0) {
  636. application_id = tag_data.application_id;
  637. app_area_version = static_cast<NFP::AppAreaVersion>(
  638. application_id >> NFP::application_id_version_offset & 0xf);
  639. // Restore application id to original value
  640. if (application_id >> 0x38 != 0) {
  641. const u8 application_byte = tag_data.application_id_byte & 0xf;
  642. application_id =
  643. RemoveVersionByte(application_id) |
  644. (static_cast<u64>(application_byte) << NFP::application_id_version_offset);
  645. }
  646. application_area_id = tag_data.application_area_id;
  647. }
  648. // TODO: Validate this data
  649. admin_info = {
  650. .application_id = application_id,
  651. .application_area_id = application_area_id,
  652. .crc_change_counter = tag_data.settings.crc_counter,
  653. .flags = flags,
  654. .tag_type = PackedTagType::Type2,
  655. .app_area_version = app_area_version,
  656. };
  657. return ResultSuccess;
  658. }
  659. Result NfcDevice::DeleteRegisterInfo() {
  660. if (device_state != DeviceState::TagMounted) {
  661. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  662. if (device_state == DeviceState::TagRemoved) {
  663. return ResultTagRemoved;
  664. }
  665. return ResultWrongDeviceState;
  666. }
  667. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  668. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  669. return ResultWrongDeviceState;
  670. }
  671. if (tag_data.settings.settings.amiibo_initialized == 0) {
  672. return ResultRegistrationIsNotInitialized;
  673. }
  674. Common::TinyMT rng{};
  675. rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
  676. rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii));
  677. rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name));
  678. rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));
  679. rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32));
  680. rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32));
  681. rng.GenerateRandomBytes(&tag_data.register_info_crc, sizeof(u32));
  682. rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32));
  683. tag_data.settings.settings.font_region.Assign(0);
  684. tag_data.settings.settings.amiibo_initialized.Assign(0);
  685. return Flush();
  686. }
  687. Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info) {
  688. if (device_state != DeviceState::TagMounted) {
  689. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  690. if (device_state == DeviceState::TagRemoved) {
  691. return ResultTagRemoved;
  692. }
  693. return ResultWrongDeviceState;
  694. }
  695. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  696. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  697. return ResultWrongDeviceState;
  698. }
  699. auto& settings = tag_data.settings;
  700. if (tag_data.settings.settings.amiibo_initialized == 0) {
  701. settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
  702. settings.write_date.raw_date = 0;
  703. }
  704. SetAmiiboName(settings, register_info.amiibo_name);
  705. tag_data.owner_mii.BuildFromStoreData(register_info.mii_store_data);
  706. tag_data.mii_extension.SetFromStoreData(register_info.mii_store_data);
  707. tag_data.unknown = 0;
  708. tag_data.unknown2 = {};
  709. settings.country_code_id = 0;
  710. settings.settings.font_region.Assign(0);
  711. settings.settings.amiibo_initialized.Assign(1);
  712. UpdateRegisterInfoCrc();
  713. return Flush();
  714. }
  715. Result NfcDevice::Format() {
  716. Result result = ResultSuccess;
  717. if (device_state == DeviceState::TagFound) {
  718. result = Mount(NFP::ModelType::Amiibo, NFP::MountTarget::All);
  719. }
  720. // We are formatting all data. Corruption is not an issue.
  721. if (result.IsError() &&
  722. (result != ResultCorruptedData && result != ResultCorruptedDataWithBackup)) {
  723. return result;
  724. }
  725. DeleteApplicationArea();
  726. DeleteRegisterInfo();
  727. return Flush();
  728. }
  729. Result NfcDevice::OpenApplicationArea(u32 access_id) {
  730. if (device_state != DeviceState::TagMounted) {
  731. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  732. if (device_state == DeviceState::TagRemoved) {
  733. return ResultTagRemoved;
  734. }
  735. return ResultWrongDeviceState;
  736. }
  737. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  738. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  739. return ResultWrongDeviceState;
  740. }
  741. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  742. LOG_WARNING(Service_NFP, "Application area is not initialized");
  743. return ResultApplicationAreaIsNotInitialized;
  744. }
  745. if (tag_data.application_area_id != access_id) {
  746. LOG_WARNING(Service_NFP, "Wrong application area id");
  747. return ResultWrongApplicationAreaId;
  748. }
  749. is_app_area_open = true;
  750. return ResultSuccess;
  751. }
  752. Result NfcDevice::GetApplicationAreaId(u32& application_area_id) const {
  753. application_area_id = {};
  754. if (device_state != DeviceState::TagMounted) {
  755. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  756. if (device_state == DeviceState::TagRemoved) {
  757. return ResultTagRemoved;
  758. }
  759. return ResultWrongDeviceState;
  760. }
  761. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  762. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  763. return ResultWrongDeviceState;
  764. }
  765. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  766. LOG_WARNING(Service_NFP, "Application area is not initialized");
  767. return ResultApplicationAreaIsNotInitialized;
  768. }
  769. application_area_id = tag_data.application_area_id;
  770. return ResultSuccess;
  771. }
  772. Result NfcDevice::GetApplicationArea(std::span<u8> data) const {
  773. if (device_state != DeviceState::TagMounted) {
  774. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  775. if (device_state == DeviceState::TagRemoved) {
  776. return ResultTagRemoved;
  777. }
  778. return ResultWrongDeviceState;
  779. }
  780. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  781. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  782. return ResultWrongDeviceState;
  783. }
  784. if (!is_app_area_open) {
  785. LOG_ERROR(Service_NFP, "Application area is not open");
  786. return ResultWrongDeviceState;
  787. }
  788. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  789. LOG_ERROR(Service_NFP, "Application area is not initialized");
  790. return ResultApplicationAreaIsNotInitialized;
  791. }
  792. memcpy(data.data(), tag_data.application_area.data(),
  793. std::min(data.size(), sizeof(NFP::ApplicationArea)));
  794. return ResultSuccess;
  795. }
  796. Result NfcDevice::SetApplicationArea(std::span<const u8> data) {
  797. if (device_state != DeviceState::TagMounted) {
  798. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  799. if (device_state == DeviceState::TagRemoved) {
  800. return ResultTagRemoved;
  801. }
  802. return ResultWrongDeviceState;
  803. }
  804. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  805. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  806. return ResultWrongDeviceState;
  807. }
  808. if (!is_app_area_open) {
  809. LOG_ERROR(Service_NFP, "Application area is not open");
  810. return ResultWrongDeviceState;
  811. }
  812. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  813. LOG_ERROR(Service_NFP, "Application area is not initialized");
  814. return ResultApplicationAreaIsNotInitialized;
  815. }
  816. if (data.size() > sizeof(NFP::ApplicationArea)) {
  817. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  818. return ResultUnknown;
  819. }
  820. Common::TinyMT rng{};
  821. rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
  822. std::memcpy(tag_data.application_area.data(), data.data(), data.size());
  823. // Fill remaining data with random numbers
  824. rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
  825. sizeof(NFP::ApplicationArea) - data.size());
  826. if (tag_data.application_write_counter != NFP::counter_limit) {
  827. tag_data.application_write_counter++;
  828. }
  829. is_data_moddified = true;
  830. return ResultSuccess;
  831. }
  832. Result NfcDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
  833. if (device_state != DeviceState::TagMounted) {
  834. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  835. if (device_state == DeviceState::TagRemoved) {
  836. return ResultTagRemoved;
  837. }
  838. return ResultWrongDeviceState;
  839. }
  840. if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
  841. LOG_ERROR(Service_NFP, "Application area already exist");
  842. return ResultApplicationAreaExist;
  843. }
  844. return RecreateApplicationArea(access_id, data);
  845. }
  846. Result NfcDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
  847. if (device_state != DeviceState::TagMounted) {
  848. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  849. if (device_state == DeviceState::TagRemoved) {
  850. return ResultTagRemoved;
  851. }
  852. return ResultWrongDeviceState;
  853. }
  854. if (is_app_area_open) {
  855. LOG_ERROR(Service_NFP, "Application area is open");
  856. return ResultWrongDeviceState;
  857. }
  858. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  859. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  860. return ResultWrongDeviceState;
  861. }
  862. if (data.size() > sizeof(NFP::ApplicationArea)) {
  863. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  864. return ResultWrongApplicationAreaSize;
  865. }
  866. Common::TinyMT rng{};
  867. rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
  868. std::memcpy(tag_data.application_area.data(), data.data(), data.size());
  869. // Fill remaining data with random numbers
  870. rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
  871. sizeof(NFP::ApplicationArea) - data.size());
  872. if (tag_data.application_write_counter != NFP::counter_limit) {
  873. tag_data.application_write_counter++;
  874. }
  875. const u64 application_id = system.GetApplicationProcessProgramID();
  876. tag_data.application_id_byte =
  877. static_cast<u8>(application_id >> NFP::application_id_version_offset & 0xf);
  878. tag_data.application_id =
  879. RemoveVersionByte(application_id) | (static_cast<u64>(NFP::AppAreaVersion::NintendoSwitch)
  880. << NFP::application_id_version_offset);
  881. tag_data.settings.settings.appdata_initialized.Assign(1);
  882. tag_data.application_area_id = access_id;
  883. tag_data.unknown = {};
  884. tag_data.unknown2 = {};
  885. UpdateRegisterInfoCrc();
  886. return Flush();
  887. }
  888. Result NfcDevice::DeleteApplicationArea() {
  889. if (device_state != DeviceState::TagMounted) {
  890. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  891. if (device_state == DeviceState::TagRemoved) {
  892. return ResultTagRemoved;
  893. }
  894. return ResultWrongDeviceState;
  895. }
  896. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  897. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  898. return ResultWrongDeviceState;
  899. }
  900. if (tag_data.settings.settings.appdata_initialized == 0) {
  901. return ResultApplicationAreaIsNotInitialized;
  902. }
  903. if (tag_data.application_write_counter != NFP::counter_limit) {
  904. tag_data.application_write_counter++;
  905. }
  906. Common::TinyMT rng{};
  907. rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
  908. rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea));
  909. rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64));
  910. rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
  911. rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
  912. tag_data.settings.settings.appdata_initialized.Assign(0);
  913. tag_data.unknown = {};
  914. tag_data.unknown2 = {};
  915. is_app_area_open = false;
  916. UpdateRegisterInfoCrc();
  917. return Flush();
  918. }
  919. Result NfcDevice::ExistsApplicationArea(bool& has_application_area) const {
  920. if (device_state != DeviceState::TagMounted) {
  921. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  922. if (device_state == DeviceState::TagRemoved) {
  923. return ResultTagRemoved;
  924. }
  925. return ResultWrongDeviceState;
  926. }
  927. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  928. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  929. return ResultWrongDeviceState;
  930. }
  931. has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0;
  932. return ResultSuccess;
  933. }
  934. Result NfcDevice::GetAll(NFP::NfpData& data) const {
  935. if (device_state != DeviceState::TagMounted) {
  936. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  937. if (device_state == DeviceState::TagRemoved) {
  938. return ResultTagRemoved;
  939. }
  940. return ResultWrongDeviceState;
  941. }
  942. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  943. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  944. return ResultWrongDeviceState;
  945. }
  946. NFP::CommonInfo common_info{};
  947. const u64 application_id = tag_data.application_id;
  948. GetCommonInfo(common_info);
  949. data = {
  950. .magic = tag_data.constant_value,
  951. .write_counter = tag_data.write_counter,
  952. .settings_crc = tag_data.settings.crc,
  953. .common_info = common_info,
  954. .mii_char_info = tag_data.owner_mii,
  955. .mii_store_data_extension = tag_data.mii_extension,
  956. .creation_date = tag_data.settings.init_date.GetWriteDate(),
  957. .amiibo_name = tag_data.settings.amiibo_name,
  958. .amiibo_name_null_terminated = 0,
  959. .settings = tag_data.settings.settings,
  960. .unknown1 = tag_data.unknown,
  961. .register_info_crc = tag_data.register_info_crc,
  962. .unknown2 = tag_data.unknown2,
  963. .application_id = application_id,
  964. .access_id = tag_data.application_area_id,
  965. .settings_crc_counter = tag_data.settings.crc_counter,
  966. .font_region = tag_data.settings.settings.font_region,
  967. .tag_type = PackedTagType::Type2,
  968. .console_type = static_cast<NFP::AppAreaVersion>(
  969. application_id >> NFP::application_id_version_offset & 0xf),
  970. .application_id_byte = tag_data.application_id_byte,
  971. .application_area = tag_data.application_area,
  972. };
  973. return ResultSuccess;
  974. }
  975. Result NfcDevice::SetAll(const NFP::NfpData& data) {
  976. if (device_state != DeviceState::TagMounted) {
  977. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  978. if (device_state == DeviceState::TagRemoved) {
  979. return ResultTagRemoved;
  980. }
  981. return ResultWrongDeviceState;
  982. }
  983. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  984. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  985. return ResultWrongDeviceState;
  986. }
  987. tag_data.constant_value = data.magic;
  988. tag_data.write_counter = data.write_counter;
  989. tag_data.settings.crc = data.settings_crc;
  990. tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date);
  991. tag_data.write_counter = data.common_info.write_counter;
  992. tag_data.amiibo_version = data.common_info.version;
  993. tag_data.owner_mii = data.mii_char_info;
  994. tag_data.mii_extension = data.mii_store_data_extension;
  995. tag_data.settings.init_date.SetWriteDate(data.creation_date);
  996. tag_data.settings.amiibo_name = data.amiibo_name;
  997. tag_data.settings.settings = data.settings;
  998. tag_data.unknown = data.unknown1;
  999. tag_data.register_info_crc = data.register_info_crc;
  1000. tag_data.unknown2 = data.unknown2;
  1001. tag_data.application_id = data.application_id;
  1002. tag_data.application_area_id = data.access_id;
  1003. tag_data.settings.crc_counter = data.settings_crc_counter;
  1004. tag_data.settings.settings.font_region.Assign(data.font_region);
  1005. tag_data.application_id_byte = data.application_id_byte;
  1006. tag_data.application_area = data.application_area;
  1007. return ResultSuccess;
  1008. }
  1009. Result NfcDevice::BreakTag(NFP::BreakType break_type) {
  1010. if (device_state != DeviceState::TagMounted) {
  1011. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  1012. if (device_state == DeviceState::TagRemoved) {
  1013. return ResultTagRemoved;
  1014. }
  1015. return ResultWrongDeviceState;
  1016. }
  1017. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  1018. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  1019. return ResultWrongDeviceState;
  1020. }
  1021. // TODO: Complete this implementation
  1022. return FlushWithBreak(break_type);
  1023. }
  1024. Result NfcDevice::HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const {
  1025. ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
  1026. constexpr auto backup_dir = "backup";
  1027. const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
  1028. const auto file_name =
  1029. fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
  1030. if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
  1031. return ResultUnableToAccessBackupFile;
  1032. }
  1033. return ResultSuccess;
  1034. }
  1035. Result NfcDevice::HasBackup(const NFP::TagUuid& tag_uid) const {
  1036. UniqueSerialNumber uuid{};
  1037. memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
  1038. return HasBackup(uuid, sizeof(NFP::TagUuid));
  1039. }
  1040. Result NfcDevice::ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
  1041. std::span<u8> data) const {
  1042. ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
  1043. constexpr auto backup_dir = "backup";
  1044. const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
  1045. const auto file_name =
  1046. fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
  1047. const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
  1048. Common::FS::FileAccessMode::Read,
  1049. Common::FS::FileType::BinaryFile};
  1050. if (!keys_file.IsOpen()) {
  1051. LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
  1052. return ResultUnableToAccessBackupFile;
  1053. }
  1054. if (keys_file.Read(data) != data.size()) {
  1055. LOG_ERROR(Service_NFP, "Failed to read amiibo backup");
  1056. return ResultUnableToAccessBackupFile;
  1057. }
  1058. return ResultSuccess;
  1059. }
  1060. Result NfcDevice::ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const {
  1061. UniqueSerialNumber uuid{};
  1062. memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
  1063. return ReadBackupData(uuid, sizeof(NFP::TagUuid), data);
  1064. }
  1065. Result NfcDevice::WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
  1066. std::span<const u8> data) {
  1067. ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
  1068. constexpr auto backup_dir = "backup";
  1069. const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
  1070. const auto file_name =
  1071. fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
  1072. if (HasBackup(uid, uuid_size).IsError()) {
  1073. if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
  1074. return ResultBackupPathAlreadyExist;
  1075. }
  1076. if (!Common::FS::NewFile(yuzu_amiibo_dir / backup_dir / file_name)) {
  1077. return ResultBackupPathAlreadyExist;
  1078. }
  1079. }
  1080. const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
  1081. Common::FS::FileAccessMode::ReadWrite,
  1082. Common::FS::FileType::BinaryFile};
  1083. if (!keys_file.IsOpen()) {
  1084. LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
  1085. return ResultUnableToAccessBackupFile;
  1086. }
  1087. if (keys_file.Write(data) != data.size()) {
  1088. LOG_ERROR(Service_NFP, "Failed to write amiibo backup");
  1089. return ResultUnableToAccessBackupFile;
  1090. }
  1091. return ResultSuccess;
  1092. }
  1093. Result NfcDevice::WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data) {
  1094. UniqueSerialNumber uuid{};
  1095. memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
  1096. return WriteBackupData(uuid, sizeof(NFP::TagUuid), data);
  1097. }
  1098. Result NfcDevice::WriteNtf(std::span<const u8> data) {
  1099. if (device_state != DeviceState::TagMounted) {
  1100. LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
  1101. if (device_state == DeviceState::TagRemoved) {
  1102. return ResultTagRemoved;
  1103. }
  1104. return ResultWrongDeviceState;
  1105. }
  1106. if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
  1107. LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
  1108. return ResultWrongDeviceState;
  1109. }
  1110. // Not implemented
  1111. return ResultSuccess;
  1112. }
  1113. NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) const {
  1114. std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
  1115. NFP::AmiiboName amiibo_name{};
  1116. // Convert from big endian to little endian
  1117. for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
  1118. settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
  1119. }
  1120. // Convert from utf16 to utf8
  1121. const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data());
  1122. memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size());
  1123. return amiibo_name;
  1124. }
  1125. void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
  1126. const NFP::AmiiboName& amiibo_name) const {
  1127. std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
  1128. // Convert from utf8 to utf16
  1129. const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
  1130. memcpy(settings_amiibo_name.data(), amiibo_name_utf16.data(),
  1131. amiibo_name_utf16.size() * sizeof(char16_t));
  1132. // Convert from little endian to big endian
  1133. for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
  1134. settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
  1135. }
  1136. }
  1137. NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
  1138. const auto& time_zone_manager =
  1139. system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
  1140. Time::TimeZone::CalendarInfo calendar_info{};
  1141. NFP::AmiiboDate amiibo_date{};
  1142. amiibo_date.SetYear(2000);
  1143. amiibo_date.SetMonth(1);
  1144. amiibo_date.SetDay(1);
  1145. if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
  1146. amiibo_date.SetYear(calendar_info.time.year);
  1147. amiibo_date.SetMonth(calendar_info.time.month);
  1148. amiibo_date.SetDay(calendar_info.time.day);
  1149. }
  1150. return amiibo_date;
  1151. }
  1152. u64 NfcDevice::GetCurrentPosixTime() const {
  1153. auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
  1154. return standard_steady_clock.GetCurrentTimePoint(system).time_point;
  1155. }
  1156. u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
  1157. return application_id & ~(0xfULL << NFP::application_id_version_offset);
  1158. }
  1159. void NfcDevice::UpdateSettingsCrc() {
  1160. auto& settings = tag_data.settings;
  1161. if (settings.crc_counter != NFP::counter_limit) {
  1162. settings.crc_counter++;
  1163. }
  1164. // TODO: this reads data from a global, find what it is
  1165. std::array<u8, 8> unknown_input{};
  1166. boost::crc_32_type crc;
  1167. crc.process_bytes(&unknown_input, sizeof(unknown_input));
  1168. settings.crc = crc.checksum();
  1169. }
  1170. void NfcDevice::UpdateRegisterInfoCrc() {
  1171. #pragma pack(push, 1)
  1172. struct CrcData {
  1173. Mii::Ver3StoreData mii;
  1174. u8 application_id_byte;
  1175. u8 unknown;
  1176. Mii::NfpStoreDataExtension mii_extension;
  1177. std::array<u32, 0x5> unknown2;
  1178. };
  1179. static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size");
  1180. #pragma pack(pop)
  1181. const CrcData crc_data{
  1182. .mii = tag_data.owner_mii,
  1183. .application_id_byte = tag_data.application_id_byte,
  1184. .unknown = tag_data.unknown,
  1185. .mii_extension = tag_data.mii_extension,
  1186. .unknown2 = tag_data.unknown2,
  1187. };
  1188. boost::crc_32_type crc;
  1189. crc.process_bytes(&crc_data, sizeof(CrcData));
  1190. tag_data.register_info_crc = crc.checksum();
  1191. }
  1192. void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
  1193. const NFP::EncryptedNTAG215File& encrypted_file) const {
  1194. Service::Mii::StoreData store_data{};
  1195. auto& settings = stubbed_tag_data.settings;
  1196. stubbed_tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_file);
  1197. // Common info
  1198. stubbed_tag_data.write_counter = 0;
  1199. stubbed_tag_data.amiibo_version = 0;
  1200. settings.write_date = GetAmiiboDate(GetCurrentPosixTime());
  1201. // Register info
  1202. SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
  1203. settings.settings.font_region.Assign(0);
  1204. settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
  1205. store_data.BuildBase(Mii::Gender::Male);
  1206. stubbed_tag_data.owner_mii.BuildFromStoreData(store_data);
  1207. // Admin info
  1208. settings.settings.amiibo_initialized.Assign(1);
  1209. settings.settings.appdata_initialized.Assign(0);
  1210. }
  1211. u64 NfcDevice::GetHandle() const {
  1212. // Generate a handle based of the npad id
  1213. return static_cast<u64>(npad_id);
  1214. }
  1215. DeviceState NfcDevice::GetCurrentState() const {
  1216. return device_state;
  1217. }
  1218. Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
  1219. // TODO: This should get the npad id from nn::hid::system::GetXcdHandleForNpadWithNfc
  1220. out_npad_id = npad_id;
  1221. return ResultSuccess;
  1222. }
  1223. } // namespace Service::NFC