diff --git a/temp/modemmanager/0001-base-manager-add-quick-suspend-resume-base.patch b/temp/modemmanager/0001-base-manager-add-quick-suspend-resume-base.patch new file mode 100644 index 000000000..24880cf67 --- /dev/null +++ b/temp/modemmanager/0001-base-manager-add-quick-suspend-resume-base.patch @@ -0,0 +1,488 @@ +From d5f3a6d441f47836698b851d6049bf738d066ef6 Mon Sep 17 00:00:00 2001 +From: Dylan Van Assche +Date: Sat, 1 May 2021 15:50:47 +0200 +Subject: [PATCH 01/39] base-manager: add quick suspend/resume base + +Quick suspend/resume infrastructure for +synchronizing the interfaces when resuming. +--- + src/main.c | 14 +++- + src/mm-base-manager.c | 48 ++++++++++++ + src/mm-base-manager.h | 4 + + src/mm-base-modem.c | 155 +++++++++++++++++++++++++++++++++++++++ + src/mm-base-modem.h | 23 ++++++ + src/mm-broadband-modem.c | 81 ++++++++++++++++++++ + src/mm-context.c | 11 +++ + src/mm-context.h | 1 + + 8 files changed, 336 insertions(+), 1 deletion(-) + +diff --git a/src/main.c b/src/main.c +index 928078a3..4a036971 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -72,6 +72,13 @@ resuming_cb (MMSleepMonitor *sleep_monitor) + mm_base_manager_start (manager, FALSE); + } + ++static void ++resuming_quick_cb (MMSleepMonitor *sleep_monitor) ++{ ++ mm_dbg ("syncing modem state (quick resuming)"); ++ mm_base_manager_sync (manager); ++} ++ + #endif + + static void +@@ -197,7 +204,12 @@ main (int argc, char *argv[]) + + if (mm_context_get_test_no_suspend_resume()) + mm_dbg ("Suspend/resume support disabled at runtime"); +- else { ++ else if (mm_context_get_test_quick_suspend_resume()) { ++ mm_dbg ("Quick suspend/resume hooks enabled"); ++ sleep_monitor = mm_sleep_monitor_get (); ++ g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_quick_cb), NULL); ++ } else { ++ mm_dbg ("Full suspend/resume hooks enabled"); + sleep_monitor = mm_sleep_monitor_get (); + g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_SLEEPING, G_CALLBACK (sleeping_cb), NULL); + g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_cb), NULL); +diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c +index 130e5ad1..0c393f11 100644 +--- a/src/mm-base-manager.c ++++ b/src/mm-base-manager.c +@@ -45,6 +45,7 @@ + #include "mm-plugin.h" + #include "mm-filter.h" + #include "mm-log-object.h" ++#include "mm-base-modem.h" + + static void initable_iface_init (GInitableIface *iface); + static void log_object_iface_init (MMLogObjectInterface *iface); +@@ -663,6 +664,53 @@ mm_base_manager_num_modems (MMBaseManager *self) + return n; + } + ++/*****************************************************************************/ ++/* Quick resume synchronization */ ++ ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++gboolean mm_base_modem_sync_finish (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void ++mm_base_modem_sync_ready (MMBaseModem *self, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ g_autoptr(GError) error; ++ ++ mm_base_modem_sync_finish (self, res, &error); ++ if (error) { ++ mm_obj_warn (self, "synchronization failed"); ++ return; ++ } ++ mm_obj_info (self, "synchronization finished"); ++} ++ ++void ++mm_base_manager_sync (MMBaseManager *self) ++{ ++ GHashTableIter iter; ++ gpointer key, value; ++ ++ g_return_if_fail (self != NULL); ++ g_return_if_fail (MM_IS_BASE_MANAGER (self)); ++ ++ /* Refresh each device */ ++ g_hash_table_iter_init (&iter, self->priv->devices); ++ while (g_hash_table_iter_next (&iter, &key, &value)) { ++ MMBaseModem *modem = mm_device_peek_modem (MM_DEVICE (value)); ++ /* We just want to start the synchronization, we don't need the result */ ++ mm_base_modem_sync (modem, (GAsyncReadyCallback)mm_base_modem_sync_ready, NULL); ++ } ++} ++ ++#endif ++ + /*****************************************************************************/ + /* Set logging */ + +diff --git a/src/mm-base-manager.h b/src/mm-base-manager.h +index d70fa08f..be51d0c0 100644 +--- a/src/mm-base-manager.h ++++ b/src/mm-base-manager.h +@@ -66,6 +66,10 @@ void mm_base_manager_start (MMBaseManager *manager, + void mm_base_manager_shutdown (MMBaseManager *manager, + gboolean disable); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++void mm_base_manager_sync (MMBaseManager *manager); ++#endif ++ + guint32 mm_base_manager_num_modems (MMBaseManager *manager); + + #endif /* MM_BASE_MANAGER_H */ +diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c +index 926d0712..38f43f8c 100644 +--- a/src/mm-base-modem.c ++++ b/src/mm-base-modem.c +@@ -369,6 +369,161 @@ mm_base_modem_grab_port (MMBaseModem *self, + return TRUE; + } + ++/******************************************************************************/ ++ ++typedef struct { ++ gchar *name; ++ gulong link_port_grabbed_id; ++ guint timeout_id; ++} WaitLinkPortContext; ++ ++static void ++wait_link_port_context_free (WaitLinkPortContext *ctx) ++{ ++ g_assert (!ctx->link_port_grabbed_id); ++ g_assert (!ctx->timeout_id); ++ g_free (ctx->name); ++ g_slice_free (WaitLinkPortContext, ctx); ++} ++ ++MMPort * ++mm_base_modem_wait_link_port_finish (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_pointer (G_TASK (res), error); ++} ++ ++static gboolean ++wait_link_port_timeout_cb (GTask *task) ++{ ++ WaitLinkPortContext *ctx; ++ MMBaseModem *self; ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ ctx->timeout_id = 0; ++ g_signal_handler_disconnect (self, ctx->link_port_grabbed_id); ++ ctx->link_port_grabbed_id = 0; ++ ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, ++ "Timed out waiting for link port 'net/%s'", ++ ctx->name); ++ g_object_unref (task); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static void ++wait_link_port_grabbed_cb (MMBaseModem *self, ++ MMPort *link_port, ++ GTask *task) ++{ ++ WaitLinkPortContext *ctx; ++ MMPortSubsys link_port_subsystem; ++ const gchar *link_port_name; ++ ++ ctx = g_task_get_task_data (task); ++ ++ link_port_subsystem = mm_port_get_subsys (link_port); ++ link_port_name = mm_port_get_device (link_port); ++ ++ if (link_port_subsystem != MM_PORT_SUBSYS_NET) { ++ mm_obj_warn (self, "unexpected link port subsystem grabbed: %s/%s", ++ mm_port_subsys_get_string (link_port_subsystem), ++ link_port_name); ++ return; ++ } ++ ++ if (g_strcmp0 (link_port_name, ctx->name) != 0) ++ return; ++ ++ /* we got it! */ ++ ++ g_source_remove (ctx->timeout_id); ++ ctx->timeout_id = 0; ++ g_signal_handler_disconnect (self, ctx->link_port_grabbed_id); ++ ctx->link_port_grabbed_id = 0; ++ ++ g_task_return_pointer (task, g_object_ref (link_port), g_object_unref); ++ g_object_unref (task); ++} ++ ++void ++mm_base_modem_wait_link_port (MMBaseModem *self, ++ const gchar *subsystem, ++ const gchar *name, ++ guint timeout_ms, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ WaitLinkPortContext *ctx; ++ GTask *task; ++ g_autofree gchar *key = NULL; ++ MMPort *port; ++ ++ task = g_task_new (self, NULL, callback, user_data); ++ ++ if (!g_str_equal (subsystem, "net")) { ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, ++ "Cannot wait for port '%s/%s', unexpected link port subsystem", subsystem, name); ++ g_object_unref (task); ++ return; ++ } ++ ++ key = g_strdup_printf ("%s%s", subsystem, name); ++ port = g_hash_table_lookup (self->priv->link_ports, key); ++ if (port) { ++ mm_obj_dbg (self, "no need to wait for port '%s/%s': already grabbed", subsystem, name); ++ g_task_return_pointer (task, g_object_ref (port), g_object_unref); ++ g_object_unref (task); ++ return; ++ } ++ ++ ctx = g_slice_new0 (WaitLinkPortContext); ++ ctx->name = g_strdup (name); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)wait_link_port_context_free); ++ ++ /* task ownership shared between timeout and signal handler */ ++ ctx->timeout_id = g_timeout_add (timeout_ms, ++ (GSourceFunc) wait_link_port_timeout_cb, ++ task); ++ ctx->link_port_grabbed_id = g_signal_connect (self, ++ MM_BASE_MODEM_SIGNAL_LINK_PORT_GRABBED, ++ G_CALLBACK (wait_link_port_grabbed_cb), ++ task); ++ ++ mm_obj_dbg (self, "waiting for port '%s/%s'...", subsystem, name); ++} ++ ++/******************************************************************************/ ++ ++static void ++mm_base_modem_sync_ready (MMBaseModem *self, ++ GAsyncResult *res) ++{ ++ g_autoptr (GError) error = NULL; ++ ++ MM_BASE_MODEM_GET_CLASS (self)->sync_finish (self, res, &error); ++ if (error) { ++ mm_obj_warn (self, "synchronization failed"); ++ } ++} ++ ++void ++mm_base_modem_sync (MMBaseModem *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync != NULL); ++ g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync_finish != NULL); ++ ++ MM_BASE_MODEM_GET_CLASS (self)->sync (self, ++ (GAsyncReadyCallback) mm_base_modem_sync_ready, ++ NULL); ++} ++ + gboolean + mm_base_modem_disable_finish (MMBaseModem *self, + GAsyncResult *res, +diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h +index 24634814..75fd99f5 100644 +--- a/src/mm-base-modem.h ++++ b/src/mm-base-modem.h +@@ -101,6 +101,22 @@ struct _MMBaseModemClass { + gboolean (*disable_finish) (MMBaseModem *self, + GAsyncResult *res, + GError **error); ++ ++ /* Modem synchronization. ++ * When resuming in quick suspend/resume mode, ++ * this method triggers a synchronization of all modem interfaces */ ++ void (* sync) (MMBaseModem *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++ gboolean (* sync_finish) (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error); ++ ++ /* signals */ ++ void (* link_port_grabbed) (MMBaseModem *self, ++ MMPort *link_port); ++ void (* link_port_released) (MMBaseModem *self, ++ MMPort *link_port); + }; + + GType mm_base_modem_get_type (void); +@@ -199,6 +215,13 @@ gboolean mm_base_modem_disable_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error); + ++void mm_base_modem_sync (MMBaseModem *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean mm_base_modem_sync_finish (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error); ++ + void mm_base_modem_process_sim_event (MMBaseModem *self); + + #endif /* MM_BASE_MODEM_H */ +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index a25883ac..6e47757e 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11337,6 +11337,82 @@ enable (MMBaseModem *self, + + g_object_unref (task); + } ++/*****************************************************************************/ ++ ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++typedef enum { ++ SYNCING_STEP_FIRST, ++ SYNCING_STEP_LAST, ++} SyncingStep; ++ ++typedef struct { ++ SyncingStep step; ++} SyncingContext; ++ ++static gboolean ++synchronize_finish (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void ++syncing_step (GTask *task) ++{ ++ MMBroadbandModem *self; ++ SyncingContext *ctx; ++ ++ /* Don't run new steps if we're cancelled */ ++ if (g_task_return_error_if_cancelled (task)) { ++ g_object_unref (task); ++ return; ++ } ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ switch (ctx->step) { ++ case SYNCING_STEP_FIRST: ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_LAST: ++ mm_obj_info (self, "resume synchronization state (%d/%d): all done", ++ ctx->step, SYNCING_STEP_LAST); ++ /* We are done without errors! */ ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); ++ return; ++ ++ default: ++ break; ++ } ++ ++ g_assert_not_reached (); ++} ++ ++/* 'sync' as function name conflicts with a declared function in unistd.h */ ++static void ++synchronize (MMBaseModem *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ SyncingContext *ctx; ++ GTask *task; ++ ++ /* Create SyncingContext */ ++ ctx = g_new0 (SyncingContext, 1); ++ ctx->step = SYNCING_STEP_FIRST; ++ ++ /* Create sync steps task and execute it */ ++ task = g_task_new (MM_BROADBAND_MODEM (self), NULL, callback, user_data); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); ++ syncing_step (task); ++} ++ ++#endif + + /*****************************************************************************/ + +@@ -12683,6 +12759,11 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) + base_modem_class->disable = disable; + base_modem_class->disable_finish = disable_finish; + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_modem_class->sync = synchronize; ++ base_modem_class->sync_finish = synchronize_finish; ++#endif ++ + klass->setup_ports = setup_ports; + klass->initialization_started = initialization_started; + klass->initialization_started_finish = initialization_started_finish; +diff --git a/src/mm-context.c b/src/mm-context.c +index 6561127e..691ca82b 100644 +--- a/src/mm-context.c ++++ b/src/mm-context.c +@@ -227,6 +227,7 @@ static gboolean test_no_udev; + #endif + #if defined WITH_SYSTEMD_SUSPEND_RESUME + static gboolean test_no_suspend_resume; ++static gboolean test_quick_suspend_resume; + #endif + + static const GOptionEntry test_entries[] = { +@@ -258,6 +259,11 @@ static const GOptionEntry test_entries[] = { + "Disable suspend/resume support at runtime even if available", + NULL + }, ++ { ++ "test-quick-suspend-resume", 0, 0, G_OPTION_ARG_NONE, &test_quick_suspend_resume, ++ "Enable quick suspend/resume support for modems which stay on during host suspension", ++ NULL ++ }, + #endif + { NULL } + }; +@@ -308,6 +314,11 @@ mm_context_get_test_no_suspend_resume (void) + { + return test_no_suspend_resume; + } ++gboolean ++mm_context_get_test_quick_suspend_resume (void) ++{ ++ return test_quick_suspend_resume; ++} + #endif + + /*****************************************************************************/ +diff --git a/src/mm-context.h b/src/mm-context.h +index 721fee88..276567fd 100644 +--- a/src/mm-context.h ++++ b/src/mm-context.h +@@ -51,6 +51,7 @@ gboolean mm_context_get_test_no_udev (void); + #endif + #if defined WITH_SYSTEMD_SUSPEND_RESUME + gboolean mm_context_get_test_no_suspend_resume (void); ++gboolean mm_context_get_test_quick_suspend_resume (void); + #endif + + #endif /* MM_CONTEXT_H */ +-- +2.31.1 + diff --git a/temp/modemmanager/0002-base-manager-make-sure-g_autoptr-variables-are-initi.patch b/temp/modemmanager/0002-base-manager-make-sure-g_autoptr-variables-are-initi.patch new file mode 100644 index 000000000..72df82baa --- /dev/null +++ b/temp/modemmanager/0002-base-manager-make-sure-g_autoptr-variables-are-initi.patch @@ -0,0 +1,33 @@ +From 4853aa702ed298ebceea2e9cd737d048380db38f Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:16:55 +0200 +Subject: [PATCH 02/39] base-manager: make sure g_autoptr() variables are + initialized to NULL + +Otherwise, we may have memory issues if the variable isn't initialized +and the method exits. +--- + src/mm-base-manager.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c +index 0c393f11..5880ffad 100644 +--- a/src/mm-base-manager.c ++++ b/src/mm-base-manager.c +@@ -681,11 +681,11 @@ mm_base_modem_sync_ready (MMBaseModem *self, + GAsyncResult *res, + gpointer user_data) + { +- g_autoptr(GError) error; ++ g_autoptr(GError) error = NULL; + + mm_base_modem_sync_finish (self, res, &error); + if (error) { +- mm_obj_warn (self, "synchronization failed"); ++ mm_obj_warn (self, "synchronization failed: %s", error->message); + return; + } + mm_obj_info (self, "synchronization finished"); +-- +2.31.1 + diff --git a/temp/modemmanager/0003-base-manager-don-t-assume-a-MMDevice-always-holds-a-.patch b/temp/modemmanager/0003-base-manager-don-t-assume-a-MMDevice-always-holds-a-.patch new file mode 100644 index 000000000..8a99cd65c --- /dev/null +++ b/temp/modemmanager/0003-base-manager-don-t-assume-a-MMDevice-always-holds-a-.patch @@ -0,0 +1,35 @@ +From dcea41cebabbcbd91597944fc3ff87c8d9aa5121 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:17:40 +0200 +Subject: [PATCH 03/39] base-manager: don't assume a MMDevice always holds a + MMModem + +There are cases, e.g. during modem object disposal, where this is not +true. +--- + src/mm-base-manager.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c +index 5880ffad..c900eeaa 100644 +--- a/src/mm-base-manager.c ++++ b/src/mm-base-manager.c +@@ -703,9 +703,13 @@ mm_base_manager_sync (MMBaseManager *self) + /* Refresh each device */ + g_hash_table_iter_init (&iter, self->priv->devices); + while (g_hash_table_iter_next (&iter, &key, &value)) { +- MMBaseModem *modem = mm_device_peek_modem (MM_DEVICE (value)); ++ MMBaseModem *modem; ++ ++ modem = mm_device_peek_modem (MM_DEVICE (value)); ++ + /* We just want to start the synchronization, we don't need the result */ +- mm_base_modem_sync (modem, (GAsyncReadyCallback)mm_base_modem_sync_ready, NULL); ++ if (modem) ++ mm_base_modem_sync (modem, (GAsyncReadyCallback)mm_base_modem_sync_ready, NULL); + } + } + +-- +2.31.1 + diff --git a/temp/modemmanager/0004-base-manager-avoid-using-the-mm_-prefix-for-static-p.patch b/temp/modemmanager/0004-base-manager-avoid-using-the-mm_-prefix-for-static-p.patch new file mode 100644 index 000000000..d6fbff2e3 --- /dev/null +++ b/temp/modemmanager/0004-base-manager-avoid-using-the-mm_-prefix-for-static-p.patch @@ -0,0 +1,39 @@ +From d02fad407c451e90fc6cbc0ad99aba86ff303816 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:18:42 +0200 +Subject: [PATCH 04/39] base-manager: avoid using the `mm_` prefix for static + private methods + +--- + src/mm-base-manager.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c +index c900eeaa..5af959fb 100644 +--- a/src/mm-base-manager.c ++++ b/src/mm-base-manager.c +@@ -677,9 +677,9 @@ gboolean mm_base_modem_sync_finish (MMBaseModem *self, + } + + static void +-mm_base_modem_sync_ready (MMBaseModem *self, +- GAsyncResult *res, +- gpointer user_data) ++base_modem_sync_ready (MMBaseModem *self, ++ GAsyncResult *res, ++ gpointer user_data) + { + g_autoptr(GError) error = NULL; + +@@ -709,7 +709,7 @@ mm_base_manager_sync (MMBaseManager *self) + + /* We just want to start the synchronization, we don't need the result */ + if (modem) +- mm_base_modem_sync (modem, (GAsyncReadyCallback)mm_base_modem_sync_ready, NULL); ++ mm_base_modem_sync (modem, (GAsyncReadyCallback)base_modem_sync_ready, NULL); + } + } + +-- +2.31.1 + diff --git a/temp/modemmanager/0005-base-modem-fix-modem_sync-operation-handling.patch b/temp/modemmanager/0005-base-modem-fix-modem_sync-operation-handling.patch new file mode 100644 index 000000000..c02de15a5 --- /dev/null +++ b/temp/modemmanager/0005-base-modem-fix-modem_sync-operation-handling.patch @@ -0,0 +1,101 @@ +From 261684e74d4d00df63d7106162e2d0bb42e9652c Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:19:06 +0200 +Subject: [PATCH 05/39] base-modem: fix modem_sync() operation handling + +The mm_base_modem_sync() method is an asynchronous method that +receives a callback and user data, and therefore we MUST always +complete the async method calling that callback. Set that up with a +GTask as usual. + +Also, the mm_base_modem_sync_finish() method should be implemented +along with mm_base_modem_sync(), not in the source file of the +caller of the async method. The finish() always depends on how the +async method was implemented, in our case using a GTask. +--- + src/mm-base-manager.c | 7 ------- + src/mm-base-modem.c | 34 +++++++++++++++++++++++++--------- + 2 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c +index 5af959fb..236405bb 100644 +--- a/src/mm-base-manager.c ++++ b/src/mm-base-manager.c +@@ -669,13 +669,6 @@ mm_base_manager_num_modems (MMBaseManager *self) + + #if defined WITH_SYSTEMD_SUSPEND_RESUME + +-gboolean mm_base_modem_sync_finish (MMBaseModem *self, +- GAsyncResult *res, +- GError **error) +-{ +- return g_task_propagate_boolean (G_TASK (res), error); +-} +- + static void + base_modem_sync_ready (MMBaseModem *self, + GAsyncResult *res, +diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c +index 38f43f8c..923f159a 100644 +--- a/src/mm-base-modem.c ++++ b/src/mm-base-modem.c +@@ -499,16 +499,26 @@ mm_base_modem_wait_link_port (MMBaseModem *self, + + /******************************************************************************/ + ++gboolean ++mm_base_modem_sync_finish (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ + static void +-mm_base_modem_sync_ready (MMBaseModem *self, +- GAsyncResult *res) ++sync_ready (MMBaseModem *self, ++ GAsyncResult *res, ++ GTask *task) + { +- g_autoptr (GError) error = NULL; ++ g_autoptr(GError) error = NULL; + +- MM_BASE_MODEM_GET_CLASS (self)->sync_finish (self, res, &error); +- if (error) { +- mm_obj_warn (self, "synchronization failed"); +- } ++ if (!MM_BASE_MODEM_GET_CLASS (self)->sync_finish (self, res, &error)) ++ g_task_return_error (task, error); ++ else ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); + } + + void +@@ -516,14 +526,20 @@ mm_base_modem_sync (MMBaseModem *self, + GAsyncReadyCallback callback, + gpointer user_data) + { ++ GTask *task; ++ ++ task = g_task_new (self, NULL, callback, user_data); ++ + g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync != NULL); + g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync_finish != NULL); + + MM_BASE_MODEM_GET_CLASS (self)->sync (self, +- (GAsyncReadyCallback) mm_base_modem_sync_ready, +- NULL); ++ (GAsyncReadyCallback) sync_ready, ++ task); + } + ++/******************************************************************************/ ++ + gboolean + mm_base_modem_disable_finish (MMBaseModem *self, + GAsyncResult *res, +-- +2.31.1 + diff --git a/temp/modemmanager/0006-base-modem-don-t-fail-if-sync-isn-t-implemented.patch b/temp/modemmanager/0006-base-modem-don-t-fail-if-sync-isn-t-implemented.patch new file mode 100644 index 000000000..59b81d7f8 --- /dev/null +++ b/temp/modemmanager/0006-base-modem-don-t-fail-if-sync-isn-t-implemented.patch @@ -0,0 +1,32 @@ +From 053d3f84f0fe4b13ec4586b180cea4aba8fc01ea Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:23:59 +0200 +Subject: [PATCH 06/39] base-modem: don't fail if sync() isn't implemented + +--- + src/mm-base-modem.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c +index 923f159a..28519ad4 100644 +--- a/src/mm-base-modem.c ++++ b/src/mm-base-modem.c +@@ -530,8 +530,13 @@ mm_base_modem_sync (MMBaseModem *self, + + task = g_task_new (self, NULL, callback, user_data); + +- g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync != NULL); +- g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync_finish != NULL); ++ if (!MM_BASE_MODEM_GET_CLASS (self)->sync || ++ !MM_BASE_MODEM_GET_CLASS (self)->sync_finish) { ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, ++ "Suspend/resume quick synchronization unsupported"); ++ g_object_unref (task); ++ return; ++ } + + MM_BASE_MODEM_GET_CLASS (self)->sync (self, + (GAsyncReadyCallback) sync_ready, +-- +2.31.1 + diff --git a/temp/modemmanager/0007-base-modem-make-sync-available-only-if-suspend-resum.patch b/temp/modemmanager/0007-base-modem-make-sync-available-only-if-suspend-resum.patch new file mode 100644 index 000000000..68c3021d3 --- /dev/null +++ b/temp/modemmanager/0007-base-modem-make-sync-available-only-if-suspend-resum.patch @@ -0,0 +1,74 @@ +From 4cf023022a07011120e18239722626efbded9180 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Wed, 26 May 2021 10:36:47 +0200 +Subject: [PATCH 07/39] base-modem: make sync() available only if + suspend-resume enabled + +--- + src/mm-base-modem.c | 4 ++++ + src/mm-base-modem.h | 6 ++++++ + 2 files changed, 10 insertions(+) + +diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c +index 28519ad4..580103ba 100644 +--- a/src/mm-base-modem.c ++++ b/src/mm-base-modem.c +@@ -499,6 +499,8 @@ mm_base_modem_wait_link_port (MMBaseModem *self, + + /******************************************************************************/ + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ + gboolean + mm_base_modem_sync_finish (MMBaseModem *self, + GAsyncResult *res, +@@ -543,6 +545,8 @@ mm_base_modem_sync (MMBaseModem *self, + task); + } + ++#endif /* WITH_SYSTEMD_SUSPEND_RESUME */ ++ + /******************************************************************************/ + + gboolean +diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h +index 75fd99f5..d9538251 100644 +--- a/src/mm-base-modem.h ++++ b/src/mm-base-modem.h +@@ -102,6 +102,7 @@ struct _MMBaseModemClass { + GAsyncResult *res, + GError **error); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME + /* Modem synchronization. + * When resuming in quick suspend/resume mode, + * this method triggers a synchronization of all modem interfaces */ +@@ -111,6 +112,7 @@ struct _MMBaseModemClass { + gboolean (* sync_finish) (MMBaseModem *self, + GAsyncResult *res, + GError **error); ++#endif + + /* signals */ + void (* link_port_grabbed) (MMBaseModem *self, +@@ -215,6 +217,8 @@ gboolean mm_base_modem_disable_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ + void mm_base_modem_sync (MMBaseModem *self, + GAsyncReadyCallback callback, + gpointer user_data); +@@ -222,6 +226,8 @@ gboolean mm_base_modem_sync_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error); + ++#endif ++ + void mm_base_modem_process_sim_event (MMBaseModem *self); + + #endif /* MM_BASE_MODEM_H */ +-- +2.31.1 + diff --git a/temp/modemmanager/0008-broadband-modem-ignore-cancellation-during-sync.patch b/temp/modemmanager/0008-broadband-modem-ignore-cancellation-during-sync.patch new file mode 100644 index 000000000..b70004264 --- /dev/null +++ b/temp/modemmanager/0008-broadband-modem-ignore-cancellation-during-sync.patch @@ -0,0 +1,31 @@ +From d5ccd5fa9d1b6b5a0367bee7da347efd460f12ca Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:28:02 +0200 +Subject: [PATCH 08/39] broadband-modem: ignore cancellation during sync() + +There is no input cancellable in the method, so the GTask will never +get cancelled from the outside. +--- + src/mm-broadband-modem.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 6e47757e..7d928aa8 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11364,12 +11364,6 @@ syncing_step (GTask *task) + MMBroadbandModem *self; + SyncingContext *ctx; + +- /* Don't run new steps if we're cancelled */ +- if (g_task_return_error_if_cancelled (task)) { +- g_object_unref (task); +- return; +- } +- + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + +-- +2.31.1 + diff --git a/temp/modemmanager/0009-broadband-modem-skip-synchronization-after-resume-if.patch b/temp/modemmanager/0009-broadband-modem-skip-synchronization-after-resume-if.patch new file mode 100644 index 000000000..577bb4522 --- /dev/null +++ b/temp/modemmanager/0009-broadband-modem-skip-synchronization-after-resume-if.patch @@ -0,0 +1,53 @@ +From d59ca53e142dcbbc6afa3d1ace97ac367f96986f Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 12:35:07 +0200 +Subject: [PATCH 09/39] broadband-modem: skip synchronization after resume if + not needed + +The synchronization after resume should only be needed on enabled +modems, as otherwise there is really no chance that the state of the +modem may have changed during suspend. + +E.g. if a modem is failed because it doesn't have a SIM card, or if +the SIM-PIN is locked, or if the modem has never been enabled, there +is no point in attempting to synchronize the runtime state of the +modem. +--- + src/mm-broadband-modem.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 7d928aa8..db6eb8ce 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11396,13 +11396,24 @@ synchronize (MMBaseModem *self, + SyncingContext *ctx; + GTask *task; + ++ task = g_task_new (MM_BROADBAND_MODEM (self), NULL, callback, user_data); ++ ++ /* Synchronization after resume is not needed on modems that have never ++ * been enabled. ++ */ ++ if (MM_BROADBAND_MODEM (self)->priv->modem_state < MM_MODEM_STATE_ENABLED) { ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, ++ "Synchronization after resume not needed in modem state '%s'", ++ mm_modem_state_get_string (MM_BROADBAND_MODEM (self)->priv->modem_state)); ++ g_object_unref (task); ++ return; ++ } ++ + /* Create SyncingContext */ + ctx = g_new0 (SyncingContext, 1); + ctx->step = SYNCING_STEP_FIRST; +- +- /* Create sync steps task and execute it */ +- task = g_task_new (MM_BROADBAND_MODEM (self), NULL, callback, user_data); + g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); ++ + syncing_step (task); + } + +-- +2.31.1 + diff --git a/temp/modemmanager/0010-iface-modem-time-synchronize-state-when-resuming.patch b/temp/modemmanager/0010-iface-modem-time-synchronize-state-when-resuming.patch new file mode 100644 index 000000000..530c8b70a --- /dev/null +++ b/temp/modemmanager/0010-iface-modem-time-synchronize-state-when-resuming.patch @@ -0,0 +1,196 @@ +From 5b3585829a4752a4b53e725a22858aa759fac472 Mon Sep 17 00:00:00 2001 +From: Dylan Van Assche +Date: Sat, 1 May 2021 15:53:55 +0200 +Subject: [PATCH 10/39] iface-modem-time: synchronize state when resuming + +On resume, fetch the current network time as +the network time may be changed when suspended. +--- + src/mm-broadband-modem.c | 30 ++++++++++++++ + src/mm-iface-modem-time.c | 84 +++++++++++++++++++++++++++++++++++++++ + src/mm-iface-modem-time.h | 12 ++++++ + 3 files changed, 126 insertions(+) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index db6eb8ce..0e4f4740 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11343,6 +11343,7 @@ enable (MMBaseModem *self, + + typedef enum { + SYNCING_STEP_FIRST, ++ SYNCING_STEP_IFACE_TIME, + SYNCING_STEP_LAST, + } SyncingStep; + +@@ -11350,6 +11351,8 @@ typedef struct { + SyncingStep step; + } SyncingContext; + ++static void syncing_step (GTask *task); ++ + static gboolean + synchronize_finish (MMBaseModem *self, + GAsyncResult *res, +@@ -11358,6 +11361,24 @@ synchronize_finish (MMBaseModem *self, + return g_task_propagate_boolean (G_TASK (res), error); + } + ++static void ++iface_modem_time_sync_ready (MMIfaceModemTime *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ g_autoptr(GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ ++ if (!mm_iface_modem_time_sync_finish (self, res, &error)) ++ mm_obj_warn (self, "time interface synchronization failed: %s", error->message); ++ ++ /* Go on to next step */ ++ ctx->step++; ++ syncing_step (task); ++} ++ + static void + syncing_step (GTask *task) + { +@@ -11372,6 +11393,15 @@ syncing_step (GTask *task) + ctx->step++; + /* fall through */ + ++ case SYNCING_STEP_IFACE_TIME: ++ /* ++ * Synchronize asynchronously the Time interface. ++ */ ++ mm_obj_info (self, "resume synchronization state (%d/%d): time interface sync", ++ ctx->step, SYNCING_STEP_LAST); ++ mm_iface_modem_time_sync (MM_IFACE_MODEM_TIME (self), (GAsyncReadyCallback)iface_modem_time_sync_ready, task); ++ return; ++ + case SYNCING_STEP_LAST: + mm_obj_info (self, "resume synchronization state (%d/%d): all done", + ctx->step, SYNCING_STEP_LAST); +diff --git a/src/mm-iface-modem-time.c b/src/mm-iface-modem-time.c +index 5770e7b7..e262b71d 100644 +--- a/src/mm-iface-modem-time.c ++++ b/src/mm-iface-modem-time.c +@@ -728,6 +728,90 @@ mm_iface_modem_time_enable (MMIfaceModemTime *self, + + /*****************************************************************************/ + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++typedef struct _SyncingContext SyncingContext; ++static void interface_syncing_step (GTask *task); ++ ++typedef enum { ++ SYNCING_STEP_FIRST, ++ SYNCING_STEP_REFRESH_NETWORK_TIMEZONE, ++ SYNCING_STEP_LAST ++} SyncingStep; ++ ++struct _SyncingContext { ++ SyncingStep step; ++}; ++ ++gboolean ++mm_iface_modem_time_sync_finish (MMIfaceModemTime *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void ++interface_syncing_step (GTask *task) ++{ ++ MMIfaceModemTime *self; ++ SyncingContext *ctx; ++ ++ /* Don't run new steps if we're cancelled */ ++ if (g_task_return_error_if_cancelled (task)) { ++ g_object_unref (task); ++ return; ++ } ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ switch (ctx->step) { ++ case SYNCING_STEP_FIRST: ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_REFRESH_NETWORK_TIMEZONE: ++ /* We start it and schedule it to run asynchronously */ ++ start_network_timezone (self); ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_LAST: ++ /* We are done without errors! */ ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); ++ return; ++ ++ default: ++ break; ++ } ++ ++ g_assert_not_reached (); ++} ++ ++void ++mm_iface_modem_time_sync (MMIfaceModemTime *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ SyncingContext *ctx; ++ GTask *task; ++ ++ /* Create SyncingContext */ ++ ctx = g_new0 (SyncingContext, 1); ++ ctx->step = SYNCING_STEP_FIRST; ++ ++ /* Create sync steps task and execute it */ ++ task = g_task_new (self, NULL, callback, user_data); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); ++ interface_syncing_step (task); ++} ++ ++#endif ++ ++/*****************************************************************************/ ++ + typedef struct _InitializationContext InitializationContext; + static void interface_initialization_step (GTask *task); + +diff --git a/src/mm-iface-modem-time.h b/src/mm-iface-modem-time.h +index ca0640d6..a3ac7074 100644 +--- a/src/mm-iface-modem-time.h ++++ b/src/mm-iface-modem-time.h +@@ -125,6 +125,18 @@ gboolean mm_iface_modem_time_disable_finish (MMIfaceModemTime *self, + /* Shutdown Time interface */ + void mm_iface_modem_time_shutdown (MMIfaceModemTime *self); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++/* Sync Time interface (async) */ ++void mm_iface_modem_time_sync (MMIfaceModemTime *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean mm_iface_modem_time_sync_finish (MMIfaceModemTime *self, ++ GAsyncResult *res, ++ GError **error); ++ ++#endif ++ + /* Bind properties for simple GetStatus() */ + void mm_iface_modem_time_bind_simple_status (MMIfaceModemTime *self, + MMSimpleStatus *status); +-- +2.31.1 + diff --git a/temp/modemmanager/0011-broadband-modem-skip-time-interface-sync-if-no-time-.patch b/temp/modemmanager/0011-broadband-modem-skip-time-interface-sync-if-no-time-.patch new file mode 100644 index 000000000..eb19473dd --- /dev/null +++ b/temp/modemmanager/0011-broadband-modem-skip-time-interface-sync-if-no-time-.patch @@ -0,0 +1,36 @@ +From 3ab85a1487e67ce8faf833bafc4c5dad430af396 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:31:13 +0200 +Subject: [PATCH 11/39] broadband-modem: skip time interface sync if no time + support + +--- + src/mm-broadband-modem.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 0e4f4740..91e023b8 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11397,10 +11397,14 @@ syncing_step (GTask *task) + /* + * Synchronize asynchronously the Time interface. + */ +- mm_obj_info (self, "resume synchronization state (%d/%d): time interface sync", +- ctx->step, SYNCING_STEP_LAST); +- mm_iface_modem_time_sync (MM_IFACE_MODEM_TIME (self), (GAsyncReadyCallback)iface_modem_time_sync_ready, task); +- return; ++ if (self->priv->modem_time_dbus_skeleton) { ++ mm_obj_info (self, "resume synchronization state (%d/%d): time interface sync", ++ ctx->step, SYNCING_STEP_LAST); ++ mm_iface_modem_time_sync (MM_IFACE_MODEM_TIME (self), (GAsyncReadyCallback)iface_modem_time_sync_ready, task); ++ return; ++ } ++ ctx->step++; ++ /* fall through */ + + case SYNCING_STEP_LAST: + mm_obj_info (self, "resume synchronization state (%d/%d): all done", +-- +2.31.1 + diff --git a/temp/modemmanager/0012-iface-modem-time-ignore-cancellation-during-sync.patch b/temp/modemmanager/0012-iface-modem-time-ignore-cancellation-during-sync.patch new file mode 100644 index 000000000..79f9f6e39 --- /dev/null +++ b/temp/modemmanager/0012-iface-modem-time-ignore-cancellation-during-sync.patch @@ -0,0 +1,31 @@ +From 35872aad3036c9c98cd3b1b6201c8057ac74ffc3 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 15:44:45 +0200 +Subject: [PATCH 12/39] iface-modem-time: ignore cancellation during sync() + +There is no input cancellable in the method, so the GTask will never +get cancelled from the outside. +--- + src/mm-iface-modem-time.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/mm-iface-modem-time.c b/src/mm-iface-modem-time.c +index e262b71d..0d4f3764 100644 +--- a/src/mm-iface-modem-time.c ++++ b/src/mm-iface-modem-time.c +@@ -757,12 +757,6 @@ interface_syncing_step (GTask *task) + MMIfaceModemTime *self; + SyncingContext *ctx; + +- /* Don't run new steps if we're cancelled */ +- if (g_task_return_error_if_cancelled (task)) { +- g_object_unref (task); +- return; +- } +- + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + +-- +2.31.1 + diff --git a/temp/modemmanager/0013-iface-modem-3gpp-synchronize-state-when-resuming.patch b/temp/modemmanager/0013-iface-modem-3gpp-synchronize-state-when-resuming.patch new file mode 100644 index 000000000..de053138b --- /dev/null +++ b/temp/modemmanager/0013-iface-modem-3gpp-synchronize-state-when-resuming.patch @@ -0,0 +1,283 @@ +From f5acb7ce85fec0c6cf1d284c125008b961f7a56e Mon Sep 17 00:00:00 2001 +From: Dylan Van Assche +Date: Sat, 13 Mar 2021 19:28:19 +0100 +Subject: [PATCH 13/39] iface-modem-3gpp: synchronize state when resuming + +On resume, refresh the EPS bearers and 3GPP registration +as the registration and bearers may expired during suspend. +--- + src/mm-broadband-modem.c | 31 +++++++ + src/mm-iface-modem-3gpp.c | 177 ++++++++++++++++++++++++++++++++++++++ + src/mm-iface-modem-3gpp.h | 12 +++ + 3 files changed, 220 insertions(+) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 91e023b8..05d72875 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11343,6 +11343,7 @@ enable (MMBaseModem *self, + + typedef enum { + SYNCING_STEP_FIRST, ++ SYNCING_STEP_IFACE_3GPP, + SYNCING_STEP_IFACE_TIME, + SYNCING_STEP_LAST, + } SyncingStep; +@@ -11379,6 +11380,24 @@ iface_modem_time_sync_ready (MMIfaceModemTime *self, + syncing_step (task); + } + ++static void ++iface_modem_3gpp_sync_ready (MMBroadbandModem *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ g_autoptr(GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ ++ if (!mm_iface_modem_3gpp_sync_finish (MM_IFACE_MODEM_3GPP (self), res, &error)) ++ mm_obj_warn (self, "3GPP interface synchronization failed: %s", error->message); ++ ++ /* Go on to next step */ ++ ctx->step++; ++ syncing_step (task); ++} ++ + static void + syncing_step (GTask *task) + { +@@ -11393,6 +11412,18 @@ syncing_step (GTask *task) + ctx->step++; + /* fall through */ + ++ case SYNCING_STEP_IFACE_3GPP: ++ /* ++ * Start interface 3GPP synchronization. ++ * We hardly depend on the registration and bearer status, ++ * therefore we cannot continue with the other steps until ++ * this one is finished. ++ */ ++ mm_obj_info (self, "resume synchronization state (%d/%d): 3GPP interface sync", ++ ctx->step, SYNCING_STEP_LAST); ++ mm_iface_modem_3gpp_sync (MM_IFACE_MODEM_3GPP (self), (GAsyncReadyCallback)iface_modem_3gpp_sync_ready, task); ++ return; ++ + case SYNCING_STEP_IFACE_TIME: + /* + * Synchronize asynchronously the Time interface. +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index 93899355..c435da87 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -2341,6 +2341,183 @@ mm_iface_modem_3gpp_enable (MMIfaceModem3gpp *self, + + /*****************************************************************************/ + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++typedef struct _SyncingContext SyncingContext; ++static void interface_syncing_step (GTask *task); ++ ++typedef enum { ++ SYNCING_STEP_FIRST, ++ SYNCING_STEP_REFRESH_3GPP_REGISTRATION, ++ SYNCING_STEP_REFRESH_EPS_BEARER, ++ SYNCING_STEP_LAST ++} SyncingStep; ++ ++struct _SyncingContext { ++ SyncingStep step; ++}; ++ ++gboolean ++mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void ++sync_eps_bearer_ready (MMIfaceModem3gpp *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ MMBearerProperties *properties; ++ SyncingContext *ctx; ++ g_autoptr (GError) error = NULL; ++ ++ mm_obj_dbg (self, "EPS bearer sync ready"); ++ ctx = g_task_get_task_data (task); ++ ++ properties = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish (self, res, &error); ++ if (!properties) { ++ mm_obj_dbg (self, "couldn't refresh EPS bearer properties: %s", error->message); ++ } else { ++ mm_iface_modem_3gpp_update_initial_eps_bearer (self, properties); ++ g_object_unref (properties); ++ } ++ ++ /* Go on to next step */ ++ ctx->step++; ++ interface_syncing_step (task); ++} ++ ++static void ++sync_eps_bearer (MMIfaceModem3gpp *self, ++ GAsyncReadyCallback callback, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ gboolean eps_supported = FALSE; ++ ++ g_object_get (self, ++ MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, &eps_supported, ++ NULL); ++ ++ /* Refresh EPS bearer if supported */ ++ if (eps_supported && ++ MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer && ++ MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish) { ++ MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer ( ++ self, ++ callback, ++ task); ++ return; ++ } ++ ++ /* If EPS is unsupported, just go to the next step */ ++ ctx = g_task_get_task_data (task); ++ ctx->step++; ++ interface_syncing_step (task); ++} ++ ++static void ++sync_registration_ready (MMIfaceModem3gpp *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ g_autoptr (GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ ++ mm_iface_modem_3gpp_run_registration_checks_finish (self, res, &error); ++ if (error) { ++ mm_obj_dbg (self, "Synchronizing 3GPP registration failed: %s", error->message); ++ g_error_free (error); ++ } ++ ++ /* Go on to next step */ ++ ctx->step++; ++ interface_syncing_step(task); ++} ++ ++static void ++interface_syncing_step (GTask *task) ++{ ++ MMIfaceModem3gpp *self; ++ SyncingContext *ctx; ++ ++ /* Don't run new steps if we're cancelled */ ++ if (g_task_return_error_if_cancelled (task)) { ++ g_object_unref (task); ++ return; ++ } ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ switch (ctx->step) { ++ case SYNCING_STEP_FIRST: ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_REFRESH_3GPP_REGISTRATION: ++ /* ++ * Refresh registration info to verify that the modem is still registered. ++ * Wait until registration checks are complete before going to the next step. ++ */ ++ mm_iface_modem_3gpp_run_registration_checks ( ++ self, ++ (GAsyncReadyCallback)sync_registration_ready, ++ task); ++ return; ++ ++ case SYNCING_STEP_REFRESH_EPS_BEARER: ++ /* ++ * Refresh EPS bearer and wait until complete. ++ * We want to make sure that the modem is fully enabled again ++ * when we refresh the mobile data connection bearers. ++ */ ++ sync_eps_bearer ( ++ self, ++ (GAsyncReadyCallback)sync_eps_bearer_ready, ++ task); ++ return; ++ ++ case SYNCING_STEP_LAST: ++ /* We are done without errors! */ ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); ++ return; ++ ++ default: ++ break; ++ } ++ ++ g_assert_not_reached (); ++} ++ ++void ++mm_iface_modem_3gpp_sync (MMIfaceModem3gpp *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ SyncingContext *ctx; ++ GTask *task; ++ ++ /* Create SyncingContext */ ++ ctx = g_new0 (SyncingContext, 1); ++ ctx->step = SYNCING_STEP_FIRST; ++ ++ /* Create sync steps task and execute it */ ++ task = g_task_new (self, NULL, callback, user_data); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); ++ interface_syncing_step (task); ++} ++ ++#endif ++ ++/*****************************************************************************/ ++ + typedef struct _InitializationContext InitializationContext; + static void interface_initialization_step (GTask *task); + +diff --git a/src/mm-iface-modem-3gpp.h b/src/mm-iface-modem-3gpp.h +index 258e5c10..027bef0f 100644 +--- a/src/mm-iface-modem-3gpp.h ++++ b/src/mm-iface-modem-3gpp.h +@@ -265,6 +265,18 @@ gboolean mm_iface_modem_3gpp_disable_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++/* Sync 3GPP interface (async) */ ++void mm_iface_modem_3gpp_sync (MMIfaceModem3gpp *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self, ++ GAsyncResult *res, ++ GError **error); ++ ++#endif ++ + /* Shutdown Modem 3GPP interface */ + void mm_iface_modem_3gpp_shutdown (MMIfaceModem3gpp *self); + +-- +2.31.1 + diff --git a/temp/modemmanager/0014-iface-modem-3gpp-use-g_autoptr-for-the-MMBearerPrope.patch b/temp/modemmanager/0014-iface-modem-3gpp-use-g_autoptr-for-the-MMBearerPrope.patch new file mode 100644 index 000000000..10884ca69 --- /dev/null +++ b/temp/modemmanager/0014-iface-modem-3gpp-use-g_autoptr-for-the-MMBearerPrope.patch @@ -0,0 +1,44 @@ +From fa6b6f69d4a2646e6695722372d9aa6b3d327151 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:14:27 +0200 +Subject: [PATCH 14/39] iface-modem-3gpp: use g_autoptr() for the + MMBearerProperties during sync + +--- + src/mm-iface-modem-3gpp.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index c435da87..c6db5e4f 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -2370,20 +2370,18 @@ sync_eps_bearer_ready (MMIfaceModem3gpp *self, + GAsyncResult *res, + GTask *task) + { +- MMBearerProperties *properties; +- SyncingContext *ctx; +- g_autoptr (GError) error = NULL; ++ SyncingContext *ctx; ++ g_autoptr(MMBearerProperties) properties = NULL; ++ g_autoptr(GError) error = NULL; + + mm_obj_dbg (self, "EPS bearer sync ready"); + ctx = g_task_get_task_data (task); + + properties = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish (self, res, &error); +- if (!properties) { +- mm_obj_dbg (self, "couldn't refresh EPS bearer properties: %s", error->message); +- } else { ++ if (!properties) ++ mm_obj_dbg (self, "couldn't refresh initial EPS bearer status: %s", error->message); ++ else + mm_iface_modem_3gpp_update_initial_eps_bearer (self, properties); +- g_object_unref (properties); +- } + + /* Go on to next step */ + ctx->step++; +-- +2.31.1 + diff --git a/temp/modemmanager/0015-iface-modem-3gpp-fix-double-GError-free-on-registrat.patch b/temp/modemmanager/0015-iface-modem-3gpp-fix-double-GError-free-on-registrat.patch new file mode 100644 index 000000000..f46ab65b9 --- /dev/null +++ b/temp/modemmanager/0015-iface-modem-3gpp-fix-double-GError-free-on-registrat.patch @@ -0,0 +1,31 @@ +From 4edb8e6c04347a0224d782f27ada1ad8d984fc91 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:15:30 +0200 +Subject: [PATCH 15/39] iface-modem-3gpp: fix double GError free on + registration sync failure + +--- + src/mm-iface-modem-3gpp.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index c6db5e4f..f0e9fe31 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -2427,11 +2427,8 @@ sync_registration_ready (MMIfaceModem3gpp *self, + + ctx = g_task_get_task_data (task); + +- mm_iface_modem_3gpp_run_registration_checks_finish (self, res, &error); +- if (error) { +- mm_obj_dbg (self, "Synchronizing 3GPP registration failed: %s", error->message); +- g_error_free (error); +- } ++ if (!mm_iface_modem_3gpp_run_registration_checks_finish (self, res, &error)) ++ mm_obj_dbg (self, "couldn't synchronize 3GPP registration: %s", error->message); + + /* Go on to next step */ + ctx->step++; +-- +2.31.1 + diff --git a/temp/modemmanager/0016-iface-modem-3gpp-remove-redundant-log-message.patch b/temp/modemmanager/0016-iface-modem-3gpp-remove-redundant-log-message.patch new file mode 100644 index 000000000..9cb236607 --- /dev/null +++ b/temp/modemmanager/0016-iface-modem-3gpp-remove-redundant-log-message.patch @@ -0,0 +1,25 @@ +From 346ca78aa710c0081af08838d5f31fc5a76065c2 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:17:57 +0200 +Subject: [PATCH 16/39] iface-modem-3gpp: remove redundant log message + +It doesn't give us any valuable information, so just remove it. +--- + src/mm-iface-modem-3gpp.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index f0e9fe31..cc39fa08 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -2374,7 +2374,6 @@ sync_eps_bearer_ready (MMIfaceModem3gpp *self, + g_autoptr(MMBearerProperties) properties = NULL; + g_autoptr(GError) error = NULL; + +- mm_obj_dbg (self, "EPS bearer sync ready"); + ctx = g_task_get_task_data (task); + + properties = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish (self, res, &error); +-- +2.31.1 + diff --git a/temp/modemmanager/0017-iface-modem-3gpp-ignore-cancellation-during-sync.patch b/temp/modemmanager/0017-iface-modem-3gpp-ignore-cancellation-during-sync.patch new file mode 100644 index 000000000..47737a83c --- /dev/null +++ b/temp/modemmanager/0017-iface-modem-3gpp-ignore-cancellation-during-sync.patch @@ -0,0 +1,31 @@ +From 290de72a45dd44ae376299d239390ff477c93982 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 15:44:22 +0200 +Subject: [PATCH 17/39] iface-modem-3gpp: ignore cancellation during sync() + +There is no input cancellable in the method, so the GTask will never +get cancelled from the outside. +--- + src/mm-iface-modem-3gpp.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index cc39fa08..660eec65 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -2440,12 +2440,6 @@ interface_syncing_step (GTask *task) + MMIfaceModem3gpp *self; + SyncingContext *ctx; + +- /* Don't run new steps if we're cancelled */ +- if (g_task_return_error_if_cancelled (task)) { +- g_object_unref (task); +- return; +- } +- + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + +-- +2.31.1 + diff --git a/temp/modemmanager/0018-broadband-modem-fix-type-in-the-ready-for-iface_mode.patch b/temp/modemmanager/0018-broadband-modem-fix-type-in-the-ready-for-iface_mode.patch new file mode 100644 index 000000000..4ab357634 --- /dev/null +++ b/temp/modemmanager/0018-broadband-modem-fix-type-in-the-ready-for-iface_mode.patch @@ -0,0 +1,38 @@ +From beaefd7ce80732a90597561eb28d103c4249d471 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:26:12 +0200 +Subject: [PATCH 18/39] broadband-modem: fix type in the ready() for + iface_modem_3gpp_sync() + +When calling an async method ona given type, the convention is to use +the same type in the corresponding ready() method, so that we can use +it without additional casts on the finish(). +--- + src/mm-broadband-modem.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 05d72875..908795cf 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11381,7 +11381,7 @@ iface_modem_time_sync_ready (MMIfaceModemTime *self, + } + + static void +-iface_modem_3gpp_sync_ready (MMBroadbandModem *self, ++iface_modem_3gpp_sync_ready (MMIfaceModem3gpp *self, + GAsyncResult *res, + GTask *task) + { +@@ -11390,7 +11390,7 @@ iface_modem_3gpp_sync_ready (MMBroadbandModem *self, + + ctx = g_task_get_task_data (task); + +- if (!mm_iface_modem_3gpp_sync_finish (MM_IFACE_MODEM_3GPP (self), res, &error)) ++ if (!mm_iface_modem_3gpp_sync_finish (self, res, &error)) + mm_obj_warn (self, "3GPP interface synchronization failed: %s", error->message); + + /* Go on to next step */ +-- +2.31.1 + diff --git a/temp/modemmanager/0019-broadband-modem-skip-3GPP-interface-sync-if-no-3GPP-.patch b/temp/modemmanager/0019-broadband-modem-skip-3GPP-interface-sync-if-no-3GPP-.patch new file mode 100644 index 000000000..0427ca082 --- /dev/null +++ b/temp/modemmanager/0019-broadband-modem-skip-3GPP-interface-sync-if-no-3GPP-.patch @@ -0,0 +1,36 @@ +From 1bfbb4a27fe5d88332dd1394c6b3aae4527661f6 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:32:20 +0200 +Subject: [PATCH 19/39] broadband-modem: skip 3GPP interface sync if no 3GPP + support + +--- + src/mm-broadband-modem.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 908795cf..05a86af3 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11419,10 +11419,14 @@ syncing_step (GTask *task) + * therefore we cannot continue with the other steps until + * this one is finished. + */ +- mm_obj_info (self, "resume synchronization state (%d/%d): 3GPP interface sync", +- ctx->step, SYNCING_STEP_LAST); +- mm_iface_modem_3gpp_sync (MM_IFACE_MODEM_3GPP (self), (GAsyncReadyCallback)iface_modem_3gpp_sync_ready, task); +- return; ++ if (self->priv->modem_3gpp_dbus_skeleton) { ++ mm_obj_info (self, "resume synchronization state (%d/%d): 3GPP interface sync", ++ ctx->step, SYNCING_STEP_LAST); ++ mm_iface_modem_3gpp_sync (MM_IFACE_MODEM_3GPP (self), (GAsyncReadyCallback)iface_modem_3gpp_sync_ready, task); ++ return; ++ } ++ ctx->step++; ++ /* fall through */ + + case SYNCING_STEP_IFACE_TIME: + /* +-- +2.31.1 + diff --git a/temp/modemmanager/0020-iface-modem-synchronize-state-when-resuming.patch b/temp/modemmanager/0020-iface-modem-synchronize-state-when-resuming.patch new file mode 100644 index 000000000..12bc3f875 --- /dev/null +++ b/temp/modemmanager/0020-iface-modem-synchronize-state-when-resuming.patch @@ -0,0 +1,371 @@ +From 97cbdf4eb409afa4a7eca6d8dbadc65c39a008b1 Mon Sep 17 00:00:00 2001 +From: Dylan Van Assche +Date: Sun, 14 Mar 2021 09:53:49 +0100 +Subject: [PATCH 20/39] iface-modem: synchronize state when resuming + +Refresh signal strength and access technologies, +check for SIM swaps, and check if the SIM is locked. +The modem may have switched to a different +access technologies or have a different signal strength +when resuming. Moreover, the user may swap or remove +the SIM when suspended. +--- + src/mm-broadband-modem.c | 44 ++++++++++ + src/mm-iface-modem-3gpp.c | 2 +- + src/mm-iface-modem.c | 177 ++++++++++++++++++++++++++++++++++++-- + src/mm-iface-modem.h | 23 ++++- + 4 files changed, 238 insertions(+), 8 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 05a86af3..b99a38a6 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11343,6 +11343,7 @@ enable (MMBaseModem *self, + + typedef enum { + SYNCING_STEP_FIRST, ++ SYNCING_STEP_IFACE_MODEM, + SYNCING_STEP_IFACE_3GPP, + SYNCING_STEP_IFACE_TIME, + SYNCING_STEP_LAST, +@@ -11398,6 +11399,36 @@ iface_modem_3gpp_sync_ready (MMIfaceModem3gpp *self, + syncing_step (task); + } + ++static void ++iface_modem_sync_ready (MMIfaceModem *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ MMModemLock lock; ++ g_autoptr (GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ lock = mm_iface_modem_get_unlock_required (self); ++ ++ if (!mm_iface_modem_sync_finish (self, res, &error)) { ++ mm_obj_warn (self, "synchronizing Modem interface failed: %s", error->message); ++ } ++ ++ /* SIM is locked, skip synchronization */ ++ if (lock == MM_MODEM_LOCK_UNKNOWN || lock == MM_MODEM_LOCK_SIM_PIN || lock == MM_MODEM_LOCK_SIM_PUK) { ++ mm_obj_warn (self, "SIM is locked... Synchronization skipped"); ++ ctx->step = SYNCING_STEP_LAST; ++ syncing_step (task); ++ } ++ ++ /* Not locked, go on to next step */ ++ mm_obj_dbg (self, "modem unlocked, continue synchronization"); ++ ctx->step++; ++ syncing_step (task); ++ return; ++} ++ + static void + syncing_step (GTask *task) + { +@@ -11412,6 +11443,19 @@ syncing_step (GTask *task) + ctx->step++; + /* fall through */ + ++ case SYNCING_STEP_IFACE_MODEM: ++ /* ++ * Start interface Modem synchronization. ++ * We want to make sure that the SIM is unlocked and not swapped before ++ * synchronizing other interfaces. ++ */ ++ mm_obj_info (self, "resume synchronization state (%d/%d): Modem interface sync", ++ ctx->step, SYNCING_STEP_LAST); ++ mm_iface_modem_sync (MM_IFACE_MODEM (self), ++ (GAsyncReadyCallback)iface_modem_sync_ready, ++ task); ++ return; ++ + case SYNCING_STEP_IFACE_3GPP: + /* + * Start interface 3GPP synchronization. +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index 660eec65..ea1ab7cb 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -314,7 +314,7 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, + * from home to roaming or viceversa, both registered states, so there + * wouldn't be an explicit refresh triggered from the modem interface as + * the modem never got un-registered during the sequence. */ +- mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self)); ++ mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self), FALSE); + mm_obj_dbg (self, "currently registered in a 3GPP network"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c +index 7a84a6d2..f208e92a 100644 +--- a/src/mm-iface-modem.c ++++ b/src/mm-iface-modem.c +@@ -1587,12 +1587,28 @@ periodic_signal_check_cb (MMIfaceModem *self) + } + + void +-mm_iface_modem_refresh_signal (MMIfaceModem *self) ++mm_iface_modem_refresh_signal (MMIfaceModem *self, ++ gboolean enforce) + { + SignalCheckContext *ctx; + +- /* Don't refresh polling if we're not enabled */ + ctx = get_signal_check_context (self); ++ ++ /* ++ * If enforced, poll once explicitly to make sure the signal strength ++ * and access technologies are updated. ++ * ++ * Modems with signal indication support block periodic polling scheduling. ++ * With enforce == TRUE, the periodic polling logic can run once as ++ * it override once the periodic polling prohibition. ++ * When the polling is complete, the periodic polling scheduling ++ * is blocked again to avoid that modems with signal indication support ++ * are periodic polled for their signal status. ++ */ ++ if (enforce) ++ ctx->enabled = TRUE; ++ ++ /* Don't refresh polling if we're not enabled */ + if (!ctx->enabled) { + mm_obj_dbg (self, "periodic signal check refresh ignored: checks not enabled"); + return; +@@ -1671,7 +1687,7 @@ periodic_signal_check_enable (MMIfaceModem *self) + } + + /* And refresh, which will trigger the first check at high frequency */ +- mm_iface_modem_refresh_signal (self); ++ mm_iface_modem_refresh_signal (self, FALSE); + } + + /*****************************************************************************/ +@@ -2345,7 +2361,7 @@ set_current_capabilities_ready (MMIfaceModem *self, + g_dbus_method_invocation_take_error (ctx->invocation, error); + else { + /* Capabilities updated: explicitly refresh signal and access technology */ +- mm_iface_modem_refresh_signal (self); ++ mm_iface_modem_refresh_signal (self, FALSE); + mm_gdbus_modem_complete_set_current_capabilities (ctx->skeleton, ctx->invocation); + } + +@@ -2835,7 +2851,7 @@ handle_set_current_bands_ready (MMIfaceModem *self, + g_dbus_method_invocation_take_error (ctx->invocation, error); + else { + /* Bands updated: explicitly refresh signal and access technology */ +- mm_iface_modem_refresh_signal (self); ++ mm_iface_modem_refresh_signal (self, FALSE); + mm_gdbus_modem_complete_set_current_bands (ctx->skeleton, ctx->invocation); + } + +@@ -3222,7 +3238,7 @@ handle_set_current_modes_ready (MMIfaceModem *self, + g_dbus_method_invocation_take_error (ctx->invocation, error); + else { + /* Modes updated: explicitly refresh signal and access technology */ +- mm_iface_modem_refresh_signal (self); ++ mm_iface_modem_refresh_signal (self, FALSE); + mm_gdbus_modem_complete_set_current_modes (ctx->skeleton, ctx->invocation); + } + +@@ -4206,6 +4222,155 @@ mm_iface_modem_enable (MMIfaceModem *self, + interface_enabling_step (task); + } + ++/*****************************************************************************/ ++/* MODEM SYNCHRONIZATION */ ++ ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++typedef struct _SyncingContext SyncingContext; ++static void interface_syncing_step (GTask *task); ++ ++typedef enum { ++ SYNCING_STEP_FIRST, ++ SYNCING_STEP_DETECT_SIM_SWAP, ++ SYNCING_STEP_REFRESH_SIM_LOCK, ++ SYNCING_STEP_REFRESH_SIGNAL_STRENGTH, ++ SYNCING_STEP_LAST ++} SyncingStep; ++ ++struct _SyncingContext { ++ SyncingStep step; ++}; ++ ++gboolean ++mm_iface_modem_sync_finish (MMIfaceModem *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void ++sync_sim_lock_ready (MMIfaceModem *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ g_autoptr (GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ ++ if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error)) ++ mm_obj_warn (self, "checking sim lock status failed: %s", error->message); ++ ++ /* Go on to next step */ ++ ctx->step++; ++ interface_syncing_step (task); ++} ++ ++static void ++sync_detect_sim_swap_ready (MMIfaceModem *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ g_autoptr (GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ ++ if (!mm_iface_modem_check_for_sim_swap_finish (self, res, &error)) ++ mm_obj_warn (self, "checking sim swap failed: %s", error->message); ++ ++ /* Go on to next step */ ++ ctx->step++; ++ interface_syncing_step (task); ++} ++ ++static void ++interface_syncing_step (GTask *task) ++{ ++ MMIfaceModem *self; ++ SyncingContext *ctx; ++ ++ /* Don't run new steps if we're cancelled */ ++ if (g_task_return_error_if_cancelled (task)) { ++ g_object_unref (task); ++ return; ++ } ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ switch (ctx->step) { ++ case SYNCING_STEP_FIRST: ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_DETECT_SIM_SWAP: ++ /* ++ * Detect possible SIM swaps. ++ * Checking lock status in all cases after possible SIM swaps are detected. ++ */ ++ mm_iface_modem_check_for_sim_swap ( ++ self, ++ 0, ++ NULL, ++ (GAsyncReadyCallback)sync_detect_sim_swap_ready, ++ task); ++ return; ++ ++ case SYNCING_STEP_REFRESH_SIM_LOCK: ++ /* ++ * Refresh SIM lock status and wait until complete. ++ */ ++ MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required ( ++ self, ++ FALSE, ++ (GAsyncReadyCallback)sync_sim_lock_ready, ++ task); ++ return; ++ ++ case SYNCING_STEP_REFRESH_SIGNAL_STRENGTH: ++ /* ++ * Start a signal strength and access technologies refresh sequence. ++ */ ++ mm_iface_modem_refresh_signal (self, TRUE); ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_LAST: ++ /* We are done without errors! */ ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); ++ return; ++ ++ default: ++ break; ++ } ++ ++ g_assert_not_reached (); ++} ++ ++void ++mm_iface_modem_sync (MMIfaceModem *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ SyncingContext *ctx; ++ GTask *task; ++ ++ /* Create SyncingContext */ ++ ctx = g_new0 (SyncingContext, 1); ++ ctx->step = SYNCING_STEP_FIRST; ++ ++ /* Create sync steps task and execute it */ ++ task = g_task_new (self, NULL, callback, user_data); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); ++ interface_syncing_step (task); ++} ++ ++#endif ++ + /*****************************************************************************/ + /* MODEM INITIALIZATION */ + +diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h +index 66d43ac0..1cd4bdd1 100644 +--- a/src/mm-iface-modem.h ++++ b/src/mm-iface-modem.h +@@ -460,6 +460,27 @@ gboolean mm_iface_modem_disable_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error); + ++/* Shutdown Modem interface */ ++void mm_iface_modem_shutdown (MMIfaceModem *self); ++ ++/* Helper to return an error when the modem is in failed state and so it ++ * cannot process a given method invocation ++ */ ++gboolean mm_iface_modem_abort_invocation_if_state_not_reached (MMIfaceModem *self, ++ GDBusMethodInvocation *invocation, ++ MMModemState minimum_required); ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++/* Sync Modem interface (async) */ ++void mm_iface_modem_sync (MMIfaceModem *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean mm_iface_modem_sync_finish (MMIfaceModem *self, ++ GAsyncResult *res, ++ GError **error); ++ ++#endif ++ + /* Allow setting power state */ + void mm_iface_modem_set_power_state (MMIfaceModem *self, + MMModemPowerState power_state, +@@ -526,7 +547,7 @@ void mm_iface_modem_update_signal_quality (MMIfaceModem *self, + guint signal_quality); + + /* Allow requesting to refresh signal via polling */ +-void mm_iface_modem_refresh_signal (MMIfaceModem *self); ++void mm_iface_modem_refresh_signal (MMIfaceModem *self, gboolean enforce); + + /* Allow setting allowed modes */ + void mm_iface_modem_set_current_modes (MMIfaceModem *self, +-- +2.31.1 + diff --git a/temp/modemmanager/0021-broadband-modem-fail-synchronization-if-no-modem-exp.patch b/temp/modemmanager/0021-broadband-modem-fail-synchronization-if-no-modem-exp.patch new file mode 100644 index 000000000..9a76f5af8 --- /dev/null +++ b/temp/modemmanager/0021-broadband-modem-fail-synchronization-if-no-modem-exp.patch @@ -0,0 +1,32 @@ +From 3ecb20084844dfccad6353abf38505d3c7635fd4 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:34:35 +0200 +Subject: [PATCH 21/39] broadband-modem: fail synchronization if no modem + exported in DBus + +--- + src/mm-broadband-modem.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index b99a38a6..8c5f7acd 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11449,7 +11449,13 @@ syncing_step (GTask *task) + * We want to make sure that the SIM is unlocked and not swapped before + * synchronizing other interfaces. + */ +- mm_obj_info (self, "resume synchronization state (%d/%d): Modem interface sync", ++ if (!self->priv->modem_dbus_skeleton) { ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, ++ "Synchronization aborted: no modem exposed in DBus"); ++ g_object_unref (task); ++ return; ++ } ++ mm_obj_info (self, "resume synchronization state (%d/%d): modem interface sync", + ctx->step, SYNCING_STEP_LAST); + mm_iface_modem_sync (MM_IFACE_MODEM (self), + (GAsyncReadyCallback)iface_modem_sync_ready, +-- +2.31.1 + diff --git a/temp/modemmanager/0022-broadband-modem-fix-state-machine-logic-when-synchro.patch b/temp/modemmanager/0022-broadband-modem-fix-state-machine-logic-when-synchro.patch new file mode 100644 index 000000000..f215993ab --- /dev/null +++ b/temp/modemmanager/0022-broadband-modem-fix-state-machine-logic-when-synchro.patch @@ -0,0 +1,25 @@ +From 82327e5898d77d0583e7f28f9d004df6a19f70b1 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:44:09 +0200 +Subject: [PATCH 22/39] broadband-modem: fix state machine logic when + synchronizing modem interface + +--- + src/mm-broadband-modem.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index 8c5f7acd..ac5fbb1c 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11420,6 +11420,7 @@ iface_modem_sync_ready (MMIfaceModem *self, + mm_obj_warn (self, "SIM is locked... Synchronization skipped"); + ctx->step = SYNCING_STEP_LAST; + syncing_step (task); ++ return; + } + + /* Not locked, go on to next step */ +-- +2.31.1 + diff --git a/temp/modemmanager/0023-broadband-modem-abort-sync-if-locked-SIM-card-found.patch b/temp/modemmanager/0023-broadband-modem-abort-sync-if-locked-SIM-card-found.patch new file mode 100644 index 000000000..4b3bd0049 --- /dev/null +++ b/temp/modemmanager/0023-broadband-modem-abort-sync-if-locked-SIM-card-found.patch @@ -0,0 +1,63 @@ +From f466eda93a2a28421557ec9a7f1bf5d0aec7dd00 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 14:44:44 +0200 +Subject: [PATCH 23/39] broadband-modem: abort sync if locked SIM card found + +We made sure that the after resume synchronization was only started on +modems that had been enabled (and so unlocked). If we detect a locked +SIM card during the sync operation, it's either because the SIM card +was swapped, or because the modem was fully shutdown during the +suspension (and so the SIM requires SIM-PIN again). + +Either way, we cannot sync the state cleanly at this point, we must +trigger a full modem reprobe in order to move back the modem state to +Locked. +--- + src/mm-broadband-modem.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c +index ac5fbb1c..d9a6d6ac 100644 +--- a/src/mm-broadband-modem.c ++++ b/src/mm-broadband-modem.c +@@ -11404,22 +11404,26 @@ iface_modem_sync_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) + { +- SyncingContext *ctx; +- MMModemLock lock; +- g_autoptr (GError) error = NULL; ++ SyncingContext *ctx; ++ MMModemLock lock; ++ g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); +- lock = mm_iface_modem_get_unlock_required (self); + +- if (!mm_iface_modem_sync_finish (self, res, &error)) { +- mm_obj_warn (self, "synchronizing Modem interface failed: %s", error->message); +- } ++ if (!mm_iface_modem_sync_finish (self, res, &error)) ++ mm_obj_warn (self, "modem interface synchronization failed: %s", error->message); + +- /* SIM is locked, skip synchronization */ ++ /* The synchronization logic only runs on modems that were enabled before ++ * the suspend/resume cycle, and therefore we should not get SIM-PIN locked ++ * at this point, unless the SIM was swapped. */ ++ lock = mm_iface_modem_get_unlock_required (self); + if (lock == MM_MODEM_LOCK_UNKNOWN || lock == MM_MODEM_LOCK_SIM_PIN || lock == MM_MODEM_LOCK_SIM_PUK) { +- mm_obj_warn (self, "SIM is locked... Synchronization skipped"); +- ctx->step = SYNCING_STEP_LAST; +- syncing_step (task); ++ /* Abort the sync() operation right away, and report a new SIM event that will ++ * disable the modem and trigger a full reprobe */ ++ mm_obj_warn (self, "SIM is locked... synchronization aborted"); ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, ++ "Locked SIM found during modem interface synchronization"); ++ g_object_unref (task); + return; + } + +-- +2.31.1 + diff --git a/temp/modemmanager/0024-iface-modem-remove-the-signal-quality-enforced-refre.patch b/temp/modemmanager/0024-iface-modem-remove-the-signal-quality-enforced-refre.patch new file mode 100644 index 000000000..b42c2c00a --- /dev/null +++ b/temp/modemmanager/0024-iface-modem-remove-the-signal-quality-enforced-refre.patch @@ -0,0 +1,129 @@ +From a414efa690d880b2037a084f33e05db4c2208123 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 15:40:36 +0200 +Subject: [PATCH 24/39] iface-modem: remove the signal quality enforced refresh + during sync() + +when mm_iface_modem_refresh_signal() is called, we'll restart the +signal quality refresh logic already, there is no need to request +an enforced start. + +The enforced start was also modifying ctx->enabled unconditionally, +which is really not ok. This logic would be enabled only when we're +registered, and that logic is fine, no need to change that. +--- + src/mm-iface-modem-3gpp.c | 2 +- + src/mm-iface-modem.c | 29 +++++++---------------------- + src/mm-iface-modem.h | 2 +- + 3 files changed, 9 insertions(+), 24 deletions(-) + +diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c +index ea1ab7cb..660eec65 100644 +--- a/src/mm-iface-modem-3gpp.c ++++ b/src/mm-iface-modem-3gpp.c +@@ -314,7 +314,7 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, + * from home to roaming or viceversa, both registered states, so there + * wouldn't be an explicit refresh triggered from the modem interface as + * the modem never got un-registered during the sequence. */ +- mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self), FALSE); ++ mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self)); + mm_obj_dbg (self, "currently registered in a 3GPP network"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c +index f208e92a..85df77bd 100644 +--- a/src/mm-iface-modem.c ++++ b/src/mm-iface-modem.c +@@ -1587,27 +1587,12 @@ periodic_signal_check_cb (MMIfaceModem *self) + } + + void +-mm_iface_modem_refresh_signal (MMIfaceModem *self, +- gboolean enforce) ++mm_iface_modem_refresh_signal (MMIfaceModem *self) + { + SignalCheckContext *ctx; + + ctx = get_signal_check_context (self); + +- /* +- * If enforced, poll once explicitly to make sure the signal strength +- * and access technologies are updated. +- * +- * Modems with signal indication support block periodic polling scheduling. +- * With enforce == TRUE, the periodic polling logic can run once as +- * it override once the periodic polling prohibition. +- * When the polling is complete, the periodic polling scheduling +- * is blocked again to avoid that modems with signal indication support +- * are periodic polled for their signal status. +- */ +- if (enforce) +- ctx->enabled = TRUE; +- + /* Don't refresh polling if we're not enabled */ + if (!ctx->enabled) { + mm_obj_dbg (self, "periodic signal check refresh ignored: checks not enabled"); +@@ -1687,7 +1672,7 @@ periodic_signal_check_enable (MMIfaceModem *self) + } + + /* And refresh, which will trigger the first check at high frequency */ +- mm_iface_modem_refresh_signal (self, FALSE); ++ mm_iface_modem_refresh_signal (self); + } + + /*****************************************************************************/ +@@ -2361,7 +2346,7 @@ set_current_capabilities_ready (MMIfaceModem *self, + g_dbus_method_invocation_take_error (ctx->invocation, error); + else { + /* Capabilities updated: explicitly refresh signal and access technology */ +- mm_iface_modem_refresh_signal (self, FALSE); ++ mm_iface_modem_refresh_signal (self); + mm_gdbus_modem_complete_set_current_capabilities (ctx->skeleton, ctx->invocation); + } + +@@ -2851,7 +2836,7 @@ handle_set_current_bands_ready (MMIfaceModem *self, + g_dbus_method_invocation_take_error (ctx->invocation, error); + else { + /* Bands updated: explicitly refresh signal and access technology */ +- mm_iface_modem_refresh_signal (self, FALSE); ++ mm_iface_modem_refresh_signal (self); + mm_gdbus_modem_complete_set_current_bands (ctx->skeleton, ctx->invocation); + } + +@@ -3238,7 +3223,7 @@ handle_set_current_modes_ready (MMIfaceModem *self, + g_dbus_method_invocation_take_error (ctx->invocation, error); + else { + /* Modes updated: explicitly refresh signal and access technology */ +- mm_iface_modem_refresh_signal (self, FALSE); ++ mm_iface_modem_refresh_signal (self); + mm_gdbus_modem_complete_set_current_modes (ctx->skeleton, ctx->invocation); + } + +@@ -4332,9 +4317,9 @@ interface_syncing_step (GTask *task) + + case SYNCING_STEP_REFRESH_SIGNAL_STRENGTH: + /* +- * Start a signal strength and access technologies refresh sequence. ++ * Restart the signal strength and access technologies refresh sequence. + */ +- mm_iface_modem_refresh_signal (self, TRUE); ++ mm_iface_modem_refresh_signal (self); + ctx->step++; + /* fall through */ + +diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h +index 1cd4bdd1..5ba2167c 100644 +--- a/src/mm-iface-modem.h ++++ b/src/mm-iface-modem.h +@@ -547,7 +547,7 @@ void mm_iface_modem_update_signal_quality (MMIfaceModem *self, + guint signal_quality); + + /* Allow requesting to refresh signal via polling */ +-void mm_iface_modem_refresh_signal (MMIfaceModem *self, gboolean enforce); ++void mm_iface_modem_refresh_signal (MMIfaceModem *self); + + /* Allow setting allowed modes */ + void mm_iface_modem_set_current_modes (MMIfaceModem *self, +-- +2.31.1 + diff --git a/temp/modemmanager/0025-iface-modem-ignore-cancellation-during-sync.patch b/temp/modemmanager/0025-iface-modem-ignore-cancellation-during-sync.patch new file mode 100644 index 000000000..04561b9d7 --- /dev/null +++ b/temp/modemmanager/0025-iface-modem-ignore-cancellation-during-sync.patch @@ -0,0 +1,31 @@ +From fc25dae6d8f433244c1126908531b5961db5776d Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 15:43:52 +0200 +Subject: [PATCH 25/39] iface-modem: ignore cancellation during sync() + +There is no input cancellable in the method, so the GTask will never +get cancelled from the outside. +--- + src/mm-iface-modem.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c +index 85df77bd..b298eb89 100644 +--- a/src/mm-iface-modem.c ++++ b/src/mm-iface-modem.c +@@ -4277,12 +4277,6 @@ interface_syncing_step (GTask *task) + MMIfaceModem *self; + SyncingContext *ctx; + +- /* Don't run new steps if we're cancelled */ +- if (g_task_return_error_if_cancelled (task)) { +- g_object_unref (task); +- return; +- } +- + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + +-- +2.31.1 + diff --git a/temp/modemmanager/0026-base-bearer-synchronize-state-when-resuming.patch b/temp/modemmanager/0026-base-bearer-synchronize-state-when-resuming.patch new file mode 100644 index 000000000..0953dd0b2 --- /dev/null +++ b/temp/modemmanager/0026-base-bearer-synchronize-state-when-resuming.patch @@ -0,0 +1,241 @@ +From a293dcb53274119799d079152b894ce4f660776c Mon Sep 17 00:00:00 2001 +From: Dylan Van Assche +Date: Sat, 20 Mar 2021 16:23:14 +0100 +Subject: [PATCH 26/39] base-bearer: synchronize state when resuming + +Refresh connection status on resume to confirm +that the connection bearers are still valid. +--- + src/mm-base-bearer.c | 124 +++++++++++++++++++++++++++++++++++++++++++ + src/mm-base-bearer.h | 24 +++++++++ + src/mm-iface-modem.c | 25 +++++++++ + 3 files changed, 173 insertions(+) + +diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c +index 7510fe19..1ce6e49c 100644 +--- a/src/mm-base-bearer.c ++++ b/src/mm-base-bearer.c +@@ -1399,6 +1399,130 @@ mm_base_bearer_report_connection_status (MMBaseBearer *self, + + /*****************************************************************************/ + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++typedef struct _SyncingContext SyncingContext; ++static void interface_syncing_step (GTask *task); ++ ++typedef enum { ++ SYNCING_STEP_FIRST, ++ SYNCING_STEP_REFRESH_CONNECTION, ++ SYNCING_STEP_LAST ++} SyncingStep; ++ ++struct _SyncingContext { ++ SyncingStep step; ++}; ++ ++gboolean ++mm_base_bearer_sync_finish (MMBaseBearer *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static gboolean ++reload_connection_status_finish (MMBaseBearer *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void ++reload_connection_status_ready (MMBaseBearer *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ SyncingContext *ctx; ++ g_autoptr(GError) error = NULL; ++ ++ ctx = g_task_get_task_data (task); ++ ++ reload_connection_status_finish (self, res, &error); ++ if (error) ++ mm_obj_warn (self, "reloading connection status failed: %s", error->message); ++ ++ /* Go on to the next step */ ++ ctx->step++; ++ interface_syncing_step (task); ++} ++ ++static void ++interface_syncing_step (GTask *task) ++{ ++ MMBaseBearer *self; ++ SyncingContext *ctx; ++ ++ /* Don't run new steps if we're cancelled */ ++ if (g_task_return_error_if_cancelled (task)) { ++ g_object_unref (task); ++ return; ++ } ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ switch (ctx->step) { ++ case SYNCING_STEP_FIRST: ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_REFRESH_CONNECTION: ++ /* ++ * AT+PPP based connections should not be synced. ++ * When a AT+PPP connection bearer is connected, the 'ignore_disconnection_reports' flag is set. ++ */ ++ if (!self->priv->ignore_disconnection_reports) { ++ if (!MM_BASE_BEARER_GET_CLASS (self)->reload_connection_status) ++ mm_obj_warn (self, "unable to reload connection status, method not implemented"); ++ else { ++ mm_obj_dbg (self, "refreshing connection status"); ++ MM_BASE_BEARER_GET_CLASS (self)->reload_connection_status (self, ++ (GAsyncReadyCallback) reload_connection_status_ready, ++ task); ++ return; ++ } ++ } ++ ctx->step++; ++ /* fall through */ ++ ++ case SYNCING_STEP_LAST: ++ /* We are done without errors! */ ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); ++ return; ++ ++ default: ++ break; ++ } ++ ++ g_assert_not_reached (); ++} ++ ++void ++mm_base_bearer_sync (MMBaseBearer *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ SyncingContext *ctx; ++ GTask *task; ++ ++ /* Create SyncingContext */ ++ ctx = g_new0 (SyncingContext, 1); ++ ctx->step = SYNCING_STEP_FIRST; ++ ++ /* Create sync steps task and execute it */ ++ task = g_task_new (self, NULL, callback, user_data); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); ++ interface_syncing_step (task); ++} ++ ++#endif ++ ++/*****************************************************************************/ ++ + static gchar * + log_object_build_id (MMLogObject *_self) + { +diff --git a/src/mm-base-bearer.h b/src/mm-base-bearer.h +index 1c1f96ea..a2a00166 100644 +--- a/src/mm-base-bearer.h ++++ b/src/mm-base-bearer.h +@@ -123,6 +123,18 @@ struct _MMBaseBearerClass { + GAsyncResult *res, + GError **error); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++ /* Reload connection status */ ++ void (* reload_connection_status) (MMBaseBearer *bearer, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++ gboolean (* reload_connection_status_finish) (MMBaseBearer *bearer, ++ GAsyncResult *res, ++ GError **error); ++ ++#endif ++ + /* Reload statistics */ + void (* reload_stats) (MMBaseBearer *bearer, + GAsyncReadyCallback callback, +@@ -169,4 +181,16 @@ void mm_base_bearer_disconnect_force (MMBaseBearer *self); + void mm_base_bearer_report_connection_status (MMBaseBearer *self, + MMBearerConnectionStatus status); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++/* Sync Broadband Bearer (async) */ ++void mm_base_bearer_sync (MMBaseBearer *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean mm_base_bearer_sync_finish (MMBaseBearer *self, ++ GAsyncResult *res, ++ GError **error); ++ ++#endif ++ + #endif /* MM_BASE_BEARER_H */ +diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c +index b298eb89..1fe1feff 100644 +--- a/src/mm-iface-modem.c ++++ b/src/mm-iface-modem.c +@@ -4220,6 +4220,7 @@ typedef enum { + SYNCING_STEP_DETECT_SIM_SWAP, + SYNCING_STEP_REFRESH_SIM_LOCK, + SYNCING_STEP_REFRESH_SIGNAL_STRENGTH, ++ SYNCING_STEP_REFRESH_BEARERS, + SYNCING_STEP_LAST + } SyncingStep; + +@@ -4271,6 +4272,22 @@ sync_detect_sim_swap_ready (MMIfaceModem *self, + interface_syncing_step (task); + } + ++static void ++reload_bearers (MMIfaceModem *self) ++{ ++ g_autoptr(MMBearerList) list = NULL; ++ ++ g_object_get (self, ++ MM_IFACE_MODEM_BEARER_LIST, &list, ++ NULL); ++ ++ if (list) { ++ mm_bearer_list_foreach (list, ++ (MMBearerListForeachFunc)mm_base_bearer_sync, ++ NULL); ++ } ++} ++ + static void + interface_syncing_step (GTask *task) + { +@@ -4317,6 +4334,14 @@ interface_syncing_step (GTask *task) + ctx->step++; + /* fall through */ + ++ case SYNCING_STEP_REFRESH_BEARERS: ++ /* ++ * Refresh bearers. ++ */ ++ reload_bearers (self); ++ ctx->step++; ++ /* fall through */ ++ + case SYNCING_STEP_LAST: + /* We are done without errors! */ + g_task_return_boolean (task, TRUE); +-- +2.31.1 + diff --git a/temp/modemmanager/0027-base-bearer-improve-comments-of-the-load-reload_conn.patch b/temp/modemmanager/0027-base-bearer-improve-comments-of-the-load-reload_conn.patch new file mode 100644 index 000000000..4d7ea45be --- /dev/null +++ b/temp/modemmanager/0027-base-bearer-improve-comments-of-the-load-reload_conn.patch @@ -0,0 +1,54 @@ +From c13c2134b4ef913f71f91128298080b5b1cf316b Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 20:58:40 +0200 +Subject: [PATCH 27/39] base-bearer: improve comments of the + load/reload_connection_status() methods + +--- + src/mm-base-bearer.h | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/src/mm-base-bearer.h b/src/mm-base-bearer.h +index a2a00166..c5a4bda5 100644 +--- a/src/mm-base-bearer.h ++++ b/src/mm-base-bearer.h +@@ -113,9 +113,15 @@ struct _MMBaseBearerClass { + GError **error); + + /* Monitor connection status: +- * NOTE: only CONNECTED or DISCONNECTED should be reported here; this method ++ * ++ * Only CONNECTED or DISCONNECTED should be reported here; this method + * is used to poll for connection status once the connection has been +- * established */ ++ * established. ++ * ++ * This method will return MM_CORE_ERROR_UNSUPPORTED if the polling ++ * is not required (i.e. if we can safely rely on async indications ++ * sent by the modem). ++ */ + void (* load_connection_status) (MMBaseBearer *bearer, + GAsyncReadyCallback callback, + gpointer user_data); +@@ -125,7 +131,17 @@ struct _MMBaseBearerClass { + + #if defined WITH_SYSTEMD_SUSPEND_RESUME + +- /* Reload connection status */ ++ /* Reload connection status: ++ * ++ * This method should return the exact connection status of the bearer, and ++ * the check must always be performed (if supported). This method should not ++ * return MM_CORE_ERROR_UNSUPPORTED as a way to skip the operation, as in ++ * this case the connection monitoring is required during the quick ++ * suspend/resume synchronization. ++ * ++ * It is up to each protocol/plugin whether providing the same method here ++ * and in load_connection_status() makes sense. ++ */ + void (* reload_connection_status) (MMBaseBearer *bearer, + GAsyncReadyCallback callback, + gpointer user_data); +-- +2.31.1 + diff --git a/temp/modemmanager/0028-base-bearer-fix-connection-reload-completion.patch b/temp/modemmanager/0028-base-bearer-fix-connection-reload-completion.patch new file mode 100644 index 000000000..6d40c8f93 --- /dev/null +++ b/temp/modemmanager/0028-base-bearer-fix-connection-reload-completion.patch @@ -0,0 +1,42 @@ +From ea6ecd7cf973022f0417e083bfe18aeaf9a94f84 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 15:51:51 +0200 +Subject: [PATCH 28/39] base-bearer: fix connection reload completion + +If we called the class reload_connection_status() method, we should +call the class reload_connection_status_finish() as well. +--- + src/mm-base-bearer.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c +index 1ce6e49c..71f6684b 100644 +--- a/src/mm-base-bearer.c ++++ b/src/mm-base-bearer.c +@@ -1422,14 +1422,6 @@ mm_base_bearer_sync_finish (MMBaseBearer *self, + return g_task_propagate_boolean (G_TASK (res), error); + } + +-static gboolean +-reload_connection_status_finish (MMBaseBearer *self, +- GAsyncResult *res, +- GError **error) +-{ +- return g_task_propagate_boolean (G_TASK (res), error); +-} +- + static void + reload_connection_status_ready (MMBaseBearer *self, + GAsyncResult *res, +@@ -1440,7 +1432,7 @@ reload_connection_status_ready (MMBaseBearer *self, + + ctx = g_task_get_task_data (task); + +- reload_connection_status_finish (self, res, &error); ++ MM_BASE_BEARER_GET_CLASS (self)->reload_connection_status_finish (self, res, &error); + if (error) + mm_obj_warn (self, "reloading connection status failed: %s", error->message); + +-- +2.31.1 + diff --git a/temp/modemmanager/0029-base-bearer-propagate-the-new-connection-status-afte.patch b/temp/modemmanager/0029-base-bearer-propagate-the-new-connection-status-afte.patch new file mode 100644 index 000000000..307d54378 --- /dev/null +++ b/temp/modemmanager/0029-base-bearer-propagate-the-new-connection-status-afte.patch @@ -0,0 +1,105 @@ +From d04b388e4dbc9c341fbd7176d1eef2b0dcba49ba Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 21:17:42 +0200 +Subject: [PATCH 29/39] base-bearer: propagate the new connection status after + reload + +Just triggering a connection status reload won't change the actual +bearer object state. + +We change the signature of the reload_connection_status_finish() +method so that it returns the actual reloaded bearer connection +status, and so both the load_ and reload_ methods can be implemented +with exactly the same method, something that was not possible before. + +Once we get the new connection status reloaded, we apply it in the +bearer object only if it's DISCONNECTED (and it wasn't DISCONNECTED +before). This should cover the true real case we're interested in, and +nothing else (i.e. we won't overcomplicate the logic attempting to +handle disconnected->connected transitions detected in the sync() +operation). +--- + src/mm-base-bearer.c | 29 +++++++++++++++++++++++------ + src/mm-base-bearer.h | 6 +++--- + 2 files changed, 26 insertions(+), 9 deletions(-) + +diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c +index 71f6684b..69600c17 100644 +--- a/src/mm-base-bearer.c ++++ b/src/mm-base-bearer.c +@@ -1411,7 +1411,8 @@ typedef enum { + } SyncingStep; + + struct _SyncingContext { +- SyncingStep step; ++ SyncingStep step; ++ MMBearerStatus status; + }; + + gboolean +@@ -1427,14 +1428,29 @@ reload_connection_status_ready (MMBaseBearer *self, + GAsyncResult *res, + GTask *task) + { +- SyncingContext *ctx; +- g_autoptr(GError) error = NULL; ++ SyncingContext *ctx; ++ MMBearerConnectionStatus reloaded_status; ++ g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + +- MM_BASE_BEARER_GET_CLASS (self)->reload_connection_status_finish (self, res, &error); +- if (error) ++ /* The only update we're really interested in is the connected->disconnected ++ * one, because any other would be extremely strange and it's probably not ++ * worth trying to support those; e.g. a disconnected->connected change here ++ * would be impossible to be handled correctly. We'll also ignore intermediate ++ * states (connecting/disconnecting), as we can rely on the reports of the final ++ * state at some point soon. ++ * ++ * So, just handle DISCONNECTED at this point. ++ */ ++ reloaded_status = MM_BASE_BEARER_GET_CLASS (self)->reload_connection_status_finish (self, res, &error); ++ if (reloaded_status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) + mm_obj_warn (self, "reloading connection status failed: %s", error->message); ++ else if ((ctx->status == MM_BEARER_STATUS_CONNECTED) && ++ (reloaded_status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED)) { ++ mm_obj_dbg (self, "disconnection detected during status synchronization"); ++ mm_base_bearer_report_connection_status (self, reloaded_status); ++ } + + /* Go on to the next step */ + ctx->step++; +@@ -1501,9 +1517,10 @@ mm_base_bearer_sync (MMBaseBearer *self, + SyncingContext *ctx; + GTask *task; + +- /* Create SyncingContext */ ++ /* Create SyncingContext and store the original bearer status */ + ctx = g_new0 (SyncingContext, 1); + ctx->step = SYNCING_STEP_FIRST; ++ ctx->status = self->priv->status; + + /* Create sync steps task and execute it */ + task = g_task_new (self, NULL, callback, user_data); +diff --git a/src/mm-base-bearer.h b/src/mm-base-bearer.h +index c5a4bda5..16e4bae5 100644 +--- a/src/mm-base-bearer.h ++++ b/src/mm-base-bearer.h +@@ -145,9 +145,9 @@ struct _MMBaseBearerClass { + void (* reload_connection_status) (MMBaseBearer *bearer, + GAsyncReadyCallback callback, + gpointer user_data); +- gboolean (* reload_connection_status_finish) (MMBaseBearer *bearer, +- GAsyncResult *res, +- GError **error); ++ MMBearerConnectionStatus (* reload_connection_status_finish) (MMBaseBearer *bearer, ++ GAsyncResult *res, ++ GError **error); + + #endif + +-- +2.31.1 + diff --git a/temp/modemmanager/0030-iface-modem-bearer-list-sync-all-bearers-one-after-t.patch b/temp/modemmanager/0030-iface-modem-bearer-list-sync-all-bearers-one-after-t.patch new file mode 100644 index 000000000..d132ea753 --- /dev/null +++ b/temp/modemmanager/0030-iface-modem-bearer-list-sync-all-bearers-one-after-t.patch @@ -0,0 +1,207 @@ +From 50be73286059a9694f0cc8cc8b42d73cb6e9cb1f Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 21:40:20 +0200 +Subject: [PATCH 30/39] iface-modem,bearer-list: sync all bearers one after the + other + +Do not launch N checks for N bearers and ignore their result. Instead, +go one by one, and report errors one by one. +--- + src/mm-bearer-list.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ + src/mm-bearer-list.h | 11 ++++++ + src/mm-iface-modem.c | 49 +++++++++++++++++++------ + 3 files changed, 136 insertions(+), 10 deletions(-) + +diff --git a/src/mm-bearer-list.c b/src/mm-bearer-list.c +index 65717132..1ce53e05 100644 +--- a/src/mm-bearer-list.c ++++ b/src/mm-bearer-list.c +@@ -268,6 +268,92 @@ mm_bearer_list_disconnect_all_bearers (MMBearerList *self, + + /*****************************************************************************/ + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++typedef struct { ++ GList *pending; ++ MMBaseBearer *current; ++} SyncAllContext; ++ ++static void ++sync_all_context_free (SyncAllContext *ctx) ++{ ++ if (ctx->current) ++ g_object_unref (ctx->current); ++ g_list_free_full (ctx->pending, g_object_unref); ++ g_free (ctx); ++} ++ ++gboolean ++mm_bearer_list_sync_all_bearers_finish (MMBearerList *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (res), error); ++} ++ ++static void sync_next_bearer (GTask *task); ++ ++static void ++sync_ready (MMBaseBearer *bearer, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ g_autoptr(GError) error = NULL; ++ ++ if (!mm_base_bearer_sync_finish (bearer, res, &error)) ++ mm_obj_warn (bearer, "failed synchronizing state: %s", error->message); ++ ++ sync_next_bearer (task); ++} ++ ++static void ++sync_next_bearer (GTask *task) ++{ ++ SyncAllContext *ctx; ++ ++ ctx = g_task_get_task_data (task); ++ if (ctx->current) ++ g_clear_object (&ctx->current); ++ ++ /* No more bearers? all done! */ ++ if (!ctx->pending) { ++ g_task_return_boolean (task, TRUE); ++ g_object_unref (task); ++ return; ++ } ++ ++ ctx->current = MM_BASE_BEARER (ctx->pending->data); ++ ctx->pending = g_list_delete_link (ctx->pending, ctx->pending); ++ ++ mm_base_bearer_sync (ctx->current, (GAsyncReadyCallback)sync_ready, task); ++} ++ ++void ++mm_bearer_list_sync_all_bearers (MMBearerList *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ SyncAllContext *ctx; ++ GTask *task; ++ ++ ctx = g_new0 (SyncAllContext, 1); ++ ++ /* Get a copy of the list */ ++ ctx->pending = g_list_copy_deep (self->priv->bearers, ++ (GCopyFunc)g_object_ref, ++ NULL); ++ ++ task = g_task_new (self, NULL, callback, user_data); ++ g_task_set_task_data (task, ctx, (GDestroyNotify)sync_all_context_free); ++ ++ sync_next_bearer (task); ++} ++ ++#endif ++ ++/*****************************************************************************/ ++ + MMBearerList * + mm_bearer_list_new (guint max_bearers, + guint max_active_bearers) +diff --git a/src/mm-bearer-list.h b/src/mm-bearer-list.h +index 0d220eee..04af79e9 100644 +--- a/src/mm-bearer-list.h ++++ b/src/mm-bearer-list.h +@@ -85,4 +85,15 @@ gboolean mm_bearer_list_disconnect_all_bearers_finish (MMBearerList *self, + GAsyncResult *res, + GError **error); + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++void mm_bearer_list_sync_all_bearers (MMBearerList *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean mm_bearer_list_sync_all_bearers_finish (MMBearerList *self, ++ GAsyncResult *res, ++ GError **error); ++ ++#endif ++ + #endif /* MM_BEARER_LIST_H */ +diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c +index 1fe1feff..c3722c0a 100644 +--- a/src/mm-iface-modem.c ++++ b/src/mm-iface-modem.c +@@ -4273,19 +4273,49 @@ sync_detect_sim_swap_ready (MMIfaceModem *self, + } + + static void +-reload_bearers (MMIfaceModem *self) ++sync_all_bearers_ready (MMBearerList *bearer_list, ++ GAsyncResult *res, ++ GTask *task) + { +- g_autoptr(MMBearerList) list = NULL; ++ MMIfaceModem *self; ++ SyncingContext *ctx; ++ g_autoptr (GError) error = NULL; ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); ++ ++ if (!mm_bearer_list_sync_all_bearers_finish (bearer_list, res, &error)) ++ mm_obj_warn (self, "synchronizing all bearer status failed: %s", error->message); ++ ++ /* Go on to next step */ ++ ctx->step++; ++ interface_syncing_step (task); ++} ++ ++static void ++reload_bearers (GTask *task) ++{ ++ MMIfaceModem *self; ++ SyncingContext *ctx; ++ g_autoptr(MMBearerList) bearer_list = NULL; ++ ++ self = g_task_get_source_object (task); ++ ctx = g_task_get_task_data (task); + + g_object_get (self, +- MM_IFACE_MODEM_BEARER_LIST, &list, ++ MM_IFACE_MODEM_BEARER_LIST, &bearer_list, + NULL); + +- if (list) { +- mm_bearer_list_foreach (list, +- (MMBearerListForeachFunc)mm_base_bearer_sync, +- NULL); ++ if (!bearer_list) { ++ /* Go on to next step */ ++ ctx->step++; ++ interface_syncing_step (task); ++ return; + } ++ ++ mm_bearer_list_sync_all_bearers (bearer_list, ++ (GAsyncReadyCallback)sync_all_bearers_ready, ++ task); + } + + static void +@@ -4338,9 +4368,8 @@ interface_syncing_step (GTask *task) + /* + * Refresh bearers. + */ +- reload_bearers (self); +- ctx->step++; +- /* fall through */ ++ reload_bearers (task); ++ return; + + case SYNCING_STEP_LAST: + /* We are done without errors! */ +-- +2.31.1 + diff --git a/temp/modemmanager/0031-base-bearer-ignore-cancellation-during-sync.patch b/temp/modemmanager/0031-base-bearer-ignore-cancellation-during-sync.patch new file mode 100644 index 000000000..289c9616a --- /dev/null +++ b/temp/modemmanager/0031-base-bearer-ignore-cancellation-during-sync.patch @@ -0,0 +1,31 @@ +From 7c93327a711c3c5e0834acabd059ebd0fc70e379 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 21:46:34 +0200 +Subject: [PATCH 31/39] base-bearer: ignore cancellation during sync() + +There is no input cancellable in the method, so the GTask will never +get cancelled from the outside. +--- + src/mm-base-bearer.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c +index 69600c17..801c3ec1 100644 +--- a/src/mm-base-bearer.c ++++ b/src/mm-base-bearer.c +@@ -1463,12 +1463,6 @@ interface_syncing_step (GTask *task) + MMBaseBearer *self; + SyncingContext *ctx; + +- /* Don't run new steps if we're cancelled */ +- if (g_task_return_error_if_cancelled (task)) { +- g_object_unref (task); +- return; +- } +- + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + +-- +2.31.1 + diff --git a/temp/modemmanager/0032-broadband-bearer-reuse-the-same-method-for-load-and-.patch b/temp/modemmanager/0032-broadband-bearer-reuse-the-same-method-for-load-and-.patch new file mode 100644 index 000000000..8e5252825 --- /dev/null +++ b/temp/modemmanager/0032-broadband-bearer-reuse-the-same-method-for-load-and-.patch @@ -0,0 +1,32 @@ +From 0576f8d28405df80c689f478363a2a041f9d5df3 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 22:11:08 +0200 +Subject: [PATCH 32/39] broadband-bearer: reuse the same method for load and + reload + +The load_() method is used for connection monitoring; while the +reload_() method is used to sync connection status after a +suspend/resume operation. The same method can be used for both things +in the case of AT+CGACT? based modems. +--- + src/mm-broadband-bearer.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c +index 73869a0c..ff49903a 100644 +--- a/src/mm-broadband-bearer.c ++++ b/src/mm-broadband-bearer.c +@@ -2333,6 +2333,10 @@ mm_broadband_bearer_class_init (MMBroadbandBearerClass *klass) + base_bearer_class->report_connection_status = report_connection_status; + base_bearer_class->load_connection_status = load_connection_status; + base_bearer_class->load_connection_status_finish = load_connection_status_finish; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = load_connection_status; ++ base_bearer_class->reload_connection_status_finish = load_connection_status_finish; ++#endif + + klass->connect_3gpp = connect_3gpp; + klass->connect_3gpp_finish = detailed_connect_finish; +-- +2.31.1 + diff --git a/temp/modemmanager/0033-novatel-lte-reuse-the-same-method-for-load-and-reloa.patch b/temp/modemmanager/0033-novatel-lte-reuse-the-same-method-for-load-and-reloa.patch new file mode 100644 index 000000000..8b4e736c8 --- /dev/null +++ b/temp/modemmanager/0033-novatel-lte-reuse-the-same-method-for-load-and-reloa.patch @@ -0,0 +1,31 @@ +From 5fdf3f0f26579cc9a453401de09ca6ea0292e27c Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 22:14:49 +0200 +Subject: [PATCH 33/39] novatel-lte: reuse the same method for load and reload + +The load_() method is used for connection monitoring; while the +reload_() method is used to sync connection status after a +suspend/resume operation. The same method can be used for both things +in the Novatel LTE plugin. +--- + plugins/novatel/mm-broadband-bearer-novatel-lte.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/plugins/novatel/mm-broadband-bearer-novatel-lte.c b/plugins/novatel/mm-broadband-bearer-novatel-lte.c +index ec08f4d7..4419eb23 100644 +--- a/plugins/novatel/mm-broadband-bearer-novatel-lte.c ++++ b/plugins/novatel/mm-broadband-bearer-novatel-lte.c +@@ -568,6 +568,10 @@ mm_broadband_bearer_novatel_lte_class_init (MMBroadbandBearerNovatelLteClass *kl + + base_bearer_class->load_connection_status = load_connection_status; + base_bearer_class->load_connection_status_finish = load_connection_status_finish; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = load_connection_status; ++ base_bearer_class->reload_connection_status_finish = load_connection_status_finish; ++#endif + + broadband_bearer_class->connect_3gpp = connect_3gpp; + broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish; +-- +2.31.1 + diff --git a/temp/modemmanager/0034-sierra-reuse-the-same-method-for-load-and-reload.patch b/temp/modemmanager/0034-sierra-reuse-the-same-method-for-load-and-reload.patch new file mode 100644 index 000000000..a64e31712 --- /dev/null +++ b/temp/modemmanager/0034-sierra-reuse-the-same-method-for-load-and-reload.patch @@ -0,0 +1,31 @@ +From 14ea67c111b6116071f00c235b23152b21ab2d04 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 22:17:25 +0200 +Subject: [PATCH 34/39] sierra: reuse the same method for load and reload + +The load_() method is used for connection monitoring; while the +reload_() method is used to sync connection status after a +suspend/resume operation. The same method can be used for both things +in the Sierra plugin. +--- + plugins/sierra/mm-broadband-bearer-sierra.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/plugins/sierra/mm-broadband-bearer-sierra.c b/plugins/sierra/mm-broadband-bearer-sierra.c +index 2c2ef375..bf95a8eb 100644 +--- a/plugins/sierra/mm-broadband-bearer-sierra.c ++++ b/plugins/sierra/mm-broadband-bearer-sierra.c +@@ -663,6 +663,10 @@ mm_broadband_bearer_sierra_class_init (MMBroadbandBearerSierraClass *klass) + + base_bearer_class->load_connection_status = load_connection_status; + base_bearer_class->load_connection_status_finish = load_connection_status_finish; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = load_connection_status; ++ base_bearer_class->reload_connection_status_finish = load_connection_status_finish; ++#endif + + broadband_bearer_class->dial_3gpp = dial_3gpp; + broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; +-- +2.31.1 + diff --git a/temp/modemmanager/0035-cinterion-reuse-the-same-method-for-load-and-reload.patch b/temp/modemmanager/0035-cinterion-reuse-the-same-method-for-load-and-reload.patch new file mode 100644 index 000000000..080f697fb --- /dev/null +++ b/temp/modemmanager/0035-cinterion-reuse-the-same-method-for-load-and-reload.patch @@ -0,0 +1,31 @@ +From e56cb4ebb98fe814a2f88d47d92e480a14be4a72 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 22:19:40 +0200 +Subject: [PATCH 35/39] cinterion: reuse the same method for load and reload + +The load_() method is used for connection monitoring; while the +reload_() method is used to sync connection status after a +suspend/resume operation. The same method can be used for both things +in the Cinterion plugin. +--- + plugins/cinterion/mm-broadband-bearer-cinterion.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.c b/plugins/cinterion/mm-broadband-bearer-cinterion.c +index 464e75e9..861c7ccb 100644 +--- a/plugins/cinterion/mm-broadband-bearer-cinterion.c ++++ b/plugins/cinterion/mm-broadband-bearer-cinterion.c +@@ -681,6 +681,10 @@ mm_broadband_bearer_cinterion_class_init (MMBroadbandBearerCinterionClass *klass + + base_bearer_class->load_connection_status = load_connection_status; + base_bearer_class->load_connection_status_finish = load_connection_status_finish; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = load_connection_status; ++ base_bearer_class->reload_connection_status_finish = load_connection_status_finish; ++#endif + + broadband_bearer_class->dial_3gpp = dial_3gpp; + broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; +-- +2.31.1 + diff --git a/temp/modemmanager/0036-plugins-ignore-reload_connection_status-where-not-su.patch b/temp/modemmanager/0036-plugins-ignore-reload_connection_status-where-not-su.patch new file mode 100644 index 000000000..871ddc0be --- /dev/null +++ b/temp/modemmanager/0036-plugins-ignore-reload_connection_status-where-not-su.patch @@ -0,0 +1,109 @@ +From 938e087defb53ca55ccc356f8094ce91f3f7da1a Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 22:21:54 +0200 +Subject: [PATCH 36/39] plugins: ignore reload_connection_status() where not + supported + +Some of the AT-based connection methods don't have any way to query +connection status, or we don't have a proper implementation for those +yet. Ignore the reload operation in all those. +--- + plugins/altair/mm-broadband-bearer-altair-lte.c | 4 ++++ + plugins/huawei/mm-broadband-bearer-huawei.c | 4 ++++ + plugins/icera/mm-broadband-bearer-icera.c | 4 ++++ + plugins/iridium/mm-bearer-iridium.c | 4 ++++ + plugins/mbm/mm-broadband-bearer-mbm.c | 4 ++++ + plugins/option/mm-broadband-bearer-hso.c | 4 ++++ + 6 files changed, 24 insertions(+) + +diff --git a/plugins/altair/mm-broadband-bearer-altair-lte.c b/plugins/altair/mm-broadband-bearer-altair-lte.c +index 1ce965a8..52403418 100644 +--- a/plugins/altair/mm-broadband-bearer-altair-lte.c ++++ b/plugins/altair/mm-broadband-bearer-altair-lte.c +@@ -358,6 +358,10 @@ mm_broadband_bearer_altair_lte_class_init (MMBroadbandBearerAltairLteClass *klas + + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = NULL; ++ base_bearer_class->reload_connection_status_finish = NULL; ++#endif + + broadband_bearer_class->connect_3gpp = connect_3gpp; + broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish; +diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c +index 4bf2bb59..5a098d1b 100644 +--- a/plugins/huawei/mm-broadband-bearer-huawei.c ++++ b/plugins/huawei/mm-broadband-bearer-huawei.c +@@ -874,6 +874,10 @@ mm_broadband_bearer_huawei_class_init (MMBroadbandBearerHuaweiClass *klass) + base_bearer_class->report_connection_status = report_connection_status; + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = NULL; ++ base_bearer_class->reload_connection_status_finish = NULL; ++#endif + + broadband_bearer_class->connect_3gpp = connect_3gpp; + broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish; +diff --git a/plugins/icera/mm-broadband-bearer-icera.c b/plugins/icera/mm-broadband-bearer-icera.c +index 1d6859c0..dcd477fa 100644 +--- a/plugins/icera/mm-broadband-bearer-icera.c ++++ b/plugins/icera/mm-broadband-bearer-icera.c +@@ -1000,6 +1000,10 @@ mm_broadband_bearer_icera_class_init (MMBroadbandBearerIceraClass *klass) + base_bearer_class->report_connection_status = report_connection_status; + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = NULL; ++ base_bearer_class->reload_connection_status_finish = NULL; ++#endif + + broadband_bearer_class->dial_3gpp = dial_3gpp; + broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; +diff --git a/plugins/iridium/mm-bearer-iridium.c b/plugins/iridium/mm-bearer-iridium.c +index 12b60419..511954f1 100644 +--- a/plugins/iridium/mm-bearer-iridium.c ++++ b/plugins/iridium/mm-bearer-iridium.c +@@ -252,4 +252,8 @@ mm_bearer_iridium_class_init (MMBearerIridiumClass *klass) + base_bearer_class->connect_finish = connect_finish; + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = NULL; ++ base_bearer_class->reload_connection_status_finish = NULL; ++#endif + } +diff --git a/plugins/mbm/mm-broadband-bearer-mbm.c b/plugins/mbm/mm-broadband-bearer-mbm.c +index 8de7a09f..0ba42aea 100644 +--- a/plugins/mbm/mm-broadband-bearer-mbm.c ++++ b/plugins/mbm/mm-broadband-bearer-mbm.c +@@ -895,6 +895,10 @@ mm_broadband_bearer_mbm_class_init (MMBroadbandBearerMbmClass *klass) + base_bearer_class->report_connection_status = report_connection_status; + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = NULL; ++ base_bearer_class->reload_connection_status_finish = NULL; ++#endif + + broadband_bearer_class->dial_3gpp = dial_3gpp; + broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; +diff --git a/plugins/option/mm-broadband-bearer-hso.c b/plugins/option/mm-broadband-bearer-hso.c +index 908d32c6..3aa8de88 100644 +--- a/plugins/option/mm-broadband-bearer-hso.c ++++ b/plugins/option/mm-broadband-bearer-hso.c +@@ -786,6 +786,10 @@ mm_broadband_bearer_hso_class_init (MMBroadbandBearerHsoClass *klass) + base_bearer_class->report_connection_status = report_connection_status; + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = NULL; ++ base_bearer_class->reload_connection_status_finish = NULL; ++#endif + + broadband_bearer_class->dial_3gpp = dial_3gpp; + broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; +-- +2.31.1 + diff --git a/temp/modemmanager/0037-bearer-qmi-implement-reload_connection_status-for-th.patch b/temp/modemmanager/0037-bearer-qmi-implement-reload_connection_status-for-th.patch new file mode 100644 index 000000000..ad62a7dfb --- /dev/null +++ b/temp/modemmanager/0037-bearer-qmi-implement-reload_connection_status-for-th.patch @@ -0,0 +1,153 @@ +From 1cf4e63d828669747424e740519a6e2da246be38 Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Sun, 23 May 2021 23:39:18 +0200 +Subject: [PATCH 37/39] bearer-qmi: implement reload_connection_status() for + the sync operation + +The original load_connection_status() method would return an +UNSUPPORTED error if connection monitoring wasn't required (which is +the default in most QMI modems). + +The new reload_connection_status() method requires the check to always +be done unconditionally. + +We take most of the original logic in the load_connection_status() for +the new reload_connection_status(), and we add the UNSUPPORTED error +logic exclusively in the new load_connection_status(). +--- + src/mm-bearer-qmi.c | 86 +++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 71 insertions(+), 15 deletions(-) + +diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c +index 670fb804..967594bf 100644 +--- a/src/mm-bearer-qmi.c ++++ b/src/mm-bearer-qmi.c +@@ -226,7 +226,7 @@ reload_stats (MMBaseBearer *self, + } + + /*****************************************************************************/ +-/* Connection status polling */ ++/* Connection status check */ + + typedef enum { + CONNECTION_STATUS_CONTEXT_STEP_FIRST, +@@ -240,9 +240,9 @@ typedef struct { + } ConnectionStatusContext; + + static MMBearerConnectionStatus +-load_connection_status_finish (MMBaseBearer *self, +- GAsyncResult *res, +- GError **error) ++reload_connection_status_finish (MMBaseBearer *self, ++ GAsyncResult *res, ++ GError **error) + { + gint val; + +@@ -312,16 +312,6 @@ connection_status_context_step (GTask *task) + + switch (ctx->step) { + case CONNECTION_STATUS_CONTEXT_STEP_FIRST: +- /* Connection status polling is an optional feature that must be +- * enabled explicitly via udev tags. If not set, out as unsupported */ +- if (self->priv->data && +- !mm_kernel_device_get_global_property_as_boolean (mm_port_peek_kernel_device (self->priv->data), +- "ID_MM_QMI_CONNECTION_STATUS_POLLING_ENABLE")) { +- g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, +- "Connection status polling not required"); +- g_object_unref (task); +- return; +- } + /* If no clients ready on start, assume disconnected */ + if (!self->priv->client_ipv4 && !self->priv->client_ipv6) { + g_task_return_int (task, MM_BEARER_CONNECTION_STATUS_DISCONNECTED); +@@ -369,7 +359,7 @@ connection_status_context_step (GTask *task) + } + + static void +-load_connection_status (MMBaseBearer *self, ++reload_connection_status (MMBaseBearer *self, + GAsyncReadyCallback callback, + gpointer user_data) + { +@@ -385,6 +375,68 @@ load_connection_status (MMBaseBearer *self, + connection_status_context_step (task); + } + ++/*****************************************************************************/ ++/* Connection status polling */ ++ ++static MMBearerConnectionStatus ++load_connection_status_finish (MMBaseBearer *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ gint val; ++ ++ val = g_task_propagate_int (G_TASK (res), error); ++ if (val < 0) ++ return MM_BEARER_CONNECTION_STATUS_UNKNOWN; ++ ++ return (MMBearerConnectionStatus) val; ++} ++ ++static void ++reload_connection_status_ready (MMBaseBearer *self, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ MMBearerConnectionStatus status; ++ GError *error = NULL; ++ ++ status = reload_connection_status_finish (self, res, &error); ++ if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) ++ g_task_return_error (task, error); ++ else ++ g_task_return_int (task, MM_BEARER_CONNECTION_STATUS_CONNECTED); ++ g_object_unref (task); ++} ++ ++static void ++load_connection_status (MMBaseBearer *_self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ MMBearerQmi *self = MM_BEARER_QMI (_self); ++ GTask *task; ++ ++ task = g_task_new (self, NULL, callback, user_data); ++ ++ /* Connection status polling is an optional feature that must be ++ * enabled explicitly via udev tags. If not set, out as unsupported. ++ * Note that when connected via a muxed link, the udev tag should be ++ * checked on the master interface (lower device) */ ++ if ((self->priv->data && ++ !mm_kernel_device_get_global_property_as_boolean (mm_port_peek_kernel_device (self->priv->data), ++ "ID_MM_QMI_CONNECTION_STATUS_POLLING_ENABLE")) || ++ (self->priv->link && ++ !mm_kernel_device_get_global_property_as_boolean (mm_kernel_device_peek_lower_device (mm_port_peek_kernel_device (self->priv->link)), ++ "ID_MM_QMI_CONNECTION_STATUS_POLLING_ENABLE"))) { ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, ++ "Connection status polling not required"); ++ g_object_unref (task); ++ return; ++ } ++ ++ reload_connection_status (_self, (GAsyncReadyCallback)reload_connection_status_ready, task); ++} ++ + /*****************************************************************************/ + /* Connect */ + +@@ -2235,4 +2287,8 @@ mm_bearer_qmi_class_init (MMBearerQmiClass *klass) + base_bearer_class->reload_stats_finish = reload_stats_finish; + base_bearer_class->load_connection_status = load_connection_status; + base_bearer_class->load_connection_status_finish = load_connection_status_finish; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = reload_connection_status; ++ base_bearer_class->reload_connection_status_finish = reload_connection_status_finish; ++#endif + } +-- +2.31.1 + diff --git a/temp/modemmanager/0038-bearer-mbim-implement-reload_connection_status.patch b/temp/modemmanager/0038-bearer-mbim-implement-reload_connection_status.patch new file mode 100644 index 000000000..b436e2e6d --- /dev/null +++ b/temp/modemmanager/0038-bearer-mbim-implement-reload_connection_status.patch @@ -0,0 +1,148 @@ +From 0a1d5d800810bce1fc14c09be5f42eb5b90e7edb Mon Sep 17 00:00:00 2001 +From: Aleksander Morgado +Date: Mon, 24 May 2021 00:08:07 +0200 +Subject: [PATCH 38/39] bearer-mbim: implement reload_connection_status() + +Implement connection status reloading for MBIM based bearers. + +Based on a patch by Dylan Van Assche +--- + src/mm-bearer-mbim.c | 115 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 115 insertions(+) + +diff --git a/src/mm-bearer-mbim.c b/src/mm-bearer-mbim.c +index 55064b30..f0479ebb 100644 +--- a/src/mm-bearer-mbim.c ++++ b/src/mm-bearer-mbim.c +@@ -1424,6 +1424,117 @@ report_connection_status (MMBaseBearer *self, + + /*****************************************************************************/ + ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ ++static MMBearerConnectionStatus ++reload_connection_status_finish (MMBaseBearer *self, ++ GAsyncResult *res, ++ GError **error) ++{ ++ gint val; ++ ++ val = g_task_propagate_int (G_TASK (res), error); ++ if (val < 0) ++ return MM_BEARER_CONNECTION_STATUS_UNKNOWN; ++ ++ return (MMBearerConnectionStatus) val; ++} ++ ++static void ++reload_connection_status_ready (MbimDevice *device, ++ GAsyncResult *res, ++ GTask *task) ++{ ++ MMBearerMbim *self; ++ guint32 session_id; ++ MbimActivationState activation_state; ++ MMBearerConnectionStatus bearer_connection_status = MM_BEARER_CONNECTION_STATUS_UNKNOWN; ++ g_autoptr(MbimMessage) response = NULL; ++ g_autoptr(GError) error = NULL; ++ ++ self = g_task_get_source_object (task); ++ ++ response = mbim_device_command_finish (device, res, &error); ++ if (!response || ++ !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) || ++ !mbim_message_connect_response_parse ( ++ response, ++ &session_id, ++ &activation_state, ++ NULL, /* voice_call_state */ ++ NULL, /* ip_type */ ++ NULL, /* context_type */ ++ NULL, /* nw_error */ ++ &error)) { ++ g_prefix_error (&error, "Cannot load session ID '%u' status: ", ++ mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (self))); ++ g_task_return_error (task, error); ++ g_object_unref (task); ++ return; ++ } ++ ++ mm_obj_dbg (self, "session ID '%u': %s", session_id, mbim_activation_state_get_string (activation_state)); ++ ++ switch (activation_state) { ++ case MBIM_ACTIVATION_STATE_ACTIVATED: ++ case MBIM_ACTIVATION_STATE_ACTIVATING: ++ /* for the purposes of the sync operation, it's fine to map ACTIVATING ++ * to CONNECTED, as we're really going to ignore that state in the actual ++ * processing of the logic. */ ++ bearer_connection_status = MM_BEARER_CONNECTION_STATUS_CONNECTED; ++ break; ++ case MBIM_ACTIVATION_STATE_DEACTIVATING: ++ bearer_connection_status = MM_BEARER_CONNECTION_STATUS_DISCONNECTING; ++ break; ++ case MBIM_ACTIVATION_STATE_DEACTIVATED: ++ bearer_connection_status = MM_BEARER_CONNECTION_STATUS_DISCONNECTED; ++ break; ++ case MBIM_ACTIVATION_STATE_UNKNOWN: ++ default: ++ break; ++ } ++ ++ if (bearer_connection_status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) ++ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, ++ "Cannot load session ID '%u' status", ++ mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (self))); ++ else ++ g_task_return_int (task, bearer_connection_status); ++ g_object_unref (task); ++} ++ ++static void ++reload_connection_status (MMBaseBearer *self, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ MMPortMbim *mbim; ++ GTask *task = NULL; ++ g_autoptr(MbimMessage) message = NULL; ++ ++ if (!peek_ports (self, &mbim, NULL, callback, user_data)) ++ return; ++ ++ task = g_task_new (self, NULL, callback, user_data); ++ message = mbim_message_connect_query_new (mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (self)), ++ MBIM_ACTIVATION_STATE_UNKNOWN, ++ MBIM_VOICE_CALL_STATE_NONE, ++ MBIM_CONTEXT_IP_TYPE_DEFAULT, ++ mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET), ++ 0, ++ NULL); ++ mbim_device_command (mm_port_mbim_peek_device (mbim), ++ message, ++ 10, ++ NULL, ++ (GAsyncReadyCallback)reload_connection_status_ready, ++ task); ++} ++ ++#endif /* WITH_SYSTEMD_SUSPEND_RESUME */ ++ ++/*****************************************************************************/ ++ + MMBaseBearer * + mm_bearer_mbim_new (MMBroadbandModemMbim *modem, + MMBearerProperties *config, +@@ -1524,6 +1635,10 @@ mm_bearer_mbim_class_init (MMBearerMbimClass *klass) + base_bearer_class->reload_stats_finish = reload_stats_finish; + base_bearer_class->load_connection_status = NULL; + base_bearer_class->load_connection_status_finish = NULL; ++#if defined WITH_SYSTEMD_SUSPEND_RESUME ++ base_bearer_class->reload_connection_status = reload_connection_status; ++ base_bearer_class->reload_connection_status_finish = reload_connection_status_finish; ++#endif + + properties[PROP_SESSION_ID] = + g_param_spec_uint (MM_BEARER_MBIM_SESSION_ID, +-- +2.31.1 + diff --git a/temp/modemmanager/0039-ModemManager-backport-Quick-Suspend-Resume-patches-t.patch b/temp/modemmanager/0039-ModemManager-backport-Quick-Suspend-Resume-patches-t.patch new file mode 100644 index 000000000..62c084773 --- /dev/null +++ b/temp/modemmanager/0039-ModemManager-backport-Quick-Suspend-Resume-patches-t.patch @@ -0,0 +1,207 @@ +From f36e79292763a06b2548619858a54562149c9857 Mon Sep 17 00:00:00 2001 +From: Dylan Van Assche +Date: Thu, 27 May 2021 21:25:16 +0200 +Subject: [PATCH 39/39] ModemManager: backport Quick Suspend/Resume patches to + MM 1.16.X + +--- + src/kerneldevice/mm-kernel-device.c | 18 ++++++++++++++++++ + src/kerneldevice/mm-kernel-device.h | 4 ++++ + src/mm-base-modem.c | 4 ++++ + src/mm-base-modem.h | 23 +++++++++++++++++++++++ + src/mm-bearer-mbim.c | 1 + + src/mm-bearer-mbim.h | 1 + + src/mm-bearer-qmi.c | 1 + + src/mm-bearer-qmi.h | 1 + + src/mm-iface-modem.h | 3 --- + 9 files changed, 53 insertions(+), 3 deletions(-) + +diff --git a/src/kerneldevice/mm-kernel-device.c b/src/kerneldevice/mm-kernel-device.c +index 464a3800..08d9d4a1 100644 +--- a/src/kerneldevice/mm-kernel-device.c ++++ b/src/kerneldevice/mm-kernel-device.c +@@ -26,6 +26,16 @@ static void log_object_iface_init (MMLogObjectInterface *iface); + + G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MMKernelDevice, mm_kernel_device, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) ++enum { ++ PROP_0, ++ PROP_LOWER_DEVICE, ++ PROP_LAST ++}; ++ ++struct _MMKernelDevicePrivate { ++ MMKernelDevice *lower_device; ++}; ++ + + /*****************************************************************************/ + +@@ -125,6 +135,12 @@ mm_kernel_device_get_physdev_product (MMKernelDevice *self) + NULL); + } + ++MMKernelDevice * ++mm_kernel_device_peek_lower_device (MMKernelDevice *self) ++{ ++ return self->priv->lower_device; ++} ++ + gint + mm_kernel_device_get_interface_class (MMKernelDevice *self) + { +@@ -347,6 +363,8 @@ log_object_build_id (MMLogObject *_self) + static void + mm_kernel_device_init (MMKernelDevice *self) + { ++ /* Initialize private data */ ++ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_KERNEL_DEVICE, MMKernelDevicePrivate); + } + + static void +diff --git a/src/kerneldevice/mm-kernel-device.h b/src/kerneldevice/mm-kernel-device.h +index 45b270d5..678b3410 100644 +--- a/src/kerneldevice/mm-kernel-device.h ++++ b/src/kerneldevice/mm-kernel-device.h +@@ -28,9 +28,11 @@ + + typedef struct _MMKernelDevice MMKernelDevice; + typedef struct _MMKernelDeviceClass MMKernelDeviceClass; ++typedef struct _MMKernelDevicePrivate MMKernelDevicePrivate; + + struct _MMKernelDevice { + GObject parent; ++ MMKernelDevicePrivate *priv; + }; + + struct _MMKernelDeviceClass { +@@ -89,6 +91,8 @@ const gchar *mm_kernel_device_get_physdev_subsystem (MMKernelDevice *self); + const gchar *mm_kernel_device_get_physdev_manufacturer (MMKernelDevice *self); + const gchar *mm_kernel_device_get_physdev_product (MMKernelDevice *self); + ++MMKernelDevice *mm_kernel_device_peek_lower_device (MMKernelDevice *self); ++ + gboolean mm_kernel_device_cmp (MMKernelDevice *a, MMKernelDevice *b); + + /* Standard properties are usually associated to single ports */ +diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c +index 580103ba..e54add87 100644 +--- a/src/mm-base-modem.c ++++ b/src/mm-base-modem.c +@@ -115,6 +115,10 @@ struct _MMBaseModemPrivate { + /* MBIM ports */ + GList *mbim; + #endif ++ ++ /* Additional port links grabbed after having ++ * organized ports */ ++ GHashTable *link_ports; + }; + + guint +diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h +index d9538251..c52f0e18 100644 +--- a/src/mm-base-modem.h ++++ b/src/mm-base-modem.h +@@ -63,6 +63,11 @@ typedef struct _MMBaseModemPrivate MMBaseModemPrivate; + #define MM_BASE_MODEM_VENDOR_ID "base-modem-vendor-id" + #define MM_BASE_MODEM_PRODUCT_ID "base-modem-product-id" + #define MM_BASE_MODEM_REPROBE "base-modem-reprobe" ++#define MM_BASE_MODEM_DATA_NET_SUPPORTED "base-modem-data-net-supported" ++#define MM_BASE_MODEM_DATA_TTY_SUPPORTED "base-modem-data-tty-supported" ++ ++#define MM_BASE_MODEM_SIGNAL_LINK_PORT_GRABBED "base-modem-link-port-grabbed" ++#define MM_BASE_MODEM_SIGNAL_LINK_PORT_RELEASED "base-modem-link-port-released" + + struct _MMBaseModem { + MmGdbusObjectSkeleton parent; +@@ -132,6 +137,24 @@ gboolean mm_base_modem_grab_port (MMBaseModem *self, + MMPortSerialAtFlag at_pflags, + GError **error); + ++gboolean mm_base_modem_grab_link_port (MMBaseModem *self, ++ MMKernelDevice *kernel_device, ++ GError **error); ++gboolean mm_base_modem_release_link_port (MMBaseModem *self, ++ const gchar *subsystem, ++ const gchar *name, ++ GError **error); ++ ++void mm_base_modem_wait_link_port (MMBaseModem *self, ++ const gchar *subsystem, ++ const gchar *name, ++ guint timeout_ms, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++MMPort *mm_base_modem_wait_link_port_finish (MMBaseModem *self, ++ GAsyncResult *res, ++ GError **error); ++ + gboolean mm_base_modem_has_at_port (MMBaseModem *self); + + gboolean mm_base_modem_organize_ports (MMBaseModem *self, +diff --git a/src/mm-bearer-mbim.c b/src/mm-bearer-mbim.c +index f0479ebb..99270474 100644 +--- a/src/mm-bearer-mbim.c ++++ b/src/mm-bearer-mbim.c +@@ -47,6 +47,7 @@ struct _MMBearerMbimPrivate { + guint32 session_id; + + MMPort *data; ++ MMPort *link; + }; + + /*****************************************************************************/ +diff --git a/src/mm-bearer-mbim.h b/src/mm-bearer-mbim.h +index 0d97d8d9..48c1c846 100644 +--- a/src/mm-bearer-mbim.h ++++ b/src/mm-bearer-mbim.h +@@ -24,6 +24,7 @@ + + #include "mm-base-bearer.h" + #include "mm-broadband-modem-mbim.h" ++#include "mm-kernel-device.h" + + #define MM_TYPE_BEARER_MBIM (mm_bearer_mbim_get_type ()) + #define MM_BEARER_MBIM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BEARER_MBIM, MMBearerMbim)) +diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c +index 967594bf..52e155d7 100644 +--- a/src/mm-bearer-qmi.c ++++ b/src/mm-bearer-qmi.c +@@ -56,6 +56,7 @@ struct _MMBearerQmiPrivate { + guint event_report_ipv6_indication_id; + + MMPort *data; ++ MMPort *link; + guint32 packet_data_handle_ipv4; + guint32 packet_data_handle_ipv6; + }; +diff --git a/src/mm-bearer-qmi.h b/src/mm-bearer-qmi.h +index d75773f5..2a3c881c 100644 +--- a/src/mm-bearer-qmi.h ++++ b/src/mm-bearer-qmi.h +@@ -26,6 +26,7 @@ + + #include "mm-base-bearer.h" + #include "mm-broadband-modem-qmi.h" ++#include "mm-kernel-device.h" + + #define MM_TYPE_BEARER_QMI (mm_bearer_qmi_get_type ()) + #define MM_BEARER_QMI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BEARER_QMI, MMBearerQmi)) +diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h +index 5ba2167c..110a839b 100644 +--- a/src/mm-iface-modem.h ++++ b/src/mm-iface-modem.h +@@ -460,9 +460,6 @@ gboolean mm_iface_modem_disable_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error); + +-/* Shutdown Modem interface */ +-void mm_iface_modem_shutdown (MMIfaceModem *self); +- + /* Helper to return an error when the modem is in failed state and so it + * cannot process a given method invocation + */ +-- +2.31.1 + diff --git a/temp/modemmanager/APKBUILD b/temp/modemmanager/APKBUILD new file mode 100644 index 000000000..05eb81027 --- /dev/null +++ b/temp/modemmanager/APKBUILD @@ -0,0 +1,166 @@ +# Forked from Alpine to apply quick suspend/resume patches for the PinePhone EG25-G modem + +pkgname=modemmanager +pkgver=9999_git20210528 +_pkgver=1.16.6 +pkgrel=0 +pkgdesc="ModemManager library" +url="http://www.freedesktop.org/wiki/Software/ModemManager" +arch="all !mips !mips64 !s390x" # polkit +license="GPL-2.0-or-later AND LGPL-2.1-or-later" +depends_dev="libmm-glib" +makedepends="$depends_dev gobject-introspection-dev gtk-doc vala + libgudev-dev polkit-dev libmbim-dev libqmi-dev linux-headers libqrtr-glib-dev gettext-dev glib-dev" +makedepends="$makedepends automake autoconf autoconf-archive libtool" +checkdepends="glib-dev" +options="!check" # https://bugs.freedesktop.org/show_bug.cgi?id=101197 +subpackages=" + $pkgname-lang + $pkgname-doc + libmm-glib:libmm + $pkgname-dev + $pkgname-openrc + $pkgname-bash-completion + " +# https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/511/commits +# patches are integrated in these patches already +source="https://www.freedesktop.org/software/ModemManager/ModemManager-$_pkgver.tar.xz + 0001-base-manager-add-quick-suspend-resume-base.patch + 0002-base-manager-make-sure-g_autoptr-variables-are-initi.patch + 0003-base-manager-don-t-assume-a-MMDevice-always-holds-a-.patch + 0004-base-manager-avoid-using-the-mm_-prefix-for-static-p.patch + 0005-base-modem-fix-modem_sync-operation-handling.patch + 0006-base-modem-don-t-fail-if-sync-isn-t-implemented.patch + 0007-base-modem-make-sync-available-only-if-suspend-resum.patch + 0008-broadband-modem-ignore-cancellation-during-sync.patch + 0009-broadband-modem-skip-synchronization-after-resume-if.patch + 0010-iface-modem-time-synchronize-state-when-resuming.patch + 0011-broadband-modem-skip-time-interface-sync-if-no-time-.patch + 0012-iface-modem-time-ignore-cancellation-during-sync.patch + 0013-iface-modem-3gpp-synchronize-state-when-resuming.patch + 0014-iface-modem-3gpp-use-g_autoptr-for-the-MMBearerPrope.patch + 0015-iface-modem-3gpp-fix-double-GError-free-on-registrat.patch + 0016-iface-modem-3gpp-remove-redundant-log-message.patch + 0017-iface-modem-3gpp-ignore-cancellation-during-sync.patch + 0018-broadband-modem-fix-type-in-the-ready-for-iface_mode.patch + 0019-broadband-modem-skip-3GPP-interface-sync-if-no-3GPP-.patch + 0020-iface-modem-synchronize-state-when-resuming.patch + 0021-broadband-modem-fail-synchronization-if-no-modem-exp.patch + 0022-broadband-modem-fix-state-machine-logic-when-synchro.patch + 0023-broadband-modem-abort-sync-if-locked-SIM-card-found.patch + 0024-iface-modem-remove-the-signal-quality-enforced-refre.patch + 0025-iface-modem-ignore-cancellation-during-sync.patch + 0026-base-bearer-synchronize-state-when-resuming.patch + 0027-base-bearer-improve-comments-of-the-load-reload_conn.patch + 0028-base-bearer-fix-connection-reload-completion.patch + 0029-base-bearer-propagate-the-new-connection-status-afte.patch + 0030-iface-modem-bearer-list-sync-all-bearers-one-after-t.patch + 0031-base-bearer-ignore-cancellation-during-sync.patch + 0032-broadband-bearer-reuse-the-same-method-for-load-and-.patch + 0033-novatel-lte-reuse-the-same-method-for-load-and-reloa.patch + 0034-sierra-reuse-the-same-method-for-load-and-reload.patch + 0035-cinterion-reuse-the-same-method-for-load-and-reload.patch + 0036-plugins-ignore-reload_connection_status-where-not-su.patch + 0037-bearer-qmi-implement-reload_connection_status-for-th.patch + 0038-bearer-mbim-implement-reload_connection_status.patch + 0039-ModemManager-backport-Quick-Suspend-Resume-patches-t.patch + $pkgname.rules + $pkgname.initd" +builddir="$srcdir"/ModemManager-$_pkgver + +build() { + ./configure \ + --build=$CBUILD \ + --host=$CHOST \ + --prefix=/usr \ + --sysconfdir=/etc \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --localstatedir=/var \ + --with-polkit=permissive \ + --enable-plugin-qcom-soc \ + --enable-gtk-doc \ + --disable-static \ + --enable-vala=yes \ + --with-systemd-suspend-resume=yes + make +} + +libmm() { + cd "$builddir" + mkdir -p "$subpkgdir" + make DESTDIR="$subpkgdir" -C libmm-glib install + # move dev files to modemmnager-dev + mv -f "$subpkgdir/usr/include/libmm-glib" "$pkgdir/usr/include/" + mv -f "$subpkgdir/usr/share/gir-1.0" "$pkgdir/usr/share/" + rmdir "$subpkgdir/usr/include" "$subpkgdir/usr/share" +} + +package() { + make DESTDIR="$pkgdir" install + make DESTDIR="$pkgdir" -C libmm-glib uninstall + rmdir "$pkgdir"/usr/lib/girepository-1.0 # in libmm-glib + rm -rf "$pkgdir"/usr/share/dbus-1/system-services #systemd-service + mkdir -p "$pkgdir/usr/share/polkit-1/rules.d" + install -m644 -D "$srcdir/$pkgname.rules" \ + "$pkgdir/usr/share/polkit-1/rules.d/01-org.freedesktop.ModemManager.rules" + install -m755 -D "$srcdir/$pkgname.initd" \ + "$pkgdir/etc/init.d/$pkgname" + # post-install message + mkdir -p "$pkgdir/usr/share/doc/$pkgname" + cat > $pkgdir/usr/share/doc/$pkgname/README.alpine <