diff options
Diffstat (limited to 'src/core/hle/service/nfp/nfp_device.cpp')
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.cpp | 1137 |
1 files changed, 0 insertions, 1137 deletions
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp deleted file mode 100644 index 3f9af53c8..000000000 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ /dev/null @@ -1,1137 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <array> - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used -#endif - -#include <boost/crc.hpp> - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#include "common/input.h" -#include "common/logging/log.h" -#include "common/string_util.h" -#include "common/tiny_mt.h" -#include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/mii/mii_manager.h" -#include "core/hle/service/mii/types.h" -#include "core/hle/service/nfp/amiibo_crypto.h" -#include "core/hle/service/nfp/nfp_device.h" -#include "core/hle/service/nfp/nfp_result.h" -#include "core/hle/service/time/time_manager.h" -#include "core/hle/service/time/time_zone_content_manager.h" -#include "core/hle/service/time/time_zone_types.h" - -namespace Service::NFP { -NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, - KernelHelpers::ServiceContext& service_context_, - Kernel::KEvent* availability_change_event_) - : npad_id{npad_id_}, system{system_}, service_context{service_context_}, - availability_change_event{availability_change_event_} { - activate_event = service_context.CreateEvent("IUser:NFPActivateEvent"); - deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent"); - npad_device = system.HIDCore().GetEmulatedController(npad_id); - - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); }, - .is_npad_service = false, - }; - is_controller_set = true; - callback_key = npad_device->SetCallback(engine_callback); - - auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; - current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point; -} - -NfpDevice::~NfpDevice() { - activate_event->Close(); - deactivate_event->Close(); - if (!is_controller_set) { - return; - } - npad_device->DeleteCallback(callback_key); - is_controller_set = false; -}; - -void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { - if (!is_initalized) { - return; - } - - if (type == Core::HID::ControllerTriggerType::Connected) { - Initialize(); - availability_change_event->Signal(); - return; - } - - if (type == Core::HID::ControllerTriggerType::Disconnected) { - device_state = DeviceState::Unavailable; - availability_change_event->Signal(); - return; - } - - if (type != Core::HID::ControllerTriggerType::Nfc) { - return; - } - - if (!npad_device->IsConnected()) { - return; - } - - const auto nfc_status = npad_device->GetNfc(); - switch (nfc_status.state) { - case Common::Input::NfcState::NewAmiibo: - LoadAmiibo(nfc_status.data); - break; - case Common::Input::NfcState::AmiiboRemoved: - if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { - break; - } - if (device_state != DeviceState::SearchingForTag) { - CloseAmiibo(); - } - break; - default: - break; - } -} - -bool NfpDevice::LoadAmiibo(std::span<const u8> data) { - if (device_state != DeviceState::SearchingForTag) { - LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state); - return false; - } - - if (data.size() != sizeof(EncryptedNTAG215File)) { - LOG_ERROR(Service_NFP, "Not an amiibo, size={}", data.size()); - return false; - } - - // TODO: Filter by allowed_protocols here - - memcpy(&tag_data, data.data(), sizeof(EncryptedNTAG215File)); - is_plain_amiibo = AmiiboCrypto::IsAmiiboValid(tag_data); - - if (is_plain_amiibo) { - encrypted_tag_data = AmiiboCrypto::EncodedDataToNfcData(tag_data); - LOG_INFO(Service_NFP, "Using plain amiibo"); - } else { - tag_data = {}; - memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); - } - - device_state = DeviceState::TagFound; - deactivate_event->GetReadableEvent().Clear(); - activate_event->Signal(); - return true; -} - -void NfpDevice::CloseAmiibo() { - LOG_INFO(Service_NFP, "Remove amiibo"); - - if (device_state == DeviceState::TagMounted) { - Unmount(); - } - - device_state = DeviceState::TagRemoved; - encrypted_tag_data = {}; - tag_data = {}; - activate_event->GetReadableEvent().Clear(); - deactivate_event->Signal(); -} - -Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const { - return activate_event->GetReadableEvent(); -} - -Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const { - return deactivate_event->GetReadableEvent(); -} - -void NfpDevice::Initialize() { - device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; - encrypted_tag_data = {}; - tag_data = {}; - is_initalized = true; -} - -void NfpDevice::Finalize() { - if (device_state == DeviceState::TagMounted) { - Unmount(); - } - if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { - StopDetection(); - } - device_state = DeviceState::Unavailable; - is_initalized = false; -} - -Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { - if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - return WrongDeviceState; - } - - if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::NFC) != - Common::Input::DriverResult::Success) { - LOG_ERROR(Service_NFP, "Nfc not supported"); - return NfcDisabled; - } - - device_state = DeviceState::SearchingForTag; - allowed_protocols = allowed_protocol; - return ResultSuccess; -} - -Result NfpDevice::StopDetection() { - npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::Active); - - if (device_state == DeviceState::Initialized) { - return ResultSuccess; - } - - if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { - CloseAmiibo(); - } - - if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { - device_state = DeviceState::Initialized; - return ResultSuccess; - } - - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - return WrongDeviceState; -} - -Result NfpDevice::Flush() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - auto& settings = tag_data.settings; - - const auto& current_date = GetAmiiboDate(current_posix_time); - if (settings.write_date.raw_date != current_date.raw_date) { - settings.write_date = current_date; - UpdateSettingsCrc(); - } - - tag_data.write_counter++; - - FlushWithBreak(BreakType::Normal); - - is_data_moddified = false; - - return ResultSuccess; -} - -Result NfpDevice::FlushDebug() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - tag_data.write_counter++; - - FlushWithBreak(BreakType::Normal); - - is_data_moddified = false; - - return ResultSuccess; -} - -Result NfpDevice::FlushWithBreak(BreakType break_type) { - if (break_type != BreakType::Normal) { - LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type); - return WrongDeviceState; - } - - std::vector<u8> data(sizeof(EncryptedNTAG215File)); - if (is_plain_amiibo) { - memcpy(data.data(), &tag_data, sizeof(tag_data)); - } else { - if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) { - LOG_ERROR(Service_NFP, "Failed to encode data"); - return WriteAmiiboFailed; - } - - memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); - } - - if (!npad_device->WriteNfc(data)) { - LOG_ERROR(Service_NFP, "Error writing to file"); - return WriteAmiiboFailed; - } - - return ResultSuccess; -} - -Result NfpDevice::Mount(MountTarget mount_target_) { - if (device_state != DeviceState::TagFound) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - return WrongDeviceState; - } - - // The loaded amiibo is not encrypted - if (is_plain_amiibo) { - device_state = DeviceState::TagMounted; - mount_target = mount_target_; - return ResultSuccess; - } - - if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { - LOG_ERROR(Service_NFP, "Not an amiibo"); - return NotAnAmiibo; - } - - // Mark amiibos as read only when keys are missing - if (!AmiiboCrypto::IsKeyAvailable()) { - LOG_ERROR(Service_NFP, "No keys detected"); - device_state = DeviceState::TagMounted; - mount_target = MountTarget::Rom; - return ResultSuccess; - } - - if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { - LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state); - return CorruptedData; - } - - device_state = DeviceState::TagMounted; - mount_target = mount_target_; - return ResultSuccess; -} - -Result NfpDevice::Unmount() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - // Save data before unloading the amiibo - if (is_data_moddified) { - Flush(); - } - - device_state = DeviceState::TagFound; - mount_target = MountTarget::None; - is_app_area_open = false; - - return ResultSuccess; -} - -Result NfpDevice::GetTagInfo(TagInfo& tag_info) const { - if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - tag_info = { - .uuid = encrypted_tag_data.uuid.uid, - .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), - .protocol = TagProtocol::TypeA, - .tag_type = TagType::Type2, - }; - - return ResultSuccess; -} - -Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - const auto& settings = tag_data.settings; - - // TODO: Validate this data - common_info = { - .last_write_date = settings.write_date.GetWriteDate(), - .write_counter = tag_data.write_counter, - .version = tag_data.amiibo_version, - .application_area_size = sizeof(ApplicationArea), - }; - return ResultSuccess; -} - -Result NfpDevice::GetModelInfo(ModelInfo& model_info) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - const auto& model_info_data = encrypted_tag_data.user_memory.model_info; - model_info = { - .character_id = model_info_data.character_id, - .character_variant = model_info_data.character_variant, - .amiibo_type = model_info_data.amiibo_type, - .model_number = model_info_data.model_number, - .series = model_info_data.series, - }; - return ResultSuccess; -} - -Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (tag_data.settings.settings.amiibo_initialized == 0) { - return RegistrationIsNotInitialized; - } - - Service::Mii::MiiManager manager; - const auto& settings = tag_data.settings; - - // TODO: Validate this data - register_info = { - .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii), - .creation_date = settings.init_date.GetWriteDate(), - .amiibo_name = GetAmiiboName(settings), - .font_region = settings.settings.font_region, - }; - - return ResultSuccess; -} - -Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (tag_data.settings.settings.amiibo_initialized == 0) { - return RegistrationIsNotInitialized; - } - - Service::Mii::MiiManager manager; - const auto& settings = tag_data.settings; - - // TODO: Validate and complete this data - register_info = { - .mii_store_data = {}, - .creation_date = settings.init_date.GetWriteDate(), - .amiibo_name = GetAmiiboName(settings), - .font_region = settings.settings.font_region, - }; - - return ResultSuccess; -} - -Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4); - if (tag_data.settings.settings.amiibo_initialized == 0) { - flags = flags & 0xfe; - } - - u64 application_id = 0; - u32 application_area_id = 0; - AppAreaVersion app_area_version = AppAreaVersion::NotSet; - if (tag_data.settings.settings.appdata_initialized != 0) { - application_id = tag_data.application_id; - app_area_version = - static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf); - - // Restore application id to original value - if (application_id >> 0x38 != 0) { - const u8 application_byte = tag_data.application_id_byte & 0xf; - application_id = RemoveVersionByte(application_id) | - (static_cast<u64>(application_byte) << application_id_version_offset); - } - - application_area_id = tag_data.application_area_id; - } - - // TODO: Validate this data - admin_info = { - .application_id = application_id, - .application_area_id = application_area_id, - .crc_change_counter = tag_data.settings.crc_counter, - .flags = flags, - .tag_type = PackedTagType::Type2, - .app_area_version = app_area_version, - }; - - return ResultSuccess; -} - -Result NfpDevice::DeleteRegisterInfo() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (tag_data.settings.settings.amiibo_initialized == 0) { - return RegistrationIsNotInitialized; - } - - Common::TinyMT rng{}; - rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii)); - rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name)); - rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8)); - rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32)); - rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32)); - rng.GenerateRandomBytes(&tag_data.register_info_crc, sizeof(u32)); - rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32)); - tag_data.settings.settings.font_region.Assign(0); - tag_data.settings.settings.amiibo_initialized.Assign(0); - - return Flush(); -} - -Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - Service::Mii::MiiManager manager; - const auto mii = manager.BuildDefault(0); - auto& settings = tag_data.settings; - - if (tag_data.settings.settings.amiibo_initialized == 0) { - settings.init_date = GetAmiiboDate(current_posix_time); - settings.write_date.raw_date = 0; - } - - SetAmiiboName(settings, amiibo_name); - tag_data.owner_mii = manager.BuildFromStoreData(mii); - tag_data.mii_extension = manager.SetFromStoreData(mii); - tag_data.unknown = 0; - tag_data.unknown2 = {}; - settings.country_code_id = 0; - settings.settings.font_region.Assign(0); - settings.settings.amiibo_initialized.Assign(1); - - UpdateRegisterInfoCrc(); - - return Flush(); -} - -Result NfpDevice::RestoreAmiibo() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - // TODO: Load amiibo from backup on system - LOG_ERROR(Service_NFP, "Not Implemented"); - return ResultSuccess; -} - -Result NfpDevice::Format() { - auto result1 = DeleteApplicationArea(); - auto result2 = DeleteRegisterInfo(); - - if (result1.IsError()) { - return result1; - } - - if (result2.IsError()) { - return result2; - } - - return Flush(); -} - -Result NfpDevice::OpenApplicationArea(u32 access_id) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (tag_data.settings.settings.appdata_initialized.Value() == 0) { - LOG_WARNING(Service_NFP, "Application area is not initialized"); - return ApplicationAreaIsNotInitialized; - } - - if (tag_data.application_area_id != access_id) { - LOG_WARNING(Service_NFP, "Wrong application area id"); - return WrongApplicationAreaId; - } - - is_app_area_open = true; - - return ResultSuccess; -} - -Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { - application_area_id = {}; - - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (tag_data.settings.settings.appdata_initialized.Value() == 0) { - LOG_WARNING(Service_NFP, "Application area is not initialized"); - return ApplicationAreaIsNotInitialized; - } - - application_area_id = tag_data.application_area_id; - - return ResultSuccess; -} - -Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (!is_app_area_open) { - LOG_ERROR(Service_NFP, "Application area is not open"); - return WrongDeviceState; - } - - if (tag_data.settings.settings.appdata_initialized.Value() == 0) { - LOG_ERROR(Service_NFP, "Application area is not initialized"); - return ApplicationAreaIsNotInitialized; - } - - if (data.size() > sizeof(ApplicationArea)) { - data.resize(sizeof(ApplicationArea)); - } - - memcpy(data.data(), tag_data.application_area.data(), data.size()); - - return ResultSuccess; -} - -Result NfpDevice::SetApplicationArea(std::span<const u8> data) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (!is_app_area_open) { - LOG_ERROR(Service_NFP, "Application area is not open"); - return WrongDeviceState; - } - - if (tag_data.settings.settings.appdata_initialized.Value() == 0) { - LOG_ERROR(Service_NFP, "Application area is not initialized"); - return ApplicationAreaIsNotInitialized; - } - - if (data.size() > sizeof(ApplicationArea)) { - LOG_ERROR(Service_NFP, "Wrong data size {}", data.size()); - return ResultUnknown; - } - - Common::TinyMT rng{}; - std::memcpy(tag_data.application_area.data(), data.data(), data.size()); - // Fill remaining data with random numbers - rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), - sizeof(ApplicationArea) - data.size()); - - if (tag_data.application_write_counter != counter_limit) { - tag_data.application_write_counter++; - } - - is_data_moddified = true; - - return ResultSuccess; -} - -Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (tag_data.settings.settings.appdata_initialized.Value() != 0) { - LOG_ERROR(Service_NFP, "Application area already exist"); - return ApplicationAreaExist; - } - - return RecreateApplicationArea(access_id, data); -} - -Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (is_app_area_open) { - LOG_ERROR(Service_NFP, "Application area is open"); - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (data.size() > sizeof(ApplicationArea)) { - LOG_ERROR(Service_NFP, "Wrong data size {}", data.size()); - return WrongApplicationAreaSize; - } - - Common::TinyMT rng{}; - std::memcpy(tag_data.application_area.data(), data.data(), data.size()); - // Fill remaining data with random numbers - rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), - sizeof(ApplicationArea) - data.size()); - - if (tag_data.application_write_counter != counter_limit) { - tag_data.application_write_counter++; - } - - const u64 application_id = system.GetApplicationProcessProgramID(); - - tag_data.application_id_byte = - static_cast<u8>(application_id >> application_id_version_offset & 0xf); - tag_data.application_id = - RemoveVersionByte(application_id) | - (static_cast<u64>(AppAreaVersion::NintendoSwitch) << application_id_version_offset); - tag_data.settings.settings.appdata_initialized.Assign(1); - tag_data.application_area_id = access_id; - tag_data.unknown = {}; - tag_data.unknown2 = {}; - - UpdateRegisterInfoCrc(); - - return Flush(); -} - -Result NfpDevice::DeleteApplicationArea() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - if (tag_data.settings.settings.appdata_initialized == 0) { - return ApplicationAreaIsNotInitialized; - } - - if (tag_data.application_write_counter != counter_limit) { - tag_data.application_write_counter++; - } - - Common::TinyMT rng{}; - rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea)); - rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64)); - rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32)); - rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8)); - tag_data.settings.settings.appdata_initialized.Assign(0); - tag_data.unknown = {}; - tag_data.unknown2 = {}; - is_app_area_open = false; - - UpdateRegisterInfoCrc(); - - return Flush(); -} - -Result NfpDevice::ExistApplicationArea(bool& has_application_area) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0; - - return ResultSuccess; -} - -Result NfpDevice::GetAll(NfpData& data) const { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - CommonInfo common_info{}; - Service::Mii::MiiManager manager; - const u64 application_id = tag_data.application_id; - - GetCommonInfo(common_info); - - data = { - .magic = tag_data.constant_value, - .write_counter = tag_data.write_counter, - .settings_crc = tag_data.settings.crc, - .common_info = common_info, - .mii_char_info = tag_data.owner_mii, - .mii_store_data_extension = tag_data.mii_extension, - .creation_date = tag_data.settings.init_date.GetWriteDate(), - .amiibo_name = tag_data.settings.amiibo_name, - .amiibo_name_null_terminated = 0, - .settings = tag_data.settings.settings, - .unknown1 = tag_data.unknown, - .register_info_crc = tag_data.register_info_crc, - .unknown2 = tag_data.unknown2, - .application_id = application_id, - .access_id = tag_data.application_area_id, - .settings_crc_counter = tag_data.settings.crc_counter, - .font_region = tag_data.settings.settings.font_region, - .tag_type = PackedTagType::Type2, - .console_type = - static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf), - .application_id_byte = tag_data.application_id_byte, - .application_area = tag_data.application_area, - }; - - return ResultSuccess; -} - -Result NfpDevice::SetAll(const NfpData& data) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - tag_data.constant_value = data.magic; - tag_data.write_counter = data.write_counter; - tag_data.settings.crc = data.settings_crc; - tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date); - tag_data.write_counter = data.common_info.write_counter; - tag_data.amiibo_version = data.common_info.version; - tag_data.owner_mii = data.mii_char_info; - tag_data.mii_extension = data.mii_store_data_extension; - tag_data.settings.init_date.SetWriteDate(data.creation_date); - tag_data.settings.amiibo_name = data.amiibo_name; - tag_data.settings.settings = data.settings; - tag_data.unknown = data.unknown1; - tag_data.register_info_crc = data.register_info_crc; - tag_data.unknown2 = data.unknown2; - tag_data.application_id = data.application_id; - tag_data.application_area_id = data.access_id; - tag_data.settings.crc_counter = data.settings_crc_counter; - tag_data.settings.settings.font_region.Assign(data.font_region); - tag_data.application_id_byte = data.application_id_byte; - tag_data.application_area = data.application_area; - - return ResultSuccess; -} - -Result NfpDevice::BreakTag(BreakType break_type) { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - // TODO: Complete this implementation - - return FlushWithBreak(break_type); -} - -Result NfpDevice::ReadBackupData() { - // Not implemented - return ResultSuccess; -} - -Result NfpDevice::WriteBackupData() { - // Not implemented - return ResultSuccess; -} - -Result NfpDevice::WriteNtf() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return TagRemoved; - } - return WrongDeviceState; - } - - if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { - LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); - return WrongDeviceState; - } - - // Not implemented - - return ResultSuccess; -} - -u64 NfpDevice::GetHandle() const { - // Generate a handle based of the npad id - return static_cast<u64>(npad_id); -} - -u32 NfpDevice::GetApplicationAreaSize() const { - return sizeof(ApplicationArea); -} - -DeviceState NfpDevice::GetCurrentState() const { - return device_state; -} - -Core::HID::NpadIdType NfpDevice::GetNpadId() const { - return npad_id; -} - -AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const { - std::array<char16_t, amiibo_name_length> settings_amiibo_name{}; - AmiiboName amiibo_name{}; - - // Convert from big endian to little endian - for (std::size_t i = 0; i < amiibo_name_length; i++) { - settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]); - } - - // Convert from utf16 to utf8 - const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data()); - memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size()); - - return amiibo_name; -} - -void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) { - std::array<char16_t, amiibo_name_length> settings_amiibo_name{}; - - // Convert from utf8 to utf16 - const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data()); - memcpy(settings_amiibo_name.data(), amiibo_name_utf16.data(), - amiibo_name_utf16.size() * sizeof(char16_t)); - - // Convert from little endian to big endian - for (std::size_t i = 0; i < amiibo_name_length; i++) { - settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]); - } -} - -AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { - const auto& time_zone_manager = - system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); - Time::TimeZone::CalendarInfo calendar_info{}; - AmiiboDate amiibo_date{}; - - amiibo_date.SetYear(2000); - amiibo_date.SetMonth(1); - amiibo_date.SetDay(1); - - if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { - amiibo_date.SetYear(calendar_info.time.year); - amiibo_date.SetMonth(calendar_info.time.month); - amiibo_date.SetDay(calendar_info.time.day); - } - - return amiibo_date; -} - -u64 NfpDevice::RemoveVersionByte(u64 application_id) const { - return application_id & ~(0xfULL << application_id_version_offset); -} - -void NfpDevice::UpdateSettingsCrc() { - auto& settings = tag_data.settings; - - if (settings.crc_counter != counter_limit) { - settings.crc_counter++; - } - - // TODO: this reads data from a global, find what it is - std::array<u8, 8> unknown_input{}; - boost::crc_32_type crc; - crc.process_bytes(&unknown_input, sizeof(unknown_input)); - settings.crc = crc.checksum(); -} - -void NfpDevice::UpdateRegisterInfoCrc() { -#pragma pack(push, 1) - struct CrcData { - Mii::Ver3StoreData mii; - u8 application_id_byte; - u8 unknown; - Mii::NfpStoreDataExtension mii_extension; - std::array<u32, 0x5> unknown2; - }; - static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size"); -#pragma pack(pop) - - const CrcData crc_data{ - .mii = tag_data.owner_mii, - .application_id_byte = tag_data.application_id_byte, - .unknown = tag_data.unknown, - .mii_extension = tag_data.mii_extension, - .unknown2 = tag_data.unknown2, - }; - - boost::crc_32_type crc; - crc.process_bytes(&crc_data, sizeof(CrcData)); - tag_data.register_info_crc = crc.checksum(); -} - -} // namespace Service::NFP |
