All of lore.kernel.org
 help / color / mirror / Atom feed
From: James Prestwood <james.prestwood@linux.intel.com>
To: ofono@ofono.org
Subject: [PATCH 2/3] sim: AID session management
Date: Fri, 03 Nov 2017 13:31:52 -0700	[thread overview]
Message-ID: <1509741113-10669-2-git-send-email-james.prestwood@linux.intel.com> (raw)
In-Reply-To: <1509741113-10669-1-git-send-email-james.prestwood@linux.intel.com>

[-- Attachment #1: Type: text/plain, Size: 8406 bytes --]

Accessing an AID requires opening a channel to that application.
This patch implements session management API's so that other atoms
can access a given AID. Now any atom can get a session ID from the
sim atom. This will either reuse an existing session or open a new
channel. Once done, the atom should release the session which will
automatically close the channel when no atoms are using it.

The major functional change to the sim atom is the AID discovery
phase of initialization. Now, the sim atom is not 'ready' until AID
discovery finishes where before, the sim was 'ready' after the IMSI
had been obtained. If application discovery is not supported then
the the sim atom behaves as it did before.
---
 src/sim.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 238 insertions(+)

diff --git a/src/sim.c b/src/sim.c
index 155f421..e66308f 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -48,6 +48,26 @@
 
 #define SIM_FLAG_READING_SPN	0x1
 
+/*
+ * A new session object will be created if a USim/ISim applications are
+ * found during app discovery. Any concurrent file/logical access to
+ * these applications will share the same session ID.
+ */
+enum session_state {
+	SESSION_STATE_INACTIVE,
+	SESSION_STATE_OPENING,
+	SESSION_STATE_CLOSING,
+	SESSION_STATE_OPEN
+};
+
+struct ofono_sim_aid_session {
+	struct sim_app_record *record;
+	int session_id;
+	struct ofono_sim *sim;
+	struct ofono_watchlist *watches;
+	enum session_state state;
+};
+
 struct ofono_sim {
 	int flags;
 
@@ -114,6 +134,9 @@ struct ofono_sim {
 	void *driver_data;
 	struct ofono_atom *atom;
 	unsigned int hfp_watch;
+
+	GSList *aid_sessions;
+	GSList *aid_list;
 };
 
 struct msisdn_set_request {
@@ -1434,6 +1457,36 @@ static void sim_set_ready(struct ofono_sim *sim)
 	call_state_watches(sim);
 }
 
+static void discover_apps_cb(const struct ofono_error *error,
+		const unsigned char *dataobj,
+		int len, void *data)
+{
+	GSList *iter;
+	struct ofono_sim *sim = data;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+		return;
+
+	sim->aid_list = sim_parse_app_template_entries(dataobj, len);
+
+	iter = sim->aid_list;
+
+	while (iter) {
+		struct sim_app_record *app = iter->data;
+		struct ofono_sim_aid_session *s = g_try_new0(
+				struct ofono_sim_aid_session, 1);
+
+		s->watches = __ofono_watchlist_new(g_free);
+		s->record = app;
+		s->sim = sim;
+		s->session_id = -1;
+		s->state = SESSION_STATE_INACTIVE;
+		sim->aid_sessions = g_slist_prepend(sim->aid_sessions, s);
+
+		iter = g_slist_next(iter);
+	}
+}
+
 static void sim_imsi_obtained(struct ofono_sim *sim, const char *imsi)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
@@ -1844,6 +1897,12 @@ static void sim_initialize_after_pin(struct ofono_sim *sim)
 {
 	sim->context = ofono_sim_context_create(sim);
 
+	/*
+	 * Discover applications on SIM
+	 */
+	if (sim->driver->list_apps)
+		sim->driver->list_apps(sim, discover_apps_cb, sim);
+
 	ofono_sim_read(sim->context, SIM_EFPHASE_FILEID,
 			OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
 			sim_efphase_read_cb, sim);
@@ -2386,6 +2445,15 @@ static void sim_spn_close(struct ofono_sim *sim)
 	sim->spn_dc = NULL;
 }
 
+static void aid_session_free(gpointer data)
+{
+	struct ofono_sim_aid_session *session = data;
+
+	__ofono_watchlist_free(session->watches);
+
+	g_free(session);
+}
+
 static void sim_free_main_state(struct ofono_sim *sim)
 {
 	if (sim->imsi) {
@@ -2450,6 +2518,9 @@ static void sim_free_main_state(struct ofono_sim *sim)
 		ofono_sim_context_free(sim->context);
 		sim->context = NULL;
 	}
+
+	if (sim->aid_sessions)
+		g_slist_free_full(sim->aid_sessions, aid_session_free);
 }
 
 static void sim_free_state(struct ofono_sim *sim)
@@ -3304,3 +3375,170 @@ void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list,
 		}
 	}
 }
+
+static void open_channel_cb(const struct ofono_error *error, int session_id,
+		void *data);
+
+static void close_channel_cb(const struct ofono_error *error, void *data)
+{
+	struct ofono_sim_aid_session *session = data;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+		DBG("session %d failed to close", session->session_id);
+
+	if (g_slist_length(session->watches->items) > 0 &&
+				session->state == SESSION_STATE_OPENING) {
+		/*
+		 * An atom requested to open during a close, we can re-open
+		 * here.
+		 */
+		session->sim->driver->open_channel(session->sim,
+				session->record->aid, open_channel_cb,
+				session);
+		return;
+	}
+
+	session->state = SESSION_STATE_INACTIVE;
+}
+
+static void open_channel_cb(const struct ofono_error *error, int session_id,
+		void *data)
+{
+	struct ofono_sim_aid_session *session = data;
+	GSList *iter = session->watches->items;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		session->state = SESSION_STATE_INACTIVE;
+		goto end;
+	}
+
+	if (g_slist_length(iter) == 0) {
+		/*
+		 * All watchers stopped watching before the channel could open.
+		 * Close the channel.
+		 */
+		session->state = SESSION_STATE_CLOSING;
+		session->sim->driver->close_channel(session->sim,
+				session->session_id, close_channel_cb, session);
+		return;
+	}
+
+	session->session_id = session_id;
+	session->state = SESSION_STATE_OPEN;
+end:
+	/*
+	 * Notify any watchers, after this point, all future watchers will be
+	 * immediately notified with the session ID.
+	 */
+	while (iter) {
+		struct ofono_watchlist_item *item = iter->data;
+		ofono_sim_session_event_cb_t notify = item->notify;
+
+		notify(error, session->session_id, item->notify_data);
+
+		iter = g_slist_next(iter);
+	}
+}
+
+unsigned int ofono_sim_add_session_watch(struct ofono_sim_aid_session *session,
+		ofono_sim_session_event_cb_t notify, void *data,
+		ofono_destroy_func destroy)
+{
+	struct ofono_watchlist_item *item;
+
+	DBG("%p", session);
+
+	if (session == NULL)
+		return 0;
+
+	if (notify == NULL)
+		return 0;
+
+	item = g_new0(struct ofono_watchlist_item, 1);
+
+	item->notify = notify;
+	item->destroy = destroy;
+	item->notify_data = data;
+
+	if (g_slist_length(session->watches->items) == 0 &&
+			session->state == SESSION_STATE_INACTIVE) {
+		/*
+		 * If the session is inactive and there are no watchers, open
+		 * a new session.
+		 */
+		session->state = SESSION_STATE_OPENING;
+		session->sim->driver->open_channel(session->sim,
+				session->record->aid, open_channel_cb,
+				session);
+	} else if (session->state == SESSION_STATE_OPEN) {
+		struct ofono_error e = {
+			.type = OFONO_ERROR_TYPE_NO_ERROR,
+			.error = 0
+		};
+		/*
+		 * Session is already open and available, just call the
+		 * notify callback immediately.
+		 */
+		notify(&e, session->session_id, data);
+	} else if (session->state == SESSION_STATE_CLOSING) {
+		/*
+		 * There is a pending close, the close callback will handle
+		 * re-opening the session.
+		 */
+		session->state = SESSION_STATE_OPENING;
+	}
+
+	return __ofono_watchlist_add_item(session->watches, item);
+}
+
+void ofono_sim_remove_session_watch(struct ofono_sim_aid_session *session,
+		unsigned int id)
+{
+	if (g_slist_length(session->watches->items) == 1) {
+		/* last watcher, close session */
+		session->state = SESSION_STATE_CLOSING;
+		session->sim->driver->close_channel(session->sim,
+				session->session_id, close_channel_cb, session);
+	}
+
+	__ofono_watchlist_remove_item(session->watches, id);
+}
+
+struct ofono_sim_aid_session *ofono_sim_get_session_by_aid(
+		struct ofono_sim *sim, unsigned char *aid)
+{
+	GSList *iter = sim->aid_sessions;
+
+	while (iter) {
+		struct ofono_sim_aid_session *session = iter->data;
+
+		if (!memcmp(session->record->aid, aid, 16))
+			return session;
+
+		iter = g_slist_next(iter);
+	}
+
+	return NULL;
+}
+
+struct ofono_sim_aid_session *ofono_sim_get_session_by_type(
+		struct ofono_sim *sim, enum sim_app_type type)
+{
+	GSList *iter = sim->aid_sessions;
+
+	while (iter) {
+		struct ofono_sim_aid_session *session = iter->data;
+
+		if (session->record->type == type)
+			return session;
+
+		iter = g_slist_next(iter);
+	}
+
+	return NULL;
+}
+
+GSList *__ofono_sim_get_aid_list(struct ofono_sim *sim)
+{
+	return sim->aid_list;
+}
-- 
2.7.4


  reply	other threads:[~2017-11-03 20:31 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-03 20:31 [PATCH 1/3] sim: header definitions for AID session APIs James Prestwood
2017-11-03 20:31 ` James Prestwood [this message]
2017-11-03 20:31 ` [PATCH 3/3] atmodem: implement new driver APIs for AID sessions James Prestwood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1509741113-10669-2-git-send-email-james.prestwood@linux.intel.com \
    --to=james.prestwood@linux.intel.com \
    --cc=ofono@ofono.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.