diff options
Diffstat (limited to 'plugins/sierra/mm-broadband-bearer-sierra.c')
-rw-r--r-- | plugins/sierra/mm-broadband-bearer-sierra.c | 320 |
1 files changed, 224 insertions, 96 deletions
diff --git a/plugins/sierra/mm-broadband-bearer-sierra.c b/plugins/sierra/mm-broadband-bearer-sierra.c index 0d872199..b2c34c7c 100644 --- a/plugins/sierra/mm-broadband-bearer-sierra.c +++ b/plugins/sierra/mm-broadband-bearer-sierra.c @@ -29,8 +29,9 @@ #include "mm-base-modem-at.h" #include "mm-broadband-bearer-sierra.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-modem-helpers.h" +#include "mm-modem-helpers-sierra.h" G_DEFINE_TYPE (MMBroadbandBearerSierra, mm_broadband_bearer_sierra, MM_TYPE_BROADBAND_BEARER); @@ -45,6 +46,121 @@ enum { }; /*****************************************************************************/ +/* Connection status monitoring */ + +static MMBearerConnectionStatus +load_connection_status_finish (MMBaseBearer *bearer, + GAsyncResult *res, + GError **error) +{ + GError *inner_error = NULL; + gssize value; + + value = g_task_propagate_int (G_TASK (res), &inner_error); + if (inner_error) { + g_propagate_error (error, inner_error); + return MM_BEARER_CONNECTION_STATUS_UNKNOWN; + } + return (MMBearerConnectionStatus)value; +} + +static void +scact_periodic_query_ready (MMBaseModem *modem, + GAsyncResult *res, + GTask *task) +{ + const gchar *response; + GError *error = NULL; + GList *pdp_active_list = NULL; + GList *l; + MMBearerConnectionStatus status = MM_BEARER_CONNECTION_STATUS_UNKNOWN; + guint cid; + + cid = GPOINTER_TO_UINT (g_task_get_task_data (task)); + + response = mm_base_modem_at_command_finish (modem, res, &error); + if (response) + pdp_active_list = mm_sierra_parse_scact_read_response (response, &error); + + if (error) { + g_assert (!pdp_active_list); + g_prefix_error (&error, "Couldn't check current list of active PDP contexts: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + for (l = pdp_active_list; l; l = g_list_next (l)) { + MM3gppPdpContextActive *pdp_active; + + /* We look for the specific CID */ + pdp_active = (MM3gppPdpContextActive *)(l->data); + if (pdp_active->cid == cid) { + status = (pdp_active->active ? MM_BEARER_CONNECTION_STATUS_CONNECTED : MM_BEARER_CONNECTION_STATUS_DISCONNECTED); + break; + } + } + mm_3gpp_pdp_context_active_list_free (pdp_active_list); + + /* PDP context not found? This shouldn't happen, error out */ + if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "PDP context not found in the known contexts list"); + else + g_task_return_int (task, (gssize) status); + g_object_unref (task); +} + +static void +load_connection_status (MMBaseBearer *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + MMBaseModem *modem = NULL; + MMPortSerialAt *port; + gint profile_id; + + task = g_task_new (self, NULL, callback, user_data); + + g_object_get (MM_BASE_BEARER (self), + MM_BASE_BEARER_MODEM, &modem, + NULL); + + /* If CID not defined, error out */ + profile_id = mm_base_bearer_get_profile_id (self); + if (profile_id == MM_3GPP_PROFILE_ID_UNKNOWN) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't load connection status: profile id not defined"); + g_object_unref (task); + goto out; + } + g_task_set_task_data (task, GUINT_TO_POINTER ((guint)profile_id), NULL); + + /* If no control port available, error out */ + port = mm_base_modem_peek_best_at_port (modem, NULL); + if (!port) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Couldn't load connection status: no control port available"); + g_object_unref (task); + goto out; + } + + mm_base_modem_at_command_full (MM_BASE_MODEM (modem), + port, + "!SCACT?", + 3, + FALSE, /* allow cached */ + FALSE, /* raw */ + NULL, /* cancellable */ + (GAsyncReadyCallback) scact_periodic_query_ready, + task); + +out: + g_clear_object (&modem); +} + +/*****************************************************************************/ /* 3GPP Dialing (sub-step of the 3GPP Connection sequence) */ typedef enum { @@ -56,27 +172,20 @@ typedef enum { } Dial3gppStep; typedef struct { - MMBroadbandBearerSierra *self; MMBaseModem *modem; MMPortSerialAt *primary; guint cid; - GCancellable *cancellable; - GSimpleAsyncResult *result; MMPort *data; Dial3gppStep step; } Dial3gppContext; static void -dial_3gpp_context_complete_and_free (Dial3gppContext *ctx) +dial_3gpp_context_free (Dial3gppContext *ctx) { - g_simple_async_result_complete_in_idle (ctx->result); - g_object_unref (ctx->cancellable); - g_object_unref (ctx->result); if (ctx->data) g_object_unref (ctx->data); g_object_unref (ctx->primary); g_object_unref (ctx->modem); - g_object_unref (ctx->self); g_slice_free (Dial3gppContext, ctx); } @@ -85,103 +194,114 @@ dial_3gpp_finish (MMBroadbandBearer *self, GAsyncResult *res, GError **error) { - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) - return NULL; - - return MM_PORT (g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)))); + return g_task_propagate_pointer (G_TASK (res), error); } -static void dial_3gpp_context_step (Dial3gppContext *ctx); +static void dial_3gpp_context_step (GTask *task); static void parent_dial_3gpp_ready (MMBroadbandBearer *self, GAsyncResult *res, - Dial3gppContext *ctx) + GTask *task) { + Dial3gppContext *ctx; GError *error = NULL; + ctx = g_task_get_task_data (task); + ctx->data = MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_sierra_parent_class)->dial_3gpp_finish (self, res, &error); if (!ctx->data) { - g_simple_async_result_take_error (ctx->result, error); - dial_3gpp_context_complete_and_free (ctx); + g_task_return_error (task, error); + g_object_unref (task); return; } /* Go on */ ctx->step++; - dial_3gpp_context_step (ctx); + dial_3gpp_context_step (task); } static void scact_ready (MMBaseModem *modem, GAsyncResult *res, - Dial3gppContext *ctx) + GTask *task) { + Dial3gppContext *ctx; GError *error = NULL; + ctx = g_task_get_task_data (task); + if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - g_simple_async_result_take_error (ctx->result, error); - dial_3gpp_context_complete_and_free (ctx); + g_task_return_error (task, error); + g_object_unref (task); return; } /* Go on */ ctx->step++; - dial_3gpp_context_step (ctx); + dial_3gpp_context_step (task); } static void authenticate_ready (MMBaseModem *modem, GAsyncResult *res, - Dial3gppContext *ctx) + GTask *task) { + Dial3gppContext *ctx; GError *error = NULL; + ctx = g_task_get_task_data (task); + if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - g_simple_async_result_take_error (ctx->result, error); - dial_3gpp_context_complete_and_free (ctx); + g_task_return_error (task, error); + g_object_unref (task); return; } /* Go on */ ctx->step++; - dial_3gpp_context_step (ctx); + dial_3gpp_context_step (task); } static void cgatt_ready (MMBaseModem *modem, GAsyncResult *res, - Dial3gppContext *ctx) + GTask *task) { + Dial3gppContext *ctx; GError *error = NULL; + ctx = g_task_get_task_data (task); + if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - g_simple_async_result_take_error (ctx->result, error); - dial_3gpp_context_complete_and_free (ctx); + g_task_return_error (task, error); + g_object_unref (task); return; } /* Go on */ ctx->step++; - dial_3gpp_context_step (ctx); + dial_3gpp_context_step (task); } static void -dial_3gpp_context_step (Dial3gppContext *ctx) +dial_3gpp_context_step (GTask *task) { - if (g_cancellable_is_cancelled (ctx->cancellable)) { - g_simple_async_result_set_error (ctx->result, - MM_CORE_ERROR, - MM_CORE_ERROR_CANCELLED, - "Dial operation has been cancelled"); - dial_3gpp_context_complete_and_free (ctx); - return; + MMBroadbandBearerSierra *self; + Dial3gppContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + if (g_task_return_error_if_cancelled (task)) { + g_object_unref (task); + return; } switch (ctx->step) { case DIAL_3GPP_STEP_FIRST: - /* Fall down */ ctx->step++; + /* fall through */ case DIAL_3GPP_STEP_PS_ATTACH: mm_base_modem_at_command_full (ctx->modem, @@ -192,7 +312,7 @@ dial_3gpp_context_step (Dial3gppContext *ctx) FALSE, /* raw */ NULL, /* cancellable */ (GAsyncReadyCallback)cgatt_ready, - ctx); + task); return; case DIAL_3GPP_STEP_AUTHENTICATE: @@ -202,13 +322,13 @@ dial_3gpp_context_step (Dial3gppContext *ctx) const gchar *password; MMBearerAllowedAuth allowed_auth; - user = mm_bearer_properties_get_user (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - password = mm_bearer_properties_get_password (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - allowed_auth = mm_bearer_properties_get_allowed_auth (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); + user = mm_bearer_properties_get_user (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); + password = mm_bearer_properties_get_password (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); + allowed_auth = mm_bearer_properties_get_allowed_auth (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); if (!user || !password || allowed_auth == MM_BEARER_ALLOWED_AUTH_NONE) { - mm_dbg ("Not using authentication"); - if (ctx->self->priv->is_icera) + mm_obj_dbg (self, "not using authentication"); + if (self->priv->is_icera) command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", ctx->cid); else command = g_strdup_printf ("$QCPDPP=%d,0", ctx->cid); @@ -218,32 +338,32 @@ dial_3gpp_context_step (Dial3gppContext *ctx) guint sierra_auth; if (allowed_auth == MM_BEARER_ALLOWED_AUTH_UNKNOWN) { - mm_dbg ("Using default (PAP) authentication method"); - sierra_auth = 1; - } else if (allowed_auth & MM_BEARER_ALLOWED_AUTH_PAP) { - mm_dbg ("Using PAP authentication method"); - sierra_auth = 1; + mm_obj_dbg (self, "using default (CHAP) authentication method"); + sierra_auth = 2; } else if (allowed_auth & MM_BEARER_ALLOWED_AUTH_CHAP) { - mm_dbg ("Using CHAP authentication method"); + mm_obj_dbg (self, "using CHAP authentication method"); sierra_auth = 2; + } else if (allowed_auth & MM_BEARER_ALLOWED_AUTH_PAP) { + mm_obj_dbg (self, "using PAP authentication method"); + sierra_auth = 1; } else { gchar *str; str = mm_bearer_allowed_auth_build_string_from_mask (allowed_auth); - g_simple_async_result_set_error ( - ctx->result, + g_task_return_new_error ( + task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Cannot use any of the specified authentication methods (%s)", str); g_free (str); - dial_3gpp_context_complete_and_free (ctx); + g_object_unref (task); return; } quoted_user = mm_port_serial_at_quote_string (user); quoted_password = mm_port_serial_at_quote_string (password); - if (ctx->self->priv->is_icera) { + if (self->priv->is_icera) { command = g_strdup_printf ("%%IPDPCFG=%d,0,%u,%s,%s", ctx->cid, sierra_auth, @@ -269,13 +389,13 @@ dial_3gpp_context_step (Dial3gppContext *ctx) FALSE, /* raw */ NULL, /* cancellable */ (GAsyncReadyCallback)authenticate_ready, - ctx); + task); g_free (command); return; } - /* Fall down */ ctx->step++; + /* fall through */ case DIAL_3GPP_STEP_CONNECT: /* We need a net or AT data port */ @@ -287,33 +407,36 @@ dial_3gpp_context_step (Dial3gppContext *ctx) mm_base_modem_at_command_full (ctx->modem, ctx->primary, command, - 10, + MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT, FALSE, FALSE, /* raw */ NULL, /* cancellable */ (GAsyncReadyCallback)scact_ready, - ctx); + task); g_free (command); return; } /* Chain up parent's dialling if we don't have a net port */ MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_sierra_parent_class)->dial_3gpp ( - MM_BROADBAND_BEARER (ctx->self), + MM_BROADBAND_BEARER (self), ctx->modem, ctx->primary, ctx->cid, - ctx->cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)parent_dial_3gpp_ready, - ctx); + task); return; case DIAL_3GPP_STEP_LAST: - g_simple_async_result_set_op_res_gpointer (ctx->result, - g_object_ref (ctx->data), - (GDestroyNotify)g_object_unref); - dial_3gpp_context_complete_and_free (ctx); + g_task_return_pointer (task, + g_object_ref (ctx->data), + g_object_unref); + g_object_unref (task); return; + + default: + g_assert_not_reached (); } } @@ -327,22 +450,20 @@ dial_3gpp (MMBroadbandBearer *self, gpointer user_data) { Dial3gppContext *ctx; + GTask *task; g_assert (primary != NULL); ctx = g_slice_new0 (Dial3gppContext); - ctx->self = g_object_ref (self); ctx->modem = g_object_ref (modem); ctx->primary = g_object_ref (primary); ctx->cid = cid; - ctx->result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - dial_3gpp); - ctx->cancellable = g_object_ref (cancellable); ctx->step = DIAL_3GPP_STEP_FIRST; - dial_3gpp_context_step (ctx); + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, ctx, (GDestroyNotify)dial_3gpp_context_free); + + dial_3gpp_context_step (task); } /*****************************************************************************/ @@ -353,43 +474,44 @@ disconnect_3gpp_finish (MMBroadbandBearer *self, GAsyncResult *res, GError **error) { - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); + return g_task_propagate_boolean (G_TASK (res), error); } static void parent_disconnect_3gpp_ready (MMBroadbandBearer *self, - GAsyncResult *res, - GSimpleAsyncResult *simple) + GAsyncResult *res, + GTask *task) { GError *error = NULL; if (!MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_sierra_parent_class)->disconnect_3gpp_finish (self, res, &error)) { - mm_dbg ("Parent disconnection failed (not fatal): %s", error->message); + mm_obj_dbg (self, "parent disconnection failed (not fatal): %s", error->message); g_error_free (error); } - g_simple_async_result_set_op_res_gboolean (simple, TRUE); - g_simple_async_result_complete (simple); - g_object_unref (simple); + g_task_return_boolean (task, TRUE); + g_object_unref (task); } static void -disconnect_scact_ready (MMBaseModem *modem, +disconnect_scact_ready (MMBaseModem *modem, GAsyncResult *res, - GSimpleAsyncResult *simple) + GTask *task) { - GError *error = NULL; + MMBroadbandBearerSierra *self; + GError *error = NULL; + + self = g_task_get_source_object (task); /* Ignore errors for now */ mm_base_modem_at_command_full_finish (modem, res, &error); if (error) { - mm_dbg ("Disconnection failed (not fatal): %s", error->message); + mm_obj_dbg (self, "disconnection failed (not fatal): %s", error->message); g_error_free (error); } - g_simple_async_result_set_op_res_gboolean (simple, TRUE); - g_simple_async_result_complete (simple); - g_object_unref (simple); + g_task_return_boolean (task, TRUE); + g_object_unref (task); } static void @@ -402,14 +524,11 @@ disconnect_3gpp (MMBroadbandBearer *self, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *result; + GTask *task; g_assert (primary != NULL); - result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - disconnect_3gpp); + task = g_task_new (self, NULL, callback, user_data); if (!MM_IS_PORT_SERIAL_AT (data)) { gchar *command; @@ -419,12 +538,12 @@ disconnect_3gpp (MMBroadbandBearer *self, mm_base_modem_at_command_full (MM_BASE_MODEM (modem), primary, command, - 3, + MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT, FALSE, FALSE, /* raw */ NULL, /* cancellable */ (GAsyncReadyCallback)disconnect_scact_ready, - result); + task); g_free (command); return; } @@ -438,7 +557,7 @@ disconnect_3gpp (MMBroadbandBearer *self, data, cid, (GAsyncReadyCallback)parent_disconnect_3gpp_ready, - result); + task); } /*****************************************************************************/ @@ -533,13 +652,22 @@ mm_broadband_bearer_sierra_init (MMBroadbandBearerSierra *self) static void mm_broadband_bearer_sierra_class_init (MMBroadbandBearerSierraClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass); MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass); g_type_class_add_private (object_class, sizeof (MMBroadbandBearerSierraPrivate)); object_class->set_property = set_property; object_class->get_property = get_property; + + base_bearer_class->load_connection_status = load_connection_status; + base_bearer_class->load_connection_status_finish = load_connection_status_finish; +#if defined WITH_SYSTEMD_SUSPEND_RESUME + base_bearer_class->reload_connection_status = load_connection_status; + base_bearer_class->reload_connection_status_finish = load_connection_status_finish; +#endif + broadband_bearer_class->dial_3gpp = dial_3gpp; broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; broadband_bearer_class->disconnect_3gpp = disconnect_3gpp; |