From 832084fae87014311e002b52e56111bcd5b10e38 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 14:46:59 +0300 Subject: [PATCH 01/26] Added callback on FieldOff event from 14443 to mfu --- lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 16e5ac294dd..db80368e0ca 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -89,8 +89,10 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypeListenerActivated) { instance->state = Iso14443_3aListenerStateActive; } else if(nfc_event->type == NfcEventTypeFieldOff) { - command = NfcCommandReset; instance->state = Iso14443_3aListenerStateIdle; + if(instance->callback) { + command = instance->callback(instance->generic_event, instance->context); + } } else if(nfc_event->type == NfcEventTypeRxEnd) { if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { command = NfcCommandReset; From 0a059ce1eab176056c904e11a32e6023055e1adf Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 14:48:45 +0300 Subject: [PATCH 02/26] Moved command enum and callback type to _i.h file --- .../mf_ultralight/mf_ultralight_listener.c | 10 ---------- .../mf_ultralight/mf_ultralight_listener_i.h | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 8eb2d542de1..0d04cdb9e3e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -14,16 +14,6 @@ typedef enum { MfUltralightListenerAccessTypeWrite, } MfUltralightListenerAccessType; -typedef enum { - MfUltralightCommandNotFound, - MfUltralightCommandProcessed, - MfUltralightCommandNotProcessedNAK, - MfUltralightCommandNotProcessedSilent, -} MfUltralightCommand; - -typedef MfUltralightCommand ( - *MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); - typedef struct { uint8_t cmd; size_t cmd_len_bits; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index eb188041f6a..95e23f94206 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -17,6 +17,23 @@ typedef enum { MfUltraligthListenerStateIdle, } MfUltraligthListenerState; +typedef enum { + MfUltralightCommandNotFound, + MfUltralightCommandProcessed, + MfUltralightCommandNotProcessedNAK, + MfUltralightCommandNotProcessedSilent, +} MfUltralightCommand; + +typedef MfUltralightCommand ( + *MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); + +typedef uint8_t MfUltralightListenerCompositeCommandData; + +typedef struct { + MfUltralightListenerCompositeCommandData data; + MfUltralightListenerCommandCallback callback; +} MfUltralightListenerCompositeCommandContext; + typedef struct { uint8_t enabled; uint8_t ascii_offset; From a1646cf7a8fd51ffbcbd2f6f967bf40a75bbac75 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 14:49:39 +0300 Subject: [PATCH 03/26] Added context for composite command to mfu_listener --- lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index 95e23f94206..f2ebb1058e0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -58,6 +58,7 @@ struct MfUltralightListener { MfUltralightListenerEventData mfu_event_data; NfcGenericCallback callback; MfUltralightMirrorMode mirror; + MfUltralightListenerCompositeCommandContext composite_cmd; void* context; }; From 9739b232459f5d51c1be65fc24654c0ccef50503 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 14:52:28 +0300 Subject: [PATCH 04/26] Functions for composite commands processing added --- .../mf_ultralight/mf_ultralight_listener_i.c | 22 +++++++++++++++++++ .../mf_ultralight/mf_ultralight_listener_i.h | 8 +++++++ 2 files changed, 30 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c index 20f43332224..43e54309e36 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -161,4 +161,26 @@ void mf_ultraligt_mirror_prepare_emulation(MfUltralightListener* instance) { instance->mirror.ascii_mirror_data, instance->data->counter[2].data, sizeof(instance->data->counter[2].data)); +} + +bool mf_ultralight_composite_command_in_progress(MfUltralightListener* instance) { + return (instance->composite_cmd.callback != NULL); +} + +MfUltralightCommand + mf_ultralight_composite_command_run(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = (instance->composite_cmd.callback)(instance, buffer); + mf_ultralight_composite_command_reset(instance); + return command; +} + +void mf_ultralight_composite_command_reset(MfUltralightListener* instance) { + instance->composite_cmd.callback = NULL; + instance->composite_cmd.data = 0; +} + +void mf_ultralight_composite_command_set_next( + MfUltralightListener* instance, + const MfUltralightListenerCommandCallback handler) { + instance->composite_cmd.callback = handler; } \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index f2ebb1058e0..ce6d0d8b9e0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -68,6 +68,14 @@ void mf_ultralight_mirror_read_handler( uint8_t mirror_page_num, uint8_t* dest, MfUltralightListener* instance); + +void mf_ultralight_composite_command_set_next( + MfUltralightListener* instance, + const MfUltralightListenerCommandCallback handler); +void mf_ultralight_composite_command_reset(MfUltralightListener* instance); +bool mf_ultralight_composite_command_in_progress(MfUltralightListener* instance); +MfUltralightCommand + mf_ultralight_composite_command_run(MfUltralightListener* instance, BitBuffer* buffer); #ifdef __cplusplus } #endif From 3ffda5d62803c8062b2aaf83d21c532b4d18bb49 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 14:55:21 +0300 Subject: [PATCH 05/26] Composite commands processing logic added --- .../mf_ultralight/mf_ultralight_listener.c | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 0d04cdb9e3e..4cc5185cf3e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -375,6 +375,7 @@ MfUltralightListener* mf_ultralight_listener_alloc( instance->data = mf_ultralight_alloc(); mf_ultralight_copy(instance->data, data); mf_ultralight_listener_prepare_emulation(instance); + mf_ultralight_composite_command_reset(instance); instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); instance->mfu_event.data = &instance->mfu_event_data; @@ -428,14 +429,17 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { size_t size = bit_buffer_get_size(rx_buffer); uint8_t cmd = bit_buffer_get_byte(rx_buffer, 0); - for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { - if(size != mf_ultralight_command[i].cmd_len_bits) continue; - if(cmd != mf_ultralight_command[i].cmd) continue; - mfu_command = mf_ultralight_command[i].callback(instance, rx_buffer); + if(mf_ultralight_composite_command_in_progress(instance)) { + mfu_command = mf_ultralight_composite_command_run(instance, rx_buffer); + } else { + for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { + if(size != mf_ultralight_command[i].cmd_len_bits) continue; + if(cmd != mf_ultralight_command[i].cmd) continue; + mfu_command = mf_ultralight_command[i].callback(instance, rx_buffer); - if(mfu_command != MfUltralightCommandNotFound) break; + if(mfu_command != MfUltralightCommandNotFound) break; + } } - if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; @@ -445,11 +449,11 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); } } - } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData) { - command = NfcCommandReset; - } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) { - command = NfcCommandReset; - } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { + } else if( + iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData || + iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff || + iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { + mf_ultralight_composite_command_reset(instance); command = NfcCommandReset; } From e9ca28af661808590c865f41819d7cb3f1dad103 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 14:59:33 +0300 Subject: [PATCH 06/26] Added COMP_WRITE command implementation --- .../protocols/mf_ultralight/mf_ultralight.h | 1 + .../mf_ultralight/mf_ultralight_listener.c | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index c4378d78aa4..e88007025c0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -11,6 +11,7 @@ extern "C" { #define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) #define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) #define MF_ULTRALIGHT_CMD_SECTOR_SELECT (0xC2) +#define MF_ULTRALIGHT_CMD_COMP_WRITE (0xA0) #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) #define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) #define MF_ULTRALIGHT_CMD_READ_CNT (0x39) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 4cc5185cf3e..ff7bb84333c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -314,6 +314,53 @@ static MfUltralightCommand return command; } +static MfUltralightCommand + mf_ultralight_comp_write_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + FURI_LOG_D(TAG, "CMD_CM_WR_2"); + + do { + if(bit_buffer_get_size_bytes(buffer) != 16) break; + + const uint8_t* rx_data = bit_buffer_get_data(buffer); + uint8_t start_page = instance->composite_cmd.data; + memcpy(instance->data->page[start_page].data, &rx_data[0], sizeof(MfUltralightPage)); + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + + command = MfUltralightCommandProcessed; + } while(false); + + return command; +} + +static MfUltralightCommand + mf_ultralight_comp_write_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; + + FURI_LOG_D(TAG, "CMD_CM_WR_1"); + + do { + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportCompatibleWrite)) + break; + + uint8_t start_page = bit_buffer_get_byte(buffer, 1); + uint16_t pages_total = instance->data->pages_total; + + if(start_page < 2 || start_page > pages_total) { + command = MfUltralightCommandNotProcessedNAK; + break; + } + + instance->composite_cmd.data = start_page; + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + command = MfUltralightCommandProcessed; + mf_ultralight_composite_command_set_next(instance, mf_ultralight_comp_write_handler_p2); + } while(false); + + return command; +} + static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { { .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, @@ -355,6 +402,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 6 * 8, .callback = mf_ultralight_listener_increase_counter_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_COMP_WRITE, + .cmd_len_bits = 2 * 8, + .callback = mf_ultralight_comp_write_handler_p1, + }, }; static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { From 27d6b02fcc1ca297c224d5bdf9ebe0a6c2a9f418 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 31 Aug 2023 19:53:06 +0300 Subject: [PATCH 07/26] Patch with some fixes --- lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c | 8 +++++++- lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c | 4 ++-- lib/nfc/protocols/mf_classic/mf_classic_listener.c | 1 + lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c | 2 ++ lib/nfc/protocols/nfc_generic_event.h | 1 + 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index db80368e0ca..7fcc6815a47 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -91,10 +91,16 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { } else if(nfc_event->type == NfcEventTypeFieldOff) { instance->state = Iso14443_3aListenerStateIdle; if(instance->callback) { - command = instance->callback(instance->generic_event, instance->context); + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeFieldOff; + instance->callback(instance->generic_event, instance->context); } + command = NfcCommandReset; } else if(nfc_event->type == NfcEventTypeRxEnd) { if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { + if(instance->callback) { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; + instance->callback(instance->generic_event, instance->context); + } command = NfcCommandReset; } else { if(iso14443_crc_check(Iso14443CrcTypeA, nfc_event->data.buffer)) { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c index 4bb413090ea..546fc4fbf1d 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c @@ -70,7 +70,7 @@ static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context) bit_buffer_get_byte(rx_buffer, 0) == ISO14443_4A_CMD_READ_ATS) { if(iso14443_4a_listener_send_ats(instance, instance->data->ats_data) != Iso14443_4aErrorNone) { - command = NfcCommandStop; + command = NfcCommandContinue; } else { instance->state = Iso14443_4aListenerStateActive; } @@ -87,7 +87,7 @@ static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context) iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted || iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) { instance->state = Iso14443_4aListenerStateIdle; - command = NfcCommandStop; + command = NfcCommandContinue; } return command; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index 9a375490365..ebb9f40ba69 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -533,6 +533,7 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { if(iso3_event->type == Iso14443_3aListenerEventTypeFieldOff) { mf_classic_listener_reset_state(instance); + command = NfcCommandReset; } else if( (iso3_event->type == Iso14443_3aListenerEventTypeReceivedData) || (iso3_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame)) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index ff7bb84333c..9bf3868b1bf 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -505,7 +505,9 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData || iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff || iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { + // TODO generic state reset ? mf_ultralight_composite_command_reset(instance); + instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; } diff --git a/lib/nfc/protocols/nfc_generic_event.h b/lib/nfc/protocols/nfc_generic_event.h index 64c7939d00d..cee465eb8a2 100644 --- a/lib/nfc/protocols/nfc_generic_event.h +++ b/lib/nfc/protocols/nfc_generic_event.h @@ -14,6 +14,7 @@ typedef void NfcGenericEventData; typedef struct { NfcProtocol protocol; NfcGenericInstance* instance; + // TODO change to event NfcGenericEventData* data; } NfcGenericEvent; From 6b21e6c692a34ec8459fbbb9ccb55ec942e6ec19 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Sep 2023 12:07:33 +0300 Subject: [PATCH 08/26] New mfu command result added for composite commands --- lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index ce6d0d8b9e0..5f8fc409e03 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -20,6 +20,7 @@ typedef enum { typedef enum { MfUltralightCommandNotFound, MfUltralightCommandProcessed, + MfUltralightCommandProcessedSilent, MfUltralightCommandNotProcessedNAK, MfUltralightCommandNotProcessedSilent, } MfUltralightCommand; From a4566a90025774f013a583707a68787bd4da9ab3 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Sep 2023 12:08:07 +0300 Subject: [PATCH 09/26] Added variable for storing sector for SECTOR_SELECT cmd --- lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index 5f8fc409e03..ac390a800e2 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -58,6 +58,7 @@ struct MfUltralightListener { MfUltralightListenerEvent mfu_event; MfUltralightListenerEventData mfu_event_data; NfcGenericCallback callback; + uint8_t sector; MfUltralightMirrorMode mirror; MfUltralightListenerCompositeCommandContext composite_cmd; void* context; From 6b8f9354aa0c817e06b816f51a32bab5bb740592 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Sep 2023 12:09:23 +0300 Subject: [PATCH 10/26] Implemented proper way of reset for composite cmds --- lib/nfc/nfc.c | 2 ++ lib/nfc/nfc.h | 1 + lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index e8b5f502b02..353e58a396d 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -125,6 +125,8 @@ static int32_t nfc_worker_listener(void* context) { break; } else if(command == NfcCommandReset) { nfc_listener_sleep(instance); + } else if(command == NfcCommandResetContinue) { + f_hal_nfc_listener_reset(); } } } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 0c7e63e96e5..64141966005 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -34,6 +34,7 @@ typedef enum { NfcCommandContinue, NfcCommandReset, NfcCommandStop, + NfcCommandResetContinue } NfcCommand; typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 9bf3868b1bf..721c82befef 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -492,7 +492,9 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { if(mfu_command != MfUltralightCommandNotFound) break; } } - if(mfu_command != MfUltralightCommandProcessed) { + if(mfu_command == MfUltralightCommandProcessedSilent) { + command = NfcCommandResetContinue; + } else if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; From 317bd3aba6c9fdc1974e54f979c83868ff40dd5a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Sep 2023 12:10:39 +0300 Subject: [PATCH 11/26] SECTOR_SELECT implementation added --- .../mf_ultralight/mf_ultralight_listener.c | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 721c82befef..df3c4c38fb2 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -361,6 +361,45 @@ static MfUltralightCommand return command; } +static MfUltralightCommand + mf_ultralight_sector_select_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + UNUSED(instance); + UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_SEC_SEL_2"); + + do { + if(bit_buffer_get_size_bytes(buffer) != 4) break; + uint8_t sector = bit_buffer_get_byte(buffer, 0); + if(sector == 0xFF) break; + + instance->sector = sector; + command = MfUltralightCommandProcessedSilent; + } while(false); + + return command; +} + +static MfUltralightCommand + mf_ultralight_sector_select_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_SEC_SEL_1"); + + do { + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportSectorSelect) && + bit_buffer_get_byte(buffer, 1) == 0xFF) + break; + + command = MfUltralightCommandProcessed; + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + mf_ultralight_composite_command_set_next(instance, mf_ultralight_sector_select_handler_p2); + } while(false); + + return command; +} + static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { { .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, @@ -402,6 +441,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 6 * 8, .callback = mf_ultralight_listener_increase_counter_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_SECTOR_SELECT, + .cmd_len_bits = 2 * 8, + .callback = mf_ultralight_sector_select_handler_p1, + }, { .cmd = MF_ULTRALIGHT_CMD_COMP_WRITE, .cmd_len_bits = 2 * 8, @@ -428,6 +472,7 @@ MfUltralightListener* mf_ultralight_listener_alloc( mf_ultralight_copy(instance->data, data); mf_ultralight_listener_prepare_emulation(instance); mf_ultralight_composite_command_reset(instance); + instance->sector = 0; instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); instance->mfu_event.data = &instance->mfu_event_data; @@ -509,6 +554,7 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { // TODO generic state reset ? mf_ultralight_composite_command_reset(instance); + instance->sector = 0; instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; } From 31243c2770304745cf286123d1692e5a3268d993 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Sep 2023 15:03:01 +0300 Subject: [PATCH 12/26] Adjust naming for PR --- .../debug/unit_tests/nfc/nfc_transport.c | 2 +- lib/nfc/nfc.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index e9084ca20b9..c91c8b95873 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -334,7 +334,7 @@ void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) furi_thread_start(instance->worker_thread); } -NfcError nfc_listener_sleep(Nfc* instance) { +NfcError nfc_listener_reset(Nfc* instance) { furi_assert(instance); furi_assert(poller_queue); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 4e205eb70a3..a416fb07ab4 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -108,7 +108,7 @@ static int32_t nfc_worker_listener(void* context) { if(event & FHalNfcEventFieldOff) { nfc_event.type = NfcEventTypeFieldOff; instance->callback(nfc_event, instance->context); - nfc_listener_sleep(instance); + nfc_listener_reset(instance); } if(event & FHalNfcEventListenerActive) { f_hal_nfc_listener_disable_auto_col_res(); @@ -124,9 +124,9 @@ static int32_t nfc_worker_listener(void* context) { if(command == NfcCommandStop) { break; } else if(command == NfcCommandReset) { + nfc_listener_reset(instance); + } else if(command == NfcCommandSleep) { nfc_listener_sleep(instance); - } else if(command == NfcCommandResetContinue) { - f_hal_nfc_listener_reset(); } } } @@ -349,7 +349,7 @@ void nfc_stop(Nfc* instance) { furi_thread_join(instance->worker_thread); } -NfcError nfc_listener_sleep(Nfc* instance) { +NfcError nfc_listener_reset(Nfc* instance) { furi_assert(instance); furi_assert(instance->state == NfcStateListenerStarted); @@ -358,6 +358,15 @@ NfcError nfc_listener_sleep(Nfc* instance) { return NfcErrorNone; } +NfcError nfc_listener_sleep(Nfc* instance) { + furi_assert(instance); + furi_assert(instance->state == NfcStateListenerStarted); + + f_hal_nfc_listener_reset(); + + return NfcErrorNone; +} + NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { furi_assert(instance); furi_assert(tx_buffer); From fd349f98f816fa0fe0669c3953b36ac15d04837b Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Sep 2023 15:05:10 +0300 Subject: [PATCH 13/26] Update api_symbols.csv, nfc.h, and mf_ultralight_listener.c --- firmware/targets/f7/api_symbols.csv | 3 ++- lib/nfc/nfc.h | 4 +++- lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 5573f3479f4..90ad35b921e 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,38.0,, +Version,+,38.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2205,6 +2205,7 @@ Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_alloc,NfcListener*,"Nfc*, NfcProtocol, const NfcDeviceData*" Function,-,nfc_listener_free,void,NfcListener* Function,-,nfc_listener_get_data,const NfcDeviceData*,"NfcListener*, NfcProtocol" +Function,-,nfc_listener_reset,NfcError,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_start,void,"NfcListener*, NfcGenericCallback, void*" diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 64141966005..d7aa4be0b3e 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -34,7 +34,7 @@ typedef enum { NfcCommandContinue, NfcCommandReset, NfcCommandStop, - NfcCommandResetContinue + NfcCommandSleep, } NfcCommand; typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); @@ -93,6 +93,8 @@ void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context); void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context); +NfcError nfc_listener_reset(Nfc* instance); + NfcError nfc_listener_sleep(Nfc* instance); void nfc_listener_abort(Nfc* instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 863fa83d60b..8ff2f1e0ab8 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -536,7 +536,7 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { } } if(mfu_command == MfUltralightCommandProcessedSilent) { - command = NfcCommandResetContinue; + command = NfcCommandSleep; } else if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; From aadc629cb29915f53b14bb7e13f044da8b2c362c Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 7 Sep 2023 23:54:03 +0300 Subject: [PATCH 14/26] FAST_READ cmd define added --- lib/nfc/protocols/mf_ultralight/mf_ultralight.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 0727adc0706..b42ecfc06c8 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -10,6 +10,7 @@ extern "C" { #define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) #define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) +#define MF_ULTRALIGHT_CMD_FAST_READ (0x3A) #define MF_ULTRALIGHT_CMD_SECTOR_SELECT (0xC2) #define MF_ULTRALIGHT_CMD_COMP_WRITE (0xA0) #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) From a31d95e069e4d94a35765801daecf7cd0f5f398c Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 7 Sep 2023 23:54:40 +0300 Subject: [PATCH 15/26] Added functions for PWD and PACK pages processing --- lib/nfc/protocols/mf_ultralight/mf_ultralight.c | 11 +++++++++++ lib/nfc/protocols/mf_ultralight/mf_ultralight.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 2d0774c4d90..6e3a6e4beaa 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -535,6 +535,17 @@ uint16_t mf_ultralight_get_config_page_num(MfUltralightType type) { return mf_ultralight_features[type].config_page; } +uint8_t mf_ultralight_get_pwd_page_num(MfUltralightType type) { + uint8_t config_page = mf_ultralight_features[type].config_page; + return (config_page != 0) ? config_page + 2 : 0; +} + +bool mf_ultralight_is_page_pwd_or_pack(MfUltralightType type, uint16_t page) { + uint8_t pwd_page = mf_ultralight_get_pwd_page_num(type); + uint8_t pack_page = pwd_page + 1; + return ((pwd_page != 0) && (page == pwd_page || page == pack_page)); +} + bool mf_ultralight_support_feature(const uint32_t feature_set, const uint32_t features_to_check) { return (feature_set & features_to_check) != 0; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index b42ecfc06c8..151dd3f9db5 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -204,6 +204,10 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); uint16_t mf_ultralight_get_config_page_num(MfUltralightType type); +uint8_t mf_ultralight_get_pwd_page_num(MfUltralightType type); + +bool mf_ultralight_is_page_pwd_or_pack(MfUltralightType type, uint16_t page_num); + bool mf_ultralight_support_feature(const uint32_t feature_set, const uint32_t features_to_check); bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightConfigPages** config); From 866671047b661b7b78d117cfc1e1f02d0f71ae7c Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 7 Sep 2023 23:55:06 +0300 Subject: [PATCH 16/26] Tx buffer size increased to maximum nfc package --- lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 8ff2f1e0ab8..0798364e3af 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -7,7 +7,7 @@ #define TAG "MfUltralightListener" -#define MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE (32) +#define MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE (256) typedef enum { MfUltralightListenerAccessTypeRead, From 82c0fb30a2ba1d63ad8e6108f48c575fa446b57a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 7 Sep 2023 23:56:06 +0300 Subject: [PATCH 17/26] Added functions for i2c page validation and allocation --- .../mf_ultralight/mf_ultralight_listener_i.c | 163 ++++++++++++++++++ .../mf_ultralight/mf_ultralight_listener_i.h | 9 + 2 files changed, 172 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c index 43e54309e36..8afaac4819f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -146,6 +146,7 @@ void mf_ultralight_mirror_read_handler( dest[j] = source[ascii_offset]; ascii_offset++; } + instance->mirror.ascii_offset = ascii_offset; } } @@ -183,4 +184,166 @@ void mf_ultralight_composite_command_set_next( MfUltralightListener* instance, const MfUltralightListenerCommandCallback handler) { instance->composite_cmd.callback = handler; +} + +static bool mf_ultralight_i2c_is_page_on_session_registers(uint16_t page) { + return page >= 0x00EC && page <= 0x00ED; +} + +static bool mf_ultralight_i2c_is_page_on_mirrored_session_registers(uint16_t page) { + return page >= 0x00F8 && page <= 0x00F9; +} + +static bool mf_ultralight_i2c_page_validator_for_sector0( + uint16_t start_page, + uint16_t end_page, + MfUltralightType type) { + UNUSED(type); + bool valid = false; + if(type == MfUltralightTypeNTAGI2CPlus1K || type == MfUltralightTypeNTAGI2CPlus2K) { + if(start_page <= 0xE9 && end_page <= 0xE9) { + valid = true; + } else if( + mf_ultralight_i2c_is_page_on_session_registers(start_page) && + mf_ultralight_i2c_is_page_on_session_registers(end_page)) { + valid = true; + } + } else if(type == MfUltralightTypeNTAGI2C1K) { + if((start_page <= 0xE2) || (start_page >= 0xE8 && start_page <= 0xE9)) { + valid = true; + } + } else if(type == MfUltralightTypeNTAGI2C2K) { + valid = (start_page <= 0xFF && end_page <= 0xFF); + } + + return valid; +} + +static bool mf_ultralight_i2c_page_validator_for_sector1( + uint16_t start_page, + uint16_t end_page, + MfUltralightType type) { + bool valid = false; + if(type == MfUltralightTypeNTAGI2CPlus2K) { + valid = (start_page <= 0xFF && end_page <= 0xFF); + } else if(type == MfUltralightTypeNTAGI2C2K) { + valid = ((start_page >= 0xE8 && start_page <= 0xE9) || (start_page <= 0xE0)); + } else if(type == MfUltralightTypeNTAGI2C1K || type == MfUltralightTypeNTAGI2CPlus1K) { + valid = false; + } + + return valid; +} + +static bool mf_ultralight_i2c_page_validator_for_sector2( + uint16_t start_page, + uint16_t end_page, + MfUltralightType type) { + UNUSED(start_page); + UNUSED(end_page); + UNUSED(type); + return false; +} + +static bool mf_ultralight_i2c_page_validator_for_sector3( + uint16_t start_page, + uint16_t end_page, + MfUltralightType type) { + UNUSED(type); + UNUSED(end_page); + bool valid = false; + + if(mf_ultralight_i2c_is_page_on_mirrored_session_registers(start_page)) { + valid = true; + } + + return valid; +} + +typedef bool ( + *MfUltralightI2CValidator)(uint16_t start_page, uint16_t end_page, MfUltralightType type); + +typedef uint16_t (*MfUltralightI2CPageProvider)(uint16_t page, MfUltralightType type); + +const MfUltralightI2CValidator validation_methods[] = { + mf_ultralight_i2c_page_validator_for_sector0, + mf_ultralight_i2c_page_validator_for_sector1, + mf_ultralight_i2c_page_validator_for_sector2, + mf_ultralight_i2c_page_validator_for_sector3, +}; + +bool mf_ultralight_i2c_validate_pages( + uint16_t start_page, + uint16_t end_page, + MfUltralightListener* instance) { + bool valid = false; + if(instance->sector < sizeof(validation_methods)) { + MfUltralightI2CValidator validate = validation_methods[instance->sector]; + valid = validate(start_page, end_page, instance->data->type); + } + return valid; +} + +bool mf_ultralight_is_i2c_tag(MfUltralightType type) { + return type == MfUltralightTypeNTAGI2C1K || type == MfUltralightTypeNTAGI2C2K || + type == MfUltralightTypeNTAGI2CPlus1K || type == MfUltralightTypeNTAGI2CPlus2K; +} + +static uint16_t mf_ultralight_i2c_page_provider_for_sector0(uint16_t page, MfUltralightType type) { + uint8_t new_page = page; + if(type == MfUltralightTypeNTAGI2CPlus1K || type == MfUltralightTypeNTAGI2CPlus2K) { + if(page == 0x00EC) { + new_page = 234; + } else if(page == 0x00ED) { + new_page = 235; + } + } else if(type == MfUltralightTypeNTAGI2C1K) { + new_page = (page == 0x00E8) ? 232 : page; + new_page = (page == 0x00E9) ? 233 : page; + } else if(type == MfUltralightTypeNTAGI2C2K) { + new_page = page; + } + return new_page; +} + +static uint16_t mf_ultralight_i2c_page_provider_for_sector1(uint16_t page, MfUltralightType type) { + UNUSED(type); + uint16_t new_page = page; + if(type == MfUltralightTypeNTAGI2CPlus2K) new_page = page + 236; + if(type == MfUltralightTypeNTAGI2C2K) new_page = page + 255; + return new_page; +} + +static uint16_t mf_ultralight_i2c_page_provider_for_sector2(uint16_t page, MfUltralightType type) { + UNUSED(type); + return page; +} + +static uint16_t mf_ultralight_i2c_page_provider_for_sector3(uint16_t page, MfUltralightType type) { + uint16_t new_page = page; + if(type == MfUltralightTypeNTAGI2CPlus1K || type == MfUltralightTypeNTAGI2CPlus2K) { + if(page == 0x00F8) new_page = 234; + if(page == 0x00F9) new_page = 235; + } else if(type == MfUltralightTypeNTAGI2C1K || type == MfUltralightTypeNTAGI2C2K) { + if(page == 0x00F8) new_page = (type == MfUltralightTypeNTAGI2C1K) ? 227 : 481; + if(page == 0x00F9) new_page = (type == MfUltralightTypeNTAGI2C1K) ? 228 : 482; + } + return new_page; +} + +const MfUltralightI2CPageProvider provider_methods[] = { + mf_ultralight_i2c_page_provider_for_sector0, + mf_ultralight_i2c_page_provider_for_sector1, + mf_ultralight_i2c_page_provider_for_sector2, + mf_ultralight_i2c_page_provider_for_sector3, +}; + +uint16_t + mf_ultralight_i2c_provide_page_by_requested(uint16_t page, MfUltralightListener* instance) { + uint16_t result = page; + if(instance->sector < sizeof(provider_methods)) { + MfUltralightI2CPageProvider provider = provider_methods[instance->sector]; + result = provider(page, instance->data->type); + } + return result; } \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index ac390a800e2..26e93c8e3d5 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -78,6 +78,15 @@ void mf_ultralight_composite_command_reset(MfUltralightListener* instance); bool mf_ultralight_composite_command_in_progress(MfUltralightListener* instance); MfUltralightCommand mf_ultralight_composite_command_run(MfUltralightListener* instance, BitBuffer* buffer); + +bool mf_ultralight_is_i2c_tag(MfUltralightType type); +bool mf_ultralight_i2c_validate_pages( + uint16_t start_page, + uint16_t end_page, + MfUltralightListener* instance); + +uint16_t + mf_ultralight_i2c_provide_page_by_requested(uint16_t page, MfUltralightListener* instance); #ifdef __cplusplus } #endif From c2b8b960c92511e8e1ed3fb98d7f4dfccf551df5 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 7 Sep 2023 23:58:20 +0300 Subject: [PATCH 18/26] READ and FAST_READ commands implementation and adjustments Both cmds now work through one function NtagI2C support added --- .../mf_ultralight/mf_ultralight_listener.c | 136 ++++++++++++++---- 1 file changed, 106 insertions(+), 30 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 0798364e3af..2fad5b11d4d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -22,7 +22,7 @@ typedef struct { static bool mf_ultralight_listener_check_access( MfUltralightListener* instance, - uint8_t start_page, + uint16_t start_page, MfUltralightListenerAccessType access_type) { bool access_success = false; bool is_write_op = (access_type == MfUltralightListenerAccessTypeWrite); @@ -59,48 +59,119 @@ static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instanc iso14443_3a_listener_tx(instance->iso14443_3a_listener, instance->tx_buffer); }; +static void mf_ultralight_listener_perform_read( + MfUltralightPage* pages, + MfUltralightListener* instance, + uint16_t start_page, + uint8_t page_cnt, + bool do_i2c_page_check) { + uint16_t pages_total = instance->data->pages_total; + mf_ultralight_mirror_read_prepare(start_page, instance); + for(uint8_t i = 0; i < page_cnt; i++) { + uint16_t page = start_page + i; + + if(do_i2c_page_check && !mf_ultralight_i2c_validate_pages(page, page, instance)) + memset(pages[i].data, 0, sizeof(MfUltralightPage)); + else if(mf_ultralight_is_page_pwd_or_pack(instance->data->type, page)) + memset(pages[i].data, 0, sizeof(MfUltralightPage)); + else { + if(do_i2c_page_check) + page = mf_ultralight_i2c_provide_page_by_requested(page, instance); + + pages[i] = instance->data->page[page % pages_total]; + mf_ultralight_mirror_read_handler(page, pages[i].data, instance); + } + } +} + static MfUltralightCommand mf_ultralight_listener_read_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { - uint8_t start_page = bit_buffer_get_byte(buffer, 1); + uint16_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; - MfUltralightPageReadCommandData read_cmd_data = {}; MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_READ: %d", start_page); - if(pages_total < start_page) { - instance->state = MfUltraligthListenerStateIdle; - instance->auth_state = MfUltralightListenerAuthStateIdle; - } else if(!mf_ultralight_listener_check_access( - instance, start_page, MfUltralightListenerAccessTypeRead)) { - instance->state = MfUltraligthListenerStateIdle; - instance->auth_state = MfUltralightListenerAuthStateIdle; - } else { - mf_ultralight_mirror_read_prepare(start_page, instance); - - uint16_t config_page = mf_ultralight_get_config_page_num(instance->data->type); - for(size_t i = 0; i < 4; i++) { - bool hide_data = - ((config_page != 0) && ((i == config_page + 1U) || (i == config_page + 2U))); - if(hide_data) { - memset(read_cmd_data.page[i].data, 0, sizeof(MfUltralightPage)); - } else { - uint8_t current_page = start_page + i; - read_cmd_data.page[i] = instance->data->page[current_page % pages_total]; - - mf_ultralight_mirror_read_handler( - current_page, read_cmd_data.page[i].data, instance); + do { + bool do_i2c_page_check = mf_ultralight_is_i2c_tag(instance->data->type); + + if(do_i2c_page_check) { + if(!mf_ultralight_i2c_validate_pages(start_page, start_page, instance)) break; + } else if(pages_total < start_page) { + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + command = MfUltralightCommandNotProcessedNAK; + break; + } + + if(!mf_ultralight_listener_check_access( + instance, start_page, MfUltralightListenerAccessTypeRead)) { + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + command = MfUltralightCommandNotProcessedNAK; + break; + } + + MfUltralightPage pages[4] = {}; + mf_ultralight_listener_perform_read(pages, instance, start_page, 4, do_i2c_page_check); + + bit_buffer_copy_bytes(instance->tx_buffer, (uint8_t*)pages, sizeof(pages)); + iso14443_3a_listener_send_standard_frame( + instance->iso14443_3a_listener, instance->tx_buffer); + command = MfUltralightCommandProcessed; + + } while(false); + + return command; +} + +static MfUltralightCommand + mf_ultralight_listener_fast_read_handler(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; + FURI_LOG_D(TAG, "CMD_FAST_READ"); + + do { + if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastRead)) + break; + uint16_t pages_total = instance->data->pages_total; + uint16_t start_page = bit_buffer_get_byte(buffer, 1); + uint16_t end_page = bit_buffer_get_byte(buffer, 2); + bool i2c_tag = mf_ultralight_is_i2c_tag(instance->data->type); + + if(i2c_tag) { + if(!mf_ultralight_i2c_validate_pages(start_page, end_page, instance)) { + command = MfUltralightCommandNotProcessedNAK; + break; } + } else if(end_page > pages_total - 1) { + command = MfUltralightCommandNotProcessedNAK; + break; } - bit_buffer_copy_bytes( - instance->tx_buffer, - (uint8_t*)&read_cmd_data, - sizeof(MfUltralightPageReadCommandData)); + if(end_page < start_page) { + command = MfUltralightCommandNotProcessedNAK; + break; + } + + if(!mf_ultralight_listener_check_access( + instance, start_page, MfUltralightListenerAccessTypeRead) || + !mf_ultralight_listener_check_access( + instance, end_page, MfUltralightListenerAccessTypeRead)) { + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + command = MfUltralightCommandNotProcessedNAK; + break; + } + + MfUltralightPage pages[64] = {}; + uint8_t page_cnt = (end_page - start_page) + 1; + mf_ultralight_listener_perform_read(pages, instance, start_page, page_cnt, true); + + bit_buffer_copy_bytes(instance->tx_buffer, (uint8_t*)pages, page_cnt * 4); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); command = MfUltralightCommandProcessed; - } + } while(false); return command; } @@ -406,6 +477,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 2 * 8, .callback = mf_ultralight_listener_read_page_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_FAST_READ, + .cmd_len_bits = 3 * 8, + .callback = mf_ultralight_listener_fast_read_handler, + }, { .cmd = MF_ULTRALIGHT_CMD_WRITE_PAGE, .cmd_len_bits = 6 * 8, From fa13faffb708ef7ba8acdd7c7cfac7573a76e730 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 8 Sep 2023 00:02:31 +0300 Subject: [PATCH 19/26] Update api_symbols.csv --- firmware/targets/f7/api_symbols.csv | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 90ad35b921e..2b3f6a5b58b 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,38.1,, +Version,+,39.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2126,11 +2126,13 @@ Function,+,mf_ultralight_get_config_page_num,uint16_t,MfUltralightType Function,+,mf_ultralight_get_device_name,const char*,"const MfUltralightData*, NfcDeviceNameType" Function,+,mf_ultralight_get_feature_support_set,uint32_t,MfUltralightType Function,+,mf_ultralight_get_pages_total,uint16_t,MfUltralightType +Function,+,mf_ultralight_get_pwd_page_num,uint8_t,MfUltralightType Function,+,mf_ultralight_get_type_by_version,MfUltralightType,MfUltralightVersion* Function,+,mf_ultralight_get_uid,const uint8_t*,"const MfUltralightData*, size_t*" Function,+,mf_ultralight_is_all_data_read,_Bool,const MfUltralightData* Function,+,mf_ultralight_is_counter_configured,_Bool,const MfUltralightData* Function,+,mf_ultralight_is_equal,_Bool,"const MfUltralightData*, const MfUltralightData*" +Function,+,mf_ultralight_is_page_pwd_or_pack,_Bool,"MfUltralightType, uint16_t" Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t" Function,+,mf_ultralight_poller_read_card,MfUltralightError,"Nfc*, MfUltralightData*" Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" From 888838043217127cb66d3ffee8568cff213a3451 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 8 Sep 2023 00:04:33 +0300 Subject: [PATCH 20/26] Renamed i2c bool switch and fixed FAST_READ where it was hardcoded --- .../protocols/mf_ultralight/mf_ultralight_listener.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 2fad5b11d4d..fa6daf9f41b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -93,9 +93,9 @@ static MfUltralightCommand FURI_LOG_D(TAG, "CMD_READ: %d", start_page); do { - bool do_i2c_page_check = mf_ultralight_is_i2c_tag(instance->data->type); + bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type); - if(do_i2c_page_check) { + if(do_i2c_check) { if(!mf_ultralight_i2c_validate_pages(start_page, start_page, instance)) break; } else if(pages_total < start_page) { instance->state = MfUltraligthListenerStateIdle; @@ -113,7 +113,7 @@ static MfUltralightCommand } MfUltralightPage pages[4] = {}; - mf_ultralight_listener_perform_read(pages, instance, start_page, 4, do_i2c_page_check); + mf_ultralight_listener_perform_read(pages, instance, start_page, 4, do_i2c_check); bit_buffer_copy_bytes(instance->tx_buffer, (uint8_t*)pages, sizeof(pages)); iso14443_3a_listener_send_standard_frame( @@ -136,9 +136,9 @@ static MfUltralightCommand uint16_t pages_total = instance->data->pages_total; uint16_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t end_page = bit_buffer_get_byte(buffer, 2); - bool i2c_tag = mf_ultralight_is_i2c_tag(instance->data->type); + bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type); - if(i2c_tag) { + if(do_i2c_check) { if(!mf_ultralight_i2c_validate_pages(start_page, end_page, instance)) { command = MfUltralightCommandNotProcessedNAK; break; @@ -165,7 +165,7 @@ static MfUltralightCommand MfUltralightPage pages[64] = {}; uint8_t page_cnt = (end_page - start_page) + 1; - mf_ultralight_listener_perform_read(pages, instance, start_page, page_cnt, true); + mf_ultralight_listener_perform_read(pages, instance, start_page, page_cnt, do_i2c_check); bit_buffer_copy_bytes(instance->tx_buffer, (uint8_t*)pages, page_cnt * 4); iso14443_3a_listener_send_standard_frame( From 7128dfcdea86e094296932955b294712822199b4 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 8 Sep 2023 00:30:01 +0300 Subject: [PATCH 21/26] Replaced some parts of code by defines --- .../mf_ultralight/mf_ultralight_listener_i.c | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c index 8afaac4819f..20e37f398b2 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -2,6 +2,14 @@ #include +#define MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(page, start, end) (page >= start && page <= end) + +#define MF_ULTRALIGHT_I2C_PAGE_ON_SESSION_REG(page) \ + MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(page, 0x00EC, 0x00ED) + +#define MF_ULTRALIGHT_I2C_PAGE_ON_MIRRORED_SESSION_REG(page) \ + MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(page, 0x00F8, 0x00F9) + static MfUltralightMirrorConf mf_ultralight_mirror_check_mode( const MfUltralightConfigPages* const config, const MfUltralightListenerAuthState auth_state) { @@ -186,14 +194,6 @@ void mf_ultralight_composite_command_set_next( instance->composite_cmd.callback = handler; } -static bool mf_ultralight_i2c_is_page_on_session_registers(uint16_t page) { - return page >= 0x00EC && page <= 0x00ED; -} - -static bool mf_ultralight_i2c_is_page_on_mirrored_session_registers(uint16_t page) { - return page >= 0x00F8 && page <= 0x00F9; -} - static bool mf_ultralight_i2c_page_validator_for_sector0( uint16_t start_page, uint16_t end_page, @@ -204,12 +204,12 @@ static bool mf_ultralight_i2c_page_validator_for_sector0( if(start_page <= 0xE9 && end_page <= 0xE9) { valid = true; } else if( - mf_ultralight_i2c_is_page_on_session_registers(start_page) && - mf_ultralight_i2c_is_page_on_session_registers(end_page)) { + MF_ULTRALIGHT_I2C_PAGE_ON_SESSION_REG(start_page) && + MF_ULTRALIGHT_I2C_PAGE_ON_SESSION_REG(end_page)) { valid = true; } } else if(type == MfUltralightTypeNTAGI2C1K) { - if((start_page <= 0xE2) || (start_page >= 0xE8 && start_page <= 0xE9)) { + if((start_page <= 0xE2) || MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(start_page, 0x00E8, 0x00E9)) { valid = true; } } else if(type == MfUltralightTypeNTAGI2C2K) { @@ -227,7 +227,8 @@ static bool mf_ultralight_i2c_page_validator_for_sector1( if(type == MfUltralightTypeNTAGI2CPlus2K) { valid = (start_page <= 0xFF && end_page <= 0xFF); } else if(type == MfUltralightTypeNTAGI2C2K) { - valid = ((start_page >= 0xE8 && start_page <= 0xE9) || (start_page <= 0xE0)); + valid = + (MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(start_page, 0x00E8, 0x00E9) || (start_page <= 0xE0)); } else if(type == MfUltralightTypeNTAGI2C1K || type == MfUltralightTypeNTAGI2CPlus1K) { valid = false; } @@ -251,13 +252,7 @@ static bool mf_ultralight_i2c_page_validator_for_sector3( MfUltralightType type) { UNUSED(type); UNUSED(end_page); - bool valid = false; - - if(mf_ultralight_i2c_is_page_on_mirrored_session_registers(start_page)) { - valid = true; - } - - return valid; + return MF_ULTRALIGHT_I2C_PAGE_ON_MIRRORED_SESSION_REG(start_page); } typedef bool ( From 2476dc84de2ea13c095d2f5969f1bd654371ede8 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 8 Sep 2023 07:56:39 +0300 Subject: [PATCH 22/26] VCSL cmd added for Ultralights --- lib/nfc/protocols/mf_ultralight/mf_ultralight.h | 1 + .../mf_ultralight/mf_ultralight_listener.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 151dd3f9db5..bde08cd487a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -19,6 +19,7 @@ extern "C" { #define MF_ULTRALIGHT_CMD_INCR_CNT (0xA5) #define MF_ULTRALIGHT_CMD_CHECK_TEARING (0x3E) #define MF_ULTRALIGHT_CMD_AUTH (0x1B) +#define MF_ULTRALIGHT_CMD_VCSL (0x4B) #define MF_ULTRALIGHT_CMD_ACK (0x0A) #define MF_ULTRALIGHT_CMD_NACK (0x00) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 71cfb88f690..39171989ca1 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -352,6 +352,15 @@ static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( return command; } +static MfUltralightCommand + mf_ultralight_listener_vcsl_handler(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; + UNUSED(instance); + UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_VCSL"); + return command; +} + static MfUltralightCommand mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; @@ -527,6 +536,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 2 * 8, .callback = mf_ultralight_comp_write_handler_p1, }, + { + .cmd = MF_ULTRALIGHT_CMD_VCSL, + .cmd_len_bits = 21 * 8, + .callback = mf_ultralight_listener_vcsl_handler, + }, }; static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { From 2dc870c07bf41d09ff897e312bdf79a6baad179b Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 8 Sep 2023 08:39:59 +0300 Subject: [PATCH 23/26] Implementation of VCSL cmd added --- .../mf_ultralight/mf_ultralight_listener.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 39171989ca1..4e520e368c5 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -358,6 +358,20 @@ static MfUltralightCommand UNUSED(instance); UNUSED(buffer); FURI_LOG_D(TAG, "CMD_VCSL"); + do { + if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportVcsl)) + break; + + MfUltralightConfigPages* config; + if(!mf_ultralight_get_config_page(instance->data, &config)) break; + + bit_buffer_set_size_bytes(instance->tx_buffer, 1); + bit_buffer_set_byte(instance->tx_buffer, 0, config->vctid); + iso14443_3a_listener_send_standard_frame( + instance->iso14443_3a_listener, instance->tx_buffer); + command = MfUltralightCommandProcessed; + } while(false); + return command; } From 2ad0344958e54d9ad6f31c46909813b12b200387 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Sep 2023 12:16:42 +0300 Subject: [PATCH 24/26] Function for static lock bytes processing added --- .../mf_ultralight/mf_ultralight_listener_i.c | 70 +++++++++++++++++-- .../mf_ultralight/mf_ultralight_listener_i.h | 12 ++++ 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c index db3c24e0487..9eab838a9bd 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -2,14 +2,38 @@ #include -#define MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(page, start, end) \ - (((page) >= (start)) && ((page) <= (end))) +#define MF_ULTRALIGHT_STATIC_BIT_LOCK_OTP_CC 0 +#define MF_ULTRALIGHT_STATIC_BIT_LOCK_BL_9_4 1 +#define MF_ULTRALIGHT_STATIC_BIT_LOCK_BL_15_10 2 + +#define MF_ULTRALIGHT_STATIC_BIT_ACTIVE(lock_bits, bit) ((lock_bits & (1U << bit)) != 0) +#define MF_ULTRALIGHT_STATIC_BITS_SET(lock_bits, mask) (lock_bits |= mask) +#define MF_ULTRALIGHT_STATIC_BITS_CLR(lock_bits, mask) (lock_bits &= ~mask) + +#define MF_ULTRALIGHT_PAGE_LOCKED(lock_bits, page) MF_ULTRALIGHT_STATIC_BIT_ACTIVE(lock_bits, page) + +#define MF_ULTRALIGHT_STATIC_BIT_OTP_CC_LOCKED(lock_bits) \ + MF_ULTRALIGHT_STATIC_BIT_ACTIVE(lock_bits, MF_ULTRALIGHT_STATIC_BIT_LOCK_OTP_CC) + +#define MF_ULTRALIGHT_STATIC_BITS_9_4_LOCKED(lock_bits) \ + MF_ULTRALIGHT_STATIC_BIT_ACTIVE(lock_bits, MF_ULTRALIGHT_STATIC_BIT_LOCK_BL_9_4) + +#define MF_ULTRALIGHT_STATIC_BITS_15_10_LOCKED(lock_bits) \ + MF_ULTRALIGHT_STATIC_BIT_ACTIVE(lock_bits, MF_ULTRALIGHT_STATIC_BIT_LOCK_BL_15_10) + +#define MF_ULTRALIGHT_STATIC_LOCK_L_OTP_CC_MASK (1U << 3) +#define MF_ULTRALIGHT_STATIC_LOCK_L_9_4_MASK \ + ((1U << 9) | (1U << 8) | (1U << 7) | (1U << 6) | (1U << 5) | (1U << 4)) +#define MF_ULTRALIGHT_STATIC_LOCK_L_15_10_MASK \ + ((1U << 15) | (1U << 14) | (1U << 13) | (1U << 12) | (1U << 11) | (1U << 10)) + +#define MF_ULTRALIGHT_PAGE_IN_BOUNDS(page, start, end) (((page) >= (start)) && ((page) <= (end))) #define MF_ULTRALIGHT_I2C_PAGE_ON_SESSION_REG(page) \ - MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(page, 0x00EC, 0x00ED) + MF_ULTRALIGHT_PAGE_IN_BOUNDS(page, 0x00EC, 0x00ED) #define MF_ULTRALIGHT_I2C_PAGE_ON_MIRRORED_SESSION_REG(page) \ - MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(page, 0x00F8, 0x00F9) + MF_ULTRALIGHT_PAGE_IN_BOUNDS(page, 0x00F8, 0x00F9) static MfUltralightMirrorConf mf_ultralight_mirror_check_mode( const MfUltralightConfigPages* const config, @@ -228,7 +252,7 @@ static bool mf_ultralight_i2c_page_validator_for_sector0( valid = true; } } else if(type == MfUltralightTypeNTAGI2C1K) { - if((start_page <= 0xE2) || MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(start_page, 0x00E8, 0x00E9)) { + if((start_page <= 0xE2) || MF_ULTRALIGHT_PAGE_IN_BOUNDS(start_page, 0x00E8, 0x00E9)) { valid = true; } } else if(type == MfUltralightTypeNTAGI2C2K) { @@ -246,8 +270,7 @@ static bool mf_ultralight_i2c_page_validator_for_sector1( if(type == MfUltralightTypeNTAGI2CPlus2K) { valid = (start_page <= 0xFF && end_page <= 0xFF); } else if(type == MfUltralightTypeNTAGI2C2K) { - valid = - (MF_ULTRALIGHT_I2C_PAGE_IN_BOUNDS(start_page, 0x00E8, 0x00E9) || (start_page <= 0xE0)); + valid = (MF_ULTRALIGHT_PAGE_IN_BOUNDS(start_page, 0x00E8, 0x00E9) || (start_page <= 0xE0)); } else if(type == MfUltralightTypeNTAGI2C1K || type == MfUltralightTypeNTAGI2CPlus1K) { valid = false; } @@ -368,3 +391,36 @@ uint16_t } return result; } + +void mf_ultralight_static_lock_bytes_prepare(MfUltralightListener* instance) { + instance->static_lock = (uint16_t*)&instance->data->page[2].data[2]; +} + +void mf_ultralight_static_lock_bytes_write( + MfUltralightStaticLockData* const lock_bits, + uint16_t new_bits) { + uint16_t current_locks = *lock_bits; + + if(MF_ULTRALIGHT_STATIC_BIT_OTP_CC_LOCKED(current_locks)) + MF_ULTRALIGHT_STATIC_BITS_CLR(new_bits, MF_ULTRALIGHT_STATIC_LOCK_L_OTP_CC_MASK); + + if(MF_ULTRALIGHT_STATIC_BITS_9_4_LOCKED(current_locks)) + MF_ULTRALIGHT_STATIC_BITS_CLR(new_bits, MF_ULTRALIGHT_STATIC_LOCK_L_9_4_MASK); + + if(MF_ULTRALIGHT_STATIC_BITS_15_10_LOCKED(current_locks)) + MF_ULTRALIGHT_STATIC_BITS_CLR(new_bits, MF_ULTRALIGHT_STATIC_LOCK_L_15_10_MASK); + + MF_ULTRALIGHT_STATIC_BITS_SET(current_locks, new_bits); + *lock_bits = current_locks; +} + +bool mf_ultralight_static_lock_check_page( + const MfUltralightStaticLockData* const lock_bits, + uint16_t page) { + bool locked = false; + if(MF_ULTRALIGHT_PAGE_IN_BOUNDS(page, 0x0003, 0x000F)) { + uint16_t current_locks = *lock_bits; + locked = MF_ULTRALIGHT_PAGE_LOCKED(current_locks, page); + } + return locked; +} \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index 3ba1c4bcfda..f3934218a9f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -41,6 +41,8 @@ typedef struct { FuriString* ascii_mirror_data; } MfUltralightMirrorMode; +typedef uint16_t MfUltralightStaticLockData; + struct MfUltralightListener { Iso14443_3aListener* iso14443_3a_listener; MfUltralightListenerAuthState auth_state; @@ -48,6 +50,7 @@ struct MfUltralightListener { BitBuffer* tx_buffer; MfUltralightFeatureSupport features; MfUltralightConfigPages* config; + MfUltralightStaticLockData* static_lock; NfcGenericEvent generic_event; MfUltralightListenerEvent mfu_event; @@ -88,6 +91,15 @@ bool mf_ultralight_i2c_validate_pages( uint16_t mf_ultralight_i2c_provide_page_by_requested(uint16_t page, MfUltralightListener* instance); + +void mf_ultralight_static_lock_bytes_prepare(MfUltralightListener* instance); +void mf_ultralight_static_lock_bytes_write( + MfUltralightStaticLockData* const lock_bits, + uint16_t new_bits); +bool mf_ultralight_static_lock_check_page( + const MfUltralightStaticLockData* const lock_bits, + uint16_t page); + #ifdef __cplusplus } #endif From 7db94fe0b67dc9a28a70226b47e36c29400fcd5c Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Sep 2023 12:18:41 +0300 Subject: [PATCH 25/26] Static lock bytes processing added to preparation and CMD_WRITE --- .../mf_ultralight/mf_ultralight_listener.c | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 7639f329e17..18ae087e81d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -177,14 +177,24 @@ static MfUltralightCommand FURI_LOG_D(TAG, "CMD_WRITE"); - if(pages_total < start_page || - !mf_ultralight_listener_check_access( - instance, start_page, MfUltralightListenerAccessTypeWrite)) { - } else { + do { + if(pages_total < start_page || + !mf_ultralight_listener_check_access( + instance, start_page, MfUltralightListenerAccessTypeWrite)) + break; + + if(mf_ultralight_static_lock_check_page(instance->static_lock, start_page)) break; + const uint8_t* rx_data = bit_buffer_get_data(buffer); - memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); + + if(start_page == 2) + mf_ultralight_static_lock_bytes_write( + instance->static_lock, *((uint16_t*)&rx_data[4])); + else + memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); command = MfUltralightCommandProcessedACK; - } + + } while(false); return command; } @@ -616,6 +626,7 @@ MfUltralightListener* mf_ultralight_listener_alloc( instance->mirror.ascii_mirror_data = furi_string_alloc(); instance->iso14443_3a_listener = iso14443_3a_listener; instance->data = data; + mf_ultralight_static_lock_bytes_prepare(instance); mf_ultralight_listener_prepare_emulation(instance); mf_ultralight_composite_command_reset(instance); instance->sector = 0; From 5c72156d523a0ee56aa29d33282b3db4d6619ce9 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Sep 2023 12:36:30 +0300 Subject: [PATCH 26/26] Static lock bytes added to COMP_WRITE command --- .../protocols/mf_ultralight/mf_ultralight_listener.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 18ae087e81d..13b81cc0937 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -438,7 +438,12 @@ static MfUltralightCommand const uint8_t* rx_data = bit_buffer_get_data(buffer); uint8_t start_page = instance->composite_cmd.data; - memcpy(instance->data->page[start_page].data, &rx_data[0], sizeof(MfUltralightPage)); + + if(start_page == 2) + mf_ultralight_static_lock_bytes_write( + instance->static_lock, *((uint16_t*)&rx_data[2])); + else + memcpy(instance->data->page[start_page].data, &rx_data[0], sizeof(MfUltralightPage)); command = MfUltralightCommandProcessedACK; } while(false); @@ -464,6 +469,11 @@ static MfUltralightCommand break; } + if(mf_ultralight_static_lock_check_page(instance->static_lock, start_page)) { + command = MfUltralightCommandNotProcessedNAK; + break; + } + instance->composite_cmd.data = start_page; command = MfUltralightCommandProcessedACK; mf_ultralight_composite_command_set_next(instance, mf_ultralight_comp_write_handler_p2);