summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nfc
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/nfc')
-rw-r--r--src/core/hle/service/nfc/common/device.cpp182
-rw-r--r--src/core/hle/service/nfc/common/device.h10
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp11
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h2
-rw-r--r--src/core/hle/service/nfc/mifare_types.h11
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp7
6 files changed, 108 insertions, 115 deletions
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index f4b180b06..5bf289818 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -93,7 +93,8 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
const auto nfc_status = npad_device->GetNfc();
switch (nfc_status.state) {
case Common::Input::NfcState::NewAmiibo:
- LoadNfcTag(nfc_status.data);
+ LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length,
+ nfc_status.uuid);
break;
case Common::Input::NfcState::AmiiboRemoved:
if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
@@ -108,28 +109,46 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
}
}
-bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
+bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) {
if (device_state != DeviceState::SearchingForTag) {
LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
return false;
}
+ if ((protocol & static_cast<u8>(allowed_protocols)) == 0) {
+ LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol);
+ return false;
+ }
+
+ real_tag_info = {
+ .uuid = uuid,
+ .uuid_length = uuid_length,
+ .protocol = static_cast<NfcProtocol>(protocol),
+ .tag_type = static_cast<TagType>(tag_type),
+ };
+
+ device_state = DeviceState::TagFound;
+ deactivate_event->GetReadableEvent().Clear();
+ activate_event->Signal();
+ return true;
+}
+
+bool NfcDevice::LoadAmiiboData() {
+ std::vector<u8> data{};
+
+ if (!npad_device->ReadAmiiboData(data)) {
+ return false;
+ }
+
if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
return false;
}
- mifare_data.resize(data.size());
- memcpy(mifare_data.data(), data.data(), data.size());
-
memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
is_write_protected = false;
- device_state = DeviceState::TagFound;
- deactivate_event->GetReadableEvent().Clear();
- activate_event->Signal();
-
// Fallback for plain amiibos
if (is_plain_amiibo) {
LOG_INFO(Service_NFP, "Using plain amiibo");
@@ -147,6 +166,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
return true;
}
+ LOG_INFO(Service_NFP, "Using encrypted amiibo");
tag_data = {};
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
return true;
@@ -162,7 +182,6 @@ void NfcDevice::CloseNfcTag() {
device_state = DeviceState::TagRemoved;
encrypted_tag_data = {};
tag_data = {};
- mifare_data = {};
activate_event->GetReadableEvent().Clear();
deactivate_event->Signal();
}
@@ -179,8 +198,12 @@ void NfcDevice::Initialize() {
device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
encrypted_tag_data = {};
tag_data = {};
- mifare_data = {};
- is_initalized = true;
+
+ if (device_state != DeviceState::Initialized) {
+ return;
+ }
+
+ is_initalized = npad_device->AddNfcHandle();
}
void NfcDevice::Finalize() {
@@ -190,6 +213,11 @@ void NfcDevice::Finalize() {
if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
StopDetection();
}
+
+ if (device_state != DeviceState::Unavailable) {
+ npad_device->RemoveNfcHandle();
+ }
+
device_state = DeviceState::Unavailable;
is_initalized = false;
}
@@ -200,10 +228,8 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
return ResultWrongDeviceState;
}
- if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
- Common::Input::PollingMode::NFC) !=
- Common::Input::DriverResult::Success) {
- LOG_ERROR(Service_NFC, "Nfc not supported");
+ if (!npad_device->StartNfcPolling()) {
+ LOG_ERROR(Service_NFC, "Nfc polling not supported");
return ResultNfcDisabled;
}
@@ -213,9 +239,6 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
}
Result NfcDevice::StopDetection() {
- npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
- Common::Input::PollingMode::Active);
-
if (device_state == DeviceState::Initialized) {
return ResultSuccess;
}
@@ -225,6 +248,7 @@ Result NfcDevice::StopDetection() {
}
if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
+ npad_device->StopNfcPolling();
device_state = DeviceState::Initialized;
return ResultSuccess;
}
@@ -233,7 +257,7 @@ Result NfcDevice::StopDetection() {
return ResultWrongDeviceState;
}
-Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
+Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
if (device_state == DeviceState::TagRemoved) {
@@ -242,41 +266,15 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
return ResultWrongDeviceState;
}
- UniqueSerialNumber uuid{};
- u8 uuid_length{};
- NfcProtocol protocol{NfcProtocol::TypeA};
- TagType tag_type{TagType::Type2};
-
- if (is_mifare) {
- tag_type = TagType::Mifare;
- uuid_length = sizeof(NFP::NtagTagUuid);
- memcpy(uuid.data(), mifare_data.data(), uuid_length);
- } else {
- tag_type = TagType::Type2;
- uuid_length = sizeof(NFP::NtagTagUuid);
- NFP::NtagTagUuid nUuid{
- .part1 = encrypted_tag_data.uuid.part1,
- .part2 = encrypted_tag_data.uuid.part2,
- .nintendo_id = encrypted_tag_data.uuid.nintendo_id,
- };
- memcpy(uuid.data(), &nUuid, uuid_length);
+ tag_info = real_tag_info;
- // Generate random UUID to bypass amiibo load limits
- if (Settings::values.random_amiibo_id) {
- Common::TinyMT rng{};
- rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
- rng.GenerateRandomBytes(uuid.data(), uuid_length);
- }
+ // Generate random UUID to bypass amiibo load limits
+ if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) {
+ Common::TinyMT rng{};
+ rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
+ rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length);
}
- // Protocol and tag type may change here
- tag_info = {
- .uuid = uuid,
- .uuid_length = uuid_length,
- .protocol = protocol,
- .tag_type = tag_type,
- };
-
return ResultSuccess;
}
@@ -293,7 +291,7 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
Result result = ResultSuccess;
TagInfo tag_info{};
- result = GetTagInfo(tag_info, true);
+ result = GetTagInfo(tag_info);
if (result.IsError()) {
return result;
@@ -307,6 +305,8 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
return ResultInvalidArgument;
}
+ Common::Input::MifareRequest request{};
+ Common::Input::MifareRequest out_data{};
const auto unknown = parameters[0].sector_key.unknown;
for (std::size_t i = 0; i < parameters.size(); i++) {
if (unknown != parameters[i].sector_key.unknown) {
@@ -315,25 +315,29 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
}
for (std::size_t i = 0; i < parameters.size(); i++) {
- result = ReadMifare(parameters[i], read_block_data[i]);
- if (result.IsError()) {
- break;
+ if (parameters[i].sector_key.command == MifareCmd::None) {
+ continue;
}
+ request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
+ request.data[i].sector = parameters[i].sector_number;
+ memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
+ sizeof(KeyData));
}
- return result;
-}
-
-Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
- MifareReadBlockData& read_block_data) const {
- const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
- read_block_data.sector_number = parameter.sector_number;
- if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
+ if (!npad_device->ReadMifareData(request, out_data)) {
return ResultMifareError288;
}
- // TODO: Use parameter.sector_key to read encrypted data
- memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock));
+ for (std::size_t i = 0; i < read_block_data.size(); i++) {
+ if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) {
+ continue;
+ }
+
+ read_block_data[i] = {
+ .data = out_data.data[i].data,
+ .sector_number = out_data.data[i].sector,
+ };
+ }
return ResultSuccess;
}
@@ -342,7 +346,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
Result result = ResultSuccess;
TagInfo tag_info{};
- result = GetTagInfo(tag_info, true);
+ result = GetTagInfo(tag_info);
if (result.IsError()) {
return result;
@@ -363,42 +367,25 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
}
}
+ Common::Input::MifareRequest request{};
for (std::size_t i = 0; i < parameters.size(); i++) {
- result = WriteMifare(parameters[i]);
- if (result.IsError()) {
- break;
+ if (parameters[i].sector_key.command == MifareCmd::None) {
+ continue;
}
+ request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
+ request.data[i].sector = parameters[i].sector_number;
+ memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
+ sizeof(KeyData));
+ memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData));
}
- if (!npad_device->WriteNfc(mifare_data)) {
- LOG_ERROR(Service_NFP, "Error writing to file");
+ if (!npad_device->WriteMifareData(request)) {
return ResultMifareError288;
}
return result;
}
-Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
- const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
-
- if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return ResultTagRemoved;
- }
- return ResultWrongDeviceState;
- }
-
- if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
- return ResultMifareError288;
- }
-
- // TODO: Use parameter.sector_key to encrypt the data
- memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock));
-
- return ResultSuccess;
-}
-
Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data,
std::span<u8> out_data) {
@@ -412,6 +399,11 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
return ResultWrongDeviceState;
}
+ if (!LoadAmiiboData()) {
+ LOG_ERROR(Service_NFP, "Not an amiibo");
+ return ResultInvalidTagType;
+ }
+
if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
LOG_ERROR(Service_NFP, "Not an amiibo");
return ResultInvalidTagType;
@@ -562,7 +554,7 @@ Result NfcDevice::Restore() {
NFC::TagInfo tag_info{};
std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
- Result result = GetTagInfo(tag_info, false);
+ Result result = GetTagInfo(tag_info);
if (result.IsError()) {
return result;
@@ -635,7 +627,7 @@ Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
// TODO: Validate this data
common_info = {
.last_write_date = settings.write_date.GetWriteDate(),
- .write_counter = tag_data.write_counter,
+ .write_counter = tag_data.application_write_counter,
.version = tag_data.amiibo_version,
.application_area_size = sizeof(NFP::ApplicationArea),
};
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 7560210d6..0ed1ff34c 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -42,15 +42,12 @@ public:
Result StartDetection(NfcProtocol allowed_protocol);
Result StopDetection();
- Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const;
+ Result GetTagInfo(TagInfo& tag_info) const;
Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
std::span<MifareReadBlockData> read_block_data) const;
- Result ReadMifare(const MifareReadBlockParameter& parameter,
- MifareReadBlockData& read_block_data) const;
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
- Result WriteMifare(const MifareWriteBlockParameter& parameter);
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data, std::span<u8> out_data);
@@ -105,7 +102,8 @@ public:
private:
void NpadUpdate(Core::HID::ControllerTriggerType type);
- bool LoadNfcTag(std::span<const u8> data);
+ bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid);
+ bool LoadAmiiboData();
void CloseNfcTag();
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
@@ -140,8 +138,8 @@ private:
bool is_write_protected{};
NFP::MountTarget mount_target{NFP::MountTarget::None};
+ TagInfo real_tag_info{};
NFP::NTAG215File tag_data{};
- std::vector<u8> mifare_data{};
NFP::EncryptedNTAG215File encrypted_tag_data{};
};
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index b0456508e..562f3a28e 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -29,6 +29,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
}
DeviceManager ::~DeviceManager() {
+ if (is_initialized) {
+ Finalize();
+ }
service_context.CloseEvent(availability_change_event);
}
@@ -125,14 +128,14 @@ Result DeviceManager::StopDetection(u64 device_handle) {
return result;
}
-Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
+Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
- result = device->GetTagInfo(tag_info, is_mifare);
+ result = device->GetTagInfo(tag_info);
result = VerifyDeviceResult(device, result);
}
@@ -546,7 +549,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
NFC::TagInfo tag_info{};
if (result.IsSuccess()) {
- result = device->GetTagInfo(tag_info, false);
+ result = device->GetTagInfo(tag_info);
}
if (result.IsSuccess()) {
@@ -565,7 +568,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
NFC::TagInfo tag_info{};
if (result.IsSuccess()) {
- result = device->GetTagInfo(tag_info, false);
+ result = device->GetTagInfo(tag_info);
}
if (result.IsSuccess()) {
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index 2971e280f..c61ba0cf3 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -33,7 +33,7 @@ public:
Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
Result StopDetection(u64 device_handle);
- Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const;
+ Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const;
Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
Result ReadMifare(u64 device_handle,
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h
index 75b59f021..467937399 100644
--- a/src/core/hle/service/nfc/mifare_types.h
+++ b/src/core/hle/service/nfc/mifare_types.h
@@ -11,9 +11,10 @@
namespace Service::NFC {
enum class MifareCmd : u8 {
+ None = 0x00,
+ Read = 0x30,
AuthA = 0x60,
AuthB = 0x61,
- Read = 0x30,
Write = 0xA0,
Transfer = 0xB0,
Decrement = 0xC0,
@@ -35,17 +36,17 @@ static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
// This is nn::nfc::MifareReadBlockParameter
struct MifareReadBlockParameter {
- u8 sector_number;
+ u8 sector_number{};
INSERT_PADDING_BYTES(0x7);
- SectorKey sector_key;
+ SectorKey sector_key{};
};
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
"MifareReadBlockParameter is an invalid size");
// This is nn::nfc::MifareReadBlockData
struct MifareReadBlockData {
- DataBlock data;
- u8 sector_number;
+ DataBlock data{};
+ u8 sector_number{};
INSERT_PADDING_BYTES(0x7);
};
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 130fb7f78..e7ca7582e 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -174,8 +174,7 @@ void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
TagInfo tag_info{};
- auto result =
- GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
+ auto result = GetManager()->GetTagInfo(device_handle, tag_info);
result = TranslateResultToServiceError(result);
if (result.IsSuccess()) {
@@ -216,8 +215,8 @@ void NfcInterface::ReadMifare(HLERequestContext& ctx) {
memcpy(read_commands.data(), buffer.data(),
number_of_commands * sizeof(MifareReadBlockParameter));
- LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
- device_handle, number_of_commands);
+ LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle,
+ number_of_commands);
std::vector<MifareReadBlockData> out_data(number_of_commands);
auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);