summaryrefslogtreecommitdiff
path: root/src/mm-broadband-modem-mbim.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2013-04-13 17:43:58 +0200
committerAleksander Morgado <aleksander@lanedo.com>2013-04-17 15:19:41 +0200
commit9cdd8c901db84b40ec126446e8a9f43376a4fd5f (patch)
tree8f16a06644a9e8a7b991aae5d8f8d615f8fc7748 /src/mm-broadband-modem-mbim.c
parent6333b239ff0e5069d1ea5b4f34626ccf7811f38a (diff)
downloadModemManager-9cdd8c901db84b40ec126446e8a9f43376a4fd5f.tar.gz
broadband-modem-mbim: implement 3GPP registration logic
Diffstat (limited to 'src/mm-broadband-modem-mbim.c')
-rw-r--r--src/mm-broadband-modem-mbim.c301
1 files changed, 298 insertions, 3 deletions
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index f7d40b613..2546f3480 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -41,6 +41,12 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbim, mm_broadband_modem_mbim, MM_TYPE_B
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init))
+typedef enum {
+ PROCESS_NOTIFICATION_FLAG_NONE = 0,
+ PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY = 1 << 0,
+ PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES = 1 << 1,
+} ProcessNotificationFlag;
+
struct _MMBroadbandModemMbimPrivate {
/* Queried and cached capabilities */
MbimCellularClass caps_cellular_class;
@@ -52,6 +58,11 @@ struct _MMBroadbandModemMbimPrivate {
/* Process unsolicited notifications */
guint notification_id;
+ ProcessNotificationFlag notification_flags;
+
+ /* 3GPP registration helpers */
+ gchar *current_operator_id;
+ gchar *current_operator_name;
};
/*****************************************************************************/
@@ -1357,7 +1368,7 @@ modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self,
}
/*****************************************************************************/
-/* Setup/cleanup unsolicited events */
+/* Common unsolicited events setup and cleanup */
static void
basic_connect_notification_signal_state (MMBroadbandModemMbim *self,
@@ -1384,12 +1395,89 @@ basic_connect_notification_signal_state (MMBroadbandModemMbim *self,
}
static void
+update_registration_info (MMBroadbandModemMbim *self,
+ MbimRegisterState state,
+ gchar *operator_id_take,
+ gchar *operator_name_take)
+{
+ MMModem3gppRegistrationState reg_state;
+
+ reg_state = mm_modem_3gpp_registration_state_from_mbim_register_state (state);
+
+ if (reg_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
+ reg_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
+ if (self->priv->current_operator_id &&
+ g_str_equal (self->priv->current_operator_id, operator_id_take)) {
+ g_free (operator_id_take);
+ } else {
+ g_free (self->priv->current_operator_id);
+ self->priv->current_operator_id = operator_id_take;
+ }
+
+ if (self->priv->current_operator_name &&
+ g_str_equal (self->priv->current_operator_name, operator_name_take)) {
+ g_free (operator_name_take);
+ } else {
+ g_free (self->priv->current_operator_name);
+ self->priv->current_operator_name = operator_name_take;
+ }
+ } else {
+ if (self->priv->current_operator_id) {
+ g_free (self->priv->current_operator_id);
+ self->priv->current_operator_id = 0;
+ }
+ if (self->priv->current_operator_name) {
+ g_free (self->priv->current_operator_name);
+ self->priv->current_operator_name = 0;
+ }
+ g_free (operator_id_take);
+ g_free (operator_name_take);
+ }
+
+ mm_iface_modem_3gpp_update_ps_registration_state (
+ MM_IFACE_MODEM_3GPP (self),
+ reg_state);
+}
+
+static void
+basic_connect_notification_register_state (MMBroadbandModemMbim *self,
+ MbimMessage *notification)
+{
+ MbimRegisterState register_state;
+ gchar *provider_id;
+ gchar *provider_name;
+
+ if (mbim_message_register_state_notification_parse (
+ notification,
+ NULL, /* nw_error */
+ &register_state,
+ NULL, /* register_mode */
+ NULL, /* available_data_classes */
+ NULL, /* current_cellular_class */
+ &provider_id,
+ &provider_name,
+ NULL, /* roaming_text */
+ NULL, /* registration_flag */
+ NULL)) {
+ update_registration_info (self,
+ register_state,
+ provider_id,
+ provider_name);
+ }
+}
+
+static void
basic_connect_notification (MMBroadbandModemMbim *self,
MbimMessage *notification)
{
switch (mbim_message_indicate_status_get_cid (notification)) {
case MBIM_CID_BASIC_CONNECT_SIGNAL_STATE:
- basic_connect_notification_signal_state (self, notification);
+ if (self->priv->notification_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY)
+ basic_connect_notification_signal_state (self, notification);
+ break;
+ case MBIM_CID_BASIC_CONNECT_REGISTER_STATE:
+ if (self->priv->notification_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES)
+ basic_connect_notification_register_state (self, notification);
break;
default:
/* Ignore */
@@ -1439,6 +1527,7 @@ common_setup_cleanup_unsolicited_events (MMIfaceModem3gpp *_self,
common_setup_cleanup_unsolicited_events);
if (setup) {
+ /* Don't re-enable it if already there */
if (!self->priv->notification_id)
self->priv->notification_id =
g_signal_connect (device,
@@ -1446,7 +1535,9 @@ common_setup_cleanup_unsolicited_events (MMIfaceModem3gpp *_self,
G_CALLBACK (device_notification_cb),
self);
} else {
- if (self->priv->notification_id &&
+ /* Don't remove the signal if there are still listeners interested */
+ if (self->priv->notification_flags == PROCESS_NOTIFICATION_FLAG_NONE &&
+ self->priv->notification_id &&
g_signal_handler_is_connected (device, self->priv->notification_id))
g_signal_handler_disconnect (device, self->priv->notification_id);
self->priv->notification_id = 0;
@@ -1456,11 +1547,15 @@ common_setup_cleanup_unsolicited_events (MMIfaceModem3gpp *_self,
g_object_unref (result);
}
+/*****************************************************************************/
+/* Setup/cleanup unsolicited events */
+
static void
cleanup_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MM_BROADBAND_MODEM_MBIM (self)->priv->notification_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
common_setup_cleanup_unsolicited_events (self, FALSE, callback, user_data);
}
@@ -1469,6 +1564,28 @@ setup_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MM_BROADBAND_MODEM_MBIM (self)->priv->notification_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
+ common_setup_cleanup_unsolicited_events (self, TRUE, callback, user_data);
+}
+
+/*****************************************************************************/
+/* Cleanup/Setup unsolicited registration events */
+
+static void
+cleanup_unsolicited_registration_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MM_BROADBAND_MODEM_MBIM (self)->priv->notification_flags &= ~PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES;
+ common_setup_cleanup_unsolicited_events (self, FALSE, callback, user_data);
+}
+
+static void
+setup_unsolicited_registration_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MM_BROADBAND_MODEM_MBIM (self)->priv->notification_flags |= PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES;
common_setup_cleanup_unsolicited_events (self, TRUE, callback, user_data);
}
@@ -1615,6 +1732,166 @@ enable_unsolicited_events (MMIfaceModem3gpp *self,
}
/*****************************************************************************/
+/* Load operator name (3GPP interface) */
+
+static gchar *
+modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *_self,
+ GAsyncResult *res,
+ GError **error)
+{
+ MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
+
+ if (self->priv->current_operator_name)
+ return g_strdup (self->priv->current_operator_name);
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Current operator name is still unknown");
+ return NULL;
+}
+
+static void
+modem_3gpp_load_operator_name (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ /* Just finish the async operation */
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_load_operator_name);
+ g_simple_async_result_set_op_res_gboolean (result, TRUE);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+/*****************************************************************************/
+/* Load operator code (3GPP interface) */
+
+static gchar *
+modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *_self,
+ GAsyncResult *res,
+ GError **error)
+{
+ MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
+
+ if (self->priv->current_operator_id)
+ return g_strdup (self->priv->current_operator_id);
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Current operator MCC/MNC is still unknown");
+ return NULL;
+}
+
+static void
+modem_3gpp_load_operator_code (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ /* Just finish the async operation */
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_load_operator_code);
+ g_simple_async_result_set_op_res_gboolean (result, TRUE);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+/*****************************************************************************/
+/* Registration checks (3GPP interface) */
+
+static gboolean
+modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+register_state_query_ready (MbimDevice *device,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimRegisterState register_state;
+ gchar *provider_id;
+ gchar *provider_name;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (response &&
+ mbim_message_command_done_get_result (response, &error) &&
+ mbim_message_register_state_response_parse (
+ response,
+ NULL, /* nw_error */
+ &register_state,
+ NULL, /* register_mode */
+ NULL, /* available_data_classes */
+ NULL, /* current_cellular_class */
+ &provider_id,
+ &provider_name,
+ NULL, /* roaming_text */
+ NULL, /* registration_flag */
+ NULL)) {
+ MMBroadbandModemMbim *self;
+
+ self = MM_BROADBAND_MODEM_MBIM (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ update_registration_info (self,
+ register_state,
+ provider_id,
+ provider_name);
+ g_object_unref (self);
+
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ } else
+ g_simple_async_result_take_error (simple, error);
+
+ if (response)
+ mbim_message_unref (response);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self,
+ gboolean cs_supported,
+ gboolean ps_supported,
+ gboolean eps_supported,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ MbimDevice *device;
+ MbimMessage *message;
+
+ if (!peek_device (self, &device, callback, user_data))
+ return;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_run_registration_checks);
+
+ message = mbim_message_register_state_query_new (NULL);
+ mbim_device_command (device,
+ message,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)register_state_query_ready,
+ result);
+ mbim_message_unref (message);
+}
+
+/*****************************************************************************/
MMBroadbandModemMbim *
mm_broadband_modem_mbim_new (const gchar *device,
@@ -1649,6 +1926,8 @@ finalize (GObject *object)
g_free (self->priv->caps_device_id);
g_free (self->priv->caps_firmware_info);
+ g_free (self->priv->current_operator_id);
+ g_free (self->priv->current_operator_name);
mbim = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self));
/* If we did open the MBIM port during initialization, close it now */
@@ -1730,6 +2009,22 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
iface->enable_unsolicited_events_finish = common_enable_disable_unsolicited_events_finish;
iface->disable_unsolicited_events = disable_unsolicited_events;
iface->disable_unsolicited_events_finish = common_enable_disable_unsolicited_events_finish;
+ iface->setup_unsolicited_registration_events = setup_unsolicited_registration_events;
+ iface->setup_unsolicited_registration_events_finish = common_setup_cleanup_unsolicited_events_finish;
+ iface->cleanup_unsolicited_registration_events = cleanup_unsolicited_registration_events;
+ iface->cleanup_unsolicited_registration_events_finish = common_setup_cleanup_unsolicited_events_finish;
+ iface->load_operator_code = modem_3gpp_load_operator_code;
+ iface->load_operator_code_finish = modem_3gpp_load_operator_code_finish;
+ iface->load_operator_name = modem_3gpp_load_operator_name;
+ iface->load_operator_name_finish = modem_3gpp_load_operator_name_finish;
+ iface->run_registration_checks = modem_3gpp_run_registration_checks;
+ iface->run_registration_checks_finish = modem_3gpp_run_registration_checks_finish;
+
+ /* Unneeded things */
+ iface->enable_unsolicited_registration_events = NULL;
+ iface->enable_unsolicited_registration_events_finish = NULL;
+ iface->disable_unsolicited_registration_events = NULL;
+ iface->disable_unsolicited_registration_events_finish = NULL;
}
static void