broadband-bearer: reimplement CDMA and 3GPP connection logic

This commit is contained in:
Aleksander Morgado
2012-03-15 14:14:54 +01:00
parent 1d450d7c4e
commit 015756e572
2 changed files with 433 additions and 305 deletions
+401 -305
View File
@@ -98,6 +98,128 @@ mm_broadband_bearer_get_allow_roaming (MMBroadbandBearer *self)
return self->priv->allow_roaming;
}
/*****************************************************************************/
/* Detailed connect context, used in both CDMA and 3GPP sequences */
typedef struct {
MMBroadbandBearer *self;
MMBaseModem *modem;
MMAtSerialPort *primary;
MMPort *data;
GCancellable *cancellable;
GSimpleAsyncResult *result;
/* 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)
{
MMCommonBearerIpConfig *config;
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
return FALSE;
config = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
/* 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;
}
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_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
detailed_connect_context_set_error_if_cancelled (DetailedConnectContext *ctx,
GError **error)
{
if (!g_cancellable_is_cancelled (ctx->cancellable))
return FALSE;
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_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
*
@@ -109,111 +231,37 @@ mm_broadband_bearer_get_allow_roaming (MMBroadbandBearer *self)
* 3) Initiate call.
*/
typedef struct {
MMBroadbandBearer *self;
MMBaseModem *modem;
MMAtSerialPort *primary;
MMPort *data;
GSimpleAsyncResult *result;
gchar *number;
GError *error;
GCancellable *cancellable;
} ConnectContextCdma;
static void
connect_context_cdma_complete_and_free (ConnectContextCdma *ctx)
dial_cdma_ready (MMBaseModem *modem,
GAsyncResult *res,
DetailedConnectContext *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));
GError *error = NULL;
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);
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
}
g_simple_async_result_complete_in_idle (ctx->result);
g_free (ctx->number);
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_cdma_set_error_if_cancelled (ConnectContextCdma *ctx,
GError **error)
{
if (!g_cancellable_is_cancelled (ctx->cancellable))
return FALSE;
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_CANCELLED,
"CDMA connection setup operation has been cancelled");
return TRUE;
}
static void
dial_ready (MMBaseModem *modem,
GAsyncResult *res,
ConnectContextCdma *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_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);
return;
}
GError *error = NULL;
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);
/* If cancelled, complete */
if (detailed_connect_context_complete_and_free_if_cancelled (ctx))
return;
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;
DetailedConnectContext *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);
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_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_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 */
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);
}
/* Otherwise, launch CDMA-specific connection */
connect_cdma (MM_BROADBAND_BEARER (self),
modem,
primary,
data,
number,
cancellable,
callback,
user_data);
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,
+32
View File
@@ -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);