[PATCHv5 1/4] sim-auth: implementation of core sim-auth atom
by James Prestwood
The sim-auth module atom can now be used for SIM application discovery
and authentication. The atom will automatically discover SIM
applications available on the SIM and register a new DBus object under
the modem, whos name is the AID string e.g.
/modem1/A0000000871004FFFFFFFF8906190000
A list of discovered AID object paths and types can be retrieved by
calling GetApplications() under the modems (new)
org.ofono.SimAuthentication interface which returns "a{oa{sv}}" where
o = path (e.g. above)
and the dictionary contains the following properties:
Type: "Umts" or "Ims"
Name: "USim" or "ISim"
The Type signifies which interfaces the AID object will have:
Umts = org.ofono.USimApplication
Ims = org.ofono.ISimApplication
These interfaces will contain the supported USIM/ISIM authentication
algorithms. Where:
org.ofono.USimApplication has:
GetProperties()
GsmAuthenticate()
UmtsAuthenticate()
org.ofono.ISimApplication has:
GetProperties()
ImsAuthenticate()
---
src/sim-auth.c | 628 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 628 insertions(+)
diff --git a/src/sim-auth.c b/src/sim-auth.c
index 5d2f075..b9552b5 100644
--- a/src/sim-auth.c
+++ b/src/sim-auth.c
@@ -28,19 +28,111 @@
#include <glib.h>
#include <errno.h>
#include <unistd.h>
+#include <gdbus.h>
+#include <string.h>
+#include <stdio.h>
#include "ofono.h"
#include "simutil.h"
+#include "util.h"
+
+#define SIM_AUTH_MAX_RANDS 3
static GSList *g_drivers = NULL;
+/*
+ * Temporary handle used for the command authentication sequence.
+ */
+struct auth_request {
+ /* DBus values for GSM authentication */
+ DBusMessage *msg;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ /* ID from open_channel */
+ int session_id;
+ /* list of rands to calculate key (1 if umts == 1) */
+ void *rands[SIM_AUTH_MAX_RANDS];
+ int num_rands;
+ /* number of keys that have been returned */
+ int cb_count;
+ void *autn;
+ uint8_t umts : 1;
+};
+
struct ofono_sim_auth {
const struct ofono_sim_auth_driver *driver;
void *driver_data;
struct ofono_atom *atom;
+ GSList *aid_list;
+ uint8_t gsm_access : 1;
+ uint8_t gsm_context : 1;
+ struct auth_request *pending;
};
+/*
+ * Find an application by path. 'path' should be a DBusMessage object path.
+ */
+static struct sim_app_record *find_aid_by_path(GSList *aid_list,
+ const char *path)
+{
+ GSList *iter = aid_list;
+ const char *aid = strrchr(path, '/') + 1;
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+ char str[33];
+
+ encode_hex_own_buf(app->aid, 16, 0, str);
+
+ if (!strcmp(aid, str))
+ return app;
+
+ iter = g_slist_next(iter);
+ }
+
+ return NULL;
+}
+
+/*
+ * Free all discovered AID's
+ */
+static void free_apps(struct ofono_sim_auth *sa)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom);
+ const char *path = __ofono_atom_get_path(sa->atom);
+ GSList *iter = sa->aid_list;
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+ char object[strlen(path) + 33];
+ int ret;
+
+ ret = sprintf(object, "%s/", path);
+ encode_hex_own_buf(app->aid, 16, 0, object + ret);
+
+ if (app->type == SIM_APP_TYPE_USIM) {
+ g_dbus_unregister_interface(conn, object,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ } else if (app->type == SIM_APP_TYPE_ISIM) {
+ g_dbus_unregister_interface(conn, object,
+ OFONO_ISIM_APPLICATION_INTERFACE);
+ }
+
+ iter = g_slist_next(iter);
+ }
+
+ g_dbus_unregister_interface(conn, path,
+ OFONO_SIM_AUTHENTICATION_INTERFACE);
+ ofono_modem_remove_interface(modem,
+ OFONO_SIM_AUTHENTICATION_INTERFACE);
+
+
+ g_slist_free(sa->aid_list);
+}
+
int ofono_sim_auth_driver_register(const struct ofono_sim_auth_driver *d)
{
DBG("driver: %p, name: %s", d, d->name);
@@ -62,6 +154,11 @@ void ofono_sim_auth_driver_unregister(const struct ofono_sim_auth_driver *d)
static void sim_auth_unregister(struct ofono_atom *atom)
{
+ struct ofono_sim_auth *sa = __ofono_atom_get_data(atom);
+
+ free_apps(sa);
+
+ g_free(sa->pending);
}
static void sim_auth_remove(struct ofono_atom *atom)
@@ -113,9 +210,540 @@ struct ofono_sim_auth *ofono_sim_auth_create(struct ofono_modem *modem,
return sa;
}
+/*
+ * appends {oa{sv}} into an existing dict array
+ */
+static void append_dict_application(DBusMessageIter *iter, const char *path,
+ const char *type, const char *name)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &array);
+
+ ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type);
+ ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_close_container(iter, &array);
+}
+
+/*
+ * appends a{say} onto an existing dict array
+ */
+static void append_dict_byte_array(DBusMessageIter *iter, const char *key,
+ const void *arr, uint32_t len)
+{
+ DBusMessageIter keyiter;
+ DBusMessageIter valueiter;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
+ &keyiter);
+ dbus_message_iter_append_basic(&keyiter, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_open_container(&keyiter, DBUS_TYPE_ARRAY,
+ "y", &valueiter);
+ dbus_message_iter_append_fixed_array(&valueiter, DBUS_TYPE_BYTE, &arr,
+ len);
+ dbus_message_iter_close_container(&keyiter, &valueiter);
+ dbus_message_iter_close_container(iter, &keyiter);
+}
+
+static void handle_umts(struct ofono_sim_auth *sim, const uint8_t *resp,
+ uint16_t len)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ const uint8_t *res = NULL;
+ const uint8_t *ck = NULL;
+ const uint8_t *ik = NULL;
+ const uint8_t *auts = NULL;
+ const uint8_t *kc = NULL;
+
+ if (!sim_parse_umts_authenticate(resp, len, &res, &ck, &ik,
+ &auts, &kc))
+ goto umts_end;
+
+ reply = dbus_message_new_method_return(sim->pending->msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict);
+
+ if (auts) {
+ append_dict_byte_array(&dict, "AUTS", auts, 16);
+ } else {
+ append_dict_byte_array(&dict, "RES", res, 8);
+ append_dict_byte_array(&dict, "CK", ck, 16);
+ append_dict_byte_array(&dict, "IK", ik, 16);
+ if (kc)
+ append_dict_byte_array(&dict, "Kc", kc, 8);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+umts_end:
+ if (!reply)
+ reply = __ofono_error_not_supported(sim->pending->msg);
+
+ __ofono_dbus_pending_reply(&sim->pending->msg, reply);
+
+ sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL);
+
+ g_free(sim->pending);
+ sim->pending = NULL;
+}
+
+static void handle_gsm(struct ofono_sim_auth *sim, const uint8_t *resp,
+ uint16_t len)
+{
+ DBusMessageIter iter;
+ const uint8_t *sres = NULL;
+ const uint8_t *kc = NULL;
+
+ if (!sim_parse_gsm_authenticate(resp, len, &sres, &kc))
+ goto gsm_end;
+
+ /* initial iteration, setup the reply message */
+ if (sim->pending->cb_count == 0) {
+ sim->pending->reply = dbus_message_new_method_return(
+ sim->pending->msg);
+
+ dbus_message_iter_init_append(sim->pending->reply,
+ &sim->pending->iter);
+
+ dbus_message_iter_open_container(&sim->pending->iter,
+ DBUS_TYPE_ARRAY, "a{say}", &sim->pending->dict);
+ }
+
+ /* append the Nth sres/kc byte arrays */
+ dbus_message_iter_open_container(&sim->pending->dict, DBUS_TYPE_ARRAY,
+ "{say}", &iter);
+ append_dict_byte_array(&iter, "SRES", sres, 4);
+ append_dict_byte_array(&iter, "Kc", kc, 8);
+ dbus_message_iter_close_container(&sim->pending->dict, &iter);
+
+ sim->pending->cb_count++;
+
+ /* calculated the number of keys requested, close container */
+ if (sim->pending->cb_count == sim->pending->num_rands) {
+ dbus_message_iter_close_container(&sim->pending->iter,
+ &sim->pending->dict);
+ goto gsm_end;
+ }
+
+ return;
+
+gsm_end:
+ if (!sim->pending->reply)
+ sim->pending->reply = __ofono_error_not_supported(
+ sim->pending->msg);
+
+ __ofono_dbus_pending_reply(&sim->pending->msg, sim->pending->reply);
+
+ sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL);
+
+ g_free(sim->pending);
+
+ sim->pending = NULL;
+}
+
+static void logical_access_cb(const struct ofono_error *error,
+ const uint8_t *resp, uint16_t len, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+
+ /* error must have occurred in a previous CB */
+ if (!sim->pending)
+ return;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ __ofono_dbus_pending_reply(&sim->pending->msg,
+ __ofono_error_failed(sim->pending->msg));
+ g_free(sim->pending);
+ sim->pending = NULL;
+ return;
+ }
+
+ if (sim->pending->umts)
+ handle_umts(sim, resp, len);
+ else
+ handle_gsm(sim, resp, len);
+}
+
+static void open_channel_cb(const struct ofono_error *error, int session_id,
+ void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ int i;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto error;
+
+ if (session_id == -1)
+ goto error;
+
+ /* save session ID for close_channel() */
+ sim->pending->session_id = session_id;
+
+ /*
+ * This will do the logical access num_rand times, providing a new
+ * RAND seed each time. In the UMTS case, num_rands should be 1.
+ */
+ for (i = 0; i < sim->pending->num_rands; i++) {
+ uint8_t auth_cmd[40];
+ int len = 0;
+
+ if (sim->pending->umts)
+ len = sim_build_umts_authenticate(auth_cmd, 40,
+ sim->pending->rands[i],
+ sim->pending->autn);
+ else
+ len = sim_build_gsm_authenticate(auth_cmd, 40,
+ sim->pending->rands[i]);
+
+ if (!len)
+ goto error;
+
+ sim->driver->logical_access(sim, session_id, auth_cmd, len,
+ logical_access_cb, sim);
+ }
+
+ return;
+
+error:
+ __ofono_dbus_pending_reply(&sim->pending->msg,
+ __ofono_error_failed(sim->pending->msg));
+ g_free(sim->pending);
+ sim->pending = NULL;
+}
+
+static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ int i;
+ struct sim_app_record *app;
+
+ if (sim->pending)
+ return __ofono_error_busy(msg);
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return __ofono_error_invalid_format(msg);
+
+ sim->pending = malloc(sizeof(struct auth_request));
+ sim->pending->msg = dbus_message_ref(msg);
+ sim->pending->umts = 0;
+ sim->pending->cb_count = 0;
+ sim->pending->num_rands = dbus_message_iter_get_element_count(&iter);
+
+ dbus_message_iter_recurse(&iter, &array);
+
+ for (i = 0; i < sim->pending->num_rands; i++) {
+ int nelement;
+ DBusMessageIter in;
+
+ dbus_message_iter_recurse(&array, &in);
+
+ dbus_message_iter_get_fixed_array(&in, &sim->pending->rands[i],
+ &nelement);
+
+ if (nelement != 16) {
+ g_free(sim->pending);
+ sim->pending = NULL;
+ return __ofono_error_invalid_format(msg);
+ }
+
+ dbus_message_iter_next(&array);
+ }
+
+ app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg));
+
+ sim->driver->open_channel(sim, app->aid, open_channel_cb, sim);
+
+ return NULL;
+}
+
+static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
+ void *data, enum sim_app_type type)
+{
+ uint8_t *rand = NULL;
+ uint8_t *autn = NULL;
+ uint32_t rlen;
+ uint32_t alen;
+ struct ofono_sim_auth *sim = data;
+ struct sim_app_record *app;
+
+ if (sim->pending)
+ return __ofono_error_busy(msg);
+
+ /* get RAND/AUTN and setup handle args */
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE, &rand, &rlen, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE, &autn, &alen,
+ DBUS_TYPE_INVALID))
+ return __ofono_error_invalid_format(msg);
+
+ if (rlen != 16 || alen != 16)
+ return __ofono_error_invalid_format(msg);
+
+ sim->pending = g_new0(struct auth_request, 1);
+ sim->pending->msg = dbus_message_ref(msg);
+ sim->pending->rands[0] = rand;
+ sim->pending->num_rands = 1;
+ sim->pending->autn = autn;
+ sim->pending->umts = 1;
+
+ app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg));
+
+ sim->driver->open_channel(sim, app->aid, open_channel_cb, sim);
+
+ return NULL;
+}
+
+static DBusMessage *get_applications(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ const char *path = __ofono_atom_get_path(sim->atom);
+ int ret;
+ char object[strlen(path) + 33];
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ GSList *aid_iter;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{oa{sv}}",
+ &array);
+
+ /* send empty array */
+ if (!sim->aid_list)
+ goto apps_end;
+
+ aid_iter = sim->aid_list;
+
+ while (aid_iter) {
+ struct sim_app_record *app = aid_iter->data;
+
+ ret = sprintf(object, "%s/", path);
+ encode_hex_own_buf(app->aid, 16, 0, object + ret);
+
+ switch (app->type) {
+ case SIM_APP_TYPE_ISIM:
+ dbus_message_iter_open_container(&array,
+ DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ append_dict_application(&dict, object, "Ims", "ISim");
+ dbus_message_iter_close_container(&array, &dict);
+
+ break;
+ case SIM_APP_TYPE_USIM:
+ dbus_message_iter_open_container(&array,
+ DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ append_dict_application(&dict, object, "Umts", "USim");
+ dbus_message_iter_close_container(&array, &dict);
+
+ break;
+ default:
+ break;
+ }
+
+ aid_iter = g_slist_next(aid_iter);
+ }
+
+apps_end:
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static DBusMessage *send_properties(DBusConnection *conn, DBusMessage *msg,
+ void *data, const char *type, const char *name)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}",
+ &array);
+
+ ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type);
+ ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static DBusMessage *usim_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return send_properties(conn, msg, data, "Umts", "USim");
+}
+
+static DBusMessage *isim_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return send_properties(conn, msg, data, "Ims", "ISim");
+}
+
+static DBusMessage *isim_ims_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return umts_common(conn, msg, data, SIM_APP_TYPE_ISIM);
+}
+
+static DBusMessage *usim_umts_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return umts_common(conn, msg, data, SIM_APP_TYPE_USIM);
+}
+
+static const GDBusMethodTable sim_authentication[] = {
+ { GDBUS_METHOD("GetApplications",
+ NULL,
+ GDBUS_ARGS({"applications", "a{oa{sv}}"}),
+ get_applications) },
+ { }
+};
+
+static const GDBusMethodTable sim_auth_usim_app[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL,
+ GDBUS_ARGS({"properties", "a{sv}"}),
+ usim_get_properties) },
+ { GDBUS_ASYNC_METHOD("GsmAuthenticate",
+ GDBUS_ARGS({"rands", "aay"}),
+ GDBUS_ARGS({"keys", "a{say}"}),
+ usim_gsm_authenticate) },
+ { GDBUS_ASYNC_METHOD("UmtsAuthenticate",
+ GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}),
+ GDBUS_ARGS({"return", "a{sv}"}),
+ usim_umts_authenticate) },
+ { }
+};
+
+static const GDBusMethodTable sim_auth_isim_app[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL,
+ GDBUS_ARGS({"properties", "a{sv}"}),
+ isim_get_properties) },
+ { GDBUS_ASYNC_METHOD("ImsAuthenticate",
+ GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}),
+ GDBUS_ARGS({"return", "a{sv}"}),
+ isim_ims_authenticate) },
+ { }
+};
+
+static void discover_apps_cb(const struct ofono_error *error,
+ const unsigned char *dataobj,
+ int len, void *data)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_sim_auth *sim = data;
+ struct ofono_modem *modem = __ofono_atom_get_modem(sim->atom);
+ const char *path = __ofono_atom_get_path(sim->atom);
+ GSList *iter;
+ char app_path[strlen(path) + 34];
+ int ret;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto parse_error;
+
+ sim->aid_list = sim_parse_app_template_entries(dataobj, len);
+
+ if (!sim->aid_list)
+ goto parse_error;
+
+ iter = sim->aid_list;
+
+ ret = sprintf(app_path, "%s/", path);
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+
+ switch (app->type) {
+ case SIM_APP_TYPE_USIM:
+ encode_hex_own_buf(app->aid, 16, 0, app_path + ret);
+
+ g_dbus_register_interface(conn, app_path,
+ OFONO_USIM_APPLICATION_INTERFACE,
+ sim_auth_usim_app, NULL, NULL,
+ sim, NULL);
+ break;
+ case SIM_APP_TYPE_ISIM:
+ encode_hex_own_buf(app->aid, 16, 0, app_path + ret);
+
+ g_dbus_register_interface(conn, app_path,
+ OFONO_ISIM_APPLICATION_INTERFACE,
+ sim_auth_isim_app, NULL, NULL,
+ sim, NULL);
+ break;
+ default:
+ DBG("Unknown SIM application '%04x'", app->type);
+ /*
+ * If we get here, the SIM application was not ISIM
+ * or USIM, skip.
+ */
+ }
+
+ iter = g_slist_next(iter);
+ }
+
+ /*
+ * Now SimAuthentication interface can be registered since app
+ * discovery has completed
+ */
+ g_dbus_register_interface(conn, path,
+ OFONO_SIM_AUTHENTICATION_INTERFACE,
+ sim_authentication, NULL, NULL,
+ sim, NULL);
+ ofono_modem_add_interface(modem,
+ OFONO_SIM_AUTHENTICATION_INTERFACE);
+
+ return;
+
+parse_error:
+ /*
+ * Something went wrong parsing the AID list, it can't be assumed that
+ * any previously parsed AID's are valid so free them all.
+ */
+ DBG("Error parsing app list");
+}
+
void ofono_sim_auth_register(struct ofono_sim_auth *sa)
{
+ struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom);
+ struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+
__ofono_atom_register(sa->atom, sim_auth_unregister);
+
+ /* Do SIM application discovery, the cb will register DBus ifaces */
+ sa->driver->list_apps(sa, discover_apps_cb, sa);
+
+ sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+
+ sa->gsm_access = __ofono_sim_ust_service_available(sim,
+ SIM_UST_SERVICE_GSM_ACCESS);
+ sa->gsm_context = __ofono_sim_ust_service_available(sim,
+ SIM_UST_SERVICE_GSM_SECURITY_CONTEXT);
}
void ofono_sim_auth_remove(struct ofono_sim_auth *sa)
--
2.7.4
3 years, 3 months
[PATCHv4 1/6] sim-auth: implementation of core sim-auth atom
by James Prestwood
The sim-auth module atom can now be used for SIM application discovery
and authentication. The atom will automatically discover SIM
applications available on the SIM and register a new DBus object under
the modem, whos name is the AID string e.g.
/modem1/A0000000871004FFFFFFFF8906190000
A list of discovered AID object paths and types can be retrieved by
calling GetApplications() under the modems (new)
org.ofono.SimAuthentication interface which returns "a{oa{sv}}" where
o = path (e.g. above)
and the dictionary contains the following properties:
Type: "Umts" or "Ims"
Name: "USim" or "ISim"
The Type signifies which interfaces the AID object will have:
Umts = org.ofono.USimApplication
Ims = org.ofono.ISimApplication
These interfaces will contain the supported USIM/ISIM authentication
algorithms. Where:
org.ofono.USimApplication has:
GetProperties()
GsmAuthenticate()
UmtsAuthenticate()
org.ofono.ISimApplication has:
GetProperties()
ImsAuthenticate()
---
src/sim-auth.c | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 612 insertions(+)
diff --git a/src/sim-auth.c b/src/sim-auth.c
index 5d2f075..65a51c3 100644
--- a/src/sim-auth.c
+++ b/src/sim-auth.c
@@ -28,19 +28,104 @@
#include <glib.h>
#include <errno.h>
#include <unistd.h>
+#include <gdbus.h>
+#include <string.h>
+#include <stdio.h>
#include "ofono.h"
#include "simutil.h"
+#include "util.h"
+
+#define SIM_AUTH_MAX_RANDS 3
static GSList *g_drivers = NULL;
+/*
+ * Temporary handle used for the command authentication sequence.
+ */
+struct auth_request {
+ /* DBus values for GSM authentication */
+ DBusMessage *msg;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ /* ID from open_channel */
+ int session_id;
+ /* list of rands to calculate key (1 if umts == 1) */
+ void *rands[SIM_AUTH_MAX_RANDS];
+ int num_rands;
+ /* number of keys that have been returned */
+ int cb_count;
+ void *autn;
+ uint8_t umts : 1;
+};
+
struct ofono_sim_auth {
const struct ofono_sim_auth_driver *driver;
void *driver_data;
struct ofono_atom *atom;
+ GSList *aid_list;
+ struct ofono_sim *sim;
+ uint8_t gsm_access : 1;
+ uint8_t gsm_context : 1;
+ struct auth_request *pending;
};
+/*
+ * Find an application by path. 'path' should be a DBusMessage object path.
+ */
+static struct sim_app_record *find_aid_by_path(GSList *aid_list,
+ const char *path)
+{
+ GSList *iter = aid_list;
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+ char str[32];
+
+ encode_hex_own_buf(app->aid, 16, 0, str);
+
+ if (strstr(path, str))
+ return app;
+
+ iter = g_slist_next(iter);
+ }
+
+ return NULL;
+}
+
+/*
+ * Free all discovered AID's
+ */
+static void free_apps(struct ofono_sim_auth *sa)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom);
+ const char *path = __ofono_atom_get_path(sa->atom);
+ GSList *iter = sa->aid_list;
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+
+ if (app->type == SIM_APP_TYPE_USIM) {
+ g_dbus_unregister_interface(conn, path,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ ofono_modem_remove_interface(modem,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ } else if (app->type == SIM_APP_TYPE_ISIM) {
+ g_dbus_unregister_interface(conn, path,
+ OFONO_ISIM_APPLICATION_INTERFACE);
+ ofono_modem_remove_interface(modem,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ }
+
+ iter = g_slist_next(iter);
+ }
+
+ g_slist_free(sa->aid_list);
+}
+
int ofono_sim_auth_driver_register(const struct ofono_sim_auth_driver *d)
{
DBG("driver: %p, name: %s", d, d->name);
@@ -76,6 +161,10 @@ static void sim_auth_remove(struct ofono_atom *atom)
if (sa->driver && sa->driver->remove)
sa->driver->remove(sa);
+ free_apps(sa);
+
+ g_free(sa->pending);
+
g_free(sa);
}
@@ -113,9 +202,532 @@ struct ofono_sim_auth *ofono_sim_auth_create(struct ofono_modem *modem,
return sa;
}
+/*
+ * appends {oa{sv}} into an existing dict array
+ */
+static void append_dict_application(DBusMessageIter *iter, const char *path,
+ const char *type, const char *name)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &array);
+
+ ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type);
+ ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_close_container(iter, &array);
+}
+
+/*
+ * appends a{say} onto an existing dict array
+ */
+static void append_dict_byte_array(DBusMessageIter *iter, const char *key,
+ const void *arr, uint32_t len)
+{
+ DBusMessageIter keyiter;
+ DBusMessageIter valueiter;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
+ &keyiter);
+ dbus_message_iter_append_basic(&keyiter, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_open_container(&keyiter, DBUS_TYPE_ARRAY,
+ "y", &valueiter);
+ dbus_message_iter_append_fixed_array(&valueiter, DBUS_TYPE_BYTE, &arr,
+ len);
+ dbus_message_iter_close_container(&keyiter, &valueiter);
+ dbus_message_iter_close_container(iter, &keyiter);
+}
+
+static void handle_umts(struct ofono_sim_auth *sim, const uint8_t *resp,
+ uint16_t len)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ const uint8_t *res = NULL;
+ const uint8_t *ck = NULL;
+ const uint8_t *ik = NULL;
+ const uint8_t *auts = NULL;
+ const uint8_t *kc = NULL;
+
+ if (!sim_parse_umts_authenticate(resp, len, &res, &ck, &ik,
+ &auts, &kc))
+ goto umts_end;
+
+ reply = dbus_message_new_method_return(sim->pending->msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict);
+
+ if (auts) {
+ append_dict_byte_array(&dict, "AUTS", auts, 16);
+ } else {
+ append_dict_byte_array(&dict, "RES", res, 8);
+ append_dict_byte_array(&dict, "CK", ck, 16);
+ append_dict_byte_array(&dict, "IK", ik, 16);
+ if (kc)
+ append_dict_byte_array(&dict, "Kc", kc, 8);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+umts_end:
+ if (!reply)
+ reply = __ofono_error_not_supported(sim->pending->msg);
+
+ __ofono_dbus_pending_reply(&sim->pending->msg, reply);
+
+ sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL);
+
+ g_free(sim->pending);
+ sim->pending = NULL;
+}
+
+static void handle_gsm(struct ofono_sim_auth *sim, const uint8_t *resp,
+ uint16_t len)
+{
+ DBusMessageIter iter;
+ const uint8_t *sres = NULL;
+ const uint8_t *kc = NULL;
+
+ if (!sim_parse_gsm_authenticate(resp, len, &sres, &kc))
+ goto gsm_end;
+
+ /* initial iteration, setup the reply message */
+ if (sim->pending->cb_count == 0) {
+ sim->pending->reply = dbus_message_new_method_return(
+ sim->pending->msg);
+
+ dbus_message_iter_init_append(sim->pending->reply,
+ &sim->pending->iter);
+
+ dbus_message_iter_open_container(&sim->pending->iter,
+ DBUS_TYPE_ARRAY, "a{say}", &sim->pending->dict);
+ }
+
+ /* append the Nth sres/kc byte arrays */
+ dbus_message_iter_open_container(&sim->pending->dict, DBUS_TYPE_ARRAY,
+ "{say}", &iter);
+ append_dict_byte_array(&iter, "SRES", sres, 4);
+ append_dict_byte_array(&iter, "Kc", kc, 8);
+ dbus_message_iter_close_container(&sim->pending->dict, &iter);
+
+ sim->pending->cb_count++;
+
+ /* calculated the number of keys requested, close container */
+ if (sim->pending->cb_count == sim->pending->num_rands) {
+ dbus_message_iter_close_container(&sim->pending->iter,
+ &sim->pending->dict);
+ goto gsm_end;
+ }
+
+ return;
+
+gsm_end:
+ if (!sim->pending->reply)
+ sim->pending->reply = __ofono_error_not_supported(
+ sim->pending->msg);
+
+ __ofono_dbus_pending_reply(&sim->pending->msg, sim->pending->reply);
+
+ sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL);
+
+ g_free(sim->pending);
+
+ sim->pending = NULL;
+}
+
+static void logical_access_cb(const struct ofono_error *error,
+ const uint8_t *resp, uint16_t len, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ __ofono_dbus_pending_reply(&sim->pending->msg,
+ __ofono_error_failed(sim->pending->msg));
+ g_free(sim->pending);
+ sim->pending = NULL;
+ return;
+ }
+
+ if (sim->pending->umts)
+ handle_umts(sim, resp, len);
+ else
+ handle_gsm(sim, resp, len);
+}
+
+static void open_channel_cb(const struct ofono_error *error, int session_id,
+ void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ int i;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto error;
+
+ if (session_id == -1)
+ goto error;
+
+ /* save session ID for close_channel() */
+ sim->pending->session_id = session_id;
+
+ /*
+ * This will do the logical access num_rand times, providing a new
+ * RAND seed each time. In the UMTS case, num_rands should be 1.
+ */
+ for (i = 0; i < sim->pending->num_rands; i++) {
+ uint8_t auth_cmd[40];
+ int len = 0;
+
+ if (sim->pending->umts)
+ len = sim_build_umts_authenticate(auth_cmd, 40,
+ sim->pending->rands[i],
+ sim->pending->autn);
+ else
+ len = sim_build_gsm_authenticate(auth_cmd, 40,
+ sim->pending->rands[i]);
+
+ if (!len)
+ goto error;
+
+ sim->driver->logical_access(sim, session_id, auth_cmd, len,
+ logical_access_cb, sim);
+ }
+
+ return;
+
+error:
+ __ofono_dbus_pending_reply(&sim->pending->msg,
+ __ofono_error_failed(sim->pending->msg));
+ g_free(sim->pending);
+ sim->pending = NULL;
+}
+
+static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ int i;
+ struct sim_app_record *app;
+
+ if (sim->pending)
+ return __ofono_error_busy(msg);
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return __ofono_error_not_supported(msg);
+
+ sim->pending = malloc(sizeof(struct auth_request));
+ sim->pending->msg = dbus_message_ref(msg);
+ sim->pending->umts = 0;
+ sim->pending->cb_count = 0;
+ sim->pending->num_rands = dbus_message_iter_get_element_count(&iter);
+
+ dbus_message_iter_recurse(&iter, &array);
+
+ for (i = 0; i < sim->pending->num_rands; i++) {
+ int nelement;
+ DBusMessageIter in;
+
+ dbus_message_iter_recurse(&array, &in);
+
+ dbus_message_iter_get_fixed_array(&in, &sim->pending->rands[i],
+ &nelement);
+ dbus_message_iter_next(&array);
+ }
+
+ app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg));
+
+ sim->driver->open_channel(sim, app->aid, open_channel_cb, sim);
+
+ return NULL;
+}
+
+static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
+ void *data, enum sim_app_type type)
+{
+ uint8_t *rand = NULL;
+ uint8_t *autn = NULL;
+ uint32_t rlen;
+ uint32_t alen;
+ struct ofono_sim_auth *sim = data;
+ struct sim_app_record *app;
+
+ if (sim->pending)
+ return __ofono_error_busy(msg);
+
+ /* get RAND/AUTN and setup handle args */
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE, &rand, &rlen, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE, &autn, &alen,
+ DBUS_TYPE_INVALID);
+
+ if (rlen != 16 || alen != 16) {
+ g_free(sim->pending);
+ sim->pending = NULL;
+ return __ofono_error_invalid_args(msg);
+ }
+
+ sim->pending = g_new0(struct auth_request, 1);
+ sim->pending->msg = dbus_message_ref(msg);
+ sim->pending->rands[0] = rand;
+ sim->pending->num_rands = 1;
+ sim->pending->autn = autn;
+ sim->pending->umts = 1;
+
+ app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg));
+
+ sim->driver->open_channel(sim, app->aid, open_channel_cb, sim);
+
+ return NULL;
+}
+
+static DBusMessage *get_applications(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ const char *path = __ofono_atom_get_path(sim->atom);
+ int ret;
+ char object[strlen(path) + 33];
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ GSList *aid_iter;
+
+ if (!sim->aid_list)
+ return __ofono_error_busy(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{oa{sv}}",
+ &array);
+
+ aid_iter = sim->aid_list;
+
+ while (aid_iter) {
+ struct sim_app_record *app = aid_iter->data;
+
+ ret = sprintf(object, "%s/", path);
+ encode_hex_own_buf(app->aid, 16, 0, object + ret);
+
+ switch (app->type) {
+ case SIM_APP_TYPE_ISIM:
+ dbus_message_iter_open_container(&array,
+ DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ append_dict_application(&dict, object, "Ims", "ISim");
+ dbus_message_iter_close_container(&array, &dict);
+
+ break;
+ case SIM_APP_TYPE_USIM:
+ dbus_message_iter_open_container(&array,
+ DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ append_dict_application(&dict, object, "Umts", "USim");
+ dbus_message_iter_close_container(&array, &dict);
+
+ break;
+ default:
+ break;
+ }
+
+ aid_iter = g_slist_next(aid_iter);
+ }
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static DBusMessage *send_properties(DBusConnection *conn, DBusMessage *msg,
+ void *data, const char *type, const char *name)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}",
+ &array);
+
+ ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type);
+ ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static DBusMessage *usim_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return send_properties(conn, msg, data, "Umts", "USim");
+}
+
+static DBusMessage *isim_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return send_properties(conn, msg, data, "Ims", "ISim");
+}
+
+static DBusMessage *isim_ims_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return umts_common(conn, msg, data, SIM_APP_TYPE_ISIM);
+}
+
+static DBusMessage *usim_umts_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return umts_common(conn, msg, data, SIM_APP_TYPE_USIM);
+}
+
+static const GDBusMethodTable sim_authentication[] = {
+ { GDBUS_METHOD("GetApplications",
+ NULL,
+ GDBUS_ARGS({"applications", "a{oa{sv}}"}),
+ get_applications) },
+ { }
+};
+
+static const GDBusMethodTable sim_auth_usim_app[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL,
+ GDBUS_ARGS({"properties", "a{sv}"}),
+ usim_get_properties) },
+ { GDBUS_ASYNC_METHOD("GsmAuthenticate",
+ GDBUS_ARGS({"rands", "aay"}),
+ GDBUS_ARGS({"keys", "a{say}"}),
+ usim_gsm_authenticate) },
+ { GDBUS_ASYNC_METHOD("UmtsAuthenticate",
+ GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}),
+ GDBUS_ARGS({"return", "a{sv}"}),
+ usim_umts_authenticate) },
+ { }
+};
+
+static const GDBusMethodTable sim_auth_isim_app[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL,
+ GDBUS_ARGS({"properties", "a{sv}"}),
+ isim_get_properties) },
+ { GDBUS_ASYNC_METHOD("ImsAuthenticate",
+ GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}),
+ GDBUS_ARGS({"return", "a{sv}"}),
+ isim_ims_authenticate) },
+ { }
+};
+
+static void discover_apps_cb(const struct ofono_error *error,
+ const unsigned char *dataobj,
+ int len, void *data)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_sim_auth *sim = data;
+ struct ofono_modem *modem = __ofono_atom_get_modem(sim->atom);
+ const char *path = __ofono_atom_get_path(sim->atom);
+ GSList *iter;
+ char app_path[strlen(path) + 34];
+ int ret;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto parse_error;
+
+ sim->aid_list = sim_parse_app_template_entries(dataobj, len);
+
+ if (!sim->aid_list)
+ goto parse_error;
+
+ iter = sim->aid_list;
+
+ ret = sprintf(app_path, "%s/", path);
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+
+ switch (app->type) {
+ case SIM_APP_TYPE_USIM:
+ encode_hex_own_buf(app->aid, 16, 0, app_path + ret);
+
+ app_path[ret + 32] = '\0';
+
+ g_dbus_register_interface(conn, app_path,
+ OFONO_USIM_APPLICATION_INTERFACE,
+ sim_auth_usim_app, NULL, NULL,
+ sim, NULL);
+ break;
+ case SIM_APP_TYPE_ISIM:
+ encode_hex_own_buf(app->aid, 16, 0, app_path + ret);
+
+ app_path[ret + 32] = '\0';
+
+ g_dbus_register_interface(conn, app_path,
+ OFONO_ISIM_APPLICATION_INTERFACE,
+ sim_auth_isim_app, NULL, NULL,
+ sim, NULL);
+ break;
+ default:
+ DBG("Unknown SIM application '%04x'", app->type);
+ /*
+ * If we get here, the SIM application was not ISIM
+ * or USIM, skip.
+ */
+ }
+
+ iter = g_slist_next(iter);
+ }
+
+ /*
+ * Now SimAuthentication interface can be registered since app
+ * discovery has completed
+ */
+ g_dbus_register_interface(conn, path,
+ OFONO_SIM_AUTHENTICATION_INTERFACE,
+ sim_authentication, NULL, NULL,
+ sim, NULL);
+ ofono_modem_add_interface(modem,
+ OFONO_SIM_AUTHENTICATION_INTERFACE);
+
+ return;
+
+parse_error:
+ /*
+ * Something went wrong parsing the AID list, it can't be assumed that
+ * any previously parsed AID's are valid so free them all.
+ */
+ DBG("Error parsing app list");
+}
+
void ofono_sim_auth_register(struct ofono_sim_auth *sa)
{
+ struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom);
+
__ofono_atom_register(sa->atom, sim_auth_unregister);
+
+ /* Do SIM application discovery, the cb will register DBus ifaces */
+ sa->driver->list_apps(sa, discover_apps_cb, sa);
+
+ sa->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+
+ sa->gsm_access = __ofono_sim_ust_service_available(sa->sim,
+ SIM_UST_SERVICE_GSM_ACCESS);
+ sa->gsm_context = __ofono_sim_ust_service_available(sa->sim,
+ SIM_UST_SERVICE_GSM_SECURITY_CONTEXT);
}
void ofono_sim_auth_remove(struct ofono_sim_auth *sa)
--
2.7.4
3 years, 3 months
[PATCHv3 1/7] sim-auth: prep simauth/dbus headers
by James Prestwood
Added new dbus interfaces for SimAuth module as well as
function prototype definitions to simauth header.
org.ofono.SimAuthentication:
Interface to hold the auth object to type mapping property
org.ofono.USimApplication:
Application with USim functionality (GSM/UMTS auth)
org.ofono.ISimApplication:
Application with ISim functionality (IMS auth)
---
include/dbus.h | 3 +++
include/sim-auth.h | 20 +++++++++++++++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/include/dbus.h b/include/dbus.h
index 0a8f2e5..9cc47f7 100644
--- a/include/dbus.h
+++ b/include/dbus.h
@@ -58,6 +58,9 @@ extern "C" {
#define OFONO_LOCATION_REPORTING_INTERFACE OFONO_SERVICE ".LocationReporting"
#define OFONO_GNSS_INTERFACE "org.ofono.AssistedSatelliteNavigation"
#define OFONO_GNSS_POSR_AGENT_INTERFACE "org.ofono.PositioningRequestAgent"
+#define OFONO_USIM_APPLICATION_INTERFACE "org.ofono.USimApplication"
+#define OFONO_ISIM_APPLICATION_INTERFACE "org.ofono.ISimApplication"
+#define OFONO_SIM_AUTHENTICATION_INTERFACE "org.ofono.SimAuthentication"
#define OFONO_HANDSFREE_INTERFACE OFONO_SERVICE ".Handsfree"
#define OFONO_SIRI_INTERFACE OFONO_SERVICE ".Siri"
#define OFONO_NETMON_INTERFACE OFONO_SERVICE ".NetworkMonitor"
diff --git a/include/sim-auth.h b/include/sim-auth.h
index 0a62adc..ccaa7f2 100644
--- a/include/sim-auth.h
+++ b/include/sim-auth.h
@@ -26,6 +26,8 @@
extern "C" {
#endif
+#include <stdint.h>
+
#include <ofono/types.h>
struct ofono_sim_auth;
@@ -34,6 +36,15 @@ typedef void (*ofono_sim_list_apps_cb_t)(const struct ofono_error *error,
const unsigned char *dataobj,
int len, void *data);
+typedef void (*ofono_sim_open_channel_cb_t)(const struct ofono_error *error,
+ int session_id, void *data);
+
+typedef void (*ofono_sim_close_channel_cb_t)(const struct ofono_error *error,
+ void *data);
+
+typedef void (*ofono_logical_access_cb_t)(const struct ofono_error *error,
+ const uint8_t *resp, uint16_t len, void *data);
+
struct ofono_sim_auth_driver {
const char *name;
int (*probe)(struct ofono_sim_auth *sa, unsigned int vendor,
@@ -41,7 +52,14 @@ struct ofono_sim_auth_driver {
void (*remove)(struct ofono_sim_auth *sa);
void (*list_apps)(struct ofono_sim_auth *sa,
- ofono_sim_list_apps_cb_t cb, void *data);
+ ofono_sim_list_apps_cb_t cb, void *data);
+ void (*open_channel)(struct ofono_sim_auth *sa, const uint8_t *aid,
+ ofono_sim_open_channel_cb_t cb, void *data);
+ void (*close_channel)(struct ofono_sim_auth *sa, int session_id,
+ ofono_sim_close_channel_cb_t cb, void *data);
+ void (*logical_access)(struct ofono_sim_auth *sa,
+ int session_id, const uint8_t *pdu, uint16_t len,
+ ofono_logical_access_cb_t cb, void *data);
};
int ofono_sim_auth_driver_register(const struct ofono_sim_auth_driver *d);
--
2.7.4
3 years, 3 months
[PATCHv2 01/11] simutil: Added app type to application parser
by James Prestwood
Parsing a SIM application only copied the 16 byte AID
portion, which included the application type. Parsing out
the type makes sorting much easier for modules using the
parser.
---
src/simutil.c | 2 ++
src/simutil.h | 12 ++++++++++++
2 files changed, 14 insertions(+)
diff --git a/src/simutil.c b/src/simutil.c
index 4731d3b..f43c2c2 100644
--- a/src/simutil.c
+++ b/src/simutil.c
@@ -1570,6 +1570,8 @@ GSList *sim_parse_app_template_entries(const unsigned char *buffer, int len)
memcpy(app.aid, aid, app.aid_len);
+ app.type = GUINT16_FROM_BE(*((unsigned short *)(app.aid + 5)));
+
/* Find the label (optional) */
label = ber_tlv_find_by_tag(dataobj, 0x50, dataobj_len,
&label_len);
diff --git a/src/simutil.h b/src/simutil.h
index 1faf948..9984b2c 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -261,6 +261,17 @@ enum sim_csp_entry {
SIM_CSP_ENTRY_INFORMATION_NUMBERS = 0xD5,
};
+/* 101.220 Annex E */
+enum sim_app_type {
+ SIM_APP_TYPE_UICC = 0x1001,
+ SIM_APP_TYPE_USIM = 0x1002,
+ SIM_APP_TYPE_USIM_TOOLKIT = 0x1003,
+ SIM_APP_TYPE_ISIM = 0x1004,
+ SIM_APP_TYPE_USIM_API = 0x1005,
+ SIM_APP_TYPE_ISIM_API = 0x1006,
+ SIM_APP_TYPE_CONTACT_MGR = 0x1007
+};
+
enum ber_tlv_data_type {
BER_TLV_DATA_TYPE_UNIVERSAL = 0,
BER_TLV_DATA_TYPE_APPLICATION = 1,
@@ -296,6 +307,7 @@ struct sim_app_record {
unsigned char aid[16];
int aid_len;
char *label;
+ enum sim_app_type type;
};
struct simple_tlv_iter {
--
2.7.4
3 years, 3 months
[PATCH] doc: Add IMS interface to Interfaces list
by Ankit Navik
---
doc/modem-api.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/doc/modem-api.txt b/doc/modem-api.txt
index 6462b17..89e6191 100644
--- a/doc/modem-api.txt
+++ b/doc/modem-api.txt
@@ -127,6 +127,7 @@ Properties boolean Powered [readwrite]
org.ofono.CallVolume
org.ofono.CellBroadcast
org.ofono.Handsfree
+ org.ofono.IpMultimediaSystem
org.ofono.LongTermEvolution
org.ofono.LocationReporting
org.ofono.MessageManager
--
1.9.1
3 years, 3 months
[PATCH 3/6] ims: add implementation for IMS atom
by Ankit Navik
This implementation includes:
* D-Bus interface
* interaction with driver
---
Makefile.am | 2 +-
src/ims.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ofono.h | 2 +
3 files changed, 392 insertions(+), 1 deletion(-)
create mode 100644 src/ims.c
diff --git a/Makefile.am b/Makefile.am
index 165235e..199de08 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -630,7 +630,7 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/cdma-provision.c src/handsfree.c \
src/handsfree-audio.c src/bluetooth.h \
src/hfp.h src/siri.c \
- src/netmon.c src/lte.c \
+ src/netmon.c src/lte.c src/ims.c \
src/netmonagent.c src/netmonagent.h
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
diff --git a/src/ims.c b/src/ims.c
new file mode 100644
index 0000000..626d5d2
--- /dev/null
+++ b/src/ims.c
@@ -0,0 +1,389 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+
+#include "common.h"
+
+#define VOICE_CAPABLE_FLAG 0x1
+#define SMS_CAPABLE_FLAG 0x4
+
+struct ofono_ims {
+ int reg_info;
+ int ext_info;
+ const struct ofono_ims_driver *driver;
+ void *driver_data;
+ struct ofono_atom *atom;
+ DBusMessage *pending;
+};
+
+static GSList *g_drivers = NULL;
+
+static DBusMessage *ims_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_ims *ims = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ dbus_bool_t value;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ value = ims->reg_info ? TRUE : FALSE;
+ ofono_dbus_dict_append(&dict, "Registered", DBUS_TYPE_BOOLEAN, &value);
+
+ if (ims->ext_info != -1) {
+ value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE;
+ ofono_dbus_dict_append(&dict, "VoiceCapable",
+ DBUS_TYPE_BOOLEAN, &value);
+
+ value = ims->ext_info & SMS_CAPABLE_FLAG ? TRUE : FALSE;
+ ofono_dbus_dict_append(&dict, "SmsCapable",
+ DBUS_TYPE_BOOLEAN, &value);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static void ims_set_sms_capable(struct ofono_ims *ims, ofono_bool_t status)
+{
+ const char *path = __ofono_atom_get_path(ims->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t new_value = status;
+ dbus_bool_t old_value = ims->ext_info & SMS_CAPABLE_FLAG ? TRUE :
+ FALSE;
+
+ if (old_value == new_value)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_IMS_INTERFACE,
+ "SmsCapable",
+ DBUS_TYPE_BOOLEAN,
+ &new_value);
+}
+
+static void ims_set_voice_capable(struct ofono_ims *ims, ofono_bool_t status)
+{
+ const char *path = __ofono_atom_get_path(ims->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t new_value = status;
+ dbus_bool_t old_value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE :
+ FALSE;
+
+ if (old_value == new_value)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_IMS_INTERFACE,
+ "VoiceCapable",
+ DBUS_TYPE_BOOLEAN,
+ &new_value);
+}
+
+static void ims_set_registered(struct ofono_ims *ims, ofono_bool_t status)
+{
+ const char *path = __ofono_atom_get_path(ims->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t new_value = status;
+ dbus_bool_t old_value = ims->reg_info ? TRUE : FALSE;
+
+ if (old_value == new_value)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_IMS_INTERFACE,
+ "Registered",
+ DBUS_TYPE_BOOLEAN,
+ &new_value);
+}
+
+void ofono_ims_status_notify(struct ofono_ims *ims, int reg_info, int ext_info)
+{
+ dbus_bool_t new_reg_info;
+ dbus_bool_t new_voice_capable, new_sms_capable;
+
+ if (ims == NULL)
+ return;
+
+ DBG("%s reg_info:%d ext_info:%d", __ofono_atom_get_path(ims->atom),
+ reg_info, ext_info);
+
+ if (ims->ext_info == ext_info && ims->reg_info == reg_info)
+ return;
+
+ new_reg_info = reg_info ? TRUE : FALSE;
+ ims_set_registered(ims, new_reg_info);
+
+ if (ext_info < 0)
+ goto skip;
+
+ new_voice_capable = ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE;
+ ims_set_voice_capable(ims, new_voice_capable);
+
+ new_sms_capable = ext_info & SMS_CAPABLE_FLAG ? TRUE: FALSE;
+ ims_set_sms_capable(ims, new_sms_capable);
+
+skip:
+ ims->reg_info = reg_info;
+ ims->ext_info = ext_info;
+}
+
+static void registration_status_cb(const struct ofono_error *error,
+ int reg_info, int ext_info,
+ void *data)
+{
+ struct ofono_ims *ims = data;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ DBG("Error during IMS registration/unregistration");
+ return;
+ }
+
+ ofono_ims_status_notify(ims, reg_info, ext_info);
+}
+
+static void register_cb(const struct ofono_error *error, void *data)
+{
+ struct ofono_ims *ims = data;
+ DBusMessage *reply;
+
+ if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
+ reply = dbus_message_new_method_return(ims->pending);
+ else
+ reply = __ofono_error_failed(ims->pending);
+
+ __ofono_dbus_pending_reply(&ims->pending, reply);
+
+ if (ims->driver->registration_status == NULL)
+ return;
+
+ ims->driver->registration_status(ims, registration_status_cb, ims);
+}
+
+static DBusMessage *ofono_ims_send_register(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_ims *ims = data;
+
+ if (ims->pending)
+ return __ofono_error_busy(msg);
+
+ if (ims->driver->ims_register == NULL)
+ return __ofono_error_not_implemented(msg);
+
+ ims->pending = dbus_message_ref(msg);
+
+ ims->driver->ims_register(ims, register_cb, ims);
+
+ return NULL;
+}
+
+static DBusMessage *ofono_ims_unregister(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_ims *ims = data;
+
+ if (ims->pending)
+ return __ofono_error_busy(msg);
+
+ if (ims->driver->ims_unregister == NULL)
+ return __ofono_error_not_implemented(msg);
+
+ ims->pending = dbus_message_ref(msg);
+
+ ims->driver->ims_unregister(ims, register_cb, ims);
+
+ return NULL;
+}
+
+static const GDBusMethodTable ims_methods[] = {
+ { GDBUS_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ ims_get_properties) },
+ { GDBUS_ASYNC_METHOD("Register", NULL, NULL,
+ ofono_ims_send_register) },
+ { GDBUS_ASYNC_METHOD("Unregister", NULL, NULL,
+ ofono_ims_unregister) },
+ { }
+};
+
+static const GDBusSignalTable ims_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { }
+};
+
+static void ims_atom_remove(struct ofono_atom *atom)
+{
+ struct ofono_ims *ims = __ofono_atom_get_data(atom);
+
+ DBG("atom: %p", atom);
+
+ if (ims == NULL)
+ return;
+
+ if (ims->driver && ims->driver->remove)
+ ims->driver->remove(ims);
+
+ g_free(ims);
+}
+
+struct ofono_ims *ofono_ims_create(struct ofono_modem *modem,
+ const char *driver, void *data)
+{
+ struct ofono_ims *ims;
+ GSList *l;
+
+ if (driver == NULL)
+ return NULL;
+
+ ims = g_try_new0(struct ofono_ims, 1);
+
+ if (ims == NULL)
+ return NULL;
+
+ ims->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_IMS,
+ ims_atom_remove, ims);
+
+ for (l = g_drivers; l; l = l->next) {
+ const struct ofono_ims_driver *drv = l->data;
+
+ if (g_strcmp0(drv->name, driver))
+ continue;
+
+ if (drv->probe(ims, data) < 0)
+ continue;
+
+ ims->driver = drv;
+ break;
+ }
+
+ DBG("IMS atom created");
+
+ return ims;
+}
+
+int ofono_ims_driver_register(const struct ofono_ims_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ if (d->probe == NULL)
+ return -EINVAL;
+
+ g_drivers = g_slist_prepend(g_drivers, (void *) d);
+
+ return 0;
+}
+
+void ofono_ims_driver_unregister(const struct ofono_ims_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ g_drivers = g_slist_remove(g_drivers, (void *) d);
+}
+
+static void ims_atom_unregister(struct ofono_atom *atom)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+ const char *path = __ofono_atom_get_path(atom);
+
+ ofono_modem_remove_interface(modem, OFONO_IMS_INTERFACE);
+ g_dbus_unregister_interface(conn, path, OFONO_IMS_INTERFACE);
+}
+
+static void ofono_ims_finish_register(struct ofono_ims *ims)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(ims->atom);
+ const char *path = __ofono_atom_get_path(ims->atom);
+
+ if (!g_dbus_register_interface(conn, path,
+ OFONO_IMS_INTERFACE,
+ ims_methods, ims_signals, NULL,
+ ims, NULL)) {
+ ofono_error("could not create %s interface",
+ OFONO_IMS_INTERFACE);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, OFONO_IMS_INTERFACE);
+
+ if (ims->driver->registration_status)
+ ims->driver->registration_status(ims,
+ registration_status_cb, ims);
+
+ __ofono_atom_register(ims->atom, ims_atom_unregister);
+}
+
+void ofono_ims_register(struct ofono_ims *ims)
+{
+ struct ofono_modem *modem = __ofono_atom_get_modem(ims->atom);
+ struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+ const char *imsi = ofono_sim_get_imsi(sim);
+
+ if (imsi == NULL) {
+ ofono_error("No sim atom required for registering IMS atom.");
+ return;
+ }
+
+ ofono_ims_finish_register(ims);
+}
+
+void ofono_ims_remove(struct ofono_ims *ims)
+{
+ __ofono_atom_free(ims->atom);
+}
+
+void ofono_ims_set_data(struct ofono_ims *ims, void *data)
+{
+ ims->driver_data = data;
+}
+
+void *ofono_ims_get_data(const struct ofono_ims *ims)
+{
+ return ims->driver_data;
+}
diff --git a/src/ofono.h b/src/ofono.h
index a797b7f..0da11a2 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -154,6 +154,7 @@ enum ofono_atom_type {
OFONO_ATOM_TYPE_SIRI,
OFONO_ATOM_TYPE_NETMON,
OFONO_ATOM_TYPE_LTE,
+ OFONO_ATOM_TYPE_IMS,
};
enum ofono_atom_watch_condition {
@@ -534,3 +535,4 @@ ofono_bool_t __ofono_private_network_request(ofono_private_network_cb_t cb,
#include <ofono/netmon.h>
#include <ofono/lte.h>
+#include <ofono/ims.h>
--
1.9.1
3 years, 3 months
[PATCH 3/6] ims: add implementation for IMS atom
by Ankit Navik
This implementation includes:
* D-Bus interface
* interaction with driver
---
Makefile.am | 2 +-
src/ims.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ofono.h | 2 +
3 files changed, 403 insertions(+), 1 deletion(-)
create mode 100644 src/ims.c
diff --git a/Makefile.am b/Makefile.am
index 165235e..199de08 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -630,7 +630,7 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/cdma-provision.c src/handsfree.c \
src/handsfree-audio.c src/bluetooth.h \
src/hfp.h src/siri.c \
- src/netmon.c src/lte.c \
+ src/netmon.c src/lte.c src/ims.c \
src/netmonagent.c src/netmonagent.h
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
diff --git a/src/ims.c b/src/ims.c
new file mode 100644
index 0000000..fb90dee
--- /dev/null
+++ b/src/ims.c
@@ -0,0 +1,400 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+
+#include "common.h"
+
+#define VOICE_CAPABLE_FLAG 0x1
+#define SMS_CAPABLE_FLAG 0x4
+
+struct ofono_ims {
+ int reg_info;
+ int ext_info;
+ const struct ofono_ims_driver *driver;
+ void *driver_data;
+ struct ofono_atom *atom;
+ DBusMessage *pending;
+};
+
+static GSList *g_drivers = NULL;
+
+static DBusMessage *ims_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_ims *ims = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ dbus_bool_t value;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ value = ims->reg_info ? TRUE : FALSE;
+ ofono_dbus_dict_append(&dict, "Registered", DBUS_TYPE_BOOLEAN, &value);
+
+ if (ims->ext_info != -1) {
+ value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE;
+ ofono_dbus_dict_append(&dict, "VoiceCapable",
+ DBUS_TYPE_BOOLEAN, &value);
+
+ value = ims->ext_info & SMS_CAPABLE_FLAG ? TRUE : FALSE;
+ ofono_dbus_dict_append(&dict, "SmsCapable",
+ DBUS_TYPE_BOOLEAN, &value);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static void ims_set_sms_capable(struct ofono_ims *ims, ofono_bool_t status)
+{
+ const char *path = __ofono_atom_get_path(ims->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t new_value = status;
+ dbus_bool_t old_value = ims->ext_info & SMS_CAPABLE_FLAG ? TRUE :
+ FALSE;
+
+ if (old_value == new_value)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_IMS_INTERFACE,
+ "SmsCapable",
+ DBUS_TYPE_BOOLEAN,
+ &new_value);
+}
+
+static void ims_set_voice_capable(struct ofono_ims *ims, ofono_bool_t status)
+{
+ const char *path = __ofono_atom_get_path(ims->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t new_value = status;
+ dbus_bool_t old_value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE :
+ FALSE;
+
+ if (old_value == new_value)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_IMS_INTERFACE,
+ "VoiceCapable",
+ DBUS_TYPE_BOOLEAN,
+ &new_value);
+}
+
+static void ims_set_registered(struct ofono_ims *ims, ofono_bool_t status)
+{
+ const char *path = __ofono_atom_get_path(ims->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t new_value = status;
+ dbus_bool_t old_value = ims->reg_info ? TRUE : FALSE;
+
+ if (old_value == new_value)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_IMS_INTERFACE,
+ "Registered",
+ DBUS_TYPE_BOOLEAN,
+ &new_value);
+}
+
+void ofono_ims_status_notify(struct ofono_ims *ims, int reg_info, int ext_info)
+{
+ dbus_bool_t new_reg_info;
+ dbus_bool_t new_voice_capable, new_sms_capable;
+
+ if (ims == NULL)
+ return;
+
+ DBG("%s reg_info:%d ext_info:%d", __ofono_atom_get_path(ims->atom),
+ reg_info, ext_info);
+
+ if (ims->ext_info == ext_info && ims->reg_info == reg_info)
+ return;
+
+ new_reg_info = reg_info ? TRUE : FALSE;
+ ims_set_registered(ims, new_reg_info);
+
+ if (ext_info < 0)
+ goto skip;
+
+ new_voice_capable = ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE;
+ ims_set_voice_capable(ims, new_voice_capable);
+
+ new_sms_capable = ext_info & SMS_CAPABLE_FLAG ? TRUE: FALSE;
+ ims_set_sms_capable(ims, new_sms_capable);
+
+skip:
+ ims->reg_info = reg_info;
+ ims->ext_info = ext_info;
+}
+
+static void registration_status_cb(const struct ofono_error *error,
+ int reg_info, int ext_info,
+ void *data)
+{
+ struct ofono_ims *ims = data;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ DBG("Error during IMS registration/unregistration");
+ return;
+ }
+
+ ofono_ims_status_notify(ims, reg_info, ext_info);
+}
+
+static void register_cb(const struct ofono_error *error, void *data)
+{
+ struct ofono_ims *ims = data;
+ DBusMessage *reply;
+
+ if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
+ reply = dbus_message_new_method_return(ims->pending);
+ else
+ reply = __ofono_error_failed(ims->pending);
+
+ __ofono_dbus_pending_reply(&ims->pending, reply);
+
+ if (ims->driver->registration_status == NULL)
+ return;
+
+ ims->driver->registration_status(ims, registration_status_cb, ims);
+}
+
+static DBusMessage *ofono_ims_send_register(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_ims *ims = data;
+
+ if (ims->pending)
+ return __ofono_error_busy(msg);
+
+ if (ims->driver->ims_register == NULL)
+ return __ofono_error_not_implemented(msg);
+
+ ims->pending = dbus_message_ref(msg);
+
+ ims->driver->ims_register(ims, register_cb, ims);
+
+ return NULL;
+}
+
+static DBusMessage *ofono_ims_unregister(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_ims *ims = data;
+
+ if (ims->pending)
+ return __ofono_error_busy(msg);
+
+ if (ims->driver->ims_unregister == NULL)
+ return __ofono_error_not_implemented(msg);
+
+ ims->pending = dbus_message_ref(msg);
+
+ ims->driver->ims_unregister(ims, register_cb, ims);
+
+ return NULL;
+}
+
+static const GDBusMethodTable ims_methods[] = {
+ { GDBUS_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ ims_get_properties) },
+ { GDBUS_ASYNC_METHOD("Register", NULL, NULL,
+ ofono_ims_send_register) },
+ { GDBUS_ASYNC_METHOD("Unregister", NULL, NULL,
+ ofono_ims_unregister) },
+ { }
+};
+
+static const GDBusSignalTable ims_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { }
+};
+
+static void ims_atom_remove(struct ofono_atom *atom)
+{
+ struct ofono_ims *ims = __ofono_atom_get_data(atom);
+
+ DBG("atom: %p", atom);
+
+ if (ims == NULL)
+ return;
+
+ if (ims->driver && ims->driver->remove)
+ ims->driver->remove(ims);
+
+ g_free(ims);
+}
+
+struct ofono_ims *ofono_ims_create(struct ofono_modem *modem,
+ const char *driver, void *data)
+{
+ struct ofono_ims *ims;
+ GSList *l;
+
+ if (driver == NULL)
+ return NULL;
+
+ ims = g_try_new0(struct ofono_ims, 1);
+
+ if (ims == NULL)
+ return NULL;
+
+ ims->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_IMS,
+ ims_atom_remove, ims);
+
+ for (l = g_drivers; l; l = l->next) {
+ const struct ofono_ims_driver *drv = l->data;
+
+ if (g_strcmp0(drv->name, driver))
+ continue;
+
+ if (drv->probe(ims, data) < 0)
+ continue;
+
+ ims->driver = drv;
+ break;
+ }
+
+ DBG("IMS atom created");
+
+ return ims;
+}
+
+int ofono_ims_driver_register(const struct ofono_ims_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ if (d->probe == NULL)
+ return -EINVAL;
+
+ g_drivers = g_slist_prepend(g_drivers, (void *) d);
+
+ return 0;
+}
+
+void ofono_ims_driver_unregister(const struct ofono_ims_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ g_drivers = g_slist_remove(g_drivers, (void *) d);
+}
+
+static void ims_atom_unregister(struct ofono_atom *atom)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+ const char *path = __ofono_atom_get_path(atom);
+
+ ofono_modem_remove_interface(modem, OFONO_IMS_INTERFACE);
+ g_dbus_unregister_interface(conn, path, OFONO_IMS_INTERFACE);
+}
+
+static void ofono_ims_finish_register(struct ofono_ims *ims)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(ims->atom);
+ const char *path = __ofono_atom_get_path(ims->atom);
+
+ if (!g_dbus_register_interface(conn, path,
+ OFONO_IMS_INTERFACE,
+ ims_methods, ims_signals, NULL,
+ ims, NULL)) {
+ ofono_error("could not create %s interface",
+ OFONO_IMS_INTERFACE);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, OFONO_IMS_INTERFACE);
+
+ __ofono_atom_register(ims->atom, ims_atom_unregister);
+}
+
+static void ims_init_registration_status_cb(const struct ofono_error *error,
+ int reg_info, int ext_info,
+ void *data)
+{
+ struct ofono_ims *ims = data;
+
+ ofono_ims_finish_register(ims);
+}
+
+void ofono_ims_register(struct ofono_ims *ims)
+{
+ struct ofono_modem *modem = __ofono_atom_get_modem(ims->atom);
+ struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+ const char *imsi = ofono_sim_get_imsi(sim);
+
+ if (imsi == NULL) {
+ ofono_error("No sim atom required for registering IMS atom.");
+ return;
+ }
+
+ if (ims->driver->registration_status) {
+ ims->driver->registration_status(ims,
+ ims_init_registration_status_cb, ims);
+ return;
+ }
+
+ ofono_ims_finish_register(ims);
+}
+
+void ofono_ims_remove(struct ofono_ims *ims)
+{
+ __ofono_atom_free(ims->atom);
+}
+
+void ofono_ims_set_data(struct ofono_ims *ims, void *data)
+{
+ ims->driver_data = data;
+}
+
+void *ofono_ims_get_data(const struct ofono_ims *ims)
+{
+ return ims->driver_data;
+}
diff --git a/src/ofono.h b/src/ofono.h
index a797b7f..0da11a2 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -154,6 +154,7 @@ enum ofono_atom_type {
OFONO_ATOM_TYPE_SIRI,
OFONO_ATOM_TYPE_NETMON,
OFONO_ATOM_TYPE_LTE,
+ OFONO_ATOM_TYPE_IMS,
};
enum ofono_atom_watch_condition {
@@ -534,3 +535,4 @@ ofono_bool_t __ofono_private_network_request(ofono_private_network_cb_t cb,
#include <ofono/netmon.h>
#include <ofono/lte.h>
+#include <ofono/ims.h>
--
1.9.1
3 years, 3 months
[PATCH 1/6] doc: add ims atom documentation
by Ankit Navik
---
Makefile.am | 3 ++-
doc/ims-api.txt | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 1 deletion(-)
create mode 100755 doc/ims-api.txt
diff --git a/Makefile.am b/Makefile.am
index 5368b61..3ce6d50 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -680,7 +680,8 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
doc/networkmonitor-api.txt \
doc/allowed-apns-api.txt \
doc/lte-api.txt \
- doc/cinterion-hardware-monitor-api.txt
+ doc/cinterion-hardware-monitor-api.txt \
+ doc/ims-api.txt
test_scripts = test/backtrace \
diff --git a/doc/ims-api.txt b/doc/ims-api.txt
new file mode 100755
index 0000000..4f9a19b
--- /dev/null
+++ b/doc/ims-api.txt
@@ -0,0 +1,60 @@
+IpMultimediaSystem Hierarchy
+============================
+
+Service org.ofono
+Interface org.ofono.IpMultimediaSystem
+Object path [variable prefix]/{modem0,modem1,...}
+
+
+Methods dict GetProperties()
+
+ Returns all IpMultimediaSystem configuration properties.
+
+ void SetProperty(string property, variant value)
+
+ Changes the value of the specified property. Only
+ properties that are listed as readwrite are
+ changeable. On success a PropertyChanged signal
+ will be emitted.
+
+ Possible Errors: [service].Error.InProgress
+ [service].Error.InvalidArguments
+ [service].Error.Failed
+
+ void Register()
+
+ Attempts to register to IMS. A successful method return
+ indicates that the registration process could be
+ initiated successfully. The actual registration state
+ will be reflected by the 'Registered' property.
+
+ Possible Errors: [service].Error.InProgress
+ [service].Error.NotImplemented
+
+ void Unregister()
+
+ Attempts to unregister from IMS. A successful method
+ return indicates that the unregistration process could
+ be initiated successfully. The actual unregistration
+ state will be reflected by the 'Registered' property.
+
+ Possible Errors: [service].Error.InProgress
+ [service].Error.NotImplemented
+
+Signals PropertyChanged(string property, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties boolean Registered [readonly]
+
+ Contains the current IMS registration state.
+
+ boolean VoiceCapable [readonly, optional]
+
+ Boolean representing whether voice call transfer over
+ RTP (IMS) is available.
+
+ boolean SmsCapable [readonly, optional]
+
+ Boolean representing whether SMS-over-IMS is available.
--
1.9.1
3 years, 3 months
[PATCH] nokia-gpio: do not create links to gpios in /dev/cmt
by Clayton Craft
The nokia-gpio plugin should not try to create symlinks to relevant gpio
pins under /dev/cmt, since the location it is looking is no longer
correct on newer kernels and it might change again in the future. This
patch removes code from nokia-gpio that tries to create a symlink.
Users will now need to symlink the modem gpios to /dev/cmt themselves.
On the 4.13 kernel, this can be done by, for example, adding a udev rule
to:
# ln -sf /sys/bus/hsi/devices/n900-modem /dev/cmt
---
plugins/nokia-gpio.c | 67 ++++------------------------------------------------
1 file changed, 4 insertions(+), 63 deletions(-)
diff --git a/plugins/nokia-gpio.c b/plugins/nokia-gpio.c
index 7a93106c..1d014337 100644
--- a/plugins/nokia-gpio.c
+++ b/plugins/nokia-gpio.c
@@ -632,74 +632,15 @@ static void phonet_status_cb(GIsiModem *idx, enum GIsiPhonetLinkState state,
static int gpio_probe_links(void)
{
- char const *gpiodir = "/sys/class/gpio";
char const *cmtdir = "/dev/cmt";
- DIR *gpio;
- struct dirent *d;
- if (file_exists(cmtdir)) {
- DBG("Using %s", cmtdir);
- return 0;
- }
-
- DBG("Using %s: trying to make links to %s", gpiodir, cmtdir);
-
- if (!dir_exists(cmtdir)) {
- if (mkdir(cmtdir, 0755) == -1) {
- DBG("%s: %s", cmtdir, strerror(errno));
- return -(errno = ENODEV);
- }
- }
-
- gpio = opendir(gpiodir);
- if (gpio == NULL) {
- DBG("%s: %s", "gpiodir", strerror(errno));
+ if (!file_exists(cmtdir)) {
+ DBG("%s: %s", cmtdir, strerror(errno));
return -(errno = ENODEV);
}
- while ((d = readdir(gpio)) != NULL) {
- char nn[PATH_MAX], name[PATH_MAX], from[PATH_MAX], to[PATH_MAX];
- FILE *nf;
- size_t len;
-
- snprintf(nn, sizeof nn, "%s/%s/name", gpiodir, d->d_name);
-
- nf = fopen(nn, "rb");
- if (nf == NULL) {
- DBG("%s: %s", nn, strerror(errno));
- continue;
- }
-
- len = fread(name, sizeof name, 1, nf);
-
- if (ferror(nf)) {
- DBG("read from %s: %s", nn, strerror(errno));
- fclose(nf);
- continue;
- }
-
- fclose(nf);
-
- if (len < 4)
- continue;
-
- name[--len] = '\0';
-
- if (strncmp(name, "cmt_", 4))
- continue;
-
- snprintf(from, sizeof from, "%s/%s", gpiodir, d->d_name);
- snprintf(to, sizeof to, "%s/%s", cmtdir, name);
-
- if (symlink(from, to) == -1)
- DBG("%s: %s", to, strerror(errno));
- }
-
- DBG("%s: %s", "/sys/class/gpio", strerror(errno));
-
- (void) closedir(gpio);
-
- return -(errno = ENODEV);
+ DBG("Using %s", cmtdir);
+ return 0;
}
--
2.14.1
3 years, 3 months
[PATCH 1/2] include: Add ofono_modem_get_sim
by Slava Monich
---
include/modem.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/modem.h b/include/modem.h
index e40b23e..c93b3d2 100644
--- a/include/modem.h
+++ b/include/modem.h
@@ -29,6 +29,7 @@ extern "C" {
#include <ofono/types.h>
struct ofono_modem;
+struct ofono_sim;
enum ofono_modem_type {
OFONO_MODEM_TYPE_HARDWARE = 0,
@@ -80,6 +81,7 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
const char *interface);
const char *ofono_modem_get_path(struct ofono_modem *modem);
+struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem);
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);
--
1.9.1
3 years, 3 months