From d6680d1f75970a81709e1febe1eb46d9a7bd2747 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 15 Dec 2023 22:09:52 +0400 Subject: [PATCH] [FL-3719] NFC Plugins loading rework (#3295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc app: rework supported cards * nfc app: supported cards optimization * nfc app: remove old nfc support implementation * nfc app: add documentation for supported cards * nfc app: format sources * nfc app: fix PVS warnings * nfc app: one more PVS fix * nfc app: PVS please stop * nfc app: add missing documentation Co-authored-by: あく --- .../main/nfc/helpers/nfc_supported_cards.c | 242 ++++++++++++++---- .../main/nfc/helpers/nfc_supported_cards.h | 37 ++- .../protocol_support/nfc_protocol_support.c | 10 +- applications/main/nfc/nfc_app.c | 5 +- applications/main/nfc/nfc_app_i.h | 2 + .../nfc/scenes/nfc_scene_supported_card.c | 3 +- 6 files changed, 236 insertions(+), 63 deletions(-) diff --git a/applications/main/nfc/helpers/nfc_supported_cards.c b/applications/main/nfc/helpers/nfc_supported_cards.c index a242ba3a..6016ae17 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.c +++ b/applications/main/nfc/helpers/nfc_supported_cards.c @@ -1,4 +1,5 @@ #include "nfc_supported_cards.h" + #include "../plugins/supported_cards/nfc_supported_card_plugin.h" #include @@ -7,22 +8,72 @@ #include #include +#include #define TAG "NfcSupportedCards" #define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins") #define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal" +typedef enum { + NfcSupportedCardsPluginFeatureHasVerify = (1U << 0), + NfcSupportedCardsPluginFeatureHasRead = (1U << 1), + NfcSupportedCardsPluginFeatureHasParse = (1U << 2), +} NfcSupportedCardsPluginFeature; + +typedef struct { + FuriString* path; + NfcProtocol protocol; + NfcSupportedCardsPluginFeature feature; +} NfcSupportedCardsPluginCache; + +ARRAY_DEF(NfcSupportedCardsPluginCache, NfcSupportedCardsPluginCache, M_POD_OPLIST); + +typedef enum { + NfcSupportedCardsLoadStateIdle, + NfcSupportedCardsLoadStateInProgress, + NfcSupportedCardsLoadStateSuccess, + NfcSupportedCardsLoadStateFail, +} NfcSupportedCardsLoadState; + typedef struct { Storage* storage; File* directory; FuriString* file_path; char file_name[256]; FlipperApplication* app; -} NfcSupportedCards; +} NfcSupportedCardsLoadContext; -static NfcSupportedCards* nfc_supported_cards_alloc() { +struct NfcSupportedCards { + NfcSupportedCardsPluginCache_t plugins_cache_arr; + NfcSupportedCardsLoadState load_state; + NfcSupportedCardsLoadContext* load_context; +}; + +NfcSupportedCards* nfc_supported_cards_alloc() { NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards)); + NfcSupportedCardsPluginCache_init(instance->plugins_cache_arr); + + return instance; +} + +void nfc_supported_cards_free(NfcSupportedCards* instance) { + furi_assert(instance); + + NfcSupportedCardsPluginCache_it_t iter; + for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr); + !NfcSupportedCardsPluginCache_end_p(iter); + NfcSupportedCardsPluginCache_next(iter)) { + NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter); + furi_string_free(plugin_cache->path); + } + + NfcSupportedCardsPluginCache_clear(instance->plugins_cache_arr); + free(instance); +} + +static NfcSupportedCardsLoadContext* nfc_supported_cards_load_context_alloc() { + NfcSupportedCardsLoadContext* instance = malloc(sizeof(NfcSupportedCardsLoadContext)); instance->storage = furi_record_open(RECORD_STORAGE); instance->directory = storage_file_alloc(instance->storage); @@ -35,7 +86,7 @@ static NfcSupportedCards* nfc_supported_cards_alloc() { return instance; } -static void nfc_supported_cards_free(NfcSupportedCards* instance) { +static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext* instance) { if(instance->app) { flipper_application_free(instance->app); } @@ -50,7 +101,36 @@ static void nfc_supported_cards_free(NfcSupportedCards* instance) { } static const NfcSupportedCardsPlugin* - nfc_supported_cards_get_next_plugin(NfcSupportedCards* instance) { + nfc_supported_cards_get_plugin(NfcSupportedCardsLoadContext* instance, FuriString* path) { + furi_assert(instance); + furi_assert(path); + + const NfcSupportedCardsPlugin* plugin = NULL; + do { + if(instance->app) flipper_application_free(instance->app); + instance->app = flipper_application_alloc(instance->storage, firmware_api_interface); + if(flipper_application_preload(instance->app, furi_string_get_cstr(path)) != + FlipperApplicationPreloadStatusSuccess) + break; + if(!flipper_application_is_plugin(instance->app)) break; + if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess) + break; + const FlipperAppPluginDescriptor* descriptor = + flipper_application_plugin_get_descriptor(instance->app); + + if(descriptor == NULL) break; + + if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) break; + if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) break; + + plugin = descriptor->entry_point; + } while(false); + + return plugin; +} + +static const NfcSupportedCardsPlugin* + nfc_supported_cards_get_next_plugin(NfcSupportedCardsLoadContext* instance) { const NfcSupportedCardsPlugin* plugin = NULL; do { @@ -65,83 +145,137 @@ static const NfcSupportedCardsPlugin* path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path); - if(instance->app) flipper_application_free(instance->app); - instance->app = flipper_application_alloc(instance->storage, firmware_api_interface); - - if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) != - FlipperApplicationPreloadStatusSuccess) - continue; - if(!flipper_application_is_plugin(instance->app)) continue; - - if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess) - continue; - - const FlipperAppPluginDescriptor* descriptor = - flipper_application_plugin_get_descriptor(instance->app); - - if(descriptor == NULL) continue; - - if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) continue; - if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) continue; - - plugin = descriptor->entry_point; + plugin = nfc_supported_cards_get_plugin(instance, instance->file_path); } while(plugin == NULL); //-V654 return plugin; } -bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc) { +void nfc_supported_cards_load_cache(NfcSupportedCards* instance) { + furi_assert(instance); + + do { + if((instance->load_state == NfcSupportedCardsLoadStateSuccess) || + (instance->load_state == NfcSupportedCardsLoadStateFail)) + break; + + instance->load_context = nfc_supported_cards_load_context_alloc(); + + while(true) { + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_next_plugin(instance->load_context); + if(plugin == NULL) break; //-V547 + + NfcSupportedCardsPluginCache plugin_cache = {}; //-V779 + plugin_cache.path = furi_string_alloc_set(instance->load_context->file_path); + plugin_cache.protocol = plugin->protocol; + if(plugin->verify) { + plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify; + } + if(plugin->read) { + plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasRead; + } + if(plugin->parse) { + plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasParse; + } + NfcSupportedCardsPluginCache_push_back(instance->plugins_cache_arr, plugin_cache); + } + + nfc_supported_cards_load_context_free(instance->load_context); + + size_t plugins_loaded = NfcSupportedCardsPluginCache_size(instance->plugins_cache_arr); + if(plugins_loaded == 0) { + FURI_LOG_D(TAG, "Plugins not found"); + instance->load_state = NfcSupportedCardsLoadStateFail; + } else { + FURI_LOG_D(TAG, "Loaded %zu plugins", plugins_loaded); + instance->load_state = NfcSupportedCardsLoadStateSuccess; + } + + } while(false); +} + +bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc) { + furi_assert(instance); furi_assert(device); furi_assert(nfc); bool card_read = false; - - NfcSupportedCards* supported_cards = nfc_supported_cards_alloc(); + NfcProtocol protocol = nfc_device_get_protocol(device); do { - const NfcSupportedCardsPlugin* plugin = - nfc_supported_cards_get_next_plugin(supported_cards); - if(plugin == NULL) break; //-V547 + if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break; - const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779 - if(plugin->protocol != protocol) continue; + instance->load_context = nfc_supported_cards_load_context_alloc(); - if(plugin->verify) { - if(!plugin->verify(nfc)) continue; + NfcSupportedCardsPluginCache_it_t iter; + for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr); + !NfcSupportedCardsPluginCache_end_p(iter); + NfcSupportedCardsPluginCache_next(iter)) { + NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter); + if(plugin_cache->protocol != protocol) continue; + if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasRead) == 0) continue; + + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path); + if(plugin == NULL) continue; + + if(plugin->verify) { + if(!plugin->verify(nfc)) continue; + } + + if(plugin->read) { + if(plugin->read(nfc, device)) { + card_read = true; + break; + } + } } - if(plugin->read) { - card_read = plugin->read(nfc, device); - } + nfc_supported_cards_load_context_free(instance->load_context); + } while(false); - } while(!card_read); - - nfc_supported_cards_free(supported_cards); return card_read; } -bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data) { +bool nfc_supported_cards_parse( + NfcSupportedCards* instance, + NfcDevice* device, + FuriString* parsed_data) { + furi_assert(instance); furi_assert(device); furi_assert(parsed_data); - bool parsed = false; - - NfcSupportedCards* supported_cards = nfc_supported_cards_alloc(); + bool card_parsed = false; + NfcProtocol protocol = nfc_device_get_protocol(device); do { - const NfcSupportedCardsPlugin* plugin = - nfc_supported_cards_get_next_plugin(supported_cards); - if(plugin == NULL) break; //-V547 + if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break; - const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779 - if(plugin->protocol != protocol) continue; + instance->load_context = nfc_supported_cards_load_context_alloc(); - if(plugin->parse) { - parsed = plugin->parse(device, parsed_data); + NfcSupportedCardsPluginCache_it_t iter; + for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr); + !NfcSupportedCardsPluginCache_end_p(iter); + NfcSupportedCardsPluginCache_next(iter)) { + NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter); + if(plugin_cache->protocol != protocol) continue; + if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasParse) == 0) continue; + + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path); + if(plugin == NULL) continue; + + if(plugin->parse) { + if(plugin->parse(device, parsed_data)) { + card_parsed = true; + break; + } + } } - } while(!parsed); + nfc_supported_cards_load_context_free(instance->load_context); + } while(false); - nfc_supported_cards_free(supported_cards); - return parsed; + return card_parsed; } diff --git a/applications/main/nfc/helpers/nfc_supported_cards.h b/applications/main/nfc/helpers/nfc_supported_cards.h index 0c25a5b1..7778c6f2 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.h +++ b/applications/main/nfc/helpers/nfc_supported_cards.h @@ -15,6 +15,34 @@ extern "C" { #endif +/** + * @brief NfcSupportedCards opaque type definition. + */ +typedef struct NfcSupportedCards NfcSupportedCards; + +/** + * @brief Allocate NfcSupportedCards instance. + * + * @return pointer to allocated NfcSupportedCards instance. + */ +NfcSupportedCards* nfc_supported_cards_alloc(); + +/** + * @brief Delete an NfcSupportedCards instance + * + * @param[in] instance pointer to instance to be deleted. + */ +void nfc_supported_cards_free(NfcSupportedCards* instance); + +/** + * @brief Load plugins information to cache. + * + * @note This function must be called before calling read and parse fanctions. + * + * @param[in, out] instance pointer to NfcSupportedCards instance. + */ +void nfc_supported_cards_load_cache(NfcSupportedCards* instance); + /** * @brief Read the card using a custom procedure. * @@ -22,13 +50,14 @@ extern "C" { * try to execute the custom read procedure specified in each. Upon first success, * no further attempts will be made and the function will return. * + * @param[in, out] instance pointer to NfcSupportedCards instance. * @param[in,out] device pointer to a device instance to hold the read data. * @param[in,out] nfc pointer to an Nfc instance. * @returns true if the card was successfully read, false otherwise. * * @see NfcSupportedCardPluginRead for detailed description. */ -bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc); +bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc); /** * @brief Parse raw data into human-readable representation. @@ -37,13 +66,17 @@ bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc); * try to parse the data according to each implementation. Upon first success, * no further attempts will be made and the function will return. * + * @param[in, out] instance pointer to NfcSupportedCards instance. * @param[in] device pointer to a device instance holding the data is to be parsed. * @param[out] parsed_data pointer to the string to contain the formatted result. * @returns true if the card was successfully parsed, false otherwise. * * @see NfcSupportedCardPluginParse for detailed description. */ -bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data); +bool nfc_supported_cards_parse( + NfcSupportedCards* instance, + NfcDevice* device, + FuriString* parsed_data); #ifdef __cplusplus } diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 87fbe9f0..38ead0ac 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -8,7 +8,6 @@ #include "nfc_protocol_support.h" #include "nfc/nfc_app_i.h" -#include "nfc/helpers/nfc_supported_cards.h" #include "nfc_protocol_support_defs.h" #include "nfc_protocol_support_gui_common.h" @@ -157,9 +156,11 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { instance->protocols_detected[instance->protocols_detected_selected_idx]; instance->poller = nfc_poller_alloc(instance->nfc, protocol); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + nfc_supported_cards_load_cache(instance->nfc_supported_cards); + // Start poller with the appropriate callback nfc_protocol_support[protocol]->scene_read.on_enter(instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); nfc_blink_detect_start(instance); } @@ -178,7 +179,8 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana } else if(event.event == NfcCustomEventPollerIncomplete) { nfc_poller_stop(instance->poller); nfc_poller_free(instance->poller); - bool card_read = nfc_supported_cards_read(instance->nfc_device, instance->nfc); + bool card_read = nfc_supported_cards_read( + instance->nfc_supported_cards, instance->nfc_device, instance->nfc); if(card_read) { notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); @@ -303,7 +305,7 @@ static void nfc_protocol_support_scene_read_success_on_enter(NfcApp* instance) { Widget* widget = instance->widget; FuriString* temp_str = furi_string_alloc(); - if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { + if(nfc_supported_cards_parse(instance->nfc_supported_cards, instance->nfc_device, temp_str)) { widget_add_text_scroll_element( instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); } else { diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 5ae0ca5f..ec528ad9 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -51,6 +51,7 @@ NfcApp* nfc_app_alloc() { instance->mf_ul_auth = mf_ultralight_auth_alloc(); instance->mfc_key_cache = mf_classic_key_cache_alloc(); + instance->nfc_supported_cards = nfc_supported_cards_alloc(); // Nfc device instance->nfc_device = nfc_device_alloc(); @@ -110,7 +111,6 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); // Dict attack - instance->dict_attack = dict_attack_alloc(); view_dispatcher_add_view( instance->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(instance->dict_attack)); @@ -141,6 +141,7 @@ void nfc_app_free(NfcApp* instance) { mf_ultralight_auth_free(instance->mf_ul_auth); mf_classic_key_cache_free(instance->mfc_key_cache); + nfc_supported_cards_free(instance->nfc_supported_cards); // Nfc device nfc_device_free(instance->nfc_device); @@ -339,6 +340,8 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { furi_assert(path); bool result = false; + nfc_supported_cards_load_cache(instance->nfc_supported_cards); + FuriString* load_path = furi_string_alloc(); if(nfc_has_shadow_file_internal(instance, path)) { nfc_set_shadow_file_path(path, load_path); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 3c009200..bde87b12 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -31,6 +31,7 @@ #include "helpers/mf_user_dict.h" #include "helpers/mfkey32_logger.h" #include "helpers/mf_classic_key_cache.h" +#include "helpers/nfc_supported_cards.h" #include #include @@ -132,6 +133,7 @@ struct NfcApp { Mfkey32Logger* mfkey32_logger; MfUserDict* mf_user_dict; MfClassicKeyCache* mfc_key_cache; + NfcSupportedCards* nfc_supported_cards; NfcDevice* nfc_device; Iso14443_3aData* iso14443_3a_edit_data; diff --git a/applications/main/nfc/scenes/nfc_scene_supported_card.c b/applications/main/nfc/scenes/nfc_scene_supported_card.c index cea55b78..e32571bf 100644 --- a/applications/main/nfc/scenes/nfc_scene_supported_card.c +++ b/applications/main/nfc/scenes/nfc_scene_supported_card.c @@ -1,6 +1,5 @@ #include "nfc/nfc_app_i.h" -#include "nfc/helpers/nfc_supported_cards.h" #include "nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h" void nfc_scene_supported_card_on_enter(void* context) { @@ -8,7 +7,7 @@ void nfc_scene_supported_card_on_enter(void* context) { FuriString* temp_str = furi_string_alloc(); - if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { + if(nfc_supported_cards_parse(instance->nfc_supported_cards, instance->nfc_device, temp_str)) { widget_add_text_scroll_element( instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); widget_add_button_element(