diff options
Diffstat (limited to 'src/sim/core.c')
-rw-r--r-- | src/sim/core.c | 118 |
1 files changed, 113 insertions, 5 deletions
diff --git a/src/sim/core.c b/src/sim/core.c index b93633c1..8b2d6f92 100644 --- a/src/sim/core.c +++ b/src/sim/core.c @@ -1,7 +1,7 @@ /*! \file core.c * Core routines for SIM/UICC/USIM access. */ /* - * (C) 2012 by Harald Welte <laforge@gnumonks.org> + * (C) 2012-2020 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -27,10 +27,13 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> +#include <errno.h> #include <osmocom/core/talloc.h> #include <osmocom/sim/sim.h> +#include "sim_int.h" + struct osim_decoded_data *osim_file_decode(struct osim_file *file, int len, uint8_t *data) { @@ -154,21 +157,19 @@ add_df_with_ef(struct osim_file_desc *parent, } struct osim_file_desc * -add_adf_with_ef(struct osim_file_desc *parent, +alloc_adf_with_ef(void *ctx, const uint8_t *adf_name, uint8_t adf_name_len, const char *name, const struct osim_file_desc *in, int num) { struct osim_file_desc *df; - df = alloc_df(parent, 0xffff, name); + df = alloc_df(ctx, 0xffff, name); if (!df) return NULL; df->type = TYPE_ADF; df->df_name = adf_name; df->df_name_len = adf_name_len; - df->parent = parent; - llist_add_tail(&df->list, &parent->child_list); add_filedesc(df, in, num); return df; @@ -187,6 +188,22 @@ osim_file_desc_find_name(struct osim_file_desc *parent, const char *name) } struct osim_file_desc * +osim_file_desc_find_aid(struct osim_file_desc *parent, const uint8_t *aid, uint8_t aid_len) +{ + struct osim_file_desc *ofd; + llist_for_each_entry(ofd, &parent->child_list, list) { + if (ofd->type != TYPE_ADF) + continue; + if (aid_len > ofd->df_name_len) + continue; + if (!memcmp(ofd->df_name, aid, aid_len)) { + return ofd; + } + } + return NULL; +} + +struct osim_file_desc * osim_file_desc_find_fid(struct osim_file_desc *parent, uint16_t fid) { struct osim_file_desc *ofd; @@ -213,6 +230,88 @@ osim_file_desc_find_sfid(struct osim_file_desc *parent, uint8_t sfid) } +/*********************************************************************** + * Application Profiles + Applications + ***********************************************************************/ + +static LLIST_HEAD(g_app_profiles); + +/*! Register an application profile. Typically called at early start-up. */ +void osim_app_profile_register(struct osim_card_app_profile *aprof) +{ + OSMO_ASSERT(!osim_app_profile_find_by_name(aprof->name)); + OSMO_ASSERT(!osim_app_profile_find_by_aid(aprof->aid, aprof->aid_len)); + llist_add_tail(&aprof->list, &g_app_profiles); +} + +/*! Find any registered application profile based on its name (e.g. "ADF.USIM") */ +const struct osim_card_app_profile * +osim_app_profile_find_by_name(const char *name) +{ + struct osim_card_app_profile *ap; + + llist_for_each_entry(ap, &g_app_profiles, list) { + if (!strcmp(name, ap->name)) + return ap; + } + return NULL; +} + +/*! Find any registered application profile based on its AID */ +const struct osim_card_app_profile * +osim_app_profile_find_by_aid(const uint8_t *aid, uint8_t aid_len) +{ + struct osim_card_app_profile *ap; + + llist_for_each_entry(ap, &g_app_profiles, list) { + if (ap->aid_len > aid_len) + continue; + if (!memcmp(ap->aid, aid, ap->aid_len)) + return ap; + } + return NULL; +} + +struct osim_card_app_hdl * +osim_card_hdl_find_app(struct osim_card_hdl *ch, const uint8_t *aid, uint8_t aid_len) +{ + struct osim_card_app_hdl *ah; + + if (aid_len > MAX_AID_LEN) + return NULL; + + llist_for_each_entry(ah, &ch->apps, list) { + if (!memcmp(ah->aid, aid, aid_len)) + return ah; + } + return NULL; +} + +/*! Add an application to a given card */ +int osim_card_hdl_add_app(struct osim_card_hdl *ch, const uint8_t *aid, uint8_t aid_len, + const char *label) +{ + struct osim_card_app_hdl *ah; + + if (aid_len > MAX_AID_LEN) + return -EINVAL; + + if (osim_card_hdl_find_app(ch, aid, aid_len)) + return -EEXIST; + + ah = talloc_zero(ch, struct osim_card_app_hdl); + if (!ah) + return -ENOMEM; + + memcpy(ah->aid, aid, aid_len); + ah->aid_len = aid_len; + ah->prof = osim_app_profile_find_by_aid(ah->aid, ah->aid_len); + if (label) + ah->label = talloc_strdup(ah, label); + llist_add_tail(&ah->list, &ch->apps); + return 0; +} + /*! Generate an APDU message and initialize APDU command header * \param[in] cla CLASS byte * \param[in] ins INSTRUCTION byte @@ -349,3 +448,12 @@ int default_decode(struct osim_decoded_data *dd, return 0; } + +int osim_init(void *ctx) +{ + osim_app_profile_register(osim_aprof_usim(ctx)); + osim_app_profile_register(osim_aprof_isim(ctx)); + osim_app_profile_register(osim_aprof_hpsim(ctx)); + + return 0; +} |