diff --git a/applications/nfc/helpers/nfc_debug_pcap.c b/applications/nfc/helpers/nfc_debug_pcap.c new file mode 100644 index 00000000..c54dbedd --- /dev/null +++ b/applications/nfc/helpers/nfc_debug_pcap.c @@ -0,0 +1,99 @@ +#include "nfc_debug_pcap.h" + +#include + +#define TAG "NfcDebugPcap" + +#define PCAP_MAGIC 0xa1b2c3d4 +#define PCAP_MAJOR 2 +#define PCAP_MINOR 4 +#define DLT_ISO_14443 264 + +#define DATA_PICC_TO_PCD 0xFF +#define DATA_PCD_TO_PICC 0xFE +#define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB +#define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA + +File* nfc_debug_pcap_open(Storage* storage) { + File* file = storage_file_alloc(storage); + if(!storage_file_open(file, "/ext/nfc/debug.pcap", FSAM_WRITE, FSOM_OPEN_APPEND)) { + storage_file_free(file); + return NULL; + } + if(!storage_file_tell(file)) { + struct { + uint32_t magic; + uint16_t major, minor; + uint32_t reserved[2]; + uint32_t snaplen; + uint32_t link_type; + } __attribute__((__packed__)) pcap_hdr = { + .magic = PCAP_MAGIC, + .major = PCAP_MAJOR, + .minor = PCAP_MINOR, + .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE, + .link_type = DLT_ISO_14443, + }; + if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) { + FURI_LOG_E(TAG, "Failed to write pcap header"); + } + } + return file; +} + +void nfc_debug_pcap_write(Storage* storage, uint8_t event, uint8_t* data, uint16_t len) { + File* file = nfc_debug_pcap_open(storage); + if(!file) return; + + FuriHalRtcDateTime datetime; + furi_hal_rtc_get_datetime(&datetime); + + struct { + // https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header + uint32_t ts_sec; + uint32_t ts_usec; + uint32_t incl_len; + uint32_t orig_len; + // https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data + uint8_t version; + uint8_t event; + uint16_t len; + } __attribute__((__packed__)) pkt_hdr = { + .ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime), + .ts_usec = 0, + .incl_len = len + 4, + .orig_len = len + 4, + .version = 0, + .event = event, + .len = len << 8 | len >> 8, + }; + if(storage_file_write(file, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr)) { + FURI_LOG_E(TAG, "Failed to write pcap packet header"); + } else if(storage_file_write(file, data, len) != len) { + FURI_LOG_E(TAG, "Failed to write pcap packet data"); + } + storage_file_free(file); +} + +void nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { + uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC; + nfc_debug_pcap_write(context, event, data, bits / 8); +} + +void nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { + uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD; + nfc_debug_pcap_write(context, event, data, bits / 8); +} + +void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(is_picc) { + tx_rx->sniff_tx = nfc_debug_pcap_write_rx; + tx_rx->sniff_rx = nfc_debug_pcap_write_tx; + } else { + tx_rx->sniff_tx = nfc_debug_pcap_write_tx; + tx_rx->sniff_rx = nfc_debug_pcap_write_rx; + } + tx_rx->sniff_context = storage; + } +} diff --git a/applications/nfc/helpers/nfc_debug_pcap.h b/applications/nfc/helpers/nfc_debug_pcap.h new file mode 100644 index 00000000..69ba86eb --- /dev/null +++ b/applications/nfc/helpers/nfc_debug_pcap.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +/** Prepare tx/rx context for debug pcap logging, if enabled. + * + * @param tx_rx TX/RX context to log + * @param storage Storage to log to + * @param is_picc if true, record Flipper as PICC, else PCD. + */ +void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 88729bf4..c058809e 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -10,6 +10,7 @@ #include #include "helpers/nfc_mf_classic_dict.h" +#include "helpers/nfc_debug_pcap.h" #define TAG "NfcWorker" @@ -153,6 +154,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { void nfc_worker_emulate(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true); FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; @@ -175,6 +177,7 @@ void nfc_worker_emulate(NfcWorker* nfc_worker) { void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); EmvApplication emv_app = {}; NfcDeviceData* result = nfc_worker->dev_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; @@ -206,6 +209,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { void nfc_worker_read_emv(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); EmvApplication emv_app = {}; NfcDeviceData* result = nfc_worker->dev_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; @@ -254,6 +258,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true); FuriHalNfcDevData params = { .uid = {0xCF, 0x72, 0xd4, 0x40}, .uid_len = 4, @@ -278,6 +283,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); MfUltralightReader reader = {}; MfUltralightData data = {}; NfcDeviceData* result = nfc_worker->dev_data; @@ -342,6 +348,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { furi_assert(nfc_worker->callback); FuriHalNfcTxRxContext tx_rx_ctx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx_ctx, nfc_worker->storage, false); MfClassicAuthContext auth_ctx = {}; MfClassicReader reader = {}; uint64_t curr_key = 0; @@ -483,7 +490,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { } void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx; + FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true); FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; MfClassicEmulator emulator = { .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), @@ -511,11 +519,8 @@ void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { } void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { - ReturnCode err; - uint8_t tx_buff[64] = {}; - uint16_t tx_len = 0; - uint8_t rx_buff[512] = {}; - uint16_t rx_len; + FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); NfcDeviceData* result = nfc_worker->dev_data; nfc_device_data_clear(result); MifareDesfireData* data = &result->mf_df_data; @@ -540,37 +545,36 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { result->protocol = NfcDeviceProtocolMifareDesfire; // Get DESFire version - tx_len = mf_df_prepare_get_version(tx_buff); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_version(tx_rx.tx_data); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting version"); continue; } - if(!mf_df_parse_get_version_response(rx_buff, rx_len, &data->version)) { + if(!mf_df_parse_get_version_response(tx_rx.rx_data, tx_rx.rx_bits / 8, &data->version)) { FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response"); continue; } - tx_len = mf_df_prepare_get_free_memory(tx_buff); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err == ERR_NONE) { + tx_rx.tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx.tx_data); + if(furi_hal_nfc_tx_rx_full(&tx_rx)) { data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); - if(!mf_df_parse_get_free_memory_response(rx_buff, rx_len, data->free_memory)) { + if(!mf_df_parse_get_free_memory_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, data->free_memory)) { FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)"); free(data->free_memory); data->free_memory = NULL; } } - tx_len = mf_df_prepare_get_key_settings(tx_buff); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_D(TAG, "Bad exchange getting key settings"); } else { data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, data->master_key_settings)) { + if(!mf_df_parse_get_key_settings_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, data->master_key_settings)) { FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); free(data->master_key_settings); data->master_key_settings = NULL; @@ -580,17 +584,16 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { MifareDesfireKeyVersion** key_version_head = &data->master_key_settings->key_version_head; for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { - tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); - err = - furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key version"); continue; } MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); key_version->id = key_id; - if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { + if(!mf_df_parse_get_key_version_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); free(key_version); continue; @@ -600,31 +603,31 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { } } - tx_len = mf_df_prepare_get_application_ids(tx_buff); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx.tx_data); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting application IDs"); } else { - if(!mf_df_parse_get_application_ids_response(rx_buff, rx_len, &data->app_head)) { + if(!mf_df_parse_get_application_ids_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, &data->app_head)) { FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response"); } } for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - tx_len = mf_df_prepare_select_application(tx_buff, app->id); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { - FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_select_application(tx_rx.tx_data, app->id); + if(!furi_hal_nfc_tx_rx_full(&tx_rx) || + !mf_df_parse_select_application_response(tx_rx.rx_data, tx_rx.rx_bits / 8)) { + FURI_LOG_W(TAG, "Bad exchange selecting application"); continue; } - tx_len = mf_df_prepare_get_key_settings(tx_buff); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key settings"); } else { app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, app->key_settings)) { + if(!mf_df_parse_get_key_settings_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, app->key_settings)) { FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); free(app->key_settings); app->key_settings = NULL; @@ -633,17 +636,16 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { - tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); - err = furi_hal_nfc_exchange_full( - tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key version"); continue; } MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); key_version->id = key_id; - if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { + if(!mf_df_parse_get_key_version_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); free(key_version); continue; @@ -653,48 +655,45 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { } } - tx_len = mf_df_prepare_get_file_ids(tx_buff); - err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx.tx_data); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting file IDs"); } else { - if(!mf_df_parse_get_file_ids_response(rx_buff, rx_len, &app->file_head)) { + if(!mf_df_parse_get_file_ids_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, &app->file_head)) { FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response"); } } for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); - err = - furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); + tx_rx.tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx.tx_data, file->id); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting file settings"); continue; } - if(!mf_df_parse_get_file_settings_response(rx_buff, rx_len, file)) { + if(!mf_df_parse_get_file_settings_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, file)) { FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response"); continue; } switch(file->type) { case MifareDesfireFileTypeStandard: case MifareDesfireFileTypeBackup: - tx_len = mf_df_prepare_read_data(tx_buff, file->id, 0, 0); + tx_rx.tx_bits = 8 * mf_df_prepare_read_data(tx_rx.tx_data, file->id, 0, 0); break; case MifareDesfireFileTypeValue: - tx_len = mf_df_prepare_get_value(tx_buff, file->id); + tx_rx.tx_bits = 8 * mf_df_prepare_get_value(tx_rx.tx_data, file->id); break; case MifareDesfireFileTypeLinearRecord: case MifareDesfireFileTypeCyclicRecord: - tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); + tx_rx.tx_bits = 8 * mf_df_prepare_read_records(tx_rx.tx_data, file->id, 0, 0); break; } - err = - furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); - if(err != ERR_NONE) { - FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id); continue; } - if(!mf_df_parse_read_data_response(rx_buff, rx_len, file)) { + if(!mf_df_parse_read_data_response(tx_rx.rx_data, tx_rx.rx_bits / 8, file)) { FURI_LOG_W(TAG, "Bad response reading file %d", file->id); continue; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 00c96ec3..070a33f6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -366,44 +366,6 @@ bool furi_hal_nfc_emulate_nfca( return true; } -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); - - ReturnCode ret; - rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; - ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); - if(ret != ERR_NONE) { - return ret; - } - uint32_t start = DWT->CYCCNT; - while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { - rfalNfcWorker(); - state = rfalNfcGetState(); - ret = rfalNfcDataExchangeGetStatus(); - if(ret == ERR_BUSY) { - if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { - ret = ERR_TIMEOUT; - break; - } - continue; - } else { - start = DWT->CYCCNT; - } - taskYIELD(); - } - if(deactivate) { - rfalNfcDeactivate(false); - rfalLowPowerModeStart(); - } - return ret; -} - static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { furi_assert(tx_rx->nfca_signal); @@ -576,6 +538,12 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { FURI_LOG_E(TAG, "Failed to start data exchange"); return false; } + + if(tx_rx->sniff_tx) { + bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_TX_MANUAL); + tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, crc_dropped, tx_rx->sniff_context); + } + uint32_t start = DWT->CYCCNT; while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { rfalNfcWorker(); @@ -602,42 +570,42 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { tx_rx->rx_bits = *temp_rx_bits; } + if(tx_rx->sniff_rx) { + bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_RX_KEEP); + tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, crc_dropped, tx_rx->sniff_context); + } + return true; } -ReturnCode furi_hal_nfc_exchange_full( - uint8_t* tx_buff, - uint16_t tx_len, - uint8_t* rx_buff, - uint16_t rx_cap, - uint16_t* rx_len) { - ReturnCode err; - uint8_t* part_buff; - uint16_t* part_len_bits; +bool furi_hal_nfc_tx_rx_full(FuriHalNfcTxRxContext* tx_rx) { uint16_t part_len_bytes; - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false); - part_len_bytes = *part_len_bits / 8; - if(part_len_bytes > rx_cap) { - return ERR_OVERRUN; + if(!furi_hal_nfc_tx_rx(tx_rx, 1000)) { + return false; } - memcpy(rx_buff, part_buff, part_len_bytes); - *rx_len = part_len_bytes; - while(err == ERR_NONE && rx_buff[0] == 0xAF) { - err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false); - part_len_bytes = *part_len_bits / 8; - if(part_len_bytes > rx_cap - *rx_len) { - return ERR_OVERRUN; + while(tx_rx->rx_bits && tx_rx->rx_data[0] == 0xAF) { + FuriHalNfcTxRxContext tmp = *tx_rx; + tmp.tx_data[0] = 0xAF; + tmp.tx_bits = 8; + if(!furi_hal_nfc_tx_rx(&tmp, 1000)) { + return false; + } + part_len_bytes = tmp.rx_bits / 8; + if(part_len_bytes > FURI_HAL_NFC_DATA_BUFF_SIZE - tx_rx->rx_bits / 8) { + FURI_LOG_W(TAG, "Overrun rx buf"); + return false; } if(part_len_bytes == 0) { - return ERR_PROTO; + FURI_LOG_W(TAG, "Empty 0xAF response"); + return false; } - memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1); - *rx_buff = *part_buff; - *rx_len += part_len_bytes - 1; + memcpy(tx_rx->rx_data + tx_rx->rx_bits / 8, tmp.rx_data + 1, part_len_bytes - 1); + tx_rx->rx_data[0] = tmp.rx_data[0]; + tx_rx->rx_bits += 8 * (part_len_bytes - 1); } - return err; + return true; } void furi_hal_nfc_sleep() { diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h old mode 100755 new mode 100644 index 30672fb9..6e438367 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -17,7 +17,7 @@ extern "C" { #endif #define FURI_HAL_NFC_UID_MAX_LEN 10 -#define FURI_HAL_NFC_DATA_BUFF_SIZE (256) +#define FURI_HAL_NFC_DATA_BUFF_SIZE (512) #define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8) #define FURI_HAL_NFC_TXRX_DEFAULT \ @@ -80,6 +80,9 @@ typedef struct { uint8_t sak; } FuriHalNfcDevData; +typedef void ( + *FuriHalNfcTxRxSniffCallback)(uint8_t* data, uint16_t bits, bool crc_dropped, void* context); + typedef struct { uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE]; uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; @@ -89,6 +92,10 @@ typedef struct { uint16_t rx_bits; FuriHalNfcTxRxType tx_rx_type; NfcaSignal* nfca_signal; + + FuriHalNfcTxRxSniffCallback sniff_tx; + FuriHalNfcTxRxSniffCallback sniff_rx; + void* sniff_context; } FuriHalNfcTxRxContext; /** Init nfc @@ -165,23 +172,6 @@ bool furi_hal_nfc_emulate_nfca( void* context, uint32_t timeout); -/** NFC data exchange - * - * @param tx_buff transmit buffer - * @param tx_len transmit buffer length - * @param rx_buff receive buffer - * @param rx_len receive buffer length - * @param deactivate deactivate flag - * - * @return ST ReturnCode - */ -ReturnCode furi_hal_nfc_data_exchange( - uint8_t* tx_buff, - uint16_t tx_len, - uint8_t** rx_buff, - uint16_t** rx_len, - bool deactivate); - /** NFC data exchange * * @param tx_rx_ctx FuriHalNfcTxRxContext instance @@ -192,20 +182,11 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms); /** NFC data full exhange * - * @param tx_buff transmit buffer - * @param tx_len transmit buffer length - * @param rx_buff receive buffer - * @param rx_cap receive buffer capacity - * @param rx_len receive buffer length + * @param tx_rx_ctx FuriHalNfcTxRxContext instance * - * @return ST ReturnCode + * @return true on success */ -ReturnCode furi_hal_nfc_exchange_full( - uint8_t* tx_buff, - uint16_t tx_len, - uint8_t* rx_buff, - uint16_t rx_cap, - uint16_t* rx_len); +bool furi_hal_nfc_tx_rx_full(FuriHalNfcTxRxContext* tx_rx); /** NFC deactivate and start sleep */ diff --git a/lib/nfc_protocols/emv.c b/lib/nfc_protocols/emv.c index 416e63a5..b69675fd 100644 --- a/lib/nfc_protocols/emv.c +++ b/lib/nfc_protocols/emv.c @@ -397,7 +397,8 @@ bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) { bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) { furi_assert(tx_rx); bool emulation_complete = false; - memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); + tx_rx->tx_bits = 0; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; do { FURI_LOG_D(TAG, "Read select PPSE command"); diff --git a/lib/nfc_protocols/mifare_classic.c b/lib/nfc_protocols/mifare_classic.c index 38c47127..b44f77cb 100644 --- a/lib/nfc_protocols/mifare_classic.c +++ b/lib/nfc_protocols/mifare_classic.c @@ -270,7 +270,9 @@ static bool mf_classic_auth( MfClassicKey key_type, Crypto1* crypto) { bool auth_success = false; - memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); + memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); + memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; do { if(key_type == MfClassicKeyA) { @@ -372,7 +374,8 @@ bool mf_classic_read_block( bool read_block_success = false; uint8_t plain_cmd[4] = {MF_CLASSIC_READ_SECT_CMD, block_num, 0x00, 0x00}; nfca_append_crc16(plain_cmd, 2); - memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); + memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); + memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); for(uint8_t i = 0; i < 4; i++) { tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ plain_cmd[i];