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

View File

@@ -29,21 +29,19 @@ void nfc_scene_felica_read_success_on_enter(void* context) {
} else { } else {
temp_str = furi_string_alloc_printf("\e#%s", nfc_felica_type(felica_data->type)); temp_str = furi_string_alloc_printf("\e#%s", nfc_felica_type(felica_data->type));
FelicaSystemList_it_t it; for
for(FelicaSystemList_it(it, felica_data->systems); !FelicaSystemList_end_p(it); M_EACH(current_system, felica_data->systems, FelicaSystemArray_t) {
FelicaSystemList_next(it)) { furi_string_cat_printf(
FelicaSystem* current_system = *FelicaSystemList_ref(it); temp_str, "\nSystem %04X (#%d):", current_system->code, current_system->number);
furi_string_cat_printf( furi_string_cat_printf(temp_str, "\nIDm:\n ");
temp_str, "\nSystem %04X (#%d):", current_system->code, current_system->number); for(size_t i = 0; i < 8; i++) {
furi_string_cat_printf(temp_str, "\nIDm:\n "); furi_string_cat_printf(temp_str, "%02X", current_system->idm[i]);
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)); 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[0],
nfc_data->f_data.pmm[1]); 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( furi_string_cat_printf(
temp_str, temp_str,
"- ReqSvc: %" PRIuLEAST32 "us\n", "- 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( furi_string_cat_printf(
temp_str, temp_str,
"- Fixed: %" PRIuLEAST32 "us\n", "- 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( furi_string_cat_printf(
temp_str, temp_str,
"- Auth1: %" PRIuLEAST32 "us\n", "- 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( furi_string_cat_printf(
temp_str, temp_str,
"- Auth2: %" PRIuLEAST32 "us\n", "- 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( furi_string_cat_printf(
temp_str, temp_str,
"- Read: %" PRIuLEAST32 "us\n", "- 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( furi_string_cat_printf(
temp_str, temp_str,
"- Write: %" PRIuLEAST32 "us\n", "- 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( furi_string_cat_printf(
temp_str, temp_str,
"- Other: %" PRIuLEAST32 "us\n\n", "- 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:"); furi_string_cat_printf(temp_str, "IDm:");
for(size_t i = 0; i < nfc_data->uid_len; i++) { for(size_t i = 0; i < nfc_data->uid_len; i++) {

View File

@@ -8,6 +8,7 @@ enum SubmenuIndex {
SubmenuIndexReadEMV, SubmenuIndexReadEMV,
SubmenuIndexReadNFCA, SubmenuIndexReadNFCA,
SubmenuIndexReadFelica, SubmenuIndexReadFelica,
SubmenuIndexReadNFCF,
}; };
void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { 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, SubmenuIndexReadFelica,
nfc_scene_read_card_type_submenu_callback, nfc_scene_read_card_type_submenu_callback,
nfc); 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); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType);
submenu_set_selected_item(submenu, state); 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); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true; 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); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event);
} }
return consumed; return consumed;

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,11.13,, Version,+,11.14,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.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_service_name,FuriString*,FelicaService*
Function,-,felica_get_system_name,FuriString*,FelicaSystem* Function,-,felica_get_system_name,FuriString*,FelicaSystem*
Function,-,felica_lite_can_read_without_mac,_Bool,"uint8_t*, uint8_t" 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_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_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_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_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_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_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_card,_Bool,"FuriHalNfcTxRxContext*, FelicaData*, uint8_t*, uint8_t*"
Function,-,felica_read_lite_system,_Bool,"FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*"
Function,-,feof,int,FILE* Function,-,feof,int,FILE*
Function,-,feof_unlocked,int,FILE* Function,-,feof_unlocked,int,FILE*
Function,-,ferror,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, NfcReadModeEMV,
NfcReadModeNFCA, NfcReadModeNFCA,
NfcReadModeFelica, NfcReadModeFelica,
NfcReadModeNFCF,
} NfcReadMode; } NfcReadMode;
typedef struct { typedef struct {

View File

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

View File

@@ -151,6 +151,55 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) {
return FelicaICType2K; 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 felica_prepare_unencrypted_read(
uint8_t* dest, uint8_t* dest,
const FelicaReader* reader, const FelicaReader* reader,
@@ -212,32 +261,12 @@ uint16_t felica_parse_unencrypted_read(
FelicaReader* reader, FelicaReader* reader,
uint8_t* out, uint8_t* out,
uint16_t out_len) { uint16_t out_len) {
if(len < 12) { uint8_t consumed = felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false);
return false; if(!consumed) {
}
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]);
return 0; return 0;
} }
len -= consumed;
buf += consumed;
if(len < 1) { if(len < 1) {
return 0; 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) { 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 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--; len--;
buf++; 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; return false;
} }
len--;
buf++;
if(memcmp(buf, reader->current_idm, 8) != 0) { for(uint8_t idx = 0; idx < entries; idx++) {
return false; FelicaSystem* system = FelicaSystemArray_push_new(*systems);
} furi_assert(system != NULL);
len -= 8;
buf += 8;
reader->status_flags[0] = buf[0]; // Set system code
reader->status_flags[1] = buf[1]; system->number = idx;
len -= 2; system->code = buf[2 * idx] | (buf[2 * idx + 1] << 8);
buf += 2;
if(reader->status_flags[0] != 0) { FURI_LOG_D(TAG, "Found system code %04X", system->code);
FURI_LOG_W(TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]);
return 0; // 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; return true;
} }
void felica_parse_system_info(FelicaSystem* system, uint8_t* IDm, uint8_t* PMm) { static FelicaSystem* felica_gen_monolithic_system_code(
memcpy(system->idm, IDm, 8); FelicaReader* reader,
memcpy(system->pmm, PMm, 8); FelicaSystemArray_t* systems,
for(int i = 0; i < 6; i++) { uint16_t system_code) {
char MRT_byte = PMm[2 + i]; FelicaSystem* system = FelicaSystemArray_push_new(*systems);
FelicaMRTParts* mrt_data = &system->maximum_response_times[i]; furi_assert(reader != NULL);
mrt_data->real_a = (MRT_byte & 7) + 1; furi_assert(system != NULL);
MRT_byte >>= 3;
mrt_data->real_b = (MRT_byte & 7) + 1; memcpy(system->idm, reader->current_idm, 8);
MRT_byte >>= 3; memcpy(system->pmm, reader->current_pmm, 8);
mrt_data->exponent = (MRT_byte & 3); system->code = system_code;
}
return system;
} }
bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number) { 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) { 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); 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, FuriHalNfcTxRxContext* tx_rx,
FelicaReader* reader, FelicaReader* reader,
FelicaData* data, FelicaData* data,
@@ -425,8 +487,6 @@ bool felica_read_lite_system(
return false; return false;
} }
system->code = LITE_SYSTEM_CODE;
FelicaLiteInfo* lite_info = &system->lite_info; FelicaLiteInfo* lite_info = &system->lite_info;
lite_info->card_key_1 = NULL; lite_info->card_key_1 = NULL;
lite_info->card_key_2 = NULL; lite_info->card_key_2 = NULL;
@@ -568,6 +628,22 @@ bool felica_read_lite_system(
return true; 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( bool felica_read_card(
FuriHalNfcTxRxContext* tx_rx, FuriHalNfcTxRxContext* tx_rx,
FelicaData* data, FelicaData* data,
@@ -583,31 +659,24 @@ bool felica_read_card(
memcpy(reader.current_idm, polled_idm, 8); memcpy(reader.current_idm, polled_idm, 8);
memcpy(reader.current_pmm, polled_pmm, 8); memcpy(reader.current_pmm, polled_pmm, 8);
FelicaSystem* current_system = malloc(sizeof(FelicaSystem)); FelicaSystemArray_init(data->systems);
FelicaSystemList_init(data->systems);
FelicaSystemList_push_back(data->systems, current_system);
felica_parse_system_info(current_system, polled_idm, polled_pmm);
if(data->type == FelicaICTypeLite || data->type == FelicaICTypeLiteS) { if(data->type == FelicaICTypeLite || data->type == FelicaICTypeLiteS) {
FURI_LOG_I(TAG, "Reading Felica Lite system"); 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; card_read = true;
break; break;
} }
FURI_LOG_I(TAG, "Reading Felica Standard system");
} while(false); } while(false);
return card_read; return card_read;
} }
void felica_service_clear(FelicaService* service) { void felica_service_clear(FelicaService* service) {
FelicaBlockList_it_t it; FelicaBlockArray_clear(service->blocks);
for(FelicaBlockList_it(it, service->blocks); !FelicaBlockList_end_p(it);
FelicaBlockList_next(it)) {
FelicaBlock* block = *FelicaBlockList_ref(it);
free(block);
}
FelicaBlockList_clear(service->blocks);
} }
void felica_lite_clear(FelicaLiteInfo* lite_info) { 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) { void felica_area_clear(FelicaArea* area) {
FelicaNodeList_it_t it; for
for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); FelicaNodeList_next(it)) { M_EACH(node, area->nodes, FelicaNodeArray_t) {
FelicaNode* node = *FelicaNodeList_ref(it); felica_node_clear(node);
if(node->type == FelicaNodeTypeArea) {
felica_area_clear(node->area);
} else if(node->type == FelicaNodeTypeService) {
felica_service_clear(node->service);
} }
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) { void felica_clear(FelicaData* data) {
FelicaSystemList_it_t it; for
for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it); M_EACH(system, data->systems, FelicaSystemArray_t) {
FelicaSystemList_next(it)) { if(system->code == LITE_SYSTEM_CODE) {
FelicaSystem* system = *FelicaSystemList_ref(it); felica_lite_clear(&system->lite_info);
if(system->code == LITE_SYSTEM_CODE) { } else {
felica_lite_clear(&system->lite_info); felica_node_clear(&system->root);
; FelicaPublicServiceDict_clear(system->public_services);
} else { }
felica_area_clear(&system->root_area);
} }
} FelicaSystemArray_clear(data->systems);
FelicaSystemList_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_x16 4833038.24 //ns, MRT_T_SIG * (4 ** 2)
#define MRT_T_SIG_x64 19332152.96 //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_VARIABLE_MRT 0
#define FELICA_FIXED_MRT 1 #define FELICA_FIXED_MRT 1
#define FELICA_MUTUAL_AUTH_MRT 2 #define FELICA_MUTUAL_AUTH_MRT 2
@@ -17,6 +19,13 @@
#define FELICA_WRITE_MRT 4 #define FELICA_WRITE_MRT 4
#define FELICA_OTHER_MRT 5 #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 FELICA_BLOCK_SIZE 16
#define CYBERNET_SYSTEM_CODE 0x0003 #define CYBERNET_SYSTEM_CODE 0x0003
@@ -55,9 +64,13 @@
#define FELICA_UNENCRYPTED_READ_CMD 0x06 #define FELICA_UNENCRYPTED_READ_CMD 0x06
#define FELICA_UNENCRYPTED_WRITE_CMD 0x08 #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_READ_RES 0x07
#define FELICA_UNENCRYPTED_WRITE_RES 0x09 #define FELICA_UNENCRYPTED_WRITE_RES 0x09
#define FELICA_SEARCH_SERVICE_CODE_RES 0x0b
#define FELICA_REQUEST_SYSTEM_CODE_RES 0x0d
typedef enum { typedef enum {
FelicaICTypeRC_SA24_10K, // RC-SA24/1x 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 FelicaICTypeSuica, // https://www.tuv-nederland.nl/assets/files/cerfiticaten/2019/07/cr-nscib-cc-10-30076-cr.pdf
} FelicaICType; } FelicaICType;
typedef struct {
uint8_t exponent : 2;
// Incremented at read
uint8_t real_a : 4;
uint8_t real_b : 4;
} FelicaMRTParts;
typedef enum { typedef enum {
FelicaServiceTypeRandom = (0b0010 << 2), FelicaServiceTypeRandom = (0b0010 << 2),
FelicaServiceTypeCyclic = (0b0011 << 2), FelicaServiceTypeCyclic = (0b0011 << 2),
@@ -121,20 +127,22 @@ DICT_SET_DEF(
FelicaServiceAttribute, FelicaServiceAttribute,
M_ENUM_OPLIST(FelicaServiceAttribute, FelicaServiceAttributeAuthRW)) M_ENUM_OPLIST(FelicaServiceAttribute, FelicaServiceAttributeAuthRW))
typedef FelicaMRTParts FelicaMRTParameters[6];
typedef struct { typedef struct {
uint8_t data[FELICA_BLOCK_SIZE]; uint8_t data[FELICA_BLOCK_SIZE];
} FelicaBlock; } 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 { typedef struct {
uint16_t number; uint16_t number;
FelicaServiceAttributeList_t access_control_list; // accounts for overlap services 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 { union {
FelicaBlockList_t blocks; // TODO change this to use FelicaBlockArray_t
FelicaBlockArray_t blocks;
struct { struct {
uint16_t overlap_target; uint16_t overlap_target;
uint8_t block_start; uint8_t block_start;
@@ -149,23 +157,44 @@ typedef enum {
} FelicaNodeType; } FelicaNodeType;
struct _FelicaArea_t; 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; FelicaNodeType type;
/** Borrowed pointer to its parent node. */
FelicaNode* parent;
union { union {
struct _FelicaArea_t* area; /** (Area/dir type only) The area struct. */
FelicaArea* area;
/** (Service/file type only) The service struct. */
FelicaService* service; 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; uint16_t number;
bool can_create_subareas; bool can_create_subareas;
uint16_t end_service_code; uint16_t end_service_code;
FelicaNodeList_t nodes; FelicaNodeArray_t nodes;
} FelicaArea; };
typedef struct { typedef struct {
uint8_t* S_PAD[14]; uint8_t* S_PAD[14];
@@ -186,24 +215,39 @@ typedef struct {
} FelicaLiteInfo; } FelicaLiteInfo;
typedef struct _FelicaSystem_t { typedef struct _FelicaSystem_t {
/** FeliCa system index. */
uint8_t number; 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; uint16_t code;
/** System IDm with system index bitfield properly set. */
uint8_t idm[8]; uint8_t idm[8];
/** Cached card PMm. */
uint8_t pmm[8]; uint8_t pmm[8];
FelicaMRTParameters maximum_response_times;
union { union {
/** (For FeliCa Lite only) Card content. */
FelicaLiteInfo lite_info; 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; } 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 { typedef struct {
FelicaICType type; FelicaICType type;
uint8_t subtype; uint8_t subtype;
FelicaSystemList_t systems; FelicaSystemArray_t systems;
} FelicaData; } FelicaData;
typedef struct { 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); 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_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, FuriHalNfcTxRxContext* tx_rx,
FelicaReader* reader, FelicaReader* reader,
FelicaData* data, FelicaData* data,

View File

@@ -3,6 +3,7 @@
static const uint32_t TIME_CONSTANT_US = 302; 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 felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units) {
uint_least32_t base_cost_factor = 1 + (timing & 0x7); uint_least32_t base_cost_factor = 1 + (timing & 0x7);
uint_least32_t unit_cost_factor = 1 + ((timing >> 3) & 0x7); uint_least32_t unit_cost_factor = 1 + ((timing >> 3) & 0x7);