diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-bearer.c | 666 | ||||
-rw-r--r-- | src/mm-broadband-bearer.h | 32 |
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); |