broadband-bearer: reimplement CDMA and 3GPP disconnection logic
This commit is contained in:
@@ -1061,8 +1061,7 @@ connect (MMBearer *self,
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* DISCONNECT (more or less the same for CDMA and 3GPP) */
|
||||
|
||||
/* Detailed disconnect context, used in both CDMA and 3GPP sequences */
|
||||
typedef struct {
|
||||
MMBroadbandBearer *self;
|
||||
MMBaseModem *modem;
|
||||
@@ -1070,52 +1069,14 @@ typedef struct {
|
||||
MMAtSerialPort *secondary;
|
||||
MMPort *data;
|
||||
GSimpleAsyncResult *result;
|
||||
GError *error;
|
||||
|
||||
gboolean cgact_needed;
|
||||
/* 3GPP-specific */
|
||||
gchar *cgact_command;
|
||||
gboolean cgact_sent;
|
||||
} DisconnectContext;
|
||||
|
||||
static void
|
||||
disconnect_context_complete_and_free (DisconnectContext *ctx)
|
||||
{
|
||||
if (ctx->error) {
|
||||
g_simple_async_result_take_error (ctx->result, ctx->error);
|
||||
} else {
|
||||
/* If properly disconnected, close the data port */
|
||||
if (MM_IS_AT_SERIAL_PORT (ctx->data))
|
||||
mm_serial_port_close (MM_SERIAL_PORT (ctx->data));
|
||||
|
||||
/* Port is disconnected; update the state */
|
||||
mm_port_set_connected (ctx->data, FALSE);
|
||||
mm_gdbus_bearer_set_connected (MM_GDBUS_BEARER (ctx->self), FALSE);
|
||||
mm_gdbus_bearer_set_interface (MM_GDBUS_BEARER (ctx->self), NULL);
|
||||
mm_gdbus_bearer_set_ip4_config (MM_GDBUS_BEARER (ctx->self), NULL);
|
||||
mm_gdbus_bearer_set_ip6_config (MM_GDBUS_BEARER (ctx->self), NULL);
|
||||
/* Clear data port and CID */
|
||||
if (ctx->self->priv->cid)
|
||||
ctx->self->priv->cid = 0;
|
||||
g_clear_object (&ctx->self->priv->port);
|
||||
|
||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||
}
|
||||
|
||||
g_simple_async_result_complete_in_idle (ctx->result);
|
||||
|
||||
g_object_unref (ctx->data);
|
||||
g_object_unref (ctx->primary);
|
||||
if (ctx->secondary)
|
||||
g_object_unref (ctx->secondary);
|
||||
g_object_unref (ctx->self);
|
||||
g_object_unref (ctx->modem);
|
||||
g_object_unref (ctx->result);
|
||||
g_free (ctx->cgact_command);
|
||||
g_free (ctx);
|
||||
}
|
||||
} DetailedDisconnectContext;
|
||||
|
||||
static gboolean
|
||||
disconnect_finish (MMBearer *self,
|
||||
detailed_disconnect_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
@@ -1123,20 +1084,52 @@ disconnect_finish (MMBearer *self,
|
||||
}
|
||||
|
||||
static void
|
||||
cgact_primary_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
DisconnectContext *ctx)
|
||||
detailed_disconnect_context_complete_and_free (DetailedDisconnectContext *ctx)
|
||||
{
|
||||
/* Ignore errors for now */
|
||||
mm_base_modem_at_command_finish (MM_BASE_MODEM (modem), res, NULL);
|
||||
|
||||
disconnect_context_complete_and_free (ctx);
|
||||
g_simple_async_result_complete_in_idle (ctx->result);
|
||||
if (ctx->cgact_command)
|
||||
g_free (ctx->cgact_command);
|
||||
g_object_unref (ctx->result);
|
||||
g_object_unref (ctx->data);
|
||||
g_object_unref (ctx->primary);
|
||||
if (ctx->secondary)
|
||||
g_object_unref (ctx->secondary);
|
||||
g_object_unref (ctx->self);
|
||||
g_object_unref (ctx->modem);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static DetailedDisconnectContext *
|
||||
detailed_disconnect_context_new (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMAtSerialPort *primary,
|
||||
MMAtSerialPort *secondary,
|
||||
MMPort *data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DetailedDisconnectContext *ctx;
|
||||
|
||||
ctx = g_new0 (DetailedDisconnectContext, 1);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->secondary = (secondary ? g_object_ref (secondary) : NULL);
|
||||
ctx->data = g_object_ref (data);
|
||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
detailed_disconnect_context_new);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CDMA DISCONNECT */
|
||||
|
||||
static void
|
||||
primary_flash_ready (MMSerialPort *port,
|
||||
primary_flash_cdma_ready (MMSerialPort *port,
|
||||
GError *error,
|
||||
DisconnectContext *ctx)
|
||||
DetailedDisconnectContext *ctx)
|
||||
{
|
||||
if (error) {
|
||||
/* Ignore "NO CARRIER" response when modem disconnects and any flash
|
||||
@@ -1149,8 +1142,85 @@ primary_flash_ready (MMSerialPort *port,
|
||||
MM_SERIAL_ERROR,
|
||||
MM_SERIAL_ERROR_FLASH_FAILED)) {
|
||||
/* Fatal */
|
||||
ctx->error = g_error_copy (error);
|
||||
disconnect_context_complete_and_free (ctx);
|
||||
g_simple_async_result_set_from_error (ctx->result, error);
|
||||
detailed_disconnect_context_complete_and_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_dbg ("Port flashing failed (not fatal): %s", error->message);
|
||||
}
|
||||
|
||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||
detailed_disconnect_context_complete_and_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_cdma (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMAtSerialPort *primary,
|
||||
MMAtSerialPort *secondary,
|
||||
MMPort *data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DetailedDisconnectContext *ctx;
|
||||
|
||||
ctx = detailed_disconnect_context_new (self,
|
||||
modem,
|
||||
primary,
|
||||
secondary,
|
||||
data,
|
||||
callback,
|
||||
user_data);
|
||||
|
||||
/* Just flash the primary port */
|
||||
mm_serial_port_flash (MM_SERIAL_PORT (ctx->primary),
|
||||
1000,
|
||||
TRUE,
|
||||
(MMSerialFlashFn)primary_flash_cdma_ready,
|
||||
ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP DISCONNECT */
|
||||
|
||||
static void
|
||||
cgact_primary_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
DetailedDisconnectContext *ctx)
|
||||
{
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
/* Ignore errors for now */
|
||||
mm_base_modem_at_command_finish (MM_BASE_MODEM (modem), res, &error);
|
||||
if (error) {
|
||||
mm_dbg ("PDP context deactivation failed (not fatal): %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||
detailed_disconnect_context_complete_and_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
primary_flash_3gpp_ready (MMSerialPort *port,
|
||||
GError *error,
|
||||
DetailedDisconnectContext *ctx)
|
||||
{
|
||||
if (error) {
|
||||
/* Ignore "NO CARRIER" response when modem disconnects and any flash
|
||||
* failures we might encounter. Other errors are hard errors.
|
||||
*/
|
||||
if (!g_error_matches (error,
|
||||
MM_CONNECTION_ERROR,
|
||||
MM_CONNECTION_ERROR_NO_CARRIER) &&
|
||||
!g_error_matches (error,
|
||||
MM_SERIAL_ERROR,
|
||||
MM_SERIAL_ERROR_FLASH_FAILED)) {
|
||||
/* Fatal */
|
||||
g_simple_async_result_set_from_error (ctx->result, error);
|
||||
detailed_disconnect_context_complete_and_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1159,12 +1229,19 @@ primary_flash_ready (MMSerialPort *port,
|
||||
|
||||
/* Don't bother doing the CGACT again if it was done on a secondary port
|
||||
* or if not needed */
|
||||
if (!ctx->cgact_needed ||
|
||||
!ctx->cgact_sent) {
|
||||
disconnect_context_complete_and_free (ctx);
|
||||
if (ctx->cgact_sent) {
|
||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||
detailed_disconnect_context_complete_and_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We don't want to try to send CGACT to the still connected port, so
|
||||
* if the primary AT port is actually the data port, set it as
|
||||
* disconnected here already. */
|
||||
if ((gpointer)ctx->primary == (gpointer)ctx->data)
|
||||
/* Port is disconnected; update the state */
|
||||
mm_port_set_connected (ctx->data, FALSE);
|
||||
|
||||
mm_base_modem_at_command_in_port (
|
||||
ctx->modem,
|
||||
ctx->primary,
|
||||
@@ -1179,7 +1256,7 @@ primary_flash_ready (MMSerialPort *port,
|
||||
static void
|
||||
cgact_secondary_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
DisconnectContext *ctx)
|
||||
DetailedDisconnectContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
@@ -1192,50 +1269,28 @@ cgact_secondary_ready (MMBaseModem *modem,
|
||||
mm_serial_port_flash (MM_SERIAL_PORT (ctx->primary),
|
||||
1000,
|
||||
TRUE,
|
||||
(MMSerialFlashFn)primary_flash_ready,
|
||||
(MMSerialFlashFn)primary_flash_3gpp_ready,
|
||||
ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect (MMBearer *self,
|
||||
disconnect_3gpp (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMAtSerialPort *primary,
|
||||
MMAtSerialPort *secondary,
|
||||
MMPort *data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DisconnectContext *ctx;
|
||||
MMBaseModem *modem = NULL;
|
||||
DetailedDisconnectContext *ctx;
|
||||
|
||||
if (!MM_BROADBAND_BEARER (self)->priv->port) {
|
||||
g_simple_async_report_error_in_idle (
|
||||
G_OBJECT (self),
|
||||
ctx = detailed_disconnect_context_new (self,
|
||||
modem,
|
||||
primary,
|
||||
secondary,
|
||||
data,
|
||||
callback,
|
||||
user_data,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't disconnect: this bearer is not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_get (self,
|
||||
MM_BEARER_MODEM, &modem,
|
||||
NULL);
|
||||
g_assert (modem != NULL);
|
||||
|
||||
ctx = g_new0 (DisconnectContext, 1);
|
||||
ctx->data = g_object_ref (MM_BROADBAND_BEARER (self)->priv->port);
|
||||
ctx->primary = g_object_ref (mm_base_modem_get_port_primary (modem));
|
||||
ctx->secondary = mm_base_modem_get_port_secondary (modem);
|
||||
if (ctx->secondary)
|
||||
g_object_ref (ctx->secondary);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->modem = modem;
|
||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
disconnect);
|
||||
|
||||
/* If the modem has 3GPP capabilities, send CGACT to disable contexts */
|
||||
if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (modem))) {
|
||||
ctx->cgact_needed = TRUE;
|
||||
user_data);
|
||||
|
||||
/* If no specific CID was used, disable all PDP contexts */
|
||||
ctx->cgact_command =
|
||||
@@ -1261,16 +1316,164 @@ disconnect (MMBearer *self,
|
||||
ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If CGACT not needed, or if no secondary port, go on to flash the primary port */
|
||||
/* If no secondary port, go on to flash the primary port */
|
||||
mm_serial_port_flash (MM_SERIAL_PORT (ctx->primary),
|
||||
1000,
|
||||
TRUE,
|
||||
(MMSerialFlashFn)primary_flash_ready,
|
||||
(MMSerialFlashFn)primary_flash_3gpp_ready,
|
||||
ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* DISCONNECT */
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandBearer *self;
|
||||
GSimpleAsyncResult *result;
|
||||
MMPort *data;
|
||||
} DisconnectContext;
|
||||
|
||||
static void
|
||||
disconnect_context_complete_and_free (DisconnectContext *ctx)
|
||||
{
|
||||
g_simple_async_result_complete_in_idle (ctx->result);
|
||||
g_object_unref (ctx->result);
|
||||
g_object_unref (ctx->data);
|
||||
g_object_unref (ctx->self);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
disconnect_finish (MMBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_succeeded (DisconnectContext *ctx)
|
||||
{
|
||||
/* If properly disconnected, close the data port */
|
||||
if (MM_IS_AT_SERIAL_PORT (ctx->data))
|
||||
mm_serial_port_close (MM_SERIAL_PORT (ctx->data));
|
||||
|
||||
/* Port is disconnected; update the state. Note: implementations may
|
||||
* already have set the port as disconnected (e.g the 3GPP one) */
|
||||
mm_port_set_connected (ctx->data, FALSE);
|
||||
|
||||
/* Clear data port and CID (if any) */
|
||||
if (ctx->self->priv->cid)
|
||||
ctx->self->priv->cid = 0;
|
||||
g_clear_object (&ctx->self->priv->port);
|
||||
|
||||
/* Set operation result */
|
||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||
disconnect_context_complete_and_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_failed (DisconnectContext *ctx,
|
||||
GError *error)
|
||||
{
|
||||
g_simple_async_result_take_error (ctx->result, error);
|
||||
disconnect_context_complete_and_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_cdma_ready (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
DisconnectContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_cdma_finish (self,
|
||||
res,
|
||||
&error))
|
||||
disconnect_failed (ctx, error);
|
||||
else
|
||||
disconnect_succeeded (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp_ready (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
DisconnectContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_3gpp_finish (self,
|
||||
res,
|
||||
&error))
|
||||
disconnect_failed (ctx, error);
|
||||
else
|
||||
disconnect_succeeded (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect (MMBearer *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBaseModem *modem = NULL;
|
||||
DisconnectContext *ctx;
|
||||
|
||||
if (!MM_BROADBAND_BEARER (self)->priv->port) {
|
||||
g_simple_async_report_error_in_idle (
|
||||
G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't disconnect: this bearer is not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_get (self,
|
||||
MM_BEARER_MODEM, &modem,
|
||||
NULL);
|
||||
g_assert (modem != NULL);
|
||||
|
||||
/* In this context, we only keep the stuff we'll need later */
|
||||
ctx = g_new0 (DisconnectContext, 1);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->data = g_object_ref (MM_BROADBAND_BEARER (self)->priv->port);
|
||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
disconnect);
|
||||
|
||||
switch (MM_BROADBAND_BEARER (self)->priv->connection_type) {
|
||||
case CONNECTION_TYPE_3GPP:
|
||||
MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_3gpp (
|
||||
MM_BROADBAND_BEARER (self),
|
||||
MM_BROADBAND_MODEM (modem),
|
||||
mm_base_modem_get_port_primary (modem),
|
||||
mm_base_modem_get_port_secondary (modem),
|
||||
MM_BROADBAND_BEARER (self)->priv->port,
|
||||
(GAsyncReadyCallback) disconnect_3gpp_ready,
|
||||
ctx);
|
||||
break;
|
||||
|
||||
case CONNECTION_TYPE_CDMA:
|
||||
MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_cdma (
|
||||
MM_BROADBAND_BEARER (self),
|
||||
MM_BROADBAND_MODEM (modem),
|
||||
mm_base_modem_get_port_primary (modem),
|
||||
mm_base_modem_get_port_secondary (modem),
|
||||
MM_BROADBAND_BEARER (self)->priv->port,
|
||||
(GAsyncReadyCallback) disconnect_cdma_ready,
|
||||
ctx);
|
||||
break;
|
||||
|
||||
case CONNECTION_TYPE_NONE:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
g_object_unref (modem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct _InitAsyncContext InitAsyncContext;
|
||||
@@ -1725,6 +1928,11 @@ mm_broadband_bearer_class_init (MMBroadbandBearerClass *klass)
|
||||
klass->connect_cdma = connect_cdma;
|
||||
klass->connect_cdma_finish = detailed_connect_finish;
|
||||
|
||||
klass->disconnect_3gpp = disconnect_3gpp;
|
||||
klass->disconnect_3gpp_finish = detailed_disconnect_finish;
|
||||
klass->disconnect_cdma = disconnect_cdma;
|
||||
klass->disconnect_cdma_finish = detailed_disconnect_finish;
|
||||
|
||||
properties[PROP_3GPP_APN] =
|
||||
g_param_spec_string (MM_BROADBAND_BEARER_3GPP_APN,
|
||||
"3GPP APN",
|
||||
|
@@ -66,6 +66,18 @@ struct _MMBroadbandBearerClass {
|
||||
MMCommonBearerIpConfig **ipv6_config,
|
||||
GError **error);
|
||||
|
||||
/* Full 3GPP disconnection sequence */
|
||||
void (* disconnect_3gpp) (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMAtSerialPort *primary,
|
||||
MMAtSerialPort *secondary,
|
||||
MMPort *data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean (* disconnect_3gpp_finish) (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/* Full CDMA connection sequence */
|
||||
void (* connect_cdma) (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
@@ -80,6 +92,18 @@ struct _MMBroadbandBearerClass {
|
||||
MMCommonBearerIpConfig **ipv4_config,
|
||||
MMCommonBearerIpConfig **ipv6_config,
|
||||
GError **error);
|
||||
|
||||
/* Full CDMA disconnection sequence */
|
||||
void (* disconnect_cdma) (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMAtSerialPort *primary,
|
||||
MMAtSerialPort *secondary,
|
||||
MMPort *data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean (* disconnect_cdma_finish) (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
};
|
||||
|
||||
GType mm_broadband_bearer_get_type (void);
|
||||
|
Reference in New Issue
Block a user