[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
This commit is contained in:
		
							parent
							
								
									439fb9c18d
								
							
						
					
					
						commit
						b0f582df99
					
				| @ -1,4 +1,5 @@ | ||||
| #include "nfc_device.h" | ||||
| #include "nfc_types.h" | ||||
| 
 | ||||
| #include <lib/toolbox/path.h> | ||||
| #include <lib/flipper_file/flipper_file.h> | ||||
| @ -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,15 +41,21 @@ 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")) { | ||||
|     } | ||||
|     // 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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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"; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										13
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										13
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -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; | ||||
|                     } | ||||
|  | ||||
| @ -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"); | ||||
|  | ||||
| @ -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"); | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
| /*! 
 | ||||
|  ***************************************************************************** | ||||
|  | ||||
| @ -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    */ | ||||
|  | ||||
| @ -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 ); | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich