mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-19 04:44:47 -07:00
NFC: Refactor common NXP Native command handling
This commit is contained in:
115
lib/nfc/helpers/nxp_native_command.c
Normal file
115
lib/nfc/helpers/nxp_native_command.c
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include "nxp_native_command.h"
|
||||||
|
|
||||||
|
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h>
|
||||||
|
|
||||||
|
#define TAG "NxpNativeCommand"
|
||||||
|
|
||||||
|
Iso14443_4aError nxp_native_command_iso14443_4a_poller(
|
||||||
|
Iso14443_4aPoller* iso14443_4a_poller,
|
||||||
|
NxpNativeCommandStatus* status_code,
|
||||||
|
const BitBuffer* input_buffer,
|
||||||
|
BitBuffer* result_buffer,
|
||||||
|
NxpNativeCommandMode command_mode,
|
||||||
|
BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer) {
|
||||||
|
furi_check(iso14443_4a_poller);
|
||||||
|
furi_check(tx_buffer);
|
||||||
|
furi_check(rx_buffer);
|
||||||
|
furi_check(input_buffer);
|
||||||
|
furi_check(result_buffer);
|
||||||
|
furi_check(command_mode < NxpNativeCommandModeMAX);
|
||||||
|
|
||||||
|
Iso14443_4aError error = Iso14443_4aErrorNone;
|
||||||
|
*status_code = NXP_NATIVE_COMMAND_STATUS_OPERATION_OK;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bit_buffer_reset(tx_buffer);
|
||||||
|
if(command_mode == NxpNativeCommandModePlain) {
|
||||||
|
bit_buffer_append(tx_buffer, input_buffer);
|
||||||
|
} else if(command_mode == NxpNativeCommandModeIsoWrapped) {
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_CLA);
|
||||||
|
bit_buffer_append_byte(tx_buffer, bit_buffer_get_byte(input_buffer, 0));
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_P1);
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_P2);
|
||||||
|
if(bit_buffer_get_size_bytes(input_buffer) > 1) {
|
||||||
|
bit_buffer_append_byte(tx_buffer, bit_buffer_get_size_bytes(input_buffer) - 1);
|
||||||
|
bit_buffer_append_right(tx_buffer, input_buffer, 1);
|
||||||
|
}
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_LE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_buffer_reset(rx_buffer);
|
||||||
|
error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
|
||||||
|
|
||||||
|
if(error != Iso14443_4aErrorNone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_buffer_reset(tx_buffer);
|
||||||
|
if(command_mode == NxpNativeCommandModePlain) {
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_STATUS_ADDITIONAL_FRAME);
|
||||||
|
} else if(command_mode == NxpNativeCommandModeIsoWrapped) {
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_CLA);
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_STATUS_ADDITIONAL_FRAME);
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_P1);
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_P2);
|
||||||
|
bit_buffer_append_byte(tx_buffer, NXP_NATIVE_COMMAND_ISO_LE);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t response_len = bit_buffer_get_size_bytes(rx_buffer);
|
||||||
|
*status_code = NXP_NATIVE_COMMAND_STATUS_LENGTH_ERROR;
|
||||||
|
bit_buffer_reset(result_buffer);
|
||||||
|
if(command_mode == NxpNativeCommandModePlain && response_len >= sizeof(uint8_t)) {
|
||||||
|
*status_code = bit_buffer_get_byte(rx_buffer, 0);
|
||||||
|
if(response_len > sizeof(uint8_t)) {
|
||||||
|
bit_buffer_copy_right(result_buffer, rx_buffer, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
} else if(
|
||||||
|
command_mode == NxpNativeCommandModeIsoWrapped &&
|
||||||
|
response_len >= 2 * sizeof(uint8_t) &&
|
||||||
|
bit_buffer_get_byte(rx_buffer, response_len - 2) == NXP_NATIVE_COMMAND_ISO_SW1) {
|
||||||
|
*status_code = bit_buffer_get_byte(rx_buffer, response_len - 1);
|
||||||
|
if(response_len > 2 * sizeof(uint8_t)) {
|
||||||
|
bit_buffer_copy_left(result_buffer, rx_buffer, response_len - 2 * sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(*status_code == NXP_NATIVE_COMMAND_STATUS_ADDITIONAL_FRAME) {
|
||||||
|
bit_buffer_reset(rx_buffer);
|
||||||
|
error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
|
||||||
|
|
||||||
|
if(error != Iso14443_4aErrorNone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t rx_size = bit_buffer_get_size_bytes(rx_buffer);
|
||||||
|
const size_t rx_capacity_remaining = bit_buffer_get_capacity_bytes(result_buffer) -
|
||||||
|
bit_buffer_get_size_bytes(result_buffer);
|
||||||
|
|
||||||
|
if(command_mode == NxpNativeCommandModePlain) {
|
||||||
|
*status_code = rx_size >= 1 ? bit_buffer_get_byte(rx_buffer, 0) :
|
||||||
|
NXP_NATIVE_COMMAND_STATUS_LENGTH_ERROR;
|
||||||
|
if(rx_size <= rx_capacity_remaining + 1) {
|
||||||
|
bit_buffer_append_right(result_buffer, rx_buffer, sizeof(uint8_t));
|
||||||
|
} else {
|
||||||
|
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1);
|
||||||
|
}
|
||||||
|
} else if(command_mode == NxpNativeCommandModeIsoWrapped) {
|
||||||
|
if(rx_size >= 2 &&
|
||||||
|
bit_buffer_get_byte(rx_buffer, rx_size - 2) == NXP_NATIVE_COMMAND_ISO_SW1) {
|
||||||
|
*status_code = bit_buffer_get_byte(rx_buffer, rx_size - 1);
|
||||||
|
} else {
|
||||||
|
*status_code = NXP_NATIVE_COMMAND_STATUS_LENGTH_ERROR;
|
||||||
|
}
|
||||||
|
if(rx_size <= rx_capacity_remaining + 2) {
|
||||||
|
bit_buffer_set_size_bytes(rx_buffer, rx_size - 2);
|
||||||
|
bit_buffer_append(result_buffer, rx_buffer);
|
||||||
|
} else {
|
||||||
|
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
92
lib/nfc/helpers/nxp_native_command.h
Normal file
92
lib/nfc/helpers/nxp_native_command.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "nxp_native_command_mode.h"
|
||||||
|
|
||||||
|
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
|
||||||
|
|
||||||
|
// ISO 7816 command wrapping
|
||||||
|
#define NXP_NATIVE_COMMAND_ISO_CLA (0x90)
|
||||||
|
#define NXP_NATIVE_COMMAND_ISO_P1 (0x00)
|
||||||
|
#define NXP_NATIVE_COMMAND_ISO_P2 (0x00)
|
||||||
|
#define NXP_NATIVE_COMMAND_ISO_LE (0x00)
|
||||||
|
// ISO 7816 status wrapping
|
||||||
|
#define NXP_NATIVE_COMMAND_ISO_SW1 (0x91)
|
||||||
|
|
||||||
|
// Successful operation
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_OPERATION_OK (0x00)
|
||||||
|
// No changes done to backup files, CommitTransaction / AbortTransaction not necessary
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_NO_CHANGES (0x0C)
|
||||||
|
// Insufficient NV-Memory to complete command
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_OUT_OF_EEPROM_ERROR (0x0E)
|
||||||
|
// Command code not supported
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_ILLEGAL_COMMAND_CODE (0x1C)
|
||||||
|
// CRC or MAC does not match data Padding bytes not valid
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_INTEGRITY_ERROR (0x1E)
|
||||||
|
// Invalid key number specified
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_NO_SUCH_KEY (0x40)
|
||||||
|
// Length of command string invalid
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_LENGTH_ERROR (0x7E)
|
||||||
|
// Current configuration / status does not allow the requested command
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_PERMISSION_DENIED (0x9D)
|
||||||
|
// Value of the parameter(s) invalid
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_PARAMETER_ERROR (0x9E)
|
||||||
|
// Requested AID not present on PICC
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_APPLICATION_NOT_FOUND (0xA0)
|
||||||
|
// Unrecoverable error within application, application will be disabled
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_APPL_INTEGRITY_ERROR (0xA1)
|
||||||
|
// Currently not allowed to authenticate. Keep trying until full delay is spent
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_STATUS_AUTHENTICATION_DELAY (0xAD)
|
||||||
|
// Current authentication status does not allow the requested command
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_AUTHENTICATION_ERROR (0xAE)
|
||||||
|
// Additional data frame is expected to be sent
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_ADDITIONAL_FRAME (0xAF)
|
||||||
|
// Attempt to read/write data from/to beyond the file's/record's limits
|
||||||
|
// Attempt to exceed the limits of a value file.
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_BOUNDARY_ERROR (0xBE)
|
||||||
|
// Unrecoverable error within PICC, PICC will be disabled
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_PICC_INTEGRITY_ERROR (0xC1)
|
||||||
|
// Previous Command was not fully completed. Not all Frames were requested or provided by the PCD
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_COMMAND_ABORTED (0xCA)
|
||||||
|
// PICC was disabled by an unrecoverable error
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_PICC_DISABLED_ERROR (0xCD)
|
||||||
|
// Number of Applications limited to 28, no additional CreateApplication possible
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_COUNT_ERROR (0xCE)
|
||||||
|
// Creation of file/application failed because file/application with same number already exists
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_DUBLICATE_ERROR (0xDE)
|
||||||
|
// Could not complete NV-write operation due to loss of power, internal backup/rollback mechanism activated
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_EEPROM_ERROR (0xEE)
|
||||||
|
// Specified file number does not exist
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_FILE_NOT_FOUND (0xF0)
|
||||||
|
// Unrecoverable error within file, file will be disabled
|
||||||
|
#define NXP_NATIVE_COMMAND_STATUS_FILE_INTEGRITY_ERROR (0xF1)
|
||||||
|
|
||||||
|
typedef uint8_t NxpNativeCommandStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive NXP Native Command chunks in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The result_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from input_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
* The tx_buffer and rx_buffer are used as working areas to handle individual
|
||||||
|
* command chunks and responses.
|
||||||
|
*
|
||||||
|
* @param[in, out] iso14443_4a_poller pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] status_code pointer to a status variable to hold the result of the operation.
|
||||||
|
* @param[in] input_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] result_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @param[in] command_mode what command formatting mode to use for the transaction.
|
||||||
|
* @param[in, out] tx_buffer pointer to the buffer for command construction.
|
||||||
|
* @param[in, out] rx_buffer pointer to the buffer for response handling.
|
||||||
|
* @return Iso14443_4aErrorNone and STATUS_OPERATION_OK on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError nxp_native_command_iso14443_4a_poller(
|
||||||
|
Iso14443_4aPoller* iso14443_4a_poller,
|
||||||
|
NxpNativeCommandStatus* status_code,
|
||||||
|
const BitBuffer* input_buffer,
|
||||||
|
BitBuffer* result_buffer,
|
||||||
|
NxpNativeCommandMode command_mode,
|
||||||
|
BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
11
lib/nfc/helpers/nxp_native_command_mode.h
Normal file
11
lib/nfc/helpers/nxp_native_command_mode.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible command modes.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NxpNativeCommandModePlain, /**< Plain native commands. */
|
||||||
|
NxpNativeCommandModeIsoWrapped, /**< ISO 7816-wrapped commands. */
|
||||||
|
|
||||||
|
NxpNativeCommandModeMAX,
|
||||||
|
} NxpNativeCommandMode;
|
||||||
@@ -2,63 +2,11 @@
|
|||||||
|
|
||||||
#include "mf_desfire.h"
|
#include "mf_desfire.h"
|
||||||
|
|
||||||
|
#include <nfc/helpers/nxp_native_command.h>
|
||||||
|
|
||||||
#define MF_DESFIRE_FFF_PICC_PREFIX "PICC"
|
#define MF_DESFIRE_FFF_PICC_PREFIX "PICC"
|
||||||
#define MF_DESFIRE_FFF_APP_PREFIX "Application"
|
#define MF_DESFIRE_FFF_APP_PREFIX "Application"
|
||||||
|
|
||||||
// ISO 7816 command wrapping
|
|
||||||
#define MF_DESFIRE_CMD_ISO_CLA (0x90)
|
|
||||||
#define MF_DESFIRE_CMD_ISO_P1 (0x00)
|
|
||||||
#define MF_DESFIRE_CMD_ISO_P2 (0x00)
|
|
||||||
#define MF_DESFIRE_CMD_ISO_LE (0x00)
|
|
||||||
// ISO 7816 status wrapping
|
|
||||||
#define MF_DESFIRE_STATUS_ISO_SW1 (0x91)
|
|
||||||
|
|
||||||
// Successful operation
|
|
||||||
#define MF_DESFIRE_STATUS_OPERATION_OK (0x00)
|
|
||||||
// No changes done to backup files, CommitTransaction / AbortTransaction not necessary
|
|
||||||
#define MF_DESFIRE_STATUS_NO_CHANGES (0x0C)
|
|
||||||
// Insufficient NV-Memory to complete command
|
|
||||||
#define MF_DESFIRE_STATUS_OUT_OF_EEPROM_ERROR (0x0E)
|
|
||||||
// Command code not supported
|
|
||||||
#define MF_DESFIRE_STATUS_ILLEGAL_COMMAND_CODE (0x1C)
|
|
||||||
// CRC or MAC does not match data Padding bytes not valid
|
|
||||||
#define MF_DESFIRE_STATUS_INTEGRITY_ERROR (0x1E)
|
|
||||||
// Invalid key number specified
|
|
||||||
#define MF_DESFIRE_STATUS_NO_SUCH_KEY (0x40)
|
|
||||||
// Length of command string invalid
|
|
||||||
#define MF_DESFIRE_STATUS_LENGTH_ERROR (0x7E)
|
|
||||||
// Current configuration / status does not allow the requested command
|
|
||||||
#define MF_DESFIRE_STATUS_PERMISSION_DENIED (0x9D)
|
|
||||||
// Value of the parameter(s) invalid
|
|
||||||
#define MF_DESFIRE_STATUS_PARAMETER_ERROR (0x9E)
|
|
||||||
// Requested AID not present on PICC
|
|
||||||
#define MF_DESFIRE_STATUS_APPLICATION_NOT_FOUND (0xA0)
|
|
||||||
// Unrecoverable error within application, application will be disabled
|
|
||||||
#define MF_DESFIRE_STATUS_APPL_INTEGRITY_ERROR (0xA1)
|
|
||||||
// Current authentication status does not allow the requested command
|
|
||||||
#define MF_DESFIRE_STATUS_AUTHENTICATION_ERROR (0xAE)
|
|
||||||
// Additional data frame is expected to be sent
|
|
||||||
#define MF_DESFIRE_STATUS_ADDITIONAL_FRAME (0xAF)
|
|
||||||
// Attempt to read/write data from/to beyond the file's/record's limits
|
|
||||||
// Attempt to exceed the limits of a value file.
|
|
||||||
#define MF_DESFIRE_STATUS_BOUNDARY_ERROR (0xBE)
|
|
||||||
// Unrecoverable error within PICC, PICC will be disabled
|
|
||||||
#define MF_DESFIRE_STATUS_PICC_INTEGRITY_ERROR (0xC1)
|
|
||||||
// Previous Command was not fully completed. Not all Frames were requested or provided by the PCD
|
|
||||||
#define MF_DESFIRE_STATUS_COMMAND_ABORTED (0xCA)
|
|
||||||
// PICC was disabled by an unrecoverable error
|
|
||||||
#define MF_DESFIRE_STATUS_PICC_DISABLED_ERROR (0xCD)
|
|
||||||
// Number of Applications limited to 28, no additional CreateApplication possible
|
|
||||||
#define MF_DESFIRE_STATUS_COUNT_ERROR (0xCE)
|
|
||||||
// Creation of file/application failed because file/application with same number already exists
|
|
||||||
#define MF_DESFIRE_STATUS_DUBLICATE_ERROR (0xDE)
|
|
||||||
// Could not complete NV-write operation due to loss of power, internal backup/rollback mechanism activated
|
|
||||||
#define MF_DESFIRE_STATUS_EEPROM_ERROR (0xEE)
|
|
||||||
// Specified file number does not exist
|
|
||||||
#define MF_DESFIRE_STATUS_FILE_NOT_FOUND (0xF0)
|
|
||||||
// Unrecoverable error within file, file will be disabled
|
|
||||||
#define MF_DESFIRE_STATUS_FILE_INTEGRITY_ERROR (0xF1)
|
|
||||||
|
|
||||||
// SimpleArray configurations
|
// SimpleArray configurations
|
||||||
|
|
||||||
extern const SimpleArrayConfig mf_desfire_key_version_array_config;
|
extern const SimpleArrayConfig mf_desfire_key_version_array_config;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "mf_desfire.h"
|
#include "mf_desfire.h"
|
||||||
|
|
||||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
|
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
|
||||||
|
#include <lib/nfc/helpers/nxp_native_command_mode.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -39,24 +40,14 @@ typedef struct {
|
|||||||
} MfDesfirePollerEvent;
|
} MfDesfirePollerEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enumeration of possible MfDesfire poller command modes.
|
* @brief Change command mode used in poller mode.
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
MfDesfirePollerCommandModeNative, /**< Native MfDesfire commands. */
|
|
||||||
MfDesfirePollerCommandModeIsoWrapped, /**< ISO 7816-wrapped commands. */
|
|
||||||
|
|
||||||
MfDesfirePollerCommandModeMAX,
|
|
||||||
} MfDesfirePollerCommandMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Change MfDesfire command mode used in poller mode.
|
|
||||||
*
|
*
|
||||||
* @param[in, out] instance pointer to the instance to affect.
|
* @param[in, out] instance pointer to the instance to affect.
|
||||||
* @param[in] command_mode command mode to use in further communication with the card.
|
* @param[in] command_mode command mode to use in further communication with the card.
|
||||||
*/
|
*/
|
||||||
void mf_desfire_poller_set_command_mode(
|
void mf_desfire_poller_set_command_mode(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
MfDesfirePollerCommandMode command_mode);
|
NxpNativeCommandMode command_mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Transmit and receive MfDesfire chunks in poller mode.
|
* @brief Transmit and receive MfDesfire chunks in poller mode.
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ MfDesfireError mf_desfire_process_error(Iso14443_4aError error) {
|
|||||||
|
|
||||||
MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
|
MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
|
||||||
switch(status_code) {
|
switch(status_code) {
|
||||||
case MF_DESFIRE_STATUS_OPERATION_OK:
|
case NXP_NATIVE_COMMAND_STATUS_OPERATION_OK:
|
||||||
return MfDesfireErrorNone;
|
return MfDesfireErrorNone;
|
||||||
case MF_DESFIRE_STATUS_AUTHENTICATION_ERROR:
|
case NXP_NATIVE_COMMAND_STATUS_AUTHENTICATION_ERROR:
|
||||||
return MfDesfireErrorAuthentication;
|
return MfDesfireErrorAuthentication;
|
||||||
case MF_DESFIRE_STATUS_ILLEGAL_COMMAND_CODE:
|
case NXP_NATIVE_COMMAND_STATUS_ILLEGAL_COMMAND_CODE:
|
||||||
return MfDesfireErrorCommandNotSupported;
|
return MfDesfireErrorCommandNotSupported;
|
||||||
default:
|
default:
|
||||||
return MfDesfireErrorProtocol;
|
return MfDesfireErrorProtocol;
|
||||||
@@ -35,10 +35,10 @@ MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
|
|||||||
|
|
||||||
void mf_desfire_poller_set_command_mode(
|
void mf_desfire_poller_set_command_mode(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
MfDesfirePollerCommandMode command_mode) {
|
NxpNativeCommandMode command_mode) {
|
||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
furi_check(instance->state == MfDesfirePollerStateIdle);
|
furi_check(instance->state == MfDesfirePollerStateIdle);
|
||||||
furi_check(command_mode < MfDesfirePollerCommandModeMAX);
|
furi_check(command_mode < NxpNativeCommandModeMAX);
|
||||||
|
|
||||||
instance->command_mode = command_mode;
|
instance->command_mode = command_mode;
|
||||||
}
|
}
|
||||||
@@ -48,111 +48,22 @@ MfDesfireError mf_desfire_poller_send_chunks(
|
|||||||
const BitBuffer* tx_buffer,
|
const BitBuffer* tx_buffer,
|
||||||
BitBuffer* rx_buffer) {
|
BitBuffer* rx_buffer) {
|
||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
furi_check(instance->iso14443_4a_poller);
|
|
||||||
furi_check(instance->tx_buffer);
|
|
||||||
furi_check(instance->rx_buffer);
|
|
||||||
furi_check(tx_buffer);
|
|
||||||
furi_check(rx_buffer);
|
|
||||||
|
|
||||||
MfDesfireError error = MfDesfireErrorNone;
|
NxpNativeCommandStatus status_code = NXP_NATIVE_COMMAND_STATUS_OPERATION_OK;
|
||||||
uint8_t status_code = MF_DESFIRE_STATUS_OPERATION_OK;
|
Iso14443_4aError iso14443_4a_error = nxp_native_command_iso14443_4a_poller(
|
||||||
|
instance->iso14443_4a_poller,
|
||||||
|
&status_code,
|
||||||
|
tx_buffer,
|
||||||
|
rx_buffer,
|
||||||
|
instance->command_mode,
|
||||||
|
instance->tx_buffer,
|
||||||
|
instance->rx_buffer);
|
||||||
|
|
||||||
do {
|
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
||||||
bit_buffer_reset(instance->tx_buffer);
|
return mf_desfire_process_error(iso14443_4a_error);
|
||||||
if(instance->command_mode == MfDesfirePollerCommandModeNative) {
|
|
||||||
bit_buffer_append(instance->tx_buffer, tx_buffer);
|
|
||||||
} else if(instance->command_mode == MfDesfirePollerCommandModeIsoWrapped) {
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_CLA);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, bit_buffer_get_byte(tx_buffer, 0));
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P1);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P2);
|
|
||||||
if(bit_buffer_get_size_bytes(tx_buffer) > 1) {
|
|
||||||
bit_buffer_append_byte(
|
|
||||||
instance->tx_buffer, bit_buffer_get_size_bytes(tx_buffer) - 1);
|
|
||||||
bit_buffer_append_right(instance->tx_buffer, tx_buffer, 1);
|
|
||||||
}
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_LE);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
|
|
||||||
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
|
|
||||||
|
|
||||||
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
|
||||||
error = mf_desfire_process_error(iso14443_4a_error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bit_buffer_reset(instance->tx_buffer);
|
|
||||||
if(instance->command_mode == MfDesfirePollerCommandModeNative) {
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME);
|
|
||||||
} else if(instance->command_mode == MfDesfirePollerCommandModeIsoWrapped) {
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_CLA);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P1);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P2);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_LE);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t response_len = bit_buffer_get_size_bytes(instance->rx_buffer);
|
|
||||||
status_code = MF_DESFIRE_STATUS_LENGTH_ERROR;
|
|
||||||
bit_buffer_reset(rx_buffer);
|
|
||||||
if(instance->command_mode == MfDesfirePollerCommandModeNative &&
|
|
||||||
response_len >= sizeof(uint8_t)) {
|
|
||||||
status_code = bit_buffer_get_byte(instance->rx_buffer, 0);
|
|
||||||
if(response_len > sizeof(uint8_t)) {
|
|
||||||
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
|
|
||||||
}
|
|
||||||
} else if(
|
|
||||||
instance->command_mode == MfDesfirePollerCommandModeIsoWrapped &&
|
|
||||||
response_len >= 2 * sizeof(uint8_t) &&
|
|
||||||
bit_buffer_get_byte(instance->rx_buffer, response_len - 2) ==
|
|
||||||
MF_DESFIRE_STATUS_ISO_SW1) {
|
|
||||||
status_code = bit_buffer_get_byte(instance->rx_buffer, response_len - 1);
|
|
||||||
if(response_len > 2 * sizeof(uint8_t)) {
|
|
||||||
bit_buffer_copy_left(
|
|
||||||
rx_buffer, instance->rx_buffer, response_len - 2 * sizeof(uint8_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(status_code == MF_DESFIRE_STATUS_ADDITIONAL_FRAME) {
|
|
||||||
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
|
|
||||||
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
|
|
||||||
|
|
||||||
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
|
||||||
error = mf_desfire_process_error(iso14443_4a_error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t rx_size = bit_buffer_get_size_bytes(instance->rx_buffer);
|
|
||||||
const size_t rx_capacity_remaining =
|
|
||||||
bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer);
|
|
||||||
|
|
||||||
if(instance->command_mode == MfDesfirePollerCommandModeNative) {
|
|
||||||
status_code = rx_size < 1 ? MF_DESFIRE_STATUS_LENGTH_ERROR :
|
|
||||||
bit_buffer_get_byte(instance->rx_buffer, 0);
|
|
||||||
if(rx_size <= rx_capacity_remaining + 1) {
|
|
||||||
bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
|
|
||||||
} else {
|
|
||||||
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1);
|
|
||||||
}
|
|
||||||
} else if(instance->command_mode == MfDesfirePollerCommandModeIsoWrapped) {
|
|
||||||
status_code = rx_size < 2 ? MF_DESFIRE_STATUS_LENGTH_ERROR :
|
|
||||||
bit_buffer_get_byte(instance->rx_buffer, rx_size - 1);
|
|
||||||
if(rx_size <= rx_capacity_remaining + 2) {
|
|
||||||
bit_buffer_set_size_bytes(instance->rx_buffer, rx_size - 2);
|
|
||||||
bit_buffer_append(rx_buffer, instance->rx_buffer);
|
|
||||||
} else {
|
|
||||||
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
if(error == MfDesfireErrorNone) {
|
|
||||||
error = mf_desfire_process_status_code(status_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return mf_desfire_process_status_code(status_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) {
|
MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ typedef enum {
|
|||||||
|
|
||||||
struct MfDesfirePoller {
|
struct MfDesfirePoller {
|
||||||
Iso14443_4aPoller* iso14443_4a_poller;
|
Iso14443_4aPoller* iso14443_4a_poller;
|
||||||
MfDesfirePollerCommandMode command_mode;
|
NxpNativeCommandMode command_mode;
|
||||||
MfDesfirePollerSessionState session_state;
|
MfDesfirePollerSessionState session_state;
|
||||||
MfDesfirePollerState state;
|
MfDesfirePollerState state;
|
||||||
MfDesfireError error;
|
MfDesfireError error;
|
||||||
|
|||||||
@@ -238,22 +238,10 @@ MfPlusError
|
|||||||
}
|
}
|
||||||
|
|
||||||
MfPlusError mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
|
MfPlusError mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
|
||||||
bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
|
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
|
||||||
|
|
||||||
if(can_parse) {
|
if(can_parse) {
|
||||||
bit_buffer_write_bytes(buf, data, sizeof(MfPlusVersion));
|
bit_buffer_write_bytes(buf, data, sizeof(MfPlusVersion));
|
||||||
} else if(
|
|
||||||
bit_buffer_get_size_bytes(buf) == 8 &&
|
|
||||||
bit_buffer_get_byte(buf, 0) == MF_PLUS_STATUS_ADDITIONAL_FRAME) {
|
|
||||||
// HACK(-nofl): There are supposed to be three parts to the GetVersion command,
|
|
||||||
// with the second and third parts fetched by sending the AdditionalFrame
|
|
||||||
// command. I don't know whether the entire MIFARE Plus line uses status as
|
|
||||||
// the first byte, so let's just assume we only have the first part of
|
|
||||||
// the response if it's size 8 and starts with the AF status. The second
|
|
||||||
// part of the response is the same size and status byte, but so far
|
|
||||||
// we're only reading one response.
|
|
||||||
can_parse = true;
|
|
||||||
bit_buffer_write_bytes_mid(buf, data, 1, bit_buffer_get_size_bytes(buf) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return can_parse ? MfPlusErrorNone : MfPlusErrorProtocol;
|
return can_parse ? MfPlusErrorNone : MfPlusErrorProtocol;
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
#include "mf_plus.h"
|
#include "mf_plus.h"
|
||||||
|
|
||||||
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
|
#include <nfc/helpers/nxp_native_command.h>
|
||||||
|
|
||||||
#define MF_PLUS_STATUS_OPERATION_OK (0x90)
|
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
|
||||||
#define MF_PLUS_STATUS_ADDITIONAL_FRAME (0xAF)
|
|
||||||
|
|
||||||
MfPlusError mf_plus_get_type_from_version(
|
MfPlusError mf_plus_get_type_from_version(
|
||||||
const Iso14443_4aData* iso14443_4a_data,
|
const Iso14443_4aData* iso14443_4a_data,
|
||||||
|
|||||||
@@ -19,28 +19,36 @@ MfPlusError mf_plus_process_error(Iso14443_4aError error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MfPlusError mf_plus_poller_send_chunk(
|
MfPlusError mf_plus_process_status_code(uint8_t status_code) {
|
||||||
|
switch(status_code) {
|
||||||
|
case NXP_NATIVE_COMMAND_STATUS_OPERATION_OK:
|
||||||
|
return MfPlusErrorNone;
|
||||||
|
default:
|
||||||
|
return MfPlusErrorProtocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MfPlusError mf_plus_poller_send_chunks(
|
||||||
MfPlusPoller* instance,
|
MfPlusPoller* instance,
|
||||||
const BitBuffer* tx_buffer,
|
const BitBuffer* tx_buffer,
|
||||||
BitBuffer* rx_buffer) {
|
BitBuffer* rx_buffer) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(instance->iso14443_4a_poller);
|
|
||||||
furi_assert(instance->tx_buffer);
|
|
||||||
furi_assert(instance->rx_buffer);
|
|
||||||
furi_assert(tx_buffer);
|
|
||||||
furi_assert(rx_buffer);
|
|
||||||
|
|
||||||
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
|
NxpNativeCommandStatus status_code = NXP_NATIVE_COMMAND_STATUS_OPERATION_OK;
|
||||||
instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer);
|
Iso14443_4aError iso14443_4a_error = nxp_native_command_iso14443_4a_poller(
|
||||||
MfPlusError error = mf_plus_process_error(iso14443_4a_error);
|
instance->iso14443_4a_poller,
|
||||||
|
&status_code,
|
||||||
|
tx_buffer,
|
||||||
|
rx_buffer,
|
||||||
|
NxpNativeCommandModePlain,
|
||||||
|
instance->tx_buffer,
|
||||||
|
instance->rx_buffer);
|
||||||
|
|
||||||
if(error == MfPlusErrorNone) {
|
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
||||||
bit_buffer_copy(rx_buffer, instance->rx_buffer);
|
return mf_plus_process_error(iso14443_4a_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_buffer_reset(instance->tx_buffer);
|
return mf_plus_process_status_code(status_code);
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data) {
|
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data) {
|
||||||
@@ -50,7 +58,7 @@ MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* d
|
|||||||
bit_buffer_append_byte(instance->input_buffer, MF_PLUS_CMD_GET_VERSION);
|
bit_buffer_append_byte(instance->input_buffer, MF_PLUS_CMD_GET_VERSION);
|
||||||
|
|
||||||
MfPlusError error =
|
MfPlusError error =
|
||||||
mf_plus_poller_send_chunk(instance, instance->input_buffer, instance->result_buffer);
|
mf_plus_poller_send_chunks(instance, instance->input_buffer, instance->result_buffer);
|
||||||
if(error == MfPlusErrorNone) {
|
if(error == MfPlusErrorNone) {
|
||||||
error = mf_plus_version_parse(data, instance->result_buffer);
|
error = mf_plus_version_parse(data, instance->result_buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ typedef enum {
|
|||||||
Ntag4xxErrorNotPresent,
|
Ntag4xxErrorNotPresent,
|
||||||
Ntag4xxErrorProtocol,
|
Ntag4xxErrorProtocol,
|
||||||
Ntag4xxErrorTimeout,
|
Ntag4xxErrorTimeout,
|
||||||
Ntag4xxErrorAuthentication,
|
|
||||||
Ntag4xxErrorCommandNotSupported,
|
|
||||||
} Ntag4xxError;
|
} Ntag4xxError;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -21,12 +21,8 @@ Ntag4xxError ntag4xx_process_error(Iso14443_4aError error) {
|
|||||||
|
|
||||||
Ntag4xxError ntag4xx_process_status_code(uint8_t status_code) {
|
Ntag4xxError ntag4xx_process_status_code(uint8_t status_code) {
|
||||||
switch(status_code) {
|
switch(status_code) {
|
||||||
case NTAG4XX_STATUS_OPERATION_OK:
|
case NXP_NATIVE_COMMAND_STATUS_OPERATION_OK:
|
||||||
return Ntag4xxErrorNone;
|
return Ntag4xxErrorNone;
|
||||||
case NTAG4XX_STATUS_AUTHENTICATION_ERROR:
|
|
||||||
return Ntag4xxErrorAuthentication;
|
|
||||||
case NTAG4XX_STATUS_ILLEGAL_COMMAND_CODE:
|
|
||||||
return Ntag4xxErrorCommandNotSupported;
|
|
||||||
default:
|
default:
|
||||||
return Ntag4xxErrorProtocol;
|
return Ntag4xxErrorProtocol;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,44 +2,10 @@
|
|||||||
|
|
||||||
#include "ntag4xx.h"
|
#include "ntag4xx.h"
|
||||||
|
|
||||||
|
#include <nfc/helpers/nxp_native_command.h>
|
||||||
|
|
||||||
#define NTAG4XX_FFF_PICC_PREFIX "PICC"
|
#define NTAG4XX_FFF_PICC_PREFIX "PICC"
|
||||||
|
|
||||||
// ISO 7816 command wrapping
|
|
||||||
#define NTAG4XX_CMD_ISO_CLA (0x90)
|
|
||||||
#define NTAG4XX_CMD_ISO_P1 (0x00)
|
|
||||||
#define NTAG4XX_CMD_ISO_P2 (0x00)
|
|
||||||
#define NTAG4XX_CMD_ISO_LE (0x00)
|
|
||||||
// ISO 7816 status wrapping
|
|
||||||
#define NTAG4XX_STATUS_ISO_SW1 (0x91)
|
|
||||||
|
|
||||||
// Successful operation
|
|
||||||
#define NTAG4XX_STATUS_OPERATION_OK (0x00)
|
|
||||||
// Command code not supported
|
|
||||||
#define NTAG4XX_STATUS_ILLEGAL_COMMAND_CODE (0x1C)
|
|
||||||
// CRC or MAC does not match data Padding bytes not valid
|
|
||||||
#define NTAG4XX_STATUS_INTEGRITY_ERROR (0x1E)
|
|
||||||
// Invalid key number specified
|
|
||||||
#define NTAG4XX_STATUS_NO_SUCH_KEY (0x40)
|
|
||||||
// Length of command string invalid
|
|
||||||
#define NTAG4XX_STATUS_LENGTH_ERROR (0x7E)
|
|
||||||
// Current configuration / status does not allow the requested command
|
|
||||||
#define NTAG4XX_STATUS_PERMISSION_DENIED (0x9D)
|
|
||||||
// Value of the parameter(s) invalid
|
|
||||||
#define NTAG4XX_STATUS_PARAMETER_ERROR (0x9E)
|
|
||||||
// Currently not allowed to authenticate. Keep trying until full delay is spent
|
|
||||||
#define NTAG4XX_STATUS_AUTHENTICATION_DELAY (0xAD)
|
|
||||||
// Current authentication status does not allow the requested command
|
|
||||||
#define NTAG4XX_STATUS_AUTHENTICATION_ERROR (0xAE)
|
|
||||||
// Additional data frame is expected to be sent
|
|
||||||
#define NTAG4XX_STATUS_ADDITIONAL_FRAME (0xAF)
|
|
||||||
// Attempt to read/write data from/to beyond the file's/record's limits
|
|
||||||
// Attempt to exceed the limits of a value file.
|
|
||||||
#define NTAG4XX_STATUS_BOUNDARY_ERROR (0xBE)
|
|
||||||
// Previous Command was not fully completed. Not all Frames were requested or provided by the PCD
|
|
||||||
#define NTAG4XX_STATUS_COMMAND_ABORTED (0xCA)
|
|
||||||
// Specified file number does not exist
|
|
||||||
#define NTAG4XX_STATUS_FILE_NOT_FOUND (0xF0)
|
|
||||||
|
|
||||||
// Internal helpers
|
// Internal helpers
|
||||||
|
|
||||||
Ntag4xxError ntag4xx_process_error(Iso14443_4aError error);
|
Ntag4xxError ntag4xx_process_error(Iso14443_4aError error);
|
||||||
|
|||||||
@@ -11,83 +11,22 @@ Ntag4xxError ntag4xx_poller_send_chunks(
|
|||||||
const BitBuffer* tx_buffer,
|
const BitBuffer* tx_buffer,
|
||||||
BitBuffer* rx_buffer) {
|
BitBuffer* rx_buffer) {
|
||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
furi_check(instance->iso14443_4a_poller);
|
|
||||||
furi_check(instance->tx_buffer);
|
|
||||||
furi_check(instance->rx_buffer);
|
|
||||||
furi_check(tx_buffer);
|
|
||||||
furi_check(rx_buffer);
|
|
||||||
|
|
||||||
Ntag4xxError error = Ntag4xxErrorNone;
|
NxpNativeCommandStatus status_code = NXP_NATIVE_COMMAND_STATUS_OPERATION_OK;
|
||||||
uint8_t status_code = NTAG4XX_STATUS_OPERATION_OK;
|
Iso14443_4aError iso14443_4a_error = nxp_native_command_iso14443_4a_poller(
|
||||||
|
instance->iso14443_4a_poller,
|
||||||
|
&status_code,
|
||||||
|
tx_buffer,
|
||||||
|
rx_buffer,
|
||||||
|
NxpNativeCommandModeIsoWrapped,
|
||||||
|
instance->tx_buffer,
|
||||||
|
instance->rx_buffer);
|
||||||
|
|
||||||
do {
|
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
||||||
bit_buffer_reset(instance->tx_buffer);
|
return ntag4xx_process_error(iso14443_4a_error);
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_CLA);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, bit_buffer_get_byte(tx_buffer, 0));
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_P1);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_P2);
|
|
||||||
if(bit_buffer_get_size_bytes(tx_buffer) > 1) {
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, bit_buffer_get_size_bytes(tx_buffer) - 1);
|
|
||||||
bit_buffer_append_right(instance->tx_buffer, tx_buffer, 1);
|
|
||||||
}
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_LE);
|
|
||||||
|
|
||||||
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
|
|
||||||
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
|
|
||||||
|
|
||||||
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
|
||||||
error = ntag4xx_process_error(iso14443_4a_error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bit_buffer_reset(instance->tx_buffer);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_CLA);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_STATUS_ADDITIONAL_FRAME);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_P1);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_P2);
|
|
||||||
bit_buffer_append_byte(instance->tx_buffer, NTAG4XX_CMD_ISO_LE);
|
|
||||||
|
|
||||||
size_t response_len = bit_buffer_get_size_bytes(instance->rx_buffer);
|
|
||||||
status_code = NTAG4XX_STATUS_LENGTH_ERROR;
|
|
||||||
bit_buffer_reset(rx_buffer);
|
|
||||||
if(response_len >= 2 * sizeof(uint8_t) &&
|
|
||||||
bit_buffer_get_byte(instance->rx_buffer, response_len - 2) == NTAG4XX_STATUS_ISO_SW1) {
|
|
||||||
status_code = bit_buffer_get_byte(instance->rx_buffer, response_len - 1);
|
|
||||||
if(response_len > 2 * sizeof(uint8_t)) {
|
|
||||||
bit_buffer_copy_left(
|
|
||||||
rx_buffer, instance->rx_buffer, response_len - 2 * sizeof(uint8_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(status_code == NTAG4XX_STATUS_ADDITIONAL_FRAME) {
|
|
||||||
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
|
|
||||||
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
|
|
||||||
|
|
||||||
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
|
||||||
error = ntag4xx_process_error(iso14443_4a_error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t rx_size = bit_buffer_get_size_bytes(instance->rx_buffer);
|
|
||||||
const size_t rx_capacity_remaining =
|
|
||||||
bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer);
|
|
||||||
|
|
||||||
status_code = rx_size < 2 ? NTAG4XX_STATUS_LENGTH_ERROR :
|
|
||||||
bit_buffer_get_byte(instance->rx_buffer, rx_size - 1);
|
|
||||||
if(rx_size <= rx_capacity_remaining + 2) {
|
|
||||||
bit_buffer_set_size_bytes(instance->rx_buffer, rx_size - 2);
|
|
||||||
bit_buffer_append(rx_buffer, instance->rx_buffer);
|
|
||||||
} else {
|
|
||||||
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
if(error == Ntag4xxErrorNone) {
|
|
||||||
error = ntag4xx_process_status_code(status_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return ntag4xx_process_status_code(status_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ntag4xxError ntag4xx_poller_read_version(Ntag4xxPoller* instance, Ntag4xxVersion* data) {
|
Ntag4xxError ntag4xx_poller_read_version(Ntag4xxPoller* instance, Ntag4xxVersion* data) {
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ Type4TagError type_4_tag_poller_detect_platform(Type4TagPoller* instance) {
|
|||||||
|
|
||||||
FURI_LOG_D(TAG, "Detect DESFire");
|
FURI_LOG_D(TAG, "Detect DESFire");
|
||||||
MfDesfirePoller* mf_desfire = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
MfDesfirePoller* mf_desfire = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||||
mf_desfire_poller_set_command_mode(mf_desfire, MfDesfirePollerCommandModeIsoWrapped);
|
mf_desfire_poller_set_command_mode(mf_desfire, NxpNativeCommandModeIsoWrapped);
|
||||||
if(mf_desfire_poller.detect(event, mf_desfire)) {
|
if(mf_desfire_poller.detect(event, mf_desfire)) {
|
||||||
platform = Type4TagPlatformMfDesfire;
|
platform = Type4TagPlatformMfDesfire;
|
||||||
nfc_device_set_data(
|
nfc_device_set_data(
|
||||||
@@ -349,7 +349,7 @@ Type4TagError type_4_tag_poller_create_app(Type4TagPoller* instance) {
|
|||||||
|
|
||||||
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
||||||
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||||
mf_desfire_poller_set_command_mode(mf_des, MfDesfirePollerCommandModeIsoWrapped);
|
mf_desfire_poller_set_command_mode(mf_des, NxpNativeCommandModeIsoWrapped);
|
||||||
MfDesfireError mf_des_error;
|
MfDesfireError mf_des_error;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -392,7 +392,7 @@ Type4TagError type_4_tag_poller_create_cc(Type4TagPoller* instance) {
|
|||||||
|
|
||||||
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
||||||
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||||
mf_desfire_poller_set_command_mode(mf_des, MfDesfirePollerCommandModeIsoWrapped);
|
mf_desfire_poller_set_command_mode(mf_des, NxpNativeCommandModeIsoWrapped);
|
||||||
MfDesfireError mf_des_error;
|
MfDesfireError mf_des_error;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -441,7 +441,7 @@ Type4TagError type_4_tag_poller_create_ndef(Type4TagPoller* instance) {
|
|||||||
|
|
||||||
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
||||||
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||||
mf_desfire_poller_set_command_mode(mf_des, MfDesfirePollerCommandModeIsoWrapped);
|
mf_desfire_poller_set_command_mode(mf_des, NxpNativeCommandModeIsoWrapped);
|
||||||
MfDesfireError mf_des_error;
|
MfDesfireError mf_des_error;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|||||||
@@ -2657,7 +2657,7 @@ Function,+,mf_desfire_poller_read_key_versions,MfDesfireError,"MfDesfirePoller*,
|
|||||||
Function,+,mf_desfire_poller_read_version,MfDesfireError,"MfDesfirePoller*, MfDesfireVersion*"
|
Function,+,mf_desfire_poller_read_version,MfDesfireError,"MfDesfirePoller*, MfDesfireVersion*"
|
||||||
Function,+,mf_desfire_poller_select_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*"
|
Function,+,mf_desfire_poller_select_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*"
|
||||||
Function,+,mf_desfire_poller_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*"
|
Function,+,mf_desfire_poller_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*"
|
||||||
Function,+,mf_desfire_poller_set_command_mode,void,"MfDesfirePoller*, MfDesfirePollerCommandMode"
|
Function,+,mf_desfire_poller_set_command_mode,void,"MfDesfirePoller*, NxpNativeCommandMode"
|
||||||
Function,+,mf_desfire_reset,void,MfDesfireData*
|
Function,+,mf_desfire_reset,void,MfDesfireData*
|
||||||
Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*"
|
Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*"
|
||||||
Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t"
|
Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t"
|
||||||
|
|||||||
|
Reference in New Issue
Block a user