summaryrefslogtreecommitdiff
path: root/plugins/sierra/mm-broadband-bearer-sierra.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/sierra/mm-broadband-bearer-sierra.c')
-rw-r--r--plugins/sierra/mm-broadband-bearer-sierra.c320
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;