From d2fd1721f3d344c4e17c1b53031282ce0ae2f79a Mon Sep 17 00:00:00 2001 From: Shweta Jain Date: Thu, 30 Jul 2020 22:37:56 +0300 Subject: [PATCH] xmm7xxx-enable-esim-feature-in-xmm_ofono --- plugins/xmm7xxx.c | 391 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) diff --git a/plugins/xmm7xxx.c b/plugins/xmm7xxx.c index b3aaf852..bf90833d 100644 --- a/plugins/xmm7xxx.c +++ b/plugins/xmm7xxx.c @@ -59,9 +59,12 @@ #include "ofono.h" #include "gdbus.h" +#include "util.h" +#include "dbus.h" #define OFONO_COEX_INTERFACE OFONO_SERVICE ".intel.LteCoexistence" #define OFONO_COEX_AGENT_INTERFACE OFONO_SERVICE ".intel.LteCoexistenceAgent" +#define OFONO_EUICC_LPA_INTERFACE OFONO_SERVICE ".intel.EuiccLpa" #define NET_BAND_LTE_INVALID 0 #define NET_BAND_LTE_1 101 @@ -73,6 +76,8 @@ static const char *none_prefix[] = { NULL }; static const char *xsimstate_prefix[] = { "+XSIMSTATE:", NULL }; static const char *xnvmplmn_prefix[] = { "+XNVMPLMN:", NULL }; +static const char *ccho_prefix[] = { "+CCHO:", NULL }; +static const char *cgla_prefix[] = { "+CGLA:", NULL }; struct bt_coex_info { int safe_tx_min; @@ -108,8 +113,380 @@ struct xmm7xxx_data { ofono_bool_t have_sim; unsigned int netreg_watch; int xsim_status; + ofono_bool_t stk_enable; + ofono_bool_t enable_euicc; }; +/* eUICC Implementation */ +#define EUICC_EID_CMD "80e2910006BF3E035C015A00" +#define EUICC_ISDR_AID "A0000005591010FFFFFFFF8900000100" + +struct xmm7xxx_euicc { + GAtChat *chat; + struct ofono_modem *modem; + char *eid; + int channel; + char *command; + int length; + DBusMessage *pending; + ofono_bool_t is_registered; +}; + +static void euicc_cleanup(void *data) +{ + struct xmm7xxx_euicc *euicc = data; + + g_free(euicc->command); + g_free(euicc->eid); + + if (euicc->pending) + dbus_message_unref(euicc->pending); + + g_free(euicc); +} + +static void euicc_release_isdr(struct xmm7xxx_euicc *euicc) +{ + char buff[20]; + + snprintf(buff, sizeof(buff), "AT+CCHC=%u", euicc->channel); + + g_at_chat_send(euicc->chat, buff, none_prefix, NULL, NULL, NULL); + + euicc->channel = -1; + g_free(euicc->command); + euicc->command = NULL; + euicc->length = 0; +} + +static void euicc_pending_reply(struct xmm7xxx_euicc *euicc, + const char *resp) +{ + DBusMessage *reply; + DBusMessageIter iter, array; + unsigned char *response = NULL; + long length; + int bufferBytesSize = strlen(resp) / 2; + + reply = dbus_message_new_method_return(euicc->pending); + if (reply == NULL) + goto done; + + response = g_new0(unsigned char, bufferBytesSize); + decode_hex_own_buf(resp, strlen(resp), &length, '\0', response ); + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &response, length); + dbus_message_iter_close_container(&iter, &array); + + g_free(response); +done: + __ofono_dbus_pending_reply(&euicc->pending, reply); +} + +static DBusMessage *euicc_get_properties(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct xmm7xxx_euicc *euicc = data; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter dict; + const char *eid = NULL; + + 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); + + eid = euicc->eid; + ofono_dbus_dict_append(&dict, "EID", DBUS_TYPE_STRING, &eid); + + dbus_message_iter_close_container(&iter, &dict); + + return reply; +} + +static DBusMessage *euicc_transmit_pdu(DBusConnection *conn, + DBusMessage *msg, void *data); +static DBusMessage *euicc_select_isdr_req(DBusConnection *conn, + DBusMessage *msg, void *data); +static DBusMessage *euicc_release_isdr_req(DBusConnection *conn, + DBusMessage *msg, void *data); + +static const GDBusMethodTable euicc_methods[] = { + { GDBUS_ASYNC_METHOD("TransmitLpaApdu", + GDBUS_ARGS({ "pdu", "ay" }), + GDBUS_ARGS({ "pdu", "ay" }), + euicc_transmit_pdu) }, + { GDBUS_ASYNC_METHOD("SelectISDR", + NULL, NULL, euicc_select_isdr_req) }, + { GDBUS_ASYNC_METHOD("ReleaseISDR", + NULL, NULL, euicc_release_isdr_req) }, + { GDBUS_ASYNC_METHOD("GetProperties", + NULL, GDBUS_ARGS({ "properties", "a{sv}" }), + euicc_get_properties) }, + { } +}; + +static const GDBusSignalTable euicc_signals[] = { + { GDBUS_SIGNAL("PropertyChanged", + GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, + { } +}; + +static void euicc_register(struct xmm7xxx_euicc *euicc) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = ofono_modem_get_path(euicc->modem); + + DBG("euicc_register"); + + if (!g_dbus_register_interface(conn, path, OFONO_EUICC_LPA_INTERFACE, + euicc_methods, + euicc_signals, + NULL, euicc, euicc_cleanup)) { + ofono_error("Could not register %s interface under %s", + OFONO_EUICC_LPA_INTERFACE, path); + return; + } + + ofono_modem_add_interface(euicc->modem, OFONO_EUICC_LPA_INTERFACE); + euicc->is_registered = TRUE; + + ofono_dbus_signal_property_changed(conn, path, + OFONO_EUICC_LPA_INTERFACE, "EID", + DBUS_TYPE_STRING, &euicc->eid); +} + +static void euicc_send_cmd_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct xmm7xxx_euicc *euicc = user_data; + GAtResultIter iter; + int length; + const char *resp; + + DBG("ok %d", ok); + + if (!ok) { + g_free(euicc->command); + + if (!euicc->is_registered) { + g_free(euicc->eid); + g_free(euicc); + } + + return; + } + + DBG("Success"); + + g_at_result_iter_init(&iter, result); + DBG("Iter init"); + + if (!g_at_result_iter_next(&iter, "+CGLA:")) + return; + + DBG("CGLA"); + + if (!g_at_result_iter_next_number(&iter, &length)) + return; + + DBG("length = %d", length); + + if (!g_at_result_iter_next_string(&iter, &resp)) + return; + + DBG("resp = %s", resp); + + if (!euicc->is_registered) { + g_free(euicc->eid); + euicc->eid = g_strdup(resp+10); + euicc_release_isdr(euicc); + + /* eid is present register interface*/ + euicc_register(euicc); + } + + DBG("pending = %p", euicc->pending); + + if (euicc->pending) + euicc_pending_reply(euicc, resp); +} + +static void euicc_send_cmd(struct xmm7xxx_euicc *euicc) +{ + char *buff = g_new0(char, euicc->length + 20); + + sprintf(buff, "AT+CGLA=%u,%u,\"%s\"", + euicc->channel, euicc->length, euicc->command); + + g_at_chat_send(euicc->chat, buff, cgla_prefix, + euicc_send_cmd_cb, euicc, NULL); + + g_free(buff); +} + +static void euicc_select_isdr_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct xmm7xxx_euicc *euicc = user_data; + GAtResultIter iter; + + DBG("ok %d", ok); + + if (!ok) { + g_free (euicc->command); + + if (!euicc->is_registered) { + g_free(euicc->eid); + g_free(euicc); + } + + return; + } + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CCHO:")) + return; + + g_at_result_iter_next_number(&iter, &euicc->channel); + + if (!euicc->is_registered) + euicc_send_cmd(euicc); + + if (euicc->pending) + __ofono_dbus_pending_reply(&euicc->pending, + dbus_message_new_method_return(euicc->pending)); +} + +static void euicc_select_isdr(struct xmm7xxx_euicc *euicc) +{ + char buff[50]; + + snprintf(buff, sizeof(buff), "AT+CCHO=\"%s\"", EUICC_ISDR_AID); + + g_at_chat_send(euicc->chat, buff, ccho_prefix, + euicc_select_isdr_cb, euicc, NULL); +} + +static DBusMessage *euicc_transmit_pdu(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct xmm7xxx_euicc *euicc = data; + DBusMessageIter iter, array; + const unsigned char *command; + int length; + + DBG("euicc_transmit_pdu"); + + if (euicc->pending) + return __ofono_error_busy(msg); + + if (euicc->channel < 0) + return __ofono_error_not_available(msg); + + if (!dbus_message_iter_init(msg, &iter)) + return __ofono_error_invalid_args(msg); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return __ofono_error_invalid_args(msg); + + dbus_message_iter_recurse(&iter, &array); + + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE) + return __ofono_error_invalid_args(msg); + + dbus_message_iter_get_fixed_array(&array, &command, &length); + + g_free(euicc->command); + euicc->length = length * 2; + euicc->command = g_new0(char, euicc->length + 1); + encode_hex_own_buf(command,(long)length,0, euicc->command); + euicc->pending = dbus_message_ref(msg); + + euicc_send_cmd(euicc); + + return NULL; +} + +static DBusMessage *euicc_select_isdr_req(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct xmm7xxx_euicc *euicc = data; + + DBG("euicc_select_isdr_req"); + + if (euicc->pending) + return __ofono_error_busy(msg); + + euicc_select_isdr(euicc); + + euicc->pending = dbus_message_ref(msg); + + return NULL; +} + +static DBusMessage *euicc_release_isdr_req(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct xmm7xxx_euicc *euicc = data; + + DBG("euicc_release_isdr_req"); + + if (euicc->pending) + return __ofono_error_busy(msg); + + euicc_release_isdr(euicc); + + return dbus_message_new_method_return(msg); +} + +static void euicc_update_eid(struct xmm7xxx_euicc *euicc) +{ + g_free(euicc->command); + euicc->command = g_strdup(EUICC_EID_CMD); + euicc->length = sizeof(EUICC_EID_CMD) - 1; + + euicc_select_isdr(euicc); +} + +static void xmm_euicc_enable(struct ofono_modem *modem, void *data) +{ + struct xmm7xxx_euicc *euicc = g_new0(struct xmm7xxx_euicc, 1); + + DBG("euicc enable"); + + euicc->chat = data; + euicc->modem = modem; + euicc->eid = g_strdup("INVALID"); + euicc->channel = -1; + euicc->command = NULL; + euicc->pending = NULL; + euicc->is_registered = FALSE; + + euicc_update_eid(euicc); +} + +static void xmm_euicc_disable(struct ofono_modem *modem) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = ofono_modem_get_path(modem); + + if (g_dbus_unregister_interface(conn, path, OFONO_EUICC_LPA_INTERFACE)) + ofono_modem_remove_interface(modem, OFONO_EUICC_LPA_INTERFACE); +} +/* eUICC Implementation Ends */ + /* Coex Implementation */ enum wlan_bw { WLAN_BW_UNSUPPORTED = -1, @@ -999,6 +1376,9 @@ static void switch_sim_state_status(struct ofono_modem *modem, int status) ofono_sim_initialized_notify(data->sim); break; + case 18: + data->enable_euicc = TRUE; + break; default: ofono_warn("Unknown SIM state %d received", status); break; @@ -1176,6 +1556,7 @@ static int xmm7xxx_disable(struct ofono_modem *modem) data->netreg_watch = 0; } + xmm_euicc_disable(modem); return -EINPROGRESS; } @@ -1188,6 +1569,8 @@ static void xmm7xxx_pre_sim(struct ofono_modem *modem) ofono_devinfo_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat); data->sim = ofono_sim_create(modem, OFONO_VENDOR_XMM, "atmodem", data->chat); + xmm_euicc_enable(modem, data->chat); + ofono_stk_create(modem, 0, "atmodem", data->chat); } static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data) @@ -1195,8 +1578,15 @@ static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data) struct cb_data *cbd = user_data; ofono_modem_online_cb_t cb = cbd->cb; struct ofono_error error; + struct ofono_modem *modem = cbd->data; + struct xmm7xxx_data *data = ofono_modem_get_data(modem); decode_at_error(&error, g_at_result_final_response(result)); + + if (data->enable_euicc == TRUE && data->stk_enable == TRUE) + g_at_chat_send(data->chat, "AT+CFUN=16", none_prefix, + NULL, NULL, NULL); + cb(&error, cbd->data); } @@ -1208,6 +1598,7 @@ static void xmm7xxx_set_online(struct ofono_modem *modem, ofono_bool_t online, char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4"; DBG("modem %p %s", modem, online ? "online" : "offline"); + data->stk_enable = online; if (g_at_chat_send(data->chat, command, none_prefix, set_online_cb, cbd, g_free) > 0)