diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-01-19 15:41:19 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:54 +0100 |
commit | 6ae1785b644d26ec8e1344e6f55e13f9b8522961 (patch) | |
tree | 61a45752f2c9045365fd71f234d8ab617d3654ec /src | |
parent | 015756e57299b9fbd1fe62f48962951ede5fb517 (diff) |
broadband-bearer: don't connect if roaming forbidden or unregistered
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-bearer.c | 236 |
1 files changed, 214 insertions, 22 deletions
diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c index e0a9e610..52a50cfe 100644 --- a/src/mm-broadband-bearer.c +++ b/src/mm-broadband-bearer.c @@ -27,6 +27,8 @@ #include "mm-broadband-bearer.h" #include "mm-iface-modem.h" +#include "mm-iface-modem-3gpp.h" +#include "mm-iface-modem-cdma.h" #include "mm-base-modem-at.h" #include "mm-utils.h" #include "mm-log.h" @@ -38,6 +40,19 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandBearer, mm_broadband_bearer, MM_TYPE_BEARER, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)); +typedef enum { + CONNECTION_FORBIDDEN_REASON_NONE, + CONNECTION_FORBIDDEN_REASON_UNREGISTERED, + CONNECTION_FORBIDDEN_REASON_ROAMING, + CONNECTION_FORBIDDEN_REASON_LAST +} ConnectionForbiddenReason; + +typedef enum { + CONNECTION_TYPE_NONE, + CONNECTION_TYPE_3GPP, + CONNECTION_TYPE_CDMA, +} ConnectionType; + enum { PROP_0, PROP_3GPP_APN, @@ -58,14 +73,25 @@ struct _MMBroadbandBearerPrivate { gboolean allow_roaming; /* Data port used when modem is connected */ MMPort *port; + /* Current connection type */ + ConnectionType connection_type; /*-- 3GPP specific --*/ + /* Reason if 3GPP connection is forbidden */ + ConnectionForbiddenReason reason_3gpp; + /* Handler ID for the registration state change signals */ + guint id_3gpp_registration_change; /* APN of the PDP context */ gchar *apn; /* CID of the PDP context */ guint cid; /*-- CDMA specific --*/ + /* Reason if CDMA connection is forbidden */ + ConnectionForbiddenReason reason_cdma; + /* Handler IDs for the registration state change signals */ + guint id_cdma1x_registration_change; + guint id_evdo_registration_change; /* (Optional) Number to dial */ gchar *number; /* Protocol of the Rm interface */ @@ -74,6 +100,14 @@ struct _MMBroadbandBearerPrivate { /*****************************************************************************/ +static const gchar *connection_forbidden_reason_str [CONNECTION_FORBIDDEN_REASON_LAST] = { + "none", + "Not registered in the network", + "Registered in roaming network, and roaming not allowed" +}; + +/*****************************************************************************/ + const gchar * mm_broadband_bearer_get_3gpp_apn (MMBroadbandBearer *self) { @@ -250,6 +284,7 @@ dial_cdma_ready (MMBaseModem *modem, } /* else... Yuhu! */ + ctx->self->priv->connection_type = CONNECTION_TYPE_CDMA; detailed_connect_context_complete_and_free_successful (ctx); } @@ -477,6 +512,7 @@ dial_3gpp_ready (MMBaseModem *modem, } /* Keep data port and CID around while connected */ + ctx->self->priv->connection_type = CONNECTION_TYPE_3GPP; ctx->self->priv->cid = ctx->cid; ctx->self->priv->port = g_object_ref (ctx->data); @@ -788,7 +824,7 @@ typedef struct { static void connect_context_complete_and_free (ConnectContext *ctx) { - g_simple_async_result_complete (ctx->result); + g_simple_async_result_complete_in_idle (ctx->result); g_object_unref (ctx->result); g_object_unref (ctx->data); g_object_unref (ctx->self); @@ -978,30 +1014,50 @@ connect (MMBearer *self, /* If the modem has 3GPP capabilities, launch 3GPP-based connection */ if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (modem))) { - MM_BROADBAND_BEARER_GET_CLASS (self)->connect_3gpp ( - MM_BROADBAND_BEARER (self), - MM_BROADBAND_MODEM (modem), - primary, - mm_base_modem_get_port_secondary (modem), - data, - cancellable, - (GAsyncReadyCallback) connect_3gpp_ready, - ctx); + /* Launch connection if allowed */ + if (MM_BROADBAND_BEARER (self)->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_NONE) { + MM_BROADBAND_BEARER_GET_CLASS (self)->connect_3gpp ( + MM_BROADBAND_BEARER (self), + MM_BROADBAND_MODEM (modem), + primary, + mm_base_modem_get_port_secondary (modem), + data, + cancellable, + (GAsyncReadyCallback) connect_3gpp_ready, + ctx); + g_object_unref (modem); + return; + } + + mm_dbg ("Not allowed to connect bearer in 3GPP network: '%s'", + connection_forbidden_reason_str[MM_BROADBAND_BEARER (self)->priv->reason_3gpp]); } + /* Otherwise, launch CDMA-specific connection */ - else { - MM_BROADBAND_BEARER_GET_CLASS (self)->connect_cdma ( - MM_BROADBAND_BEARER (self), - MM_BROADBAND_MODEM (modem), - primary, - mm_base_modem_get_port_secondary (modem), - data, - cancellable, - (GAsyncReadyCallback) connect_cdma_ready, - ctx); + if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (modem))) { + /* Launch connection if allowed */ + if (MM_BROADBAND_BEARER (self)->priv->reason_cdma == CONNECTION_FORBIDDEN_REASON_NONE) { + MM_BROADBAND_BEARER_GET_CLASS (self)->connect_cdma ( + MM_BROADBAND_BEARER (self), + MM_BROADBAND_MODEM (modem), + primary, + mm_base_modem_get_port_secondary (modem), + data, + cancellable, + (GAsyncReadyCallback) connect_cdma_ready, + ctx); + g_object_unref (modem); + return; + } + mm_dbg ("Not allowed to connect bearer in CDMA network: '%s'", + connection_forbidden_reason_str[MM_BROADBAND_BEARER (self)->priv->reason_cdma]); } - g_object_unref (modem); + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_UNAUTHORIZED, + "Not allowed to connect bearer"); + connect_context_complete_and_free (ctx); } /*****************************************************************************/ @@ -1178,7 +1234,7 @@ disconnect (MMBearer *self, disconnect); /* If the modem has 3GPP capabilities, send CGACT to disable contexts */ - if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self))) { + if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (modem))) { ctx->cgact_needed = TRUE; /* If no specific CID was used, disable all PDP contexts */ @@ -1322,6 +1378,83 @@ crm_range_ready (MMBaseModem *modem, } static void +modem_3gpp_registration_state_changed (MMBroadbandModem *modem, + GParamSpec *pspec, + MMBroadbandBearer *self) +{ + MMModem3gppRegistrationState state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + + g_object_get (modem, + MM_IFACE_MODEM_3GPP_REGISTRATION_STATE, &state, + NULL); + + switch (state) { + case MM_MODEM_3GPP_REGISTRATION_STATE_IDLE: + case MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING: + case MM_MODEM_3GPP_REGISTRATION_STATE_DENIED: + case MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN: + mm_dbg ("Bearer not allowed to connect, not registered"); + self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_UNREGISTERED; + break; + case MM_MODEM_3GPP_REGISTRATION_STATE_HOME: + mm_dbg ("Bearer allowed to connect, registered in home network"); + self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_NONE; + break; + case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING: + if (self->priv->allow_roaming) { + mm_dbg ("Bearer allowed to connect, registered in roaming network"); + self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_NONE; + } else { + mm_dbg ("Bearer not allowed to connect, registered in roaming network"); + self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_ROAMING; + } + break; + } + + /* close connection if we're connected in 3GPP */ + if (self->priv->reason_3gpp != CONNECTION_FORBIDDEN_REASON_NONE && + self->priv->connection_type == CONNECTION_TYPE_3GPP) + mm_bearer_disconnect_force (MM_BEARER (self)); +} + +static void +modem_cdma_registration_state_changed (MMBroadbandModem *modem, + GParamSpec *pspec, + MMBroadbandBearer *self) +{ + MMModemCdmaRegistrationState cdma1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + + g_object_get (modem, + MM_IFACE_MODEM_CDMA_CDMA1X_REGISTRATION_STATE, &cdma1x_state, + MM_IFACE_MODEM_CDMA_EVDO_REGISTRATION_STATE, &evdo_state, + NULL); + + if (cdma1x_state == MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING || + evdo_state == MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING) { + if (self->priv->allow_roaming) { + mm_dbg ("Bearer allowed to connect, registered in roaming network"); + self->priv->reason_cdma = CONNECTION_FORBIDDEN_REASON_NONE; + } else { + mm_dbg ("Bearer not allowed to connect, registered in roaming network"); + self->priv->reason_cdma = CONNECTION_FORBIDDEN_REASON_ROAMING; + } + } else if (cdma1x_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN || + evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) { + mm_dbg ("Bearer allowed to connect, registered in home network"); + self->priv->reason_cdma = CONNECTION_FORBIDDEN_REASON_NONE; + } else { + mm_dbg ("Bearer not allowed to connect, not registered"); + self->priv->reason_cdma = CONNECTION_FORBIDDEN_REASON_UNREGISTERED; + } + + /* close connection if we're connected in CDMA */ + if (self->priv->reason_cdma != CONNECTION_FORBIDDEN_REASON_NONE && + self->priv->connection_type == CONNECTION_TYPE_CDMA) + mm_bearer_disconnect_force (MM_BEARER (self)); +} + +static void interface_initialization_step (InitAsyncContext *ctx) { switch (ctx->step) { @@ -1350,6 +1483,30 @@ interface_initialization_step (InitAsyncContext *ctx) ctx->step++; case INITIALIZATION_STEP_LAST: + + if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (ctx->modem))) { + ctx->self->priv->id_3gpp_registration_change = + g_signal_connect (ctx->modem, + "notify::" MM_IFACE_MODEM_3GPP_REGISTRATION_STATE, + G_CALLBACK (modem_3gpp_registration_state_changed), + ctx->self); + modem_3gpp_registration_state_changed (MM_BROADBAND_MODEM (ctx->modem), NULL, ctx->self); + } + + if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (ctx->modem))) { + ctx->self->priv->id_cdma1x_registration_change = + g_signal_connect (ctx->modem, + "notify::" MM_IFACE_MODEM_CDMA_CDMA1X_REGISTRATION_STATE, + G_CALLBACK (modem_cdma_registration_state_changed), + ctx->self); + ctx->self->priv->id_evdo_registration_change = + g_signal_connect (ctx->modem, + "notify::" MM_IFACE_MODEM_CDMA_EVDO_REGISTRATION_STATE, + G_CALLBACK (modem_cdma_registration_state_changed), + ctx->self); + modem_cdma_registration_state_changed (MM_BROADBAND_MODEM (ctx->modem), NULL, ctx->self); + } + /* We are done without errors! */ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); g_simple_async_result_complete_in_idle (ctx->result); @@ -1489,8 +1646,41 @@ mm_broadband_bearer_init (MMBroadbandBearer *self) MMBroadbandBearerPrivate); /* Set defaults */ + self->priv->connection_type = CONNECTION_TYPE_NONE; self->priv->allow_roaming = TRUE; self->priv->rm_protocol = MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN; + self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_NONE; + self->priv->reason_cdma = CONNECTION_FORBIDDEN_REASON_NONE; +} + +static void +dispose (GObject *object) +{ + MMBroadbandBearer *self = MM_BROADBAND_BEARER (object); + MMBroadbandModem *modem = NULL; + + g_object_get (self, + MM_BEARER_MODEM, &modem, + NULL); + + /* We will disconnect the signals before calling parent's dispose, so that + * we can get the 'modem' object we need to perform the disconnection */ + if (self->priv->id_3gpp_registration_change) { + g_signal_handler_disconnect (modem, self->priv->id_3gpp_registration_change); + self->priv->id_3gpp_registration_change = 0; + } + if (self->priv->id_cdma1x_registration_change) { + g_signal_handler_disconnect (modem, self->priv->id_cdma1x_registration_change); + self->priv->id_cdma1x_registration_change = 0; + } + if (self->priv->id_evdo_registration_change) { + g_signal_handler_disconnect (modem, self->priv->id_evdo_registration_change); + self->priv->id_evdo_registration_change = 0; + } + + g_object_unref (modem); + + G_OBJECT_CLASS (mm_broadband_bearer_parent_class)->dispose (object); } static void @@ -1523,6 +1713,8 @@ mm_broadband_bearer_class_init (MMBroadbandBearerClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; + object_class->dispose = dispose; + bearer_class->connect = connect; bearer_class->connect_finish = connect_finish; bearer_class->disconnect = disconnect; |