broadband-modem-mbim: implement 3GPP USSD support

This commit is contained in:
Aleksander Morgado
2018-08-21 16:50:15 +00:00
committed by Dan Williams
parent eda46d05cf
commit 532ff24101
+617 -5
View File
@@ -35,6 +35,7 @@
#include "mm-bearer-list.h"
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
#include "mm-iface-modem-3gpp-ussd.h"
#include "mm-iface-modem-location.h"
#include "mm-iface-modem-messaging.h"
#include "mm-iface-modem-signal.h"
@@ -47,6 +48,7 @@
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface);
static void iface_modem_location_init (MMIfaceModemLocation *iface);
static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
static void iface_modem_signal_init (MMIfaceModemSignal *iface);
@@ -62,6 +64,7 @@ static MMIfaceModemSignal *iface_modem_signal_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbim, mm_broadband_modem_mbim, MM_TYPE_BROADBAND_MODEM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_USSD, iface_modem_3gpp_ussd_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init)
@@ -79,6 +82,7 @@ typedef enum {
PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO = 1 << 4,
PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE = 1 << 5,
PROCESS_NOTIFICATION_FLAG_PCO = 1 << 6,
PROCESS_NOTIFICATION_FLAG_USSD = 1 << 7,
} ProcessNotificationFlag;
struct _MMBroadbandModemMbimPrivate {
@@ -108,6 +112,9 @@ struct _MMBroadbandModemMbimPrivate {
gchar *current_operator_id;
gchar *current_operator_name;
/* USSD helpers */
GTask *pending_ussd_action;
/* Access technology updates */
MbimDataClass available_data_classes;
MbimDataClass highest_available_data_class;
@@ -2520,6 +2527,25 @@ basic_connect_extensions_notification (MMBroadbandModemMbim *self,
}
}
static void
process_ussd_notification (MMBroadbandModemMbim *self,
MbimMessage *notification);
static void
ussd_notification (MMBroadbandModemMbim *self,
MbimMessage *notification)
{
if (mbim_message_indicate_status_get_cid (notification) != MBIM_CID_USSD) {
mm_warn ("unexpected USSD notification (cid %u)", mbim_message_indicate_status_get_cid (notification));
return;
}
if (!(self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_USSD))
return;
process_ussd_notification (self, notification);
}
static void
device_notification_cb (MbimDevice *device,
MbimMessage *notification,
@@ -2543,6 +2569,9 @@ device_notification_cb (MbimDevice *device,
case MBIM_SERVICE_SMS:
sms_notification (self, notification);
break;
case MBIM_SERVICE_USSD:
ussd_notification (self, notification);
break;
default:
/* Ignore */
break;
@@ -2557,14 +2586,15 @@ common_setup_cleanup_unsolicited_events_sync (MMBroadbandModemMbim *self,
if (!device)
return;
mm_dbg ("Supported notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s)",
mm_dbg ("Supported notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s), ussd (%s)",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no");
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no");
if (setup) {
/* Don't re-enable it if already there */
@@ -2732,16 +2762,17 @@ common_enable_disable_unsolicited_events (MMBroadbandModemMbim *self,
if (!peek_device (self, &device, callback, user_data))
return;
mm_dbg ("Enabled notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s)",
mm_dbg ("Enabled notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s), ussd (%s)",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no");
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no");
entries = g_new0 (MbimEventEntry *, 4);
entries = g_new0 (MbimEventEntry *, 5);
/* Basic connect service */
if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ||
@@ -2787,6 +2818,16 @@ common_enable_disable_unsolicited_events (MMBroadbandModemMbim *self,
n_entries++;
}
/* USSD service */
if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_USSD) {
entries[n_entries] = g_new (MbimEventEntry, 1);
memcpy (&(entries[n_entries]->device_service_id), MBIM_UUID_USSD, sizeof (MbimUuid));
entries[n_entries]->cids_count = 1;
entries[n_entries]->cids = g_new0 (guint32, 1);
entries[n_entries]->cids[0] = MBIM_CID_USSD;
n_entries++;
}
task = g_task_new (self, NULL, callback, user_data);
request = (mbim_message_device_service_subscribe_list_set_new (
@@ -3549,6 +3590,551 @@ modem_signal_load_values (MMIfaceModemSignal *self,
task);
}
/*****************************************************************************/
/* Check if USSD supported (3GPP/USSD interface) */
static gboolean
modem_3gpp_ussd_check_support_finish (MMIfaceModem3gppUssd *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
modem_3gpp_ussd_check_support (MMIfaceModem3gppUssd *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (self, NULL, callback, user_data);
g_task_return_boolean (task, MM_BROADBAND_MODEM_MBIM (self)->priv->is_ussd_supported);
g_object_unref (task);
}
/*****************************************************************************/
/* USSD encoding/deconding helpers
*
* Note: we don't care about subclassing the ussd_encode/decode methods in the
* interface, as we're going to use this methods just here.
*/
static GByteArray *
ussd_encode (const gchar *command,
guint32 *scheme,
GError **error)
{
GByteArray *array;
if (mm_charset_can_convert_to (command, MM_MODEM_CHARSET_GSM)) {
guint8 *gsm;
guint8 *packed;
guint32 len = 0;
guint32 packed_len = 0;
*scheme = MM_MODEM_GSM_USSD_SCHEME_7BIT;
gsm = mm_charset_utf8_to_unpacked_gsm (command, &len);
if (!gsm) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Failed to encode USSD command in GSM7 charset");
return NULL;
}
packed = mm_charset_gsm_pack (gsm, len, 0, &packed_len);
g_free (gsm);
array = g_byte_array_new_take (packed, packed_len);
} else {
*scheme = MM_MODEM_GSM_USSD_SCHEME_UCS2;
array = g_byte_array_sized_new (strlen (command) * 2);
if (!mm_modem_charset_byte_array_append (array, command, FALSE, MM_MODEM_CHARSET_UCS2)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Failed to encode USSD command in UCS2 charset");
g_byte_array_unref (array);
return NULL;
}
}
if (array->len > 160) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"Failed to encode USSD command: encoded data too long (%u > 160)", array->len);
g_byte_array_unref (array);
return NULL;
}
return array;
}
static gchar *
ussd_decode (guint32 scheme,
GByteArray *data,
GError **error)
{
gchar *decoded = NULL;
if (scheme == MM_MODEM_GSM_USSD_SCHEME_7BIT) {
guint8 *unpacked;
guint32 unpacked_len;
unpacked = mm_charset_gsm_unpack ((const guint8 *)data->data, (data->len * 8) / 7, 0, &unpacked_len);
decoded = (gchar *) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len);
if (!decoded)
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Error decoding USSD command in 0x%04x scheme (GSM7 charset)",
scheme);
} else if (scheme == MM_MODEM_GSM_USSD_SCHEME_UCS2) {
decoded = mm_modem_charset_byte_array_to_utf8 (data, MM_MODEM_CHARSET_UCS2);
if (!decoded)
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Error decoding USSD command in 0x%04x scheme (UCS2 charset)",
scheme);
} else
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Failed to decode USSD command in unsupported 0x%04x scheme", scheme);
return decoded;
}
/*****************************************************************************/
/* USSD notifications */
static void
process_ussd_message (MMBroadbandModemMbim *self,
MbimUssdResponse ussd_response,
MbimUssdSessionState ussd_session_state,
guint32 scheme,
guint32 data_size,
const guint8 *data)
{
GTask *task = NULL;
MMModem3gppUssdSessionState ussd_state = MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE;
GByteArray *bytearray = NULL;
gchar *converted = NULL;
GError *error = NULL;
/* Steal task and balance out received reference */
if (self->priv->pending_ussd_action) {
task = self->priv->pending_ussd_action;
self->priv->pending_ussd_action = NULL;
}
if (data_size)
bytearray = g_byte_array_append (g_byte_array_new (), data, data_size);
switch (ussd_response) {
case MBIM_USSD_RESPONSE_NO_ACTION_REQUIRED:
/* no further action required */
converted = ussd_decode (scheme, bytearray, &error);
if (!converted)
break;
/* Response to the user's request? */
if (task)
break;
/* Network-initiated USSD-Notify */
mm_iface_modem_3gpp_ussd_update_network_notification (MM_IFACE_MODEM_3GPP_USSD (self), converted);
g_clear_pointer (&converted, g_free);
break;
case MBIM_USSD_RESPONSE_ACTION_REQUIRED:
/* further action required */
ussd_state = MM_MODEM_3GPP_USSD_SESSION_STATE_USER_RESPONSE;
converted = ussd_decode (scheme, bytearray, &error);
if (!converted)
break;
/* Response to the user's request? */
if (task)
break;
/* Network-initiated USSD-Request */
mm_iface_modem_3gpp_ussd_update_network_request (MM_IFACE_MODEM_3GPP_USSD (self), converted);
g_clear_pointer (&converted, g_free);
break;
case MBIM_USSD_RESPONSE_TERMINATED_BY_NETWORK:
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "USSD terminated by network");
break;
case MBIM_USSD_RESPONSE_OTHER_LOCAL_CLIENT:
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Another ongoing USSD operation is in progress");
break;
case MBIM_USSD_RESPONSE_OPERATION_NOT_SUPPORTED:
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Operation not supported");
break;
case MBIM_USSD_RESPONSE_NETWORK_TIMEOUT:
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Network timeout");
break;
default:
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Unknown USSD response (%u)", ussd_response);
break;
}
mm_iface_modem_3gpp_ussd_update_state (MM_IFACE_MODEM_3GPP_USSD (self), ussd_state);
if (bytearray)
g_byte_array_unref (bytearray);
/* Complete the pending action */
if (task) {
if (error)
g_task_return_error (task, error);
else if (converted)
g_task_return_pointer (task, converted, g_free);
else
g_assert_not_reached ();
return;
}
/* If no pending task, just report the error */
if (error) {
mm_dbg ("Network reported USSD message: %s", error->message);
g_error_free (error);
}
g_assert (!converted);
}
static void
process_ussd_notification (MMBroadbandModemMbim *self,
MbimMessage *notification)
{
MbimUssdResponse ussd_response;
MbimUssdSessionState ussd_session_state;
guint32 scheme;
guint32 data_size;
const guint8 *data;
if (mbim_message_ussd_notification_parse (notification,
&ussd_response,
&ussd_session_state,
&scheme,
&data_size,
&data,
NULL)) {
mm_dbg ("Received USSD indication: %s, session state: %s, scheme: 0x%x, data size: %u bytes",
mbim_ussd_response_get_string (ussd_response),
mbim_ussd_session_state_get_string (ussd_session_state),
scheme,
data_size);
process_ussd_message (self, ussd_response, ussd_session_state, scheme, data_size, data);
}
}
/*****************************************************************************/
/* Setup/Cleanup unsolicited result codes (3GPP/USSD interface) */
static gboolean
modem_3gpp_ussd_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gppUssd *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
common_setup_flag_ussd_ready (MMBroadbandModemMbim *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
if (!common_setup_cleanup_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
common_setup_cleanup_unsolicited_ussd_events (MMBroadbandModemMbim *self,
gboolean setup,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (self, NULL, callback, user_data);
g_task_set_task_data (task, GINT_TO_POINTER (setup), NULL);
if (setup)
self->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_USSD;
else
self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_USSD;
common_setup_cleanup_unsolicited_events (self, setup, (GAsyncReadyCallback)common_setup_flag_ussd_ready, task);
}
static void
modem_3gpp_ussd_cleanup_unsolicited_events (MMIfaceModem3gppUssd *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
common_setup_cleanup_unsolicited_ussd_events (MM_BROADBAND_MODEM_MBIM (self), FALSE, callback, user_data);
}
static void
modem_3gpp_ussd_setup_unsolicited_events (MMIfaceModem3gppUssd *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
common_setup_cleanup_unsolicited_ussd_events (MM_BROADBAND_MODEM_MBIM (self), TRUE, callback, user_data);
}
/*****************************************************************************/
/* Enable/Disable URCs (3GPP/USSD interface) */
static gboolean
modem_3gpp_ussd_enable_disable_unsolicited_events_finish (MMIfaceModem3gppUssd *self,
GAsyncResult *res,
GError **error)
{
return common_enable_disable_unsolicited_events_finish (MM_BROADBAND_MODEM_MBIM (self), res, error);
}
static void
modem_3gpp_ussd_disable_unsolicited_events (MMIfaceModem3gppUssd *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
self->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_USSD;
common_enable_disable_unsolicited_events (self, callback, user_data);
}
static void
modem_3gpp_ussd_enable_unsolicited_events (MMIfaceModem3gppUssd *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
self->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_USSD;
common_enable_disable_unsolicited_events (self, callback, user_data);
}
/*****************************************************************************/
/* Send command (3GPP/USSD interface) */
static gchar *
modem_3gpp_ussd_send_finish (MMIfaceModem3gppUssd *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_pointer (G_TASK (res), error);
}
static void
ussd_send_ready (MbimDevice *device,
GAsyncResult *res,
MMBroadbandModemMbim *self)
{
MbimMessage *response;
GError *error = NULL;
MbimUssdResponse ussd_response;
MbimUssdSessionState ussd_session_state;
guint32 scheme;
guint32 data_size;
const guint8 *data;
/* Note: if there is a cached task, it is ALWAYS completed here */
response = mbim_device_command_finish (device, res, &error);
if (response &&
mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) &&
mbim_message_ussd_response_parse (response,
&ussd_response,
&ussd_session_state,
&scheme,
&data_size,
&data,
&error)) {
mm_dbg ("Received USSD response: %s, session state: %s, scheme: 0x%x, data size: %u bytes",
mbim_ussd_response_get_string (ussd_response),
mbim_ussd_session_state_get_string (ussd_session_state),
scheme,
data_size);
process_ussd_message (self, ussd_response, ussd_session_state, scheme, data_size, data);
} else {
/* Report error in the cached task, if any */
if (self->priv->pending_ussd_action) {
GTask *task;
task = self->priv->pending_ussd_action;
self->priv->pending_ussd_action = NULL;
g_task_return_error (task, error);
g_object_unref (task);
} else {
mm_dbg ("Failed to parse USSD response: %s", error->message);
g_clear_error (&error);
}
}
if (response)
mbim_message_unref (response);
/* Balance out received reference */
g_object_unref (self);
}
static void
modem_3gpp_ussd_send (MMIfaceModem3gppUssd *_self,
const gchar *command,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemMbim *self;
MbimDevice *device;
GTask *task;
MbimUssdAction action;
MbimMessage *message;
GByteArray *encoded;
guint32 scheme = 0;
GError *error = NULL;
self = MM_BROADBAND_MODEM_MBIM (_self);
if (!peek_device (self, &device, callback, user_data))
return;
task = g_task_new (self, NULL, callback, user_data);
/* Fail if there is an ongoing operation already */
if (self->priv->pending_ussd_action) {
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS,
"there is already an ongoing USSD operation");
g_object_unref (task);
return;
}
switch (mm_iface_modem_3gpp_ussd_get_state (MM_IFACE_MODEM_3GPP_USSD (self))) {
case MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE:
action = MBIM_USSD_ACTION_INITIATE;
break;
case MM_MODEM_3GPP_USSD_SESSION_STATE_USER_RESPONSE:
action = MBIM_USSD_ACTION_CONTINUE;
break;
default:
g_assert_not_reached ();
return;
}
encoded = ussd_encode (command, &scheme, &error);
if (!encoded) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
message = mbim_message_ussd_set_new (action, scheme, encoded->len, encoded->data, &error);
if (!message) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
/* Cache the action, as it may be completed via URCs */
self->priv->pending_ussd_action = task;
mm_iface_modem_3gpp_ussd_update_state (_self, MM_MODEM_3GPP_USSD_SESSION_STATE_ACTIVE);
mbim_device_command (device,
message,
100,
NULL,
(GAsyncReadyCallback)ussd_send_ready,
g_object_ref (self)); /* Full reference! */
mbim_message_unref (message);
}
/*****************************************************************************/
/* Cancel USSD (3GPP/USSD interface) */
static gboolean
modem_3gpp_ussd_cancel_finish (MMIfaceModem3gppUssd *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
ussd_cancel_ready (MbimDevice *device,
GAsyncResult *res,
GTask *task)
{
MMBroadbandModemMbim *self;
MbimMessage *response;
GError *error = NULL;
self = g_task_get_source_object (task);
response = mbim_device_command_finish (device, res, &error);
if (response)
mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error);
/* Complete the pending action, regardless of the operation result */
if (self->priv->pending_ussd_action) {
GTask *task;
task = self->priv->pending_ussd_action;
self->priv->pending_ussd_action = NULL;
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED,
"USSD session was cancelled");
g_object_unref (task);
}
mm_iface_modem_3gpp_ussd_update_state (MM_IFACE_MODEM_3GPP_USSD (self),
MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE);
if (error)
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
if (response)
mbim_message_unref (response);
}
static void
modem_3gpp_ussd_cancel (MMIfaceModem3gppUssd *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemMbim *self;
MbimDevice *device;
GTask *task;
MbimMessage *message;
GError *error = NULL;
self = MM_BROADBAND_MODEM_MBIM (_self);
if (!peek_device (self, &device, callback, user_data))
return;
task = g_task_new (self, NULL, callback, user_data);
message = mbim_message_ussd_set_new (MBIM_USSD_ACTION_CANCEL, 0, 0, NULL, &error);
if (!message) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
mbim_device_command (device,
message,
10,
NULL,
(GAsyncReadyCallback)ussd_cancel_ready,
task);
mbim_message_unref (message);
}
/*****************************************************************************/
/* Check support (Messaging interface) */
@@ -3955,6 +4541,32 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
iface->scan_networks_finish = modem_3gpp_scan_networks_finish;
}
static void
iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface)
{
/* Initialization steps */
iface->check_support = modem_3gpp_ussd_check_support;
iface->check_support_finish = modem_3gpp_ussd_check_support_finish;
/* Enabling steps */
iface->setup_unsolicited_events = modem_3gpp_ussd_setup_unsolicited_events;
iface->setup_unsolicited_events_finish = modem_3gpp_ussd_setup_cleanup_unsolicited_events_finish;
iface->enable_unsolicited_events = modem_3gpp_ussd_enable_unsolicited_events;
iface->enable_unsolicited_events_finish = modem_3gpp_ussd_enable_disable_unsolicited_events_finish;
/* Disabling steps */
iface->cleanup_unsolicited_events_finish = modem_3gpp_ussd_setup_cleanup_unsolicited_events_finish;
iface->cleanup_unsolicited_events = modem_3gpp_ussd_cleanup_unsolicited_events;
iface->disable_unsolicited_events = modem_3gpp_ussd_disable_unsolicited_events;
iface->disable_unsolicited_events_finish = modem_3gpp_ussd_enable_disable_unsolicited_events_finish;
/* Additional actions */
iface->send = modem_3gpp_ussd_send;
iface->send_finish = modem_3gpp_ussd_send_finish;
iface->cancel = modem_3gpp_ussd_cancel;
iface->cancel_finish = modem_3gpp_ussd_cancel_finish;
}
static void
iface_modem_location_init (MMIfaceModemLocation *iface)
{