From 1b6b4b65227750f4b5842c151cc98ad2f3ff4ea3 Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Tue, 29 Nov 2022 01:00:41 +0100 Subject: [PATCH 1/2] cleaned up SLIX code added callbacks for card-specific ISO15693-3 handling --- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 26 +- .../nfc/scenes/nfc_scene_nfcv_key_input.c | 2 +- .../main/nfc/scenes/nfc_scene_nfcv_unlock.c | 2 +- firmware/targets/f7/api_symbols.csv | 3 +- lib/nfc/nfc_device.c | 12 +- lib/nfc/nfc_worker.c | 2 +- lib/nfc/protocols/nfcv.c | 404 +++++++----------- lib/nfc/protocols/nfcv.h | 77 ++-- lib/nfc/protocols/slix.c | 263 +++++++++++- lib/nfc/protocols/slix.h | 29 +- 10 files changed, 491 insertions(+), 329 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index a7ffccdb8..9912b1b0c 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -123,27 +123,27 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { case NfcVTypeSlixS: furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_read)); - furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_write)); - furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_privacy)); - furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_destroy)); - furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_eas)); + furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); + furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); + furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); break; case NfcVTypeSlixL: furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_privacy)); - furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_destroy)); - furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_eas)); + furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); break; case NfcVTypeSlix2: furi_string_cat_printf(temp_str, "Type: SLIX2\n"); furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_read)); - furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_write)); - furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_privacy)); - furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_destroy)); - furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_eas)); + furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); + furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); + furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); break; default: furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c b/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c index d0e223c15..cc53c4dcb 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c @@ -3,7 +3,7 @@ void nfc_scene_nfcv_key_input_byte_input_callback(void* context) { Nfc* nfc = context; - NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l; + NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; memcpy(data->key_privacy, nfc->byte_input_store, 4); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c index 96293a7c6..d3624143b 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c @@ -11,7 +11,7 @@ typedef enum { static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) { Nfc* nfc = context; - NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l; + NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; if(event == NfcWorkerEventNfcVPassKey) { memcpy(data->key_privacy, nfc->byte_input_store, 4); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index b18083e68..9ff48484c 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,+,7.37,, +Version,+,7.38,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1969,6 +1969,7 @@ Function,-,nfca_signal_free,void,NfcaSignal* Function,-,nfcv_emu_deinit,void,NfcVData* Function,-,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*" Function,-,nfcv_emu_loop,_Bool,"FuriHalNfcTxRxContext*, FuriHalNfcDevData*, NfcVData*, uint32_t" +Function,-,nfcv_emu_send,void,"FuriHalNfcTxRxContext*, NfcVData*, uint8_t*, uint8_t, NfcVSendFlags" Function,-,nfcv_inventory,ReturnCode,uint8_t* Function,-,nfcv_read_blocks,ReturnCode,"NfcVReader*, NfcVData*" Function,-,nfcv_read_card,_Bool,"NfcVReader*, FuriHalNfcDevData*, NfcVData*" diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index b773be90b..9b2c4b385 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -674,7 +674,7 @@ bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) { static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; - NfcVSlixSData* data = &dev->dev_data.nfcv_data.sub_data.slix_s; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; do { if(!flipper_format_write_comment_cstr(file, "SLIX-S specific data")) break; @@ -692,7 +692,7 @@ static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; - NfcVSlixSData* data = &dev->dev_data.nfcv_data.sub_data.slix_s; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVData)); do { @@ -721,7 +721,7 @@ bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; - NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; do { if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break; @@ -737,7 +737,7 @@ static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; - NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVData)); do { @@ -760,7 +760,7 @@ bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; - NfcVSlix2Data* data = &dev->dev_data.nfcv_data.sub_data.slix2; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; do { if(!flipper_format_write_comment_cstr(file, "SLIX2 specific data")) break; @@ -778,7 +778,7 @@ static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; - NfcVSlix2Data* data = &dev->dev_data.nfcv_data.sub_data.slix2; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVData)); do { diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 818d54968..2d2df759f 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -154,7 +154,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; FuriHalNfcTxRxContext tx_rx = {}; - uint8_t *key_data = nfcv_data->sub_data.slix_l.key_privacy; + uint8_t *key_data = nfcv_data->sub_data.slix.key_privacy; uint32_t key = 0; if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index f8e739beb..88fd7894e 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -171,92 +171,92 @@ void nfcv_crc(uint8_t* data, uint32_t length) { } void nfcv_emu_free(NfcVData* data) { - digital_sequence_free(data->emulation.nfcv_signal); - digital_signal_free(data->emulation.nfcv_resp_unmod_256); - digital_signal_free(data->emulation.nfcv_resp_pulse_32); - digital_signal_free(data->emulation.nfcv_resp_one); - digital_signal_free(data->emulation.nfcv_resp_zero); - digital_signal_free(data->emulation.nfcv_resp_sof); - digital_signal_free(data->emulation.nfcv_resp_eof); + digital_sequence_free(data->emu_air.nfcv_signal); + digital_signal_free(data->emu_air.nfcv_resp_unmod_256); + digital_signal_free(data->emu_air.nfcv_resp_pulse_32); + digital_signal_free(data->emu_air.nfcv_resp_one); + digital_signal_free(data->emu_air.nfcv_resp_zero); + digital_signal_free(data->emu_air.nfcv_resp_sof); + digital_signal_free(data->emu_air.nfcv_resp_eof); - data->emulation.nfcv_signal = NULL; - data->emulation.nfcv_resp_unmod_256 = NULL; - data->emulation.nfcv_resp_pulse_32 = NULL; - data->emulation.nfcv_resp_one = NULL; - data->emulation.nfcv_resp_zero = NULL; - data->emulation.nfcv_resp_sof = NULL; - data->emulation.nfcv_resp_eof = NULL; + data->emu_air.nfcv_signal = NULL; + data->emu_air.nfcv_resp_unmod_256 = NULL; + data->emu_air.nfcv_resp_pulse_32 = NULL; + data->emu_air.nfcv_resp_one = NULL; + data->emu_air.nfcv_resp_zero = NULL; + data->emu_air.nfcv_resp_sof = NULL; + data->emu_air.nfcv_resp_eof = NULL; } void nfcv_emu_alloc(NfcVData* data) { - if(!data->emulation.nfcv_signal) { + if(!data->emu_air.nfcv_signal) { /* assuming max frame length is 255 bytes */ - data->emulation.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); + data->emu_air.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); } - if(!data->emulation.nfcv_resp_unmod_256) { + if(!data->emu_air.nfcv_resp_unmod_256) { /* unmodulated 256/fc signal as building block */ - data->emulation.nfcv_resp_unmod_256 = digital_signal_alloc(4); - data->emulation.nfcv_resp_unmod_256->start_level = false; - data->emulation.nfcv_resp_unmod_256->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); - data->emulation.nfcv_resp_unmod_256->edge_cnt = 1; + data->emu_air.nfcv_resp_unmod_256 = digital_signal_alloc(4); + data->emu_air.nfcv_resp_unmod_256->start_level = false; + data->emu_air.nfcv_resp_unmod_256->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); + data->emu_air.nfcv_resp_unmod_256->edge_cnt = 1; } - if(!data->emulation.nfcv_resp_pulse_32) { + if(!data->emu_air.nfcv_resp_pulse_32) { /* modulated fc/32 pulse as building block */ - data->emulation.nfcv_resp_pulse_32 = digital_signal_alloc(4); - data->emulation.nfcv_resp_pulse_32->start_level = true; - data->emulation.nfcv_resp_pulse_32->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); - data->emulation.nfcv_resp_pulse_32->edge_timings[1] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); - data->emulation.nfcv_resp_pulse_32->edge_cnt = 2; + data->emu_air.nfcv_resp_pulse_32 = digital_signal_alloc(4); + data->emu_air.nfcv_resp_pulse_32->start_level = true; + data->emu_air.nfcv_resp_pulse_32->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + data->emu_air.nfcv_resp_pulse_32->edge_timings[1] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + data->emu_air.nfcv_resp_pulse_32->edge_cnt = 2; } - if(!data->emulation.nfcv_resp_one) { + if(!data->emu_air.nfcv_resp_one) { /* logical one: 256/fc unmodulated then 8 pulses fc/32 */ - data->emulation.nfcv_resp_one = digital_signal_alloc(24); - digital_signal_append(data->emulation.nfcv_resp_one, data->emulation.nfcv_resp_unmod_256); + data->emu_air.nfcv_resp_one = digital_signal_alloc(24); + digital_signal_append(data->emu_air.nfcv_resp_one, data->emu_air.nfcv_resp_unmod_256); for(size_t i = 0; i < 8; i++) { - digital_signal_append(data->emulation.nfcv_resp_one, data->emulation.nfcv_resp_pulse_32); + digital_signal_append(data->emu_air.nfcv_resp_one, data->emu_air.nfcv_resp_pulse_32); } } - if(!data->emulation.nfcv_resp_zero) { + if(!data->emu_air.nfcv_resp_zero) { /* logical zero: 8 pulses fc/32 then 256/fc unmodulated */ - data->emulation.nfcv_resp_zero = digital_signal_alloc(24); + data->emu_air.nfcv_resp_zero = digital_signal_alloc(24); for(size_t i = 0; i < 8; i++) { - digital_signal_append(data->emulation.nfcv_resp_zero, data->emulation.nfcv_resp_pulse_32); + digital_signal_append(data->emu_air.nfcv_resp_zero, data->emu_air.nfcv_resp_pulse_32); } - digital_signal_append(data->emulation.nfcv_resp_zero, data->emulation.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_zero, data->emu_air.nfcv_resp_unmod_256); } - if(!data->emulation.nfcv_resp_sof) { + if(!data->emu_air.nfcv_resp_sof) { /* SOF: unmodulated 768/fc, 24 pulses fc/32, logic 1 */ - data->emulation.nfcv_resp_sof = digital_signal_alloc(128); - digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_unmod_256); - digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_unmod_256); - digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_unmod_256); + data->emu_air.nfcv_resp_sof = digital_signal_alloc(128); + digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_unmod_256); for(size_t i = 0; i < 24; i++) { - digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_pulse_32); + digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_pulse_32); } - digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_one); + digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_one); } - if(!data->emulation.nfcv_resp_eof) { + if(!data->emu_air.nfcv_resp_eof) { /* EOF: logic 0, 24 pulses fc/32, unmodulated 768/fc */ - data->emulation.nfcv_resp_eof = digital_signal_alloc(128); - digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_zero); + data->emu_air.nfcv_resp_eof = digital_signal_alloc(128); + digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_zero); for(size_t i = 0; i < 24; i++) { - digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_pulse_32); + digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_pulse_32); } - digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256); - digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256); - digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256); /* add extra silence */ - digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256); + digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256); } - digital_sequence_set_signal(data->emulation.nfcv_signal, NFCV_SIG_SOF, data->emulation.nfcv_resp_sof); - digital_sequence_set_signal(data->emulation.nfcv_signal, NFCV_SIG_BIT0, data->emulation.nfcv_resp_zero); - digital_sequence_set_signal(data->emulation.nfcv_signal, NFCV_SIG_BIT1, data->emulation.nfcv_resp_one); - digital_sequence_set_signal(data->emulation.nfcv_signal, NFCV_SIG_EOF, data->emulation.nfcv_resp_eof); + digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_SOF, data->emu_air.nfcv_resp_sof); + digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT0, data->emu_air.nfcv_resp_zero); + digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT1, data->emu_air.nfcv_resp_one); + digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_EOF, data->emu_air.nfcv_resp_eof); } -static void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags) { +void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags) { /* picked default value (0) to match the most common format */ if(!flags) { flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate; @@ -267,10 +267,10 @@ static void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* length += 2; } - digital_sequence_clear(nfcv->emulation.nfcv_signal); + digital_sequence_clear(nfcv->emu_air.nfcv_signal); if(flags & NfcVSendFlagsSof) { - digital_sequence_add(nfcv->emulation.nfcv_signal, NFCV_SIG_SOF); + digital_sequence_add(nfcv->emu_air.nfcv_signal, NFCV_SIG_SOF); } for(int bit_total = 0; bit_total < length * 8; bit_total++) { @@ -278,19 +278,18 @@ static void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* uint32_t bit_pos = bit_total % 8; uint8_t bit_val = 0x01 << bit_pos; - digital_sequence_add(nfcv->emulation.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0); + digital_sequence_add(nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0); } if(flags & NfcVSendFlagsEof) { - digital_sequence_add(nfcv->emulation.nfcv_signal, NFCV_SIG_EOF); + digital_sequence_add(nfcv->emu_air.nfcv_signal, NFCV_SIG_EOF); } FURI_CRITICAL_ENTER(); - digital_sequence_send(nfcv->emulation.nfcv_signal); + digital_sequence_send(nfcv->emu_air.nfcv_signal); FURI_CRITICAL_EXIT(); furi_hal_gpio_write(&gpio_spi_r_mosi, false); - if(tx_rx->sniff_tx) { tx_rx->sniff_tx(data, length * 8, false, tx_rx->sniff_context); } @@ -311,222 +310,141 @@ static int nfcv_uidcmp(uint8_t *dst, uint8_t *src) { return 0; } -static uint32_t nfcv_read_be(uint8_t *data, uint32_t length) { - uint32_t value = 0; - - for(uint32_t pos = 0; pos < length; pos++) { - value <<= 8; - value |= data[pos]; - } - - return value; -} - void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint8_t* payload, uint32_t payload_length) { if(!payload_length) { return; } - - uint8_t flags = payload[0]; - uint8_t command = payload[1]; - bool addressed = !(flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (flags & RFAL_NFCV_REQ_FLAG_ADDRESS); - bool advanced = (command >= 0xA0); - uint8_t address_offset = 2 + (advanced ? 1 : 0); - uint8_t payload_offset = address_offset + (addressed ? 8 : 0); - uint8_t *address = &payload[address_offset]; - uint8_t response_buffer[32]; - NfcVSendFlags response_flags = NfcVSendFlagsNormal; - if(addressed && nfcv_uidcmp(address, nfc_data->uid)) { - FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", command); - FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]); - FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]); + NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx; + + ctx->payload = payload; + ctx->flags = ctx->payload[0]; + ctx->command = ctx->payload[1]; + ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); + ctx->advanced = (ctx->command >= 0xA0); + ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); + ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); + ctx->address = &ctx->payload[ctx->address_offset]; + ctx->response_flags = NfcVSendFlagsNormal; + + bool handled = false; + + /* first give control to the card specific protocol handler */ + if(nfcv_data->emu_protocol_handler != NULL) { + handled = nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); + } + + if(handled) { return; } - - switch(nfcv_data->type) { - case NfcVTypeSlixL: - if(nfcv_data->sub_data.slix_l.privacy && - command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER && - command != ISO15693_CMD_NXP_SET_PASSWORD) { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "command 0x%02X ignored, privacy mode", command); - FURI_LOG_D(TAG, "%s", nfcv_data->last_command); - return; - } - break; - - default: - break; + if(ctx->addressed && nfcv_uidcmp(ctx->address, nfc_data->uid)) { + FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command); + FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", ctx->address[7], ctx->address[6], ctx->address[5], ctx->address[4], ctx->address[3], ctx->address[2], ctx->address[1], ctx->address[0]); + FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]); + return; } /* unfortunately our response is quicker than the original NFC tag which causes frame misses */ furi_delay_us(270); - switch(command) { - case ISO15693_INVENTORY: - { - response_buffer[0] = ISO15693_NOERROR; - response_buffer[1] = nfcv_data->dsfid; - nfcv_uidcpy(&response_buffer[2], nfc_data->uid); + switch(ctx->command) { + case ISO15693_INVENTORY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = nfcv_data->dsfid; + nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid); - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 10, response_flags); + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); break; } - case ISO15693_STAYQUIET: - { + case ISO15693_STAYQUIET: { snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET"); break; } - case ISO15693_LOCKBLOCK: - { + case ISO15693_LOCKBLOCK: { snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK"); break; } - case ISO15693_READ_MULTI_BLOCK: - { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ_MULTI_BLOCK"); - break; - } - - case ISO15693_WRITE_MULTI_BLOCK: - { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE_MULTI_BLOCK"); - break; - } - - case ISO15693_SELECT: - { - response_buffer[0] = ISO15693_NOERROR; - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags); + case ISO15693_SELECT: { + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT"); break; } - case ISO15693_READBLOCK: - { - uint8_t block = payload[payload_offset]; + case ISO15693_READ_MULTI_BLOCK: + case ISO15693_READBLOCK: { + uint8_t block = ctx->payload[ctx->payload_offset]; + uint8_t blocks = 1; - if(block >= nfcv_data->block_num) { - response_buffer[0] = ISO15693_ERROR_BLOCK_WRITE; - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags); + if(ctx->command == ISO15693_READ_MULTI_BLOCK) { + blocks = ctx->payload[ctx->payload_offset + 1] + 1; + } + + if(block + blocks > nfcv_data->block_num) { + ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); } else { - response_buffer[0] = ISO15693_NOERROR; - memcpy(&response_buffer[1], &nfcv_data->data[nfcv_data->block_size * block], nfcv_data->block_size); - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1 + nfcv_data->block_size, response_flags); + ctx->response_buffer[0] = ISO15693_NOERROR; + memcpy(&ctx->response_buffer[1], &nfcv_data->data[nfcv_data->block_size * block], nfcv_data->block_size * blocks); + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1 + nfcv_data->block_size * blocks, ctx->response_flags); } snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block); break; } - case ISO15693_WRITEBLOCK: - { - uint8_t block = payload[payload_offset]; - uint8_t *data = &payload[payload_offset + 1]; + case ISO15693_WRITE_MULTI_BLOCK: + case ISO15693_WRITEBLOCK: { + uint8_t block = ctx->payload[ctx->payload_offset]; + uint8_t blocks = 1; + uint8_t data_pos = 1; - if(block >= nfcv_data->block_num) { - response_buffer[0] = ISO15693_ERROR_BLOCK_WRITE; - } else { - response_buffer[0] = ISO15693_NOERROR; - memcpy(&nfcv_data->data[nfcv_data->block_size * block], &response_buffer[1], nfcv_data->block_size); + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + blocks = ctx->payload[ctx->payload_offset + 1] + 1; + data_pos++; + } + + uint8_t *data = &ctx->payload[ctx->payload_offset + data_pos]; + uint32_t data_len = nfcv_data->block_size * blocks; + + if(block + blocks > nfcv_data->block_num || ctx->payload_offset + data_len + 2 > payload_length) { + ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; + } else { + ctx->response_buffer[0] = ISO15693_NOERROR; + memcpy(&nfcv_data->data[nfcv_data->block_size * block], &ctx->payload[ctx->payload_offset + data_pos], data_len); + } + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); + + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE MULTI BLOCK %d, %d blocks", block, blocks); + } else { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE BLOCK %d <- %02X %02X %02X %02X", block, data[0], data[1], data[2], data[3]); } - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE BLOCK %d <- %02X %02X %02X %02X", block, data[0], data[1], data[2], data[3]); break; } - case ISO15693_GET_SYSTEM_INFO: - { - response_buffer[0] = ISO15693_NOERROR; - response_buffer[1] = 0x0F; - nfcv_uidcpy(&response_buffer[2], nfc_data->uid); - response_buffer[10] = nfcv_data->dsfid; /* DSFID */ - response_buffer[11] = nfcv_data->afi; /* AFI */ - response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */ - response_buffer[13] = nfcv_data->block_size - 1; /* block size */ - response_buffer[14] = nfcv_data->ic_ref; /* IC reference */ + case ISO15693_GET_SYSTEM_INFO: { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = 0x0F; + nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid); + ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */ + ctx->response_buffer[11] = nfcv_data->afi; /* AFI */ + ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */ + ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */ + ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */ - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 15, response_flags); + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO"); - - break; - } - - case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: - { - nfcv_data->sub_data.slix_l.rand[0] = furi_hal_random_get(); - nfcv_data->sub_data.slix_l.rand[1] = furi_hal_random_get(); - - response_buffer[0] = ISO15693_NOERROR; - response_buffer[1] = nfcv_data->sub_data.slix_l.rand[1]; - response_buffer[2] = nfcv_data->sub_data.slix_l.rand[0]; - - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 3, response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), - "GET_RANDOM_NUMBER -> 0x%02X%02X", - nfcv_data->sub_data.slix_l.rand[0], - nfcv_data->sub_data.slix_l.rand[1]); - break; - } - - case ISO15693_CMD_NXP_SET_PASSWORD: - { - uint8_t password_id = payload[payload_offset]; - uint8_t *password_xored = &payload[payload_offset + 1]; - uint8_t *rand = nfcv_data->sub_data.slix_l.rand; - uint8_t *password = NULL; - uint8_t password_rcv[4]; - - switch(password_id) { - case 4: - password = nfcv_data->sub_data.slix_l.key_privacy; - break; - case 8: - password = nfcv_data->sub_data.slix_l.key_destroy; - break; - case 10: - password = nfcv_data->sub_data.slix_l.key_eas; - break; - default: - break; - } - - for(int pos = 0; pos < 4; pos++) { - password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; - } - uint32_t pass_expect = nfcv_read_be(password, 4); - uint32_t pass_received = nfcv_read_be(password_rcv, 4); - - /* if the password is all-zeroes, just accept any password*/ - if(!pass_expect || pass_expect == pass_received) { - nfcv_data->sub_data.slix_l.privacy = false; - response_buffer[0] = ISO15693_NOERROR; - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SET_PASSWORD #%02X 0x%08lX OK", password_id, pass_received); - } else { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", password_id, pass_received, pass_expect); - } - break; - } - - case ISO15693_CMD_NXP_ENABLE_PRIVACY: - { - response_buffer[0] = ISO15693_NOERROR; - - nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ISO15693_CMD_NXP_ENABLE_PRIVACY"); - - nfcv_data->sub_data.slix_l.privacy = true; break; } default: - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "unsupported: %02X", command); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "unsupported: %02X", ctx->command); break; } @@ -554,32 +472,32 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { switch(nfcv_data->type) { case NfcVTypeSlixL: FURI_LOG_D(TAG, " Card type: SLIX-L"); - FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", nfcv_read_be(nfcv_data->sub_data.slix_l.key_privacy, 4)); - FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", nfcv_read_be(nfcv_data->sub_data.slix_l.key_destroy, 4)); - FURI_LOG_D(TAG, " EAS pass: 0x%08lX", nfcv_read_be(nfcv_data->sub_data.slix_l.key_eas, 4)); - FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix_l.privacy ? "ON" : "OFF"); + slix_l_prepare(nfcv_data); break; case NfcVTypeSlixS: FURI_LOG_D(TAG, " Card type: SLIX-S"); + slix_s_prepare(nfcv_data); break; case NfcVTypeSlix2: FURI_LOG_D(TAG, " Card type: SLIX2"); + slix2_prepare(nfcv_data); + break; + case NfcVTypeSlix: + FURI_LOG_D(TAG, " Card type: SLIX"); + slix_prepare(nfcv_data); break; case NfcVTypePlain: FURI_LOG_D(TAG, " Card type: Plain"); break; - case NfcVTypeSlix: - FURI_LOG_D(TAG, " Card type: SLIX-L"); - break; } /* allocate a 512 edge buffer, more than enough */ - nfcv_data->emulation.reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512); + nfcv_data->emu_air.reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512); /* timebase shall be 1 ns */ - pulse_reader_set_timebase(nfcv_data->emulation.reader_signal, PulseReaderUnitNanosecond); + pulse_reader_set_timebase(nfcv_data->emu_air.reader_signal, PulseReaderUnitNanosecond); /* and configure to already calculate the number of bits */ - pulse_reader_set_bittime(nfcv_data->emulation.reader_signal, PULSE_DURATION_NS); - pulse_reader_start(nfcv_data->emulation.reader_signal); + pulse_reader_set_bittime(nfcv_data->emu_air.reader_signal, PULSE_DURATION_NS); + pulse_reader_start(nfcv_data->emu_air.reader_signal); } void nfcv_emu_deinit(NfcVData* nfcv_data) { @@ -587,7 +505,7 @@ void nfcv_emu_deinit(NfcVData* nfcv_data) { rfal_platform_spi_release(); nfcv_emu_free(nfcv_data); - pulse_reader_free(nfcv_data->emulation.reader_signal); + pulse_reader_free(nfcv_data->emu_air.reader_signal); } bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms) { @@ -604,7 +522,7 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf while(true) { - uint32_t periods = pulse_reader_receive(nfcv_data->emulation.reader_signal, timeout_ms * 1000); + uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); if(periods == PULSE_READER_NO_EDGE) { break; @@ -728,12 +646,12 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf if(frame_state == NFCV_FRAME_STATE_EOF) { /* we know that this code uses TIM2, so stop pulse reader */ - pulse_reader_stop(nfcv_data->emulation.reader_signal); + pulse_reader_stop(nfcv_data->emu_air.reader_signal); if(tx_rx->sniff_rx) { tx_rx->sniff_rx(frame_payload, frame_pos * 8, false, tx_rx->sniff_context); } nfcv_emu_handle_packet(tx_rx, nfc_data, nfcv_data, frame_payload, frame_pos); - pulse_reader_start(nfcv_data->emulation.reader_signal); + pulse_reader_start(nfcv_data->emu_air.reader_signal); ret = true; } diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index 2f72f872e..14d9b1ed6 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -38,7 +38,7 @@ #define NFCV_SIG_BIT1 2 #define NFCV_SIG_EOF 3 -/* */ +/* ISO15693 command codes */ #define ISO15693_INVENTORY 0x01 #define ISO15693_STAYQUIET 0x02 #define ISO15693_READBLOCK 0x20 @@ -55,25 +55,8 @@ #define ISO15693_GET_SYSTEM_INFO 0x2B #define ISO15693_READ_MULTI_SECSTATUS 0x2C -// ISO15693 MANUFACTURER CODES -#define ISO15693_MANUFACTURER_NXP 0x04 -// ISO15693-3 CUSTOM NXP COMMANDS -#define ISO15693_CMD_NXP_SET_EAS 0xA2 -#define ISO15693_CMD_NXP_RESET_EAS 0xA3 -#define ISO15693_CMD_NXP_LOCK_EAS 0xA4 -#define ISO15693_CMD_NXP_EAS_ALARM 0xA5 -#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6 -#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7 -#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0 -#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1 -#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2 -#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3 -#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4 -#define ISO15693_CMD_NXP_DESTROY 0xB9 -#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA - -// ISO15693 RESPONSE ERROR CODES +/* ISO15693 RESPONSE ERROR CODES */ #define ISO15693_NOERROR 0x00 #define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported #define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) @@ -99,11 +82,6 @@ typedef enum { NfcVTypeSlix2 = 4, } NfcVType; -typedef struct { - uint8_t key_eas[4]; - uint8_t rand[2]; -} NfcVSlixData; - typedef enum { NfcVSendFlagsNormal = 0, NfcVSendFlagsSof = 1<<0, @@ -123,34 +101,12 @@ typedef struct { uint8_t key_eas[4]; uint8_t rand[2]; bool privacy; -} NfcVSlix2Data; - -typedef struct { - uint8_t key_read[4]; - uint8_t key_write[4]; - uint8_t key_privacy[4]; - uint8_t key_destroy[4]; - uint8_t key_eas[4]; - uint8_t rand[2]; - bool privacy; -} NfcVSlixSData; - -typedef struct { - uint8_t key_privacy[4]; - uint8_t key_destroy[4]; - uint8_t key_eas[4]; - uint8_t rand[2]; - bool privacy; -} NfcVSlixLData; +} NfcVSlixData; typedef union { NfcVSlixData slix; - NfcVSlix2Data slix2; - NfcVSlixSData slix_s; - NfcVSlixLData slix_l; } NfcVSubtypeData; - typedef struct { PulseReader *reader_signal; DigitalSignal* nfcv_resp_pulse_32; @@ -162,7 +118,23 @@ typedef struct { DigitalSignal* nfcv_resp_unmod_256; DigitalSignal* nfcv_resp_unmod_768; DigitalSequence* nfcv_signal; -} NfcVEmuData; +} NfcVEmuAir; + + +typedef struct { + uint8_t* payload; + uint8_t flags; + uint8_t command; + bool addressed; + bool advanced; + uint8_t address_offset; + uint8_t payload_offset; + uint8_t* address; + uint8_t response_buffer[128]; + NfcVSendFlags response_flags; +} NfcVEmuProtocolCtx; + +typedef bool (*NfcVEmuProtocolHandler) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data); typedef struct { /* common ISO15693 fields */ @@ -176,7 +148,9 @@ typedef struct { /* specfic variant infos */ NfcVType type; NfcVSubtypeData sub_data; - NfcVEmuData emulation; + NfcVEmuAir emu_air; + NfcVEmuProtocolCtx emu_protocol_ctx; + NfcVEmuProtocolHandler emu_protocol_handler; /* runtime data */ char last_command[128]; @@ -190,6 +164,7 @@ typedef struct { int16_t blocks_read; } NfcVReader; + ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data); ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data); ReturnCode nfcv_inventory(uint8_t* uid); @@ -198,3 +173,7 @@ bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* d void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data); void nfcv_emu_deinit(NfcVData* nfcv_data); bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms); +void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags); + + + diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c index d8befc399..49bc12e0e 100644 --- a/lib/nfc/protocols/slix.c +++ b/lib/nfc/protocols/slix.c @@ -5,12 +5,25 @@ #include "nfc_util.h" #include #include "furi_hal_nfc.h" +#include + +#define TAG "SLIX" + +static uint32_t slix_read_be(uint8_t *data, uint32_t length) { + uint32_t value = 0; + + for(uint32_t pos = 0; pos < length; pos++) { + value <<= 8; + value |= data[pos]; + } + + return value; +} uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) { return (nfc_data->uid[3] >> 3) & 3; } - bool slix_check_card_type(FuriHalNfcDevData* nfc_data) { if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) @@ -70,8 +83,8 @@ ReturnCode slix_l_get_random(NfcVData* data) { return ERR_PROTO; } if(data != NULL) { - data->sub_data.slix_l.rand[0] = rxBuf[2]; - data->sub_data.slix_l.rand[1] = rxBuf[1]; + data->sub_data.slix.rand[0] = rxBuf[2]; + data->sub_data.slix.rand[1] = rxBuf[1]; } } @@ -85,22 +98,28 @@ ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) { uint8_t rxBuf[32]; uint8_t cmd_set_pass[] = { password_id, - data->sub_data.slix_l.rand[1], - data->sub_data.slix_l.rand[0], - data->sub_data.slix_l.rand[1], - data->sub_data.slix_l.rand[0] + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0], + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0] }; uint8_t *password = NULL; switch(password_id) { - case 4: - password = data->sub_data.slix_l.key_privacy; + case SLIX_PASS_READ: + password = data->sub_data.slix.key_read; break; - case 8: - password = data->sub_data.slix_l.key_destroy; + case SLIX_PASS_WRITE: + password = data->sub_data.slix.key_write; break; - case 10: - password = data->sub_data.slix_l.key_eas; + case SLIX_PASS_PRIVACY: + password = data->sub_data.slix.key_privacy; + break; + case SLIX_PASS_DESTROY: + password = data->sub_data.slix.key_destroy; + break; + case SLIX_PASS_EASAFI: + password = data->sub_data.slix.key_eas; break; default: break; @@ -127,3 +146,221 @@ ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) { return ret; } + + +bool slix_generic_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint32_t password_supported) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx; + NfcVSlixData* slix = &nfcv_data->sub_data.slix; + + if(slix->privacy && + ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER && + ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), + "command 0x%02X ignored, privacy mode", ctx->command); + FURI_LOG_D(TAG, "%s", nfcv_data->last_command); + return true; + } + + bool handled = false; + + switch(ctx->command) { + case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: { + slix->rand[0] = furi_hal_random_get(); + slix->rand[1] = furi_hal_random_get(); + + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = slix->rand[1]; + ctx->response_buffer[2] = slix->rand[0]; + + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), + "GET_RANDOM_NUMBER -> 0x%02X%02X", slix->rand[0], slix->rand[1]); + + handled = true; + break; + } + + case ISO15693_CMD_NXP_SET_PASSWORD: { + uint8_t password_id = ctx->payload[ctx->payload_offset]; + + if(!(password_id & password_supported)) { + break; + } + + uint8_t *password_xored = &ctx->payload[ctx->payload_offset + 1]; + uint8_t *rand = slix->rand; + uint8_t *password = NULL; + uint8_t password_rcv[4]; + + switch(password_id) { + case SLIX_PASS_READ: + password = slix->key_read; + break; + case SLIX_PASS_WRITE: + password = slix->key_write; + break; + case SLIX_PASS_PRIVACY: + password = slix->key_privacy; + break; + case SLIX_PASS_DESTROY: + password = slix->key_destroy; + break; + case SLIX_PASS_EASAFI: + password = slix->key_eas; + break; + default: + break; + } + + for(int pos = 0; pos < 4; pos++) { + password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; + } + uint32_t pass_expect = slix_read_be(password, 4); + uint32_t pass_received = slix_read_be(password_rcv, 4); + + /* if the password is all-zeroes, just accept any password*/ + if(!pass_expect || pass_expect == pass_received) { + switch(password_id) { + case SLIX_PASS_READ: + break; + case SLIX_PASS_WRITE: + break; + case SLIX_PASS_PRIVACY: + slix->privacy = false; + break; + case SLIX_PASS_DESTROY: + FURI_LOG_D(TAG, "Pooof! Got destroyed"); + break; + case SLIX_PASS_EASAFI: + break; + default: + break; + } + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX OK", password_id, pass_received); + } else { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", password_id, pass_received, pass_expect); + } + handled = true; + break; + } + + case ISO15693_CMD_NXP_ENABLE_PRIVACY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), + "ISO15693_CMD_NXP_ENABLE_PRIVACY"); + + slix->privacy = true; + handled = true; + break; + } + } + + return handled; +} + +bool slix_l_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { + return true; + } + + return handled; +} + +void slix_l_prepare(NfcVData* nfcv_data) { + FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + nfcv_data->emu_protocol_handler = &slix_l_protocol_handler; +} + +bool slix_s_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + return true; + } + + return handled; +} + +void slix_s_prepare(NfcVData* nfcv_data) { + FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + nfcv_data->emu_protocol_handler = &slix_s_protocol_handler; +} + +bool slix_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) { + return true; + } + + return handled; +} + +void slix_prepare(NfcVData* nfcv_data) { + FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + nfcv_data->emu_protocol_handler = &slix_protocol_handler; +} + +bool slix2_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + return true; + } + + return handled; +} + +void slix2_prepare(NfcVData* nfcv_data) { + FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + nfcv_data->emu_protocol_handler = &slix2_protocol_handler; +} diff --git a/lib/nfc/protocols/slix.h b/lib/nfc/protocols/slix.h index b95a27abd..f30efacc1 100644 --- a/lib/nfc/protocols/slix.h +++ b/lib/nfc/protocols/slix.h @@ -5,9 +5,31 @@ #include "nfc_util.h" #include +#define ISO15693_MANUFACTURER_NXP 0x04 + +/* ISO15693-3 CUSTOM NXP COMMANDS */ +#define ISO15693_CMD_NXP_SET_EAS 0xA2 +#define ISO15693_CMD_NXP_RESET_EAS 0xA3 +#define ISO15693_CMD_NXP_LOCK_EAS 0xA4 +#define ISO15693_CMD_NXP_EAS_ALARM 0xA5 +#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6 +#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1 #define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2 #define ISO15693_CMD_NXP_SET_PASSWORD 0xB3 -#define ISO15693_MANUFACTURER_NXP 0x04 +#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4 +#define ISO15693_CMD_NXP_DESTROY 0xB9 +#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA + +/* available passwords */ +#define SLIX_PASS_READ 0x01 +#define SLIX_PASS_WRITE 0x02 +#define SLIX_PASS_PRIVACY 0x04 +#define SLIX_PASS_DESTROY 0x08 +#define SLIX_PASS_EASAFI 0x10 + +#define SLIX_PASS_ALL (SLIX_PASS_READ|SLIX_PASS_WRITE|SLIX_PASS_PRIVACY|SLIX_PASS_DESTROY|SLIX_PASS_EASAFI) bool slix_check_card_type(FuriHalNfcDevData* nfc_data); @@ -17,3 +39,8 @@ bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data); ReturnCode slix_l_get_random(NfcVData* data); ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id); +void slix_prepare(NfcVData* nfcv_data); +void slix_s_prepare(NfcVData* nfcv_data); +void slix_l_prepare(NfcVData* nfcv_data); +void slix2_prepare(NfcVData* nfcv_data); + From 1489e3e676b482e12bc55cccb21ac32cce7d6b8f Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Tue, 29 Nov 2022 02:15:20 +0100 Subject: [PATCH 2/2] better layer separation for ISO15693 --- lib/nfc/nfc_worker.c | 16 ++++++------- lib/nfc/protocols/nfcv.c | 52 +++++++++++++++++++++------------------- lib/nfc/protocols/nfcv.h | 26 +++++++++++--------- lib/nfc/protocols/slix.c | 34 +++++++++++++------------- lib/nfc/protocols/slix.h | 4 ++-- 5 files changed, 69 insertions(+), 63 deletions(-) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 2d2df759f..5b26a6cf1 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -181,7 +181,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV); furi_hal_console_printf("Detect presence\r\n"); - ReturnCode ret = slix_l_get_random(nfcv_data); + ReturnCode ret = slix_get_random(nfcv_data); if(ret == ERR_NONE) { /* there is some chip, responding with a RAND */ @@ -207,13 +207,13 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); } - while(slix_l_get_random(NULL) == ERR_NONE) { + while(slix_get_random(NULL) == ERR_NONE) { furi_delay_ms(100); } furi_hal_console_printf(" => chip is already visible, wait for chip to disappear.\r\n"); nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context); - while(slix_l_get_random(NULL) == ERR_NONE) { + while(slix_get_random(NULL) == ERR_NONE) { furi_delay_ms(100); } @@ -233,14 +233,14 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { key |= key_data[2] << 8; key |= key_data[3] << 0; - ret = slix_l_unlock(nfcv_data, 4); + ret = slix_unlock(nfcv_data, 4); } else { key = 0x7FFD6E5B; key_data[0] = key >> 24; key_data[1] = key >> 16; key_data[2] = key >> 8; key_data[3] = key >> 0; - ret = slix_l_unlock(nfcv_data, 4); + ret = slix_unlock(nfcv_data, 4); if(ret != ERR_NONE) { /* main key failed, trying second one */ @@ -251,7 +251,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { furi_delay_ms(20); furi_hal_nfc_ll_txrx_on(); - if(slix_l_get_random(nfcv_data) != ERR_NONE) { + if(slix_get_random(nfcv_data) != ERR_NONE) { furi_hal_console_printf(" reset failed\r\n"); } @@ -260,7 +260,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { key_data[1] = key >> 16; key_data[2] = key >> 8; key_data[3] = key >> 0; - ret = slix_l_unlock(nfcv_data, 4); + ret = slix_unlock(nfcv_data, 4); } } if(ret != ERR_NONE) { @@ -275,7 +275,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { furi_hal_nfc_ll_txrx_on(); /* wait for disappearing */ - while(slix_l_get_random(NULL) == ERR_NONE) { + while(slix_get_random(NULL) == ERR_NONE) { furi_delay_ms(100); } } diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 88fd7894e..b7a8dd7cb 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -310,40 +310,40 @@ static int nfcv_uidcmp(uint8_t *dst, uint8_t *src) { return 0; } -void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint8_t* payload, uint32_t payload_length) { +void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint8_t* payload, uint32_t payload_length) { if(!payload_length) { return; } + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx; - ctx->payload = payload; - ctx->flags = ctx->payload[0]; - ctx->command = ctx->payload[1]; + ctx->frame = payload; + ctx->frame_length = payload_length; + ctx->flags = ctx->frame[0]; + ctx->command = ctx->frame[1]; ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); ctx->advanced = (ctx->command >= 0xA0); ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); - ctx->address = &ctx->payload[ctx->address_offset]; ctx->response_flags = NfcVSendFlagsNormal; - bool handled = false; - /* first give control to the card specific protocol handler */ - if(nfcv_data->emu_protocol_handler != NULL) { - handled = nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); + if(nfcv_data->emu_protocol_filter != NULL) { + if(nfcv_data->emu_protocol_filter(tx_rx, nfc_data, nfcv_data)) { + return; + } } - if(handled) { - return; - } - - if(ctx->addressed && nfcv_uidcmp(ctx->address, nfc_data->uid)) { - FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command); - FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", ctx->address[7], ctx->address[6], ctx->address[5], ctx->address[4], ctx->address[3], ctx->address[2], ctx->address[1], ctx->address[0]); - FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]); - return; + if(ctx->addressed) { + uint8_t* address = &ctx->frame[ctx->address_offset]; + if(nfcv_uidcmp(address, nfc_data->uid)) { + FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command); + FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]); + FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]); + return; + } } /* unfortunately our response is quicker than the original NFC tag which causes frame misses */ @@ -379,11 +379,11 @@ void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc case ISO15693_READ_MULTI_BLOCK: case ISO15693_READBLOCK: { - uint8_t block = ctx->payload[ctx->payload_offset]; + uint8_t block = ctx->frame[ctx->payload_offset]; uint8_t blocks = 1; if(ctx->command == ISO15693_READ_MULTI_BLOCK) { - blocks = ctx->payload[ctx->payload_offset + 1] + 1; + blocks = ctx->frame[ctx->payload_offset + 1] + 1; } if(block + blocks > nfcv_data->block_num) { @@ -400,23 +400,23 @@ void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc case ISO15693_WRITE_MULTI_BLOCK: case ISO15693_WRITEBLOCK: { - uint8_t block = ctx->payload[ctx->payload_offset]; + uint8_t block = ctx->frame[ctx->payload_offset]; uint8_t blocks = 1; uint8_t data_pos = 1; if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { - blocks = ctx->payload[ctx->payload_offset + 1] + 1; + blocks = ctx->frame[ctx->payload_offset + 1] + 1; data_pos++; } - uint8_t *data = &ctx->payload[ctx->payload_offset + data_pos]; + uint8_t *data = &ctx->frame[ctx->payload_offset + data_pos]; uint32_t data_len = nfcv_data->block_size * blocks; if(block + blocks > nfcv_data->block_num || ctx->payload_offset + data_len + 2 > payload_length) { ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; } else { ctx->response_buffer[0] = ISO15693_NOERROR; - memcpy(&nfcv_data->data[nfcv_data->block_size * block], &ctx->payload[ctx->payload_offset + data_pos], data_len); + memcpy(&nfcv_data->data[nfcv_data->block_size * block], &ctx->frame[ctx->payload_offset + data_pos], data_len); } nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); @@ -464,6 +464,8 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); + nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet; + FURI_LOG_D(TAG, "Starting NfcV emulation"); FURI_LOG_D(TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], @@ -650,7 +652,7 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf if(tx_rx->sniff_rx) { tx_rx->sniff_rx(frame_payload, frame_pos * 8, false, tx_rx->sniff_context); } - nfcv_emu_handle_packet(tx_rx, nfc_data, nfcv_data, frame_payload, frame_pos); + nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data, frame_payload, frame_pos); pulse_reader_start(nfcv_data->emu_air.reader_signal); ret = true; } diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index 14d9b1ed6..86f75b19e 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -122,19 +122,22 @@ typedef struct { typedef struct { - uint8_t* payload; - uint8_t flags; - uint8_t command; - bool addressed; - bool advanced; - uint8_t address_offset; - uint8_t payload_offset; - uint8_t* address; - uint8_t response_buffer[128]; - NfcVSendFlags response_flags; + uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */ + uint8_t frame_length; /* ISO15693-2 length of incoming data */ + + uint8_t flags; /* ISO15693-3 flags of the header as specified */ + uint8_t command; /* ISO15693-3 command at offset 1 as specified */ + bool addressed; /* ISO15693-3 flags: addressed frame */ + bool advanced; /* ISO15693-3 command: advanced command */ + uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ + uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ + + uint8_t response_buffer[128]; /* pre-allocated response buffer */ + NfcVSendFlags response_flags; /* flags to use when sending response */ } NfcVEmuProtocolCtx; -typedef bool (*NfcVEmuProtocolHandler) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data); +typedef void (*NfcVEmuProtocolHandler) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data, uint8_t* payload, uint32_t payload_length); +typedef bool (*NfcVEmuProtocolFilter) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data); typedef struct { /* common ISO15693 fields */ @@ -151,6 +154,7 @@ typedef struct { NfcVEmuAir emu_air; NfcVEmuProtocolCtx emu_protocol_ctx; NfcVEmuProtocolHandler emu_protocol_handler; + NfcVEmuProtocolFilter emu_protocol_filter; /* runtime data */ char last_command[128]; diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c index 49bc12e0e..abd76ee81 100644 --- a/lib/nfc/protocols/slix.c +++ b/lib/nfc/protocols/slix.c @@ -63,7 +63,7 @@ bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) { } -ReturnCode slix_l_get_random(NfcVData* data) { +ReturnCode slix_get_random(NfcVData* data) { uint16_t received = 0; uint8_t rxBuf[32]; @@ -91,7 +91,7 @@ ReturnCode slix_l_get_random(NfcVData* data) { return ret; } -ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) { +ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) { furi_assert(rand); uint16_t received = 0; @@ -148,7 +148,7 @@ ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) { } -bool slix_generic_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint32_t password_supported) { +bool slix_generic_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint32_t password_supported) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); @@ -186,13 +186,13 @@ bool slix_generic_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevD } case ISO15693_CMD_NXP_SET_PASSWORD: { - uint8_t password_id = ctx->payload[ctx->payload_offset]; + uint8_t password_id = ctx->frame[ctx->payload_offset]; if(!(password_id & password_supported)) { break; } - uint8_t *password_xored = &ctx->payload[ctx->payload_offset + 1]; + uint8_t *password_xored = &ctx->frame[ctx->payload_offset + 1]; uint8_t *rand = slix->rand; uint8_t *password = NULL; uint8_t password_rcv[4]; @@ -269,7 +269,7 @@ bool slix_generic_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevD return handled; } -bool slix_l_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix_l_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); @@ -277,7 +277,7 @@ bool slix_l_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* n bool handled = false; /* many SLIX share some of the functions, place that in a generic handler */ - if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { return true; } @@ -290,10 +290,10 @@ void slix_l_prepare(NfcVData* nfcv_data) { FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); - nfcv_data->emu_protocol_handler = &slix_l_protocol_handler; + nfcv_data->emu_protocol_filter = &slix_l_protocol_filter; } -bool slix_s_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix_s_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); @@ -301,7 +301,7 @@ bool slix_s_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* n bool handled = false; /* many SLIX share some of the functions, place that in a generic handler */ - if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { return true; } @@ -314,10 +314,10 @@ void slix_s_prepare(NfcVData* nfcv_data) { FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); - nfcv_data->emu_protocol_handler = &slix_s_protocol_handler; + nfcv_data->emu_protocol_filter = &slix_s_protocol_filter; } -bool slix_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); @@ -325,7 +325,7 @@ bool slix_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc bool handled = false; /* many SLIX share some of the functions, place that in a generic handler */ - if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) { + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) { return true; } @@ -338,10 +338,10 @@ void slix_prepare(NfcVData* nfcv_data) { FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); - nfcv_data->emu_protocol_handler = &slix_protocol_handler; + nfcv_data->emu_protocol_filter = &slix_protocol_filter; } -bool slix2_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix2_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); @@ -349,7 +349,7 @@ bool slix2_protocol_handler (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nf bool handled = false; /* many SLIX share some of the functions, place that in a generic handler */ - if(slix_generic_protocol_handler(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { return true; } @@ -362,5 +362,5 @@ void slix2_prepare(NfcVData* nfcv_data) { FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); - nfcv_data->emu_protocol_handler = &slix2_protocol_handler; + nfcv_data->emu_protocol_filter = &slix2_protocol_filter; } diff --git a/lib/nfc/protocols/slix.h b/lib/nfc/protocols/slix.h index f30efacc1..e3c0e2076 100644 --- a/lib/nfc/protocols/slix.h +++ b/lib/nfc/protocols/slix.h @@ -36,8 +36,8 @@ bool slix_check_card_type(FuriHalNfcDevData* nfc_data); bool slix2_check_card_type(FuriHalNfcDevData* nfc_data); bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data); bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data); -ReturnCode slix_l_get_random(NfcVData* data); -ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id); +ReturnCode slix_get_random(NfcVData* data); +ReturnCode slix_unlock(NfcVData* data, uint32_t password_id); void slix_prepare(NfcVData* nfcv_data); void slix_s_prepare(NfcVData* nfcv_data);