 d92b0a82cc
			
		
	
	
		d92b0a82cc
		
			
		
	
	
	
	
		
			
			"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.
		
			
				
	
	
		
			264 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			264 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;
 | |
| }
 |