jolly has submitted this change. ( https://gerrit.osmocom.org/c/onomondo-ipa/+/43653?usp=email )
Change subject: Add support for polling multiple eIMs ......................................................................
Add support for polling multiple eIMs
If the eUICC stores multiple eIM configurations, poll all eIMs rather than only the first one found.
The poll loop is moved from main.c to ipad.c. This poll loop is then called for all eIMs found in the EimConfigurationData list.
To abort execution, the global "running" flag is mode from main.c to context structure. A new function is used to clear the flag and cause the poll loop to terminate.
Related: SYS#8101 Change-Id: Ifcad584dd04dc83c59124ce32e60254a72537d02 --- M include/onomondo/ipa/ipad.h M src/ipa/libipa/context.h M src/ipa/libipa/ipad.c M src/ipa/main.c 4 files changed, 146 insertions(+), 95 deletions(-)
Approvals: dexter: Looks good to me, approved Jenkins Builder: Verified
diff --git a/include/onomondo/ipa/ipad.h b/include/onomondo/ipa/ipad.h index 77a66df..af8de91 100644 --- a/include/onomondo/ipa/ipad.h +++ b/include/onomondo/ipa/ipad.h @@ -45,6 +45,9 @@ * used.) */ char *preferred_eim_id;
+ /*! force the IPAd to process only one eUICC package (debug, use with caution) */ + bool one_euicc_pkg_only; + /*! current TAC (This struct member may be updated at any time after context creation.) */ uint8_t tac[IPA_LEN_TAC];
@@ -87,7 +90,6 @@
struct ipa_context *ipa_new_ctx(struct ipa_config *cfg, struct ipa_buf *nvstate); int ipa_init(struct ipa_context *ctx); -int eim_init(struct ipa_context *ctx); int ipa_add_init_eim_cfg(struct ipa_context *ctx, struct ipa_buf *cfg); int ipa_euicc_mem_rst(struct ipa_context *ctx, bool operatnl_profiles, bool field_test_profiles, bool default_smdp_addr, bool pre_test_profiles, bool provisioning_profiles, bool eim_cfg_data, bool immediate_enable_cfg); @@ -97,5 +99,6 @@ int ipa_disable_emerg_prfle(struct ipa_context *ctx); int ipa_get_connnectivity_parameters(struct ipa_context *ctx, struct ipa_buf **http_params); int ipa_poll(struct ipa_context *ctx); +void ipa_abort(struct ipa_context *ctx); void ipa_close(struct ipa_context *ctx); struct ipa_buf *ipa_free_ctx(struct ipa_context *ctx); diff --git a/src/ipa/libipa/context.h b/src/ipa/libipa/context.h index 2100cc2..d9c8324 100644 --- a/src/ipa/libipa/context.h +++ b/src/ipa/libipa/context.h @@ -67,10 +67,10 @@ } immediate_enable; } iot_euicc_emu;
- /*! cached eimId (read from eUICC when ipa_init is called) */ + /*! cached eimId (read from eUICC when eim_init is called) */ char *eim_id;
- /*! cached eIM address (read from eUICC when ipa_init is called) */ + /*! cached eIM address (read from eUICC when eim_init is called) */ char *eim_fqdn;
/*! cached state of generic eUICC package download and execute procedure @@ -86,4 +86,7 @@
/*! A canary to detect HTTP communication errors */ bool check_http; + + /*! Flag to keep polling eIM(s) or terminate the loop */ + bool poll_running; }; diff --git a/src/ipa/libipa/ipad.c b/src/ipa/libipa/ipad.c index 8838f91..fa91961 100644 --- a/src/ipa/libipa/ipad.c +++ b/src/ipa/libipa/ipad.c @@ -138,45 +138,6 @@ nvstate_deserialize_ipa_buf(&nvstate_data, &nvstate_data_len); }
-/*! Read eIM configuration from eUICC and pick a suitable eIM. - * \param[inout] ctx pointer to ipa_context. - * \returns 0 success, -EINVAL on failure. */ -int eim_init(struct ipa_context *ctx) -{ - struct ipa_es10b_eim_cfg_data *eim_cfg_data = NULL; - struct EimConfigurationData *eim_cfg_data_item = NULL; - int rc; - - eim_cfg_data = ipa_es10b_get_eim_cfg_data(ctx); - if (!eim_cfg_data) { - IPA_LOGP(SIPA, LERROR, "cannot read EimConfigurationData from eUICC\n"); - goto error; - } - - /* In case no preferred_eim_id is set, the first eIM configuration item will be pulled from the list */ - rc = ipa_es10b_get_eim_cfg_data_filter(&eim_cfg_data_item, eim_cfg_data, ctx->cfg->preferred_eim_id, 0); - if (rc < 0) { - IPA_LOGP(SIPA, LERROR, "no suitable EimConfigurationData item present.\n"); - goto error; - } - - ctx->eim_id = IPA_STR_FROM_ASN(&eim_cfg_data_item->eimId); - if (!ctx->eim_id) - goto error; - - if (eim_cfg_data_item->eimFqdn) - ctx->eim_fqdn = IPA_STR_FROM_ASN(eim_cfg_data_item->eimFqdn); - else - goto error; - - ipa_es10b_get_eim_cfg_data_free(eim_cfg_data); - return 0; -error: - IPA_LOGP(SIPA, LERROR, "unable to retrieve EimConfigurationData\n"); - ipa_es10b_get_eim_cfg_data_free(eim_cfg_data); - return -EINVAL; -} - /*! Create a new ipa_context. * \param[in] cfg IPAd configuration. * \returns ipa_context on success, NULL on failure. */ @@ -393,13 +354,53 @@ return -EINVAL; }
-/*! poll the IPAd (may be called in regular intervals or on purpose). - * \param[inout] ctx pointer to ipa_context. - * \returns positive on success, negative on error (see also enum ipa_poll_rc). */ -int ipa_poll(struct ipa_context *ctx) +static int eim_init(struct ipa_context *ctx, int index) +{ + struct ipa_es10b_eim_cfg_data *eim_cfg_data = NULL; + struct EimConfigurationData *eim_cfg_data_item = NULL; + int rc = -EINVAL; + + eim_cfg_data = ipa_es10b_get_eim_cfg_data(ctx); + if (!eim_cfg_data) { + IPA_LOGP(SIPA, LERROR, "cannot read EimConfigurationData from eUICC\n"); + goto error; + } + + /* In case no preferred_eim_id is set, the eIM configuration item of the given index will be pulled from the list */ + rc = ipa_es10b_get_eim_cfg_data_filter(&eim_cfg_data_item, eim_cfg_data, ctx->cfg->preferred_eim_id, index); + if (rc) { + if (rc != -ENOENT) + IPA_LOGP(SIPA, LERROR, "no suitable EimConfigurationData item present.\n"); + goto error; + } + + IPA_FREE(ctx->eim_id); + ctx->eim_id = IPA_STR_FROM_ASN(&eim_cfg_data_item->eimId); + if (!ctx->eim_id) { + IPA_LOGP(SIPA, LERROR, "unable to allocate memory\n"); + goto error; + } + + IPA_FREE(ctx->eim_fqdn); + if (eim_cfg_data_item->eimFqdn) { + ctx->eim_fqdn = IPA_STR_FROM_ASN(eim_cfg_data_item->eimFqdn); + } else { + IPA_LOGP(SIPA, LERROR, "unable to allocate memory\n"); + goto error; + } + + rc = 0; +error: + ipa_es10b_get_eim_cfg_data_free(eim_cfg_data); + return rc; +} + +static int ipa_poll_eim_package(struct ipa_context *ctx) { int rc;
+ IPA_LOGP(SIPA, LINFO, "Polling eIM "%s"\n", ctx->eim_id); + /* Reset canaries */ ctx->check_scard = false; ctx->check_http = false; @@ -448,6 +449,94 @@ } }
+static int ipa_poll_eim(struct ipa_context *ctx, int index) +{ + int rc = 0; + + while (ctx->poll_running) { + IPA_LOGP(SIPA, LINFO, "-----------------------------8<-----------------------------\n"); + rc = ipa_poll_eim_package(ctx); + + switch (rc) { + case IPA_POLL_AGAIN_WHEN_ONLINE: + /* ipa_poll asks us to wait with the next poll cycle until we have a stable IP + * connection. In this example we assume that IP connectivity is always available. */ + IPA_LOGP(SIPA, LINFO, "poll cycle continues normally (profile change)\n"); + rc = 0; + break; + case IPA_POLL_AGAIN: + /* ipa_poll asks us to continue polling normally */ + rc = 0; + if (ctx->cfg->one_euicc_pkg_only) { + IPA_LOGP(SIPA, LINFO, "forcefully stopping poll cycle upon user decision!\n"); + goto leave; + } else { + IPA_LOGP(SIPA, LINFO, "poll cycle continues normally\n"); + break; + } + case IPA_POLL_AGAIN_LATER: + /* ipa_poll tells us that we may poll less frequently, so just exit. */ + IPA_LOGP(SIPA, LINFO, "poll cycle ends normally\n"); + rc = 0; + goto leave; + default: + /* We got a negative return code from ipa_poll. This means something does not work + * normally. In a productive setup we would continue calling ipa_poll a few more times + * to see if the cause is a temporary problem. After that we would free the context + * using ipa_free_ctx and start over. */ + IPA_LOGP(SIPA, LERROR, "poll cycle ends due to error (%d)\n", rc); + rc = -EINVAL; + goto leave; + } + } + +leave: + return rc; +} + +/*! run the poll loop of the IPAd. + * \param[inout] ctx pointer to ipa_context. + * \returns positive on success or when polling all eIMs, negative on error (see also enum ipa_poll_rc). */ +int ipa_poll(struct ipa_context *ctx) +{ + int rc, index; + + ctx->poll_running = true; + + /* Loop through all eIM, if no preferred eIM ID is specified. */ + for (index = 0; ; index++) { + IPA_LOGP(SIPA, LINFO, "-----------------------------8<-----------------------------\n"); + rc = eim_init(ctx, index); + if (rc < 0) { + if (rc == -ENOENT) { + IPA_LOGP(SIPA, LINFO, "all eIMs polled!\n"); + break; + } + IPA_LOGP(SIPA, LERROR, "eIM initialization failed!\n"); + return rc; + } + + rc = ipa_poll_eim(ctx, index); + + if (!ctx->poll_running) { + IPA_LOGP(SIPA, LINFO, "polling aborted by user!\n"); + break; + } + + if (ctx->cfg->preferred_eim_id) + return rc; + } + + return 0; +} + +/*! abort IPAd polling (may be called from signal handler). */ +void ipa_abort(struct ipa_context *ctx) +{ + ctx->poll_running = false; +} + + /*! close connection towards the eIM. * \param[inout] ctx pointer to ipa_context. */ void ipa_close(struct ipa_context *ctx) diff --git a/src/ipa/main.c b/src/ipa/main.c index 2b15d9b..183a584 100644 --- a/src/ipa/main.c +++ b/src/ipa/main.c @@ -35,7 +35,8 @@ OPER_GET_CONN_PARAMS, };
-bool running = true; +/* IPA context, used in main() and signal handler */ +static struct ipa_context *ctx = NULL;
static void print_help(const char *prog_name) { @@ -138,13 +139,12 @@
static void sig_usr1(int signum) { - running = false; + ipa_abort(ctx); }
int main(int argc, char **argv) { struct ipa_config cfg = { 0 }; - struct ipa_context *ctx = NULL; int opt; int rc; enum operation operation = OPER_GET_EIM_PACKAGE; @@ -152,7 +152,6 @@ char *getopt_nvstate_path = DEFAULT_NVSTATE_PATH; struct ipa_buf *nvstate_load = NULL; struct ipa_buf *nvstate_save = NULL; - bool getopt_one_euicc_pkg_only = false;
signal(SIGUSR1, sig_usr1);
@@ -209,7 +208,7 @@ cfg.esipa_req_retries = atoi(optarg); break; case '1': - getopt_one_euicc_pkg_only = true; + cfg.one_euicc_pkg_only = true; break; case 'D': cfg.device_capabilities = strtoul(optarg, NULL, 0); @@ -300,50 +299,7 @@
switch (operation) { case OPER_GET_EIM_PACKAGE: - IPA_LOGP(SMAIN, LINFO, "-----------------------------8<-----------------------------\n"); - rc = eim_init(ctx); - if (rc < 0) { - IPA_LOGP(SMAIN, LERROR, "eIM initialization failed!\n"); - rc = -EINVAL; - goto leave; - } - - while (running) { - IPA_LOGP(SMAIN, LINFO, "-----------------------------8<-----------------------------\n"); - rc = ipa_poll(ctx); - - switch (rc) { - case IPA_POLL_AGAIN_WHEN_ONLINE: - /* ipa_poll asks us to wait with the next poll cycle until we have a stable IP - * connection. In this example we assume that IP connectivity is always available. */ - IPA_LOGP(SMAIN, LINFO, "poll cycle continues normally (profile change)\n"); - rc = 0; - break; - case IPA_POLL_AGAIN: - /* ipa_poll asks us to continue polling normally */ - rc = 0; - if (getopt_one_euicc_pkg_only) { - IPA_LOGP(SMAIN, LINFO, "forcefully stopping poll cycle upon user decision!\n"); - goto leave; - } else { - IPA_LOGP(SMAIN, LINFO, "poll cycle continues normally\n"); - break; - } - case IPA_POLL_AGAIN_LATER: - /* ipa_poll tells us that we may poll less frequently, so just exit. */ - IPA_LOGP(SMAIN, LERROR, "poll cycle ends normally\n"); - rc = 0; - goto leave; - default: - /* We got a negative return code from ipa_poll. This means something does not work - * normally. In a productive setup we would continue calling ipa_poll a few more times - * to see if the cause is a temporary problem. After that we would free the context - * using ipa_free_ctx and start over. */ - IPA_LOGP(SMAIN, LERROR, "poll cycle ends due to error (%d)\n", rc); - rc = -EINVAL; - goto leave; - } - } + rc = ipa_poll(ctx); break; case OPER_ADD_INITIAL_EIM: /* Load initial eIM configuration */