Refactor CC parsing and dumping

This commit is contained in:
Willy-JL
2025-03-15 03:08:24 +00:00
parent b05a735e8f
commit 384f365cff
4 changed files with 93 additions and 74 deletions
@@ -1,5 +1,7 @@
#include "type_4_tag_i.h"
#include <bit_lib/bit_lib.h>
#define TAG "Type4Tag"
#define TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY "NDEF Data Size"
@@ -20,6 +22,88 @@ Type4TagError type_4_tag_process_error(Iso14443_4aError error) {
}
}
void type_4_tag_cc_dump(const Type4TagData* data, uint8_t* buf, size_t len) {
furi_check(len >= TYPE_4_TAG_T4T_CC_MIN_SIZE);
Type4TagCc* cc = (Type4TagCc*)buf;
bit_lib_num_to_bytes_be(TYPE_4_TAG_T4T_CC_MIN_SIZE, sizeof(cc->len), (void*)&cc->len);
cc->t4t_vno = TYPE_4_TAG_T4T_CC_VNO;
bit_lib_num_to_bytes_be(
data->is_tag_specific ? MIN(data->chunk_max_read, TYPE_4_TAG_CHUNK_LEN) :
TYPE_4_TAG_CHUNK_LEN,
sizeof(cc->mle),
(void*)&cc->mle);
bit_lib_num_to_bytes_be(
data->is_tag_specific ? MIN(data->chunk_max_write, TYPE_4_TAG_CHUNK_LEN) :
TYPE_4_TAG_CHUNK_LEN,
sizeof(cc->mlc),
(void*)&cc->mlc);
cc->tlv[0].type = Type4TagCcTlvTypeNdefFileCtrl;
cc->tlv[0].len = sizeof(cc->tlv[0].value.ndef_file_ctrl);
bit_lib_num_to_bytes_be(
data->is_tag_specific ? data->ndef_file_id : TYPE_4_TAG_T4T_DEFAULT_FILE_ID,
sizeof(cc->tlv[0].value.ndef_file_ctrl.file_id),
(void*)&cc->tlv[0].value.ndef_file_ctrl.file_id);
bit_lib_num_to_bytes_be(
data->is_tag_specific ? data->ndef_max_len : TYPE_4_TAG_DEFAULT_SIZE,
sizeof(cc->tlv[0].value.ndef_file_ctrl.max_len),
(void*)&cc->tlv[0].value.ndef_file_ctrl.max_len);
cc->tlv[0].value.ndef_file_ctrl.read_perm =
data->is_tag_specific ? data->ndef_read_lock : TYPE_4_TAG_T4T_CC_RW_LOCK_NONE;
cc->tlv[0].value.ndef_file_ctrl.write_perm =
data->is_tag_specific ? data->ndef_write_lock : TYPE_4_TAG_T4T_CC_RW_LOCK_NONE;
}
Type4TagError type_4_tag_cc_parse(Type4TagData* data, const BitBuffer* buf) {
const size_t cc_len = bit_buffer_get_size_bytes(buf);
if(cc_len < TYPE_4_TAG_T4T_CC_MIN_SIZE) {
FURI_LOG_E(TAG, "Unsupported T4T version");
return Type4TagErrorWrongFormat;
}
const Type4TagCc* cc = (const Type4TagCc*)bit_buffer_get_data(buf);
if(cc->t4t_vno != TYPE_4_TAG_T4T_CC_VNO) {
FURI_LOG_E(TAG, "Unsupported T4T version");
return Type4TagErrorNotSupported;
}
const Type4TagCcTlv* tlv = cc->tlv;
const Type4TagCcTlvNdefFileCtrl* ndef_file_ctrl = NULL;
const void* end = MIN((void*)cc + cc->len, (void*)cc + cc_len);
while((void*)tlv < end) {
if(tlv->type == Type4TagCcTlvTypeNdefFileCtrl) {
ndef_file_ctrl = &tlv->value.ndef_file_ctrl;
break;
}
if(tlv->len < 0xFF) {
tlv = (void*)&tlv->value + tlv->len;
} else {
uint16_t len = bit_lib_bytes_to_num_be((void*)&tlv->len + 1, sizeof(uint16_t));
tlv = (void*)&tlv->value + sizeof(len) + len;
}
}
if(!ndef_file_ctrl) {
FURI_LOG_E(TAG, "No NDEF file ctrl TLV");
return Type4TagErrorWrongFormat;
}
data->t4t_version.value = cc->t4t_vno;
data->chunk_max_read = bit_lib_bytes_to_num_be((void*)&cc->mle, sizeof(cc->mle));
data->chunk_max_write = bit_lib_bytes_to_num_be((void*)&cc->mlc, sizeof(cc->mlc));
data->ndef_file_id =
bit_lib_bytes_to_num_be((void*)&ndef_file_ctrl->file_id, sizeof(ndef_file_ctrl->file_id));
data->ndef_max_len =
bit_lib_bytes_to_num_be((void*)&ndef_file_ctrl->max_len, sizeof(ndef_file_ctrl->max_len)) -
sizeof(uint16_t);
data->ndef_read_lock = ndef_file_ctrl->read_perm;
data->ndef_write_lock = ndef_file_ctrl->write_perm;
return Type4TagErrorNone;
}
bool type_4_tag_ndef_data_load(Type4TagData* data, FlipperFormat* ff) {
uint32_t ndef_data_size;
if(!flipper_format_read_uint32(ff, TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY, &ndef_data_size, 1)) {
@@ -34,6 +34,7 @@
#define TYPE_4_TAG_T4T_CC_VNO (0x20)
#define TYPE_4_TAG_T4T_DEFAULT_FILE_ID 0xE104
#define TYPE_4_TAG_T4T_CC_RW_LOCK_NONE 0x00
#define TYPE_4_TAG_T4T_CC_MIN_SIZE (sizeof(Type4TagCc) + sizeof(Type4TagCcTlv))
// 4a layer adds 1..3 byte prefix, 3a layer adds 2 byte suffix and has 256 byte buffer
#define TYPE_4_TAG_BUF_SIZE (256U - 3U - 2U)
@@ -77,6 +78,10 @@ typedef struct FURI_PACKED {
Type4TagError type_4_tag_process_error(Iso14443_4aError error);
void type_4_tag_cc_dump(const Type4TagData* data, uint8_t* buf, size_t len);
Type4TagError type_4_tag_cc_parse(Type4TagData* data, const BitBuffer* buf);
// Load internal Type4Tag structures
bool type_4_tag_ndef_data_load(Type4TagData* data, FlipperFormat* ff);
@@ -104,7 +104,7 @@ static Type4TagError type_4_tag_listener_iso_read(
}
if(instance->state == Type4TagListenerStateSelectedCapabilityContainer) {
uint8_t cc_buf[sizeof(Type4TagCc) + sizeof(Type4TagCcTlv)];
uint8_t cc_buf[TYPE_4_TAG_T4T_CC_MIN_SIZE];
if(offset >= sizeof(cc_buf)) {
bit_buffer_append_bytes(
instance->tx_buffer,
@@ -112,39 +112,7 @@ static Type4TagError type_4_tag_listener_iso_read(
sizeof(type_4_tag_offset_error_apdu));
return Type4TagErrorWrongFormat;
}
Type4TagCc* cc = (Type4TagCc*)cc_buf;
bit_lib_num_to_bytes_be(sizeof(cc_buf), sizeof(cc->len), (void*)&cc->len);
cc->t4t_vno = TYPE_4_TAG_T4T_CC_VNO;
bit_lib_num_to_bytes_be(
instance->data->is_tag_specific ?
MIN(instance->data->chunk_max_read, TYPE_4_TAG_CHUNK_LEN) :
TYPE_4_TAG_CHUNK_LEN,
sizeof(cc->mle),
(void*)&cc->mle);
bit_lib_num_to_bytes_be(
instance->data->is_tag_specific ?
MIN(instance->data->chunk_max_write, TYPE_4_TAG_CHUNK_LEN) :
TYPE_4_TAG_CHUNK_LEN,
sizeof(cc->mlc),
(void*)&cc->mlc);
cc->tlv[0].type = Type4TagCcTlvTypeNdefFileCtrl;
cc->tlv[0].len = sizeof(cc->tlv[0].value.ndef_file_ctrl);
bit_lib_num_to_bytes_be(
instance->data->is_tag_specific ? instance->data->ndef_file_id :
TYPE_4_TAG_T4T_DEFAULT_FILE_ID,
sizeof(cc->tlv[0].value.ndef_file_ctrl.file_id),
(void*)&cc->tlv[0].value.ndef_file_ctrl.file_id);
bit_lib_num_to_bytes_be(
instance->data->is_tag_specific ? instance->data->ndef_max_len :
TYPE_4_TAG_DEFAULT_SIZE,
sizeof(cc->tlv[0].value.ndef_file_ctrl.max_len),
(void*)&cc->tlv[0].value.ndef_file_ctrl.max_len);
cc->tlv[0].value.ndef_file_ctrl.read_perm = instance->data->is_tag_specific ?
instance->data->ndef_read_lock :
TYPE_4_TAG_T4T_CC_RW_LOCK_NONE;
cc->tlv[0].value.ndef_file_ctrl.write_perm = instance->data->is_tag_specific ?
instance->data->ndef_write_lock :
TYPE_4_TAG_T4T_CC_RW_LOCK_NONE;
type_4_tag_cc_dump(instance->data, cc_buf, sizeof(cc_buf));
bit_buffer_append_bytes(
instance->tx_buffer, cc_buf + offset, MIN(sizeof(cc_buf) - offset, le));
@@ -93,47 +93,9 @@ Type4TagError type_4_tag_poller_read_cc(Type4TagPoller* instance) {
error = type_4_tag_apdu_trx(instance, instance->tx_buffer, instance->rx_buffer);
if(error != Type4TagErrorNone) break;
const Type4TagCc* cc = (const Type4TagCc*)bit_buffer_get_data(instance->rx_buffer);
if(cc->t4t_vno != TYPE_4_TAG_T4T_CC_VNO) {
FURI_LOG_E(TAG, "Unsupported T4T version");
error = Type4TagErrorNotSupported;
break;
}
const Type4TagCcTlv* tlv = cc->tlv;
const Type4TagCcTlvNdefFileCtrl* ndef_file_ctrl = NULL;
while((void*)tlv < (void*)cc + cc->len) {
if(tlv->type == Type4TagCcTlvTypeNdefFileCtrl) {
ndef_file_ctrl = &tlv->value.ndef_file_ctrl;
break;
}
if(tlv->len < 0xFF) {
tlv = (void*)&tlv->value + tlv->len;
} else {
uint16_t len = bit_lib_bytes_to_num_be((void*)&tlv->len + 1, sizeof(uint16_t));
tlv = (void*)&tlv->value + sizeof(len) + len;
}
}
if(!ndef_file_ctrl) {
FURI_LOG_E(TAG, "No NDEF file ctrl TLV");
error = Type4TagErrorWrongFormat;
break;
}
error = type_4_tag_cc_parse(instance->data, instance->rx_buffer);
if(error != Type4TagErrorNone) break;
instance->data->is_tag_specific = true;
instance->data->t4t_version.value = cc->t4t_vno;
instance->data->chunk_max_read = bit_lib_bytes_to_num_be((void*)&cc->mle, sizeof(cc->mle));
instance->data->chunk_max_write =
bit_lib_bytes_to_num_be((void*)&cc->mlc, sizeof(cc->mlc));
instance->data->ndef_file_id = bit_lib_bytes_to_num_be(
(void*)&ndef_file_ctrl->file_id, sizeof(ndef_file_ctrl->file_id));
instance->data->ndef_max_len =
bit_lib_bytes_to_num_be(
(void*)&ndef_file_ctrl->max_len, sizeof(ndef_file_ctrl->max_len)) -
sizeof(uint16_t);
instance->data->ndef_read_lock = ndef_file_ctrl->read_perm;
instance->data->ndef_write_lock = ndef_file_ctrl->write_perm;
FURI_LOG_D(TAG, "Detected NDEF file ID 0x%04X", instance->data->ndef_file_id);
} while(false);