broadband-modem-mbim: handle network initiated disconnect

Observing registration updates via the MBIM_CID_REGISTER_STATE
notification alone is not always sufficient to detect if the modem is
disconnected from the network. In case of a network-initiated
disconnect, it is possible that the modem is disconnected from the
network but remains registered.

This patch modifies MMBroadbandModemMbim to subscribe to the
MBIM_CID_CONNECT notification. Upon receiving a notification of a
deactivated session ID, the corresponding bearer is reported as
disconnected.
This commit is contained in:
Ben Chan
2014-02-19 21:44:23 -08:00
committed by Aleksander Morgado
parent 1866aad9d3
commit 705dd0133d

View File

@@ -52,6 +52,7 @@ typedef enum {
PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY = 1 << 0, PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY = 1 << 0,
PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES = 1 << 1, PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES = 1 << 1,
PROCESS_NOTIFICATION_FLAG_SMS_READ = 1 << 2, PROCESS_NOTIFICATION_FLAG_SMS_READ = 1 << 2,
PROCESS_NOTIFICATION_FLAG_CONNECT = 1 << 3,
} ProcessNotificationFlag; } ProcessNotificationFlag;
struct _MMBroadbandModemMbimPrivate { struct _MMBroadbandModemMbimPrivate {
@@ -1607,6 +1608,65 @@ basic_connect_notification_register_state (MMBroadbandModemMbim *self,
} }
} }
typedef struct {
guint32 session_id;
} ReportDisconnectedStatusContext;
static void
bearer_list_report_disconnected_status (MMBearer *bearer,
gpointer user_data)
{
ReportDisconnectedStatusContext *ctx = user_data;
if (MM_IS_BEARER_MBIM (bearer) &&
mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (bearer)) == ctx->session_id) {
mm_dbg ("Bearer '%s' was disconnected.", mm_bearer_get_path (bearer));
mm_bearer_report_connection_status (bearer, MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
}
}
static void
basic_connect_notification_connect (MMBroadbandModemMbim *self,
MbimMessage *notification)
{
guint32 session_id;
MbimActivationState activation_state;
const MbimUuid *context_type;
MMBearerList *bearer_list;
if (!mbim_message_connect_notification_parse (
notification,
&session_id,
&activation_state,
NULL, /* voice_call_state */
NULL, /* ip_type */
&context_type,
NULL, /* nw_error */
NULL)) {
return;
}
g_object_get (self,
MM_IFACE_MODEM_BEARER_LIST, &bearer_list,
NULL);
if (!bearer_list)
return;
if (mbim_uuid_to_context_type (context_type) == MBIM_CONTEXT_TYPE_INTERNET &&
activation_state == MBIM_ACTIVATION_STATE_DEACTIVATED) {
ReportDisconnectedStatusContext ctx;
mm_dbg ("Session ID '%u' was deactivated.", session_id);
ctx.session_id = session_id;
mm_bearer_list_foreach (bearer_list,
(MMBearerListForeachFunc)bearer_list_report_disconnected_status,
&ctx);
}
g_object_unref (bearer_list);
}
static void add_sms_part (MMBroadbandModemMbim *self, static void add_sms_part (MMBroadbandModemMbim *self,
const MbimSmsPduReadRecord *pdu); const MbimSmsPduReadRecord *pdu);
@@ -1650,6 +1710,10 @@ basic_connect_notification (MMBroadbandModemMbim *self,
if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES) if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES)
basic_connect_notification_register_state (self, notification); basic_connect_notification_register_state (self, notification);
break; break;
case MBIM_CID_BASIC_CONNECT_CONNECT:
if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_CONNECT)
basic_connect_notification_connect (self, notification);
break;
default: default:
/* Ignore */ /* Ignore */
break; break;
@@ -1808,10 +1872,11 @@ common_setup_cleanup_unsolicited_events (MMBroadbandModemMbim *self,
user_data, user_data,
common_setup_cleanup_unsolicited_events); common_setup_cleanup_unsolicited_events);
mm_dbg ("Supported notifications: signal (%s), registration (%s), sms (%s)", mm_dbg ("Supported notifications: signal (%s), registration (%s), sms (%s), connect (%s)",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no", 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_REGISTRATION_UPDATES ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no"); self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no");
if (setup) { if (setup) {
/* Don't re-enable it if already there */ /* Don't re-enable it if already there */
@@ -1852,6 +1917,7 @@ cleanup_unsolicited_events_3gpp (MMIfaceModem3gpp *self,
gpointer user_data) gpointer user_data)
{ {
MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY; MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_CONNECT;
common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), FALSE, callback, user_data); common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), FALSE, callback, user_data);
} }
@@ -1861,6 +1927,7 @@ setup_unsolicited_events_3gpp (MMIfaceModem3gpp *self,
gpointer user_data) gpointer user_data)
{ {
MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY; MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_CONNECT;
common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), TRUE, callback, user_data); common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), TRUE, callback, user_data);
} }
@@ -1938,24 +2005,28 @@ common_enable_disable_unsolicited_events (MMBroadbandModemMbim *self,
user_data, user_data,
common_enable_disable_unsolicited_events); common_enable_disable_unsolicited_events);
mm_dbg ("Enabled notifications: signal (%s), registration (%s), sms (%s)", mm_dbg ("Enabled notifications: signal (%s), registration (%s), sms (%s), connect (%s)",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no", 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_REGISTRATION_UPDATES ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no"); self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no",
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no");
entries = g_new0 (MbimEventEntry *, 3); entries = g_new0 (MbimEventEntry *, 3);
/* Basic connect service */ /* Basic connect service */
if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY || if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ||
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES) { self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ||
self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_CONNECT) {
entries[n_entries] = g_new (MbimEventEntry, 1); entries[n_entries] = g_new (MbimEventEntry, 1);
memcpy (&(entries[n_entries]->device_service_id), MBIM_UUID_BASIC_CONNECT, sizeof (MbimUuid)); memcpy (&(entries[n_entries]->device_service_id), MBIM_UUID_BASIC_CONNECT, sizeof (MbimUuid));
entries[n_entries]->cids_count = 0; entries[n_entries]->cids_count = 0;
entries[n_entries]->cids = g_new0 (guint32, 2); entries[n_entries]->cids = g_new0 (guint32, 3);
if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY) if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY)
entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_SIGNAL_STATE; entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_SIGNAL_STATE;
if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES) if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES)
entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_REGISTER_STATE; entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_REGISTER_STATE;
if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_CONNECT)
entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_CONNECT;
n_entries++; n_entries++;
} }
@@ -2037,6 +2108,7 @@ modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
gpointer user_data) gpointer user_data)
{ {
MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY; MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_CONNECT;
common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data); common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
} }
@@ -2046,6 +2118,7 @@ modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
gpointer user_data) gpointer user_data)
{ {
MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY; MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_CONNECT;
common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data); common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
} }