unleashed-firmware/lib/nfc/protocols/iso15693_3/iso15693_3_i.c
gornekich d92b0a82cc
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.

Starring:

- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer

Supporting roles:

- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance

Special thanks:

@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 12:08:09 +09:00

263 lines
8.2 KiB
C

#include "iso15693_3_i.h"
bool iso15693_3_error_response_parse(Iso15693_3Error* error, const BitBuffer* buf) {
furi_assert(error);
if(bit_buffer_get_size_bytes(buf) == 0) {
// YEET!
*error = Iso15693_3ErrorBufferEmpty;
return true;
}
typedef struct {
uint8_t flags;
uint8_t error;
} ErrorResponseLayout;
const ErrorResponseLayout* resp = (const ErrorResponseLayout*)bit_buffer_get_data(buf);
if((resp->flags & ISO15693_3_RESP_FLAG_ERROR) == 0) {
// No error flag is set, the data does not contain an error frame
return false;
} else if(bit_buffer_get_size_bytes(buf) < sizeof(ErrorResponseLayout)) {
// Error bit is set, but not enough data to determine the error
*error = Iso15693_3ErrorUnexpectedResponse;
return true;
} else if(
resp->error >= ISO15693_3_RESP_ERROR_CUSTOM_START &&
resp->error <= ISO15693_3_RESP_ERROR_CUSTOM_END) {
// Custom vendor-specific error, must be checked in the respective protocol implementation
*error = Iso15693_3ErrorCustom;
return true;
}
switch(resp->error) {
case ISO15693_3_RESP_ERROR_NOT_SUPPORTED:
case ISO15693_3_RESP_ERROR_OPTION:
*error = Iso15693_3ErrorNotSupported;
break;
case ISO15693_3_RESP_ERROR_FORMAT:
*error = Iso15693_3ErrorFormat;
break;
case ISO15693_3_RESP_ERROR_BLOCK_UNAVAILABLE:
case ISO15693_3_RESP_ERROR_BLOCK_ALREADY_LOCKED:
case ISO15693_3_RESP_ERROR_BLOCK_LOCKED:
case ISO15693_3_RESP_ERROR_BLOCK_WRITE:
case ISO15693_3_RESP_ERROR_BLOCK_LOCK:
*error = Iso15693_3ErrorInternal;
break;
case ISO15693_3_RESP_ERROR_UNKNOWN:
default:
*error = Iso15693_3ErrorUnknown;
}
return true;
}
Iso15693_3Error iso15693_3_inventory_response_parse(uint8_t* data, const BitBuffer* buf) {
furi_assert(data);
Iso15693_3Error ret = Iso15693_3ErrorNone;
do {
if(iso15693_3_error_response_parse(&ret, buf)) break;
typedef struct {
uint8_t flags;
uint8_t dsfid;
uint8_t uid[ISO15693_3_UID_SIZE];
} InventoryResponseLayout;
if(bit_buffer_get_size_bytes(buf) != sizeof(InventoryResponseLayout)) {
ret = Iso15693_3ErrorUnexpectedResponse;
break;
}
const InventoryResponseLayout* resp =
(const InventoryResponseLayout*)bit_buffer_get_data(buf);
// Reverse UID for backward compatibility
for(uint32_t i = 0; i < ISO15693_3_UID_SIZE; ++i) {
data[i] = resp->uid[ISO15693_3_UID_SIZE - i - 1];
}
} while(false);
return ret;
}
Iso15693_3Error
iso15693_3_system_info_response_parse(Iso15693_3SystemInfo* data, const BitBuffer* buf) {
furi_assert(data);
Iso15693_3Error ret = Iso15693_3ErrorNone;
do {
if(iso15693_3_error_response_parse(&ret, buf)) break;
typedef struct {
uint8_t flags;
uint8_t info_flags;
uint8_t uid[ISO15693_3_UID_SIZE];
uint8_t extra[];
} SystemInfoResponseLayout;
if(bit_buffer_get_size_bytes(buf) < sizeof(SystemInfoResponseLayout)) {
ret = Iso15693_3ErrorUnexpectedResponse;
break;
}
const SystemInfoResponseLayout* resp =
(const SystemInfoResponseLayout*)bit_buffer_get_data(buf);
const uint8_t* extra = resp->extra;
const size_t extra_size = (resp->info_flags & ISO15693_3_SYSINFO_FLAG_DSFID ? 1 : 0) +
(resp->info_flags & ISO15693_3_SYSINFO_FLAG_AFI ? 1 : 0) +
(resp->info_flags & ISO15693_3_SYSINFO_FLAG_MEMORY ? 2 : 0) +
(resp->info_flags & ISO15693_3_SYSINFO_FLAG_IC_REF ? 1 : 0);
if(extra_size != bit_buffer_get_size_bytes(buf) - sizeof(SystemInfoResponseLayout)) {
ret = Iso15693_3ErrorUnexpectedResponse;
break;
}
data->flags = resp->info_flags;
if(data->flags & ISO15693_3_SYSINFO_FLAG_DSFID) {
data->dsfid = *extra++;
}
if(data->flags & ISO15693_3_SYSINFO_FLAG_AFI) {
data->afi = *extra++;
}
if(data->flags & ISO15693_3_SYSINFO_FLAG_MEMORY) {
// Add 1 to get actual values
data->block_count = *extra++ + 1;
data->block_size = (*extra++ & 0x1F) + 1;
}
if(data->flags & ISO15693_3_SYSINFO_FLAG_IC_REF) {
data->ic_ref = *extra;
}
} while(false);
return ret;
}
Iso15693_3Error
iso15693_3_read_block_response_parse(uint8_t* data, uint8_t block_size, const BitBuffer* buf) {
furi_assert(data);
Iso15693_3Error ret = Iso15693_3ErrorNone;
do {
if(iso15693_3_error_response_parse(&ret, buf)) break;
typedef struct {
uint8_t flags;
uint8_t block_data[];
} ReadBlockResponseLayout;
const size_t buf_size = bit_buffer_get_size_bytes(buf);
const size_t received_block_size = buf_size - sizeof(ReadBlockResponseLayout);
if(buf_size <= sizeof(ReadBlockResponseLayout) || received_block_size != block_size) {
ret = Iso15693_3ErrorUnexpectedResponse;
break;
}
const ReadBlockResponseLayout* resp =
(const ReadBlockResponseLayout*)bit_buffer_get_data(buf);
memcpy(data, resp->block_data, received_block_size);
} while(false);
return ret;
}
Iso15693_3Error iso15693_3_get_block_security_response_parse(
uint8_t* data,
uint16_t block_count,
const BitBuffer* buf) {
furi_assert(data);
furi_assert(block_count);
Iso15693_3Error ret = Iso15693_3ErrorNone;
do {
if(iso15693_3_error_response_parse(&ret, buf)) break;
typedef struct {
uint8_t flags;
uint8_t block_security[];
} GetBlockSecurityResponseLayout;
const size_t buf_size = bit_buffer_get_size_bytes(buf);
const size_t received_block_count = buf_size - sizeof(GetBlockSecurityResponseLayout);
if(buf_size <= sizeof(GetBlockSecurityResponseLayout) ||
received_block_count != block_count) {
ret = Iso15693_3ErrorUnexpectedResponse;
break;
}
const GetBlockSecurityResponseLayout* resp =
(const GetBlockSecurityResponseLayout*)bit_buffer_get_data(buf);
memcpy(data, resp->block_security, received_block_count);
} while(false);
return ret;
}
void iso15693_3_append_uid(const Iso15693_3Data* data, BitBuffer* buf) {
for(size_t i = 0; i < ISO15693_3_UID_SIZE; ++i) {
// Reverse the UID
bit_buffer_append_byte(buf, data->uid[ISO15693_3_UID_SIZE - i - 1]);
}
}
void iso15693_3_append_block(const Iso15693_3Data* data, uint8_t block_num, BitBuffer* buf) {
furi_assert(block_num < data->system_info.block_count);
const uint32_t block_offset = block_num * data->system_info.block_size;
const uint8_t* block_data = simple_array_cget(data->block_data, block_offset);
bit_buffer_append_bytes(buf, block_data, data->system_info.block_size);
}
void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_index, bool locked) {
furi_assert(data);
furi_assert(block_index < data->system_info.block_count);
*(uint8_t*)simple_array_get(data->block_security, block_index) = locked ? 1 : 0;
}
void iso15693_3_set_block_data(
Iso15693_3Data* data,
uint8_t block_num,
const uint8_t* block_data,
size_t block_data_size) {
furi_assert(block_num < data->system_info.block_count);
furi_assert(block_data_size == data->system_info.block_size);
const uint32_t block_offset = block_num * data->system_info.block_size;
uint8_t* block = simple_array_get(data->block_data, block_offset);
memcpy(block, block_data, block_data_size);
}
void iso15693_3_append_block_security(
const Iso15693_3Data* data,
uint8_t block_num,
BitBuffer* buf) {
bit_buffer_append_byte(buf, *(uint8_t*)simple_array_cget(data->block_security, block_num));
}
bool iso15693_3_is_equal_uid(const Iso15693_3Data* data, const uint8_t* uid) {
for(size_t i = 0; i < ISO15693_3_UID_SIZE; ++i) {
if(data->uid[i] != uid[ISO15693_3_UID_SIZE - i - 1]) return false;
}
return true;
}