aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2025-02-22 17:20:20 +0100
committerDan Williams <dan@ioncontrol.co>2025-03-28 20:53:52 +0000
commit2878833f5c83fe112f579865a6d318ce8413f452 (patch)
treef9761ec5a2a79de9f36b35246be0c24e8b913d37
parentd8135be6e2c132e59d3fbe9d231afa88b1e5e2b2 (diff)
modem: Allow to set current channel list
This adds support for setting the channels to override the boot up modem defaults: ``` busctl --system call org.freedesktop.ModemManager1 /org/freedesktop/ModemManager1/Modem/0 org.freedesktop.ModemManager1.Modem.CellBroadcast SetChannels 'a(uu)' 1 0 9999 busctl --system get-property org.freedesktop.ModemManager1 /org/freedesktop/ModemManager1/Modem/0 org.freedesktop.ModemManager1.Modem.CellBroadcast Channels a(uu) 1 0 9999 ``` Closes: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/934 Signed-off-by: Guido Günther <agx@sigxcpu.org>
-rw-r--r--introspection/org.freedesktop.ModemManager1.Modem.CellBroadcast.xml22
-rw-r--r--src/mm-broadband-modem.c62
-rw-r--r--src/mm-iface-modem-cell-broadcast.c102
-rw-r--r--src/mm-iface-modem-cell-broadcast.h9
4 files changed, 195 insertions, 0 deletions
diff --git a/introspection/org.freedesktop.ModemManager1.Modem.CellBroadcast.xml b/introspection/org.freedesktop.ModemManager1.Modem.CellBroadcast.xml
index 9e8584a1..572e094c 100644
--- a/introspection/org.freedesktop.ModemManager1.Modem.CellBroadcast.xml
+++ b/introspection/org.freedesktop.ModemManager1.Modem.CellBroadcast.xml
@@ -87,5 +87,27 @@
-->
<property name="CellBroadcasts" type="ao" access="read" />
+ <!--
+ SetChannels:
+ @channels: The list of channels
+
+ Set the list of channels to receive Cell Broadcasts for.
+
+ Since: 1.24
+ -->
+ <method name="SetChannels">
+ <arg name="channels" type="a(uu)" direction="in" />
+ </method>
+
+ <!--
+ Channels:
+
+ The list of channels that cell broadcast messages are
+ received for.
+
+ Since: 1.24
+ -->
+ <property name="Channels" type="a(uu)" access="read" />
+
</interface>
</node>
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 4b13fd09..ffabec2e 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -10603,6 +10603,66 @@ modem_cell_broadcast_create_cbm (MMIfaceModemCellBroadcast *self)
return mm_base_cbm_new (MM_BASE_MODEM (self));
}
+/***********************************************************************************/
+/* Get channels (CellBroadcast interface) */
+
+static gboolean
+modem_cell_broadcast_set_channels_finish (MMIfaceModemCellBroadcast *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+modem_cell_broadcast_set_channels_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+modem_cell_broadcast_set_channels (MMIfaceModemCellBroadcast *self,
+ GArray *channels,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr (GString) cmd = g_string_new ("+CSCB=0,\"");
+ guint i;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ for (i = 0; i < channels->len; i++) {
+ MMCellBroadcastChannels ch = g_array_index (channels, MMCellBroadcastChannels, i);
+
+ if (i > 0)
+ g_string_append_c (cmd, ',');
+
+ if (ch.start == ch.end)
+ g_string_append_printf (cmd, "%u", ch.start);
+ else
+ g_string_append_printf (cmd, "%u-%u", ch.start, ch.end);
+ }
+ g_string_append (cmd, "\",\"\"");
+
+ mm_obj_dbg (self, "Setting channels...");
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ cmd->str,
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)modem_cell_broadcast_set_channels_ready,
+ task);
+}
+
/*********************************************************/
/* Check CellBroadcast support (CellBroadcast interface) */
@@ -14344,6 +14404,8 @@ iface_modem_cell_broadcast_init (MMIfaceModemCellBroadcastInterface *iface)
iface->setup_unsolicited_events_finish = modem_cell_broadcast_setup_cleanup_unsolicited_events_finish;
iface->cleanup_unsolicited_events = modem_cell_broadcast_cleanup_unsolicited_events;
iface->cleanup_unsolicited_events_finish = modem_cell_broadcast_setup_cleanup_unsolicited_events_finish;
+ iface->set_channels = modem_cell_broadcast_set_channels;
+ iface->set_channels_finish = modem_cell_broadcast_set_channels_finish;
iface->create_cbm = modem_cell_broadcast_create_cbm;
}
diff --git a/src/mm-iface-modem-cell-broadcast.c b/src/mm-iface-modem-cell-broadcast.c
index 8e5af67c..a4ab41e3 100644
--- a/src/mm-iface-modem-cell-broadcast.c
+++ b/src/mm-iface-modem-cell-broadcast.c
@@ -42,6 +42,102 @@ mm_iface_modem_cell_broadcast_bind_simple_status (MMIfaceModemCellBroadcast *sel
/*****************************************************************************/
+
+typedef struct {
+ MmGdbusModemCellBroadcast *skeleton;
+ GDBusMethodInvocation *invocation;
+ MMIfaceModemCellBroadcast *self;
+ GArray *channels;
+} HandleSetChannelsCellBroadcastContext;
+
+static void
+handle_set_channels_context_free (HandleSetChannelsCellBroadcastContext *ctx)
+{
+ g_object_unref (ctx->skeleton);
+ g_object_unref (ctx->invocation);
+ g_object_unref (ctx->self);
+ g_array_unref (ctx->channels);
+ g_slice_free (HandleSetChannelsCellBroadcastContext, ctx);
+}
+
+static void
+set_channels_ready (MMIfaceModemCellBroadcast *self,
+ GAsyncResult *res,
+ HandleSetChannelsCellBroadcastContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels_finish (self, res, &error))
+ mm_dbus_method_invocation_take_error (ctx->invocation, error);
+ else {
+ mm_gdbus_modem_cell_broadcast_set_channels (ctx->skeleton,
+ mm_common_cell_broadcast_channels_garray_to_variant (ctx->channels));
+ mm_gdbus_modem_cell_broadcast_complete_set_channels (ctx->skeleton, ctx->invocation);
+ }
+
+ handle_set_channels_context_free (ctx);
+}
+
+static void
+handle_set_channels_auth_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ HandleSetChannelsCellBroadcastContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_authorize_finish (self, res, &error)) {
+ mm_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_set_channels_context_free (ctx);
+ return;
+ }
+
+ /* Validate channels (either number or range) */
+ if (!mm_validate_cbs_channels (ctx->channels, &error)) {
+ mm_dbus_method_invocation_return_gerror (ctx->invocation, error);
+ handle_set_channels_context_free (ctx);
+ return;
+ }
+
+ /* Check if plugin implements it */
+ if (!MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels ||
+ !MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels_finish) {
+ mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot set channels: not implemented");
+ handle_set_channels_context_free (ctx);
+ return;
+ }
+
+ /* Request to change channels */
+ mm_obj_info (self, "processing user request to set channels...");
+ MM_IFACE_MODEM_CELL_BROADCAST_GET_IFACE (self)->set_channels (ctx->self,
+ ctx->channels,
+ (GAsyncReadyCallback)set_channels_ready,
+ ctx);
+}
+
+static gboolean
+handle_set_channels (MmGdbusModemCellBroadcast *skeleton,
+ GDBusMethodInvocation *invocation,
+ GVariant *channels,
+ MMIfaceModemCellBroadcast *self)
+{
+ HandleSetChannelsCellBroadcastContext *ctx;
+
+ ctx = g_slice_new0 (HandleSetChannelsCellBroadcastContext);
+ ctx->skeleton = g_object_ref (skeleton);
+ ctx->invocation = g_object_ref (invocation);
+ ctx->self = g_object_ref (self);
+ ctx->channels = mm_common_cell_broadcast_channels_variant_to_garray (channels);
+ mm_base_modem_authorize (MM_BASE_MODEM (self),
+ invocation,
+ MM_AUTHORIZATION_DEVICE_CONTROL,
+ (GAsyncReadyCallback)handle_set_channels_auth_ready,
+ ctx);
+ return TRUE;
+}
+
+/*****************************************************************************/
+
typedef struct {
MmGdbusModemCellBroadcast *skeleton;
GDBusMethodInvocation *invocation;
@@ -315,6 +411,12 @@ interface_initialization_step (GTask *task)
case INITIALIZATION_STEP_LAST:
/* We are done without errors! */
+
+ /* Handle method invocations */
+ g_signal_connect (ctx->skeleton,
+ "handle-set-channels",
+ G_CALLBACK (handle_set_channels),
+ self);
g_signal_connect (ctx->skeleton,
"handle-delete",
G_CALLBACK (handle_delete),
diff --git a/src/mm-iface-modem-cell-broadcast.h b/src/mm-iface-modem-cell-broadcast.h
index 5990b865..34cd1b47 100644
--- a/src/mm-iface-modem-cell-broadcast.h
+++ b/src/mm-iface-modem-cell-broadcast.h
@@ -76,6 +76,15 @@ struct _MMIfaceModemCellBroadcastInterface {
/* Create Cbm objects */
MMBaseCbm * (* create_cbm) (MMIfaceModemCellBroadcast *self);
+
+ /* Set channel list */
+ void (* set_channels) (MMIfaceModemCellBroadcast *self,
+ GArray *channels,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* set_channels_finish) (MMIfaceModemCellBroadcast *self,
+ GAsyncResult *res,
+ GError **error);
};
/* Initialize CellBroadcast interface (async) */