jolly has submitted this change. ( https://gerrit.osmocom.org/c/onomondo-ipa/+/43042?usp=email )
Change subject: V1.2: Add function ES10b.ReturnFromFallback ......................................................................
V1.2: Add function ES10b.ReturnFromFallback
Add new library function to return from fallback profile on IoT eUICC. Also add an option to the command line interface to call the library function. The optional refresh flag may be set via command line option.
The function cannot be emulated with non-IoT eUICC.
Reference: SGP.32 Section 5.9.21
Related: SYS#8101 Change-Id: Ib49a8ef3a5ea5639d881ca51eaeeea24f083fe0e --- M asn1/SGP32Definitions.asn M include/onomondo/ipa/ipad.h M src/ipa/libasn/CMakeLists.txt A src/ipa/libasn/ReturnFromFallbackRequest.c A src/ipa/libasn/ReturnFromFallbackRequest.h A src/ipa/libasn/ReturnFromFallbackResponse.c A src/ipa/libasn/ReturnFromFallbackResponse.h M src/ipa/libipa/CMakeLists.txt A src/ipa/libipa/es10b_ret_from_fallback.c A src/ipa/libipa/es10b_ret_from_fallback.h M src/ipa/libipa/ipad.c M src/ipa/main.c 12 files changed, 378 insertions(+), 0 deletions(-)
Approvals: Jenkins Builder: Verified dexter: Looks good to me, approved laforge: Looks good to me, but someone else must approve
diff --git a/asn1/SGP32Definitions.asn b/asn1/SGP32Definitions.asn index 99b26e6..9f3ce9c 100644 --- a/asn1/SGP32Definitions.asn +++ b/asn1/SGP32Definitions.asn @@ -612,6 +612,24 @@ } -- ASN1STOP
+-- Section 5.9.21 +-- ASN1START +ReturnFromFallbackRequest ::= [94] SEQUENCE { -- Tag 'BF5E' + refreshFlag BOOLEAN -- indicating whether REFRESH is required +} +-- ASN1STOP +-- ASN1START +ReturnFromFallbackResponse ::= [94] SEQUENCE { -- Tag 'BF5E' + returnFromFallbackResult [0] INTEGER { + ok(0), + catBusy(5), + fallbackNotAvailable(6), -- Fallback Attribute not set + commandError(7), + undefinedError(127) + } +} +-- ASN1STOP + -- Section 5.9.25 -- ASN1START SGP32-SetDefaultDpAddressRequest ::= [101] SEQUENCE { -- Tag 'BF65' diff --git a/include/onomondo/ipa/ipad.h b/include/onomondo/ipa/ipad.h index 55c64e3..8474097 100644 --- a/include/onomondo/ipa/ipad.h +++ b/include/onomondo/ipa/ipad.h @@ -95,6 +95,7 @@ int ipa_euicc_mem_rst(struct ipa_context *ctx, bool operatnl_profiles, bool test_profiles, bool default_smdp_addr, bool eim_cfg_data, bool immediate_enable_cfg); int ipa_execute_fallback_mechanism(struct ipa_context *ctx); +int ipa_return_from_fallback(struct ipa_context *ctx); int ipa_poll(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/libasn/CMakeLists.txt b/src/ipa/libasn/CMakeLists.txt index 166d7f2..859578a 100644 --- a/src/ipa/libasn/CMakeLists.txt +++ b/src/ipa/libasn/CMakeLists.txt @@ -780,6 +780,10 @@ RetrieveNotificationsListRequest.h RetrieveNotificationsListResponse.c RetrieveNotificationsListResponse.h +ReturnFromFallbackRequest.c +ReturnFromFallbackRequest.h +ReturnFromFallbackResponse.c +ReturnFromFallbackResponse.h RollbackProfileResult.c RollbackProfileResult.h RspCapability.c diff --git a/src/ipa/libasn/ReturnFromFallbackRequest.c b/src/ipa/libasn/ReturnFromFallbackRequest.c new file mode 100644 index 0000000..69bd3a3 --- /dev/null +++ b/src/ipa/libasn/ReturnFromFallbackRequest.c @@ -0,0 +1,51 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "SGP32Definitions" + * found in "../../../asn1/SGP32Definitions.asn" + * `asn1c -fcompound-names -no-gen-example` + */ + +#include "ReturnFromFallbackRequest.h" + +static asn_TYPE_member_t asn_MBR_ReturnFromFallbackRequest_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ReturnFromFallbackRequest, refreshFlag), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, + { 0, 0, 0 }, + 0, 0, /* No default value */ + "refreshFlag" + }, +}; +static const ber_tlv_tag_t asn_DEF_ReturnFromFallbackRequest_tags_1[] = { + (ASN_TAG_CLASS_CONTEXT | (94 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_ReturnFromFallbackRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* refreshFlag */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ReturnFromFallbackRequest_specs_1 = { + sizeof(struct ReturnFromFallbackRequest), + offsetof(struct ReturnFromFallbackRequest, _asn_ctx), + asn_MAP_ReturnFromFallbackRequest_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + 1, /* First extension addition */ +}; +asn_TYPE_descriptor_t asn_DEF_ReturnFromFallbackRequest = { + "ReturnFromFallbackRequest", + "ReturnFromFallbackRequest", + &asn_OP_SEQUENCE, + asn_DEF_ReturnFromFallbackRequest_tags_1, + sizeof(asn_DEF_ReturnFromFallbackRequest_tags_1) + /sizeof(asn_DEF_ReturnFromFallbackRequest_tags_1[0]) - 1, /* 1 */ + asn_DEF_ReturnFromFallbackRequest_tags_1, /* Same as above */ + sizeof(asn_DEF_ReturnFromFallbackRequest_tags_1) + /sizeof(asn_DEF_ReturnFromFallbackRequest_tags_1[0]), /* 2 */ + { 0, 0, SEQUENCE_constraint }, + asn_MBR_ReturnFromFallbackRequest_1, + 1, /* Elements count */ + &asn_SPC_ReturnFromFallbackRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/ipa/libasn/ReturnFromFallbackRequest.h b/src/ipa/libasn/ReturnFromFallbackRequest.h new file mode 100644 index 0000000..5a43ff0 --- /dev/null +++ b/src/ipa/libasn/ReturnFromFallbackRequest.h @@ -0,0 +1,42 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "SGP32Definitions" + * found in "../../../asn1/SGP32Definitions.asn" + * `asn1c -fcompound-names -no-gen-example` + */ + +#ifndef _ReturnFromFallbackRequest_H_ +#define _ReturnFromFallbackRequest_H_ + + +#include <asn_application.h> + +/* Including external dependencies */ +#include <BOOLEAN.h> +#include <constr_SEQUENCE.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* ReturnFromFallbackRequest */ +typedef struct ReturnFromFallbackRequest { + BOOLEAN_t refreshFlag; + /* + * This type is extensible, + * possible extensions are below. + */ + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ReturnFromFallbackRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ReturnFromFallbackRequest; + +#ifdef __cplusplus +} +#endif + +#endif /* _ReturnFromFallbackRequest_H_ */ +#include <asn_internal.h> diff --git a/src/ipa/libasn/ReturnFromFallbackResponse.c b/src/ipa/libasn/ReturnFromFallbackResponse.c new file mode 100644 index 0000000..a1d21ce --- /dev/null +++ b/src/ipa/libasn/ReturnFromFallbackResponse.c @@ -0,0 +1,51 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "SGP32Definitions" + * found in "../../../asn1/SGP32Definitions.asn" + * `asn1c -fcompound-names -no-gen-example` + */ + +#include "ReturnFromFallbackResponse.h" + +static asn_TYPE_member_t asn_MBR_ReturnFromFallbackResponse_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ReturnFromFallbackResponse, returnFromFallbackResult), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + 0, + { 0, 0, 0 }, + 0, 0, /* No default value */ + "returnFromFallbackResult" + }, +}; +static const ber_tlv_tag_t asn_DEF_ReturnFromFallbackResponse_tags_1[] = { + (ASN_TAG_CLASS_CONTEXT | (94 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_ReturnFromFallbackResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* returnFromFallbackResult */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ReturnFromFallbackResponse_specs_1 = { + sizeof(struct ReturnFromFallbackResponse), + offsetof(struct ReturnFromFallbackResponse, _asn_ctx), + asn_MAP_ReturnFromFallbackResponse_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + 1, /* First extension addition */ +}; +asn_TYPE_descriptor_t asn_DEF_ReturnFromFallbackResponse = { + "ReturnFromFallbackResponse", + "ReturnFromFallbackResponse", + &asn_OP_SEQUENCE, + asn_DEF_ReturnFromFallbackResponse_tags_1, + sizeof(asn_DEF_ReturnFromFallbackResponse_tags_1) + /sizeof(asn_DEF_ReturnFromFallbackResponse_tags_1[0]) - 1, /* 1 */ + asn_DEF_ReturnFromFallbackResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_ReturnFromFallbackResponse_tags_1) + /sizeof(asn_DEF_ReturnFromFallbackResponse_tags_1[0]), /* 2 */ + { 0, 0, SEQUENCE_constraint }, + asn_MBR_ReturnFromFallbackResponse_1, + 1, /* Elements count */ + &asn_SPC_ReturnFromFallbackResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/ipa/libasn/ReturnFromFallbackResponse.h b/src/ipa/libasn/ReturnFromFallbackResponse.h new file mode 100644 index 0000000..c4a7ae0 --- /dev/null +++ b/src/ipa/libasn/ReturnFromFallbackResponse.h @@ -0,0 +1,51 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "SGP32Definitions" + * found in "../../../asn1/SGP32Definitions.asn" + * `asn1c -fcompound-names -no-gen-example` + */ + +#ifndef _ReturnFromFallbackResponse_H_ +#define _ReturnFromFallbackResponse_H_ + + +#include <asn_application.h> + +/* Including external dependencies */ +#include <NativeInteger.h> +#include <constr_SEQUENCE.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ReturnFromFallbackResponse__returnFromFallbackResult { + ReturnFromFallbackResponse__returnFromFallbackResult_ok = 0, + ReturnFromFallbackResponse__returnFromFallbackResult_catBusy = 5, + ReturnFromFallbackResponse__returnFromFallbackResult_fallbackNotAvailable = 6, + ReturnFromFallbackResponse__returnFromFallbackResult_commandError = 7, + ReturnFromFallbackResponse__returnFromFallbackResult_undefinedError = 127 +} e_ReturnFromFallbackResponse__returnFromFallbackResult; + +/* ReturnFromFallbackResponse */ +typedef struct ReturnFromFallbackResponse { + long returnFromFallbackResult; + /* + * This type is extensible, + * possible extensions are below. + */ + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ReturnFromFallbackResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ReturnFromFallbackResponse; + +#ifdef __cplusplus +} +#endif + +#endif /* _ReturnFromFallbackResponse_H_ */ +#include <asn_internal.h> diff --git a/src/ipa/libipa/CMakeLists.txt b/src/ipa/libipa/CMakeLists.txt index a46e22b..45d8f4a 100644 --- a/src/ipa/libipa/CMakeLists.txt +++ b/src/ipa/libipa/CMakeLists.txt @@ -21,6 +21,7 @@ es10b_retr_notif_from_lst.c es10b_rm_notif_from_lst.c es10b_exec_fallback_mech.c + es10b_ret_from_fallback.c es10c_delete_prfle.c es10c_disable_prfle.c es10c_enable_prfle.c diff --git a/src/ipa/libipa/es10b_ret_from_fallback.c b/src/ipa/libipa/es10b_ret_from_fallback.c new file mode 100644 index 0000000..7d9a835 --- /dev/null +++ b/src/ipa/libipa/es10b_ret_from_fallback.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2026 sysmocom - s.f.m.c. GmbH. All rights reserved. + * + * SPDX-License-Identifier: AGPL-3.0-only + * + * Author: Philipp Maier pmaier@sysmocom.de / sysmocom - s.f.m.c. GmbH + * Andreas Eversberg aeversberg@sysmocom.de / sysmocom - s.f.m.c. GmbH + * + * See also: GSMA SGP.22, 5.9.21: Function (ES10b): ReturnFromFallback + */ + +#include <stdio.h> +#include <assert.h> +#include <onomondo/ipa/utils.h> +#include "context.h" +#include "utils.h" +#include "euicc.h" +#include "es10x.h" +#include "es10b_ret_from_fallback.h" + +static const struct num_str_map error_code_strings[] = { + { ReturnFromFallbackResponse__returnFromFallbackResult_ok, "ok" }, + { ReturnFromFallbackResponse__returnFromFallbackResult_catBusy, "catBusy" }, + { ReturnFromFallbackResponse__returnFromFallbackResult_fallbackNotAvailable, "fallbackNotAvailable" }, + { ReturnFromFallbackResponse__returnFromFallbackResult_commandError, "commandError" }, + { ReturnFromFallbackResponse__returnFromFallbackResult_undefinedError, "undefinedError" }, + + { 0, NULL } +}; + +static int dec_ret_from_fallback_res(struct ipa_es10b_ret_from_fallback_res *res, const struct ipa_buf *es10b_res) +{ + struct ReturnFromFallbackResponse *asn = NULL; + + asn = ipa_es10x_res_dec(&asn_DEF_ReturnFromFallbackResponse, es10b_res, "ReturnFromFallback"); + if (!asn) + return -EINVAL; + + if (asn->returnFromFallbackResult != ReturnFromFallbackResponse__returnFromFallbackResult_ok) { + IPA_LOGP_ES10X("ReturnFromFallback", LERROR, "function failed with error code %ld=%s!\n", + asn->returnFromFallbackResult, + ipa_str_from_num(error_code_strings, asn->returnFromFallbackResult, "(unknown)")); + } else { + IPA_LOGP_ES10X("ReturnFromFallback", LERROR, "function succeeded with status code %ld=%s!\n", + asn->returnFromFallbackResult, + ipa_str_from_num(error_code_strings, asn->returnFromFallbackResult, "(unknown)")); + } + + res->res = asn; + return 0; +} + +static struct ReturnFromFallbackResponse *generate_ret_from_fallback_err(void) +{ + struct ReturnFromFallbackResponse *res = IPA_ALLOC_ZERO(struct ReturnFromFallbackResponse); + + assert(res); + res->returnFromFallbackResult = ReturnFromFallbackResponse__returnFromFallbackResult_undefinedError; + return res; +} + +/*! Function (Es10b): ReturnFromFallback. + * \param[inout] ctx pointer to ipa_context. + * \param[in] refresh_flag send a CAT refresh after enabling profile. + * \returns pointer newly allocated struct with function result, NULL on error. */ +struct ipa_es10b_ret_from_fallback_res *ipa_es10b_ret_from_fallback(struct ipa_context *ctx, bool refresh_flag) +{ + struct ipa_buf *es10b_req = NULL; + struct ipa_buf *es10b_res = NULL; + struct ReturnFromFallbackRequest req = { 0 }; + struct ipa_es10b_ret_from_fallback_res *res = IPA_ALLOC_ZERO(struct ipa_es10b_ret_from_fallback_res); + int rc; + + if (ctx->cfg->iot_euicc_emu_enabled) { + IPA_LOGP_ES10X("ReturnFromFallback", LERROR, + "Unable to emulate switching back from fallback profile.\n"); + res->res = generate_ret_from_fallback_err(); + return res; + } + + req.refreshFlag = refresh_flag; + + es10b_req = ipa_es10x_req_enc(&asn_DEF_ReturnFromFallbackRequest, &req, "ReturnFromFallback"); + if (!es10b_req) { + IPA_LOGP_ES10X("ReturnFromFallback", LERROR, "unable to encode Es10b request\n"); + goto error; + } + + es10b_res = ipa_euicc_transceive_es10x(ctx, es10b_req); + if (!es10b_res) { + IPA_LOGP_ES10X("ReturnFromFallback", LERROR, "no Es10b response\n"); + goto error; + } + + rc = dec_ret_from_fallback_res(res, es10b_res); + if (rc < 0) + goto error; + + IPA_FREE(es10b_req); + IPA_FREE(es10b_res); + return res; +error: + IPA_FREE(es10b_req); + IPA_FREE(es10b_res); + ipa_es10b_ret_from_fallback_res_free(res); + return NULL; +} + +/*! Free results of function (Es10b): ReturnFromFallback. + * \param[in] res pointer to function result. */ +void ipa_es10b_ret_from_fallback_res_free(struct ipa_es10b_ret_from_fallback_res *res) +{ + IPA_ES10X_RES_FREE(asn_DEF_ReturnFromFallbackResponse, res); +} diff --git a/src/ipa/libipa/es10b_ret_from_fallback.h b/src/ipa/libipa/es10b_ret_from_fallback.h new file mode 100644 index 0000000..ff93b35 --- /dev/null +++ b/src/ipa/libipa/es10b_ret_from_fallback.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026 sysmocom - s.f.m.c. GmbH. All rights reserved. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#pragma once + +#include <ReturnFromFallbackRequest.h> +#include <ReturnFromFallbackResponse.h> +struct ipa_context; + +struct ipa_es10b_ret_from_fallback_res { + struct ReturnFromFallbackResponse *res; +}; + +struct ipa_es10b_ret_from_fallback_res *ipa_es10b_ret_from_fallback(struct ipa_context *ctx, bool refresh_flag); +void ipa_es10b_ret_from_fallback_res_free(struct ipa_es10b_ret_from_fallback_res *res); diff --git a/src/ipa/libipa/ipad.c b/src/ipa/libipa/ipad.c index 0dffd12..d151969 100644 --- a/src/ipa/libipa/ipad.c +++ b/src/ipa/libipa/ipad.c @@ -26,6 +26,7 @@ #include "es10b_euicc_mem_rst.h" #include "es10b_load_euicc_pkg.h" #include "es10b_exec_fallback_mech.h" +#include "es10b_ret_from_fallback.h" #include "proc_euicc_pkg_dwnld_exec.h" #include "proc_notif_delivery.h"
@@ -284,6 +285,24 @@ return rc; }
+/*! Trigger enabling of emergency profile. + * \param[inout] ctx pointer to ipa_context. + * \returns 0 on success, negative on error. */ +int ipa_return_from_fallback(struct ipa_context *ctx) +{ + struct ipa_es10b_ret_from_fallback_res *res; + int rc = -EINVAL; + + res = ipa_es10b_ret_from_fallback(ctx, ctx->cfg->refresh_flag); + if (!res) + return -EIO; + if (res->res->returnFromFallbackResult == ReturnFromFallbackResponse__returnFromFallbackResult_ok) + rc = 0; + ipa_es10b_ret_from_fallback_res_free(res); + + return rc; +} + static int check_canaries(struct ipa_context *ctx) { if (ctx->check_http) diff --git a/src/ipa/main.c b/src/ipa/main.c index 39412c3..bf54f56 100644 --- a/src/ipa/main.c +++ b/src/ipa/main.c @@ -29,6 +29,7 @@ OPER_ADD_INITIAL_EIM, OPER_EUICC_MEMORY_RESET, OPER_EXEC_FALLBACK_MECH, + OPER_RETURN_FROM_FALLBACK, };
bool running = true; @@ -70,6 +71,7 @@ printf(" add-initial-eim PATH ........ set initial eIM configuration from given file\n"); printf(" euicc-memory-reset .......... reset eUICC memory\n"); printf(" execute-fallback-mechanism .. Trigger enabling of fallback profile\n"); + printf(" return-from-fallback ........ Trigger return from fallback profile to previous profile\n"); }
struct ipa_buf *load_ber_from_file(char *dir, char *file) @@ -240,6 +242,8 @@ operation = OPER_EUICC_MEMORY_RESET; } else if (!strcmp(argv[optind], "execute-fallback-mechanism")) { operation = OPER_EXEC_FALLBACK_MECH; + } else if (!strcmp(argv[optind], "return-from-fallback")) { + operation = OPER_RETURN_FROM_FALLBACK; } else if (!!strcmp(argv[optind], "get-eim-package")) { printf("unknown operation: %s\n", argv[optind]); exit(-1); @@ -355,6 +359,10 @@ /* Trigger enabling of fallback profile */ ipa_execute_fallback_mechanism(ctx); break; + case OPER_RETURN_FROM_FALLBACK: + /* Trigger return from fallback profile to previous profile */ + ipa_return_from_fallback(ctx); + break; }
leave: