broadband-modem: try to simplify 3GPP network registration
When requesting to register in the network manually, we will poll every once in a while to check whether we got registered or not. We remove the registration timeout and we handle the case where it never gets registered by allowing a maximum number of registration checks in our request.
This commit is contained in:
@@ -76,8 +76,7 @@ struct _MMBroadbandModemPrivate {
|
|||||||
MMModem3gppRegistrationState reg_cs;
|
MMModem3gppRegistrationState reg_cs;
|
||||||
MMModem3gppRegistrationState reg_ps;
|
MMModem3gppRegistrationState reg_ps;
|
||||||
gboolean manual_reg;
|
gboolean manual_reg;
|
||||||
guint pending_reg_id;
|
GCancellable *pending_reg_cancellable;
|
||||||
GSimpleAsyncResult *pending_reg_request;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -1062,8 +1061,8 @@ load_operator_name (MMIfaceModem3gpp *self,
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Unsolicited registration messages handling (3GPP) */
|
/* Unsolicited registration messages handling (3GPP) */
|
||||||
|
|
||||||
static void clear_previous_registration_request (MMBroadbandModem *self,
|
/* static void clear_previous_registration_request (MMBroadbandModem *self, */
|
||||||
gboolean complete_with_cancel);
|
/* gboolean complete_with_cancel); */
|
||||||
|
|
||||||
static MMModem3gppRegistrationState
|
static MMModem3gppRegistrationState
|
||||||
get_consolidated_reg_state (MMBroadbandModem *self)
|
get_consolidated_reg_state (MMBroadbandModem *self)
|
||||||
@@ -1133,11 +1132,11 @@ reg_state_changed (MMAtSerialPort *port,
|
|||||||
state,
|
state,
|
||||||
act);
|
act);
|
||||||
|
|
||||||
/* If registration is finished (either registered or failed) but the
|
/* /\* If registration is finished (either registered or failed) but the */
|
||||||
* registration query hasn't completed yet, just remove the timeout and
|
/* * registration query hasn't completed yet, just remove the timeout and */
|
||||||
* let the registration query complete by itself.
|
/* * let the registration query complete by itself. */
|
||||||
*/
|
/* *\/ */
|
||||||
clear_previous_registration_request (self, FALSE);
|
/* clear_previous_registration_request (self, FALSE); */
|
||||||
|
|
||||||
/* TODO: report LAC/CI location */
|
/* TODO: report LAC/CI location */
|
||||||
/* update_lac_ci (self, lac, cell_id, cgreg ? 1 : 0); */
|
/* update_lac_ci (self, lac, cell_id, cgreg ? 1 : 0); */
|
||||||
@@ -1214,8 +1213,8 @@ cleanup_unsolicited_registration (MMIfaceModem3gpp *self,
|
|||||||
|
|
||||||
mm_dbg ("cleaning up unsolicited registration messages handling");
|
mm_dbg ("cleaning up unsolicited registration messages handling");
|
||||||
|
|
||||||
/* Cancel any ongoing registration request */
|
/* /\* Cancel any ongoing registration request *\/ */
|
||||||
clear_previous_registration_request (MM_BROADBAND_MODEM (self), TRUE);
|
/* clear_previous_registration_request (MM_BROADBAND_MODEM (self), TRUE); */
|
||||||
|
|
||||||
result = g_simple_async_result_new (G_OBJECT (self),
|
result = g_simple_async_result_new (G_OBJECT (self),
|
||||||
callback,
|
callback,
|
||||||
@@ -1282,9 +1281,34 @@ scan_networks (MMIfaceModem3gpp *self,
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Register in network (3GPP) */
|
/* Register in network (3GPP) */
|
||||||
|
|
||||||
static void run_all_registration_checks_ready (MMBroadbandModem *self,
|
/* Maximum time to wait for a successful registration when polling
|
||||||
GAsyncResult *res,
|
* periodically */
|
||||||
GSimpleAsyncResult *operation_result);
|
#define MAX_REGISTRATION_CHECK_WAIT_TIME 60
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBroadbandModem *self;
|
||||||
|
GSimpleAsyncResult *result;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
GTimer *timer;
|
||||||
|
} RegisterInNetworkContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
register_in_network_context_complete_and_free (RegisterInNetworkContext *ctx)
|
||||||
|
{
|
||||||
|
/* If our cancellable reference is still around, clear it */
|
||||||
|
if (ctx->self->priv->pending_reg_cancellable == ctx->cancellable) {
|
||||||
|
g_clear_object (&ctx->self->priv->pending_reg_cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->timer)
|
||||||
|
g_timer_destroy (ctx->timer);
|
||||||
|
|
||||||
|
g_simple_async_result_complete (ctx->result);
|
||||||
|
g_object_unref (ctx->result);
|
||||||
|
g_object_unref (ctx->cancellable);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
register_in_network_finish (MMIfaceModem3gpp *self,
|
register_in_network_finish (MMIfaceModem3gpp *self,
|
||||||
@@ -1295,86 +1319,34 @@ register_in_network_finish (MMIfaceModem3gpp *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define REG_IS_IDLE(state) \
|
#define REG_IS_IDLE(state) \
|
||||||
(state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || \
|
(state != MM_MODEM_3GPP_REGISTRATION_STATE_HOME && \
|
||||||
state == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || \
|
state != MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING && \
|
||||||
state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING)
|
state != MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING)
|
||||||
|
|
||||||
#define REG_IS_DONE(state) \
|
#define REG_IS_DONE(state) \
|
||||||
(state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || \
|
(state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || \
|
||||||
state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING || \
|
state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING || \
|
||||||
state == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED)
|
state == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED)
|
||||||
|
|
||||||
static void
|
static void run_all_registration_checks_ready (MMBroadbandModem *self,
|
||||||
clear_previous_registration_request (MMBroadbandModem *self,
|
GAsyncResult *res,
|
||||||
gboolean complete_with_cancel)
|
RegisterInNetworkContext *ctx);
|
||||||
{
|
|
||||||
if (self->priv->pending_reg_id) {
|
|
||||||
/* Clear the registration timeout handler */
|
|
||||||
g_source_remove (self->priv->pending_reg_id);
|
|
||||||
self->priv->pending_reg_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->priv->pending_reg_request) {
|
|
||||||
if (complete_with_cancel) {
|
|
||||||
g_simple_async_result_set_error (self->priv->pending_reg_request,
|
|
||||||
MM_CORE_ERROR,
|
|
||||||
MM_CORE_ERROR_CANCELLED,
|
|
||||||
"New registration request to be processed");
|
|
||||||
g_simple_async_result_complete_in_idle (self->priv->pending_reg_request);
|
|
||||||
}
|
|
||||||
g_object_unref (self->priv->pending_reg_request);
|
|
||||||
self->priv->pending_reg_request = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
register_in_network_timed_out (MMBroadbandModem *self)
|
run_all_registration_checks_again (RegisterInNetworkContext *ctx)
|
||||||
{
|
{
|
||||||
g_assert (self->priv->pending_reg_request != NULL);
|
|
||||||
|
|
||||||
/* Report IDLE registration state */
|
|
||||||
mm_iface_modem_3gpp_update_registration_state (MM_IFACE_MODEM_3GPP (self),
|
|
||||||
MM_MODEM_3GPP_REGISTRATION_STATE_IDLE,
|
|
||||||
MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
|
||||||
|
|
||||||
g_simple_async_result_take_error (
|
|
||||||
self->priv->pending_reg_request,
|
|
||||||
mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT));
|
|
||||||
g_simple_async_result_complete (self->priv->pending_reg_request);
|
|
||||||
g_object_unref (self->priv->pending_reg_request);
|
|
||||||
self->priv->pending_reg_request = NULL;
|
|
||||||
self->priv->pending_reg_id = 0;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
run_all_registration_checks_again (GSimpleAsyncResult *operation_result)
|
|
||||||
{
|
|
||||||
MMBroadbandModem *self;
|
|
||||||
|
|
||||||
self = MM_BROADBAND_MODEM (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
|
|
||||||
|
|
||||||
/* If the registration timed out (and thus pending_reg_info will be NULL)
|
|
||||||
* and the modem eventually got around to sending the response for the
|
|
||||||
* registration request then just ignore the response since the callback is
|
|
||||||
* already called.
|
|
||||||
*/
|
|
||||||
if (!self->priv->pending_reg_request)
|
|
||||||
g_object_unref (operation_result);
|
|
||||||
else
|
|
||||||
/* Get fresh registration state */
|
/* Get fresh registration state */
|
||||||
mm_iface_modem_3gpp_run_all_registration_checks (
|
mm_iface_modem_3gpp_run_all_registration_checks (
|
||||||
MM_IFACE_MODEM_3GPP (self),
|
MM_IFACE_MODEM_3GPP (ctx->self),
|
||||||
(GAsyncReadyCallback)run_all_registration_checks_ready,
|
(GAsyncReadyCallback)run_all_registration_checks_ready,
|
||||||
operation_result);
|
ctx);
|
||||||
g_object_unref (self);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
run_all_registration_checks_ready (MMBroadbandModem *self,
|
run_all_registration_checks_ready (MMBroadbandModem *self,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GSimpleAsyncResult *operation_result)
|
RegisterInNetworkContext *ctx)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
@@ -1382,70 +1354,74 @@ run_all_registration_checks_ready (MMBroadbandModem *self,
|
|||||||
res,
|
res,
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
/* If the registration timed out (and thus pending_reg_info will be NULL)
|
if (error) {
|
||||||
* and the modem eventually got around to sending the response for the
|
mm_dbg ("Registration check failed: '%s'", error->message);
|
||||||
* registration request then just ignore the response since the callback is
|
mm_iface_modem_3gpp_update_registration_state (MM_IFACE_MODEM_3GPP (self),
|
||||||
* already called.
|
MM_MODEM_3GPP_REGISTRATION_STATE_IDLE,
|
||||||
*/
|
MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
||||||
if (!self->priv->pending_reg_request) {
|
g_simple_async_result_take_error (ctx->result, error);
|
||||||
g_object_unref (operation_result);
|
register_in_network_context_complete_and_free (ctx);
|
||||||
g_clear_error (&error);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we got registered, end registration checks */
|
||||||
|
if (REG_IS_DONE (self->priv->modem_3gpp_registration_state)) {
|
||||||
|
mm_dbg ("Modem is currently registered in 3GPP network");
|
||||||
|
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||||
|
register_in_network_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't spent too much time waiting to get registered */
|
||||||
|
if (g_timer_elapsed (ctx->timer, NULL) > MAX_REGISTRATION_CHECK_WAIT_TIME) {
|
||||||
|
mm_dbg ("Registration check timed out");
|
||||||
|
mm_iface_modem_3gpp_update_registration_state (MM_IFACE_MODEM_3GPP (self),
|
||||||
|
MM_MODEM_3GPP_REGISTRATION_STATE_IDLE,
|
||||||
|
MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
||||||
|
g_simple_async_result_take_error (
|
||||||
|
ctx->result,
|
||||||
|
mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT));
|
||||||
|
register_in_network_context_complete_and_free (ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error)
|
|
||||||
g_simple_async_result_take_error (operation_result, error);
|
|
||||||
else if (REG_IS_DONE (self->priv->modem_3gpp_registration_state))
|
|
||||||
g_simple_async_result_set_op_res_gboolean (operation_result, TRUE);
|
|
||||||
else {
|
|
||||||
/* If we're still waiting for automatic registration to complete or
|
/* If we're still waiting for automatic registration to complete or
|
||||||
* fail, check again in a few seconds.
|
* fail, check again in a few seconds.
|
||||||
|
*
|
||||||
|
* This 3s timeout will catch results from automatic registrations as
|
||||||
|
* well.
|
||||||
*/
|
*/
|
||||||
g_timeout_add_seconds (1,
|
mm_dbg ("Modem not yet registered... will recheck soon");
|
||||||
|
g_timeout_add_seconds (3,
|
||||||
(GSourceFunc)run_all_registration_checks_again,
|
(GSourceFunc)run_all_registration_checks_again,
|
||||||
operation_result);
|
ctx);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_simple_async_result_complete (operation_result);
|
|
||||||
clear_previous_registration_request (self, FALSE);
|
|
||||||
g_object_unref (operation_result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
register_in_network_ready (MMBroadbandModem *self,
|
register_in_network_ready (MMBroadbandModem *self,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GSimpleAsyncResult *operation_result)
|
RegisterInNetworkContext *ctx)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||||
|
|
||||||
/* If the registration timed out (and thus pending_reg_info will be NULL)
|
|
||||||
* and the modem eventually got around to sending the response for the
|
|
||||||
* registration request then just ignore the response since the callback is
|
|
||||||
* already called.
|
|
||||||
*/
|
|
||||||
if (!self->priv->pending_reg_request) {
|
|
||||||
g_object_unref (operation_result);
|
|
||||||
g_clear_error (&error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
/* Propagate error in COPS, if any */
|
/* Propagate error in COPS, if any */
|
||||||
g_simple_async_result_take_error (operation_result, error);
|
mm_iface_modem_3gpp_update_registration_state (MM_IFACE_MODEM_3GPP (self),
|
||||||
g_simple_async_result_complete (operation_result);
|
MM_MODEM_3GPP_REGISTRATION_STATE_IDLE,
|
||||||
clear_previous_registration_request (self, FALSE);
|
MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
||||||
g_object_unref (operation_result);
|
g_simple_async_result_take_error (ctx->result, error);
|
||||||
|
register_in_network_context_complete_and_free (ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get fresh registration state */
|
/* Get fresh registration state */
|
||||||
|
ctx->timer = g_timer_new ();
|
||||||
mm_iface_modem_3gpp_run_all_registration_checks (
|
mm_iface_modem_3gpp_run_all_registration_checks (
|
||||||
MM_IFACE_MODEM_3GPP (self),
|
MM_IFACE_MODEM_3GPP (self),
|
||||||
(GAsyncReadyCallback)run_all_registration_checks_ready,
|
(GAsyncReadyCallback)run_all_registration_checks_ready,
|
||||||
operation_result);
|
ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1455,23 +1431,26 @@ register_in_network (MMIfaceModem3gpp *self,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
MMBroadbandModem *broadband = MM_BROADBAND_MODEM (self);
|
MMBroadbandModem *broadband = MM_BROADBAND_MODEM (self);
|
||||||
GSimpleAsyncResult *result;
|
RegisterInNetworkContext *ctx;
|
||||||
gchar *command = NULL;
|
gchar *command = NULL;
|
||||||
|
|
||||||
result = g_simple_async_result_new (G_OBJECT (self),
|
/* (Try to) cancel previous registration request */
|
||||||
|
if (broadband->priv->pending_reg_cancellable) {
|
||||||
|
g_cancellable_cancel (broadband->priv->pending_reg_cancellable);
|
||||||
|
g_clear_object (&broadband->priv->pending_reg_cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = g_new0 (RegisterInNetworkContext, 1);
|
||||||
|
ctx->self = g_object_ref (self);
|
||||||
|
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||||
callback,
|
callback,
|
||||||
user_data,
|
user_data,
|
||||||
register_in_network);
|
register_in_network);
|
||||||
|
ctx->cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
/* Cleanup any previous registration, completing it with a cancelled error */
|
/* Keep an accessible reference to the cancellable, so that we can cancel
|
||||||
clear_previous_registration_request (broadband, TRUE);
|
* previous request when needed */
|
||||||
|
broadband->priv->pending_reg_cancellable = g_object_ref (ctx->cancellable);
|
||||||
/* Setup timeout */
|
|
||||||
broadband->priv->pending_reg_id =
|
|
||||||
g_timeout_add_seconds (60,
|
|
||||||
(GSourceFunc)register_in_network_timed_out,
|
|
||||||
self);
|
|
||||||
broadband->priv->pending_reg_request = g_object_ref (result);
|
|
||||||
|
|
||||||
/* If the user sent a specific network to use, lock it in. */
|
/* If the user sent a specific network to use, lock it in. */
|
||||||
if (network_id && network_id[0]) {
|
if (network_id && network_id[0]) {
|
||||||
@@ -1486,24 +1465,32 @@ register_in_network (MMIfaceModem3gpp *self,
|
|||||||
broadband->priv->manual_reg) {
|
broadband->priv->manual_reg) {
|
||||||
command = g_strdup ("+COPS=0,,");
|
command = g_strdup ("+COPS=0,,");
|
||||||
broadband->priv->manual_reg = FALSE;
|
broadband->priv->manual_reg = FALSE;
|
||||||
} else
|
}
|
||||||
mm_dbg ("Not launching any new network selection request");
|
|
||||||
|
|
||||||
if (command) {
|
if (command) {
|
||||||
|
/* Don't setup an additional timeout to handle registration timeouts. We
|
||||||
|
* already do this with the 120s timeout in the AT command: if that times
|
||||||
|
* out, we can consider the registration itself timed out. */
|
||||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||||
command,
|
command,
|
||||||
120,
|
120,
|
||||||
FALSE,
|
FALSE,
|
||||||
NULL, /* cancellable */
|
ctx->cancellable,
|
||||||
(GAsyncReadyCallback)register_in_network_ready,
|
(GAsyncReadyCallback)register_in_network_ready,
|
||||||
result);
|
ctx);
|
||||||
} else {
|
g_free (command);
|
||||||
/* Just rely on the unsolicited registration, periodic registration
|
return;
|
||||||
* checks or the timeout. */
|
|
||||||
g_simple_async_result_set_op_res_gboolean (result, TRUE);
|
|
||||||
g_simple_async_result_complete_in_idle (result);
|
|
||||||
g_object_unref (result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Just rely on the unsolicited registration and periodic registration checks */
|
||||||
|
mm_dbg ("Not launching any new network selection request");
|
||||||
|
|
||||||
|
/* Get fresh registration state */
|
||||||
|
ctx->timer = g_timer_new ();
|
||||||
|
mm_iface_modem_3gpp_run_all_registration_checks (
|
||||||
|
MM_IFACE_MODEM_3GPP (self),
|
||||||
|
(GAsyncReadyCallback)run_all_registration_checks_ready,
|
||||||
|
ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
Reference in New Issue
Block a user