device.cpp 50 KB

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