aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-bearer.c666
-rw-r--r--src/mm-broadband-bearer.h32
2 files changed, 413 insertions, 285 deletions
diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c
index 884b0392..e0a9e610 100644
--- a/src/mm-broadband-bearer.c
+++ b/src/mm-broadband-bearer.c
@@ -99,80 +99,76 @@ mm_broadband_bearer_get_allow_roaming (MMBroadbandBearer *self)
}
/*****************************************************************************/
-/* CDMA CONNECT
- *
- * CDMA connection procedure of a bearer involves several steps:
- * 1) Get data port from the modem. Default implementation will have only
- * one single possible data port, but plugins may have more.
- * 2) If requesting specific RM, load current.
- * 2.1) If current RM different to the requested one, set the new one.
- * 3) Initiate call.
- */
-
+/* Detailed connect context, used in both CDMA and 3GPP sequences */
typedef struct {
MMBroadbandBearer *self;
MMBaseModem *modem;
MMAtSerialPort *primary;
MMPort *data;
- GSimpleAsyncResult *result;
- gchar *number;
- GError *error;
GCancellable *cancellable;
-} ConnectContextCdma;
+ GSimpleAsyncResult *result;
-static void
-connect_context_cdma_complete_and_free (ConnectContextCdma *ctx)
+ /* 3GPP-specific */
+ guint cid;
+ guint max_cid;
+ GError *saved_error;
+} DetailedConnectContext;
+
+static gboolean
+detailed_connect_finish (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ MMCommonBearerIpConfig **ipv4_config,
+ MMCommonBearerIpConfig **ipv6_config,
+ GError **error)
{
- if (ctx->error) {
- /* On errors, close the data port */
- if (MM_IS_AT_SERIAL_PORT (ctx->data))
- mm_serial_port_close (MM_SERIAL_PORT (ctx->data));
+ MMCommonBearerIpConfig *config;
- g_simple_async_result_take_error (ctx->result, ctx->error);
- } else {
- GVariant *ip_config;
- GVariantBuilder builder;
- MMBearerIpMethod ip_method;
-
- /* Port is connected; update the state */
- mm_port_set_connected (ctx->data, TRUE);
- mm_gdbus_bearer_set_connected (MM_GDBUS_BEARER (ctx->self),
- TRUE);
- mm_gdbus_bearer_set_interface (MM_GDBUS_BEARER (ctx->self),
- mm_port_get_device (ctx->data));
-
- /* If serial port, set PPP method */
- ip_method = (MM_IS_AT_SERIAL_PORT (ctx->data) ?
- MM_BEARER_IP_METHOD_PPP :
- MM_BEARER_IP_METHOD_DHCP);
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
- g_variant_builder_add (&builder, "{sv}", "method", g_variant_new_uint32 (ip_method));
- ip_config = g_variant_builder_end (&builder);
- mm_gdbus_bearer_set_ip4_config (MM_GDBUS_BEARER (ctx->self), ip_config);
- mm_gdbus_bearer_set_ip6_config (MM_GDBUS_BEARER (ctx->self), ip_config);
-
- /* Keep data port around while connected */
- ctx->self->priv->port = g_object_ref (ctx->data);
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return FALSE;
- g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
- }
+ config = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
- g_simple_async_result_complete_in_idle (ctx->result);
+ /* In the default implementation, we assume we'll have the same configs */
+ *ipv4_config = g_object_ref (config);
+ *ipv6_config = g_object_ref (config);
+ return TRUE;
+}
- g_free (ctx->number);
+static void
+detailed_connect_context_complete_and_free (DetailedConnectContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_object_unref (ctx->result);
+ if (ctx->saved_error)
+ g_error_free (ctx->saved_error);
g_object_unref (ctx->cancellable);
g_object_unref (ctx->data);
g_object_unref (ctx->primary);
g_object_unref (ctx->self);
g_object_unref (ctx->modem);
- g_object_unref (ctx->result);
g_free (ctx);
}
+static void
+detailed_connect_context_complete_and_free_successful (DetailedConnectContext *ctx)
+{
+ MMCommonBearerIpConfig *config;
+
+ /* If serial port, set PPP method. Otherwise, assume DHCP is needed. */
+ config = mm_common_bearer_ip_config_new ();
+ mm_common_bearer_ip_config_set_method (config,
+ (MM_IS_AT_SERIAL_PORT (ctx->data) ?
+ MM_BEARER_IP_METHOD_PPP :
+ MM_BEARER_IP_METHOD_DHCP));
+ g_simple_async_result_set_op_res_gpointer (ctx->result,
+ config,
+ (GDestroyNotify)g_object_unref);
+ detailed_connect_context_complete_and_free (ctx);
+}
+
static gboolean
-connect_context_cdma_set_error_if_cancelled (ConnectContextCdma *ctx,
- GError **error)
+detailed_connect_context_set_error_if_cancelled (DetailedConnectContext *ctx,
+ GError **error)
{
if (!g_cancellable_is_cancelled (ctx->cancellable))
return FALSE;
@@ -180,40 +176,92 @@ connect_context_cdma_set_error_if_cancelled (ConnectContextCdma *ctx,
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_CANCELLED,
- "CDMA connection setup operation has been cancelled");
+ "Connection setup operation has been cancelled");
+ return TRUE;
+}
+
+static gboolean
+detailed_connect_context_complete_and_free_if_cancelled (DetailedConnectContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!detailed_connect_context_set_error_if_cancelled (ctx, &error))
+ return FALSE;
+
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return TRUE;
}
+static DetailedConnectContext *
+detailed_connect_context_new (MMBroadbandBearer *self,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMPort *data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DetailedConnectContext *ctx;
+
+ ctx = g_new0 (DetailedConnectContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
+ ctx->primary = g_object_ref (primary);
+ ctx->data = g_object_ref (data);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ detailed_connect_context_new);
+ /* NOTE:
+ * We don't currently support cancelling AT commands, so we'll just check
+ * whether the operation is to be cancelled at each step. */
+ ctx->cancellable = g_object_ref (cancellable);
+ return ctx;
+}
+
+/*****************************************************************************/
+/* CDMA CONNECT
+ *
+ * CDMA connection procedure of a bearer involves several steps:
+ * 1) Get data port from the modem. Default implementation will have only
+ * one single possible data port, but plugins may have more.
+ * 2) If requesting specific RM, load current.
+ * 2.1) If current RM different to the requested one, set the new one.
+ * 3) Initiate call.
+ */
+
static void
-dial_ready (MMBaseModem *modem,
- GAsyncResult *res,
- ConnectContextCdma *ctx)
+dial_cdma_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ DetailedConnectContext *ctx)
{
+ GError *error = NULL;
+
/* DO NOT check for cancellable here. If we got here without errors, the
* bearer is really connected and therefore we need to reflect that in
* the state machine. */
- mm_base_modem_at_command_finish (modem, res, &(ctx->error));
- if (ctx->error)
- mm_warn ("Couldn't connect: '%s'", ctx->error->message);
- /* else... Yuhu! */
+ mm_base_modem_at_command_finish (modem, res, &error);
+ if (error) {
+ mm_warn ("Couldn't connect: '%s'", error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
+ return;
+ }
- connect_context_cdma_complete_and_free (ctx);
+ /* else... Yuhu! */
+ detailed_connect_context_complete_and_free_successful (ctx);
}
static void
-cdma_connect_context_dial (ConnectContextCdma *ctx)
+cdma_connect_context_dial (DetailedConnectContext *ctx)
{
gchar *command;
- /* Decide which number to dial, in the following order:
- * (1) If a number given during Connect(), use it.
- * (2) If a number given when creating the bearer, use that one. Wait, this is quite
- * redundant, isn't it?
- * (3) Otherwise, use the default one, #777
+ /* If a number was given when creating the bearer, use that one.
+ * Otherwise, use the default one, #777
*/
- if (ctx->number)
- command = g_strconcat ("DT", ctx->number, NULL);
- else if (ctx->self->priv->number)
+ if (ctx->self->priv->number)
command = g_strconcat ("DT", ctx->self->priv->number, NULL);
else
command = g_strdup ("DT#777");
@@ -224,7 +272,7 @@ cdma_connect_context_dial (ConnectContextCdma *ctx)
90,
FALSE,
NULL, /* cancellable */
- (GAsyncReadyCallback)dial_ready,
+ (GAsyncReadyCallback)dial_cdma_ready,
ctx);
g_free (command);
}
@@ -232,18 +280,19 @@ cdma_connect_context_dial (ConnectContextCdma *ctx)
static void
set_rm_protocol_ready (MMBaseModem *self,
GAsyncResult *res,
- ConnectContextCdma *ctx)
+ DetailedConnectContext *ctx)
{
- /* If cancelled, complete */
- if (connect_context_cdma_set_error_if_cancelled (ctx, &ctx->error)) {
- connect_context_cdma_complete_and_free (ctx);
+ GError *error = NULL;
+
+ /* If cancelled, complete */
+ if (detailed_connect_context_complete_and_free_if_cancelled (ctx))
return;
- }
- mm_base_modem_at_command_finish (self, res, &(ctx->error));
- if (ctx->error) {
- mm_warn ("Couldn't set RM protocol: '%s'", ctx->error->message);
- connect_context_cdma_complete_and_free (ctx);
+ mm_base_modem_at_command_finish (self, res, &error);
+ if (error) {
+ mm_warn ("Couldn't set RM protocol: '%s'", error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return;
}
@@ -254,33 +303,34 @@ set_rm_protocol_ready (MMBaseModem *self,
static void
current_rm_protocol_ready (MMBaseModem *self,
GAsyncResult *res,
- ConnectContextCdma *ctx)
+ DetailedConnectContext *ctx)
{
const gchar *result;
+ GError *error = NULL;
guint current_index;
MMModemCdmaRmProtocol current_rm;
/* If cancelled, complete */
- if (connect_context_cdma_set_error_if_cancelled (ctx, &ctx->error)) {
- connect_context_cdma_complete_and_free (ctx);
+ if (detailed_connect_context_complete_and_free_if_cancelled (ctx))
return;
- }
- result = mm_base_modem_at_command_finish (self, res, &(ctx->error));
- if (ctx->error) {
- mm_warn ("Couldn't query current RM protocol: '%s'", ctx->error->message);
- connect_context_cdma_complete_and_free (ctx);
+ result = mm_base_modem_at_command_finish (self, res, &error);
+ if (error) {
+ mm_warn ("Couldn't query current RM protocol: '%s'", error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return;
}
result = mm_strip_tag (result, "+CRM:");
current_index = (guint) atoi (result);
- current_rm = mm_cdma_get_rm_protocol_from_index (current_index, &ctx->error);
- if (ctx->error) {
+ current_rm = mm_cdma_get_rm_protocol_from_index (current_index, &error);
+ if (error) {
mm_warn ("Couldn't parse RM protocol reply (%s): '%s'",
result,
- ctx->error->message);
- connect_context_cdma_complete_and_free (ctx);
+ error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return;
}
@@ -292,11 +342,12 @@ current_rm_protocol_ready (MMBaseModem *self,
new_index = (mm_cdma_get_index_from_rm_protocol (
ctx->self->priv->rm_protocol,
- &ctx->error));
- if (ctx->error) {
+ &error));
+ if (error) {
mm_warn ("Cannot set RM protocol: '%s'",
- ctx->error->message);
- connect_context_cdma_complete_and_free (ctx);
+ error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return;
}
@@ -320,32 +371,23 @@ current_rm_protocol_ready (MMBaseModem *self,
static void
connect_cdma (MMBroadbandBearer *self,
- MMBaseModem *modem,
+ MMBroadbandModem *modem,
MMAtSerialPort *primary,
+ MMAtSerialPort *secondary, /* unused by us */
MMPort *data,
- const gchar *number,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
- ConnectContextCdma *ctx;
-
- ctx = g_new0 (ConnectContextCdma, 1);
- ctx->primary = g_object_ref (primary);
- ctx->data = g_object_ref (data);
- ctx->self = g_object_ref (self);
- ctx->number = g_strdup (number);
- ctx->modem = g_object_ref (modem);
-
- /* NOTE:
- * We don't currently support cancelling AT commands, so we'll just check
- * whether the operation is to be cancelled at each step. */
- ctx->cancellable = g_object_ref (cancellable);
+ DetailedConnectContext *ctx;
- ctx->result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- connect_cdma);
+ ctx = detailed_connect_context_new (self,
+ modem,
+ primary,
+ data,
+ cancellable,
+ callback,
+ user_data);
if (self->priv->rm_protocol != MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN) {
/* Need to query current RM protocol */
@@ -381,122 +423,46 @@ connect_cdma (MMBroadbandBearer *self,
* 4) Initiate call.
*/
-typedef struct {
- MMBroadbandBearer *self;
- MMBaseModem *modem;
- MMAtSerialPort *primary;
- MMPort *data;
- guint cid;
- guint max_cid;
- GSimpleAsyncResult *result;
- GError *error;
- GCancellable *cancellable;
-} ConnectContext3gpp;
-
-static void
-connect_context_3gpp_complete_and_free (ConnectContext3gpp *ctx)
-{
- if (ctx->error) {
- /* On errors, close the data port */
- if (MM_IS_AT_SERIAL_PORT (ctx->data))
- mm_serial_port_close (MM_SERIAL_PORT (ctx->data));
-
- g_simple_async_result_take_error (ctx->result, ctx->error);
- } else {
- GVariant *ip_config;
- GVariantBuilder builder;
- MMBearerIpMethod ip_method;
-
- /* Port is connected; update the state */
- mm_port_set_connected (ctx->data, TRUE);
- mm_gdbus_bearer_set_connected (MM_GDBUS_BEARER (ctx->self),
- TRUE);
- mm_gdbus_bearer_set_interface (MM_GDBUS_BEARER (ctx->self),
- mm_port_get_device (ctx->data));
-
- /* If serial port, set PPP method */
- ip_method = (MM_IS_AT_SERIAL_PORT (ctx->data) ?
- MM_BEARER_IP_METHOD_PPP :
- MM_BEARER_IP_METHOD_DHCP);
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
- g_variant_builder_add (&builder, "{sv}", "method", g_variant_new_uint32 (ip_method));
- ip_config = g_variant_builder_end (&builder);
- mm_gdbus_bearer_set_ip4_config (MM_GDBUS_BEARER (ctx->self), ip_config);
- mm_gdbus_bearer_set_ip6_config (MM_GDBUS_BEARER (ctx->self), ip_config);
-
- /* Keep data port and CID around while connected */
- ctx->self->priv->cid = ctx->cid;
- ctx->self->priv->port = g_object_ref (ctx->data);
-
- g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
- }
-
- g_simple_async_result_complete_in_idle (ctx->result);
-
- g_object_unref (ctx->cancellable);
- g_object_unref (ctx->data);
- g_object_unref (ctx->primary);
- g_object_unref (ctx->self);
- g_object_unref (ctx->modem);
- g_object_unref (ctx->result);
- g_free (ctx);
-}
-
-static gboolean
-connect_context_3gpp_set_error_if_cancelled (ConnectContext3gpp *ctx,
- GError **error)
-{
- if (!g_cancellable_is_cancelled (ctx->cancellable))
- return FALSE;
-
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
- "3GPP connection setup operation has been cancelled");
- return TRUE;
-}
-
static void
connect_report_ready (MMBaseModem *modem,
GAsyncResult *res,
- ConnectContext3gpp *ctx)
+ DetailedConnectContext *ctx)
{
const gchar *result;
/* If cancelled, complete */
- if (connect_context_3gpp_set_error_if_cancelled (ctx, &ctx->error)) {
- connect_context_3gpp_complete_and_free (ctx);
+ if (detailed_connect_context_complete_and_free_if_cancelled (ctx))
return;
- }
result = mm_base_modem_at_command_finish (modem, res, NULL);
if (result &&
g_str_has_prefix (result, "+CEER: ") &&
strlen (result) > 7) {
- GError *rebuilt;
+ g_simple_async_result_set_error (ctx->result,
+ ctx->saved_error->domain,
+ ctx->saved_error->code,
+ "%s", &result[7]);
+ } else
+ g_simple_async_result_take_error (ctx->result,
+ ctx->saved_error);
- rebuilt = g_error_new (ctx->error->domain,
- ctx->error->code,
- "%s", &result[7]);
- g_error_free (ctx->error);
- ctx->error = rebuilt;
- }
+ g_error_free (ctx->saved_error);
+ ctx->saved_error = NULL;
/* Done with errors */
- connect_context_3gpp_complete_and_free (ctx);
+ detailed_connect_context_complete_and_free (ctx);
}
static void
-connect_ready (MMBaseModem *modem,
- GAsyncResult *res,
- ConnectContext3gpp *ctx)
+dial_3gpp_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ DetailedConnectContext *ctx)
{
/* DO NOT check for cancellable here. If we got here without errors, the
* bearer is really connected and therefore we need to reflect that in
* the state machine. */
- mm_base_modem_at_command_finish (modem, res, &(ctx->error));
- if (ctx->error) {
+ mm_base_modem_at_command_finish (modem, res, &(ctx->saved_error));
+ if (ctx->saved_error) {
/* Try to get more information why it failed */
mm_base_modem_at_command_in_port (
modem,
@@ -510,27 +476,32 @@ connect_ready (MMBaseModem *modem,
return;
}
+ /* Keep data port and CID around while connected */
+ ctx->self->priv->cid = ctx->cid;
+ ctx->self->priv->port = g_object_ref (ctx->data);
+
/* Yuhu! */
- connect_context_3gpp_complete_and_free (ctx);
+ detailed_connect_context_complete_and_free_successful (ctx);
}
static void
initialize_pdp_context_ready (MMBaseModem *self,
GAsyncResult *res,
- ConnectContext3gpp *ctx)
+ DetailedConnectContext *ctx)
{
+ GError *error = NULL;
gchar *command;
/* If cancelled, complete */
- if (connect_context_3gpp_set_error_if_cancelled (ctx, &ctx->error)) {
- connect_context_3gpp_complete_and_free (ctx);
+ if (detailed_connect_context_complete_and_free_if_cancelled (ctx))
return;
- }
- mm_base_modem_at_command_finish (self, res, &(ctx->error));
- if (ctx->error) {
- mm_warn ("Couldn't initialize PDP context with our APN: '%s'", ctx->error->message);
- connect_context_3gpp_complete_and_free (ctx);
+ mm_base_modem_at_command_finish (self, res, &error);
+ if (error) {
+ mm_warn ("Couldn't initialize PDP context with our APN: '%s'",
+ error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return;
}
@@ -543,7 +514,7 @@ initialize_pdp_context_ready (MMBaseModem *self,
60,
FALSE,
NULL, /* cancellable */
- (GAsyncReadyCallback)connect_ready,
+ (GAsyncReadyCallback)dial_3gpp_ready,
ctx);
g_free (command);
}
@@ -551,7 +522,7 @@ initialize_pdp_context_ready (MMBaseModem *self,
static void
find_cid_ready (MMBaseModem *self,
GAsyncResult *res,
- ConnectContext3gpp *ctx)
+ DetailedConnectContext *ctx)
{
GVariant *result;
gchar *command;
@@ -560,18 +531,16 @@ find_cid_ready (MMBaseModem *self,
result = mm_base_modem_at_sequence_finish (self, res, NULL, &error);
if (!result) {
mm_warn ("Couldn't find best CID to use: '%s'", error->message);
- ctx->error = error;
- connect_context_3gpp_complete_and_free (ctx);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
return;
}
/* If cancelled, complete. Normally, we would get the cancellation error
* already when finishing the sequence, but we may still get cancelled
* between last command result parsing in the sequence and the ready(). */
- if (connect_context_3gpp_set_error_if_cancelled (ctx, &ctx->error)) {
- connect_context_3gpp_complete_and_free (ctx);
+ if (detailed_connect_context_complete_and_free_if_cancelled (ctx))
return;
- }
/* Initialize PDP context with our APN */
ctx->cid = g_variant_get_uint32 (result);
@@ -592,7 +561,7 @@ find_cid_ready (MMBaseModem *self,
static gboolean
parse_cid_range (MMBaseModem *self,
- ConnectContext3gpp *ctx,
+ DetailedConnectContext *ctx,
const gchar *command,
const gchar *response,
gboolean last_command,
@@ -606,7 +575,7 @@ parse_cid_range (MMBaseModem *self,
guint cid = 0;
/* If cancelled, set result error */
- if (connect_context_3gpp_set_error_if_cancelled (ctx, result_error))
+ if (detailed_connect_context_set_error_if_cancelled (ctx, result_error))
return FALSE;
if (error) {
@@ -677,7 +646,7 @@ parse_cid_range (MMBaseModem *self,
static gboolean
parse_pdp_list (MMBaseModem *self,
- ConnectContext3gpp *ctx,
+ DetailedConnectContext *ctx,
const gchar *command,
const gchar *response,
gboolean last_command,
@@ -691,7 +660,7 @@ parse_pdp_list (MMBaseModem *self,
guint cid;
/* If cancelled, set result error */
- if (connect_context_3gpp_set_error_if_cancelled (ctx, result_error))
+ if (detailed_connect_context_set_error_if_cancelled (ctx, result_error))
return FALSE;
ctx->max_cid = 0;
@@ -760,30 +729,23 @@ static const MMBaseModemAtCommand find_cid_sequence[] = {
static void
connect_3gpp (MMBroadbandBearer *self,
- MMBaseModem *modem,
+ MMBroadbandModem *modem,
MMAtSerialPort *primary,
+ MMAtSerialPort *secondary, /* unused by us */
MMPort *data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
- ConnectContext3gpp *ctx;
+ DetailedConnectContext *ctx;
- ctx = g_new0 (ConnectContext3gpp, 1);
- ctx->primary = g_object_ref (primary);
- ctx->data = g_object_ref (data);
- ctx->self = g_object_ref (self);
- ctx->modem = g_object_ref (modem);
-
- /* NOTE:
- * We don't currently support cancelling AT commands, so we'll just check
- * whether the operation is to be cancelled at each step. */
- ctx->cancellable = g_object_ref (cancellable);
-
- ctx->result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- connect_3gpp);
+ ctx = detailed_connect_context_new (self,
+ modem,
+ primary,
+ data,
+ cancellable,
+ callback,
+ user_data);
mm_dbg ("Looking for best CID...");
mm_base_modem_at_sequence_in_port (
@@ -800,24 +762,144 @@ connect_3gpp (MMBroadbandBearer *self,
/*****************************************************************************/
/* CONNECT */
+typedef struct {
+ MMPort *data;
+ MMCommonBearerIpConfig *ipv4_config;
+ MMCommonBearerIpConfig *ipv6_config;
+} ConnectResult;
+
+static void
+connect_result_free (ConnectResult *result)
+{
+ if (result->ipv4_config)
+ g_object_unref (result->ipv4_config);
+ if (result->ipv6_config)
+ g_object_unref (result->ipv6_config);
+ g_object_unref (result->data);
+ g_free (result);
+}
+
+typedef struct {
+ MMBroadbandBearer *self;
+ GSimpleAsyncResult *result;
+ MMPort *data;
+} ConnectContext;
+
+static void
+connect_context_complete_and_free (ConnectContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->data);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
static gboolean
connect_finish (MMBearer *self,
GAsyncResult *res,
+ MMPort **data,
+ MMCommonBearerIpConfig **ipv4_config,
+ MMCommonBearerIpConfig **ipv6_config,
GError **error)
{
- return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+ ConnectResult *result;
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return FALSE;
+
+ result = (ConnectResult *) g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+ *data = MM_PORT (g_object_ref (result->data));
+ *ipv4_config = (result->ipv4_config ? g_object_ref (result->ipv4_config) : NULL);
+ *ipv6_config = (result->ipv6_config ? g_object_ref (result->ipv6_config) : NULL);
+
+ return TRUE;
+}
+
+static void
+connect_succeeded (ConnectContext *ctx,
+ MMCommonBearerIpConfig *ipv4_config,
+ MMCommonBearerIpConfig *ipv6_config)
+{
+ ConnectResult *result;
+
+ /* Port is connected; update the state */
+ mm_port_set_connected (ctx->data, TRUE);
+
+ /* Build result */
+ result = g_new0 (ConnectResult, 1);
+ result->data = g_object_ref (ctx->data);
+ result->ipv4_config = ipv4_config;
+ result->ipv6_config = ipv6_config;
+
+ /* Set operation result */
+ g_simple_async_result_set_op_res_gpointer (ctx->result,
+ result,
+ (GDestroyNotify)connect_result_free);
+
+ connect_context_complete_and_free (ctx);
+}
+
+static void
+connect_failed (ConnectContext *ctx,
+ GError *error)
+{
+ /* On errors, close the data port */
+ if (MM_IS_AT_SERIAL_PORT (ctx->data))
+ mm_serial_port_close (MM_SERIAL_PORT (ctx->data));
+
+ g_simple_async_result_take_error (ctx->result, error);
+ connect_context_complete_and_free (ctx);
+}
+
+static void
+connect_cdma_ready (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ ConnectContext *ctx)
+{
+ GError *error = NULL;
+ MMCommonBearerIpConfig *ipv4_config = NULL;
+ MMCommonBearerIpConfig *ipv6_config = NULL;
+
+ if (!MM_BROADBAND_BEARER_GET_CLASS (self)->connect_cdma_finish (self,
+ res,
+ &ipv4_config,
+ &ipv6_config,
+ &error))
+ connect_failed (ctx, error);
+ else
+ connect_succeeded (ctx, ipv4_config, ipv6_config);
+}
+
+static void
+connect_3gpp_ready (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ ConnectContext *ctx)
+{
+ GError *error = NULL;
+ MMCommonBearerIpConfig *ipv4_config = NULL;
+ MMCommonBearerIpConfig *ipv6_config = NULL;
+
+ if (!MM_BROADBAND_BEARER_GET_CLASS (self)->connect_3gpp_finish (self,
+ res,
+ &ipv4_config,
+ &ipv6_config,
+ &error))
+ connect_failed (ctx, error);
+ else
+ connect_succeeded (ctx, ipv4_config, ipv6_config);
}
static void
connect (MMBearer *self,
- const gchar *number,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MMBaseModem *modem = NULL;
MMAtSerialPort *primary;
MMPort *data;
- MMBaseModem *modem = NULL;
+ ConnectContext *ctx;
/* Don't try to connect if already connected */
if (MM_BROADBAND_BEARER (self)->priv->port) {
@@ -870,46 +952,55 @@ connect (MMBearer *self,
* which is actually always right now, this is already ensured because the
* primary port is kept open as long as the modem is enabled, but anyway
* there's no real problem in keeping an open count here as well. */
- if (MM_IS_AT_SERIAL_PORT (data)) {
- GError *error = NULL;
-
- if (!mm_serial_port_open (MM_SERIAL_PORT (data), &error)) {
- g_prefix_error (&error, "Couldn't connect: cannot keep data port open.");
- g_simple_async_report_take_gerror_in_idle (
- G_OBJECT (self),
- callback,
- user_data,
- error);
- g_object_unref (modem);
- return;
- }
+ if (MM_IS_AT_SERIAL_PORT (data)) {
+ GError *error = NULL;
+
+ if (!mm_serial_port_open (MM_SERIAL_PORT (data), &error)) {
+ g_prefix_error (&error, "Couldn't connect: cannot keep data port open.");
+ g_simple_async_report_take_gerror_in_idle (
+ G_OBJECT (self),
+ callback,
+ user_data,
+ error);
+ g_object_unref (modem);
+ return;
+ }
}
+ /* In this context, we only keep the stuff we'll need later */
+ ctx = g_new0 (ConnectContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->data = g_object_ref (data);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ connect);
+
/* If the modem has 3GPP capabilities, launch 3GPP-based connection */
- if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self))) {
- if (number && number[0])
- mm_warn ("Ignoring number to use when connecting 3GPP bearer: '%s'", number);
-
- connect_3gpp (MM_BROADBAND_BEARER (self),
- modem,
- primary,
- data,
- cancellable,
- callback,
- user_data);
- g_object_unref (modem);
- return;
+ 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);
}
-
/* Otherwise, launch CDMA-specific connection */
- connect_cdma (MM_BROADBAND_BEARER (self),
- modem,
- primary,
- data,
- number,
- cancellable,
- callback,
- user_data);
+ 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);
+ }
+
g_object_unref (modem);
}
@@ -1437,6 +1528,11 @@ mm_broadband_bearer_class_init (MMBroadbandBearerClass *klass)
bearer_class->disconnect = disconnect;
bearer_class->disconnect_finish = disconnect_finish;
+ klass->connect_3gpp = connect_3gpp;
+ klass->connect_3gpp_finish = detailed_connect_finish;
+ klass->connect_cdma = connect_cdma;
+ klass->connect_cdma_finish = detailed_connect_finish;
+
properties[PROP_3GPP_APN] =
g_param_spec_string (MM_BROADBAND_BEARER_3GPP_APN,
"3GPP APN",
@@ -1471,7 +1567,7 @@ mm_broadband_bearer_class_init (MMBroadbandBearerClass *klass)
g_object_class_install_property (object_class, PROP_IP_TYPE, properties[PROP_IP_TYPE]);
properties[PROP_ALLOW_ROAMING] =
- g_param_spec_boolean (MM_BEARER_ALLOW_ROAMING,
+ g_param_spec_boolean (MM_BROADBAND_BEARER_ALLOW_ROAMING,
"Allow roaming",
"Whether connections are allowed when roaming",
TRUE,
diff --git a/src/mm-broadband-bearer.h b/src/mm-broadband-bearer.h
index 31f60565..5355d2c2 100644
--- a/src/mm-broadband-bearer.h
+++ b/src/mm-broadband-bearer.h
@@ -21,6 +21,8 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmm-common.h>
+
#include "mm-bearer.h"
#include "mm-broadband-modem.h"
@@ -48,6 +50,36 @@ struct _MMBroadbandBearer {
struct _MMBroadbandBearerClass {
MMBearerClass parent;
+
+ /* Full 3GPP connection sequence */
+ void (* connect_3gpp) (MMBroadbandBearer *self,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMAtSerialPort *secondary,
+ MMPort *data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* connect_3gpp_finish) (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ MMCommonBearerIpConfig **ipv4_config,
+ MMCommonBearerIpConfig **ipv6_config,
+ GError **error);
+
+ /* Full CDMA connection sequence */
+ void (* connect_cdma) (MMBroadbandBearer *self,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMAtSerialPort *secondary,
+ MMPort *data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* connect_cdma_finish) (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ MMCommonBearerIpConfig **ipv4_config,
+ MMCommonBearerIpConfig **ipv6_config,
+ GError **error);
};
GType mm_broadband_bearer_get_type (void);