diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-05-09 10:50:31 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-05-09 10:57:19 +0200 |
commit | 31c79ff2e438498f8f0272c1a361c72de21dc8a0 (patch) | |
tree | 072b551bfc2aebabafe96d3587ccb87f637017c1 | |
parent | 6ec525a769df53d8dc555e5a89509710b7c9319f (diff) | |
download | ModemManager-aleksander/registration-updates.tar.gz |
bearer: defer forced disconnection when modem unregistered while connectedaleksander/registration-updates
If the bearer is connected and we get a notification of being unregistered, wait
up to 15s to force the disconnection, in case we can recover the registration
in the meantime.
-rw-r--r-- | src/mm-bearer.c | 141 |
1 files changed, 108 insertions, 33 deletions
diff --git a/src/mm-bearer.c b/src/mm-bearer.c index 7ef516f47..c057f6405 100644 --- a/src/mm-bearer.c +++ b/src/mm-bearer.c @@ -40,6 +40,8 @@ /* We require up to 20s to get a proper IP when using PPP */ #define MM_BEARER_IP_TIMEOUT_DEFAULT 20 +#define MM_BEARER_DEFERRED_UNREGISTRATION_TIMEOUT 15 + G_DEFINE_TYPE (MMBearer, mm_bearer, MM_GDBUS_TYPE_BEARER_SKELETON); @@ -83,12 +85,14 @@ struct _MMBearerPrivate { gulong disconnect_signal_handler; /*-- 3GPP specific --*/ + guint deferred_3gpp_unregistration_id; /* Reason if 3GPP connection is forbidden */ ConnectionForbiddenReason reason_3gpp; /* Handler ID for the registration state change signals */ guint id_3gpp_registration_change; /*-- CDMA specific --*/ + guint deferred_cdma_unregistration_id; /* Reason if CDMA connection is forbidden */ ConnectionForbiddenReason reason_cdma; /* Handler IDs for the registration state change signals */ @@ -176,6 +180,31 @@ bearer_update_status_connected (MMBearer *self, /*****************************************************************************/ static void +reset_deferred_unregistration (MMBearer *self) +{ + if (self->priv->deferred_cdma_unregistration_id) { + g_source_remove (self->priv->deferred_cdma_unregistration_id); + self->priv->deferred_cdma_unregistration_id = 0; + } + + if (self->priv->deferred_3gpp_unregistration_id) { + g_source_remove (self->priv->deferred_3gpp_unregistration_id); + self->priv->deferred_3gpp_unregistration_id = 0; + } +} + +static gboolean +deferred_3gpp_unregistration_cb (MMBearer *self) +{ + g_warn_if_fail (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_UNREGISTERED); + self->priv->deferred_3gpp_unregistration_id = 0; + + mm_dbg ("Forcing bearer disconnection, not registered in 3GPP network"); + mm_bearer_disconnect_force (MM_BEARER (self)); + return FALSE; +} + +static void modem_3gpp_registration_state_changed (MMIfaceModem3gpp *modem, GParamSpec *pspec, MMBearer *self) @@ -204,29 +233,57 @@ modem_3gpp_registration_state_changed (MMIfaceModem3gpp *modem, break; } - /* close connection if some reason found */ - - if (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_NONE) + /* If no reason to disconnect, or if it's a mixed CDMA+LTE modem without a CDMA reason, + * just don't do anything. */ + if (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_NONE || + (mm_iface_modem_is_cdma (MM_IFACE_MODEM (modem)) && + self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_NONE)) { + reset_deferred_unregistration (self); return; + } - /* For mixed CDMA+LTE modems, don't close the connection if there is no - * CDMA reason to do so. */ - if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (modem)) && - self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_NONE) + /* Modem is roaming and roaming not allowed, report right away */ + if (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_ROAMING) { + mm_dbg ("Bearer not allowed to connect, registered in roaming 3GPP network"); + reset_deferred_unregistration (self); + mm_bearer_disconnect_force (MM_BEARER (self)); return; + } - switch (self->priv->reason_3gpp) { - case CONNECTION_FORBIDDEN_REASON_UNREGISTERED: - mm_dbg ("Bearer not allowed to connect, not registered in 3GPP network"); - break; - case CONNECTION_FORBIDDEN_REASON_ROAMING: - mm_dbg ("Bearer not allowed to connect, registered in roaming 3GPP network"); - break; - default: - break; + /* Modem reports being unregistered */ + if (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_UNREGISTERED) { + /* If there is already a notification pending, just return */ + if (self->priv->deferred_3gpp_unregistration_id) + return; + + /* If the bearer is not connected, report right away */ + if (self->priv->status != MM_BEARER_STATUS_CONNECTED) { + mm_dbg ("Bearer not allowed to connect, not registered in 3GPP network"); + mm_bearer_disconnect_force (MM_BEARER (self)); + return; + } + + /* Otherwise, setup the new timeout */ + mm_dbg ("Connected bearer not registered in 3GPP network"); + self->priv->deferred_3gpp_unregistration_id = + g_timeout_add_seconds (MM_BEARER_DEFERRED_UNREGISTRATION_TIMEOUT, + (GSourceFunc) deferred_3gpp_unregistration_cb, + self); + return; } + g_assert_not_reached (); +} + +static gboolean +deferred_cdma_unregistration_cb (MMBearer *self) +{ + g_warn_if_fail (self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_UNREGISTERED); + self->priv->deferred_cdma_unregistration_id = 0; + + mm_dbg ("Forcing bearer disconnection, not registered in CDMA network"); mm_bearer_disconnect_force (MM_BEARER (self)); + return FALSE; } static void @@ -255,29 +312,46 @@ modem_cdma_registration_state_changed (MMIfaceModemCdma *modem, self->priv->reason_cdma = CONNECTION_FORBIDDEN_REASON_UNREGISTERED; } - /* close connection if some reason found */ - - if (self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_NONE) + /* If no reason to disconnect, or if it's a mixed CDMA+LTE modem without a 3GPP reason, + * just don't do anything. */ + if (self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_NONE || + (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (modem)) && + self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_NONE)) { + reset_deferred_unregistration (self); return; + } - /* For mixed CDMA+LTE modems, don't close the connection if there is no - * 3GPP reason to do so. */ - if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (modem)) && - self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_NONE) + /* Modem is roaming and roaming not allowed, report right away */ + if (self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_ROAMING) { + mm_dbg ("Bearer not allowed to connect, registered in roaming CDMA network"); + reset_deferred_unregistration (self); + mm_bearer_disconnect_force (MM_BEARER (self)); return; + } - switch (self->priv->reason_cdma) { - case CONNECTION_FORBIDDEN_REASON_UNREGISTERED: - mm_dbg ("Bearer not allowed to connect, not registered in CDMA network"); - break; - case CONNECTION_FORBIDDEN_REASON_ROAMING: - mm_dbg ("Bearer not allowed to connect, registered in roaming CDMA network"); - break; - default: - break; + /* Modem reports being unregistered */ + if (self->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_UNREGISTERED) { + /* If there is already a notification pending, just return */ + if (self->priv->deferred_cdma_unregistration_id) + return; + + /* If the bearer is not connected, report right away */ + if (self->priv->status != MM_BEARER_STATUS_CONNECTED) { + mm_dbg ("Bearer not allowed to connect, not registered in CDMA network"); + mm_bearer_disconnect_force (MM_BEARER (self)); + return; + } + + /* Otherwise, setup the new timeout */ + mm_dbg ("Connected bearer not registered in CDMA network"); + self->priv->deferred_cdma_unregistration_id = + g_timeout_add_seconds (MM_BEARER_DEFERRED_UNREGISTRATION_TIMEOUT, + (GSourceFunc) deferred_cdma_unregistration_cb, + self); + return; } - mm_bearer_disconnect_force (MM_BEARER (self)); + g_assert_not_reached (); } static void @@ -1065,6 +1139,7 @@ dispose (GObject *object) } reset_signal_handlers (self); + reset_deferred_unregistration (self); g_clear_object (&self->priv->modem); g_clear_object (&self->priv->config); |