Array use refactor

Move all arrays to allocating actual data rather than pointers to simplify construction and destruction. Also moved to M_EACH for iterating over arrays for less boilerplate code.

Also did some function renaming for extra clarity.

root_area is now a node type for simplified area traversal (coming soon).
This commit is contained in:
dogtopus
2023-03-18 03:04:00 -03:00
parent a2cd122f78
commit 43341980cc
10 changed files with 323 additions and 181 deletions

View File

@@ -19,24 +19,24 @@ void nfc_scene_felica_info_select_on_enter(void* context) {
uint8_t i = 1;
if(state->selected_system == NULL || state->selected_system->code == LITE_SYSTEM_CODE) {
submenu_set_header(submenu, "Systems");
FelicaSystemList_it_t it;
for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it);
FelicaSystemList_next(it)) {
FelicaSystem* current_system = *FelicaSystemList_ref(it);
FuriString* system_name = felica_get_system_name(current_system);
submenu_add_item(
submenu,
furi_string_get_cstr(system_name),
i++,
nfc_scene_felica_info_select_submenu_callback,
nfc);
furi_string_free(system_name);
}
for
M_EACH(current_system, data->systems, FelicaSystemArray_t) {
FuriString* system_name = felica_get_system_name(current_system);
submenu_add_item(
submenu,
furi_string_get_cstr(system_name),
i++,
nfc_scene_felica_info_select_submenu_callback,
nfc);
furi_string_free(system_name);
}
} else {
FelicaSystem* system = state->selected_system;
FuriString* header = furi_string_alloc_printf("%04X/", system->code);
FelicaArea* area = &system->root_area;
FelicaNode* root = &system->root;
furi_assert(root->type == FelicaNodeTypeArea);
FelicaArea* area = root->area;
if(FelicaAreaPath_size(state->selected_areas) > 0) {
FelicaAreaPath_it_t it;
for(FelicaAreaPath_it(it, state->selected_areas); !FelicaAreaPath_end_p(it);
@@ -51,32 +51,30 @@ void nfc_scene_felica_info_select_on_enter(void* context) {
submenu_set_header(submenu, furi_string_get_cstr(header));
furi_string_free(header);
FelicaNodeList_it_t it;
for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it);
FelicaNodeList_next(it)) {
FelicaNode* node = *FelicaNodeList_ref(it);
FuriString* node_name = furi_string_alloc();
if(node->type == FelicaNodeTypeArea) {
furi_string_printf(node_name, "Area %d", node->area->number);
submenu_add_item(
submenu,
furi_string_get_cstr(node_name),
i++,
nfc_scene_felica_info_select_submenu_callback,
nfc);
} else {
uint16_t service_code = node->service->number << 6;
furi_string_printf(node_name, "Service %04X", service_code);
submenu_add_item(
submenu,
furi_string_get_cstr(node_name),
i++,
nfc_scene_felica_info_select_submenu_callback,
nfc);
}
for
M_EACH(node, area->nodes, FelicaNodeArray_t) {
FuriString* node_name = furi_string_alloc();
if(node->type == FelicaNodeTypeArea) {
furi_string_printf(node_name, "Area %d", node->area->number);
submenu_add_item(
submenu,
furi_string_get_cstr(node_name),
i++,
nfc_scene_felica_info_select_submenu_callback,
nfc);
} else {
uint16_t service_code = node->service->number << 6;
furi_string_printf(node_name, "Service %04X", service_code);
submenu_add_item(
submenu,
furi_string_get_cstr(node_name),
i++,
nfc_scene_felica_info_select_submenu_callback,
nfc);
}
furi_string_free(node_name);
}
furi_string_free(node_name);
}
}
state->selected_service = NULL;
@@ -102,7 +100,7 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even
index -= 1;
if(state->selected_system == NULL) {
state->selected_system = *FelicaSystemList_get(data->systems, index);
state->selected_system = FelicaSystemArray_get(data->systems, index);
if(state->selected_system->code == LITE_SYSTEM_CODE) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaServiceData);
} else {
@@ -111,12 +109,15 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even
consumed = true;
} else {
FelicaNode* selected_node = NULL;
FelicaNode* root = &(state->selected_system->root);
furi_assert(root->type == FelicaNodeTypeArea);
if(FelicaAreaPath_size(state->selected_areas) == 0) {
selected_node =
*FelicaNodeList_get(state->selected_system->root_area.nodes, index);
selected_node = FelicaNodeArray_get(root->area->nodes, index);
} else {
FelicaArea* current_area = *FelicaAreaPath_back(state->selected_areas);
selected_node = *FelicaNodeList_get(current_area->nodes, index);
selected_node = FelicaNodeArray_get(current_area->nodes, index);
}
if(selected_node->type == FelicaNodeTypeArea) {

View File

@@ -29,21 +29,19 @@ void nfc_scene_felica_read_success_on_enter(void* context) {
} else {
temp_str = furi_string_alloc_printf("\e#%s", nfc_felica_type(felica_data->type));
FelicaSystemList_it_t it;
for(FelicaSystemList_it(it, felica_data->systems); !FelicaSystemList_end_p(it);
FelicaSystemList_next(it)) {
FelicaSystem* current_system = *FelicaSystemList_ref(it);
furi_string_cat_printf(
temp_str, "\nSystem %04X (#%d):", current_system->code, current_system->number);
furi_string_cat_printf(temp_str, "\nIDm:\n ");
for(size_t i = 0; i < 8; i++) {
furi_string_cat_printf(temp_str, "%02X", current_system->idm[i]);
for
M_EACH(current_system, felica_data->systems, FelicaSystemArray_t) {
furi_string_cat_printf(
temp_str, "\nSystem %04X (#%d):", current_system->code, current_system->number);
furi_string_cat_printf(temp_str, "\nIDm:\n ");
for(size_t i = 0; i < 8; i++) {
furi_string_cat_printf(temp_str, "%02X", current_system->idm[i]);
}
furi_string_cat_printf(temp_str, "\nPMm:\n ");
for(size_t i = 0; i < 8; i++) {
furi_string_cat_printf(temp_str, "%02X", current_system->pmm[i]);
}
}
furi_string_cat_printf(temp_str, "\nPMm:\n ");
for(size_t i = 0; i < 8; i++) {
furi_string_cat_printf(temp_str, "%02X", current_system->pmm[i]);
}
}
}
widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));

View File

@@ -66,35 +66,35 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
nfc_data->f_data.pmm[0],
nfc_data->f_data.pmm[1]);
furi_string_cat_printf(temp_str, "Timings (1 node/blk):\n");
furi_string_cat_printf(temp_str, "MRT (1 node/blk):\n");
furi_string_cat_printf(
temp_str,
"- ReqSvc: %" PRIuLEAST32 "us\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[2], 1));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_VARIABLE_MRT], 1));
furi_string_cat_printf(
temp_str,
"- Fixed: %" PRIuLEAST32 "us\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[3], 0));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_FIXED_MRT], 0));
furi_string_cat_printf(
temp_str,
"- Auth1: %" PRIuLEAST32 "us\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[4], 1));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_MUTUAL_AUTH_MRT], 1));
furi_string_cat_printf(
temp_str,
"- Auth2: %" PRIuLEAST32 "us\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[4], 0));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_MUTUAL_AUTH_MRT], 0));
furi_string_cat_printf(
temp_str,
"- Read: %" PRIuLEAST32 "us\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[5], 1));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_READ_MRT], 1));
furi_string_cat_printf(
temp_str,
"- Write: %" PRIuLEAST32 "us\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[6], 1));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_WRITE_MRT], 1));
furi_string_cat_printf(
temp_str,
"- Other: %" PRIuLEAST32 "us\n\n",
felica_estimate_timing_us(nfc_data->f_data.pmm[7], 0));
felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_OTHER_MRT], 0));
furi_string_cat_printf(temp_str, "IDm:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {

View File

@@ -8,6 +8,7 @@ enum SubmenuIndex {
SubmenuIndexReadEMV,
SubmenuIndexReadNFCA,
SubmenuIndexReadFelica,
SubmenuIndexReadNFCF,
};
void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) {
@@ -56,6 +57,12 @@ void nfc_scene_read_card_type_on_enter(void* context) {
SubmenuIndexReadFelica,
nfc_scene_read_card_type_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Read NFC-F data",
SubmenuIndexReadNFCF,
nfc_scene_read_card_type_submenu_callback,
nfc);
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType);
submenu_set_selected_item(submenu, state);
@@ -97,6 +104,11 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
if(event.event == SubmenuIndexReadNFCF) {
nfc->dev->dev_data.read_mode = NfcReadModeNFCF;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event);
}
return consumed;

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,11.13,,
Version,+,11.14,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@@ -808,14 +808,15 @@ Function,-,felica_get_ic_type,FelicaICType,uint8_t*
Function,-,felica_get_service_name,FuriString*,FelicaService*
Function,-,felica_get_system_name,FuriString*,FelicaSystem*
Function,-,felica_lite_can_read_without_mac,_Bool,"uint8_t*, uint8_t"
Function,-,felica_lite_dump_data,_Bool,"FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*"
Function,-,felica_lite_prepare_unencrypted_read,uint8_t,"uint8_t*, const FelicaReader*, _Bool, const uint8_t*, uint8_t"
Function,-,felica_lite_prepare_unencrypted_write,uint8_t,"uint8_t*, const FelicaReader*, const uint8_t*, uint8_t, const uint8_t*"
Function,-,felica_parse_unencrypted_read,uint16_t,"uint8_t*, uint8_t, FelicaReader*, uint8_t*, uint16_t"
Function,-,felica_parse_unencrypted_write,_Bool,"uint8_t*, uint8_t, FelicaReader*"
Function,-,felica_prepare_unencrypted_read,uint8_t,"uint8_t*, const FelicaReader*, const uint16_t*, uint8_t, const uint32_t*, uint8_t"
Function,-,felica_prepare_unencrypted_write,uint8_t,"uint8_t*, FelicaReader*, const uint16_t*, uint8_t, const uint32_t*, uint8_t, const uint8_t*"
Function,-,felica_push_normal_block,void,"FelicaService*, uint8_t*"
Function,-,felica_read_card,_Bool,"FuriHalNfcTxRxContext*, FelicaData*, uint8_t*, uint8_t*"
Function,-,felica_read_lite_system,_Bool,"FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*"
Function,-,feof,int,FILE*
Function,-,feof_unlocked,int,FILE*
Function,-,ferror,int,FILE*
1 entry status name type params
2 Version + 11.13 11.14
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
808 Function - felica_get_service_name FuriString* FelicaService*
809 Function - felica_get_system_name FuriString* FelicaSystem*
810 Function - felica_lite_can_read_without_mac _Bool uint8_t*, uint8_t
811 Function - felica_lite_dump_data _Bool FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*
812 Function - felica_lite_prepare_unencrypted_read uint8_t uint8_t*, const FelicaReader*, _Bool, const uint8_t*, uint8_t
813 Function - felica_lite_prepare_unencrypted_write uint8_t uint8_t*, const FelicaReader*, const uint8_t*, uint8_t, const uint8_t*
814 Function - felica_parse_unencrypted_read uint16_t uint8_t*, uint8_t, FelicaReader*, uint8_t*, uint16_t
815 Function - felica_parse_unencrypted_write _Bool uint8_t*, uint8_t, FelicaReader*
816 Function - felica_prepare_unencrypted_read uint8_t uint8_t*, const FelicaReader*, const uint16_t*, uint8_t, const uint32_t*, uint8_t
817 Function - felica_prepare_unencrypted_write uint8_t uint8_t*, FelicaReader*, const uint16_t*, uint8_t, const uint32_t*, uint8_t, const uint8_t*
818 Function - felica_push_normal_block void FelicaService*, uint8_t*
819 Function - felica_read_card _Bool FuriHalNfcTxRxContext*, FelicaData*, uint8_t*, uint8_t*
Function - felica_read_lite_system _Bool FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*
820 Function - feof int FILE*
821 Function - feof_unlocked int FILE*
822 Function - ferror int FILE*

View File

@@ -63,6 +63,7 @@ typedef enum {
NfcReadModeEMV,
NfcReadModeNFCA,
NfcReadModeFelica,
NfcReadModeNFCF,
} NfcReadMode;
typedef struct {

View File

@@ -508,6 +508,10 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) {
break;
}
}
} else if(read_mode == NfcReadModeNFCF) {
nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
event = NfcWorkerEventReadUidNfcF;
break;
}
}
} else {

View File

@@ -151,6 +151,55 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) {
return FelicaICType2K;
}
/** Parse common FeliCa response headers.
*
* This parses and validates the most commonly occurring response header types.
*
* The header needs to match the (length, res, idm) format, and also (sf1, sf2) when always_succeed
* is set to false.
*
* @param buf RX buffer.
* @param len RX buffer length.
* @param reader The FeliCa reader context.
* @param expected_resp Expected response code. Must be an odd number.
* @param always_succeed When set to true, skip status flags (sf1 and sf2) parsing.
* @return The number of bytes parsed, or 0 when response is invalid or status flags are set.
*/
static uint8_t felica_consume_header(
uint8_t* buf,
uint8_t len,
FelicaReader* reader,
uint8_t expected_resp,
bool always_succeed) {
furi_assert(expected_resp & 1);
furi_assert(buf != NULL);
furi_assert(reader != NULL);
uint8_t header_size = always_succeed ? 10 : 12;
if(len < header_size) {
FURI_LOG_E(TAG, "Malformed header: too short.");
return 0;
}
if(buf[1] != expected_resp) {
FURI_LOG_E(TAG, "Expecting %u, got %u.", expected_resp, buf[1]);
return 0;
}
if(memcmp(&buf[2], reader->current_idm, 8) != 0) {
FURI_LOG_E(TAG, "IDm mismatch.");
return 0;
}
if(always_succeed) {
reader->status_flags[0] = buf[10];
reader->status_flags[1] = buf[11];
if(reader->status_flags[0] != 0 || reader->status_flags[1] != 0) {
FURI_LOG_W(
TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]);
return 0;
}
}
return header_size;
}
uint8_t felica_prepare_unencrypted_read(
uint8_t* dest,
const FelicaReader* reader,
@@ -212,32 +261,12 @@ uint16_t felica_parse_unencrypted_read(
FelicaReader* reader,
uint8_t* out,
uint16_t out_len) {
if(len < 12) {
return false;
}
len--;
buf++;
if(*buf != FELICA_UNENCRYPTED_READ_RES) {
return false;
}
len--;
buf++;
if(memcmp(buf, reader->current_idm, 8) != 0) {
return false;
}
len -= 8;
buf += 8;
reader->status_flags[0] = buf[0];
reader->status_flags[1] = buf[1];
len -= 2;
buf += 2;
if(reader->status_flags[0] != 0) {
FURI_LOG_W(TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]);
uint8_t consumed = felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false);
if(!consumed) {
return 0;
}
len -= consumed;
buf += consumed;
if(len < 1) {
return 0;
@@ -315,48 +344,77 @@ uint8_t felica_lite_prepare_unencrypted_write(
}
bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* reader) {
if(len < 12) {
uint8_t consumed =
felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_WRITE_RES, false);
if(!consumed) {
return false;
}
return true;
}
uint8_t felica_prepare_request_system_code(uint8_t* dest, FelicaReader* reader) {
dest[0] = FELICA_REQUEST_SYSTEM_CODE_CMD;
memcpy(&dest[1], reader->current_idm, 8);
return 9;
}
bool felica_parse_request_system_code(
uint8_t* buf,
uint8_t len,
FelicaReader* reader,
FelicaSystemArray_t* systems) {
uint8_t consumed =
felica_consume_header(buf, len, reader, FELICA_REQUEST_SYSTEM_CODE_RES, true);
if(consumed == 0) {
return false;
}
len -= consumed;
buf += consumed;
uint8_t entries = *buf;
len--;
buf++;
if(*buf != FELICA_UNENCRYPTED_WRITE_RES) {
if(len < 2 * entries) {
FURI_LOG_E(TAG, "FELICA_REQUEST_SYSTEM_CODE_RES: Response too short");
return false;
}
len--;
buf++;
if(memcmp(buf, reader->current_idm, 8) != 0) {
return false;
}
len -= 8;
buf += 8;
for(uint8_t idx = 0; idx < entries; idx++) {
FelicaSystem* system = FelicaSystemArray_push_new(*systems);
furi_assert(system != NULL);
reader->status_flags[0] = buf[0];
reader->status_flags[1] = buf[1];
len -= 2;
buf += 2;
if(reader->status_flags[0] != 0) {
FURI_LOG_W(TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]);
return 0;
// Set system code
system->number = idx;
system->code = buf[2 * idx] | (buf[2 * idx + 1] << 8);
FURI_LOG_D(TAG, "Found system code %04X", system->code);
// Fill in IDm and PMm
memcpy(system->idm, reader->current_idm, 8);
memcpy(system->pmm, reader->current_pmm, 8);
// Set system index field in IDm
system->idm[0] &= 0x0f;
system->idm[0] |= ((idx & 0xf) << 4);
}
return true;
}
void felica_parse_system_info(FelicaSystem* system, uint8_t* IDm, uint8_t* PMm) {
memcpy(system->idm, IDm, 8);
memcpy(system->pmm, PMm, 8);
for(int i = 0; i < 6; i++) {
char MRT_byte = PMm[2 + i];
FelicaMRTParts* mrt_data = &system->maximum_response_times[i];
mrt_data->real_a = (MRT_byte & 7) + 1;
MRT_byte >>= 3;
mrt_data->real_b = (MRT_byte & 7) + 1;
MRT_byte >>= 3;
mrt_data->exponent = (MRT_byte & 3);
}
static FelicaSystem* felica_gen_monolithic_system_code(
FelicaReader* reader,
FelicaSystemArray_t* systems,
uint16_t system_code) {
FelicaSystem* system = FelicaSystemArray_push_new(*systems);
furi_assert(reader != NULL);
furi_assert(system != NULL);
memcpy(system->idm, reader->current_idm, 8);
memcpy(system->pmm, reader->current_pmm, 8);
system->code = system_code;
return system;
}
bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number) {
@@ -368,12 +426,16 @@ bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number)
}
void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data) {
FelicaBlock* block = malloc(sizeof(FelicaBlock));
FelicaBlock* block = FelicaBlockArray_safe_get(service->blocks, number);
memcpy(block->data, data, FELICA_BLOCK_SIZE);
FelicaBlockList_set_at(service->blocks, number, block);
}
bool felica_read_lite_system(
void felica_push_normal_block(FelicaService* service, uint8_t* data) {
FelicaBlock* block = FelicaBlockArray_push_new(service->blocks);
memcpy(block->data, data, FELICA_BLOCK_SIZE);
}
bool felica_lite_dump_data(
FuriHalNfcTxRxContext* tx_rx,
FelicaReader* reader,
FelicaData* data,
@@ -425,8 +487,6 @@ bool felica_read_lite_system(
return false;
}
system->code = LITE_SYSTEM_CODE;
FelicaLiteInfo* lite_info = &system->lite_info;
lite_info->card_key_1 = NULL;
lite_info->card_key_2 = NULL;
@@ -568,6 +628,22 @@ bool felica_read_lite_system(
return true;
}
bool felica_std_request_system_code(
FuriHalNfcTxRxContext* tx_rx,
FelicaReader* reader,
FelicaSystemArray_t* systems) {
tx_rx->tx_bits = 8 * felica_prepare_request_system_code(tx_rx->tx_data, reader);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_E(TAG, "Bad exchange requesting system code");
return false;
}
if(!felica_parse_request_system_code(tx_rx->rx_data, tx_rx->rx_bits / 8, reader, systems)) {
FURI_LOG_E(TAG, "Bad response to Request System Code command");
return false;
}
return true;
}
bool felica_read_card(
FuriHalNfcTxRxContext* tx_rx,
FelicaData* data,
@@ -583,31 +659,24 @@ bool felica_read_card(
memcpy(reader.current_idm, polled_idm, 8);
memcpy(reader.current_pmm, polled_pmm, 8);
FelicaSystem* current_system = malloc(sizeof(FelicaSystem));
FelicaSystemList_init(data->systems);
FelicaSystemList_push_back(data->systems, current_system);
felica_parse_system_info(current_system, polled_idm, polled_pmm);
FelicaSystemArray_init(data->systems);
if(data->type == FelicaICTypeLite || data->type == FelicaICTypeLiteS) {
FURI_LOG_I(TAG, "Reading Felica Lite system");
felica_read_lite_system(tx_rx, &reader, data, current_system);
FelicaSystem* lite_system =
felica_gen_monolithic_system_code(&reader, &(data->systems), LITE_SYSTEM_CODE);
felica_lite_dump_data(tx_rx, &reader, data, lite_system);
card_read = true;
break;
}
FURI_LOG_I(TAG, "Reading Felica Standard system");
} while(false);
return card_read;
}
void felica_service_clear(FelicaService* service) {
FelicaBlockList_it_t it;
for(FelicaBlockList_it(it, service->blocks); !FelicaBlockList_end_p(it);
FelicaBlockList_next(it)) {
FelicaBlock* block = *FelicaBlockList_ref(it);
free(block);
}
FelicaBlockList_clear(service->blocks);
FelicaBlockArray_clear(service->blocks);
}
void felica_lite_clear(FelicaLiteInfo* lite_info) {
@@ -630,31 +699,33 @@ void felica_lite_clear(FelicaLiteInfo* lite_info) {
}
}
void felica_node_clear(FelicaNode* node);
void felica_area_clear(FelicaArea* area) {
FelicaNodeList_it_t it;
for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); FelicaNodeList_next(it)) {
FelicaNode* node = *FelicaNodeList_ref(it);
if(node->type == FelicaNodeTypeArea) {
felica_area_clear(node->area);
} else if(node->type == FelicaNodeTypeService) {
felica_service_clear(node->service);
for
M_EACH(node, area->nodes, FelicaNodeArray_t) {
felica_node_clear(node);
}
free(node);
FelicaNodeArray_clear(area->nodes);
}
void felica_node_clear(FelicaNode* node) {
if(node->type == FelicaNodeTypeArea) {
felica_area_clear(node->area);
} else if(node->type == FelicaNodeTypeService) {
felica_service_clear(node->service);
}
FelicaNodeList_clear(area->nodes);
}
void felica_clear(FelicaData* data) {
FelicaSystemList_it_t it;
for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it);
FelicaSystemList_next(it)) {
FelicaSystem* system = *FelicaSystemList_ref(it);
if(system->code == LITE_SYSTEM_CODE) {
felica_lite_clear(&system->lite_info);
;
} else {
felica_area_clear(&system->root_area);
for
M_EACH(system, data->systems, FelicaSystemArray_t) {
if(system->code == LITE_SYSTEM_CODE) {
felica_lite_clear(&system->lite_info);
} else {
felica_node_clear(&system->root);
FelicaPublicServiceDict_clear(system->public_services);
}
}
}
FelicaSystemList_clear(data->systems);
FelicaSystemArray_clear(data->systems);
}

View File

@@ -10,6 +10,8 @@
#define MRT_T_SIG_x16 4833038.24 //ns, MRT_T_SIG * (4 ** 2)
#define MRT_T_SIG_x64 19332152.96 //ns, MRT_T_SIG * (4 ** 2)
#define FELICA_PMM_MRT_BASE 2
#define FELICA_VARIABLE_MRT 0
#define FELICA_FIXED_MRT 1
#define FELICA_MUTUAL_AUTH_MRT 2
@@ -17,6 +19,13 @@
#define FELICA_WRITE_MRT 4
#define FELICA_OTHER_MRT 5
#define FELICA_PMM_VARIABLE_MRT (FELICA_PMM_MRT_BASE + FELICA_VARIABLE_MRT)
#define FELICA_PMM_FIXED_MRT (FELICA_PMM_MRT_BASE + FELICA_FIXED_MRT)
#define FELICA_PMM_MUTUAL_AUTH_MRT (FELICA_PMM_MRT_BASE + FELICA_MUTUAL_AUTH_MRT)
#define FELICA_PMM_READ_MRT (FELICA_PMM_MRT_BASE + FELICA_READ_MRT)
#define FELICA_PMM_WRITE_MRT (FELICA_PMM_MRT_BASE + FELICA_WRITE_MRT)
#define FELICA_PMM_OTHER_MRT (FELICA_PMM_MRT_BASE + FELICA_OTHER_MRT)
#define FELICA_BLOCK_SIZE 16
#define CYBERNET_SYSTEM_CODE 0x0003
@@ -55,9 +64,13 @@
#define FELICA_UNENCRYPTED_READ_CMD 0x06
#define FELICA_UNENCRYPTED_WRITE_CMD 0x08
#define FELICA_SEARCH_SERVICE_CODE_CMD 0x0a
#define FELICA_REQUEST_SYSTEM_CODE_CMD 0x0c
#define FELICA_UNENCRYPTED_READ_RES 0x07
#define FELICA_UNENCRYPTED_WRITE_RES 0x09
#define FELICA_SEARCH_SERVICE_CODE_RES 0x0b
#define FELICA_REQUEST_SYSTEM_CODE_RES 0x0d
typedef enum {
FelicaICTypeRC_SA24_10K, // RC-SA24/1x
@@ -88,13 +101,6 @@ typedef enum {
FelicaICTypeSuica, // https://www.tuv-nederland.nl/assets/files/cerfiticaten/2019/07/cr-nscib-cc-10-30076-cr.pdf
} FelicaICType;
typedef struct {
uint8_t exponent : 2;
// Incremented at read
uint8_t real_a : 4;
uint8_t real_b : 4;
} FelicaMRTParts;
typedef enum {
FelicaServiceTypeRandom = (0b0010 << 2),
FelicaServiceTypeCyclic = (0b0011 << 2),
@@ -121,20 +127,22 @@ DICT_SET_DEF(
FelicaServiceAttribute,
M_ENUM_OPLIST(FelicaServiceAttribute, FelicaServiceAttributeAuthRW))
typedef FelicaMRTParts FelicaMRTParameters[6];
typedef struct {
uint8_t data[FELICA_BLOCK_SIZE];
} FelicaBlock;
ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST)
// TODO properly remove this
//ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST)
ARRAY_DEF(FelicaBlockArray, FelicaBlock, M_POD_OPLIST)
#define M_OPL_FelicaBlockArray_t() ARRAY_OPLIST(FelicaBlockArray, M_POD_OPLIST)
typedef struct {
uint16_t number;
FelicaServiceAttributeList_t access_control_list; // accounts for overlap services
bool is_extended_overlap;
bool is_extended_overlap; // We don't know much about this currently. will always be false
union {
FelicaBlockList_t blocks;
// TODO change this to use FelicaBlockArray_t
FelicaBlockArray_t blocks;
struct {
uint16_t overlap_target;
uint8_t block_start;
@@ -149,23 +157,44 @@ typedef enum {
} FelicaNodeType;
struct _FelicaArea_t;
typedef struct {
typedef struct _FelicaArea_t FelicaArea;
struct _FelicaNode_s;
typedef struct _FelicaNode_s FelicaNode;
struct _FelicaNode_s {
/** Node type. */
FelicaNodeType type;
/** Borrowed pointer to its parent node. */
FelicaNode* parent;
union {
struct _FelicaArea_t* area;
/** (Area/dir type only) The area struct. */
FelicaArea* area;
/** (Service/file type only) The service struct. */
FelicaService* service;
};
} FelicaNode;
};
ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST)
// TODO properly remove this
//ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST)
ARRAY_DEF(FelicaNodeArray, FelicaNode, M_POD_OPLIST)
#define M_OPL_FelicaNodeArray_t() ARRAY_OPLIST(FelicaNodeArray, M_POD_OPLIST)
typedef struct _FelicaArea_t {
ARRAY_DEF(FelicaNodeRefArray, FelicaNode*, M_PTR_OPLIST)
#define M_OPL_FelicaNodeRefArray_t() ARRAY_OPLIST(FelicaNodeRefArray, M_PTR_OPLIST)
// { service_number: service_ptr_in_tree }
DICT_DEF2(FelicaPublicServiceDict, uint16_t, M_DEFAULT_OPLIST, FelicaService*, M_PTR_OPLIST)
#define M_OPL_FelicaPublicServiceDict_t() \
DICT_OPLIST(FelicaPublicServiceDict, M_DEFAULT_OPLIST, M_PTR_OPLIST)
struct _FelicaArea_t {
uint16_t number;
bool can_create_subareas;
uint16_t end_service_code;
FelicaNodeList_t nodes;
} FelicaArea;
FelicaNodeArray_t nodes;
};
typedef struct {
uint8_t* S_PAD[14];
@@ -186,24 +215,39 @@ typedef struct {
} FelicaLiteInfo;
typedef struct _FelicaSystem_t {
/** FeliCa system index. */
uint8_t number;
/** If the system belongs to a FeliCa Lite (and be its only system). */
bool is_lite;
/** FeliCa system code. */
uint16_t code;
/** System IDm with system index bitfield properly set. */
uint8_t idm[8];
/** Cached card PMm. */
uint8_t pmm[8];
FelicaMRTParameters maximum_response_times;
union {
/** (For FeliCa Lite only) Card content. */
FelicaLiteInfo lite_info;
FelicaArea root_area;
struct {
/** (For FeliCa Standard only) The root of the raw filesystem tree. */
FelicaNode root;
/** (For FeliCa Standard only) Shortcut for all publicly accessible services for quick
* access by card parsers. */
FelicaPublicServiceDict_t public_services;
};
};
} FelicaSystem;
ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST)
// TODO properly remove this
//ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST)
ARRAY_DEF(FelicaSystemArray, FelicaSystem, M_POD_OPLIST)
#define M_OPL_FelicaSystemArray_t() ARRAY_OPLIST(FelicaSystemArray, M_POD_OPLIST)
typedef struct {
FelicaICType type;
uint8_t subtype;
FelicaSystemList_t systems;
FelicaSystemArray_t systems;
} FelicaData;
typedef struct {
@@ -255,8 +299,17 @@ bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* rea
bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number);
void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data);
void felica_push_normal_block(FelicaService* service, uint8_t* data);
bool felica_read_lite_system(
/** Dump a FeliCa Lite or Lite-S tag.
*
* @param tx_rx NFC context.
* @param reader FeliCa reader context.
* @param data Output data object.
* @param system FeliCa system description.
* @return true if successful.
*/
bool felica_lite_dump_data(
FuriHalNfcTxRxContext* tx_rx,
FelicaReader* reader,
FelicaData* data,

View File

@@ -3,6 +3,7 @@
static const uint32_t TIME_CONSTANT_US = 302;
// TODO move this to felica.c
uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units) {
uint_least32_t base_cost_factor = 1 + (timing & 0x7);
uint_least32_t unit_cost_factor = 1 + ((timing >> 3) & 0x7);