Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
95c0a86
Update nfc.c, iso14443_3a_listener.c, and mf_ultralight_listener.c
RebornedBrain Aug 8, 2023
7957012
Removed a lot of unnecessary logs to comply timings
RebornedBrain Aug 9, 2023
1d460f7
Poller adjusted to read single tearing flag for NTAGs
RebornedBrain Aug 9, 2023
af8d4fd
Fix for proper saving of tear flags
RebornedBrain Aug 9, 2023
3bcd9af
CHECK_TEARING_CMD support for NTAGs
RebornedBrain Aug 9, 2023
54fea6f
Duplicated gpio call removed
RebornedBrain Aug 9, 2023
cb41793
Added TODO for future work
RebornedBrain Aug 9, 2023
07f5302
Fix MF Classic emulation
RebornedBrain Aug 10, 2023
db5f72e
Function mf_ultralight_support_feature added to API
RebornedBrain Aug 11, 2023
5286674
Adjusted listener and poller with new function and removed some nesting
RebornedBrain Aug 11, 2023
c8f6117
Merge branch 'gornek/nfc_refactoring'
RebornedBrain Aug 11, 2023
af73cc4
NFC layer adjustments
RebornedBrain Aug 17, 2023
eb9b444
iso14443_3a_listener cleanup to avoid duplicate calls and race condit…
RebornedBrain Aug 17, 2023
c5d3b0b
Added result statuses for mfu commands and command signature changed,…
RebornedBrain Aug 17, 2023
44c364a
mf_ultralight_listener_run adjusted to process statuses
RebornedBrain Aug 17, 2023
d404c65
Comments adjusted according bits set
RebornedBrain Aug 17, 2023
50cd625
Merge branch 'gornek/nfc_refactoring'
RebornedBrain Aug 18, 2023
d927cb7
Renamed enum type and values
RebornedBrain Aug 18, 2023
9d8e1a8
Command adjustments
RebornedBrain Aug 21, 2023
a9db709
Merge branch 'gornek/nfc_refactoring'
RebornedBrain Aug 21, 2023
95cba95
f_hal_nfc_listener_tx is now blocking
RebornedBrain Aug 21, 2023
1d97927
Merge branch 'gornek/nfc_refactoring'
RebornedBrain Aug 22, 2023
a905c75
Adjusted READ_CNT function to check nfc_cnt_en for NTAG
RebornedBrain Aug 22, 2023
a62aa65
INCR_CNT command added for Ultralight
RebornedBrain Aug 22, 2023
c033ac2
IncrValue is now taken using MfUltralightCounter union
RebornedBrain Aug 22, 2023
1a6422e
Merge branch 'gornek/nfc_refactoring'
RebornedBrain Aug 28, 2023
dd5a8cc
Update api_symbols.csv
RebornedBrain Aug 28, 2023
580865e
New struct for mirror mode added
RebornedBrain Aug 28, 2023
4a374d3
Mirror mode implementation added
RebornedBrain Aug 28, 2023
09b43b7
Moved mirror implementation to a separate file mf_ultralight_listener…
RebornedBrain Aug 29, 2023
0ba2dad
Adjustments according to PR comments
RebornedBrain Aug 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion firmware/targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,35.2,,
Version,+,36.1,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
Expand Down
12 changes: 11 additions & 1 deletion lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,23 @@ static MfUltralightCommand
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 {
read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total];
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);
}
}

bit_buffer_copy_bytes(
instance->tx_buffer,
(uint8_t*)&read_cmd_data,
Expand Down Expand Up @@ -364,6 +371,7 @@ static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* insta
MfUltralightData* data = instance->data;
instance->features = mf_ultralight_get_feature_support_set(data->type);
mf_ultralight_get_config_page(data, &instance->config);
mf_ultraligt_mirror_prepare_emulation(instance);
}

MfUltralightListener* mf_ultralight_listener_alloc(
Expand All @@ -372,6 +380,7 @@ MfUltralightListener* mf_ultralight_listener_alloc(
furi_assert(iso14443_3a_listener);

MfUltralightListener* instance = malloc(sizeof(MfUltralightListener));
instance->mirror.ascii_mirror_data = furi_string_alloc();
instance->iso14443_3a_listener = iso14443_3a_listener;
instance->data = mf_ultralight_alloc();
mf_ultralight_copy(instance->data, data);
Expand All @@ -392,6 +401,7 @@ void mf_ultralight_listener_free(MfUltralightListener* instance) {
furi_assert(instance->tx_buffer);

bit_buffer_free(instance->tx_buffer);
furi_string_free(instance->mirror.ascii_mirror_data);
mf_ultralight_free(instance->data);
free(instance);
}
Expand Down
164 changes: 164 additions & 0 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#include "mf_ultralight_listener_i.h"

#include <furi.h>

static MfUltralightMirrorConf mf_ultralight_mirror_check_mode(
const MfUltralightConfigPages* const config,
const MfUltralightListenerAuthState auth_state) {
MfUltralightMirrorConf mirror_mode = config->mirror.mirror_conf;

if(mirror_mode == MfUltralightMirrorNone || mirror_mode == MfUltralightMirrorUid)
return mirror_mode;

if(!config->access.nfc_cnt_en ||
(config->access.nfc_cnt_pwd_prot && auth_state != MfUltralightListenerAuthStateSuccess)) {
mirror_mode = mirror_mode == MfUltralightMirrorCounter ? MfUltralightMirrorNone :
MfUltralightMirrorUid;
}
return mirror_mode;
}

static bool mf_ultralight_mirror_check_boundaries(MfUltralightListener* instance) {
const MfUltralightConfigPages* const conf = instance->config;

uint8_t last_user_page = mf_ultralight_get_config_page_num(instance->data->type) - 2;

uint8_t max_page_offset = 0;
uint8_t max_byte_offset = 2;

MfUltralightMirrorConf mode = mf_ultralight_mirror_check_mode(conf, instance->auth_state);

bool result = false;
bool again = false;
do {
if(mode == MfUltralightMirrorNone) {
break;
} else if(mode == MfUltralightMirrorUid) {
max_page_offset = 3;
} else if(mode == MfUltralightMirrorCounter) {
max_page_offset = 1;
} else if(mode == MfUltralightMirrorUidCounter) {
max_page_offset = 5;
max_byte_offset = 3;
}

instance->mirror.actual_mode = mode;

if(conf->mirror_page <= 3) break;
if(conf->mirror_page < last_user_page - max_page_offset) {
result = true;
break;
}
if(conf->mirror_page == last_user_page - max_page_offset) {
result = (conf->mirror.mirror_byte <= max_byte_offset);
break;
}

if(conf->mirror_page > last_user_page - max_page_offset &&
mode == MfUltralightMirrorUidCounter) {
mode = MfUltralightMirrorUid;
again = true;
}
} while(again);

return result;
}

static bool mf_ultralight_mirror_enabled(MfUltralightListener* instance) {
bool mirror_enabled = false;
if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportAsciiMirror) &&
(instance->config != NULL) && mf_ultralight_mirror_check_boundaries(instance)) {
mirror_enabled = true;
}
instance->mirror.enabled = mirror_enabled;
return instance->mirror.enabled;
}

static uint8_t mf_ultralight_get_mirror_data_size(MfUltralightMirrorConf mode) {
switch(mode) {
case MfUltralightMirrorUid:
return 14;
case MfUltralightMirrorCounter:
return 6;
case MfUltralightMirrorUidCounter:
return 21;
default:
return 0;
}
}

static uint8_t mf_ultralight_get_mirror_last_page(MfUltralightListener* instance) {
uint8_t strSize = mf_ultralight_get_mirror_data_size(instance->mirror.actual_mode);
return (instance->config->mirror_page + 1U + strSize / 4);
}

static uint8_t mf_ultralight_get_ascii_offset(uint8_t start_page, MfUltralightListener* instance) {
uint8_t start_offset = 0;
if(instance->config->mirror.mirror_conf == MfUltralightMirrorCounter) start_offset = 15;

uint8_t ascii_offset = start_offset;

if(start_page > instance->config->mirror_page)
ascii_offset = (start_page - instance->config->mirror_page) * 4 -
instance->config->mirror.mirror_byte + start_offset;

return ascii_offset;
}

static uint8_t mf_ultralight_get_ascii_end(MfUltralightMirrorConf mode) {
return (mode == MfUltralightMirrorUid) ? 14 : 21;
}

static uint8_t mf_ultralight_get_byte_offset(
uint8_t current_page,
const MfUltralightConfigPages* const config) {
return (current_page > config->mirror_page) ? 0 : config->mirror.mirror_byte;
}

static void mf_ultraligt_format_mirror_data(
FuriString* str,
const uint8_t* const data,
const uint8_t data_len) {
for(uint8_t i = 0; i < data_len; i++) furi_string_cat_printf(str, "%02X", data[i]);
}

void mf_ultralight_mirror_read_prepare(uint8_t start_page, MfUltralightListener* instance) {
if(mf_ultralight_mirror_enabled(instance)) {
instance->mirror.ascii_offset = mf_ultralight_get_ascii_offset(start_page, instance);
instance->mirror.ascii_end = mf_ultralight_get_ascii_end(instance->mirror.actual_mode);

instance->mirror.mirror_last_page = mf_ultralight_get_mirror_last_page(instance);
}
}

void mf_ultralight_mirror_read_handler(
uint8_t mirror_page_num,
uint8_t* dest,
MfUltralightListener* instance) {
if(instance->mirror.enabled && mirror_page_num >= instance->config->mirror_page &&
mirror_page_num <= instance->mirror.mirror_last_page) {
uint8_t byte_offset = mf_ultralight_get_byte_offset(mirror_page_num, instance->config);

uint8_t ascii_offset = instance->mirror.ascii_offset;
uint8_t ascii_end = instance->mirror.ascii_end;
uint8_t* source = (uint8_t*)furi_string_get_cstr(instance->mirror.ascii_mirror_data);
for(uint8_t j = byte_offset; (j < 4) && (ascii_offset < ascii_end); j++) {
dest[j] = source[ascii_offset];
ascii_offset++;
}
}
}

void mf_ultraligt_mirror_prepare_emulation(MfUltralightListener* instance) {
mf_ultraligt_format_mirror_data(
instance->mirror.ascii_mirror_data,
instance->data->iso14443_3a_data->uid,
instance->data->iso14443_3a_data->uid_len);

furi_string_push_back(instance->mirror.ascii_mirror_data, 'x');

mf_ultraligt_format_mirror_data(
instance->mirror.ascii_mirror_data,
instance->data->counter[2].data,
sizeof(instance->data->counter[2].data));
}
16 changes: 16 additions & 0 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ typedef enum {
MfUltraligthListenerStateIdle,
} MfUltraligthListenerState;

typedef struct {
uint8_t enabled;
uint8_t ascii_offset;
uint8_t ascii_end;
uint8_t mirror_last_page;
MfUltralightMirrorConf actual_mode;
FuriString* ascii_mirror_data;
} MfUltralightMirrorMode;

struct MfUltralightListener {
Iso14443_3aListener* iso14443_3a_listener;
MfUltralightListenerAuthState auth_state;
Expand All @@ -31,9 +40,16 @@ struct MfUltralightListener {
MfUltralightListenerEvent mfu_event;
MfUltralightListenerEventData mfu_event_data;
NfcGenericCallback callback;
MfUltralightMirrorMode mirror;
void* context;
};

void mf_ultraligt_mirror_prepare_emulation(MfUltralightListener* instance);
void mf_ultralight_mirror_read_prepare(uint8_t start_page, MfUltralightListener* instance);
void mf_ultralight_mirror_read_handler(
uint8_t mirror_page_num,
uint8_t* dest,
MfUltralightListener* instance);
#ifdef __cplusplus
}
#endif