From b0f582df9950c2a1a18c4f3b8a9a4fe4da4a3613 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 21 Dec 2021 15:33:17 +0300 Subject: [PATCH] [FL-1972], [FL-1920] Mifare Ultralight and NTAG separation (#918) * nfc: rename read mifare ultralight menu * nfc: separate ntag and mifare ultralight * nfc: save Mifare Ultralight type * nfc: add valid ack and nack messages * nfc: add compatible write command implementation * nfc: support f6 target --- applications/nfc/nfc_device.c | 19 ++- applications/nfc/nfc_types.h | 20 ++- applications/nfc/nfc_worker.c | 13 +- applications/nfc/scenes/nfc_scene_delete.c | 16 +-- .../nfc/scenes/nfc_scene_device_info.c | 16 +-- .../nfc/scenes/nfc_scene_read_card_success.c | 4 +- .../scenes/nfc_scene_read_mifare_ul_success.c | 5 +- .../nfc/scenes/nfc_scene_scripts_menu.c | 2 +- firmware/targets/f6/furi-hal/furi-hal-nfc.c | 39 +++++- firmware/targets/f7/furi-hal/furi-hal-nfc.c | 39 +++++- .../targets/furi-hal-include/furi-hal-nfc.h | 2 + lib/ST25RFAL002/include/rfal_nfc.h | 2 +- lib/ST25RFAL002/include/rfal_rf.h | 2 +- lib/ST25RFAL002/source/rfal_nfc.c | 7 +- lib/nfc_protocols/mifare_ultralight.c | 125 ++++++++++++------ lib/nfc_protocols/mifare_ultralight.h | 8 +- 16 files changed, 234 insertions(+), 85 deletions(-) mode change 100644 => 100755 applications/nfc/nfc_worker.c diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index 17a261f27..cfd0db2dd 100755 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -1,4 +1,5 @@ #include "nfc_device.h" +#include "nfc_types.h" #include #include @@ -29,7 +30,7 @@ void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { } else if(dev->format == NfcDeviceSaveFormatBankCard) { string_set_str(format_string, "Bank card"); } else if(dev->format == NfcDeviceSaveFormatMifareUl) { - string_set_str(format_string, "Mifare Ultralight"); + string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true)); } else { string_set_str(format_string, "Unknown"); } @@ -40,14 +41,20 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { dev->format = NfcDeviceSaveFormatUid; dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; return true; - } else if(string_start_with_str_p(format_string, "Bank card")) { + } + if(string_start_with_str_p(format_string, "Bank card")) { dev->format = NfcDeviceSaveFormatBankCard; dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; return true; - } else if(string_start_with_str_p(format_string, "Mifare Ultralight")) { - dev->format = NfcDeviceSaveFormatMifareUl; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; - return true; + } + // Check Mifare Ultralight types + for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { + if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) { + dev->format = NfcDeviceSaveFormatMifareUl; + dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; + dev->dev_data.mf_ul_data.type = type; + return true; + } } return false; } diff --git a/applications/nfc/nfc_types.h b/applications/nfc/nfc_types.h index 6c37076a5..12bcc0934 100644 --- a/applications/nfc/nfc_types.h +++ b/applications/nfc/nfc_types.h @@ -54,12 +54,28 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { } } -static inline const char* nfc_get_protocol(NfcProtocol protocol) { +static inline const char* nfc_guess_protocol(NfcProtocol protocol) { if(protocol == NfcDeviceProtocolEMV) { return "EMV bank card"; } else if(protocol == NfcDeviceProtocolMifareUl) { - return "Mifare Ultralight"; + return "Mifare Ultral/NTAG"; } else { return "Unrecognized"; } } + +static inline const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { + if(type == MfUltralightTypeNTAG213) { + return "NTAG213"; + } else if(type == MfUltralightTypeNTAG215) { + return "NTAG215"; + } else if(type == MfUltralightTypeNTAG216) { + return "NTAG216"; + } else if(type == MfUltralightTypeUL11 && full_name) { + return "Mifare Ultralight 11"; + } else if(type == MfUltralightTypeUL21 && full_name) { + return "Mifare Ultralight 21"; + } else { + return "Mifare Ultralight"; + } +} diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c old mode 100644 new mode 100755 index 5f810cf63..ad1aa6e51 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -503,7 +503,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { FURI_LOG_D( TAG, "Mifare Ultralight Type: %d, Pages: %d", - mf_ul_read.type, + mf_ul_read.data.type, mf_ul_read.pages_to_read); FURI_LOG_D(TAG, "Reading signature ..."); tx_len = mf_ul_prepare_read_signature(tx_buff); @@ -629,8 +629,14 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { 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(tx_len < 8) { + err = furi_hal_nfc_raw_bitstream_exchange( + tx_buff, tx_len, &rx_buff, &rx_len, false); + *rx_len /= 8; + } else { + err = furi_hal_nfc_data_exchange( + tx_buff, tx_len / 8, &rx_buff, &rx_len, false); + } if(err == ERR_NONE) { continue; } else { @@ -638,7 +644,6 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { break; } } else { - FURI_LOG_D(TAG, "Not valid command: %02X", rx_buff[0]); furi_hal_nfc_deactivate(); break; } diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c index 498e6ecd8..d67511c44 100755 --- a/applications/nfc/scenes/nfc_scene_delete.c +++ b/applications/nfc/scenes/nfc_scene_delete.c @@ -44,15 +44,15 @@ void nfc_scene_delete_on_enter(void* context) { } widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); - if(data->protocol > NfcDeviceProtocolUnknown) { + const char* protocol_name = NULL; + if(data->protocol == NfcDeviceProtocolEMV) { + protocol_name = nfc_guess_protocol(data->protocol); + } else if(data->protocol == NfcDeviceProtocolMifareUl) { + protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); + } + if(protocol_name) { widget_add_string_element( - nfc->widget, - 10, - 32, - AlignLeft, - AlignTop, - FontSecondary, - nfc_get_protocol(data->protocol)); + nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); } // TODO change dinamically widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index 1495c1279..659ced9db 100755 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -68,15 +68,15 @@ void nfc_scene_device_info_on_enter(void* context) { } widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); - if(data->protocol > NfcDeviceProtocolUnknown) { + const char* protocol_name = NULL; + if(data->protocol == NfcDeviceProtocolEMV) { + protocol_name = nfc_guess_protocol(data->protocol); + } else if(data->protocol == NfcDeviceProtocolMifareUl) { + protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); + } + if(protocol_name) { widget_add_string_element( - nfc->widget, - 10, - 32, - AlignLeft, - AlignTop, - FontSecondary, - nfc_get_protocol(data->protocol)); + nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); } // TODO change dinamically widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index c70bf1b27..d03dc831a 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -27,7 +27,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { nfc, NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X", - nfc_get_protocol(data->protocol), + nfc_guess_protocol(data->protocol), data->atqa[0], data->atqa[1], data->sak, @@ -41,7 +41,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", - nfc_get_protocol(data->protocol), + nfc_guess_protocol(data->protocol), data->atqa[0], data->atqa[1], data->sak, diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index 9c8dfc78c..a11af2b5b 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -28,11 +28,13 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { // Setup dialog view NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "More"); dialog_ex_set_center_button_text(dialog_ex, "Data"); - dialog_ex_set_header(dialog_ex, "Mifare Ultralight", 22, 8, AlignLeft, AlignCenter); + dialog_ex_set_header( + dialog_ex, nfc_mf_ul_type(mf_ul_data->type, true), 64, 8, AlignCenter, AlignCenter); dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); // Display UID nfc_text_store_set( @@ -54,7 +56,6 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); // Setup TextBox view - MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; TextBox* text_box = nfc->text_box; text_box_set_context(text_box, nfc); text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.c b/applications/nfc/scenes/nfc_scene_scripts_menu.c index c82c45645..ffb856d3b 100755 --- a/applications/nfc/scenes/nfc_scene_scripts_menu.c +++ b/applications/nfc/scenes/nfc_scene_scripts_menu.c @@ -23,7 +23,7 @@ void nfc_scene_scripts_menu_on_enter(void* context) { nfc); submenu_add_item( submenu, - "Read Mifare Ultralight", + "Read Mifare Ultral/Ntag", SubmenuIndexMifareUltralight, nfc_scene_scripts_menu_submenu_callback, nfc); diff --git a/firmware/targets/f6/furi-hal/furi-hal-nfc.c b/firmware/targets/f6/furi-hal/furi-hal-nfc.c index dbe5579cb..ee1138d88 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-nfc.c +++ b/firmware/targets/f6/furi-hal/furi-hal-nfc.c @@ -131,7 +131,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s } 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); + ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); return ret == ERR_NONE; } @@ -141,7 +141,42 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t ReturnCode ret; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; - ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); + 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_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_bit_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); if(ret != ERR_NONE) { return ret; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-nfc.c b/firmware/targets/f7/furi-hal/furi-hal-nfc.c index dbe5579cb..ee1138d88 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-nfc.c +++ b/firmware/targets/f7/furi-hal/furi-hal-nfc.c @@ -131,7 +131,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s } 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); + ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); return ret == ERR_NONE; } @@ -141,7 +141,42 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t ReturnCode ret; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; - ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); + 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_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_bit_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); if(ret != ERR_NONE) { 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 c05b4df9e..babc7b180 100644 --- a/firmware/targets/furi-hal-include/furi-hal-nfc.h +++ b/firmware/targets/furi-hal-include/furi-hal-nfc.h @@ -87,6 +87,8 @@ bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len); */ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate); +ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate); + /** NFC deactivate and start sleep */ void furi_hal_nfc_deactivate(); diff --git a/lib/ST25RFAL002/include/rfal_nfc.h b/lib/ST25RFAL002/include/rfal_nfc.h index 0500659b1..6147148d3 100755 --- a/lib/ST25RFAL002/include/rfal_nfc.h +++ b/lib/ST25RFAL002/include/rfal_nfc.h @@ -364,7 +364,7 @@ ReturnCode rfalNfcSelect( uint8_t devIdx ); * \return ERR_NONE : No error ***************************************************************************** */ -ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ); +ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt, uint32_t tx_flag); /*! ***************************************************************************** diff --git a/lib/ST25RFAL002/include/rfal_rf.h b/lib/ST25RFAL002/include/rfal_rf.h index 96b662a57..f7f68c4f2 100755 --- a/lib/ST25RFAL002/include/rfal_rf.h +++ b/lib/ST25RFAL002/include/rfal_rf.h @@ -110,7 +110,7 @@ /*! Default TxRx flags: Tx CRC automatic, Rx CRC removed, NFCIP1 mode off, AGC On, Tx Parity automatic, Rx Parity removed */ #define RFAL_TXRX_FLAGS_DEFAULT ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) - +#define RFAL_TXRX_FLAGS_RAW ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE| (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) #define RFAL_LM_MASK_NFCA ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCA) /*!< Bitmask for Listen Mode enabling NFCA */ diff --git a/lib/ST25RFAL002/source/rfal_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c index f1f3ddd3e..4f66f4103 100755 --- a/lib/ST25RFAL002/source/rfal_nfc.c +++ b/lib/ST25RFAL002/source/rfal_nfc.c @@ -550,7 +550,7 @@ void rfalNfcWorker( void ) /*******************************************************************************/ -ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ) +ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt, uint32_t flags) { ReturnCode err; rfalTransceiveContext ctx; @@ -588,7 +588,10 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_ /*******************************************************************************/ case RFAL_NFC_INTERFACE_RF: - rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, RFAL_TXRX_FLAGS_DEFAULT, fwt ); + rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, flags, fwt ); + if(flags == RFAL_TXRX_FLAGS_RAW) { + ctx.txBufLen = txDataLen; + } *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; *rvdLen = (uint16_t*)&gNfcDev.rxLen; err = rfalStartTransceive( &ctx ); diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index b36788648..b11380749 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -16,23 +16,23 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) MfUltralightVersion* version = (MfUltralightVersion*) buff; memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion)); if(version->storage_size == 0x0B || version->storage_size == 0x00) { - mf_ul_read->type = MfUltralightTypeUL11; + mf_ul_read->data.type = MfUltralightTypeUL11; mf_ul_read->pages_to_read = 20; mf_ul_read->support_fast_read = true; } else if(version->storage_size == 0x0E) { - mf_ul_read->type = MfUltralightTypeUL21; + mf_ul_read->data.type = MfUltralightTypeUL21; mf_ul_read->pages_to_read = 41; mf_ul_read->support_fast_read = true; } else if(version->storage_size == 0x0F) { - mf_ul_read->type = MfUltralightTypeNTAG213; + mf_ul_read->data.type = MfUltralightTypeNTAG213; mf_ul_read->pages_to_read = 45; mf_ul_read->support_fast_read = false; } else if(version->storage_size == 0x11) { - mf_ul_read->type = MfUltralightTypeNTAG215; + mf_ul_read->data.type = MfUltralightTypeNTAG215; mf_ul_read->pages_to_read = 135; mf_ul_read->support_fast_read = false; } else if(version->storage_size == 0x13) { - mf_ul_read->type = MfUltralightTypeNTAG216; + mf_ul_read->data.type = MfUltralightTypeNTAG216; mf_ul_read->pages_to_read = 231; mf_ul_read->support_fast_read = false; } else { @@ -41,7 +41,7 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) } void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) { - mf_ul_read->type = MfUltralightTypeUnknown; + mf_ul_read->data.type = MfUltralightTypeUnknown; mf_ul_read->pages_to_read = 16; mf_ul_read->support_fast_read = false; } @@ -148,26 +148,26 @@ void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) mf_ul_emulate->auth_data = NULL; mf_ul_emulate->data_changed = false; if(data->version.storage_size == 0) { - mf_ul_emulate->type = MfUltralightTypeUnknown; + mf_ul_emulate->data.type = MfUltralightTypeUnknown; mf_ul_emulate->support_fast_read = false; } else if(data->version.storage_size == 0x0B) { - mf_ul_emulate->type = MfUltralightTypeUL11; + mf_ul_emulate->data.type = MfUltralightTypeUL11; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x0E) { - mf_ul_emulate->type = MfUltralightTypeUL21; + mf_ul_emulate->data.type = MfUltralightTypeUL21; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x0F) { - mf_ul_emulate->type = MfUltralightTypeNTAG213; + mf_ul_emulate->data.type = MfUltralightTypeNTAG213; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x11) { - mf_ul_emulate->type = MfUltralightTypeNTAG215; + mf_ul_emulate->data.type = MfUltralightTypeNTAG215; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x13) { - mf_ul_emulate->type = MfUltralightTypeNTAG216; + mf_ul_emulate->data.type = MfUltralightTypeNTAG216; mf_ul_emulate->support_fast_read = true; } - if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { uint16_t pwd_page = (data->data_size / 4) - 2; mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4]; } @@ -178,7 +178,7 @@ void mf_ul_protect_auth_data_on_read_command( uint8_t start_page, uint8_t end_page, MifareUlDevice* mf_ul_emulate) { - if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2; uint8_t pack_page = pwd_page + 1; if((start_page <= pwd_page) && (end_page >= pwd_page)) { @@ -193,27 +193,43 @@ void mf_ul_protect_auth_data_on_read_command( 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; + uint16_t tx_bytes = 0; + uint16_t tx_bits = 0; + bool command_parsed = false; - 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); + // Check composite commands + if(mf_ul_emulate->comp_write_cmd_started) { + // Compatibility write is the only one composit command + if(len_rx == 16) { + memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4); + mf_ul_emulate->data_changed = true; + // Send ACK message + buff_tx[0] = 0x0A; + tx_bits = 4; + command_parsed = true; + } + mf_ul_emulate->comp_write_cmd_started = false; + } else if(cmd == MF_UL_GET_VERSION_CMD) { + if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) { + tx_bytes = sizeof(mf_ul_emulate->data.version); + memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes); + command_parsed = true; } } else if(cmd == MF_UL_READ_CMD) { uint8_t start_page = buff_rx[1]; if(start_page < page_num) { - tx_len = 16; + tx_bytes = 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); + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); } mf_ul_protect_auth_data_on_read_command( buff_tx, start_page, (start_page + 4), mf_ul_emulate); + command_parsed = true; } } else if(cmd == MF_UL_FAST_READ_CMD) { if(mf_ul_emulate->support_fast_read) { @@ -221,14 +237,11 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin uint8_t end_page = buff_rx[2]; if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) { - tx_len = ((end_page + 1) - start_page) * 4; - memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); + tx_bytes = ((end_page + 1) - start_page) * 4; + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); mf_ul_protect_auth_data_on_read_command( buff_tx, start_page, end_page, mf_ul_emulate); - } else { - // TODO make 4-bit NAK - buff_tx[0] = 0x0; - tx_len = 1; + command_parsed = true; } } } else if(cmd == MF_UL_WRITE) { @@ -236,9 +249,20 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin 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 + // ACK buff_tx[0] = 0x0A; - tx_len = 1; + tx_bits = 4; + command_parsed = true; + } + } else if(cmd == MF_UL_COMP_WRITE) { + uint8_t write_page = buff_rx[1]; + if((write_page > 1) && (write_page < page_num - 2)) { + mf_ul_emulate->comp_write_cmd_started = true; + mf_ul_emulate->comp_write_page_addr = write_page; + // ACK + buff_tx[0] = 0x0A; + tx_bits = 4; + command_parsed = true; } } else if(cmd == MF_UL_READ_CNT) { uint8_t cnt_num = buff_rx[1]; @@ -246,7 +270,8 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin 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; + tx_bytes = 3; + command_parsed = true; } } else if(cmd == MF_UL_INC_CNT) { uint8_t cnt_num = buff_rx[1]; @@ -254,38 +279,52 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin 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 + // ACK buff_tx[0] = 0x0A; - tx_len = 1; + tx_bits = 4; + command_parsed = true; } } else if(cmd == MF_UL_AUTH) { - if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) { buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0]; buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; - tx_len = 2; + tx_bytes = 2; + command_parsed = true; } else if(!mf_ul_emulate->auth_data->pack.value) { buff_tx[0] = 0x80; buff_tx[1] = 0x80; - tx_len = 2; - } else { - // TODO make 4-bit NAK - buff_tx[0] = 0x0; - tx_len = 1; + tx_bytes = 2; + command_parsed = true; } } } 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); + tx_bytes = sizeof(mf_ul_emulate->data.signature); + memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes); + command_parsed = true; } } 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; + tx_bytes = 1; + command_parsed = true; } + } else if(cmd == MF_UL_HALT_START) { + tx_bits = 0; + command_parsed = true; } - return tx_len; + + if(!command_parsed) { + // Send NACK + buff_tx[0] = 0x00; + tx_bits = 4; + } + // Return tx buffer size in bits + if(tx_bytes) { + tx_bits = tx_bytes * 8; + } + return tx_bits; } diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 386850c82..6b8ec6ee4 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -8,6 +8,7 @@ #define MF_UL_TEARING_FLAG_DEFAULT (0xBD) +#define MF_UL_HALT_START (0x50) #define MF_UL_GET_VERSION_CMD (0x60) #define MF_UL_READ_CMD (0x30) #define MF_UL_FAST_READ_CMD (0x3A) @@ -28,6 +29,9 @@ typedef enum { MfUltralightTypeNTAG213, MfUltralightTypeNTAG215, MfUltralightTypeNTAG216, + + // Keep last for number of types calculation + MfUltralightTypeNum, } MfUltralightType; typedef struct { @@ -52,6 +56,7 @@ typedef struct { } MfUltralightManufacturerBlock; typedef struct { + MfUltralightType type; MfUltralightVersion version; uint8_t signature[32]; uint32_t counter[3]; @@ -69,13 +74,14 @@ typedef struct { } MifareUlAuthData; typedef struct { - MfUltralightType type; uint8_t pages_to_read; uint8_t pages_readed; bool support_fast_read; bool data_changed; MifareUlData data; MifareUlAuthData* auth_data; + bool comp_write_cmd_started; + uint8_t comp_write_page_addr; } MifareUlDevice; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);