From f972ba88f1bd570c0b511f90c249816029ca701a Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 6 Nov 2017 13:07:38 -0800 Subject: [PATCH] simfs: read files from specific AID's The simfs atom could not read EF's that did not exist on the 'default' ADF directory. This implements a new way to read EF's that exist on a given AID. A new fs object/context can be initialized for a given AID. Using this fs context with the existing read file API will read from that AID rather than the default ADF. --- src/simfs.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++------ src/simfs.h | 3 + 2 files changed, 155 insertions(+), 18 deletions(-) diff --git a/src/simfs.c b/src/simfs.c index 37a232a7..efee13e5 100644 --- a/src/simfs.c +++ b/src/simfs.c @@ -74,12 +74,10 @@ struct sim_fs_op { struct ofono_sim_context *context; }; -static void sim_fs_op_free(gpointer pointer) -{ - struct sim_fs_op *node = pointer; - g_free(node->buffer); - g_free(node); -} +struct ofono_sim_context { + struct sim_fs *fs; + struct ofono_watchlist *file_watches; +}; struct sim_fs { GQueue *op_q; @@ -89,8 +87,26 @@ struct sim_fs { struct ofono_sim *sim; const struct ofono_sim_driver *driver; GSList *contexts; + struct ofono_sim_aid_session *session; + int session_id; + unsigned int watch_id; }; +static void sim_fs_op_free(gpointer pointer) +{ + struct sim_fs_op *node = pointer; + struct sim_fs *fs = node->context->fs; + + /* only release the session if there are no pending reads */ + if (fs->session && g_queue_is_empty(fs->op_q)) { + __ofono_sim_remove_session_watch(fs->session, fs->watch_id); + fs->watch_id = 0; + } + + g_free(node->buffer); + g_free(node); +} + void sim_fs_free(struct sim_fs *fs) { if (fs == NULL) @@ -121,11 +137,6 @@ struct file_watch { int ef; }; -struct ofono_sim_context { - struct sim_fs *fs; - struct ofono_watchlist *file_watches; -}; - struct sim_fs *sim_fs_new(struct ofono_sim *sim, const struct ofono_sim_driver *driver) { @@ -156,6 +167,23 @@ struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs) return context; } +struct ofono_sim_context *sim_fs_context_new_with_aid(struct sim_fs *fs, + unsigned char *aid) +{ + struct ofono_sim_context *context = sim_fs_context_new(fs); + + if (context == NULL) + return NULL; + + context->fs->session = __ofono_sim_get_session_by_aid(fs->sim, aid); + if (!context->fs->session) { + sim_fs_context_free(context); + return NULL; + } + + return context; +} + void sim_fs_context_free(struct ofono_sim_context *context) { struct sim_fs *fs = context->fs; @@ -805,6 +833,92 @@ error: return FALSE; } +static void sim_fs_read_session_cb(const struct ofono_error *error, + const unsigned char *sdata, int length, void *data) +{ + struct sim_fs *fs = data; + struct sim_fs_op *op = g_queue_peek_head(fs->op_q); + ofono_sim_file_read_cb_t cb; + + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { + sim_fs_op_error(fs); + return; + } + + cb = op->cb; + cb(TRUE, length, 0, sdata, length, op->userdata); + + sim_fs_end_current(fs); +} + +static void session_read_info_cb(const struct ofono_error *error, + int filelength, + enum ofono_sim_file_structure structure, + int recordlength, + const unsigned char access[3], + unsigned char file_status, + void *data) +{ + struct sim_fs *fs = data; + struct sim_fs_op *op = g_queue_peek_head(fs->op_q); + + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { + sim_fs_op_error(fs); + return; + } + + sim_fs_op_cache_fileinfo(fs, error, filelength, structure, recordlength, + access, file_status); + + if (op->info_only) { + sim_fs_read_info_cb_t cb = op->cb; + + cb(1, file_status, filelength, recordlength, op->userdata); + + sim_fs_end_current(fs); + return; + } + + if (op->structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT) { + if (!fs->driver->session_read_binary) { + sim_fs_op_error(fs); + return; + } + + fs->driver->session_read_binary(fs->sim, fs->session_id, + op->id, op->offset, filelength, op->path, + op->path_len, sim_fs_read_session_cb, fs); + } else { + if (!fs->driver->session_read_record) { + sim_fs_op_error(fs); + return; + } + + fs->driver->session_read_record(fs->sim, fs->session_id, + op->id, op->offset, recordlength, op->path, + op->path_len, sim_fs_read_session_cb, fs); + } +} + +static void get_session_cb(ofono_bool_t active, int session_id, + void *data) +{ + struct sim_fs *fs = data; + struct sim_fs_op *op; + + if (!active) { + sim_fs_op_error(fs); + return; + } + + op = g_queue_peek_head(fs->op_q); + + fs->session_id = session_id; + + fs->driver->session_read_info(fs->sim, session_id, op->id, op->path, + op->path_len, session_read_info_cb, fs); +} + static gboolean sim_fs_op_next(gpointer user_data) { struct sim_fs *fs = user_data; @@ -827,10 +941,22 @@ static gboolean sim_fs_op_next(gpointer user_data) if (sim_fs_op_check_cached(fs)) return FALSE; - driver->read_file_info(fs->sim, op->id, - op->path_len ? op->path : NULL, - op->path_len, - sim_fs_op_info_cb, fs); + if (!fs->session) { + driver->read_file_info(fs->sim, op->id, + op->path_len ? op->path : NULL, + op->path_len, + sim_fs_op_info_cb, fs); + } else { + if (fs->watch_id) + fs->driver->session_read_info(fs->sim, + fs->session_id, op->id, + op->path, op->path_len, + session_read_info_cb, fs); + else + fs->watch_id = __ofono_sim_add_session_watch( + fs->session, get_session_cb, + fs, NULL); + } } else { switch (op->structure) { case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT: @@ -914,9 +1040,17 @@ int sim_fs_read(struct ofono_sim_context *context, int id, if (fs->driver == NULL) return -EINVAL; - if (fs->driver->read_file_info == NULL) { - cb(0, 0, 0, NULL, 0, data); - return -ENOSYS; + /* check driver support for session based read */ + if (fs->session) { + if (!fs->driver->session_read_info) { + cb(0, 0, 0, NULL, 0, data); + return -ENOSYS; + } + } else { + if (!fs->driver->read_file_info) { + cb(0, 0, 0, NULL, 0, data); + return -ENOSYS; + } } if (fs->op_q == NULL) diff --git a/src/simfs.h b/src/simfs.h index bb3ab0fd..39af6a37 100644 --- a/src/simfs.h +++ b/src/simfs.h @@ -29,6 +29,9 @@ struct sim_fs *sim_fs_new(struct ofono_sim *sim, const struct ofono_sim_driver *driver); struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs); +struct ofono_sim_context *sim_fs_context_new_with_aid(struct sim_fs *fs, + unsigned char *aid); + unsigned int sim_fs_file_watch_add(struct ofono_sim_context *context, int id, ofono_sim_file_changed_cb_t cb, void *userdata,