From c1223174681f8fa96caee376f502d49886db0355 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 17 Aug 2021 00:45:04 +0300 Subject: [PATCH] [FL-1526] Mifare Ultralight emulation (#645) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rfal: add discovery parameter for passing listen activation * nfc: add discovery parameter to furi_hal_nfc_listen * mifare_ul: add emulation parsing commands * nfc: add mifare ul emulation * nfc: switch to mifare ultralight emulation form menu * furi-hal-nfc: add first frame reception in emulation mode * nfc: change argument check * nfc: rework nfc worker and mifare ul lib * mifare_ul: add write and cnt increment commands * nfc: add card modification check * mifare_ul: add data changed flag * nfc: add shodow files * nfc: add restore original file Co-authored-by: あく --- applications/nfc/nfc.c | 3 +- applications/nfc/nfc_cli.c | 2 +- applications/nfc/nfc_device.c | 93 +++++++++++++++++-- applications/nfc/nfc_device.h | 5 + applications/nfc/nfc_worker.c | 55 +++++++---- applications/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_emulate_mifare_ul.c | 51 +++++----- .../nfc/scenes/nfc_scene_mifare_ul_menu.c | 2 +- .../nfc/scenes/nfc_scene_restore_original.c | 48 ++++++++++ .../nfc/scenes/nfc_scene_saved_menu.c | 41 +++++--- firmware/targets/f6/furi-hal/furi-hal-nfc.c | 11 ++- .../targets/furi-hal-include/furi-hal-nfc.h | 7 +- lib/ST25RFAL002/include/rfal_nfc.h | 2 + lib/ST25RFAL002/source/rfal_nfc.c | 8 ++ lib/nfc_protocols/mifare_ultralight.c | 91 ++++++++++++++++++ lib/nfc_protocols/mifare_ultralight.h | 3 + 16 files changed, 354 insertions(+), 69 deletions(-) create mode 100644 applications/nfc/scenes/nfc_scene_restore_original.c diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index a1f4a19e..5bf788b9 100755 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -151,9 +151,10 @@ void nfc_text_store_clear(Nfc* nfc) { int32_t nfc_app(void* p) { Nfc* nfc = nfc_alloc(); + char* args = p; // Check argument and run corresponding scene - if(p && nfc_device_load(&nfc->dev, p)) { + if((*args != '\0') && nfc_device_load(&nfc->dev, p)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c index 8adf5761..e2ddb5ed 100755 --- a/applications/nfc/nfc_cli.c +++ b/applications/nfc/nfc_cli.c @@ -64,7 +64,7 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) { }; while(!cli_cmd_interrupt_received(cli)) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 100)) { + if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { printf("Reader detected\r\n"); furi_hal_nfc_deactivate(); } diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index bfe0e877..bdb3d547 100755 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -8,6 +8,7 @@ static const char* nfc_app_folder = "/any/nfc"; static const char* nfc_app_extension = ".nfc"; +static const char* nfc_app_shadow_extension = ".shd"; static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) { string_strim(str); @@ -259,7 +260,11 @@ void nfc_device_set_name(NfcDevice* dev, const char* name) { strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN); } -bool nfc_device_save(NfcDevice* dev, const char* dev_name) { +static bool nfc_device_save_file( + NfcDevice* dev, + const char* dev_name, + const char* folder, + const char* extension) { furi_assert(dev); FileWorker* file_worker = file_worker_alloc(false); @@ -275,7 +280,7 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { break; }; // First remove nfc device file if it was saved - string_printf(dev_file_name, "%s/%s%s", nfc_app_folder, dev_name, nfc_app_extension); + string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension); if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { break; }; @@ -316,16 +321,42 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { return true; } +bool nfc_device_save(NfcDevice* dev, const char* dev_name) { + return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_extension); +} + +bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { + dev->shadow_file_exist = true; + return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension); +} + static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) { string_t temp_string; string_init(temp_string); bool parsed = false; do { - // Open key file - if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + // Check existance of shadow file + size_t ext_start = string_search_str(path, nfc_app_extension); + string_set_n(temp_string, path, 0, ext_start); + string_cat_printf(temp_string, "%s", nfc_app_shadow_extension); + if(!file_worker_is_file_exist( + file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) { break; } + // Open shadow file if it exists. If not - open original + if(dev->shadow_file_exist) { + if(!file_worker_open( + file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + } else { + if(!file_worker_open( + file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + } + // Read and parse format from 1st line if(!file_worker_read_until(file_worker, temp_string, '\n')) { break; @@ -427,13 +458,61 @@ void nfc_device_clear(NfcDevice* dev) { bool nfc_device_delete(NfcDevice* dev) { furi_assert(dev); - bool result = false; + bool result = true; FileWorker* file_worker = file_worker_alloc(false); string_t file_path; - string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); - result = file_worker_remove(file_worker, string_get_cstr(file_path)); + + do { + // Delete original file + string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); + if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { + result = false; + break; + } + // Delete shadow file if it exists + if(dev->shadow_file_exist) { + string_clean(file_path); + string_printf( + file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); + if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { + result = false; + break; + } + } + } while(0); + string_clear(file_path); file_worker_close(file_worker); file_worker_free(file_worker); return result; } + +bool nfc_device_restore(NfcDevice* dev) { + furi_assert(dev); + furi_assert(dev->shadow_file_exist); + + bool result = true; + FileWorker* file_worker = file_worker_alloc(false); + string_t path; + + do { + string_init_printf( + path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); + if(!file_worker_remove(file_worker, string_get_cstr(path))) { + result = false; + break; + } + dev->shadow_file_exist = false; + string_clean(path); + string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); + if(!nfc_device_load_data(file_worker, path, dev)) { + result = false; + break; + } + } while(0); + + string_clear(path); + file_worker_close(file_worker); + file_worker_free(file_worker); + return result; +} diff --git a/applications/nfc/nfc_device.h b/applications/nfc/nfc_device.h index c2de3120..25f0e42f 100644 --- a/applications/nfc/nfc_device.h +++ b/applications/nfc/nfc_device.h @@ -59,12 +59,15 @@ typedef struct { char dev_name[NFC_DEV_NAME_MAX_LEN]; char file_name[NFC_FILE_NAME_MAX_LEN]; NfcDeviceSaveFormat format; + bool shadow_file_exist; } NfcDevice; void nfc_device_set_name(NfcDevice* dev, const char* name); bool nfc_device_save(NfcDevice* dev, const char* dev_name); +bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name); + bool nfc_device_load(NfcDevice* dev, const char* file_path); bool nfc_file_select(NfcDevice* dev); @@ -72,3 +75,5 @@ bool nfc_file_select(NfcDevice* dev); void nfc_device_clear(NfcDevice* dev); bool nfc_device_delete(NfcDevice* dev); + +bool nfc_device_restore(NfcDevice* dev); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 334e6d7b..9fd6dc64 100755 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -143,7 +143,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { void nfc_worker_emulate(NfcWorker* nfc_worker) { NfcDeviceCommomData* data = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateEmulate) { - if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, 100)) { + if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); } osDelay(10); @@ -406,7 +406,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { 0x00, 0x00}; while(nfc_worker->state == NfcWorkerStateEmulateApdu) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 300)) { + if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected"); // Read data from POS terminal err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); @@ -608,33 +608,52 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { uint8_t* rx_buff; uint16_t* rx_len; NfcDeviceData* data = nfc_worker->dev_data; - + MifareUlDevice mf_ul_emulate; + // Setup emulation parameters from mifare ultralight data structure + mf_ul_prepare_emulation(&mf_ul_emulate, &data->mf_ul_data); while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { if(furi_hal_nfc_listen( data->nfc_data.uid, data->nfc_data.uid_len, data->nfc_data.atqa, data->nfc_data.sak, - 1000)) { - FURI_LOG_I(NFC_WORKER_TAG, "Hello my dudes"); - // Prepare version answer - tx_len = sizeof(data->mf_ul_data.version); - memcpy(tx_buff, &data->mf_ul_data.version, tx_len); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_I(NFC_WORKER_TAG, "Received 1st message:"); - for(uint16_t i = 0; i < *rx_len; i++) { - printf("%02X ", rx_buff[i]); + true, + 200)) { + FURI_LOG_D(NFC_WORKER_TAG, "Anticollision passed"); + if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) { + // Data exchange loop + while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + tx_len = mf_ul_prepare_emulation_response( + rx_buff, *rx_len, tx_buff, &mf_ul_emulate); + if(tx_len > 0) { + err = + furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); + if(err == ERR_NONE) { + continue; + } else { + FURI_LOG_E(NFC_WORKER_TAG, "Communication error: %d", err); + break; + } + } else { + FURI_LOG_W(NFC_WORKER_TAG, "Not valid command: %02X", rx_buff[0]); + furi_hal_nfc_deactivate(); + break; + } } - printf("\r\n"); } else { - FURI_LOG_E(NFC_WORKER_TAG, "Error in 1st data exchange: select PPSE"); + FURI_LOG_W(NFC_WORKER_TAG, "Error in 1st data exchange"); furi_hal_nfc_deactivate(); - continue; } } - FURI_LOG_W(NFC_WORKER_TAG, "Hello my dudes"); - osDelay(10); + // Check if data was modified + if(mf_ul_emulate.data_changed) { + nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; + if(nfc_worker->callback) { + nfc_worker->callback(nfc_worker->context); + } + } + FURI_LOG_W(NFC_WORKER_TAG, "Can't find reader"); + osThreadYield(); } } diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 149b4d7f..97072ead 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -26,3 +26,4 @@ ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm) ADD_SCENE(nfc, read_emv_data, ReadEmvData) ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) +ADD_SCENE(nfc, restore_original, RestoreOriginal) diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c index 7286b7ac..d1d52bef 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c @@ -1,38 +1,33 @@ #include "../nfc_i.h" +#define NFC_MF_UL_DATA_NOT_CHANGED (0UL) +#define NFC_MF_UL_DATA_CHANGED (1UL) + +void nfc_emulate_mifare_ul_worker_callback(void* context) { + Nfc* nfc = (Nfc*)context; + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); +} + const void nfc_scene_emulate_mifare_ul_on_enter(void* context) { Nfc* nfc = (Nfc*)context; // Setup view Popup* popup = nfc->popup; - NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; - if(strcmp(nfc->dev.dev_name, "")) { nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); - } else if(data->uid_len == 4) { - nfc_text_store_set( - nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]); - } else if(data->uid_len == 7) { - nfc_text_store_set( - nfc, - "%02X %02X %02X %02X\n%02X %02X %02X", - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3], - data->uid[4], - data->uid[5], - data->uid[6]); } - popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); - popup_set_header(popup, "Emulating Mf Ul", 56, 31, AlignLeft, AlignTop); - popup_set_text(popup, nfc->text_store, 56, 43, AlignLeft, AlignTop); + popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop); // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc_worker_start(nfc->worker, NfcWorkerStateEmulateMifareUl, &nfc->dev.dev_data, NULL, nfc); + nfc_worker_start( + nfc->worker, + NfcWorkerStateEmulateMifareUl, + &nfc->dev.dev_data, + nfc_emulate_mifare_ul_worker_callback, + nfc); } const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { @@ -42,6 +37,17 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); consumed = true; + } else if(event.type == SceneManagerEventTypeBack) { + // Stop worker + nfc_worker_stop(nfc->worker); + // Check if data changed and save in shadow file + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) == + NFC_MF_UL_DATA_CHANGED) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED); + nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name); + } + consumed = false; } return consumed; } @@ -49,9 +55,6 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent const void nfc_scene_emulate_mifare_ul_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view Popup* popup = nfc->popup; popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c index 396c393b..70716618 100755 --- a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c @@ -38,7 +38,7 @@ const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent ev } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); return true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/nfc/scenes/nfc_scene_restore_original.c b/applications/nfc/scenes/nfc_scene_restore_original.c new file mode 100644 index 00000000..3229d023 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_restore_original.c @@ -0,0 +1,48 @@ +#include "../nfc_i.h" + +#define SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT (0UL) + +void nfc_scene_restore_original_popup_callback(void* context) { + Nfc* nfc = (Nfc*)context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT); +} + +const void nfc_scene_restore_original_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_restore_original_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +const bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + return consumed; +} + +const void nfc_scene_restore_original_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + // Clear view + Popup* popup = nfc->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); +} diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index 24d03fbc..cd682783 100755 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -5,6 +5,7 @@ enum SubmenuIndex { SubmenuIndexEdit, SubmenuIndexDelete, SubmenuIndexInfo, + SubmenuIndexRestoreOriginal, }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { @@ -29,36 +30,52 @@ const void nfc_scene_saved_menu_on_enter(void* context) { submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); + if(nfc->dev.shadow_file_exist) { + submenu_add_item( + submenu, + "Restore original", + SubmenuIndexRestoreOriginal, + nfc_scene_saved_menu_submenu_callback, + nfc); + } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = (Nfc*)context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); if(event.event == SubmenuIndexEmulate) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - return true; + if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + } + consumed = true; } else if(event.event == SubmenuIndexEdit) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEdit); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); - return true; + consumed = true; } else if(event.event == SubmenuIndexDelete) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexDelete); scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); - return true; + consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexInfo); scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); - return true; + consumed = true; + } else if(event.event == SubmenuIndexRestoreOriginal) { + if(!nfc_device_restore(&nfc->dev)) { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal); + } + consumed = true; } } - return false; + return consumed; } const void nfc_scene_saved_menu_on_exit(void* context) { diff --git a/firmware/targets/f6/furi-hal/furi-hal-nfc.c b/firmware/targets/f6/furi-hal/furi-hal-nfc.c index d64a344e..d92e2cad 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-nfc.c +++ b/firmware/targets/f6/furi-hal/furi-hal-nfc.c @@ -86,9 +86,8 @@ bool furi_hal_nfc_detect(rfalNfcDevice **dev_list, uint8_t* dev_cnt, uint32_t ti return true; } -bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout) { +bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, bool activate_after_sak, uint32_t timeout) { rfalNfcState state = rfalNfcGetState(); - if(state == RFAL_NFC_STATE_NOTINIT) { rfalNfcInitialize(); } else if(state >= RFAL_NFC_STATE_ACTIVATED) { @@ -107,6 +106,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s .maxBR = RFAL_BR_KEEP, .GBLen = RFAL_NFCDEP_GB_MAX_LEN, .notifyCb = NULL, + .activate_after_sak = activate_after_sak, }; params.lmConfigPA.nfcidLen = uid_len; memcpy(params.lmConfigPA.nfcid, uid, uid_len); @@ -119,7 +119,6 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s while(state != RFAL_NFC_STATE_ACTIVATED) { rfalNfcWorker(); state = rfalNfcGetState(); - FURI_LOG_D("HAL NFC", "Current state %d", state); if(DWT->CYCCNT - start > timeout * clocks_in_ms) { rfalNfcDeactivate(true); return false; @@ -129,6 +128,11 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s return true; } +bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { + ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0); + return ret == ERR_NONE; +} + ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate) { furi_assert(rx_buff); furi_assert(rx_len); @@ -144,7 +148,6 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t rfalNfcWorker(); state = rfalNfcGetState(); ret = rfalNfcDataExchangeGetStatus(); - FURI_LOG_D("HAL NFC", "Nfc st: %d Data st: %d", state, ret); if(ret > ERR_SLEEP_REQ) { return ret; } diff --git a/firmware/targets/furi-hal-include/furi-hal-nfc.h b/firmware/targets/furi-hal-include/furi-hal-nfc.h index aaed2924..1ef9063d 100644 --- a/firmware/targets/furi-hal-include/furi-hal-nfc.h +++ b/firmware/targets/furi-hal-include/furi-hal-nfc.h @@ -49,7 +49,12 @@ bool furi_hal_nfc_detect(rfalNfcDevice** dev_list, uint8_t* dev_cnt, uint32_t ti /** * NFC listen */ -bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout); +bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, bool activate_after_sak, uint32_t timeout); + +/** + * Get first command from reader after activation in emulation mode + */ +bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len); /** * NFC data exchange diff --git a/lib/ST25RFAL002/include/rfal_nfc.h b/lib/ST25RFAL002/include/rfal_nfc.h index d8086d20..0500659b 100755 --- a/lib/ST25RFAL002/include/rfal_nfc.h +++ b/lib/ST25RFAL002/include/rfal_nfc.h @@ -213,6 +213,8 @@ typedef struct{ bool wakeupEnabled; /*!< Enable Wake-Up mode before polling */ bool wakeupConfigDefault; /*!< Wake-Up mode default configuration */ rfalWakeUpConfig wakeupConfig; /*!< Wake-Up mode configuration */ + + bool activate_after_sak; // Set device to Active mode after SAK responce }rfalNfcDiscoverParam; diff --git a/lib/ST25RFAL002/source/rfal_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c index a12cdcc9..96d35889 100755 --- a/lib/ST25RFAL002/source/rfal_nfc.c +++ b/lib/ST25RFAL002/source/rfal_nfc.c @@ -575,6 +575,7 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_ *rvdLen = (uint16_t*)&gNfcDev.rxLen; *rxData = (uint8_t*)( (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ? gNfcDev.rxBuf.isoDepBuf.apdu : ((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ? gNfcDev.rxBuf.nfcDepBuf.pdu : gNfcDev.rxBuf.rfBuf)); + gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE; return ERR_NONE; } @@ -1579,6 +1580,7 @@ static ReturnCode rfalNfcListenActivation( void ) lmSt = rfalListenGetState( &isDataRcvd, &bitRate ); + switch(lmSt) { @@ -1595,6 +1597,12 @@ static ReturnCode rfalNfcListenActivation( void ) /* Set the Listen Mode in Sleep state */ EXIT_ON_ERR( ret, rfalListenSleepStart( RFAL_LM_STATE_SLEEP_A, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen ) ); } + + else if(gNfcDev.disc.activate_after_sak) { + gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA; + rfalListenSetState(RFAL_LM_STATE_ACTIVE_A); + return ERR_NONE; + } #if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_LISTEN /* Check if received data is a valid RATS */ diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index a96c2889..39a93a00 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -137,3 +137,94 @@ uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) { dest[5] = (uint8_t) data; return 6; } + +void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) { + mf_ul_emulate->data = *data; + mf_ul_emulate->data_changed = false; + if(data->version.storage_size == 0) { + mf_ul_emulate->type = MfUltralightTypeUnknown; + mf_ul_emulate->support_fast_read = false; + } else if(data->version.storage_size == 0x0B) { + mf_ul_emulate->type = MfUltralightTypeUL11; + mf_ul_emulate->support_fast_read = true; + } else if(data->version.storage_size == 0x0E) { + mf_ul_emulate->type = MfUltralightTypeUL21; + mf_ul_emulate->support_fast_read = true; + } +} + +uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate) { + uint8_t cmd = buff_rx[0]; + uint16_t page_num = mf_ul_emulate->data.data_size / 4; + uint16_t tx_len = 0; + + if(cmd == MF_UL_GET_VERSION_CMD) { + if(mf_ul_emulate->type != MfUltralightTypeUnknown) { + tx_len = sizeof(mf_ul_emulate->data.version); + memcpy(buff_tx, &mf_ul_emulate->data.version, tx_len); + } + } else if(cmd == MF_UL_READ_CMD) { + uint8_t start_page = buff_rx[1]; + if(start_page < page_num) { + tx_len = 16; + if(start_page + 4 > page_num) { + // Handle roll-over mechanism + uint8_t end_pages_num = page_num - start_page; + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4); + memcpy(&buff_tx[end_pages_num * 4], mf_ul_emulate->data.data, (4 - end_pages_num) * 4); + } else { + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); + } + } + } else if(cmd == MF_UL_FAST_READ_CMD) { + if(mf_ul_emulate->support_fast_read) { + uint8_t start_page = buff_rx[1]; + uint8_t end_page = buff_rx[2]; + if((start_page < page_num) && + (end_page < page_num) && (start_page < end_page)) { + tx_len = (end_page - start_page) * 4; + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); + } + } + } else if(cmd == MF_UL_WRITE) { + uint8_t write_page = buff_rx[1]; + if((write_page > 1) && (write_page < page_num - 2)) { + memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4); + mf_ul_emulate->data_changed = true; + // TODO make 4-bit ACK + buff_tx[0] = 0x0A; + tx_len = 1; + } + } else if(cmd == MF_UL_READ_CNT) { + uint8_t cnt_num = buff_rx[1]; + if(cnt_num < 3) { + buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16; + buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8; + buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; + tx_len = 3; + } + } else if(cmd == MF_UL_INC_CNT) { + uint8_t cnt_num = buff_rx[1]; + uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16)); + if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) { + mf_ul_emulate->data.counter[cnt_num] += inc; + mf_ul_emulate->data_changed = true; + // TODO make 4-bit ACK + buff_tx[0] = 0x0A; + tx_len = 1; + } + } else if(cmd == MF_UL_READ_SIG) { + // Check 2nd byte = 0x00 - RFU + if(buff_rx[1] == 0x00) { + tx_len = sizeof(mf_ul_emulate->data.signature); + memcpy(buff_tx, mf_ul_emulate->data.signature, tx_len); + } + } else if(cmd == MF_UL_CHECK_TEARING) { + uint8_t cnt_num = buff_rx[1]; + if(cnt_num < 3) { + buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; + tx_len = 1; + } + } + return tx_len; +} diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 83673a7e..7522f334 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -65,6 +65,7 @@ typedef struct { uint8_t pages_to_read; uint8_t pages_readed; bool support_fast_read; + bool data_changed; MifareUlData data; } MifareUlDevice; @@ -93,3 +94,5 @@ void mf_ul_parse_fast_read_response(uint8_t* buff, uint8_t start_page, uint8_t e uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data); +void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data); +uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate);