blob: 3ef5c31554e1a76ebc6116abaa6b16efa6e7bf0a [file] [log] [blame]
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01001/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details:
12 *
13 * Copyright (C) 2011 Google, Inc.
14 */
15
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +010016#include <ModemManager.h>
Aleksander Morgadoc250fa32012-10-03 12:46:37 +020017#define _LIBMM_INSIDE_MM
18#include <libmm-glib.h>
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +010019
Aleksander Morgadoc9c94212011-12-22 20:41:11 +010020#include "mm-modem-helpers.h"
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +010021#include "mm-iface-modem.h"
Aleksander Morgado875ade32017-03-07 11:12:51 +010022#include "mm-iface-modem-3gpp.h"
23#include "mm-iface-modem-cdma.h"
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +010024#include "mm-base-modem.h"
Nathan Williams3c41ce52012-01-23 11:04:49 -050025#include "mm-base-modem-at.h"
Aleksander Morgado5358d6f2014-07-06 16:50:30 +020026#include "mm-base-sim.h"
Aleksander Morgado776cc662011-12-12 20:22:51 +010027#include "mm-bearer-list.h"
Aleksander Morgadoe7409b62020-08-01 09:59:27 +020028#include "mm-private-boxed-types.h"
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +010029#include "mm-log-object.h"
Aleksander Morgado64f49c02012-02-28 23:24:53 +010030#include "mm-context.h"
Aleksander Morgadob8f6fb52020-10-22 12:07:09 +020031#if defined WITH_QMI
32# include "mm-broadband-modem-qmi.h"
33#endif
Aleksander Morgado6defec22020-10-22 11:52:46 +020034#if defined WITH_MBIM
35# include "mm-broadband-modem-mbim.h"
36#endif
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +010037
Aleksander Morgado8ad868c2017-05-30 20:09:55 +020038#define SIGNAL_QUALITY_RECENT_TIMEOUT_SEC 60
Aleksander Morgado953be3e2011-12-29 11:31:27 +010039
Aleksander Morgado8ad868c2017-05-30 20:09:55 +020040#define SIGNAL_CHECK_INITIAL_RETRIES 5
41#define SIGNAL_CHECK_INITIAL_TIMEOUT_SEC 3
42#define SIGNAL_CHECK_TIMEOUT_SEC 30
43
44#define STATE_UPDATE_CONTEXT_TAG "state-update-context-tag"
45#define SIGNAL_QUALITY_UPDATE_CONTEXT_TAG "signal-quality-update-context-tag"
46#define SIGNAL_CHECK_CONTEXT_TAG "signal-check-context-tag"
47#define RESTART_INITIALIZE_IDLE_TAG "restart-initialize-tag"
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +010048
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +010049static GQuark state_update_context_quark;
Aleksander Morgadobe7cee22011-12-31 11:34:58 +010050static GQuark signal_quality_update_context_quark;
Aleksander Morgado8ad868c2017-05-30 20:09:55 +020051static GQuark signal_check_context_quark;
Aleksander Morgado1cb58312013-04-05 08:54:09 +020052static GQuark restart_initialize_idle_quark;
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +010053
Aleksander Morgado0c009a22011-12-28 14:00:15 +010054/*****************************************************************************/
55
Teijo Kinnunen06148ab2020-09-08 09:52:31 +000056gboolean
57mm_iface_modem_check_for_sim_swap_finish (MMIfaceModem *self,
58 GAsyncResult *res,
59 GError **error)
60{
61 return g_task_propagate_boolean (G_TASK (res), error);
62}
63
64static void
65explicit_check_for_sim_swap_ready (MMIfaceModem *self,
66 GAsyncResult *res,
67 GTask *task)
68{
69 GError *error = NULL;
70
71 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish (self, res, &error)) {
72 mm_obj_warn (self, "SIM swap check failed: %s", error->message);
73 g_task_return_error (task, error);
74 } else {
75 mm_obj_dbg (self, "SIM swap check completed");
76 g_task_return_boolean (task, TRUE);
77 }
78 g_object_unref (task);
79}
80
81void
82mm_iface_modem_check_for_sim_swap (MMIfaceModem *self,
83 guint slot_index,
84 const gchar *iccid,
85 GAsyncReadyCallback callback,
86 gpointer user_data)
87{
88 GTask *task;
89
90 task = g_task_new (self, NULL, callback, user_data);
91
92 /* Slot index 0 is used when slot is not known, assumingly on a modem with just one SIM slot */
93 if (slot_index != 0) {
94 MmGdbusModem *skeleton;
95 guint primary_slot;
96
97 g_object_get (self,
98 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
99 NULL);
100
101 g_assert (skeleton);
102
103 primary_slot = mm_gdbus_modem_get_primary_sim_slot (MM_GDBUS_MODEM (skeleton));
104 g_object_unref (skeleton);
105
106 /* Check that it's really the primary slot whose iccid has changed */
107 if (primary_slot && primary_slot != slot_index) {
108 mm_obj_dbg (self, "checking for SIM swap ignored: status changed in slot %u, but primary is %u", slot_index, primary_slot);
109 g_task_return_boolean (task, TRUE);
110 g_object_unref (task);
111 return;
112 }
113 }
114
115 if (MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap &&
116 MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish) {
117 mm_obj_dbg (self, "start checking for SIM swap in slot %u", slot_index);
118 MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap (
119 self,
120 iccid,
121 (GAsyncReadyCallback)explicit_check_for_sim_swap_ready,
122 task);
123 return;
124 }
125
126 g_task_return_boolean (task, FALSE);
127 g_object_unref (task);
128}
129
130/*****************************************************************************/
131
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100132void
133mm_iface_modem_bind_simple_status (MMIfaceModem *self,
Aleksander Morgadocd63df92012-03-01 13:17:12 +0100134 MMSimpleStatus *status)
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100135{
136 MmGdbusModem *skeleton;
137
138 g_object_get (self,
139 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
140 NULL);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200141 if (!skeleton)
142 return;
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100143
144 g_object_bind_property (skeleton, "state",
Aleksander Morgadocd63df92012-03-01 13:17:12 +0100145 status, MM_SIMPLE_PROPERTY_STATE,
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100146 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
147
148 g_object_bind_property (skeleton, "signal-quality",
Aleksander Morgadocd63df92012-03-01 13:17:12 +0100149 status, MM_SIMPLE_PROPERTY_SIGNAL_QUALITY,
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100150 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
151
Aleksander Morgado212d00c2013-05-29 10:47:53 +0200152 g_object_bind_property (skeleton, "current-bands",
153 status, MM_SIMPLE_PROPERTY_CURRENT_BANDS,
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100154 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
155
156 g_object_bind_property (skeleton, "access-technologies",
Aleksander Morgadocd63df92012-03-01 13:17:12 +0100157 status, MM_SIMPLE_PROPERTY_ACCESS_TECHNOLOGIES,
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100158 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
159
160 g_object_unref (skeleton);
161}
162
163/*****************************************************************************/
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200164/* Helper method to wait for a final state */
165
Ben Chanaa74ea12013-09-17 14:47:09 -0700166#define MODEM_STATE_IS_INTERMEDIATE(state) \
167 (state == MM_MODEM_STATE_INITIALIZING || \
168 state == MM_MODEM_STATE_DISABLING || \
169 state == MM_MODEM_STATE_ENABLING || \
170 state == MM_MODEM_STATE_DISCONNECTING || \
171 state == MM_MODEM_STATE_CONNECTING)
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200172
173typedef struct {
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200174 MMModemState final_state;
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200175 gulong state_changed_id;
176 guint state_changed_wait_id;
177} WaitForFinalStateContext;
178
179static void
Ben Chan347610a2017-06-30 03:52:13 -0700180wait_for_final_state_context_complete (GTask *task,
181 MMModemState state,
182 GError *error)
183{
184 MMIfaceModem *self;
185 WaitForFinalStateContext *ctx;
186
187 self = g_task_get_source_object (task);
188 ctx = g_task_get_task_data (task);
189
190 /* The callback associated with 'task' may update the modem state.
191 * Disconnect the signal handler for modem state changes before completing
192 * 'task' in order to prevent state_changed from being invoked, which
193 * invokes wait_for_final_state_context_complete again. */
194 if (ctx->state_changed_id) {
195 g_signal_handler_disconnect (self, ctx->state_changed_id);
196 ctx->state_changed_id = 0;
197 }
198
199 /* Remove any outstanding timeout on waiting for state change. */
200 if (ctx->state_changed_wait_id) {
201 g_source_remove (ctx->state_changed_wait_id);
202 ctx->state_changed_wait_id = 0;
203 }
204
205 if (error)
206 g_task_return_error (task, error);
207 else
208 g_task_return_int (task, state);
209
210 g_object_unref (task);
211}
212
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200213MMModemState
214mm_iface_modem_wait_for_final_state_finish (MMIfaceModem *self,
215 GAsyncResult *res,
216 GError **error)
217{
Ben Chan347610a2017-06-30 03:52:13 -0700218 GError *inner_error = NULL;
219 gssize value;
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200220
Ben Chan347610a2017-06-30 03:52:13 -0700221 value = g_task_propagate_int (G_TASK (res), &inner_error);
222 if (inner_error) {
223 g_propagate_error (error, inner_error);
224 return MM_MODEM_STATE_UNKNOWN;
225 }
226 return (MMModemState)value;
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200227}
228
229static gboolean
Ben Chan347610a2017-06-30 03:52:13 -0700230state_changed_wait_expired (GTask *task)
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200231{
Ben Chan347610a2017-06-30 03:52:13 -0700232 GError *error;
233
234 error = g_error_new (MM_CORE_ERROR,
235 MM_CORE_ERROR_RETRY,
236 "Too much time waiting to get to a final state");
237 wait_for_final_state_context_complete (task, MM_MODEM_STATE_UNKNOWN, error);
Aleksander Morgadoffde4292015-12-02 17:07:11 +0100238 return G_SOURCE_REMOVE;
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200239}
240
241static void
242state_changed (MMIfaceModem *self,
243 GParamSpec *spec,
Ben Chan347610a2017-06-30 03:52:13 -0700244 GTask *task)
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200245{
Ben Chan347610a2017-06-30 03:52:13 -0700246 WaitForFinalStateContext *ctx;
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200247 MMModemState state = MM_MODEM_STATE_UNKNOWN;
248
249 g_object_get (self,
250 MM_IFACE_MODEM_STATE, &state,
251 NULL);
252
253 /* Are we in a final state already? */
254 if (MODEM_STATE_IS_INTERMEDIATE (state))
255 return;
256
Ben Chan347610a2017-06-30 03:52:13 -0700257 ctx = g_task_get_task_data (task);
258
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200259 /* If we want a specific final state and this is not the one we were
260 * looking for, then skip */
261 if (ctx->final_state != MM_MODEM_STATE_UNKNOWN &&
262 state != MM_MODEM_STATE_UNKNOWN &&
263 state != ctx->final_state)
264 return;
265
266 /* Done! */
Ben Chan347610a2017-06-30 03:52:13 -0700267 wait_for_final_state_context_complete (task, state, NULL);
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200268}
269
270void
271mm_iface_modem_wait_for_final_state (MMIfaceModem *self,
272 MMModemState final_state,
273 GAsyncReadyCallback callback,
274 gpointer user_data)
275{
276 MMModemState state = MM_MODEM_STATE_UNKNOWN;
277 WaitForFinalStateContext *ctx;
Ben Chan347610a2017-06-30 03:52:13 -0700278 GTask *task;
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200279
Ben Chan347610a2017-06-30 03:52:13 -0700280 task = g_task_new (self, NULL, callback, user_data);
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200281
282 g_object_get (self,
283 MM_IFACE_MODEM_STATE, &state,
284 NULL);
285
286 /* Are we in a final state already? */
287 if (!MODEM_STATE_IS_INTERMEDIATE (state)) {
288 /* Is this the state we actually wanted? */
289 if (final_state == MM_MODEM_STATE_UNKNOWN ||
290 (state != MM_MODEM_STATE_UNKNOWN && state == final_state)) {
Ben Chan347610a2017-06-30 03:52:13 -0700291 g_task_return_int (task, state);
292 g_object_unref (task);
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200293 return;
294 }
295
296 /* Otherwise, we'll need to wait for the exact one we want */
297 }
298
Ben Chan524acd72017-06-30 06:27:07 -0700299 ctx = g_new0 (WaitForFinalStateContext, 1);
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200300 ctx->final_state = final_state;
301
Ben Chan524acd72017-06-30 06:27:07 -0700302 g_task_set_task_data (task, ctx, g_free);
Ben Chan347610a2017-06-30 03:52:13 -0700303
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200304 /* Want to get notified when modem state changes */
Ben Chan347610a2017-06-30 03:52:13 -0700305 ctx->state_changed_id = g_signal_connect (self,
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200306 "notify::" MM_IFACE_MODEM_STATE,
307 G_CALLBACK (state_changed),
Ben Chan347610a2017-06-30 03:52:13 -0700308 task);
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200309 /* But we don't want to wait forever */
310 ctx->state_changed_wait_id = g_timeout_add_seconds (10,
311 (GSourceFunc)state_changed_wait_expired,
Ben Chan347610a2017-06-30 03:52:13 -0700312 task);
Aleksander Morgado4fc3f522012-10-24 13:37:52 +0200313}
314
315/*****************************************************************************/
Aleksander Morgadocae73772018-12-06 14:54:19 +0100316/* Helper to return an error when the modem is in failed state and so it
317 * cannot process a given method invocation
318 */
319
320static gboolean
321abort_invocation_if_state_not_reached (MMIfaceModem *self,
322 GDBusMethodInvocation *invocation,
323 MMModemState minimum_required)
324{
325 MMModemState state = MM_MODEM_STATE_UNKNOWN;
326
327 g_object_get (self,
328 MM_IFACE_MODEM_STATE, &state,
329 NULL);
330
331 if (state >= minimum_required)
332 return FALSE;
333
334 g_dbus_method_invocation_return_error (invocation,
335 MM_CORE_ERROR,
336 MM_CORE_ERROR_WRONG_STATE,
337 "modem in %s state",
338 mm_modem_state_get_string (state));
339 return TRUE;
340}
341
342/*****************************************************************************/
Aleksander Morgado13c73192013-09-18 19:55:22 +0200343/* Helper method to load unlock required, considering retries */
Pavan Holla66b7cad2021-04-09 03:00:38 +0000344/* Increase retries for chromeos devices in M90 and M91, b:184278156 */
345#define MAX_RETRIES 12
Aleksander Morgado13c73192013-09-18 19:55:22 +0200346
347typedef struct {
Aleksander Morgado13c73192013-09-18 19:55:22 +0200348 guint retries;
349 guint pin_check_timeout_id;
350} InternalLoadUnlockRequiredContext;
351
Aleksander Morgado13c73192013-09-18 19:55:22 +0200352static MMModemLock
353internal_load_unlock_required_finish (MMIfaceModem *self,
354 GAsyncResult *res,
355 GError **error)
356{
Ben Chand56621b2017-07-05 22:20:09 -0700357 GError *inner_error = NULL;
Ben Chan7d197d12017-06-30 02:23:46 -0700358 gssize value;
Aleksander Morgado13c73192013-09-18 19:55:22 +0200359
Ben Chand56621b2017-07-05 22:20:09 -0700360 value = g_task_propagate_int (G_TASK (res), &inner_error);
361 if (inner_error) {
362 g_propagate_error (error, inner_error);
363 return MM_MODEM_LOCK_UNKNOWN;
364 }
365 return (MMModemLock)value;
Aleksander Morgado13c73192013-09-18 19:55:22 +0200366}
367
Ben Chan7d197d12017-06-30 02:23:46 -0700368static void internal_load_unlock_required_context_step (GTask *task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200369
370static gboolean
Ben Chan7d197d12017-06-30 02:23:46 -0700371load_unlock_required_again (GTask *task)
Aleksander Morgado13c73192013-09-18 19:55:22 +0200372{
Ben Chan7d197d12017-06-30 02:23:46 -0700373 InternalLoadUnlockRequiredContext *ctx;
374
375 ctx = g_task_get_task_data (task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200376 ctx->pin_check_timeout_id = 0;
377 /* Retry the step */
Ben Chan7d197d12017-06-30 02:23:46 -0700378 internal_load_unlock_required_context_step (task);
Aleksander Morgadoffde4292015-12-02 17:07:11 +0100379 return G_SOURCE_REMOVE;
Aleksander Morgado13c73192013-09-18 19:55:22 +0200380}
381
382static void
383load_unlock_required_ready (MMIfaceModem *self,
384 GAsyncResult *res,
Ben Chan7d197d12017-06-30 02:23:46 -0700385 GTask *task)
Aleksander Morgado13c73192013-09-18 19:55:22 +0200386{
Ben Chan7d197d12017-06-30 02:23:46 -0700387 InternalLoadUnlockRequiredContext *ctx;
Aleksander Morgado13c73192013-09-18 19:55:22 +0200388 GError *error = NULL;
389 MMModemLock lock;
390
Ben Chan7d197d12017-06-30 02:23:46 -0700391 ctx = g_task_get_task_data (task);
392
Aleksander Morgado13c73192013-09-18 19:55:22 +0200393 lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error);
394 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +0100395 mm_obj_dbg (self, "couldn't check if unlock required: %s", error->message);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200396
397 /* For several kinds of errors, just return them directly */
398 if (error->domain == MM_SERIAL_ERROR ||
399 g_error_matches (error,
Aleksander Morgadocf0d3f32019-10-09 10:49:25 +0200400 G_IO_ERROR,
401 G_IO_ERROR_CANCELLED) ||
Aleksander Morgado13c73192013-09-18 19:55:22 +0200402 g_error_matches (error,
403 MM_MOBILE_EQUIPMENT_ERROR,
404 MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
405 g_error_matches (error,
406 MM_MOBILE_EQUIPMENT_ERROR,
407 MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
408 g_error_matches (error,
409 MM_MOBILE_EQUIPMENT_ERROR,
410 MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
Ben Chan7d197d12017-06-30 02:23:46 -0700411 g_task_return_error (task, error);
412 g_object_unref (task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200413 return;
414 }
415
416 /* For the remaining ones, retry if possible */
417 if (ctx->retries < MAX_RETRIES) {
418 ctx->retries++;
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +0100419 mm_obj_dbg (self, "retrying (%u) unlock required check", ctx->retries);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200420
421 g_assert (ctx->pin_check_timeout_id == 0);
422 ctx->pin_check_timeout_id = g_timeout_add_seconds (2,
423 (GSourceFunc)load_unlock_required_again,
Ben Chan7d197d12017-06-30 02:23:46 -0700424 task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200425 g_error_free (error);
426 return;
427 }
428
429 /* If reached max retries and still reporting error... default to SIM error */
430 g_error_free (error);
Ben Chan7d197d12017-06-30 02:23:46 -0700431 g_task_return_new_error (task,
432 MM_MOBILE_EQUIPMENT_ERROR,
433 MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE,
434 "Couldn't get SIM lock status after %u retries",
435 MAX_RETRIES);
436 g_object_unref (task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200437 return;
438 }
439
440 /* Got the lock value, return it */
Ben Chan7d197d12017-06-30 02:23:46 -0700441 g_task_return_int (task, lock);
442 g_object_unref (task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200443}
444
445static void
Ben Chan7d197d12017-06-30 02:23:46 -0700446internal_load_unlock_required_context_step (GTask *task)
Aleksander Morgado13c73192013-09-18 19:55:22 +0200447{
Ben Chan7d197d12017-06-30 02:23:46 -0700448 MMIfaceModem *self;
449 InternalLoadUnlockRequiredContext *ctx;
450
451 self = g_task_get_source_object (task);
452 ctx = g_task_get_task_data (task);
453
Aleksander Morgado13c73192013-09-18 19:55:22 +0200454 g_assert (ctx->pin_check_timeout_id == 0);
Ben Chan7d197d12017-06-30 02:23:46 -0700455 MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required (
456 self,
Aleksander Morgadof2f42e12019-09-13 18:25:32 +0200457 (ctx->retries == MAX_RETRIES), /* last_attempt? */
Aleksander Morgado13c73192013-09-18 19:55:22 +0200458 (GAsyncReadyCallback)load_unlock_required_ready,
Ben Chan7d197d12017-06-30 02:23:46 -0700459 task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200460}
461
462static void
463internal_load_unlock_required (MMIfaceModem *self,
464 GAsyncReadyCallback callback,
465 gpointer user_data)
466{
467 InternalLoadUnlockRequiredContext *ctx;
Ben Chan7d197d12017-06-30 02:23:46 -0700468 GTask *task;
Aleksander Morgado13c73192013-09-18 19:55:22 +0200469
Ben Chan524acd72017-06-30 06:27:07 -0700470 ctx = g_new0 (InternalLoadUnlockRequiredContext, 1);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200471
Ben Chan7d197d12017-06-30 02:23:46 -0700472 task = g_task_new (self, NULL, callback, user_data);
Ben Chan524acd72017-06-30 06:27:07 -0700473 g_task_set_task_data (task, ctx, g_free);
Ben Chan7d197d12017-06-30 02:23:46 -0700474
475 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required ||
476 !MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish) {
Aleksander Morgado13c73192013-09-18 19:55:22 +0200477 /* Just assume that no lock is required */
Ben Chan7d197d12017-06-30 02:23:46 -0700478 g_task_return_boolean (task, TRUE);
479 g_object_unref (task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200480 return;
481 }
482
Ben Chan7d197d12017-06-30 02:23:46 -0700483 internal_load_unlock_required_context_step (task);
Aleksander Morgado13c73192013-09-18 19:55:22 +0200484}
485
486/*****************************************************************************/
Aleksander Morgado0c009a22011-12-28 14:00:15 +0100487
Aleksander Morgado7f442b72013-11-15 19:06:58 +0100488static void
489bearer_list_updated (MMBearerList *bearer_list,
490 GParamSpec *pspec,
491 MMIfaceModem *self)
492{
493 MmGdbusModem *skeleton;
494 gchar **paths;
495
496 g_object_get (self,
497 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
498 NULL);
499 if (!skeleton)
500 return;
501
502 paths = mm_bearer_list_get_paths (bearer_list);
503 mm_gdbus_modem_set_bearers (skeleton, (const gchar *const *)paths);
504 g_strfreev (paths);
505
506 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (skeleton));
Aleksander Morgadod12ab8a2021-01-11 14:18:36 +0100507 g_object_unref (skeleton);
Aleksander Morgado7f442b72013-11-15 19:06:58 +0100508}
509
510/*****************************************************************************/
511
Aleksander Morgadoaa223872019-05-28 17:59:30 +0200512static MMModemState get_consolidated_subsystem_state (MMIfaceModem *self);
Aleksander Morgado4aeadbb2012-01-20 12:30:12 +0100513
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100514typedef struct {
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200515 MMBaseBearer *self;
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100516 guint others_connected;
517} CountOthersConnectedContext;
518
519static void
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200520bearer_list_count_others_connected (MMBaseBearer *bearer,
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100521 CountOthersConnectedContext *ctx)
522{
523 /* We can safely compare pointers here */
524 if (bearer != ctx->self &&
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200525 mm_base_bearer_get_status (bearer) == MM_BEARER_STATUS_CONNECTED) {
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100526 ctx->others_connected++;
527 }
528}
529
530static void
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200531bearer_status_changed (MMBaseBearer *bearer,
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100532 GParamSpec *pspec,
533 MMIfaceModem *self)
534{
535 CountOthersConnectedContext ctx;
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100536 MMBearerList *list = NULL;
Aleksander Morgadodb80fd22012-10-24 16:22:05 +0200537 MMModemState state = MM_MODEM_STATE_UNKNOWN;
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100538
539 g_object_get (self,
Aleksander Morgadodb80fd22012-10-24 16:22:05 +0200540 MM_IFACE_MODEM_STATE, &state,
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100541 MM_IFACE_MODEM_BEARER_LIST, &list,
542 NULL);
Aleksander Morgadod9916902012-09-03 09:43:52 +0200543 if (!list)
544 return;
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100545
Aleksander Morgadodb80fd22012-10-24 16:22:05 +0200546 if (state == MM_MODEM_STATE_DISABLING ||
547 state == MM_MODEM_STATE_ENABLING) {
548 /* Don't log modem bearer-specific status changes if we're disabling
549 * or enabling */
550 g_object_unref (list);
551 return;
552 }
553
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100554 ctx.self = bearer;
555 ctx.others_connected = 0;
556
557 /* We now count how many *other* bearers are connected */
558 mm_bearer_list_foreach (list,
559 (MMBearerListForeachFunc)bearer_list_count_others_connected,
560 &ctx);
561
562 /* If no other bearers are connected, change modem state */
563 if (!ctx.others_connected) {
Aleksander Morgado5edb8632012-01-03 20:27:18 +0100564 MMModemState new_state = MM_MODEM_STATE_UNKNOWN;
565
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200566 switch (mm_base_bearer_get_status (bearer)) {
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100567 case MM_BEARER_STATUS_CONNECTED:
568 new_state = MM_MODEM_STATE_CONNECTED;
569 break;
570 case MM_BEARER_STATUS_CONNECTING:
571 new_state = MM_MODEM_STATE_CONNECTING;
572 break;
573 case MM_BEARER_STATUS_DISCONNECTING:
574 new_state = MM_MODEM_STATE_DISCONNECTING;
575 break;
576 case MM_BEARER_STATUS_DISCONNECTED:
Aleksander Morgadoaa223872019-05-28 17:59:30 +0200577 new_state = get_consolidated_subsystem_state (self);
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100578 break;
Aleksander Morgadoeb04ead2019-11-28 22:46:04 +0100579 default:
580 g_assert_not_reached ();
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100581 }
582
583 mm_iface_modem_update_state (self,
584 new_state,
585 MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED);
586 }
Aleksander Morgado8610fd42012-01-03 19:56:16 +0100587
588 g_object_unref (list);
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +0100589}
590
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200591typedef struct {
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200592 MMBearerList *list;
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200593} CreateBearerContext;
594
595static void
Ben Chan0bc40c82017-06-30 02:23:41 -0700596create_bearer_context_free (CreateBearerContext *ctx)
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200597{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200598 if (ctx->list)
599 g_object_unref (ctx->list);
600 g_slice_free (CreateBearerContext, ctx);
601}
602
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200603MMBaseBearer *
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100604mm_iface_modem_create_bearer_finish (MMIfaceModem *self,
605 GAsyncResult *res,
606 GError **error)
607{
Ben Chan0bc40c82017-06-30 02:23:41 -0700608 return g_task_propagate_pointer (G_TASK (res), error);
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100609}
610
Aleksander Morgado2be22882011-11-30 18:22:22 +0100611static void
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100612create_bearer_ready (MMIfaceModem *self,
613 GAsyncResult *res,
Ben Chan0bc40c82017-06-30 02:23:41 -0700614 GTask *task)
Aleksander Morgado2be22882011-11-30 18:22:22 +0100615{
Ben Chan0bc40c82017-06-30 02:23:41 -0700616 CreateBearerContext *ctx;
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200617 MMBaseBearer *bearer;
Aleksander Morgado2be22882011-11-30 18:22:22 +0100618 GError *error = NULL;
619
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200620 bearer = MM_IFACE_MODEM_GET_INTERFACE (self)->create_bearer_finish (self, res, &error);
621 if (error) {
Ben Chan0bc40c82017-06-30 02:23:41 -0700622 g_task_return_error (task, error);
623 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200624 return;
Aleksander Morgado776cc662011-12-12 20:22:51 +0100625 }
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100626
Ben Chan0bc40c82017-06-30 02:23:41 -0700627 ctx = g_task_get_task_data (task);
628
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200629 if (!mm_bearer_list_add_bearer (ctx->list, bearer, &error)) {
Ben Chan0bc40c82017-06-30 02:23:41 -0700630 g_task_return_error (task, error);
631 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200632 g_object_unref (bearer);
633 return;
634 }
635
636 /* If bearer properly created and added to the list, follow its
637 * status */
638 g_signal_connect (bearer,
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200639 "notify::" MM_BASE_BEARER_STATUS,
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200640 (GCallback)bearer_status_changed,
641 self);
Ben Chan0bc40c82017-06-30 02:23:41 -0700642 g_task_return_pointer (task, bearer, g_object_unref);
643 g_object_unref (task);
Aleksander Morgado2be22882011-11-30 18:22:22 +0100644}
645
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100646void
647mm_iface_modem_create_bearer (MMIfaceModem *self,
Aleksander Morgadod306bb02012-03-01 12:14:44 +0100648 MMBearerProperties *properties,
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100649 GAsyncReadyCallback callback,
650 gpointer user_data)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +0100651{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200652 CreateBearerContext *ctx;
Ben Chan0bc40c82017-06-30 02:23:41 -0700653 GTask *task;
Aleksander Morgado776cc662011-12-12 20:22:51 +0100654
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200655 ctx = g_slice_new (CreateBearerContext);
Ben Chan0bc40c82017-06-30 02:23:41 -0700656
657 task = g_task_new (self, NULL, callback, user_data);
658 g_task_set_task_data (task, ctx, (GDestroyNotify)create_bearer_context_free);
659
Aleksander Morgado776cc662011-12-12 20:22:51 +0100660 g_object_get (self,
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200661 MM_IFACE_MODEM_BEARER_LIST, &ctx->list,
Aleksander Morgado776cc662011-12-12 20:22:51 +0100662 NULL);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200663 if (!ctx->list) {
Ben Chan0bc40c82017-06-30 02:23:41 -0700664 g_task_return_new_error (
665 task,
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200666 MM_CORE_ERROR,
667 MM_CORE_ERROR_FAILED,
668 "Cannot add new bearer: bearer list not found");
Ben Chan0bc40c82017-06-30 02:23:41 -0700669 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200670 return;
671 }
Aleksander Morgado776cc662011-12-12 20:22:51 +0100672
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200673 if (mm_bearer_list_get_count (ctx->list) == mm_bearer_list_get_max (ctx->list)) {
Ben Chan0bc40c82017-06-30 02:23:41 -0700674 g_task_return_new_error (
675 task,
Aleksander Morgadof0710192012-01-12 14:07:58 +0100676 MM_CORE_ERROR,
677 MM_CORE_ERROR_TOO_MANY,
678 "Cannot add new bearer: already reached maximum (%u)",
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200679 mm_bearer_list_get_count (ctx->list));
Ben Chan0bc40c82017-06-30 02:23:41 -0700680 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200681 return;
682 }
683
684 MM_IFACE_MODEM_GET_INTERFACE (self)->create_bearer (
685 self,
686 properties,
687 (GAsyncReadyCallback)create_bearer_ready,
Ben Chan0bc40c82017-06-30 02:23:41 -0700688 task);
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100689}
690
Aleksander Morgado22407472012-02-27 10:40:03 +0100691typedef struct {
692 MmGdbusModem *skeleton;
693 GDBusMethodInvocation *invocation;
694 MMIfaceModem *self;
695 GVariant *dictionary;
696} HandleCreateBearerContext;
697
698static void
699handle_create_bearer_context_free (HandleCreateBearerContext *ctx)
700{
701 g_variant_unref (ctx->dictionary);
702 g_object_unref (ctx->skeleton);
703 g_object_unref (ctx->invocation);
704 g_object_unref (ctx->self);
705 g_free (ctx);
706}
707
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100708static void
709handle_create_bearer_ready (MMIfaceModem *self,
710 GAsyncResult *res,
Aleksander Morgado22407472012-02-27 10:40:03 +0100711 HandleCreateBearerContext *ctx)
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100712{
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200713 MMBaseBearer *bearer;
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100714 GError *error = NULL;
715
Aleksander Morgado4ccc00f2011-12-27 15:33:33 +0100716 bearer = mm_iface_modem_create_bearer_finish (self, res, &error);
717 if (!bearer)
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100718 g_dbus_method_invocation_take_error (ctx->invocation, error);
719 else {
720 mm_gdbus_modem_complete_create_bearer (ctx->skeleton,
721 ctx->invocation,
Aleksander Morgado3ca267b2014-07-06 15:55:34 +0200722 mm_base_bearer_get_path (bearer));
Aleksander Morgado4ccc00f2011-12-27 15:33:33 +0100723 g_object_unref (bearer);
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100724 }
Aleksander Morgado22407472012-02-27 10:40:03 +0100725
726 handle_create_bearer_context_free (ctx);
727}
728
729static void
730handle_create_bearer_auth_ready (MMBaseModem *self,
731 GAsyncResult *res,
732 HandleCreateBearerContext *ctx)
733{
Aleksander Morgadod306bb02012-03-01 12:14:44 +0100734 MMBearerProperties *properties;
Aleksander Morgado22407472012-02-27 10:40:03 +0100735 GError *error = NULL;
736
737 if (!mm_base_modem_authorize_finish (self, res, &error)) {
738 g_dbus_method_invocation_take_error (ctx->invocation, error);
739 handle_create_bearer_context_free (ctx);
740 return;
741 }
742
Aleksander Morgadocae73772018-12-06 14:54:19 +0100743 if (abort_invocation_if_state_not_reached (ctx->self, ctx->invocation, MM_MODEM_STATE_LOCKED)) {
744 handle_create_bearer_context_free (ctx);
745 return;
746 }
747
Aleksander Morgadod306bb02012-03-01 12:14:44 +0100748 properties = mm_bearer_properties_new_from_dictionary (ctx->dictionary, &error);
Aleksander Morgado22407472012-02-27 10:40:03 +0100749 if (!properties) {
750 g_dbus_method_invocation_take_error (ctx->invocation, error);
751 handle_create_bearer_context_free (ctx);
752 return;
753 }
754
755 mm_iface_modem_create_bearer (
756 ctx->self,
757 properties,
758 (GAsyncReadyCallback)handle_create_bearer_ready,
759 ctx);
760 g_object_unref (properties);
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100761}
762
763static gboolean
764handle_create_bearer (MmGdbusModem *skeleton,
765 GDBusMethodInvocation *invocation,
766 GVariant *dictionary,
767 MMIfaceModem *self)
768{
Aleksander Morgado22407472012-02-27 10:40:03 +0100769 HandleCreateBearerContext *ctx;
Aleksander Morgado93732cf2011-12-27 14:36:54 +0100770
Aleksander Morgado22407472012-02-27 10:40:03 +0100771 ctx = g_new (HandleCreateBearerContext, 1);
772 ctx->skeleton = g_object_ref (skeleton);
773 ctx->invocation = g_object_ref (invocation);
774 ctx->self = g_object_ref (self);
775 ctx->dictionary = g_variant_ref (dictionary);
Aleksander Morgado776cc662011-12-12 20:22:51 +0100776
Aleksander Morgado22407472012-02-27 10:40:03 +0100777 mm_base_modem_authorize (MM_BASE_MODEM (self),
778 invocation,
779 MM_AUTHORIZATION_DEVICE_CONTROL,
780 (GAsyncReadyCallback)handle_create_bearer_auth_ready,
781 ctx);
Aleksander Morgado2be22882011-11-30 18:22:22 +0100782 return TRUE;
783}
784
Aleksander Morgado22407472012-02-27 10:40:03 +0100785/*****************************************************************************/
786
787typedef struct {
788 MmGdbusModem *skeleton;
789 GDBusMethodInvocation *invocation;
790 MMIfaceModem *self;
791 gchar *cmd;
792 guint timeout;
793} HandleCommandContext;
794
Nathan Williams3c41ce52012-01-23 11:04:49 -0500795static void
Aleksander Morgado22407472012-02-27 10:40:03 +0100796handle_command_context_free (HandleCommandContext *ctx)
797{
798 g_object_unref (ctx->skeleton);
799 g_object_unref (ctx->invocation);
800 g_object_unref (ctx->self);
801 g_free (ctx->cmd);
802 g_free (ctx);
803}
804
805static void
806command_ready (MMIfaceModem *self,
807 GAsyncResult *res,
808 HandleCommandContext *ctx)
Nathan Williams3c41ce52012-01-23 11:04:49 -0500809{
810 GError *error = NULL;
811 const gchar *result;
812
813 result = MM_IFACE_MODEM_GET_INTERFACE (self)->command_finish (self,
814 res,
815 &error);
816 if (error)
Aleksander Morgado22407472012-02-27 10:40:03 +0100817 g_dbus_method_invocation_take_error (ctx->invocation, error);
Nathan Williams3c41ce52012-01-23 11:04:49 -0500818 else
Aleksander Morgado22407472012-02-27 10:40:03 +0100819 mm_gdbus_modem_complete_command (ctx->skeleton, ctx->invocation, result);
820
821 handle_command_context_free (ctx);
822}
823
824static void
825handle_command_auth_ready (MMBaseModem *self,
826 GAsyncResult *res,
827 HandleCommandContext *ctx)
828{
829 GError *error = NULL;
830
831 if (!mm_base_modem_authorize_finish (self, res, &error)) {
832 g_dbus_method_invocation_take_error (ctx->invocation, error);
833 handle_command_context_free (ctx);
834 return;
835 }
836
Aleksander Morgadoc78ba5e2019-06-01 10:23:15 +0200837#if ! defined WITH_AT_COMMAND_VIA_DBUS
Aleksander Morgado64f49c02012-02-28 23:24:53 +0100838 /* If we are not in Debug mode, report an error */
839 if (!mm_context_get_debug ()) {
840 g_dbus_method_invocation_return_error (ctx->invocation,
841 MM_CORE_ERROR,
842 MM_CORE_ERROR_UNAUTHORIZED,
843 "Cannot send AT command to modem: "
844 "operation only allowed in debug mode");
845 handle_command_context_free (ctx);
846 return;
847 }
Aleksander Morgadoc78ba5e2019-06-01 10:23:15 +0200848#endif
Aleksander Morgado64f49c02012-02-28 23:24:53 +0100849
Aleksander Morgado22407472012-02-27 10:40:03 +0100850 /* If command is not implemented, report an error */
851 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->command ||
852 !MM_IFACE_MODEM_GET_INTERFACE (self)->command_finish) {
853 g_dbus_method_invocation_return_error (ctx->invocation,
854 MM_CORE_ERROR,
855 MM_CORE_ERROR_UNSUPPORTED,
856 "Cannot send AT command to modem: "
857 "operation not supported");
858 handle_command_context_free (ctx);
859 return;
860 }
861
862 MM_IFACE_MODEM_GET_INTERFACE (self)->command (ctx->self,
863 ctx->cmd,
864 ctx->timeout,
865 (GAsyncReadyCallback)command_ready,
866 ctx);
Nathan Williams3c41ce52012-01-23 11:04:49 -0500867}
868
869static gboolean
870handle_command (MmGdbusModem *skeleton,
871 GDBusMethodInvocation *invocation,
872 const gchar *cmd,
873 guint timeout,
874 MMIfaceModem *self)
875{
Aleksander Morgado22407472012-02-27 10:40:03 +0100876 HandleCommandContext *ctx;
Nathan Williams3c41ce52012-01-23 11:04:49 -0500877
Aleksander Morgado22407472012-02-27 10:40:03 +0100878 ctx = g_new (HandleCommandContext, 1);
879 ctx->skeleton = g_object_ref (skeleton);
880 ctx->invocation = g_object_ref (invocation);
881 ctx->self = g_object_ref (self);
882 ctx->cmd = g_strdup (cmd);
883 ctx->timeout = timeout;
Nathan Williams3c41ce52012-01-23 11:04:49 -0500884
Aleksander Morgado22407472012-02-27 10:40:03 +0100885 mm_base_modem_authorize (MM_BASE_MODEM (self),
886 invocation,
887 MM_AUTHORIZATION_DEVICE_CONTROL,
888 (GAsyncReadyCallback)handle_command_auth_ready,
889 ctx);
Nathan Williams3c41ce52012-01-23 11:04:49 -0500890 return TRUE;
891}
892
Aleksander Morgado2be22882011-11-30 18:22:22 +0100893/*****************************************************************************/
894
Aleksander Morgado22407472012-02-27 10:40:03 +0100895typedef struct {
896 MmGdbusModem *skeleton;
897 GDBusMethodInvocation *invocation;
898 MMIfaceModem *self;
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200899 MMBearerList *list;
Aleksander Morgado22407472012-02-27 10:40:03 +0100900 gchar *bearer_path;
Aleksander Morgado4c036eb2015-12-03 12:01:00 +0100901 MMBaseBearer *bearer;
Aleksander Morgado22407472012-02-27 10:40:03 +0100902} HandleDeleteBearerContext;
903
904static void
905handle_delete_bearer_context_free (HandleDeleteBearerContext *ctx)
906{
Aleksander Morgado4c036eb2015-12-03 12:01:00 +0100907 if (ctx->bearer)
908 g_object_unref (ctx->bearer);
Aleksander Morgado22407472012-02-27 10:40:03 +0100909 g_object_unref (ctx->skeleton);
910 g_object_unref (ctx->invocation);
911 g_object_unref (ctx->self);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200912 if (ctx->list)
913 g_object_unref (ctx->list);
Aleksander Morgado22407472012-02-27 10:40:03 +0100914 g_free (ctx->bearer_path);
915 g_free (ctx);
916}
917
918static void
Aleksander Morgado4c036eb2015-12-03 12:01:00 +0100919delete_bearer_disconnect_ready (MMBaseBearer *bearer,
920 GAsyncResult *res,
921 HandleDeleteBearerContext *ctx)
922{
923 GError *error = NULL;
924
925 if (!mm_base_bearer_disconnect_finish (bearer, res, &error)) {
926 g_dbus_method_invocation_take_error (ctx->invocation, error);
927 handle_delete_bearer_context_free (ctx);
928 return;
929 }
930
931 if (!mm_bearer_list_delete_bearer (ctx->list, ctx->bearer_path, &error))
932 g_dbus_method_invocation_take_error (ctx->invocation, error);
933 else
934 mm_gdbus_modem_complete_delete_bearer (ctx->skeleton, ctx->invocation);
935 handle_delete_bearer_context_free (ctx);
936}
937
938static void
Aleksander Morgado22407472012-02-27 10:40:03 +0100939handle_delete_bearer_auth_ready (MMBaseModem *self,
940 GAsyncResult *res,
941 HandleDeleteBearerContext *ctx)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +0100942{
Aleksander Morgado776cc662011-12-12 20:22:51 +0100943 GError *error = NULL;
944
Aleksander Morgado22407472012-02-27 10:40:03 +0100945 if (!mm_base_modem_authorize_finish (self, res, &error)) {
946 g_dbus_method_invocation_take_error (ctx->invocation, error);
947 handle_delete_bearer_context_free (ctx);
948 return;
949 }
950
Aleksander Morgadocae73772018-12-06 14:54:19 +0100951 if (abort_invocation_if_state_not_reached (ctx->self, ctx->invocation, MM_MODEM_STATE_LOCKED)) {
952 handle_delete_bearer_context_free (ctx);
953 return;
954 }
955
Aleksander Morgado4c036eb2015-12-03 12:01:00 +0100956 if (!g_str_has_prefix (ctx->bearer_path, MM_DBUS_BEARER_PREFIX)) {
957 g_dbus_method_invocation_return_error (ctx->invocation,
958 MM_CORE_ERROR,
959 MM_CORE_ERROR_INVALID_ARGS,
960 "Cannot delete bearer: invalid path '%s'",
961 ctx->bearer_path);
962 handle_delete_bearer_context_free (ctx);
963 return;
964 }
Aleksander Morgado776cc662011-12-12 20:22:51 +0100965
Aleksander Morgado4c036eb2015-12-03 12:01:00 +0100966 ctx->bearer = mm_bearer_list_find_by_path (ctx->list, ctx->bearer_path);
967 if (!ctx->bearer) {
968 g_dbus_method_invocation_return_error (ctx->invocation,
969 MM_CORE_ERROR,
970 MM_CORE_ERROR_INVALID_ARGS,
971 "Cannot delete bearer: no bearer found with path '%s'",
972 ctx->bearer_path);
973 handle_delete_bearer_context_free (ctx);
974 return;
975 }
976
977 mm_base_bearer_disconnect (ctx->bearer,
978 (GAsyncReadyCallback)delete_bearer_disconnect_ready,
979 ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +0100980}
981
982static gboolean
983handle_delete_bearer (MmGdbusModem *skeleton,
984 GDBusMethodInvocation *invocation,
985 const gchar *bearer,
986 MMIfaceModem *self)
987{
988 HandleDeleteBearerContext *ctx;
989
990 ctx = g_new (HandleDeleteBearerContext, 1);
991 ctx->skeleton = g_object_ref (skeleton);
992 ctx->invocation = g_object_ref (invocation);
993 ctx->self = g_object_ref (self);
994 ctx->bearer_path = g_strdup (bearer);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +0200995 g_object_get (self,
996 MM_IFACE_MODEM_BEARER_LIST, &ctx->list,
997 NULL);
Aleksander Morgado22407472012-02-27 10:40:03 +0100998
999 mm_base_modem_authorize (MM_BASE_MODEM (self),
1000 invocation,
1001 MM_AUTHORIZATION_DEVICE_CONTROL,
1002 (GAsyncReadyCallback)handle_delete_bearer_auth_ready,
1003 ctx);
Aleksander Morgado2be22882011-11-30 18:22:22 +01001004 return TRUE;
1005}
1006
1007/*****************************************************************************/
1008
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01001009static gboolean
Aleksander Morgado2be22882011-11-30 18:22:22 +01001010handle_list_bearers (MmGdbusModem *skeleton,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01001011 GDBusMethodInvocation *invocation,
1012 MMIfaceModem *self)
1013{
Aleksander Morgado776cc662011-12-12 20:22:51 +01001014 GStrv paths;
1015 MMBearerList *list = NULL;
1016
Aleksander Morgadocae73772018-12-06 14:54:19 +01001017 if (abort_invocation_if_state_not_reached (self, invocation, MM_MODEM_STATE_LOCKED))
1018 return TRUE;
1019
Aleksander Morgado776cc662011-12-12 20:22:51 +01001020 g_object_get (self,
1021 MM_IFACE_MODEM_BEARER_LIST, &list,
1022 NULL);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02001023 if (!list) {
1024 g_dbus_method_invocation_return_error (invocation,
1025 MM_CORE_ERROR,
1026 MM_CORE_ERROR_FAILED,
1027 "Bearer list not found");
1028 return TRUE;
1029 }
Aleksander Morgado776cc662011-12-12 20:22:51 +01001030
1031 paths = mm_bearer_list_get_paths (list);
1032 mm_gdbus_modem_complete_list_bearers (skeleton,
1033 invocation,
1034 (const gchar *const *)paths);
1035
1036 g_strfreev (paths);
1037 g_object_unref (list);
Aleksander Morgado2be22882011-11-30 18:22:22 +01001038 return TRUE;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01001039}
1040
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001041/*****************************************************************************/
1042
Aleksander Morgado924cf1a2020-08-01 09:59:37 +02001043typedef struct {
1044 MmGdbusModem *skeleton;
1045 GDBusMethodInvocation *invocation;
1046 MMIfaceModem *self;
1047 guint requested_sim_slot;
1048} HandleSetPrimarySimSlotContext;
1049
1050static void
1051handle_set_primary_sim_slot_context_free (HandleSetPrimarySimSlotContext *ctx)
1052{
1053 g_clear_object (&ctx->skeleton);
1054 g_clear_object (&ctx->invocation);
1055 g_clear_object (&ctx->self);
1056 g_free (ctx);
1057}
1058
1059static void
1060set_primary_sim_slot_ready (MMIfaceModem *self,
1061 GAsyncResult *res,
1062 HandleSetPrimarySimSlotContext *ctx)
1063{
1064 g_autoptr(GError) error = NULL;
1065
1066 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot_finish (self, res, &error)) {
1067 /* If the implementation returns EXISTS, we're already in the requested SIM slot,
1068 * so we can safely return a success on the operation and skip the reprobing */
1069 if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_EXISTS)) {
1070 mm_obj_warn (self, "couldn't process primary SIM update request: %s", error->message);
1071 g_dbus_method_invocation_take_error (ctx->invocation, g_steal_pointer (&error));
1072 handle_set_primary_sim_slot_context_free (ctx);
1073 return;
1074 }
1075 mm_obj_dbg (self, "ignoring SIM update request: %s", error->message);
1076 } else {
1077 /* Notify about the SIM swap, which will disable and reprobe the device.
1078 * There is no need to update the PrimarySimSlot property, as this value will be
1079 * reloaded automatically during the reprobe. */
Pavan Holla38f67042020-11-23 17:52:17 +00001080 mm_base_modem_process_sim_event (MM_BASE_MODEM (self));
Aleksander Morgado924cf1a2020-08-01 09:59:37 +02001081 }
1082
1083 mm_gdbus_modem_complete_set_primary_sim_slot (ctx->skeleton, ctx->invocation);
1084 handle_set_primary_sim_slot_context_free (ctx);
1085}
1086
1087static void
1088handle_set_primary_sim_slot_auth_ready (MMBaseModem *self,
1089 GAsyncResult *res,
1090 HandleSetPrimarySimSlotContext *ctx)
1091{
1092 GError *error = NULL;
1093 const gchar *const *sim_slot_paths;
1094
1095 if (!mm_base_modem_authorize_finish (self, res, &error)) {
1096 g_dbus_method_invocation_take_error (ctx->invocation, error);
1097 handle_set_primary_sim_slot_context_free (ctx);
1098 return;
1099 }
1100
1101 /* If SIM switching is not implemented, report an error */
1102 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot ||
1103 !MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot_finish) {
1104 g_dbus_method_invocation_return_error (ctx->invocation,
1105 MM_CORE_ERROR,
1106 MM_CORE_ERROR_UNSUPPORTED,
1107 "Cannot switch sim: "
1108 "operation not supported");
1109 handle_set_primary_sim_slot_context_free (ctx);
1110 return;
1111 }
1112
1113 /* Validate SIM slot number */
1114 sim_slot_paths = mm_gdbus_modem_get_sim_slots (ctx->skeleton);
1115 if (ctx->requested_sim_slot > g_strv_length ((gchar **)sim_slot_paths)) {
1116 g_dbus_method_invocation_return_error (ctx->invocation,
1117 MM_CORE_ERROR,
1118 MM_CORE_ERROR_INVALID_ARGS,
1119 "Cannot switch sim: requested SIM slot number is out of bounds");
1120 handle_set_primary_sim_slot_context_free (ctx);
1121 return;
1122 }
1123
1124 MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot (MM_IFACE_MODEM (self),
1125 ctx->requested_sim_slot,
1126 (GAsyncReadyCallback)set_primary_sim_slot_ready,
1127 ctx);
1128}
1129
1130static gboolean
1131handle_set_primary_sim_slot (MmGdbusModem *skeleton,
1132 GDBusMethodInvocation *invocation,
1133 guint sim_slot,
1134 MMIfaceModem *self)
1135{
1136 HandleSetPrimarySimSlotContext *ctx;
1137
1138 ctx = g_new0 (HandleSetPrimarySimSlotContext, 1);
1139 ctx->skeleton = g_object_ref (skeleton);
1140 ctx->invocation = g_object_ref (invocation);
1141 ctx->self = g_object_ref (self);
1142 ctx->requested_sim_slot = sim_slot;
1143
1144 mm_base_modem_authorize (MM_BASE_MODEM (self),
1145 invocation,
1146 MM_AUTHORIZATION_DEVICE_CONTROL,
1147 (GAsyncReadyCallback)handle_set_primary_sim_slot_auth_ready,
1148 ctx);
1149 return TRUE;
1150}
1151
1152/*****************************************************************************/
1153
Aleksander Morgado4495ba12011-12-20 18:48:54 +01001154void
Aleksander Morgado65455552012-01-22 10:44:34 +01001155mm_iface_modem_update_access_technologies (MMIfaceModem *self,
1156 MMModemAccessTechnology new_access_tech,
1157 guint32 mask)
Aleksander Morgado4495ba12011-12-20 18:48:54 +01001158{
1159 MmGdbusModem *skeleton = NULL;
Aleksander Morgado5c74c532011-12-23 13:45:59 +01001160 MMModemAccessTechnology old_access_tech;
1161 MMModemAccessTechnology built_access_tech;
Aleksander Morgado4495ba12011-12-20 18:48:54 +01001162
1163 g_object_get (self,
1164 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
1165 NULL);
1166
Aleksander Morgado0336b8f2012-08-02 09:23:16 +02001167 /* Don't process updates if the interface is shut down */
1168 if (!skeleton)
1169 return;
1170
Aleksander Morgado5c74c532011-12-23 13:45:59 +01001171 old_access_tech = mm_gdbus_modem_get_access_technologies (skeleton);
Aleksander Morgado4495ba12011-12-20 18:48:54 +01001172
Aleksander Morgado5c74c532011-12-23 13:45:59 +01001173 /* Build the new access tech */
1174 built_access_tech = old_access_tech;
1175 built_access_tech &= ~mask;
1176 built_access_tech |= new_access_tech;
Aleksander Morgado4495ba12011-12-20 18:48:54 +01001177
Aleksander Morgado5c74c532011-12-23 13:45:59 +01001178 if (built_access_tech != old_access_tech) {
1179 gchar *old_access_tech_string;
1180 gchar *new_access_tech_string;
Aleksander Morgado5c74c532011-12-23 13:45:59 +01001181
1182 mm_gdbus_modem_set_access_technologies (skeleton, built_access_tech);
1183
1184 /* Log */
Aleksander Morgado7e36f042012-01-18 13:43:49 +01001185 old_access_tech_string = mm_modem_access_technology_build_string_from_mask (old_access_tech);
1186 new_access_tech_string = mm_modem_access_technology_build_string_from_mask (built_access_tech);
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001187 mm_obj_dbg (self, "access technology changed (%s -> %s)",
1188 old_access_tech_string,
1189 new_access_tech_string);
Aleksander Morgado5c74c532011-12-23 13:45:59 +01001190 g_free (old_access_tech_string);
1191 g_free (new_access_tech_string);
1192 }
1193
1194 g_object_unref (skeleton);
Aleksander Morgado4495ba12011-12-20 18:48:54 +01001195}
1196
1197/*****************************************************************************/
1198
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001199typedef struct {
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001200 guint recent_timeout_source;
1201} SignalQualityUpdateContext;
1202
1203static void
1204signal_quality_update_context_free (SignalQualityUpdateContext *ctx)
1205{
1206 if (ctx->recent_timeout_source)
1207 g_source_remove (ctx->recent_timeout_source);
1208 g_free (ctx);
1209}
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001210
1211static gboolean
1212expire_signal_quality (MMIfaceModem *self)
1213{
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001214 MmGdbusModem *skeleton = NULL;
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001215 SignalQualityUpdateContext *ctx;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001216
1217 g_object_get (self,
1218 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
1219 NULL);
1220
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02001221 if (skeleton) {
1222 GVariant *old;
1223 guint signal_quality = 0;
1224 gboolean recent = FALSE;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001225
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02001226 old = mm_gdbus_modem_get_signal_quality (skeleton);
1227 g_variant_get (old,
1228 "(ub)",
1229 &signal_quality,
1230 &recent);
1231
1232 /* If value is already not recent, we're done */
1233 if (recent) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001234 mm_obj_dbg (self, "signal quality value not updated in %us, marking as not being recent",
1235 SIGNAL_QUALITY_RECENT_TIMEOUT_SEC);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02001236 mm_gdbus_modem_set_signal_quality (skeleton,
1237 g_variant_new ("(ub)",
1238 signal_quality,
1239 FALSE));
1240 }
1241
1242 g_object_unref (skeleton);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001243 }
1244
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001245 /* Remove source id */
1246 ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_update_context_quark);
1247 ctx->recent_timeout_source = 0;
Aleksander Morgadoffde4292015-12-02 17:07:11 +01001248 return G_SOURCE_REMOVE;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001249}
1250
1251static void
1252update_signal_quality (MMIfaceModem *self,
1253 guint signal_quality,
1254 gboolean expire)
1255{
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001256 SignalQualityUpdateContext *ctx;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001257 MmGdbusModem *skeleton = NULL;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001258
Aleksander Morgado0336b8f2012-08-02 09:23:16 +02001259 g_object_get (self,
1260 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
1261 NULL);
1262
1263 /* Don't process updates if the interface is shut down */
1264 if (!skeleton)
1265 return;
1266
Aleksander Morgadocb2612d2012-01-03 21:43:20 +01001267 if (G_UNLIKELY (!signal_quality_update_context_quark))
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001268 signal_quality_update_context_quark = (g_quark_from_static_string (
1269 SIGNAL_QUALITY_UPDATE_CONTEXT_TAG));
1270
Aleksander Morgadocb2612d2012-01-03 21:43:20 +01001271 ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_update_context_quark);
1272 if (!ctx) {
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001273 /* Create context and keep it as object data */
1274 ctx = g_new0 (SignalQualityUpdateContext, 1);
1275 g_object_set_qdata_full (
1276 G_OBJECT (self),
1277 signal_quality_update_context_quark,
1278 ctx,
1279 (GDestroyNotify)signal_quality_update_context_free);
Aleksander Morgadocb2612d2012-01-03 21:43:20 +01001280 }
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001281
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001282 /* Note: we always set the new value, even if the signal quality level
1283 * is the same, in order to provide an up to date 'recent' flag.
1284 * The only exception being if 'expire' is FALSE; in that case we assume
1285 * the value won't expire and therefore can be considered obsolete
1286 * already. */
1287 mm_gdbus_modem_set_signal_quality (skeleton,
1288 g_variant_new ("(ub)",
1289 signal_quality,
1290 expire));
1291
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001292 mm_obj_dbg (self, "signal quality updated (%u)", signal_quality);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001293
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001294 /* Remove any previous expiration refresh timeout */
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001295 if (ctx->recent_timeout_source) {
1296 g_source_remove (ctx->recent_timeout_source);
1297 ctx->recent_timeout_source = 0;
1298 }
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001299
1300 /* If we got a new expirable value, setup new timeout */
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001301 if (expire)
1302 ctx->recent_timeout_source = (g_timeout_add_seconds (
1303 SIGNAL_QUALITY_RECENT_TIMEOUT_SEC,
1304 (GSourceFunc)expire_signal_quality,
1305 self));
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001306
1307 g_object_unref (skeleton);
1308}
1309
1310void
1311mm_iface_modem_update_signal_quality (MMIfaceModem *self,
1312 guint signal_quality)
1313{
1314 update_signal_quality (self, signal_quality, TRUE);
1315}
1316
1317/*****************************************************************************/
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001318/* Signal info (quality and access technology) polling */
1319
1320typedef enum {
1321 SIGNAL_CHECK_STEP_NONE,
1322 SIGNAL_CHECK_STEP_FIRST,
1323 SIGNAL_CHECK_STEP_SIGNAL_QUALITY,
1324 SIGNAL_CHECK_STEP_ACCESS_TECHNOLOGIES,
1325 SIGNAL_CHECK_STEP_LAST,
1326} SignalCheckStep;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001327
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001328typedef struct {
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001329 gboolean enabled;
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001330 guint timeout_source;
1331
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001332 /* We first attempt an initial loading, and once it's done we
1333 * setup polling */
1334 guint initial_retries;
1335 gboolean initial_check_done;
1336
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001337 /* Values polled in this iteration */
1338 guint signal_quality;
1339 MMModemAccessTechnology access_technologies;
1340 guint access_technologies_mask;
1341
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001342 /* If both signal and access tech polling are either unsupported
1343 * or disabled, we'll automatically stop polling */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001344 gboolean signal_quality_polling_supported;
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001345 gboolean signal_quality_polling_disabled;
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001346 gboolean access_technology_polling_supported;
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001347 gboolean access_technology_polling_disabled;
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001348
1349 /* Steps triggered when polling active */
1350 SignalCheckStep running_step;
1351} SignalCheckContext;
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001352
1353static void
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001354signal_check_context_free (SignalCheckContext *ctx)
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001355{
1356 if (ctx->timeout_source)
1357 g_source_remove (ctx->timeout_source);
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001358 g_slice_free (SignalCheckContext, ctx);
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001359}
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001360
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001361static SignalCheckContext *
1362get_signal_check_context (MMIfaceModem *self)
1363{
1364 SignalCheckContext *ctx;
1365
1366 if (G_UNLIKELY (!signal_check_context_quark))
1367 signal_check_context_quark = (g_quark_from_static_string (
1368 SIGNAL_CHECK_CONTEXT_TAG));
1369
1370 ctx = g_object_get_qdata (G_OBJECT (self), signal_check_context_quark);
1371 if (!ctx) {
1372 /* Create context and attach it to the object */
1373 ctx = g_slice_new0 (SignalCheckContext);
1374 ctx->running_step = SIGNAL_CHECK_STEP_NONE;
1375
1376 /* Initially assume supported if load_access_technologies() is
1377 * implemented. If the plugin reports an UNSUPPORTED error we'll clear
1378 * this flag and no longer poll. */
1379 ctx->access_technology_polling_supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies &&
1380 MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies_finish);
1381
1382 /* Initially assume supported if load_signal_quality() is
1383 * implemented. If the plugin reports an UNSUPPORTED error we'll clear
1384 * this flag and no longer poll. */
1385 ctx->signal_quality_polling_supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality &&
1386 MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish);
1387
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001388 /* Get plugin-specific setup for the polling logic */
1389 g_object_get (self,
1390 MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, &ctx->signal_quality_polling_disabled,
1391 MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, &ctx->access_technology_polling_disabled,
1392 NULL);
1393
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001394 g_object_set_qdata_full (G_OBJECT (self), signal_check_context_quark,
1395 ctx, (GDestroyNotify) signal_check_context_free);
1396 }
1397
1398 g_assert (ctx);
1399 return ctx;
1400}
1401
1402static void periodic_signal_check_disable (MMIfaceModem *self,
1403 gboolean clear);
1404static gboolean periodic_signal_check_cb (MMIfaceModem *self);
1405static void peridic_signal_check_step (MMIfaceModem *self);
1406
1407static void
1408access_technologies_check_ready (MMIfaceModem *self,
1409 GAsyncResult *res)
1410{
1411 GError *error = NULL;
1412 SignalCheckContext *ctx;
1413
1414 ctx = get_signal_check_context (self);
1415
1416 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies_finish (
1417 self,
1418 res,
1419 &ctx->access_technologies,
1420 &ctx->access_technologies_mask,
1421 &error)) {
1422 /* Did the plugin report that polling access technology is unsupported? */
1423 if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001424 mm_obj_dbg (self, "polling to refresh access technologies is unsupported");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001425 ctx->access_technology_polling_supported = FALSE;
Aleksander Morgado765f26a2019-09-17 13:28:51 +02001426 }
1427 /* Ignore logging any message if the error is in 'in-progress' */
1428 else if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS))
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001429 mm_obj_dbg (self, "couldn't refresh access technologies: %s", error->message);
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001430 g_error_free (error);
1431 }
1432 /* We may have been disabled while this command was running. */
1433 else if (ctx->enabled)
1434 mm_iface_modem_update_access_technologies (self, ctx->access_technologies, ctx->access_technologies_mask);
1435
1436 /* Go on */
1437 ctx->running_step++;
1438 peridic_signal_check_step (self);
1439}
Ben Chan1cf8ccb2013-01-17 23:06:45 -08001440
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001441static void
1442signal_quality_check_ready (MMIfaceModem *self,
1443 GAsyncResult *res)
1444{
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001445 GError *error = NULL;
1446 SignalCheckContext *ctx;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001447
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001448 ctx = get_signal_check_context (self);
1449
1450 ctx->signal_quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish (self, res, &error);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001451 if (error) {
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001452 /* Did the plugin report that polling signal quality is unsupported? */
1453 if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001454 mm_obj_dbg (self, "polling to refresh signal quality is unsupported");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001455 ctx->signal_quality_polling_supported = FALSE;
Aleksander Morgado765f26a2019-09-17 13:28:51 +02001456 }
1457 /* Ignore logging any message if the error is in 'in-progress' */
1458 else if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS))
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001459 mm_obj_dbg (self, "couldn't refresh signal quality: %s", error->message);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001460 g_error_free (error);
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001461 }
1462 /* We may have been disabled while this command was running. */
1463 else if (ctx->enabled)
1464 update_signal_quality (self, ctx->signal_quality, TRUE);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001465
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001466 /* Go on */
1467 ctx->running_step++;
1468 peridic_signal_check_step (self);
1469}
1470
1471static void
1472peridic_signal_check_step (MMIfaceModem *self)
1473{
1474 SignalCheckContext *ctx;
1475
1476 ctx = get_signal_check_context (self);
1477
1478 switch (ctx->running_step) {
1479 case SIGNAL_CHECK_STEP_NONE:
1480 g_assert_not_reached ();
1481
1482 case SIGNAL_CHECK_STEP_FIRST:
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001483 ctx->running_step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01001484 /* fall-through */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001485
1486 case SIGNAL_CHECK_STEP_SIGNAL_QUALITY:
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001487 if (ctx->enabled && ctx->signal_quality_polling_supported &&
1488 (!ctx->initial_check_done || !ctx->signal_quality_polling_disabled)) {
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001489 MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (
1490 self, (GAsyncReadyCallback)signal_quality_check_ready, NULL);
1491 return;
1492 }
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001493 ctx->running_step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01001494 /* fall-through */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001495
1496 case SIGNAL_CHECK_STEP_ACCESS_TECHNOLOGIES:
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001497 if (ctx->enabled && ctx->access_technology_polling_supported &&
1498 (!ctx->initial_check_done || !ctx->access_technology_polling_disabled)) {
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001499 MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies (
1500 self, (GAsyncReadyCallback)access_technologies_check_ready, NULL);
1501 return;
1502 }
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001503 ctx->running_step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01001504 /* fall-through */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001505
1506 case SIGNAL_CHECK_STEP_LAST:
1507 /* Flag as sequence finished */
1508 ctx->running_step = SIGNAL_CHECK_STEP_NONE;
1509
1510 /* If we have been disabled while we were running the steps, we don't
1511 * do anything else. */
1512 if (!ctx->enabled) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001513 mm_obj_dbg (self, "periodic signal quality and access technology checks not rescheduled: disabled");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001514 return;
1515 }
1516
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001517 /* Schedule when we poll next time.
1518 * Initially we poll at a higher frequency until we get valid signal
1519 * quality and access technology values. As soon as we get them, OR if
1520 * we made too many retries at a high frequency, we fallback to the
1521 * slower polling. */
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001522 if (!ctx->initial_check_done) {
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001523 gboolean signal_quality_ready;
1524 gboolean access_technology_ready;
1525
1526 /* Signal quality is ready if unsupported or if we got a valid
1527 * value reported */
1528 signal_quality_ready = (!ctx->signal_quality_polling_supported || (ctx->signal_quality != 0));
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001529
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001530 /* Access technology is ready if unsupported or if we got a valid
1531 * value reported */
1532 access_technology_ready = (!ctx->access_technology_polling_supported ||
1533 ((ctx->access_technologies & ctx->access_technologies_mask) != MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN));
1534
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001535 ctx->initial_check_done = ((signal_quality_ready && access_technology_ready) || (--ctx->initial_retries == 0));
Ben Chan1cf8ccb2013-01-17 23:06:45 -08001536 }
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001537
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001538 /* After running the initial check, if both signal quality and access tech
1539 * loading are either disabled or unsupported, we'll stop polling completely,
1540 * because they may be loaded asynchronously by unsolicited messages */
1541 if (ctx->initial_check_done &&
1542 (!ctx->signal_quality_polling_supported || ctx->signal_quality_polling_disabled) &&
1543 (!ctx->access_technology_polling_supported || ctx->access_technology_polling_disabled)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001544 mm_obj_dbg (self, "periodic signal quality and access technology checks not rescheduled: unneeded or unsupported");
Ben Chan708b00a2018-04-23 16:24:41 -07001545 periodic_signal_check_disable (self, FALSE);
1546 return;
1547 }
1548
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001549 mm_obj_dbg (self, "periodic signal quality and access technology checks scheduled");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001550 g_assert (!ctx->timeout_source);
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001551 ctx->timeout_source = g_timeout_add_seconds (ctx->initial_check_done ? SIGNAL_CHECK_TIMEOUT_SEC : SIGNAL_CHECK_INITIAL_TIMEOUT_SEC,
1552 (GSourceFunc) periodic_signal_check_cb,
1553 self);
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001554 return;
Aleksander Morgadoeb04ead2019-11-28 22:46:04 +01001555
1556 default:
1557 g_assert_not_reached ();
Ben Chan1cf8ccb2013-01-17 23:06:45 -08001558 }
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001559}
1560
1561static gboolean
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001562periodic_signal_check_cb (MMIfaceModem *self)
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001563{
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001564 SignalCheckContext *ctx;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001565
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001566 ctx = get_signal_check_context (self);
1567 g_assert (ctx->enabled);
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001568
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001569 /* Start the sequence */
1570 ctx->running_step = SIGNAL_CHECK_STEP_FIRST;
1571 ctx->signal_quality = 0;
1572 ctx->access_technologies = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
1573 ctx->access_technologies_mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY;
1574 peridic_signal_check_step (self);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001575
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001576 /* Remove the timeout and clear the source id */
1577 if (ctx->timeout_source)
1578 ctx->timeout_source = 0;
1579 return G_SOURCE_REMOVE;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001580}
1581
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001582void
1583mm_iface_modem_refresh_signal (MMIfaceModem *self)
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001584{
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001585 SignalCheckContext *ctx;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001586
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001587 /* Don't refresh polling if we're not enabled */
1588 ctx = get_signal_check_context (self);
1589 if (!ctx->enabled) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001590 mm_obj_dbg (self, "periodic signal check refresh ignored: checks not enabled");
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001591 return;
1592 }
1593
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001594 /* Don't refresh if we're already doing it */
1595 if (ctx->running_step != SIGNAL_CHECK_STEP_NONE) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001596 mm_obj_dbg (self, "periodic signal check refresh ignored: check already running");
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001597 return;
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001598 }
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001599
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001600 mm_obj_dbg (self, "periodic signal check refresh requested");
Aleksander Morgado73eeffb2011-12-29 23:16:14 +01001601
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001602 /* Remove the scheduled timeout as we're going to refresh
1603 * right away */
1604 if (ctx->timeout_source) {
1605 g_source_remove (ctx->timeout_source);
1606 ctx->timeout_source = 0;
1607 }
1608
1609 /* Reset refresh rate and initial retries when we're asked to refresh signal
1610 * so that we poll at a higher frequency */
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001611 ctx->initial_retries = SIGNAL_CHECK_INITIAL_RETRIES;
1612 ctx->initial_check_done = FALSE;
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001613
1614 /* Start sequence */
1615 periodic_signal_check_cb (self);
1616}
1617
1618static void
1619periodic_signal_check_disable (MMIfaceModem *self,
1620 gboolean clear)
1621{
1622 SignalCheckContext *ctx;
1623
1624 ctx = get_signal_check_context (self);
1625 if (!ctx->enabled)
1626 return;
1627
1628 /* Clear access technology and signal quality */
1629 if (clear) {
1630 update_signal_quality (self, 0, FALSE);
1631 mm_iface_modem_update_access_technologies (self,
1632 MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,
1633 MM_MODEM_ACCESS_TECHNOLOGY_ANY);
1634 }
1635
1636 /* Remove scheduled timeout */
1637 if (ctx->timeout_source) {
1638 g_source_remove (ctx->timeout_source);
1639 ctx->timeout_source = 0;
1640 }
1641
1642 ctx->enabled = FALSE;
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001643 mm_obj_dbg (self, "periodic signal checks disabled");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001644}
1645
1646static void
1647periodic_signal_check_enable (MMIfaceModem *self)
1648{
1649 SignalCheckContext *ctx;
1650
1651 ctx = get_signal_check_context (self);
1652
1653 /* If polling access technology and signal quality not supported, don't even
1654 * bother trying. */
1655 if (!ctx->signal_quality_polling_supported && !ctx->access_technology_polling_supported) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001656 mm_obj_dbg (self, "not enabling periodic signal checks: unsupported");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001657 return;
1658 }
1659
1660 /* Log and flag as enabled */
1661 if (!ctx->enabled) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001662 mm_obj_dbg (self, "periodic signal checks enabled");
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001663 ctx->enabled = TRUE;
1664 }
1665
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02001666 /* And refresh, which will trigger the first check at high frequency */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001667 mm_iface_modem_refresh_signal (self);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001668}
1669
1670/*****************************************************************************/
1671
Aleksander Morgadodd200672011-12-20 10:34:36 +01001672static void
Aleksander Morgado3ca267b2014-07-06 15:55:34 +02001673bearer_list_count_connected (MMBaseBearer *bearer,
Aleksander Morgadodd200672011-12-20 10:34:36 +01001674 guint *count)
1675{
Aleksander Morgado3ca267b2014-07-06 15:55:34 +02001676 if (mm_base_bearer_get_status (bearer) == MM_BEARER_STATUS_CONNECTED)
Aleksander Morgadoe71a9ef2011-12-20 10:45:54 +01001677 (*count)++;
Aleksander Morgadodd200672011-12-20 10:34:36 +01001678}
1679
Aleksander Morgado75d20c12013-02-22 08:58:36 +01001680static void
1681__iface_modem_update_state_internal (MMIfaceModem *self,
1682 MMModemState new_state,
1683 MMModemStateChangeReason reason,
1684 MMModemStateFailedReason failed_reason)
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001685{
1686 MMModemState old_state = MM_MODEM_STATE_UNKNOWN;
1687 MmGdbusModem *skeleton = NULL;
Aleksander Morgadodd200672011-12-20 10:34:36 +01001688 MMBearerList *bearer_list = NULL;
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001689
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001690 g_object_get (self,
1691 MM_IFACE_MODEM_STATE, &old_state,
1692 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
Aleksander Morgadodd200672011-12-20 10:34:36 +01001693 MM_IFACE_MODEM_BEARER_LIST, &bearer_list,
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001694 NULL);
1695
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02001696 if (!skeleton || !bearer_list) {
1697 if (skeleton)
1698 g_object_unref (skeleton);
1699 if (bearer_list)
1700 g_object_unref (bearer_list);
1701 return;
1702 }
1703
Aleksander Morgadodd200672011-12-20 10:34:36 +01001704 /* While connected we don't want registration status changes to change
1705 * the modem's state away from CONNECTED. */
Aleksander Morgado16e3bb82020-08-04 14:13:45 +02001706 if ((new_state == MM_MODEM_STATE_ENABLED ||
1707 new_state == MM_MODEM_STATE_SEARCHING ||
Aleksander Morgadodd200672011-12-20 10:34:36 +01001708 new_state == MM_MODEM_STATE_REGISTERED) &&
1709 bearer_list &&
1710 old_state > MM_MODEM_STATE_REGISTERED) {
1711 guint connected = 0;
1712
1713 mm_bearer_list_foreach (bearer_list,
1714 (MMBearerListForeachFunc)bearer_list_count_connected,
1715 &connected);
1716 if (connected > 0)
1717 /* Don't update state */
1718 new_state = old_state;
1719 }
1720
Aleksander Morgadoa12d1e32012-10-24 16:22:25 +02001721 /* Enabled may really be searching or registered */
1722 if (new_state == MM_MODEM_STATE_ENABLED)
Aleksander Morgadoaa223872019-05-28 17:59:30 +02001723 new_state = get_consolidated_subsystem_state (self);
Aleksander Morgadoa12d1e32012-10-24 16:22:25 +02001724
Aleksander Morgadodd200672011-12-20 10:34:36 +01001725 /* Update state only if different */
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001726 if (new_state != old_state) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001727 mm_obj_info (self, "state changed (%s -> %s)",
1728 mm_modem_state_get_string (old_state),
1729 mm_modem_state_get_string (new_state));
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001730
1731 /* The property in the interface is bound to the property
1732 * in the skeleton, so just updating here is enough */
1733 g_object_set (self,
1734 MM_IFACE_MODEM_STATE, new_state,
1735 NULL);
1736
1737 /* Signal status change */
Aleksander Morgado00a8ed32012-09-28 14:57:25 +02001738 if (skeleton) {
Aleksander Morgado75d20c12013-02-22 08:58:36 +01001739 /* Set failure reason */
1740 if (failed_reason != mm_gdbus_modem_get_state_failed_reason (skeleton))
1741 mm_gdbus_modem_set_state_failed_reason (skeleton, failed_reason);
1742
Aleksander Morgado00a8ed32012-09-28 14:57:25 +02001743 /* Flush current change before signaling the state change,
1744 * so that clients get the proper state already in the
1745 * state-changed callback */
1746 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (skeleton));
Aleksander Morgadod27e40a2012-03-09 19:48:43 +01001747 mm_gdbus_modem_emit_state_changed (skeleton,
1748 old_state,
1749 new_state,
1750 reason);
Aleksander Morgado00a8ed32012-09-28 14:57:25 +02001751 }
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001752
Aleksander Morgadoe8acfe02017-05-15 12:26:57 +02001753 /* If we go to a registered/connected state (from unregistered), setup
1754 * signal quality and access technologies periodic retrieval */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001755 if (new_state >= MM_MODEM_STATE_REGISTERED && old_state < MM_MODEM_STATE_REGISTERED)
1756 periodic_signal_check_enable (self);
Aleksander Morgadof0433a42011-12-28 20:31:48 +01001757 /* If we go from a registered/connected state to unregistered,
1758 * cleanup signal quality retrieval */
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02001759 else if (old_state >= MM_MODEM_STATE_REGISTERED && new_state < MM_MODEM_STATE_REGISTERED)
1760 periodic_signal_check_disable (self, TRUE);
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001761 }
Aleksander Morgadodd200672011-12-20 10:34:36 +01001762
1763 if (skeleton)
1764 g_object_unref (skeleton);
1765 if (bearer_list)
1766 g_object_unref (bearer_list);
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001767}
1768
Aleksander Morgado75d20c12013-02-22 08:58:36 +01001769void
1770mm_iface_modem_update_state (MMIfaceModem *self,
1771 MMModemState new_state,
1772 MMModemStateChangeReason reason)
1773{
Aleksander Morgado89461cf2013-02-26 21:17:43 +01001774 if (new_state == MM_MODEM_STATE_FAILED) {
1775 mm_iface_modem_update_failed_state (self, MM_MODEM_STATE_FAILED_REASON_UNKNOWN);
1776 return;
1777 }
Aleksander Morgado75d20c12013-02-22 08:58:36 +01001778
1779 __iface_modem_update_state_internal (self, new_state, reason, MM_MODEM_STATE_FAILED_REASON_NONE);
1780}
1781
1782void
1783mm_iface_modem_update_failed_state (MMIfaceModem *self,
1784 MMModemStateFailedReason failed_reason)
1785{
1786 __iface_modem_update_state_internal (self, MM_MODEM_STATE_FAILED, MM_MODEM_STATE_CHANGE_REASON_FAILURE, failed_reason);
1787}
1788
Aleksander Morgadof049dbb2011-11-25 14:42:34 +01001789/*****************************************************************************/
1790
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001791typedef struct {
1792 gchar *subsystem;
1793 MMModemState state;
1794} SubsystemState;
1795
1796static void
1797subsystem_state_array_free (GArray *array)
1798{
1799 guint i;
1800
1801 for (i = 0; i < array->len; i++) {
1802 SubsystemState *s;
1803
1804 s = &g_array_index (array, SubsystemState, i);
1805 g_free (s->subsystem);
1806 }
1807
1808 g_array_free (array, TRUE);
1809}
1810
1811static MMModemState
Aleksander Morgadoaa223872019-05-28 17:59:30 +02001812get_consolidated_subsystem_state (MMIfaceModem *self)
Aleksander Morgado4aeadbb2012-01-20 12:30:12 +01001813{
Aleksander Morgadoaa223872019-05-28 17:59:30 +02001814 /* Use as initial state ENABLED, which is the minimum one expected. Do not
1815 * use the old modem state as initial state, as that would disallow reporting
1816 * e.g. ENABLED if the old state was REGISTERED (as ENABLED < REGISTERED). */
1817 MMModemState consolidated = MM_MODEM_STATE_ENABLED;
Aleksander Morgado4aeadbb2012-01-20 12:30:12 +01001818 GArray *subsystem_states;
1819
1820 if (G_UNLIKELY (!state_update_context_quark))
1821 state_update_context_quark = (g_quark_from_static_string (
1822 STATE_UPDATE_CONTEXT_TAG));
1823
1824 subsystem_states = g_object_get_qdata (G_OBJECT (self),
1825 state_update_context_quark);
1826
1827 /* Build consolidated state, expected fixes are:
1828 * - Enabled (meaning unregistered) --> Searching|Registered
1829 * - Searching --> Registered
1830 */
1831 if (subsystem_states) {
1832 guint i;
1833
1834 for (i = 0; i < subsystem_states->len; i++) {
1835 SubsystemState *s;
1836
1837 s = &g_array_index (subsystem_states, SubsystemState, i);
1838 if (s->state > consolidated)
1839 consolidated = s->state;
1840 }
1841 }
1842
1843 return consolidated;
1844}
1845
1846static MMModemState
1847get_updated_consolidated_state (MMIfaceModem *self,
Ben Chan69aff612013-01-23 17:16:52 -08001848 MMModemState modem_state,
Aleksander Morgado4aeadbb2012-01-20 12:30:12 +01001849 const gchar *subsystem,
1850 MMModemState subsystem_state)
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001851{
1852 guint i;
1853 GArray *subsystem_states;
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001854
1855 /* Reported subsystem states will be REGISTRATION-related. This means
1856 * that we would only expect a subset of the states being reported for
Ben Chan073163f2013-12-04 23:44:15 -08001857 * the subsystem. Warn if we get others */
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001858 g_warn_if_fail (subsystem_state == MM_MODEM_STATE_ENABLED ||
1859 subsystem_state == MM_MODEM_STATE_SEARCHING ||
1860 subsystem_state == MM_MODEM_STATE_REGISTERED);
1861
1862 if (G_UNLIKELY (!state_update_context_quark))
1863 state_update_context_quark = (g_quark_from_static_string (
1864 STATE_UPDATE_CONTEXT_TAG));
1865
1866 subsystem_states = g_object_get_qdata (G_OBJECT (self),
1867 state_update_context_quark);
1868 if (!subsystem_states) {
1869 subsystem_states = g_array_sized_new (FALSE,
1870 FALSE,
1871 sizeof (SubsystemState),
1872 2);
1873 g_object_set_qdata_full (G_OBJECT (self),
1874 state_update_context_quark,
1875 subsystem_states,
1876 (GDestroyNotify)subsystem_state_array_free);
1877 }
1878
1879 /* Store new subsystem state */
1880 for (i = 0; i < subsystem_states->len; i++) {
1881 SubsystemState *s;
1882
1883 s = &g_array_index (subsystem_states, SubsystemState, i);
1884 if (g_str_equal (s->subsystem, subsystem)) {
1885 s->state = subsystem_state;
1886 break;
1887 }
1888 }
1889
1890 /* If not found, insert new element */
1891 if (i == subsystem_states->len) {
1892 SubsystemState s;
1893
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01001894 mm_obj_dbg (self, "will start keeping track of state for subsystem '%s'", subsystem);
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001895 s.subsystem = g_strdup (subsystem);
1896 s.state = subsystem_state;
1897 g_array_append_val (subsystem_states, s);
1898 }
1899
Aleksander Morgadoaa223872019-05-28 17:59:30 +02001900 return get_consolidated_subsystem_state (self);
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001901}
1902
1903void
1904mm_iface_modem_update_subsystem_state (MMIfaceModem *self,
1905 const gchar *subsystem,
1906 MMModemState new_state,
Aleksander Morgado12786d22012-02-27 23:00:11 +01001907 MMModemStateChangeReason reason)
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001908{
1909 MMModemState consolidated;
Aleksander Morgadof6678982012-10-24 16:22:55 +02001910 MMModemState state = MM_MODEM_STATE_UNKNOWN;
1911
1912 g_object_get (self,
1913 MM_IFACE_MODEM_STATE, &state,
1914 NULL);
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001915
1916 /* We may have different subsystems being handled (e.g. 3GPP and CDMA), and
1917 * the registration status value is unique, so if we get subsystem-specific
1918 * state updates, we'll need to merge all to get a consolidated one. */
Ben Chan69aff612013-01-23 17:16:52 -08001919 consolidated = get_updated_consolidated_state (self, state, subsystem, new_state);
Aleksander Morgadof6678982012-10-24 16:22:55 +02001920
1921 /* Don't update registration-related states while disabling/enabling */
1922 if (state == MM_MODEM_STATE_ENABLING ||
1923 state == MM_MODEM_STATE_DISABLING)
1924 return;
1925
Aleksander Morgado0b8d0c62012-01-05 19:05:15 +01001926 mm_iface_modem_update_state (self, consolidated, reason);
1927}
1928
1929/*****************************************************************************/
1930
Aleksander Morgado22407472012-02-27 10:40:03 +01001931typedef struct {
1932 MmGdbusModem *skeleton;
1933 GDBusMethodInvocation *invocation;
1934 MMIfaceModem *self;
1935 gboolean enable;
1936} HandleEnableContext;
1937
Aleksander Morgado27494ea2011-11-25 15:27:41 +01001938static void
Aleksander Morgado22407472012-02-27 10:40:03 +01001939handle_enable_context_free (HandleEnableContext *ctx)
1940{
1941 g_object_unref (ctx->skeleton);
1942 g_object_unref (ctx->invocation);
1943 g_object_unref (ctx->self);
1944 g_free (ctx);
1945}
1946
1947static void
1948enable_ready (MMBaseModem *self,
1949 GAsyncResult *res,
1950 HandleEnableContext *ctx)
Aleksander Morgado27494ea2011-11-25 15:27:41 +01001951{
1952 GError *error = NULL;
1953
Aleksander Morgado22407472012-02-27 10:40:03 +01001954 if (ctx->enable) {
Aleksander Morgado215c2782012-03-08 15:30:48 +01001955 if (!mm_base_modem_enable_finish (self, res, &error))
Aleksander Morgado22407472012-02-27 10:40:03 +01001956 g_dbus_method_invocation_take_error (ctx->invocation, error);
1957 else
1958 mm_gdbus_modem_complete_enable (ctx->skeleton, ctx->invocation);
1959 } else {
Aleksander Morgado215c2782012-03-08 15:30:48 +01001960 if (!mm_base_modem_disable_finish (self, res, &error))
Aleksander Morgado22407472012-02-27 10:40:03 +01001961 g_dbus_method_invocation_take_error (ctx->invocation, error);
1962 else
1963 mm_gdbus_modem_complete_enable (ctx->skeleton, ctx->invocation);
1964 }
1965
1966 handle_enable_context_free (ctx);
1967}
1968
1969static void
1970handle_enable_auth_ready (MMBaseModem *self,
1971 GAsyncResult *res,
1972 HandleEnableContext *ctx)
1973{
1974 GError *error = NULL;
1975
1976 if (!mm_base_modem_authorize_finish (self, res, &error)) {
1977 g_dbus_method_invocation_take_error (ctx->invocation, error);
1978 handle_enable_context_free (ctx);
1979 return;
1980 }
1981
Aleksander Morgadocae73772018-12-06 14:54:19 +01001982 if (abort_invocation_if_state_not_reached (ctx->self, ctx->invocation, MM_MODEM_STATE_LOCKED)) {
1983 handle_enable_context_free (ctx);
1984 return;
1985 }
1986
Aleksander Morgado215c2782012-03-08 15:30:48 +01001987 if (ctx->enable)
1988 mm_base_modem_enable (self,
1989 (GAsyncReadyCallback)enable_ready,
1990 ctx);
1991 else
1992 mm_base_modem_disable (self,
1993 (GAsyncReadyCallback)enable_ready,
1994 ctx);
Aleksander Morgado27494ea2011-11-25 15:27:41 +01001995}
1996
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01001997static gboolean
Aleksander Morgado27494ea2011-11-25 15:27:41 +01001998handle_enable (MmGdbusModem *skeleton,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01001999 GDBusMethodInvocation *invocation,
Aleksander Morgado22407472012-02-27 10:40:03 +01002000 gboolean enable,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002001 MMIfaceModem *self)
2002{
Aleksander Morgado22407472012-02-27 10:40:03 +01002003 HandleEnableContext *ctx;
Aleksander Morgado27494ea2011-11-25 15:27:41 +01002004
Aleksander Morgado22407472012-02-27 10:40:03 +01002005 ctx = g_new (HandleEnableContext, 1);
2006 ctx->skeleton = g_object_ref (skeleton);
2007 ctx->invocation = g_object_ref (invocation);
2008 ctx->self = g_object_ref (self);
2009 ctx->enable = enable;
2010
2011 mm_base_modem_authorize (MM_BASE_MODEM (self),
2012 invocation,
2013 MM_AUTHORIZATION_DEVICE_CONTROL,
2014 (GAsyncReadyCallback)handle_enable_auth_ready,
2015 ctx);
2016 return TRUE;
2017}
2018
2019/*****************************************************************************/
2020
2021typedef struct {
2022 MmGdbusModem *skeleton;
2023 GDBusMethodInvocation *invocation;
2024 MMIfaceModem *self;
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01002025 MMModemPowerState power_state;
2026} HandleSetPowerStateContext;
2027
2028static void
2029handle_set_power_state_context_free (HandleSetPowerStateContext *ctx)
2030{
2031 g_object_unref (ctx->skeleton);
2032 g_object_unref (ctx->invocation);
2033 g_object_unref (ctx->self);
2034 g_slice_free (HandleSetPowerStateContext, ctx);
2035}
2036
2037static void
2038set_power_state_ready (MMIfaceModem *self,
2039 GAsyncResult *res,
2040 HandleSetPowerStateContext *ctx)
2041{
2042 GError *error = NULL;
2043
2044 if (!mm_iface_modem_set_power_state_finish (self, res, &error))
2045 g_dbus_method_invocation_take_error (ctx->invocation, error);
2046 else
2047 mm_gdbus_modem_complete_set_power_state (ctx->skeleton, ctx->invocation);
2048 handle_set_power_state_context_free (ctx);
2049}
2050
2051static void
2052handle_set_power_state_auth_ready (MMBaseModem *self,
2053 GAsyncResult *res,
2054 HandleSetPowerStateContext *ctx)
2055{
2056 MMModemState modem_state;
2057 GError *error = NULL;
2058
2059 if (!mm_base_modem_authorize_finish (self, res, &error)) {
2060 g_dbus_method_invocation_take_error (ctx->invocation, error);
2061 handle_set_power_state_context_free (ctx);
2062 return;
2063 }
2064
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01002065 /* Only 'off', 'low' or 'up' expected */
2066 if (ctx->power_state != MM_MODEM_POWER_STATE_LOW &&
2067 ctx->power_state != MM_MODEM_POWER_STATE_ON &&
2068 ctx->power_state != MM_MODEM_POWER_STATE_OFF) {
2069 g_dbus_method_invocation_return_error (ctx->invocation,
2070 MM_CORE_ERROR,
2071 MM_CORE_ERROR_INVALID_ARGS,
2072 "Cannot set '%s' power state",
2073 mm_modem_power_state_get_string (ctx->power_state));
2074 handle_set_power_state_context_free (ctx);
2075 return;
2076 }
2077
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01002078 modem_state = MM_MODEM_STATE_UNKNOWN;
2079 g_object_get (self,
2080 MM_IFACE_MODEM_STATE, &modem_state,
2081 NULL);
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01002082
2083 /* Going into LOW or ON only allowed in disabled state */
2084 if ((ctx->power_state == MM_MODEM_POWER_STATE_LOW ||
2085 ctx->power_state == MM_MODEM_POWER_STATE_ON) &&
2086 modem_state != MM_MODEM_STATE_DISABLED) {
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01002087 g_dbus_method_invocation_return_error (ctx->invocation,
2088 MM_CORE_ERROR,
2089 MM_CORE_ERROR_WRONG_STATE,
2090 "Cannot set power state: not in disabled state");
2091 handle_set_power_state_context_free (ctx);
2092 return;
2093 }
2094
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01002095 /* Going into OFF, only allowed if locked, disabled or failed */
2096 if (ctx->power_state == MM_MODEM_POWER_STATE_OFF &&
2097 modem_state != MM_MODEM_STATE_FAILED &&
2098 modem_state != MM_MODEM_STATE_LOCKED &&
2099 modem_state != MM_MODEM_STATE_DISABLED) {
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01002100 g_dbus_method_invocation_return_error (ctx->invocation,
2101 MM_CORE_ERROR,
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01002102 MM_CORE_ERROR_WRONG_STATE,
2103 "Cannot set power state: modem either enabled or initializing");
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01002104 handle_set_power_state_context_free (ctx);
2105 return;
2106 }
2107
2108 mm_iface_modem_set_power_state (MM_IFACE_MODEM (self),
2109 ctx->power_state,
2110 (GAsyncReadyCallback)set_power_state_ready,
2111 ctx);
2112}
2113
2114static gboolean
2115handle_set_power_state (MmGdbusModem *skeleton,
2116 GDBusMethodInvocation *invocation,
2117 guint32 power_state,
2118 MMIfaceModem *self)
2119{
2120 HandleSetPowerStateContext *ctx;
2121
2122 ctx = g_slice_new (HandleSetPowerStateContext);
2123 ctx->skeleton = g_object_ref (skeleton);
2124 ctx->invocation = g_object_ref (invocation);
2125 ctx->self = g_object_ref (self);
2126 ctx->power_state = (MMModemPowerState)power_state;
2127
2128 mm_base_modem_authorize (MM_BASE_MODEM (self),
2129 invocation,
2130 MM_AUTHORIZATION_DEVICE_CONTROL,
2131 (GAsyncReadyCallback)handle_set_power_state_auth_ready,
2132 ctx);
2133 return TRUE;
2134}
2135
2136/*****************************************************************************/
2137
2138typedef struct {
2139 MmGdbusModem *skeleton;
2140 GDBusMethodInvocation *invocation;
2141 MMIfaceModem *self;
Aleksander Morgado22407472012-02-27 10:40:03 +01002142} HandleResetContext;
2143
2144static void
2145handle_reset_context_free (HandleResetContext *ctx)
2146{
2147 g_object_unref (ctx->skeleton);
2148 g_object_unref (ctx->invocation);
2149 g_object_unref (ctx->self);
2150 g_free (ctx);
2151}
2152
2153static void
2154handle_reset_ready (MMIfaceModem *self,
2155 GAsyncResult *res,
2156 HandleResetContext *ctx)
2157{
2158 GError *error = NULL;
2159
2160 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->reset_finish (self, res, &error))
2161 g_dbus_method_invocation_take_error (ctx->invocation, error);
2162 else
2163 mm_gdbus_modem_complete_reset (ctx->skeleton, ctx->invocation);
2164
2165 handle_reset_context_free (ctx);
2166}
2167
2168static void
2169handle_reset_auth_ready (MMBaseModem *self,
2170 GAsyncResult *res,
2171 HandleResetContext *ctx)
2172{
Aleksander Morgado22407472012-02-27 10:40:03 +01002173 GError *error = NULL;
2174
2175 if (!mm_base_modem_authorize_finish (self, res, &error)) {
2176 g_dbus_method_invocation_take_error (ctx->invocation, error);
2177 handle_reset_context_free (ctx);
2178 return;
2179 }
2180
2181 /* If reseting is not implemented, report an error */
2182 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->reset ||
2183 !MM_IFACE_MODEM_GET_INTERFACE (self)->reset_finish) {
2184 g_dbus_method_invocation_return_error (ctx->invocation,
2185 MM_CORE_ERROR,
2186 MM_CORE_ERROR_UNSUPPORTED,
2187 "Cannot reset the modem: operation not supported");
2188 handle_reset_context_free (ctx);
2189 return;
2190 }
Aleksander Morgado27494ea2011-11-25 15:27:41 +01002191
Aleksander Morgado75187722012-03-30 11:06:32 +02002192 MM_IFACE_MODEM_GET_INTERFACE (self)->reset (MM_IFACE_MODEM (self),
2193 (GAsyncReadyCallback)handle_reset_ready,
2194 ctx);
Aleksander Morgado03490d12011-11-22 19:03:25 +01002195}
2196
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002197static gboolean
Aleksander Morgado03490d12011-11-22 19:03:25 +01002198handle_reset (MmGdbusModem *skeleton,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002199 GDBusMethodInvocation *invocation,
2200 MMIfaceModem *self)
2201{
Aleksander Morgado22407472012-02-27 10:40:03 +01002202 HandleResetContext *ctx;
Aleksander Morgado03490d12011-11-22 19:03:25 +01002203
Aleksander Morgado22407472012-02-27 10:40:03 +01002204 ctx = g_new (HandleResetContext, 1);
2205 ctx->skeleton = g_object_ref (skeleton);
2206 ctx->invocation = g_object_ref (invocation);
2207 ctx->self = g_object_ref (self);
Aleksander Morgado03490d12011-11-22 19:03:25 +01002208
Aleksander Morgado22407472012-02-27 10:40:03 +01002209 mm_base_modem_authorize (MM_BASE_MODEM (self),
2210 invocation,
2211 MM_AUTHORIZATION_DEVICE_CONTROL,
2212 (GAsyncReadyCallback)handle_reset_auth_ready,
2213 ctx);
Aleksander Morgado03490d12011-11-22 19:03:25 +01002214
2215 return TRUE;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002216}
2217
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002218/*****************************************************************************/
2219
Aleksander Morgado22407472012-02-27 10:40:03 +01002220typedef struct {
2221 MmGdbusModem *skeleton;
2222 GDBusMethodInvocation *invocation;
2223 MMIfaceModem *self;
2224 gchar *code;
2225} HandleFactoryResetContext;
2226
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002227static void
Aleksander Morgado22407472012-02-27 10:40:03 +01002228handle_factory_reset_context_free (HandleFactoryResetContext *ctx)
2229{
2230 g_object_unref (ctx->skeleton);
2231 g_object_unref (ctx->invocation);
2232 g_object_unref (ctx->self);
2233 g_free (ctx->code);
2234 g_free (ctx);
2235}
2236
2237static void
2238handle_factory_reset_ready (MMIfaceModem *self,
2239 GAsyncResult *res,
2240 HandleFactoryResetContext *ctx)
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002241{
2242 GError *error = NULL;
2243
Aleksander Morgado22407472012-02-27 10:40:03 +01002244 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->factory_reset_finish (self, res, &error))
2245 g_dbus_method_invocation_take_error (ctx->invocation, error);
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002246 else
Aleksander Morgado22407472012-02-27 10:40:03 +01002247 mm_gdbus_modem_complete_factory_reset (ctx->skeleton, ctx->invocation);
2248
2249 handle_factory_reset_context_free (ctx);
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002250}
2251
Aleksander Morgado22407472012-02-27 10:40:03 +01002252static void
2253handle_factory_reset_auth_ready (MMBaseModem *self,
2254 GAsyncResult *res,
2255 HandleFactoryResetContext *ctx)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002256{
Aleksander Morgado22407472012-02-27 10:40:03 +01002257 GError *error = NULL;
2258
2259 if (!mm_base_modem_authorize_finish (self, res, &error)) {
2260 g_dbus_method_invocation_take_error (ctx->invocation, error);
2261 handle_factory_reset_context_free (ctx);
2262 return;
2263 }
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002264
2265 /* If reseting is not implemented, report an error */
2266 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->factory_reset ||
2267 !MM_IFACE_MODEM_GET_INTERFACE (self)->factory_reset_finish) {
Aleksander Morgado22407472012-02-27 10:40:03 +01002268 g_dbus_method_invocation_return_error (ctx->invocation,
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002269 MM_CORE_ERROR,
2270 MM_CORE_ERROR_UNSUPPORTED,
2271 "Cannot reset the modem to factory defaults: "
2272 "operation not supported");
Aleksander Morgado22407472012-02-27 10:40:03 +01002273 handle_factory_reset_context_free (ctx);
2274 return;
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002275 }
2276
Aleksander Morgado75187722012-03-30 11:06:32 +02002277 MM_IFACE_MODEM_GET_INTERFACE (self)->factory_reset (MM_IFACE_MODEM (self),
2278 ctx->code,
2279 (GAsyncReadyCallback)handle_factory_reset_ready,
2280 ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01002281}
2282
2283static gboolean
2284handle_factory_reset (MmGdbusModem *skeleton,
2285 GDBusMethodInvocation *invocation,
2286 const gchar *code,
2287 MMIfaceModem *self)
2288{
2289 HandleFactoryResetContext *ctx;
2290
2291 ctx = g_new (HandleFactoryResetContext, 1);
2292 ctx->skeleton = g_object_ref (skeleton);
2293 ctx->invocation = g_object_ref (invocation);
2294 ctx->self = g_object_ref (self);
2295 ctx->code = g_strdup (code);
2296
2297 mm_base_modem_authorize (MM_BASE_MODEM (self),
2298 invocation,
2299 MM_AUTHORIZATION_DEVICE_CONTROL,
2300 (GAsyncReadyCallback)handle_factory_reset_auth_ready,
2301 ctx);
Aleksander Morgadob9d60d22011-11-22 19:06:07 +01002302
2303 return TRUE;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002304}
2305
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002306/*****************************************************************************/
Aleksander Morgadocae73772018-12-06 14:54:19 +01002307/* Current capabilities setting
2308 *
2309 * Setting capabilities allowed also in FAILED state. Just imagine a
2310 * 3GPP+3GPP2 modem in 3GPP-only mode without SIM, we should allow
2311 * changing caps to 3GPP2, which doesn't require SIM
2312 */
Aleksander Morgadoa902e682013-05-24 12:55:07 +02002313
2314typedef struct {
2315 MmGdbusModem *skeleton;
2316 GDBusMethodInvocation *invocation;
2317 MMIfaceModem *self;
2318 MMModemCapability capabilities;
2319} HandleSetCurrentCapabilitiesContext;
2320
2321static void
2322handle_set_current_capabilities_context_free (HandleSetCurrentCapabilitiesContext *ctx)
2323{
2324 g_object_unref (ctx->skeleton);
2325 g_object_unref (ctx->invocation);
2326 g_object_unref (ctx->self);
2327 g_slice_free (HandleSetCurrentCapabilitiesContext, ctx);
2328}
2329
2330static void
2331set_current_capabilities_ready (MMIfaceModem *self,
2332 GAsyncResult *res,
2333 HandleSetCurrentCapabilitiesContext *ctx)
2334{
2335 GError *error = NULL;
2336
2337 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_capabilities_finish (self, res, &error))
2338 g_dbus_method_invocation_take_error (ctx->invocation, error);
Aleksander Morgado2c19b1f2017-05-30 20:09:56 +02002339 else {
2340 /* Capabilities updated: explicitly refresh signal and access technology */
2341 mm_iface_modem_refresh_signal (self);
Aleksander Morgadoa902e682013-05-24 12:55:07 +02002342 mm_gdbus_modem_complete_set_current_capabilities (ctx->skeleton, ctx->invocation);
Aleksander Morgado2c19b1f2017-05-30 20:09:56 +02002343 }
2344
Aleksander Morgadoa902e682013-05-24 12:55:07 +02002345 handle_set_current_capabilities_context_free (ctx);
2346}
2347
2348static void
2349handle_set_current_capabilities_auth_ready (MMBaseModem *self,
2350 GAsyncResult *res,
2351 HandleSetCurrentCapabilitiesContext *ctx)
2352{
2353 GError *error = NULL;
2354 gchar *capabilities_string;
2355 GArray *supported;
2356 gboolean matched = FALSE;
2357 guint i;
2358
2359 if (!mm_base_modem_authorize_finish (self, res, &error)) {
2360 g_dbus_method_invocation_take_error (ctx->invocation, error);
2361 handle_set_current_capabilities_context_free (ctx);
2362 return;
2363 }
2364
2365 /* Get list of supported capabilities */
2366 supported = mm_common_capability_combinations_variant_to_garray (
2367 mm_gdbus_modem_get_supported_capabilities (ctx->skeleton));
2368
2369 /* Don't allow capability switching if only one item given in the supported list */
2370 if (supported->len == 1) {
2371 g_dbus_method_invocation_return_error (ctx->invocation,
2372 MM_CORE_ERROR,
2373 MM_CORE_ERROR_UNSUPPORTED,
2374 "Cannot change capabilities: only one combination supported");
2375 handle_set_current_capabilities_context_free (ctx);
2376 g_array_unref (supported);
2377 return;
2378 }
2379
2380 /* Check if the given combination is supported */
2381 for (i = 0; !matched && i < supported->len; i++) {
2382 MMModemCapability supported_capability;
2383
2384 supported_capability = g_array_index (supported, MMModemCapability, i);
2385 if (supported_capability == ctx->capabilities)
2386 matched = TRUE;
2387 }
2388 g_array_unref (supported);
2389
2390 if (!matched) {
2391 g_dbus_method_invocation_return_error (ctx->invocation,
2392 MM_CORE_ERROR,
2393 MM_CORE_ERROR_UNSUPPORTED,
2394 "The given combination of capabilities is not supported");
2395 handle_set_current_capabilities_context_free (ctx);
2396 return;
2397 }
2398
2399 /* Check if we already are in the requested setup */
2400 if (mm_gdbus_modem_get_current_capabilities (ctx->skeleton) == ctx->capabilities) {
2401 /* Nothing to do */
2402 mm_gdbus_modem_complete_set_current_capabilities (ctx->skeleton, ctx->invocation);
2403 handle_set_current_capabilities_context_free (ctx);
2404 return;
2405 }
2406
2407 /* If setting current capabilities is not implemented, report an error */
2408 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_capabilities ||
2409 !MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_capabilities_finish) {
2410 g_dbus_method_invocation_return_error (ctx->invocation,
2411 MM_CORE_ERROR,
2412 MM_CORE_ERROR_UNSUPPORTED,
2413 "Setting current capabilities not supported");
2414 handle_set_current_capabilities_context_free (ctx);
2415 return;
2416 }
2417
2418 capabilities_string = mm_modem_capability_build_string_from_mask (ctx->capabilities);
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002419 mm_obj_dbg (self, "setting new list of capabilities: %s", capabilities_string);
Aleksander Morgadoa902e682013-05-24 12:55:07 +02002420 g_free (capabilities_string);
2421
2422 MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_capabilities (
2423 MM_IFACE_MODEM (self),
2424 ctx->capabilities,
2425 (GAsyncReadyCallback)set_current_capabilities_ready,
2426 ctx);
2427}
2428
2429static gboolean
2430handle_set_current_capabilities (MmGdbusModem *skeleton,
2431 GDBusMethodInvocation *invocation,
2432 guint capabilities,
2433 MMIfaceModem *self)
2434{
2435 HandleSetCurrentCapabilitiesContext *ctx;
2436
2437 ctx = g_slice_new (HandleSetCurrentCapabilitiesContext);
2438 ctx->skeleton = g_object_ref (skeleton);
2439 ctx->invocation = g_object_ref (invocation);
2440 ctx->self = g_object_ref (self);
2441 ctx->capabilities = capabilities;
2442
2443 mm_base_modem_authorize (MM_BASE_MODEM (self),
2444 invocation,
2445 MM_AUTHORIZATION_DEVICE_CONTROL,
2446 (GAsyncReadyCallback)handle_set_current_capabilities_auth_ready,
2447 ctx);
2448 return TRUE;
2449}
2450
2451/*****************************************************************************/
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002452/* Current bands setting */
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002453
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002454#define AFTER_SET_LOAD_CURRENT_BANDS_RETRIES 5
2455#define AFTER_SET_LOAD_CURRENT_BANDS_TIMEOUT_SECS 1
2456
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002457typedef struct {
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002458 MmGdbusModem *skeleton;
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002459 GArray *bands_array;
2460 GArray *supported_bands_array; /* when ANY requested */
2461 guint retries;
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002462} SetCurrentBandsContext;
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002463
2464static void
Ben Chan71dd1522017-06-30 02:23:42 -07002465set_current_bands_context_free (SetCurrentBandsContext *ctx)
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002466{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02002467 if (ctx->skeleton)
2468 g_object_unref (ctx->skeleton);
2469 if (ctx->bands_array)
2470 g_array_unref (ctx->bands_array);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002471 if (ctx->supported_bands_array)
2472 g_array_unref (ctx->supported_bands_array);
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002473 g_slice_free (SetCurrentBandsContext, ctx);
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002474}
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002475
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002476gboolean
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002477mm_iface_modem_set_current_bands_finish (MMIfaceModem *self,
2478 GAsyncResult *res,
2479 GError **error)
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002480{
Ben Chan71dd1522017-06-30 02:23:42 -07002481 return g_task_propagate_boolean (G_TASK (res), error);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002482}
2483
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002484static void
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002485set_current_bands_complete_with_defaults (GTask *task)
2486{
2487 SetCurrentBandsContext *ctx;
2488
2489 ctx = g_task_get_task_data (task);
2490
2491 /* Never show just 'any' in the interface */
2492 if (ctx->bands_array->len == 1 && g_array_index (ctx->bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002493 g_assert (ctx->supported_bands_array);
2494 g_array_unref (ctx->bands_array);
2495 ctx->bands_array = g_array_ref (ctx->supported_bands_array);
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002496 }
2497
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002498 mm_common_bands_garray_sort (ctx->bands_array);
2499 mm_gdbus_modem_set_current_bands (ctx->skeleton, mm_common_bands_garray_to_variant (ctx->bands_array));
2500
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002501 g_task_return_boolean (task, TRUE);
2502 g_object_unref (task);
2503}
2504
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002505static void set_current_bands_reload_schedule (GTask *task);
2506
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002507static void
2508after_set_load_current_bands_ready (MMIfaceModem *self,
2509 GAsyncResult *res,
2510 GTask *task)
2511{
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002512 SetCurrentBandsContext *ctx;
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002513 GArray *current_bands;
2514 GError *error = NULL;
2515 GArray *requested_bands = NULL;
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002516
2517 ctx = g_task_get_task_data (task);
2518
2519 current_bands = MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands_finish (self, res, &error);
2520 if (!current_bands) {
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002521 /* If we can retry, do it */
2522 if (ctx->retries > 0) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002523 mm_obj_dbg (self, "couldn't load current bands: %s (will retry)", error->message);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002524 g_clear_error (&error);
2525 set_current_bands_reload_schedule (task);
2526 goto out;
2527 }
2528
2529 /* Errors when reloading bands won't be critical */
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002530 mm_obj_warn (self, "couldn't load current bands: %s", error->message);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002531 g_clear_error (&error);
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002532 set_current_bands_complete_with_defaults (task);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002533 goto out;
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002534 }
2535
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002536 if ((ctx->bands_array->len == 1) && (g_array_index (ctx->bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY))
2537 requested_bands = g_array_ref (ctx->supported_bands_array);
2538 else
2539 requested_bands = g_array_ref (ctx->bands_array);
2540
2541 /* Compare arrays */
2542 if (!mm_common_bands_garray_cmp (current_bands, requested_bands)) {
2543 gchar *requested_str;
2544 gchar *current_str;
2545
2546 /* If we can retry, do it */
2547 if (ctx->retries > 0) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002548 mm_obj_dbg (self, "reloaded current bands different to the requested ones (will retry)");
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002549 set_current_bands_reload_schedule (task);
2550 goto out;
2551 }
2552
Aleksander Morgado7ccec0b2020-05-19 11:40:33 +02002553 requested_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)requested_bands->data, requested_bands->len);
2554 current_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)current_bands->data, current_bands->len);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002555 error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
2556 "reloaded current bands (%s) different to the requested ones (%s)",
2557 current_str, requested_str);
2558 g_free (requested_str);
2559 g_free (current_str);
2560 }
2561
2562 /* Store as current the last loaded ones and set operation result */
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002563 mm_common_bands_garray_sort (current_bands);
2564 mm_gdbus_modem_set_current_bands (ctx->skeleton, mm_common_bands_garray_to_variant (current_bands));
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002565
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002566 if (error)
2567 g_task_return_error (task, error);
2568 else
2569 g_task_return_boolean (task, TRUE);
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002570 g_object_unref (task);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002571
2572 out:
2573 g_array_unref (requested_bands);
2574 g_array_unref (current_bands);
2575}
2576
2577static gboolean
2578set_current_bands_reload (GTask *task)
2579{
2580 MMIfaceModem *self;
2581 SetCurrentBandsContext *ctx;
2582
2583 self = g_task_get_source_object (task);
2584 ctx = g_task_get_task_data (task);
2585
2586 g_assert (ctx->retries > 0);
2587 ctx->retries--;
2588
2589 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands (
2590 self,
2591 (GAsyncReadyCallback)after_set_load_current_bands_ready,
2592 task);
2593
2594 return G_SOURCE_REMOVE;
2595}
2596
2597static void
2598set_current_bands_reload_schedule (GTask *task)
2599{
2600 g_timeout_add_seconds (AFTER_SET_LOAD_CURRENT_BANDS_TIMEOUT_SECS,
2601 (GSourceFunc) set_current_bands_reload,
2602 task);
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002603}
2604
2605static void
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002606set_current_bands_ready (MMIfaceModem *self,
2607 GAsyncResult *res,
Ben Chan71dd1522017-06-30 02:23:42 -07002608 GTask *task)
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002609{
2610 GError *error = NULL;
2611
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002612 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_bands_finish (self, res, &error)) {
Ben Chan71dd1522017-06-30 02:23:42 -07002613 g_task_return_error (task, error);
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002614 g_object_unref (task);
2615 return;
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002616 }
2617
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002618 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands &&
2619 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands_finish) {
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002620 set_current_bands_reload (task);
Aleksander Morgado59a5af92018-08-04 17:27:53 +02002621 return;
2622 }
2623
2624 /* Default to the ones we requested */
2625 set_current_bands_complete_with_defaults (task);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002626}
2627
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002628static gboolean
Aleksander Morgado09d2f062012-02-17 16:57:12 +01002629validate_bands (const GArray *supported_bands_array,
2630 const GArray *bands_array,
2631 GError **error)
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002632{
2633 /* When the array has more than one element, there MUST NOT include ANY or
2634 * UNKNOWN */
Aleksander Morgado09d2f062012-02-17 16:57:12 +01002635 if (bands_array->len > 1) {
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002636 guint i;
2637
Aleksander Morgado09d2f062012-02-17 16:57:12 +01002638 for (i = 0; i < bands_array->len; i++) {
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002639 MMModemBand band;
2640
Aleksander Morgado09d2f062012-02-17 16:57:12 +01002641 band = g_array_index (bands_array, MMModemBand, i);
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002642 if (band == MM_MODEM_BAND_UNKNOWN ||
2643 band == MM_MODEM_BAND_ANY) {
Aleksander Morgado09d2f062012-02-17 16:57:12 +01002644 g_set_error (error,
2645 MM_CORE_ERROR,
2646 MM_CORE_ERROR_INVALID_ARGS,
2647 "Wrong list of bands: "
2648 "'%s' should have been the only element in the list",
2649 mm_modem_band_get_string (band));
2650 return FALSE;
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002651 }
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002652
2653 if (supported_bands_array->len > 1 ||
Aleksander Morgado9dbf9a82012-08-28 16:26:28 +02002654 (g_array_index (supported_bands_array, MMModemBand, 0) != MM_MODEM_BAND_ANY &&
2655 g_array_index (supported_bands_array, MMModemBand, 0) != MM_MODEM_BAND_UNKNOWN)) {
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002656 gboolean found = FALSE;
2657 guint j;
2658
2659 /* The band given in allowed MUST be available in supported */
2660 for (j = 0; !found && j < supported_bands_array->len; j++) {
2661 if (band == g_array_index (supported_bands_array, MMModemBand, j))
2662 found = TRUE;
2663 }
2664
2665 if (!found) {
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002666 gchar *supported_bands_str;
2667
Aleksander Morgado7e36f042012-01-18 13:43:49 +01002668 supported_bands_str = (mm_common_build_bands_string (
Aleksander Morgado7ccec0b2020-05-19 11:40:33 +02002669 (const MMModemBand *)(gconstpointer)supported_bands_array->data,
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002670 supported_bands_array->len));
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002671 g_set_error (error,
2672 MM_CORE_ERROR,
2673 MM_CORE_ERROR_INVALID_ARGS,
2674 "Given allowed band (%s) is not supported (%s)",
Aleksander Morgado7e36f042012-01-18 13:43:49 +01002675 mm_modem_band_get_string (band),
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002676 supported_bands_str);
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002677 g_free (supported_bands_str);
2678 return FALSE;
2679 }
2680 }
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002681 }
2682 }
2683 return TRUE;
2684}
2685
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002686void
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002687mm_iface_modem_set_current_bands (MMIfaceModem *self,
2688 GArray *bands_array,
2689 GAsyncReadyCallback callback,
2690 gpointer user_data)
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002691{
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002692 SetCurrentBandsContext *ctx;
Ben Chan667df562012-08-24 09:12:42 -07002693 GArray *current_bands_array;
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002694 GError *error = NULL;
Ben Chan667df562012-08-24 09:12:42 -07002695 gchar *bands_string;
Ben Chan71dd1522017-06-30 02:23:42 -07002696 GTask *task;
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002697
2698 /* If setting allowed bands is not implemented, report an error */
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002699 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_bands ||
2700 !MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_bands_finish) {
Ben Chan71dd1522017-06-30 02:23:42 -07002701 g_task_report_new_error (self,
2702 callback,
2703 user_data,
2704 mm_iface_modem_set_current_bands,
2705 MM_CORE_ERROR,
2706 MM_CORE_ERROR_UNSUPPORTED,
2707 "Setting allowed bands not supported");
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002708 return;
2709 }
2710
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002711 /* Setup context */
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002712 ctx = g_slice_new0 (SetCurrentBandsContext);
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002713 ctx->retries = AFTER_SET_LOAD_CURRENT_BANDS_RETRIES;
Ben Chan71dd1522017-06-30 02:23:42 -07002714
2715 task = g_task_new (self, NULL, callback, user_data);
2716 g_task_set_task_data (task, ctx, (GDestroyNotify)set_current_bands_context_free);
2717
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002718 g_object_get (self,
2719 MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
2720 NULL);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02002721 if (!ctx->skeleton) {
Ben Chan71dd1522017-06-30 02:23:42 -07002722 g_task_return_new_error (task,
2723 MM_CORE_ERROR,
2724 MM_CORE_ERROR_FAILED,
2725 "Couldn't get interface skeleton");
2726 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02002727 return;
2728 }
2729
Aleksander Morgado7ccec0b2020-05-19 11:40:33 +02002730 bands_string = mm_common_build_bands_string ((const MMModemBand *)(gpointer)bands_array->data, bands_array->len);
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002731
2732 /* Get list of supported bands */
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002733 ctx->supported_bands_array = (mm_common_bands_variant_to_garray (
2734 mm_gdbus_modem_get_supported_bands (ctx->skeleton)));
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002735
Ben Chan667df562012-08-24 09:12:42 -07002736 /* Set ctx->bands_array to target list of bands before comparing with current list
2737 * of bands. If input list of bands contains only ANY, target list of bands is set
2738 * to list of supported bands excluding ANY. */
2739 if (bands_array->len == 1 &&
2740 g_array_index (bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
2741 guint i;
Aleksander Morgado8225dec2012-08-28 16:36:37 +02002742
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002743 for (i = 0; i < ctx->supported_bands_array->len; i++) {
2744 MMModemBand band = g_array_index (ctx->supported_bands_array, MMModemBand, i);
Aleksander Morgado8225dec2012-08-28 16:36:37 +02002745
2746 if (band != MM_MODEM_BAND_ANY &&
2747 band != MM_MODEM_BAND_UNKNOWN) {
2748 if (!ctx->bands_array)
2749 ctx->bands_array = g_array_sized_new (FALSE,
2750 FALSE,
2751 sizeof (MMModemBand),
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002752 ctx->supported_bands_array->len);
Dan Williams18bfefb2013-04-24 15:04:57 -05002753 g_array_append_val (ctx->bands_array, band);
Aleksander Morgado8225dec2012-08-28 16:36:37 +02002754 }
Ben Chan667df562012-08-24 09:12:42 -07002755 }
Ben Chan667df562012-08-24 09:12:42 -07002756 }
2757
Aleksander Morgado8225dec2012-08-28 16:36:37 +02002758 if (!ctx->bands_array)
2759 ctx->bands_array = g_array_ref (bands_array);
2760
Ben Chan667df562012-08-24 09:12:42 -07002761 /* Simply return if target list of bands equals to current list of bands */
2762 current_bands_array = (mm_common_bands_variant_to_garray (
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002763 mm_gdbus_modem_get_current_bands (ctx->skeleton)));
Ben Chan667df562012-08-24 09:12:42 -07002764 if (mm_common_bands_garray_cmp (ctx->bands_array, current_bands_array)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002765 mm_obj_dbg (self, "requested list of bands (%s) is equal to the current ones, skipping re-set", bands_string);
Ben Chan667df562012-08-24 09:12:42 -07002766 g_free (bands_string);
Ben Chan667df562012-08-24 09:12:42 -07002767 g_array_unref (current_bands_array);
Ben Chan71dd1522017-06-30 02:23:42 -07002768 g_task_return_boolean (task, TRUE);
2769 g_object_unref (task);
Ben Chan667df562012-08-24 09:12:42 -07002770 return;
2771 }
2772
2773 /* Done comparison with current list of bands. Always use input list of bands
2774 * when setting bands */
2775 if (ctx->bands_array != bands_array) {
2776 g_array_unref (ctx->bands_array);
2777 ctx->bands_array = g_array_ref (bands_array);
2778 }
2779
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002780 /* Validate input list of bands */
Aleksander Morgadof1dcc712019-07-21 11:22:30 +02002781 if (!validate_bands (ctx->supported_bands_array,
Aleksander Morgado09d2f062012-02-17 16:57:12 +01002782 ctx->bands_array,
2783 &error)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002784 mm_obj_dbg (self, "requested list of bands (%s) cannot be handled", bands_string);
Ben Chan667df562012-08-24 09:12:42 -07002785 g_free (bands_string);
Ben Chan667df562012-08-24 09:12:42 -07002786 g_array_unref (current_bands_array);
Ben Chan71dd1522017-06-30 02:23:42 -07002787 g_task_return_error (task, error);
2788 g_object_unref (task);
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01002789 return;
2790 }
2791
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002792 mm_obj_dbg (self, "setting new list of bands: %s", bands_string);
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002793 MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_bands (
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002794 self,
Ben Chan667df562012-08-24 09:12:42 -07002795 ctx->bands_array,
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002796 (GAsyncReadyCallback)set_current_bands_ready,
Ben Chan71dd1522017-06-30 02:23:42 -07002797 task);
Aleksander Morgado6002ad12011-12-30 16:52:58 +01002798
Ben Chan667df562012-08-24 09:12:42 -07002799 g_array_unref (current_bands_array);
2800 g_free (bands_string);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002801}
2802
Aleksander Morgado22407472012-02-27 10:40:03 +01002803typedef struct {
2804 MmGdbusModem *skeleton;
2805 GDBusMethodInvocation *invocation;
2806 MMIfaceModem *self;
2807 GVariant *bands;
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002808} HandleSetCurrentBandsContext;
Aleksander Morgado22407472012-02-27 10:40:03 +01002809
2810static void
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002811handle_set_current_bands_context_free (HandleSetCurrentBandsContext *ctx)
Aleksander Morgado22407472012-02-27 10:40:03 +01002812{
2813 g_variant_unref (ctx->bands);
2814 g_object_unref (ctx->skeleton);
2815 g_object_unref (ctx->invocation);
2816 g_object_unref (ctx->self);
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002817 g_slice_free (HandleSetCurrentBandsContext, ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01002818}
2819
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002820static void
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002821handle_set_current_bands_ready (MMIfaceModem *self,
2822 GAsyncResult *res,
2823 HandleSetCurrentBandsContext *ctx)
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002824{
2825 GError *error = NULL;
2826
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002827 if (!mm_iface_modem_set_current_bands_finish (self, res, &error))
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002828 g_dbus_method_invocation_take_error (ctx->invocation, error);
Aleksander Morgado2c19b1f2017-05-30 20:09:56 +02002829 else {
2830 /* Bands updated: explicitly refresh signal and access technology */
2831 mm_iface_modem_refresh_signal (self);
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002832 mm_gdbus_modem_complete_set_current_bands (ctx->skeleton, ctx->invocation);
Aleksander Morgado2c19b1f2017-05-30 20:09:56 +02002833 }
Aleksander Morgado22407472012-02-27 10:40:03 +01002834
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002835 handle_set_current_bands_context_free (ctx);
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002836}
2837
Aleksander Morgado22407472012-02-27 10:40:03 +01002838static void
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002839handle_set_current_bands_auth_ready (MMBaseModem *self,
2840 GAsyncResult *res,
2841 HandleSetCurrentBandsContext *ctx)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002842{
Aleksander Morgado75187722012-03-30 11:06:32 +02002843 GArray *bands_array;
Aleksander Morgado22407472012-02-27 10:40:03 +01002844 GError *error = NULL;
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002845
Aleksander Morgado22407472012-02-27 10:40:03 +01002846 if (!mm_base_modem_authorize_finish (self, res, &error)) {
2847 g_dbus_method_invocation_take_error (ctx->invocation, error);
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002848 handle_set_current_bands_context_free (ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01002849 return;
2850 }
2851
Aleksander Morgadocae73772018-12-06 14:54:19 +01002852 if (abort_invocation_if_state_not_reached (ctx->self, ctx->invocation, MM_MODEM_STATE_DISABLED)) {
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002853 handle_set_current_bands_context_free (ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01002854 return;
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002855 }
Aleksander Morgado75187722012-03-30 11:06:32 +02002856
2857 bands_array = mm_common_bands_variant_to_garray (ctx->bands);
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002858 mm_iface_modem_set_current_bands (MM_IFACE_MODEM (self),
2859 bands_array,
2860 (GAsyncReadyCallback)handle_set_current_bands_ready,
2861 ctx);
Aleksander Morgado75187722012-03-30 11:06:32 +02002862 g_array_unref (bands_array);
Aleksander Morgado22407472012-02-27 10:40:03 +01002863}
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002864
Aleksander Morgado22407472012-02-27 10:40:03 +01002865static gboolean
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002866handle_set_current_bands (MmGdbusModem *skeleton,
2867 GDBusMethodInvocation *invocation,
2868 GVariant *bands_variant,
2869 MMIfaceModem *self)
Aleksander Morgado22407472012-02-27 10:40:03 +01002870{
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002871 HandleSetCurrentBandsContext *ctx;
Aleksander Morgado22407472012-02-27 10:40:03 +01002872
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002873 ctx = g_slice_new (HandleSetCurrentBandsContext);
Aleksander Morgado22407472012-02-27 10:40:03 +01002874 ctx->skeleton = g_object_ref (skeleton);
2875 ctx->invocation = g_object_ref (invocation);
2876 ctx->self = g_object_ref (self);
2877 ctx->bands = g_variant_ref (bands_variant);
2878
2879 mm_base_modem_authorize (MM_BASE_MODEM (self),
2880 invocation,
2881 MM_AUTHORIZATION_DEVICE_CONTROL,
Aleksander Morgado212d00c2013-05-29 10:47:53 +02002882 (GAsyncReadyCallback)handle_set_current_bands_auth_ready,
Aleksander Morgado22407472012-02-27 10:40:03 +01002883 ctx);
Aleksander Morgado1dcd20f2011-11-22 19:12:33 +01002884 return TRUE;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01002885}
2886
Aleksander Morgado59c37af2011-11-22 19:16:07 +01002887/*****************************************************************************/
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002888/* Set current modes */
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002889
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002890#define AFTER_SET_LOAD_CURRENT_MODES_RETRIES 5
2891#define AFTER_SET_LOAD_CURRENT_MODES_TIMEOUT_SECS 1
2892
Aleksander Morgado1be7c272011-12-30 15:38:55 +01002893typedef struct {
Aleksander Morgado1be7c272011-12-30 15:38:55 +01002894 MmGdbusModem *skeleton;
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002895 MMModemMode allowed;
2896 MMModemMode preferred;
2897 guint retries;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002898} SetCurrentModesContext;
Aleksander Morgado1be7c272011-12-30 15:38:55 +01002899
2900static void
Ben Chan25f0d422017-06-30 02:23:43 -07002901set_current_modes_context_free (SetCurrentModesContext *ctx)
Aleksander Morgado1be7c272011-12-30 15:38:55 +01002902{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02002903 if (ctx->skeleton)
2904 g_object_unref (ctx->skeleton);
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002905 g_slice_free (SetCurrentModesContext, ctx);
Aleksander Morgado1be7c272011-12-30 15:38:55 +01002906}
2907
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002908gboolean
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002909mm_iface_modem_set_current_modes_finish (MMIfaceModem *self,
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002910 GAsyncResult *res,
2911 GError **error)
2912{
Ben Chan25f0d422017-06-30 02:23:43 -07002913 return g_task_propagate_boolean (G_TASK (res), error);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01002914}
Aleksander Morgado59c37af2011-11-22 19:16:07 +01002915
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002916static void set_current_modes_reload_schedule (GTask *task);
2917
Aleksander Morgado59c37af2011-11-22 19:16:07 +01002918static void
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002919after_set_load_current_modes_ready (MMIfaceModem *self,
2920 GAsyncResult *res,
Ben Chan25f0d422017-06-30 02:23:43 -07002921 GTask *task)
Aleksander Morgado59c37af2011-11-22 19:16:07 +01002922{
Ben Chan25f0d422017-06-30 02:23:43 -07002923 SetCurrentModesContext *ctx;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002924 MMModemMode allowed = MM_MODEM_MODE_NONE;
2925 MMModemMode preferred = MM_MODEM_MODE_NONE;
Aleksander Morgado59c37af2011-11-22 19:16:07 +01002926 GError *error = NULL;
2927
Ben Chan25f0d422017-06-30 02:23:43 -07002928 ctx = g_task_get_task_data (task);
2929
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002930 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes_finish (self,
2931 res,
2932 &allowed,
2933 &preferred,
2934 &error)) {
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002935 /* If we can retry, do it */
2936 if (ctx->retries > 0) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002937 mm_obj_dbg (self, "couldn't load current allowed/preferred modes: %s", error->message);
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002938 g_error_free (error);
2939 set_current_modes_reload_schedule (task);
2940 return;
2941 }
2942
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002943 /* Errors when getting allowed/preferred won't be critical */
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002944 mm_obj_warn (self, "couldn't load current allowed/preferred modes: %s", error->message);
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002945 g_clear_error (&error);
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002946
2947 /* If errors getting allowed modes, default to the ones we asked for */
2948 mm_gdbus_modem_set_current_modes (ctx->skeleton, g_variant_new ("(uu)", ctx->allowed, ctx->preferred));
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002949 goto out;
2950 }
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002951
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002952 /* Store as current the last loaded ones and set operation result */
2953 mm_gdbus_modem_set_current_modes (ctx->skeleton, g_variant_new ("(uu)", allowed, preferred));
2954
2955 /* Compare modes. If the requested one was ANY, we won't consider an error if the
2956 * result differs. */
2957 if (((allowed != ctx->allowed) || (preferred != ctx->preferred)) && (ctx->allowed != MM_MODEM_MODE_ANY)) {
2958 gchar *requested_allowed_str;
2959 gchar *requested_preferred_str;
2960 gchar *current_allowed_str;
2961 gchar *current_preferred_str;
2962
2963 /* If we can retry, do it */
2964 if (ctx->retries > 0) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01002965 mm_obj_dbg (self, "reloaded current modes different to the requested ones (will retry)");
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002966 set_current_modes_reload_schedule (task);
2967 return;
2968 }
2969
2970 requested_allowed_str = mm_modem_mode_build_string_from_mask (ctx->allowed);
2971 requested_preferred_str = mm_modem_mode_build_string_from_mask (ctx->preferred);
2972 current_allowed_str = mm_modem_mode_build_string_from_mask (allowed);
2973 current_preferred_str = mm_modem_mode_build_string_from_mask (preferred);
2974
2975 error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
2976 "reloaded modes (allowed '%s' and preferred '%s') different "
2977 "to the requested ones (allowed '%s' and preferred '%s')",
2978 requested_allowed_str, requested_preferred_str,
2979 current_allowed_str, current_preferred_str);
2980
2981 g_free (requested_allowed_str);
2982 g_free (requested_preferred_str);
2983 g_free (current_allowed_str);
2984 g_free (current_preferred_str);
2985 }
2986
2987out:
2988 if (error)
2989 g_task_return_error (task, error);
2990 else
2991 g_task_return_boolean (task, TRUE);
Ben Chan25f0d422017-06-30 02:23:43 -07002992 g_object_unref (task);
Aleksander Morgado1c67d052013-05-29 13:42:14 +02002993}
2994
Aleksander Morgadod7696d82019-07-21 22:17:48 +02002995static gboolean
2996set_current_modes_reload (GTask *task)
2997{
2998 MMIfaceModem *self;
2999 SetCurrentModesContext *ctx;
3000
3001 self = g_task_get_source_object (task);
3002 ctx = g_task_get_task_data (task);
3003
3004 g_assert (ctx->retries > 0);
3005 ctx->retries--;
3006
3007 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes (
3008 self,
3009 (GAsyncReadyCallback)after_set_load_current_modes_ready,
3010 task);
3011
3012 return G_SOURCE_REMOVE;
3013}
3014
3015static void
3016set_current_modes_reload_schedule (GTask *task)
3017{
3018 g_timeout_add_seconds (AFTER_SET_LOAD_CURRENT_MODES_TIMEOUT_SECS,
3019 (GSourceFunc) set_current_modes_reload,
3020 task);
3021}
3022
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003023static void
3024set_current_modes_ready (MMIfaceModem *self,
3025 GAsyncResult *res,
Ben Chan25f0d422017-06-30 02:23:43 -07003026 GTask *task)
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003027{
Ben Chan25f0d422017-06-30 02:23:43 -07003028 SetCurrentModesContext *ctx;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003029 GError *error = NULL;
3030
3031 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_modes_finish (self, res, &error)) {
Ben Chan25f0d422017-06-30 02:23:43 -07003032 g_task_return_error (task, error);
3033 g_object_unref (task);
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003034 return;
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003035 }
3036
Ben Chan25f0d422017-06-30 02:23:43 -07003037 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes &&
3038 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes_finish) {
Aleksander Morgadod7696d82019-07-21 22:17:48 +02003039 set_current_modes_reload (task);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02003040 return;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003041 }
3042
Ben Chan25f0d422017-06-30 02:23:43 -07003043 ctx = g_task_get_task_data (task);
3044
Aleksander Morgadof09eff62013-05-31 09:14:18 +02003045 /* Default to the ones we requested */
3046 mm_gdbus_modem_set_current_modes (ctx->skeleton,
3047 g_variant_new ("(uu)",
3048 ctx->allowed,
3049 ctx->preferred));
3050
Ben Chan25f0d422017-06-30 02:23:43 -07003051 g_task_return_boolean (task, TRUE);
3052 g_object_unref (task);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003053}
3054
3055void
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003056mm_iface_modem_set_current_modes (MMIfaceModem *self,
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003057 MMModemMode allowed,
3058 MMModemMode preferred,
3059 GAsyncReadyCallback callback,
3060 gpointer user_data)
3061{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003062 GArray *supported;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003063 SetCurrentModesContext *ctx;
3064 MMModemMode current_allowed = MM_MODEM_MODE_ANY;
3065 MMModemMode current_preferred = MM_MODEM_MODE_NONE;
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003066 guint i;
Ben Chan25f0d422017-06-30 02:23:43 -07003067 GTask *task;
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003068
3069 /* If setting allowed modes is not implemented, report an error */
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003070 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_modes ||
3071 !MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_modes_finish) {
Ben Chan25f0d422017-06-30 02:23:43 -07003072 g_task_report_new_error (self,
3073 callback,
3074 user_data,
3075 mm_iface_modem_set_current_modes,
3076 MM_CORE_ERROR,
3077 MM_CORE_ERROR_UNSUPPORTED,
3078 "Setting allowed modes not supported");
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003079 return;
3080 }
3081
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003082 /* Setup context */
Aleksander Morgadod7696d82019-07-21 22:17:48 +02003083 ctx = g_slice_new0 (SetCurrentModesContext);
3084 ctx->retries = AFTER_SET_LOAD_CURRENT_MODES_RETRIES;
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003085 ctx->allowed = allowed;
3086 ctx->preferred = preferred;
Ben Chan25f0d422017-06-30 02:23:43 -07003087
3088 task = g_task_new (self, NULL, callback, user_data);
3089 g_task_set_task_data (task, ctx, (GDestroyNotify)set_current_modes_context_free);
3090
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003091 g_object_get (self,
3092 MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
3093 NULL);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02003094 if (!ctx->skeleton) {
Ben Chan25f0d422017-06-30 02:23:43 -07003095 g_task_return_new_error (task,
3096 MM_CORE_ERROR,
3097 MM_CORE_ERROR_FAILED,
3098 "Couldn't get interface skeleton");
3099 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02003100 return;
3101 }
3102
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003103 /* Get list of supported modes */
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003104 supported = mm_common_mode_combinations_variant_to_garray (
3105 mm_gdbus_modem_get_supported_modes (ctx->skeleton));
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003106
Ben Chan073163f2013-12-04 23:44:15 -08003107 /* Don't allow mode switching if only one item given in the supported list */
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003108 if (supported->len == 1) {
Ben Chan25f0d422017-06-30 02:23:43 -07003109 g_task_return_new_error (task,
3110 MM_CORE_ERROR,
3111 MM_CORE_ERROR_UNSUPPORTED,
3112 "Cannot change modes: only one combination supported");
3113 g_object_unref (task);
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003114 g_array_unref (supported);
Aleksander Morgadof6d8c522012-03-25 01:09:24 +01003115 return;
3116 }
3117
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003118 if (allowed == MM_MODEM_MODE_ANY &&
3119 preferred == MM_MODEM_MODE_NONE) {
3120 /* Allow allowed=ANY & preferred=NONE, all plugins should support it */
3121 } else {
3122 gboolean matched = FALSE;
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003123
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003124 /* Check if the given combination is supported */
3125 for (i = 0; !matched && i < supported->len; i++) {
3126 MMModemModeCombination *supported_mode;
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003127
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003128 supported_mode = &g_array_index (supported, MMModemModeCombination, i);
3129 if ((supported_mode->allowed == MM_MODEM_MODE_ANY &&
3130 supported_mode->preferred == MM_MODEM_MODE_NONE) ||
3131 (supported_mode->allowed == allowed &&
3132 supported_mode->preferred == preferred)) {
3133 matched = TRUE;
3134 }
3135 }
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003136
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003137 if (!matched) {
Ben Chan25f0d422017-06-30 02:23:43 -07003138 g_task_return_new_error (task,
3139 MM_CORE_ERROR,
3140 MM_CORE_ERROR_UNSUPPORTED,
3141 "The given combination of allowed and preferred modes is not supported");
3142 g_object_unref (task);
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003143 g_array_unref (supported);
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003144 return;
3145 }
3146 }
3147
3148 g_array_unref (supported);
3149
3150 /* Check if we already are in the requested setup */
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003151 g_variant_get (mm_gdbus_modem_get_current_modes (ctx->skeleton),
3152 "(uu)",
3153 &current_allowed,
3154 &current_preferred);
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003155 if (current_allowed == allowed &&
3156 current_preferred == preferred) {
Ben Chan25f0d422017-06-30 02:23:43 -07003157 g_task_return_boolean (task, TRUE);
3158 g_object_unref (task);
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003159 return;
3160 }
3161
3162 /* Ensure preferred, if given, is a subset of allowed */
3163 if ((allowed ^ preferred) & preferred) {
3164 gchar *preferred_str;
3165 gchar *allowed_str;
3166
Aleksander Morgado7e36f042012-01-18 13:43:49 +01003167 preferred_str = mm_modem_mode_build_string_from_mask (preferred);
3168 allowed_str = mm_modem_mode_build_string_from_mask (allowed);
Ben Chan25f0d422017-06-30 02:23:43 -07003169 g_task_return_new_error (task,
3170 MM_CORE_ERROR,
3171 MM_CORE_ERROR_UNSUPPORTED,
3172 "Preferred mode (%s) is not allowed (%s)",
3173 preferred_str,
3174 allowed_str);
3175 g_object_unref (task);
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003176 g_free (preferred_str);
3177 g_free (allowed_str);
Aleksander Morgado1be7c272011-12-30 15:38:55 +01003178 return;
3179 }
3180
Aleksander Morgado45ceba72013-05-29 12:41:49 +02003181 ctx->allowed = allowed;
3182 ctx->preferred = preferred;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003183 MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_modes (self,
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003184 allowed,
3185 preferred,
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003186 (GAsyncReadyCallback)set_current_modes_ready,
Ben Chan25f0d422017-06-30 02:23:43 -07003187 task);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003188}
3189
Aleksander Morgado22407472012-02-27 10:40:03 +01003190typedef struct {
3191 MmGdbusModem *skeleton;
3192 GDBusMethodInvocation *invocation;
3193 MMIfaceModem *self;
3194 MMModemMode allowed;
3195 MMModemMode preferred;
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003196} HandleSetCurrentModesContext;
Aleksander Morgado22407472012-02-27 10:40:03 +01003197
3198static void
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003199handle_set_current_modes_context_free (HandleSetCurrentModesContext *ctx)
Aleksander Morgado22407472012-02-27 10:40:03 +01003200{
3201 g_object_unref (ctx->skeleton);
3202 g_object_unref (ctx->invocation);
3203 g_object_unref (ctx->self);
3204 g_free (ctx);
3205}
3206
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003207static void
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003208handle_set_current_modes_ready (MMIfaceModem *self,
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003209 GAsyncResult *res,
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003210 HandleSetCurrentModesContext *ctx)
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003211{
3212 GError *error = NULL;
3213
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003214 if (!mm_iface_modem_set_current_modes_finish (self, res, &error))
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01003215 g_dbus_method_invocation_take_error (ctx->invocation, error);
Aleksander Morgado2c19b1f2017-05-30 20:09:56 +02003216 else {
3217 /* Modes updated: explicitly refresh signal and access technology */
3218 mm_iface_modem_refresh_signal (self);
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003219 mm_gdbus_modem_complete_set_current_modes (ctx->skeleton, ctx->invocation);
Aleksander Morgado2c19b1f2017-05-30 20:09:56 +02003220 }
Aleksander Morgado22407472012-02-27 10:40:03 +01003221
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003222 handle_set_current_modes_context_free (ctx);
Aleksander Morgado59c37af2011-11-22 19:16:07 +01003223}
3224
Aleksander Morgado22407472012-02-27 10:40:03 +01003225static void
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003226handle_set_current_modes_auth_ready (MMBaseModem *self,
Aleksander Morgado22407472012-02-27 10:40:03 +01003227 GAsyncResult *res,
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003228 HandleSetCurrentModesContext *ctx)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01003229{
Aleksander Morgado22407472012-02-27 10:40:03 +01003230 GError *error = NULL;
Aleksander Morgado59c37af2011-11-22 19:16:07 +01003231
Aleksander Morgado22407472012-02-27 10:40:03 +01003232 if (!mm_base_modem_authorize_finish (self, res, &error)) {
3233 g_dbus_method_invocation_take_error (ctx->invocation, error);
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003234 handle_set_current_modes_context_free (ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01003235 return;
3236 }
3237
Aleksander Morgadocae73772018-12-06 14:54:19 +01003238 if (abort_invocation_if_state_not_reached (ctx->self, ctx->invocation, MM_MODEM_STATE_DISABLED)) {
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003239 handle_set_current_modes_context_free (ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01003240 return;
Aleksander Morgado59c37af2011-11-22 19:16:07 +01003241 }
Aleksander Morgado75187722012-03-30 11:06:32 +02003242
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003243 mm_iface_modem_set_current_modes (MM_IFACE_MODEM (self),
Aleksander Morgado75187722012-03-30 11:06:32 +02003244 ctx->allowed,
3245 ctx->preferred,
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003246 (GAsyncReadyCallback)handle_set_current_modes_ready,
Aleksander Morgado75187722012-03-30 11:06:32 +02003247 ctx);
Aleksander Morgado22407472012-02-27 10:40:03 +01003248}
Aleksander Morgado59c37af2011-11-22 19:16:07 +01003249
Aleksander Morgado22407472012-02-27 10:40:03 +01003250static gboolean
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003251handle_set_current_modes (MmGdbusModem *skeleton,
Aleksander Morgado22407472012-02-27 10:40:03 +01003252 GDBusMethodInvocation *invocation,
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003253 GVariant *variant,
Aleksander Morgado22407472012-02-27 10:40:03 +01003254 MMIfaceModem *self)
3255{
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003256 HandleSetCurrentModesContext *ctx;
Aleksander Morgado22407472012-02-27 10:40:03 +01003257
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003258 ctx = g_new (HandleSetCurrentModesContext, 1);
Aleksander Morgado22407472012-02-27 10:40:03 +01003259 ctx->skeleton = g_object_ref (skeleton);
3260 ctx->invocation = g_object_ref (invocation);
3261 ctx->self = g_object_ref (self);
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003262
3263 g_variant_get (variant,
3264 "(uu)",
3265 &ctx->allowed,
3266 &ctx->preferred);
Aleksander Morgado22407472012-02-27 10:40:03 +01003267
3268 mm_base_modem_authorize (MM_BASE_MODEM (self),
3269 invocation,
3270 MM_AUTHORIZATION_DEVICE_CONTROL,
Aleksander Morgado1c67d052013-05-29 13:42:14 +02003271 (GAsyncReadyCallback)handle_set_current_modes_auth_ready,
Aleksander Morgado22407472012-02-27 10:40:03 +01003272 ctx);
Aleksander Morgado59c37af2011-11-22 19:16:07 +01003273 return TRUE;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01003274}
3275
3276/*****************************************************************************/
3277
Aleksander Morgado3a221282012-03-09 19:43:34 +01003278static void
3279reinitialize_ready (MMBaseModem *self,
3280 GAsyncResult *res)
3281{
Aleksander Morgadod27e40a2012-03-09 19:48:43 +01003282 GError *error = NULL;
3283
3284 mm_base_modem_initialize_finish (self, res, &error);
3285 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003286 mm_obj_warn (self, "reinitialization failed: %s", error->message);
Aleksander Morgadod27e40a2012-03-09 19:48:43 +01003287 g_error_free (error);
3288 }
Aleksander Morgado3a221282012-03-09 19:43:34 +01003289}
3290
Aleksander Morgado79fbe272012-07-22 00:21:07 +02003291static gboolean
3292restart_initialize_idle (MMIfaceModem *self)
3293{
Aleksander Morgado1cb58312013-04-05 08:54:09 +02003294 g_object_set_qdata (G_OBJECT (self), restart_initialize_idle_quark, NULL);
3295
Aleksander Morgado1c49e352012-08-28 18:34:07 +02003296 /* If no wait needed, just go on */
3297 mm_base_modem_initialize (MM_BASE_MODEM (self),
3298 (GAsyncReadyCallback) reinitialize_ready,
3299 NULL);
Aleksander Morgadoffde4292015-12-02 17:07:11 +01003300 return G_SOURCE_REMOVE;
Aleksander Morgado1453f352011-11-23 13:16:28 +01003301}
3302
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01003303static void
Aleksander Morgado1cb58312013-04-05 08:54:09 +02003304restart_initialize_idle_cancel (gpointer idp)
3305{
3306 g_source_remove (GPOINTER_TO_UINT (idp));
3307}
3308
3309static void
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01003310set_lock_status (MMIfaceModem *self,
3311 MmGdbusModem *skeleton,
3312 MMModemLock lock)
3313{
Aleksander Morgadoca15a102011-11-22 18:01:09 +01003314 MMModemLock old_lock;
3315
3316 old_lock = mm_gdbus_modem_get_unlock_required (skeleton);
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01003317 mm_gdbus_modem_set_unlock_required (skeleton, lock);
Pavan Holla38f67042020-11-23 17:52:17 +00003318 if (lock == MM_MODEM_LOCK_UNKNOWN)
3319 mm_gdbus_modem_set_unlock_retries (skeleton, 0);
Aleksander Morgadoca15a102011-11-22 18:01:09 +01003320
Aleksander Morgado00761062011-11-29 17:02:05 +01003321 /* We don't care about SIM-PIN2/SIM-PUK2 since the device is
3322 * operational without it. */
3323 if (lock == MM_MODEM_LOCK_NONE ||
3324 lock == MM_MODEM_LOCK_SIM_PIN2 ||
3325 lock == MM_MODEM_LOCK_SIM_PUK2) {
Aleksander Morgadod27e40a2012-03-09 19:48:43 +01003326 /* Notify transition from INITIALIZING/LOCKED to DISABLED */
Aleksander Morgadodc1df5b2012-02-17 10:52:28 +01003327 if (old_lock != MM_MODEM_LOCK_NONE &&
3328 old_lock != MM_MODEM_LOCK_SIM_PIN2 &&
3329 old_lock != MM_MODEM_LOCK_SIM_PUK2) {
Aleksander Morgadod27e40a2012-03-09 19:48:43 +01003330 /* Only restart initialization if leaving LOCKED.
Aleksander Morgado3a221282012-03-09 19:43:34 +01003331 * If this is the case, we do NOT update the state yet, we wait
3332 * to be completely re-initialized to do so. */
Aleksander Morgado1cb58312013-04-05 08:54:09 +02003333 if (old_lock != MM_MODEM_LOCK_UNKNOWN) {
3334 guint id;
3335
3336 if (G_UNLIKELY (!restart_initialize_idle_quark))
3337 restart_initialize_idle_quark = (g_quark_from_static_string (RESTART_INITIALIZE_IDLE_TAG));
3338
3339 id = g_idle_add ((GSourceFunc)restart_initialize_idle, self);
3340 g_object_set_qdata_full (G_OBJECT (self),
3341 restart_initialize_idle_quark,
3342 GUINT_TO_POINTER (id),
3343 (GDestroyNotify)restart_initialize_idle_cancel);
3344 }
Aleksander Morgadoca15a102011-11-22 18:01:09 +01003345 }
3346 } else {
3347 if (old_lock == MM_MODEM_LOCK_UNKNOWN) {
Aleksander Morgadod27e40a2012-03-09 19:48:43 +01003348 /* Notify transition from INITIALIZING to LOCKED */
Aleksander Morgadob31ad372011-11-29 12:05:44 +01003349 mm_iface_modem_update_state (self,
3350 MM_MODEM_STATE_LOCKED,
3351 MM_MODEM_STATE_CHANGE_REASON_UNKNOWN);
Aleksander Morgadoca15a102011-11-22 18:01:09 +01003352 }
3353 }
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01003354}
3355
Aleksander Morgado9f192be2020-01-09 12:45:41 +01003356MMModemLock
3357mm_iface_modem_get_unlock_required (MMIfaceModem *self)
3358{
3359 MmGdbusModem *skeleton = NULL;
3360 MMModemLock lock;
3361
3362 g_object_get (self,
3363 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
3364 NULL);
3365 if (skeleton) {
3366 lock = mm_gdbus_modem_get_unlock_required (skeleton);
3367 g_object_unref (skeleton);
3368 } else
3369 lock = MM_MODEM_LOCK_UNKNOWN;
3370
3371 return lock;
3372}
3373
Ben Chan4f8e9e22017-09-18 09:10:56 -07003374MMUnlockRetries *
3375mm_iface_modem_get_unlock_retries (MMIfaceModem *self)
3376{
3377 MmGdbusModem *skeleton = NULL;
3378 MMUnlockRetries *unlock_retries;
3379
3380 g_object_get (self,
3381 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
3382 NULL);
3383 if (skeleton) {
3384 GVariant *dictionary;
3385
3386 dictionary = mm_gdbus_modem_get_unlock_retries (skeleton);
3387 unlock_retries = mm_unlock_retries_new_from_dictionary (dictionary);
3388 g_object_unref (skeleton);
3389 } else
3390 unlock_retries = mm_unlock_retries_new ();
3391
3392 return unlock_retries;
3393}
3394
Ben Chand4ff05a2017-08-07 14:22:51 -07003395void
3396mm_iface_modem_update_unlock_retries (MMIfaceModem *self,
3397 MMUnlockRetries *unlock_retries)
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003398{
3399 MmGdbusModem *skeleton = NULL;
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003400 GVariant *previous_dictionary;
3401 MMUnlockRetries *previous_unlock_retries;
3402
3403 g_object_get (self,
3404 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
3405 NULL);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02003406 if (!skeleton)
3407 return;
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003408
3409 previous_dictionary = mm_gdbus_modem_get_unlock_retries (skeleton);
3410 previous_unlock_retries = mm_unlock_retries_new_from_dictionary (previous_dictionary);
3411
Ben Chan05a10972017-08-07 14:05:03 -07003412 /* If they are different, update */
3413 if (!mm_unlock_retries_cmp (unlock_retries, previous_unlock_retries)) {
3414 GVariant *new_dictionary;
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003415
Ben Chan05a10972017-08-07 14:05:03 -07003416 new_dictionary = mm_unlock_retries_get_dictionary (unlock_retries);
3417 mm_gdbus_modem_set_unlock_retries (skeleton, new_dictionary);
3418 g_variant_unref (new_dictionary);
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003419 }
3420
3421 g_object_unref (previous_unlock_retries);
3422 g_object_unref (skeleton);
3423}
3424
Aleksander Morgado13729332012-12-18 23:38:42 +01003425typedef enum {
3426 UPDATE_LOCK_INFO_CONTEXT_STEP_FIRST = 0,
3427 UPDATE_LOCK_INFO_CONTEXT_STEP_LOCK,
Aleksander Morgado13729332012-12-18 23:38:42 +01003428 UPDATE_LOCK_INFO_CONTEXT_STEP_AFTER_UNLOCK,
Carlo Lobrano43d97a42016-05-13 17:15:20 +02003429 UPDATE_LOCK_INFO_CONTEXT_STEP_RETRIES,
Aleksander Morgado13729332012-12-18 23:38:42 +01003430 UPDATE_LOCK_INFO_CONTEXT_STEP_LAST
3431} UpdateLockInfoContextStep;
3432
3433typedef struct {
Aleksander Morgado13729332012-12-18 23:38:42 +01003434 UpdateLockInfoContextStep step;
Aleksander Morgado13729332012-12-18 23:38:42 +01003435 MmGdbusModem *skeleton;
3436 MMModemLock lock;
3437 GError *saved_error;
3438} UpdateLockInfoContext;
3439
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003440static void
Ben Chan4df54582017-06-30 02:23:45 -07003441update_lock_info_context_free (UpdateLockInfoContext *ctx)
Aleksander Morgado13729332012-12-18 23:38:42 +01003442{
3443 g_assert (ctx->saved_error == NULL);
3444
Aleksander Morgado13729332012-12-18 23:38:42 +01003445 if (ctx->skeleton)
3446 g_object_unref (ctx->skeleton);
3447 g_slice_free (UpdateLockInfoContext, ctx);
3448}
3449
3450MMModemLock
3451mm_iface_modem_update_lock_info_finish (MMIfaceModem *self,
3452 GAsyncResult *res,
3453 GError **error)
3454{
Ben Chand56621b2017-07-05 22:20:09 -07003455 GError *inner_error = NULL;
Ben Chan4df54582017-06-30 02:23:45 -07003456 gssize value;
Aleksander Morgado13729332012-12-18 23:38:42 +01003457
Ben Chand56621b2017-07-05 22:20:09 -07003458 value = g_task_propagate_int (G_TASK (res), &inner_error);
3459 if (inner_error) {
3460 g_propagate_error (error, inner_error);
3461 return MM_MODEM_LOCK_UNKNOWN;
3462 }
3463 return (MMModemLock)value;
Aleksander Morgado13729332012-12-18 23:38:42 +01003464}
3465
Ben Chan4df54582017-06-30 02:23:45 -07003466static void update_lock_info_context_step (GTask *task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003467
3468static void
3469load_unlock_retries_ready (MMIfaceModem *self,
3470 GAsyncResult *res,
Ben Chan4df54582017-06-30 02:23:45 -07003471 GTask *task)
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003472{
Ben Chan4df54582017-06-30 02:23:45 -07003473 UpdateLockInfoContext *ctx;
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003474 GError *error = NULL;
3475 MMUnlockRetries *unlock_retries;
3476
3477 unlock_retries = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_retries_finish (self, res, &error);
3478 if (!unlock_retries) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003479 mm_obj_warn (self, "couldn't load unlock retries: %s", error->message);
Aleksander Morgado13729332012-12-18 23:38:42 +01003480 g_error_free (error);
3481 } else {
3482 /* Update the dictionary in the DBus interface */
Ben Chand4ff05a2017-08-07 14:22:51 -07003483 mm_iface_modem_update_unlock_retries (self, unlock_retries);
Aleksander Morgado13729332012-12-18 23:38:42 +01003484 g_object_unref (unlock_retries);
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003485 }
3486
Aleksander Morgado13729332012-12-18 23:38:42 +01003487 /* Go on to next step */
Ben Chan4df54582017-06-30 02:23:45 -07003488 ctx = g_task_get_task_data (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003489 ctx->step++;
Ben Chan4df54582017-06-30 02:23:45 -07003490 update_lock_info_context_step (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003491}
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003492
Aleksander Morgado13729332012-12-18 23:38:42 +01003493static void
3494modem_after_sim_unlock_ready (MMIfaceModem *self,
3495 GAsyncResult *res,
Ben Chan4df54582017-06-30 02:23:45 -07003496 GTask *task)
Aleksander Morgado13729332012-12-18 23:38:42 +01003497{
Ben Chan4df54582017-06-30 02:23:45 -07003498 UpdateLockInfoContext *ctx;
Aleksander Morgado13729332012-12-18 23:38:42 +01003499 GError *error = NULL;
3500
3501 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock_finish (self, res, &error)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003502 mm_obj_warn (self, "after SIM unlock failed: %s", error->message);
Aleksander Morgado13729332012-12-18 23:38:42 +01003503 g_error_free (error);
3504 }
3505
3506 /* Go on to next step */
Ben Chan4df54582017-06-30 02:23:45 -07003507 ctx = g_task_get_task_data (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003508 ctx->step++;
Ben Chan4df54582017-06-30 02:23:45 -07003509 update_lock_info_context_step (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003510}
3511
Aleksander Morgado13729332012-12-18 23:38:42 +01003512static void
Aleksander Morgado13c73192013-09-18 19:55:22 +02003513internal_load_unlock_required_ready (MMIfaceModem *self,
3514 GAsyncResult *res,
Ben Chan4df54582017-06-30 02:23:45 -07003515 GTask *task)
Aleksander Morgado13729332012-12-18 23:38:42 +01003516{
Ben Chan4df54582017-06-30 02:23:45 -07003517 UpdateLockInfoContext *ctx;
Aleksander Morgado13729332012-12-18 23:38:42 +01003518 GError *error = NULL;
3519
Ben Chan4df54582017-06-30 02:23:45 -07003520 ctx = g_task_get_task_data (task);
3521
Aleksander Morgado13c73192013-09-18 19:55:22 +02003522 ctx->lock = internal_load_unlock_required_finish (self, res, &error);
Aleksander Morgado13729332012-12-18 23:38:42 +01003523 if (error) {
3524 /* Treat several SIM related, serial and other core errors as critical
3525 * and abort the checks. These will end up moving the modem to a FAILED
3526 * state. */
3527 if (error->domain == MM_SERIAL_ERROR ||
3528 g_error_matches (error,
Aleksander Morgadocf0d3f32019-10-09 10:49:25 +02003529 G_IO_ERROR,
3530 G_IO_ERROR_CANCELLED)) {
Aleksander Morgado13729332012-12-18 23:38:42 +01003531 ctx->saved_error = error;
3532 ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
Ben Chan4df54582017-06-30 02:23:45 -07003533 update_lock_info_context_step (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003534 return;
Aleksander Morgado13c73192013-09-18 19:55:22 +02003535 }
3536
3537 if (g_error_matches (error,
3538 MM_MOBILE_EQUIPMENT_ERROR,
3539 MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
3540 g_error_matches (error,
3541 MM_MOBILE_EQUIPMENT_ERROR,
3542 MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
3543 g_error_matches (error,
3544 MM_MOBILE_EQUIPMENT_ERROR,
3545 MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
3546 /* SIM errors are only critical in 3GPP-only devices */
3547 if (!mm_iface_modem_is_cdma (self)) {
Aleksander Morgado4f3932c2013-04-18 15:15:38 +02003548 ctx->saved_error = error;
3549 ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
Ben Chan4df54582017-06-30 02:23:45 -07003550 update_lock_info_context_step (task);
Aleksander Morgado4f3932c2013-04-18 15:15:38 +02003551 return;
3552 }
Aleksander Morgado13c73192013-09-18 19:55:22 +02003553
3554 /* For mixed 3GPP+3GPP2 devices, skip SIM errors */
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003555 mm_obj_dbg (self, "skipping SIM error in 3GPP2-capable device, assuming no lock is needed");
Aleksander Morgado13c73192013-09-18 19:55:22 +02003556 g_error_free (error);
3557 ctx->lock = MM_MODEM_LOCK_NONE;
Aleksander Morgado4f3932c2013-04-18 15:15:38 +02003558 } else {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003559 mm_obj_dbg (self, "couldn't check if unlock required: %s", error->message);
Aleksander Morgado4f3932c2013-04-18 15:15:38 +02003560 g_error_free (error);
Aleksander Morgado4f3932c2013-04-18 15:15:38 +02003561 ctx->lock = MM_MODEM_LOCK_UNKNOWN;
Aleksander Morgado13729332012-12-18 23:38:42 +01003562 }
Aleksander Morgado13729332012-12-18 23:38:42 +01003563 }
3564
3565 /* Go on to next step */
3566 ctx->step++;
Ben Chan4df54582017-06-30 02:23:45 -07003567 update_lock_info_context_step (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003568}
3569
3570static void
Ben Chan4df54582017-06-30 02:23:45 -07003571update_lock_info_context_step (GTask *task)
Aleksander Morgado13729332012-12-18 23:38:42 +01003572{
Ben Chan4df54582017-06-30 02:23:45 -07003573 MMIfaceModem *self;
3574 UpdateLockInfoContext *ctx;
3575
3576 self = g_task_get_source_object (task);
3577 ctx = g_task_get_task_data (task);
3578
Aleksander Morgado13729332012-12-18 23:38:42 +01003579 switch (ctx->step) {
3580 case UPDATE_LOCK_INFO_CONTEXT_STEP_FIRST:
3581 /* We need the skeleton around */
3582 if (!ctx->skeleton) {
3583 ctx->saved_error = g_error_new (MM_CORE_ERROR,
3584 MM_CORE_ERROR_FAILED,
3585 "Couldn't get interface skeleton");
3586 ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
Ben Chan4df54582017-06-30 02:23:45 -07003587 update_lock_info_context_step (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003588 return;
3589 }
Aleksander Morgado13729332012-12-18 23:38:42 +01003590 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01003591 /* fall-through */
Aleksander Morgado13729332012-12-18 23:38:42 +01003592
3593 case UPDATE_LOCK_INFO_CONTEXT_STEP_LOCK:
3594 /* Don't re-ask if already known */
3595 if (ctx->lock == MM_MODEM_LOCK_UNKNOWN) {
3596 /* If we're already unlocked, we're done */
Dan Williams9b051b12015-07-20 12:17:12 -05003597 internal_load_unlock_required (
Ben Chan4df54582017-06-30 02:23:45 -07003598 self,
Dan Williams9b051b12015-07-20 12:17:12 -05003599 (GAsyncReadyCallback)internal_load_unlock_required_ready,
Ben Chan4df54582017-06-30 02:23:45 -07003600 task);
Dan Williams9b051b12015-07-20 12:17:12 -05003601 return;
Aleksander Morgado13729332012-12-18 23:38:42 +01003602 }
Aleksander Morgado13729332012-12-18 23:38:42 +01003603 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01003604 /* fall-through */
Aleksander Morgado13729332012-12-18 23:38:42 +01003605
Aleksander Morgado13729332012-12-18 23:38:42 +01003606 case UPDATE_LOCK_INFO_CONTEXT_STEP_AFTER_UNLOCK:
3607 /* If we get that no lock is required, run the after SIM unlock step
Dan Williams92035fd2013-04-18 12:19:46 -05003608 * in order to wait for the SIM to get ready. Skip waiting on
3609 * CDMA-only modems where we don't support a SIM. */
Ben Chan4df54582017-06-30 02:23:45 -07003610 if (!mm_iface_modem_is_cdma_only (self) &&
Dan Williams92035fd2013-04-18 12:19:46 -05003611 (ctx->lock == MM_MODEM_LOCK_NONE ||
3612 ctx->lock == MM_MODEM_LOCK_SIM_PIN2 ||
3613 ctx->lock == MM_MODEM_LOCK_SIM_PUK2)) {
Ben Chan4df54582017-06-30 02:23:45 -07003614 if (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock != NULL &&
3615 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock_finish != NULL) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003616 mm_obj_dbg (self, "SIM is ready, running after SIM unlock step...");
Ben Chan4df54582017-06-30 02:23:45 -07003617 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock (
3618 self,
Aleksander Morgado13729332012-12-18 23:38:42 +01003619 (GAsyncReadyCallback)modem_after_sim_unlock_ready,
Ben Chan4df54582017-06-30 02:23:45 -07003620 task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003621 return;
3622 }
3623
3624 /* If no way to run after SIM unlock step, we're done */
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003625 mm_obj_dbg (self, "SIM is ready, and no need for the after SIM unlock step...");
Aleksander Morgado13729332012-12-18 23:38:42 +01003626 }
Aleksander Morgado13729332012-12-18 23:38:42 +01003627 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01003628 /* fall-through */
Aleksander Morgado13729332012-12-18 23:38:42 +01003629
Carlo Lobrano43d97a42016-05-13 17:15:20 +02003630 case UPDATE_LOCK_INFO_CONTEXT_STEP_RETRIES:
3631 /* Load unlock retries if possible */
Ben Chan4df54582017-06-30 02:23:45 -07003632 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_retries &&
3633 MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_retries_finish) {
3634 MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_retries (
3635 self,
Carlo Lobrano43d97a42016-05-13 17:15:20 +02003636 (GAsyncReadyCallback)load_unlock_retries_ready,
Ben Chan4df54582017-06-30 02:23:45 -07003637 task);
Carlo Lobrano43d97a42016-05-13 17:15:20 +02003638 return;
3639 }
Carlo Lobrano43d97a42016-05-13 17:15:20 +02003640 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01003641 /* fall-through */
Carlo Lobrano43d97a42016-05-13 17:15:20 +02003642
Aleksander Morgado13729332012-12-18 23:38:42 +01003643 case UPDATE_LOCK_INFO_CONTEXT_STEP_LAST:
3644 if (ctx->saved_error) {
Pavan Holla38f67042020-11-23 17:52:17 +00003645 set_lock_status (self, ctx->skeleton, MM_MODEM_LOCK_UNKNOWN);
Aleksander Morgado13729332012-12-18 23:38:42 +01003646 /* Return saved error */
Ben Chan4df54582017-06-30 02:23:45 -07003647 g_task_return_error (task, ctx->saved_error);
Aleksander Morgado13729332012-12-18 23:38:42 +01003648 ctx->saved_error = NULL;
3649 } else {
3650 /* Update lock status and modem status if needed */
Ben Chan4df54582017-06-30 02:23:45 -07003651 set_lock_status (self, ctx->skeleton, ctx->lock);
3652 g_task_return_int (task, ctx->lock);
Aleksander Morgado13729332012-12-18 23:38:42 +01003653 }
3654
Ben Chan4df54582017-06-30 02:23:45 -07003655 g_object_unref (task);
Aleksander Morgado13729332012-12-18 23:38:42 +01003656 return;
3657
3658 default:
Ben Chancdff53d2017-07-17 10:09:03 -07003659 g_assert_not_reached ();
Aleksander Morgado13729332012-12-18 23:38:42 +01003660 }
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003661}
3662
3663void
Aleksander Morgado13729332012-12-18 23:38:42 +01003664mm_iface_modem_update_lock_info (MMIfaceModem *self,
3665 MMModemLock known_lock,
3666 GAsyncReadyCallback callback,
3667 gpointer user_data)
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003668{
Aleksander Morgado13729332012-12-18 23:38:42 +01003669 UpdateLockInfoContext *ctx;
Ben Chan4df54582017-06-30 02:23:45 -07003670 GTask *task;
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003671
Aleksander Morgado13729332012-12-18 23:38:42 +01003672 ctx = g_slice_new0 (UpdateLockInfoContext);
Ben Chan4df54582017-06-30 02:23:45 -07003673 g_object_get (self,
Aleksander Morgado13729332012-12-18 23:38:42 +01003674 MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
3675 NULL);
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003676
Aleksander Morgado13729332012-12-18 23:38:42 +01003677 /* If the given lock is known, we will avoid re-asking for it */
3678 ctx->lock = known_lock;
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003679
Ben Chan4df54582017-06-30 02:23:45 -07003680 task = g_task_new (self, NULL, callback, user_data);
3681 g_task_set_task_data (task, ctx, (GDestroyNotify)update_lock_info_context_free);
3682
3683 update_lock_info_context_step (task);
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01003684}
3685
3686/*****************************************************************************/
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003687/* Set power state sequence */
3688
3689typedef struct {
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003690 MmGdbusModem *skeleton;
3691 MMModemPowerState power_state;
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003692 MMModemPowerState previous_cached_power_state;
3693 MMModemPowerState previous_real_power_state;
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003694} SetPowerStateContext;
3695
3696static void
Ben Chanebc20e72017-06-30 02:23:44 -07003697set_power_state_context_free (SetPowerStateContext *ctx)
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003698{
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003699 if (ctx->skeleton)
3700 g_object_unref (ctx->skeleton);
3701 g_slice_free (SetPowerStateContext, ctx);
3702}
3703
3704gboolean
3705mm_iface_modem_set_power_state_finish (MMIfaceModem *self,
3706 GAsyncResult *res,
3707 GError **error)
3708{
Ben Chanebc20e72017-06-30 02:23:44 -07003709 return g_task_propagate_boolean (G_TASK (res), error);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003710}
3711
3712static void
3713modem_after_power_up_ready (MMIfaceModem *self,
3714 GAsyncResult *res,
Ben Chanebc20e72017-06-30 02:23:44 -07003715 GTask *task)
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003716{
3717 GError *error = NULL;
3718
3719 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish (self, res, &error);
3720 if (error)
Ben Chanebc20e72017-06-30 02:23:44 -07003721 g_task_return_error (task, error);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003722 else
Ben Chanebc20e72017-06-30 02:23:44 -07003723 g_task_return_boolean (task, TRUE);
3724 g_object_unref (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003725}
3726
3727static void
3728modem_power_up_ready (MMIfaceModem *self,
3729 GAsyncResult *res,
Ben Chanebc20e72017-06-30 02:23:44 -07003730 GTask *task)
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003731{
Ben Chanebc20e72017-06-30 02:23:44 -07003732 SetPowerStateContext *ctx;
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003733 GError *error = NULL;
3734
Ben Chanebc20e72017-06-30 02:23:44 -07003735 ctx = g_task_get_task_data (task);
3736
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003737 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish (self, res, &error);
3738 if (error) {
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003739 /* If the real and cached ones are different, set the real one */
3740 if (ctx->previous_cached_power_state != ctx->previous_real_power_state)
3741 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state);
Ben Chanebc20e72017-06-30 02:23:44 -07003742 g_task_return_error (task, error);
3743 g_object_unref (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003744 return;
3745 }
3746
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003747 mm_obj_dbg (self, "set in full-power mode...");
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003748 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state);
3749
3750 /* If we have something to do just after power-up, do it */
3751 if (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up &&
3752 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish) {
3753 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up (
3754 self,
3755 (GAsyncReadyCallback)modem_after_power_up_ready,
Ben Chanebc20e72017-06-30 02:23:44 -07003756 task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003757 return;
3758 }
3759
3760 /* Otherwise, we're done */
Ben Chanebc20e72017-06-30 02:23:44 -07003761 g_task_return_boolean (task, TRUE);
3762 g_object_unref (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003763}
3764
3765static void
3766modem_power_down_ready (MMIfaceModem *self,
3767 GAsyncResult *res,
Ben Chanebc20e72017-06-30 02:23:44 -07003768 GTask *task)
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003769{
Ben Chanebc20e72017-06-30 02:23:44 -07003770 SetPowerStateContext *ctx;
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003771 GError *error = NULL;
3772
Ben Chanebc20e72017-06-30 02:23:44 -07003773 ctx = g_task_get_task_data (task);
3774
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003775 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish (self, res, &error);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003776 if (error) {
3777 /* If the real and cached ones are different, set the real one */
3778 if (ctx->previous_cached_power_state != ctx->previous_real_power_state)
3779 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state);
Ben Chanebc20e72017-06-30 02:23:44 -07003780 g_task_return_error (task, error);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003781 } else {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003782 mm_obj_dbg (self, "set in low-power mode...");
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003783 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state);
Ben Chanebc20e72017-06-30 02:23:44 -07003784 g_task_return_boolean (task, TRUE);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003785 }
3786
Ben Chanebc20e72017-06-30 02:23:44 -07003787 g_object_unref (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003788}
3789
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003790static void
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003791modem_power_off_ready (MMIfaceModem *self,
Ben Chanebc20e72017-06-30 02:23:44 -07003792 GAsyncResult *res,
3793 GTask *task)
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003794{
Ben Chanebc20e72017-06-30 02:23:44 -07003795 SetPowerStateContext *ctx;
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003796 GError *error = NULL;
3797
Ben Chanebc20e72017-06-30 02:23:44 -07003798 ctx = g_task_get_task_data (task);
3799
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003800 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off_finish (self, res, &error);
3801 if (error) {
3802 /* If the real and cached ones are different, set the real one */
3803 if (ctx->previous_cached_power_state != ctx->previous_real_power_state)
3804 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state);
Ben Chanebc20e72017-06-30 02:23:44 -07003805 g_task_return_error (task, error);
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003806 } else {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003807 mm_obj_info (self, "powered off... may no longer be accessible");
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003808 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state);
Ben Chanebc20e72017-06-30 02:23:44 -07003809 g_task_return_boolean (task, TRUE);
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003810 }
3811
Ben Chanebc20e72017-06-30 02:23:44 -07003812 g_object_unref (task);
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003813}
3814
3815static void
Ben Chanebc20e72017-06-30 02:23:44 -07003816set_power_state (GTask *task)
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003817{
Ben Chanebc20e72017-06-30 02:23:44 -07003818 MMIfaceModem *self;
3819 SetPowerStateContext *ctx;
3820
3821 self = g_task_get_source_object (task);
3822 ctx = g_task_get_task_data (task);
3823
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003824 /* Already done if we're in the desired power state */
3825 if (ctx->previous_real_power_state == ctx->power_state) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003826 mm_obj_dbg (self, "no need to change power state: already in '%s' power state",
3827 mm_modem_power_state_get_string (ctx->power_state));
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003828 /* If the real and cached ones are different, set the real one */
3829 if (ctx->previous_cached_power_state != ctx->previous_real_power_state)
3830 mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state);
Ben Chanebc20e72017-06-30 02:23:44 -07003831 g_task_return_boolean (task, TRUE);
3832 g_object_unref (task);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003833 return;
3834 }
3835
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003836 /* Fully powering off the modem? */
3837 if (ctx->power_state == MM_MODEM_POWER_STATE_OFF) {
3838 /* Error if unsupported */
Ben Chanebc20e72017-06-30 02:23:44 -07003839 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off ||
3840 !MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off_finish) {
3841 g_task_return_new_error (task,
3842 MM_CORE_ERROR,
3843 MM_CORE_ERROR_UNSUPPORTED,
3844 "Powering off is not supported by this modem");
3845 g_object_unref (task);
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003846 return;
3847 }
3848
Ben Chanebc20e72017-06-30 02:23:44 -07003849 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off (
3850 MM_IFACE_MODEM (self),
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003851 (GAsyncReadyCallback)modem_power_off_ready,
Ben Chanebc20e72017-06-30 02:23:44 -07003852 task);
Aleksander Morgado9239fbc2014-02-18 10:35:58 +01003853 return;
3854 }
3855
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003856 /* Going into low power mode? */
3857 if (ctx->power_state == MM_MODEM_POWER_STATE_LOW) {
3858 /* Error if unsupported */
Ben Chanebc20e72017-06-30 02:23:44 -07003859 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down ||
3860 !MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish) {
3861 g_task_return_new_error (task,
3862 MM_CORE_ERROR,
3863 MM_CORE_ERROR_UNSUPPORTED,
3864 "Going into low-power mode is not supported by this modem");
3865 g_object_unref (task);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003866 return;
3867 }
3868
Ben Chanebc20e72017-06-30 02:23:44 -07003869 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down (
3870 MM_IFACE_MODEM (self),
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003871 (GAsyncReadyCallback)modem_power_down_ready,
Ben Chanebc20e72017-06-30 02:23:44 -07003872 task);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003873 return;
3874 }
3875
3876 /* Going out of low power mode? */
3877 if (ctx->power_state == MM_MODEM_POWER_STATE_ON) {
3878 /* Error if unsupported */
Ben Chanebc20e72017-06-30 02:23:44 -07003879 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up ||
3880 !MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish) {
3881 g_task_return_new_error (task,
3882 MM_CORE_ERROR,
3883 MM_CORE_ERROR_UNSUPPORTED,
3884 "Going into full-power mode is not supported by this modem");
3885 g_object_unref (task);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003886 return;
3887 }
3888
Ben Chanebc20e72017-06-30 02:23:44 -07003889 MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up (
3890 MM_IFACE_MODEM (self),
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003891 (GAsyncReadyCallback)modem_power_up_ready,
Ben Chanebc20e72017-06-30 02:23:44 -07003892 task);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003893 return;
3894 }
3895
3896 g_assert_not_reached ();
3897}
3898
3899static void
3900set_power_state_load_ready (MMIfaceModem *self,
3901 GAsyncResult *res,
Ben Chanebc20e72017-06-30 02:23:44 -07003902 GTask *task)
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003903{
Ben Chanebc20e72017-06-30 02:23:44 -07003904 SetPowerStateContext *ctx;
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003905 GError *error = NULL;
3906
Ben Chanebc20e72017-06-30 02:23:44 -07003907 ctx = g_task_get_task_data (task);
3908
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003909 ctx->previous_real_power_state = MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish (self, res, &error);
3910 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01003911 mm_obj_dbg (self, "couldn't reload current power state: %s", error->message);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003912 g_error_free (error);
3913 /* Default to the cached one */
3914 ctx->previous_real_power_state = ctx->previous_cached_power_state;
3915 }
3916
3917 /* And keep on */
Ben Chanebc20e72017-06-30 02:23:44 -07003918 set_power_state (task);
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003919}
3920
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003921void
3922mm_iface_modem_set_power_state (MMIfaceModem *self,
3923 MMModemPowerState power_state,
3924 GAsyncReadyCallback callback,
3925 gpointer user_data)
3926{
3927 SetPowerStateContext *ctx;
Ben Chanebc20e72017-06-30 02:23:44 -07003928 GTask *task;
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003929
3930 ctx = g_slice_new0 (SetPowerStateContext);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003931 ctx->power_state = power_state;
Ben Chanebc20e72017-06-30 02:23:44 -07003932
3933 task = g_task_new (self, NULL, callback, user_data);
3934 g_task_set_task_data (task, ctx, (GDestroyNotify)set_power_state_context_free);
3935
3936 g_object_get (self,
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003937 MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
3938 NULL);
3939 if (!ctx->skeleton) {
Ben Chanebc20e72017-06-30 02:23:44 -07003940 g_task_return_new_error (task,
3941 MM_CORE_ERROR,
3942 MM_CORE_ERROR_FAILED,
3943 "Couldn't get interface skeleton");
3944 g_object_unref (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003945 return;
3946 }
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003947
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003948 ctx->previous_cached_power_state = mm_gdbus_modem_get_power_state (ctx->skeleton);
3949
3950 /* We cannot really rely on the power state value that we had cached before,
3951 * as the real power status of the modem may also be changed by rfkill. So,
3952 * before updating the current power state, re-check which is the real power
3953 * state. */
Ben Chanebc20e72017-06-30 02:23:44 -07003954 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state &&
3955 MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish) {
3956 MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state (
3957 self,
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003958 (GAsyncReadyCallback)set_power_state_load_ready,
Ben Chanebc20e72017-06-30 02:23:44 -07003959 task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003960 return;
3961 }
3962
Aleksander Morgadoe227d4a2013-06-23 11:22:00 +02003963 /* If there is no way to load power state, just keep on assuming the cached
3964 * one is also the real one */
3965 ctx->previous_real_power_state = ctx->previous_cached_power_state;
Ben Chanebc20e72017-06-30 02:23:44 -07003966 set_power_state (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01003967}
3968
3969/*****************************************************************************/
Aleksander Morgadobe7cee22011-12-31 11:34:58 +01003970/* MODEM DISABLING */
3971
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +01003972gboolean
3973mm_iface_modem_disable_finish (MMIfaceModem *self,
Ben Chanc09b3b92017-06-30 02:23:40 -07003974 GAsyncResult *res,
3975 GError **error)
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +01003976{
Ben Chanc09b3b92017-06-30 02:23:40 -07003977 return g_task_propagate_boolean (G_TASK (res), error);
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +01003978}
3979
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +01003980void
3981mm_iface_modem_disable (MMIfaceModem *self,
3982 GAsyncReadyCallback callback,
3983 gpointer user_data)
3984{
Ben Chanc09b3b92017-06-30 02:23:40 -07003985 GTask *task;
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02003986
Aleksander Morgadof09eff62013-05-31 09:14:18 +02003987 /* Just complete, nothing to do */
Ben Chanc09b3b92017-06-30 02:23:40 -07003988 task = g_task_new (self, NULL, callback, user_data);
3989 g_task_return_boolean (task, TRUE);
3990 g_object_unref (task);
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +01003991}
3992
3993/*****************************************************************************/
Aleksander Morgadobe7cee22011-12-31 11:34:58 +01003994/* MODEM ENABLING */
3995
3996typedef struct _EnablingContext EnablingContext;
Ben Chan00a092d2017-06-30 02:23:39 -07003997static void interface_enabling_step (GTask *task);
Aleksander Morgadof3b6bfe2011-11-25 15:10:13 +01003998
3999typedef enum {
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004000 ENABLING_STEP_FIRST,
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004001 ENABLING_STEP_SET_POWER_STATE,
Eric Carusoc44b9282017-12-13 10:17:33 -08004002 ENABLING_STEP_CHECK_FOR_SIM_SWAP,
Aleksander Morgadoc0d3bd92011-11-25 15:04:17 +01004003 ENABLING_STEP_FLOW_CONTROL,
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004004 ENABLING_STEP_LAST
4005} EnablingStep;
4006
4007struct _EnablingContext {
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004008 EnablingStep step;
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004009 MmGdbusModem *skeleton;
4010};
4011
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004012static void
Ben Chan00a092d2017-06-30 02:23:39 -07004013enabling_context_free (EnablingContext *ctx)
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004014{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02004015 if (ctx->skeleton)
4016 g_object_unref (ctx->skeleton);
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004017 g_free (ctx);
4018}
4019
4020gboolean
4021mm_iface_modem_enable_finish (MMIfaceModem *self,
4022 GAsyncResult *res,
4023 GError **error)
4024{
Ben Chan00a092d2017-06-30 02:23:39 -07004025 return g_task_propagate_boolean (G_TASK (res), error);
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004026}
4027
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004028static void
4029enabling_set_power_state_ready (MMIfaceModem *self,
4030 GAsyncResult *res,
Ben Chan00a092d2017-06-30 02:23:39 -07004031 GTask *task)
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004032{
Ben Chan00a092d2017-06-30 02:23:39 -07004033 EnablingContext *ctx;
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004034 GError *error = NULL;
4035
4036 if (!mm_iface_modem_set_power_state_finish (self, res, &error)) {
Ben Chan00a092d2017-06-30 02:23:39 -07004037 g_task_return_error (task, error);
4038 g_object_unref (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004039 return;
4040 }
4041
4042 /* Go on to next step */
Ben Chan00a092d2017-06-30 02:23:39 -07004043 ctx = g_task_get_task_data (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004044 ctx->step++;
Ben Chan00a092d2017-06-30 02:23:39 -07004045 interface_enabling_step (task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004046}
4047
Aleksander Morgado17469492013-02-18 13:37:35 +01004048static void
Eric Carusoc44b9282017-12-13 10:17:33 -08004049check_for_sim_swap_ready (MMIfaceModem *self,
4050 GAsyncResult *res,
4051 GTask *task)
4052{
4053 EnablingContext *ctx;
4054 GError *error = NULL;
4055
4056 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish (self, res, &error)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004057 mm_obj_warn (self, "failed to check if SIM was swapped: %s", error->message);
Eric Carusoc44b9282017-12-13 10:17:33 -08004058 g_error_free (error);
4059 }
4060
4061 /* Go on to next step */
4062 ctx = g_task_get_task_data (task);
4063 ctx->step++;
4064 interface_enabling_step (task);
4065}
4066
4067static void
Aleksander Morgado17469492013-02-18 13:37:35 +01004068setup_flow_control_ready (MMIfaceModem *self,
4069 GAsyncResult *res,
Ben Chan00a092d2017-06-30 02:23:39 -07004070 GTask *task)
Aleksander Morgado17469492013-02-18 13:37:35 +01004071{
Ben Chan00a092d2017-06-30 02:23:39 -07004072 EnablingContext *ctx;
Aleksander Morgado17469492013-02-18 13:37:35 +01004073 GError *error = NULL;
4074
4075 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_flow_control_finish (self, res, &error);
4076 if (error) {
Ben Chan00a092d2017-06-30 02:23:39 -07004077 g_task_return_error (task, error);
4078 g_object_unref (task);
Aleksander Morgado17469492013-02-18 13:37:35 +01004079 return;
4080 }
4081
4082 /* Go on to next step */
Ben Chan00a092d2017-06-30 02:23:39 -07004083 ctx = g_task_get_task_data (task);
Aleksander Morgado17469492013-02-18 13:37:35 +01004084 ctx->step++;
Ben Chan00a092d2017-06-30 02:23:39 -07004085 interface_enabling_step (task);
Aleksander Morgado17469492013-02-18 13:37:35 +01004086}
Aleksander Morgadob948c932011-11-25 14:59:53 +01004087
Aleksander Morgado781c1822011-11-25 15:05:56 +01004088static const MMModemCharset best_charsets[] = {
4089 MM_MODEM_CHARSET_UTF8,
4090 MM_MODEM_CHARSET_UCS2,
4091 MM_MODEM_CHARSET_8859_1,
4092 MM_MODEM_CHARSET_IRA,
4093 MM_MODEM_CHARSET_GSM,
4094 MM_MODEM_CHARSET_UNKNOWN
4095};
4096
Aleksander Morgadob0a1ecc2011-11-25 14:57:54 +01004097static void
Ben Chan00a092d2017-06-30 02:23:39 -07004098interface_enabling_step (GTask *task)
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004099{
Ben Chan00a092d2017-06-30 02:23:39 -07004100 MMIfaceModem *self;
4101 EnablingContext *ctx;
4102
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004103 /* Don't run new steps if we're cancelled */
Ben Chan00a092d2017-06-30 02:23:39 -07004104 if (g_task_return_error_if_cancelled (task)) {
4105 g_object_unref (task);
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004106 return;
Ben Chan00a092d2017-06-30 02:23:39 -07004107 }
4108
4109 self = g_task_get_source_object (task);
4110 ctx = g_task_get_task_data (task);
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004111
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004112 switch (ctx->step) {
4113 case ENABLING_STEP_FIRST:
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004114 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01004115 /* fall-through */
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004116
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004117 case ENABLING_STEP_SET_POWER_STATE:
Ben Chan00a092d2017-06-30 02:23:39 -07004118 mm_iface_modem_set_power_state (self,
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004119 MM_MODEM_POWER_STATE_ON,
4120 (GAsyncReadyCallback)enabling_set_power_state_ready,
Ben Chan00a092d2017-06-30 02:23:39 -07004121 task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004122 return;
Aleksander Morgado7fa372d2011-11-25 15:02:31 +01004123
Eric Carusoc44b9282017-12-13 10:17:33 -08004124 case ENABLING_STEP_CHECK_FOR_SIM_SWAP:
4125 if (MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap &&
4126 MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish) {
4127 MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap (
4128 self,
Teijo Kinnunene52ad1c2020-09-07 15:18:52 +03004129 NULL,
Eric Carusoc44b9282017-12-13 10:17:33 -08004130 (GAsyncReadyCallback)check_for_sim_swap_ready,
4131 task);
4132 return;
4133 }
Eric Carusoc44b9282017-12-13 10:17:33 -08004134 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01004135 /* fall-through */
Eric Carusoc44b9282017-12-13 10:17:33 -08004136
Aleksander Morgadoc0d3bd92011-11-25 15:04:17 +01004137 case ENABLING_STEP_FLOW_CONTROL:
Ben Chan00a092d2017-06-30 02:23:39 -07004138 if (MM_IFACE_MODEM_GET_INTERFACE (self)->setup_flow_control &&
4139 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_flow_control_finish) {
4140 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_flow_control (
4141 self,
Aleksander Morgado7b506bc2011-12-29 11:37:52 +01004142 (GAsyncReadyCallback)setup_flow_control_ready,
Ben Chan00a092d2017-06-30 02:23:39 -07004143 task);
Aleksander Morgadoc0d3bd92011-11-25 15:04:17 +01004144 return;
4145 }
Aleksander Morgadoc0d3bd92011-11-25 15:04:17 +01004146 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01004147 /* fall-through */
Aleksander Morgadoc0d3bd92011-11-25 15:04:17 +01004148
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004149 case ENABLING_STEP_LAST:
4150 /* We are done without errors! */
Ben Chan00a092d2017-06-30 02:23:39 -07004151 g_task_return_boolean (task, TRUE);
4152 g_object_unref (task);
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004153 return;
Aleksander Morgadoeb04ead2019-11-28 22:46:04 +01004154
4155 default:
4156 break;
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004157 }
4158
4159 g_assert_not_reached ();
4160}
4161
4162void
4163mm_iface_modem_enable (MMIfaceModem *self,
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004164 GCancellable *cancellable,
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004165 GAsyncReadyCallback callback,
4166 gpointer user_data)
4167{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02004168 EnablingContext *ctx;
Ben Chan00a092d2017-06-30 02:23:39 -07004169 GTask *task;
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02004170
4171 ctx = g_new0 (EnablingContext, 1);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02004172 ctx->step = ENABLING_STEP_FIRST;
Ben Chan00a092d2017-06-30 02:23:39 -07004173
4174 task = g_task_new (self, cancellable, callback, user_data);
4175 g_task_set_task_data (task, ctx, (GDestroyNotify)enabling_context_free);
4176
4177 g_object_get (self,
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02004178 MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
4179 NULL);
4180 if (!ctx->skeleton) {
Ben Chan00a092d2017-06-30 02:23:39 -07004181 g_task_return_new_error (task,
4182 MM_CORE_ERROR,
4183 MM_CORE_ERROR_FAILED,
4184 "Couldn't get interface skeleton");
4185 g_object_unref (task);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02004186 return;
4187 }
4188
Ben Chan00a092d2017-06-30 02:23:39 -07004189 interface_enabling_step (task);
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004190}
4191
4192/*****************************************************************************/
Aleksander Morgadobe7cee22011-12-31 11:34:58 +01004193/* MODEM INITIALIZATION */
4194
4195typedef struct _InitializationContext InitializationContext;
Ben Chan66f10d62017-06-30 02:23:38 -07004196static void interface_initialization_step (GTask *task);
Aleksander Morgado8327b6a2011-11-25 14:49:40 +01004197
4198typedef enum {
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004199 INITIALIZATION_STEP_FIRST,
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004200 INITIALIZATION_STEP_CURRENT_CAPABILITIES,
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004201 INITIALIZATION_STEP_SUPPORTED_CAPABILITIES,
Giacinto Cifelli8e033ba2020-05-18 16:50:33 +02004202 INITIALIZATION_STEP_SUPPORTED_CHARSETS,
4203 INITIALIZATION_STEP_CHARSET,
Aleksander Morgado776cc662011-12-12 20:22:51 +01004204 INITIALIZATION_STEP_BEARERS,
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004205 INITIALIZATION_STEP_MANUFACTURER,
4206 INITIALIZATION_STEP_MODEL,
4207 INITIALIZATION_STEP_REVISION,
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004208 INITIALIZATION_STEP_CARRIER_CONFIG,
Ben Chandaa59ae2017-09-17 19:45:27 -07004209 INITIALIZATION_STEP_HARDWARE_REVISION,
Aleksander Morgado98524332011-11-22 17:40:52 +01004210 INITIALIZATION_STEP_EQUIPMENT_ID,
4211 INITIALIZATION_STEP_DEVICE_ID,
Aleksander Morgado48babcf2011-11-22 17:53:49 +01004212 INITIALIZATION_STEP_SUPPORTED_MODES,
4213 INITIALIZATION_STEP_SUPPORTED_BANDS,
Aleksander Morgadob3222202013-05-23 10:39:13 +02004214 INITIALIZATION_STEP_SUPPORTED_IP_FAMILIES,
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004215 INITIALIZATION_STEP_POWER_STATE,
Carlo Lobrano60f4f9e2016-08-08 15:47:18 +02004216 INITIALIZATION_STEP_SIM_HOT_SWAP,
Aleksander Morgadoe7409b62020-08-01 09:59:27 +02004217 INITIALIZATION_STEP_SIM_SLOTS,
Ben Chanc204a8c2013-01-24 00:43:08 -08004218 INITIALIZATION_STEP_UNLOCK_REQUIRED,
4219 INITIALIZATION_STEP_SIM,
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004220 INITIALIZATION_STEP_SETUP_CARRIER_CONFIG,
Ben Chanc204a8c2013-01-24 00:43:08 -08004221 INITIALIZATION_STEP_OWN_NUMBERS,
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004222 INITIALIZATION_STEP_CURRENT_MODES,
4223 INITIALIZATION_STEP_CURRENT_BANDS,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004224 INITIALIZATION_STEP_LAST
4225} InitializationStep;
4226
4227struct _InitializationContext {
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004228 InitializationStep step;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004229 MmGdbusModem *skeleton;
Giacinto Cifelli8e033ba2020-05-18 16:50:33 +02004230 MMModemCharset supported_charsets;
4231 const MMModemCharset *current_charset;
Aleksander Morgado75187722012-03-30 11:06:32 +02004232 GError *fatal_error;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004233};
4234
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004235static void
Ben Chan66f10d62017-06-30 02:23:38 -07004236initialization_context_free (InitializationContext *ctx)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004237{
Aleksander Morgado75187722012-03-30 11:06:32 +02004238 g_assert (ctx->fatal_error == NULL);
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004239 g_object_unref (ctx->skeleton);
4240 g_free (ctx);
4241}
4242
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004243#undef STR_REPLY_READY_FN
4244#define STR_REPLY_READY_FN(NAME,DISPLAY) \
4245 static void \
4246 load_##NAME##_ready (MMIfaceModem *self, \
4247 GAsyncResult *res, \
Ben Chan66f10d62017-06-30 02:23:38 -07004248 GTask *task) \
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004249 { \
Ben Chan66f10d62017-06-30 02:23:38 -07004250 InitializationContext *ctx; \
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004251 GError *error = NULL; \
4252 gchar *val; \
4253 \
Ben Chan66f10d62017-06-30 02:23:38 -07004254 ctx = g_task_get_task_data (task); \
4255 \
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004256 val = MM_IFACE_MODEM_GET_INTERFACE (self)->load_##NAME##_finish (self, res, &error); \
Aleksander Morgadofb90f202011-12-01 19:40:07 +01004257 mm_gdbus_modem_set_##NAME (ctx->skeleton, val); \
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004258 g_free (val); \
4259 \
4260 if (error) { \
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004261 mm_obj_warn (self, "couldn't load %s: %s", DISPLAY, error->message); \
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004262 g_error_free (error); \
4263 } \
4264 \
4265 /* Go on to next step */ \
4266 ctx->step++; \
Ben Chan66f10d62017-06-30 02:23:38 -07004267 interface_initialization_step (task); \
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01004268 }
4269
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004270#undef UINT_REPLY_READY_FN
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004271#define UINT_REPLY_READY_FN(NAME,DISPLAY) \
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004272 static void \
4273 load_##NAME##_ready (MMIfaceModem *self, \
4274 GAsyncResult *res, \
Ben Chan66f10d62017-06-30 02:23:38 -07004275 GTask *task) \
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004276 { \
Ben Chan66f10d62017-06-30 02:23:38 -07004277 InitializationContext *ctx; \
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004278 GError *error = NULL; \
4279 \
Ben Chan66f10d62017-06-30 02:23:38 -07004280 ctx = g_task_get_task_data (task); \
4281 \
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004282 mm_gdbus_modem_set_##NAME ( \
4283 ctx->skeleton, \
4284 MM_IFACE_MODEM_GET_INTERFACE (self)->load_##NAME##_finish (self, res, &error)); \
4285 \
4286 if (error) { \
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004287 mm_obj_warn (self, "couldn't load %s: %s", DISPLAY, error->message); \
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004288 g_error_free (error); \
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004289 } \
4290 \
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004291 /* Go on to next step */ \
4292 ctx->step++; \
Ben Chan66f10d62017-06-30 02:23:38 -07004293 interface_initialization_step (task); \
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004294 }
4295
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004296static void
Aleksander Morgado13c73192013-09-18 19:55:22 +02004297current_capabilities_internal_load_unlock_required_ready (MMIfaceModem *self,
4298 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004299 GTask *task)
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004300{
Ben Chan66f10d62017-06-30 02:23:38 -07004301 InitializationContext *ctx;
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004302 GError *error = NULL;
4303
Ben Chan66f10d62017-06-30 02:23:38 -07004304 ctx = g_task_get_task_data (task);
4305
Aleksander Morgado13c73192013-09-18 19:55:22 +02004306 internal_load_unlock_required_finish (self, res, &error);
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004307 if (error) {
4308 /* These SIM errors indicate that there is NO valid SIM available. So,
4309 * remove all 3GPP caps from the current capabilities */
4310 if (g_error_matches (error,
4311 MM_MOBILE_EQUIPMENT_ERROR,
4312 MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
4313 g_error_matches (error,
4314 MM_MOBILE_EQUIPMENT_ERROR,
4315 MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
4316 g_error_matches (error,
4317 MM_MOBILE_EQUIPMENT_ERROR,
4318 MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
4319 MMModemCapability caps;
4320
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004321 mm_obj_dbg (self, "multimode device without SIM, no 3GPP capabilities");
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004322 caps = mm_gdbus_modem_get_current_capabilities (ctx->skeleton);
Aleksander Morgado7354dc92020-03-23 06:36:36 +01004323 caps &= ~MM_MODEM_CAPABILITY_3GPP;
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004324
4325 /* CDMA-EVDO must still be around */
4326 g_assert (caps & MM_MODEM_CAPABILITY_CDMA_EVDO);
4327 mm_gdbus_modem_set_current_capabilities (ctx->skeleton, caps);
4328 }
4329
4330 g_error_free (error);
4331 }
4332
4333 /* Keep on */
4334 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004335 interface_initialization_step (task);
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004336}
4337
4338static void
4339load_current_capabilities_ready (MMIfaceModem *self,
4340 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004341 GTask *task)
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004342{
Ben Chan66f10d62017-06-30 02:23:38 -07004343 InitializationContext *ctx;
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004344 MMModemCapability caps;
4345 GError *error = NULL;
4346
Ben Chan66f10d62017-06-30 02:23:38 -07004347 ctx = g_task_get_task_data (task);
4348
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004349 caps = MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_capabilities_finish (self, res, &error);
4350 if (error) {
4351 g_propagate_error (&ctx->fatal_error, error);
4352 g_prefix_error (&ctx->fatal_error, "couldn't load current capabilities: ");
4353 /* Jump to the last step */
4354 ctx->step = INITIALIZATION_STEP_LAST;
Ben Chan66f10d62017-06-30 02:23:38 -07004355 interface_initialization_step (task);
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004356 return;
4357 }
4358
Aleksander Morgado05301f22020-03-23 07:58:23 +01004359 /* By default CS/PS/CDMA1X/EVDO network registration checks are the only
4360 * ones enabled, so fix them up based on capabilities, enabling EPS or 5GS
4361 * checks if required, and disabling CS/PS/CDMA1X/EVDO if required. */
Aleksander Morgado875ade32017-03-07 11:12:51 +01004362 if (caps & MM_MODEM_CAPABILITY_LTE) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004363 mm_obj_dbg (self, "setting EPS network as supported");
Ben Chan66f10d62017-06-30 02:23:38 -07004364 g_object_set (G_OBJECT (self),
Aleksander Morgado875ade32017-03-07 11:12:51 +01004365 MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, TRUE,
4366 NULL);
4367 }
Aleksander Morgado05301f22020-03-23 07:58:23 +01004368 if (caps & MM_MODEM_CAPABILITY_5GNR) {
4369 mm_obj_dbg (self, "setting 5GS network as supported");
Ben Chan66f10d62017-06-30 02:23:38 -07004370 g_object_set (G_OBJECT (self),
Aleksander Morgado05301f22020-03-23 07:58:23 +01004371 MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED, TRUE,
4372 NULL);
4373 }
4374 if (!(caps & MM_MODEM_CAPABILITY_CDMA_EVDO)) {
4375 mm_obj_dbg (self, "setting CDMA1x/EVDO networks as unsupported");
4376 g_object_set (G_OBJECT (self),
Aleksander Morgado875ade32017-03-07 11:12:51 +01004377 MM_IFACE_MODEM_CDMA_CDMA1X_NETWORK_SUPPORTED, FALSE,
4378 MM_IFACE_MODEM_CDMA_EVDO_NETWORK_SUPPORTED, FALSE,
4379 NULL);
4380 }
Aleksander Morgado05301f22020-03-23 07:58:23 +01004381 if (!(caps & MM_MODEM_CAPABILITY_GSM_UMTS)) {
4382 mm_obj_dbg (self, "setting CS/PS networks as unsupported");
4383 g_object_set (G_OBJECT (self),
4384 MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, FALSE,
4385 MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, FALSE,
4386 NULL);
4387 }
Aleksander Morgado875ade32017-03-07 11:12:51 +01004388
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004389 /* Update current caps right away, even if we may fix them during the
4390 * multimode device check. No big deal in updating them twice, as we're not
4391 * exposed in DBus yet. */
4392 mm_gdbus_modem_set_current_capabilities (ctx->skeleton, caps);
4393
4394 /* If the device is a multimode device (3GPP+3GPP2) check whether we have a
4395 * SIM or not. */
Aleksander Morgado7354dc92020-03-23 06:36:36 +01004396 if ((caps & MM_MODEM_CAPABILITY_CDMA_EVDO) && (caps & MM_MODEM_CAPABILITY_3GPP)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004397 mm_obj_dbg (self, "checking if multimode device has a SIM...");
Aleksander Morgado13c73192013-09-18 19:55:22 +02004398 internal_load_unlock_required (
Ben Chan66f10d62017-06-30 02:23:38 -07004399 self,
Aleksander Morgado13c73192013-09-18 19:55:22 +02004400 (GAsyncReadyCallback)current_capabilities_internal_load_unlock_required_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07004401 task);
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004402 return;
4403 }
4404
4405 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004406 interface_initialization_step (task);
Aleksander Morgado7d668eb2013-04-18 18:32:13 +02004407}
4408
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004409static void
4410load_supported_capabilities_ready (MMIfaceModem *self,
4411 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004412 GTask *task)
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004413{
Ben Chan66f10d62017-06-30 02:23:38 -07004414 InitializationContext *ctx;
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004415 GArray *supported_capabilities;
4416 GError *error = NULL;
4417
Ben Chan66f10d62017-06-30 02:23:38 -07004418 ctx = g_task_get_task_data (task);
4419
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004420 supported_capabilities = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_capabilities_finish (self, res, &error);
4421 if (error) {
4422 g_propagate_error (&ctx->fatal_error, error);
4423 g_prefix_error (&ctx->fatal_error, "couldn't load supported capabilities: ");
4424 /* Jump to the last step */
4425 ctx->step = INITIALIZATION_STEP_LAST;
Ben Chan66f10d62017-06-30 02:23:38 -07004426 interface_initialization_step (task);
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004427 return;
4428 }
4429
4430 /* Update supported caps */
4431 mm_gdbus_modem_set_supported_capabilities (ctx->skeleton,
4432 mm_common_capability_combinations_garray_to_variant (supported_capabilities));
4433 g_array_unref (supported_capabilities);
4434
4435 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004436 interface_initialization_step (task);
Aleksander Morgado700ebc52013-05-24 12:35:44 +02004437}
4438
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004439STR_REPLY_READY_FN (manufacturer, "manufacturer")
4440STR_REPLY_READY_FN (model, "model")
4441STR_REPLY_READY_FN (revision, "revision")
4442STR_REPLY_READY_FN (hardware_revision, "hardware revision")
4443STR_REPLY_READY_FN (equipment_identifier, "equipment identifier")
4444STR_REPLY_READY_FN (device_identifier, "device identifier")
Aleksander Morgadobf699302011-12-30 17:24:14 +01004445
4446static void
Giacinto Cifelli8e033ba2020-05-18 16:50:33 +02004447load_supported_charsets_ready (MMIfaceModem *self,
4448 GAsyncResult *res,
4449 GTask *task)
4450{
4451 InitializationContext *ctx;
4452 GError *error = NULL;
4453
4454 ctx = g_task_get_task_data (task);
4455
4456 ctx->supported_charsets =
4457 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets_finish (self, res, &error);
4458 if (error) {
4459 mm_obj_warn (self, "couldn't load supported charsets: %s", error->message);
4460 g_error_free (error);
4461 }
4462
4463 /* Go on to next step */
4464 ctx->step++;
4465 interface_initialization_step (task);
4466}
4467
4468static void
4469setup_charset_ready (MMIfaceModem *self,
4470 GAsyncResult *res,
4471 GTask *task)
4472{
4473 InitializationContext *ctx;
4474 GError *error = NULL;
4475
4476 ctx = g_task_get_task_data (task);
4477
4478 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset_finish (self, res, &error)) {
4479 mm_obj_dbg (self, "couldn't set charset '%s': %s",
4480 mm_modem_charset_to_string (*ctx->current_charset),
4481 error->message);
4482 g_error_free (error);
4483
4484 /* Will retry step with some other charset type */
4485 } else
4486 /* Done, Go on to next step */
4487 ctx->step++;
4488
4489 interface_initialization_step (task);
4490}
4491
4492static void
Aleksander Morgadobf699302011-12-30 17:24:14 +01004493load_supported_modes_ready (MMIfaceModem *self,
4494 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004495 GTask *task)
Aleksander Morgadobf699302011-12-30 17:24:14 +01004496{
Ben Chan66f10d62017-06-30 02:23:38 -07004497 InitializationContext *ctx;
Aleksander Morgadobf699302011-12-30 17:24:14 +01004498 GError *error = NULL;
Aleksander Morgado45ceba72013-05-29 12:41:49 +02004499 GArray *modes_array;
Aleksander Morgadobf699302011-12-30 17:24:14 +01004500
Ben Chan66f10d62017-06-30 02:23:38 -07004501 ctx = g_task_get_task_data (task);
4502
Aleksander Morgado45ceba72013-05-29 12:41:49 +02004503 modes_array = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_modes_finish (self, res, &error);
4504 if (modes_array != NULL) {
4505 mm_gdbus_modem_set_supported_modes (ctx->skeleton,
4506 mm_common_mode_combinations_garray_to_variant (modes_array));
4507 g_array_unref (modes_array);
Aleksander Morgadobf699302011-12-30 17:24:14 +01004508 }
4509
4510 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004511 mm_obj_warn (self, "couldn't load supported modes: %s", error->message);
Aleksander Morgadobf699302011-12-30 17:24:14 +01004512 g_error_free (error);
4513 }
4514
4515 /* Go on to next step */
4516 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004517 interface_initialization_step (task);
Aleksander Morgadobf699302011-12-30 17:24:14 +01004518}
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004519
4520static void
4521load_supported_bands_ready (MMIfaceModem *self,
4522 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004523 GTask *task)
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004524{
Ben Chan66f10d62017-06-30 02:23:38 -07004525 InitializationContext *ctx;
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004526 GError *error = NULL;
4527 GArray *bands_array;
4528
Ben Chan66f10d62017-06-30 02:23:38 -07004529 ctx = g_task_get_task_data (task);
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004530
Ben Chan66f10d62017-06-30 02:23:38 -07004531 bands_array = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_bands_finish (self, res, &error);
Aleksander Morgado0c009a22011-12-28 14:00:15 +01004532 if (bands_array) {
Aleksander Morgado292914c2016-08-11 14:03:45 +02004533 mm_common_bands_garray_sort (bands_array);
Aleksander Morgado0c009a22011-12-28 14:00:15 +01004534 mm_gdbus_modem_set_supported_bands (ctx->skeleton,
4535 mm_common_bands_garray_to_variant (bands_array));
Aleksander Morgado0c009a22011-12-28 14:00:15 +01004536 g_array_unref (bands_array);
4537 }
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004538
4539 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004540 mm_obj_warn (self, "couldn't load supported bands: %s", error->message);
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004541 g_error_free (error);
4542 }
4543
4544 /* Go on to next step */
4545 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004546 interface_initialization_step (task);
Aleksander Morgado9d7e3de2011-12-26 18:50:16 +01004547}
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004548
Aleksander Morgadob3222202013-05-23 10:39:13 +02004549static void
4550load_supported_ip_families_ready (MMIfaceModem *self,
4551 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004552 GTask *task)
Aleksander Morgadob3222202013-05-23 10:39:13 +02004553{
Ben Chan66f10d62017-06-30 02:23:38 -07004554 InitializationContext *ctx;
Aleksander Morgadob3222202013-05-23 10:39:13 +02004555 GError *error = NULL;
4556 MMBearerIpFamily ip_families;
4557
Ben Chan66f10d62017-06-30 02:23:38 -07004558 ctx = g_task_get_task_data (task);
4559
Aleksander Morgadob3222202013-05-23 10:39:13 +02004560 ip_families = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_ip_families_finish (self, res, &error);
4561
4562 if (ip_families != MM_BEARER_IP_FAMILY_NONE)
4563 mm_gdbus_modem_set_supported_ip_families (ctx->skeleton, ip_families);
4564
4565 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004566 mm_obj_warn (self, "couldn't load supported IP families: %s", error->message);
Aleksander Morgadob3222202013-05-23 10:39:13 +02004567 g_error_free (error);
4568 }
4569
4570 /* Go on to next step */
4571 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004572 interface_initialization_step (task);
Aleksander Morgadob3222202013-05-23 10:39:13 +02004573}
4574
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004575UINT_REPLY_READY_FN (power_state, "power state")
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01004576
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004577static void
Aleksander Morgado130ea742020-08-01 09:59:01 +02004578setup_sim_hot_swap_ready (MMIfaceModem *self,
4579 GAsyncResult *res,
4580 GTask *task)
4581{
4582 InitializationContext *ctx;
4583 g_autoptr(GError) error = NULL;
4584
4585 ctx = g_task_get_task_data (task);
4586
4587 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish (self, res, &error);
4588 if (error)
4589 mm_obj_warn (self, "SIM hot swap setup failed: %s", error->message);
4590 else {
4591 mm_obj_dbg (self, "SIM hot swap setup succeeded");
4592 g_object_set (self,
4593 MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, TRUE,
4594 NULL);
4595 }
4596
4597 /* Go on to next step */
4598 ctx->step++;
4599 interface_initialization_step (task);
4600}
4601
4602static void
Aleksander Morgadoe7409b62020-08-01 09:59:27 +02004603load_sim_slots_ready (MMIfaceModem *self,
4604 GAsyncResult *res,
4605 GTask *task)
4606{
4607 InitializationContext *ctx;
4608 g_autoptr(GPtrArray) sim_slots = NULL;
4609 g_autoptr(GError) error = NULL;
4610 guint primary_sim_slot = 0;
4611
4612 ctx = g_task_get_task_data (task);
4613
4614 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots_finish (self,
4615 res,
4616 &sim_slots,
4617 &primary_sim_slot,
4618 &error))
4619 mm_obj_warn (self, "couldn't query SIM slots: %s", error->message);
4620
4621 if (sim_slots) {
4622 MMBaseSim *primary_sim = NULL;
4623 GPtrArray *sim_slot_paths_array;
4624 g_auto(GStrv) sim_slot_paths = NULL;
4625 guint i;
4626
4627 g_assert (primary_sim_slot);
4628 g_assert_cmpuint (primary_sim_slot, <=, sim_slots->len);
4629
4630 sim_slot_paths_array = g_ptr_array_new ();
4631 for (i = 0; i < sim_slots->len; i++) {
4632 MMBaseSim *sim;
4633 const gchar *sim_path;
4634
4635 sim = MM_BASE_SIM (g_ptr_array_index (sim_slots, i));
4636 if (!sim) {
4637 g_ptr_array_add (sim_slot_paths_array, g_strdup ("/"));
4638 continue;
4639 }
4640
4641 sim_path = mm_base_sim_get_path (sim);
4642 g_ptr_array_add (sim_slot_paths_array, g_strdup (sim_path));
4643 }
4644 g_ptr_array_add (sim_slot_paths_array, NULL);
4645 sim_slot_paths = (GStrv) g_ptr_array_free (sim_slot_paths_array, FALSE);
4646
4647 mm_gdbus_modem_set_sim_slots (ctx->skeleton, (const gchar *const *)sim_slot_paths);
4648 mm_gdbus_modem_set_primary_sim_slot (ctx->skeleton, primary_sim_slot);
4649
4650 /* If loading SIM slots is supported, we also expose already the primary active SIM object */
4651 if (primary_sim_slot) {
4652 primary_sim = g_ptr_array_index (sim_slots, primary_sim_slot - 1);
4653 if (primary_sim)
4654 g_object_bind_property (primary_sim, MM_BASE_SIM_PATH,
4655 ctx->skeleton, "sim",
4656 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
4657 }
4658 g_object_set (self,
4659 MM_IFACE_MODEM_SIM, primary_sim,
4660 MM_IFACE_MODEM_SIM_SLOTS, sim_slots,
4661 NULL);
4662 }
4663
4664 /* Go on to next step */
4665 ctx->step++;
4666 interface_initialization_step (task);
4667}
4668
4669static void
Aleksander Morgado13729332012-12-18 23:38:42 +01004670modem_update_lock_info_ready (MMIfaceModem *self,
4671 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004672 GTask *task)
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01004673{
Ben Chan66f10d62017-06-30 02:23:38 -07004674 InitializationContext *ctx;
4675
4676 ctx = g_task_get_task_data (task);
4677
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01004678 /* NOTE: we already propagated the lock state, no need to do it again */
Aleksander Morgado13729332012-12-18 23:38:42 +01004679 mm_iface_modem_update_lock_info_finish (self, res, &ctx->fatal_error);
Aleksander Morgado75187722012-03-30 11:06:32 +02004680 if (ctx->fatal_error) {
4681 g_prefix_error (&ctx->fatal_error,
4682 "Couldn't check unlock status: ");
4683 /* Jump to the last step */
4684 ctx->step = INITIALIZATION_STEP_LAST;
4685 } else
4686 /* Go on to next step */
4687 ctx->step++;
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01004688
Ben Chan66f10d62017-06-30 02:23:38 -07004689 interface_initialization_step (task);
Aleksander Morgado7a20ad42011-11-22 17:47:46 +01004690}
4691
Aleksander Morgado3ccc78e2012-03-01 00:22:22 +01004692static void
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004693sim_new_ready (GAsyncInitable *initable,
4694 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004695 GTask *task)
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004696{
Ben Chan66f10d62017-06-30 02:23:38 -07004697 MMIfaceModem *self;
4698 InitializationContext *ctx;
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02004699 MMBaseSim *sim;
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004700 GError *error = NULL;
4701
Ben Chan66f10d62017-06-30 02:23:38 -07004702 self = g_task_get_source_object (task);
4703 ctx = g_task_get_task_data (task);
4704
4705 sim = MM_IFACE_MODEM_GET_INTERFACE (self)->create_sim_finish (self, res, &error);
Aleksander Morgadobda0d0c2011-12-31 12:56:55 +01004706 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004707 mm_obj_warn (self, "couldn't create SIM: %s", error->message);
Ben Chan66f10d62017-06-30 02:23:38 -07004708 g_task_return_error (task, error);
4709 g_object_unref (task);
Aleksander Morgadoba5321a2011-12-30 23:47:39 +01004710 return;
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004711 }
4712
Aleksander Morgadobda0d0c2011-12-31 12:56:55 +01004713 /* We may get error with !sim, when the implementation doesn't want to
4714 * handle any (e.g. CDMA) */
4715 if (sim) {
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02004716 g_object_bind_property (sim, MM_BASE_SIM_PATH,
Aleksander Morgadobda0d0c2011-12-31 12:56:55 +01004717 ctx->skeleton, "sim",
4718 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
Aleksander Morgadoba5321a2011-12-30 23:47:39 +01004719
Ben Chan66f10d62017-06-30 02:23:38 -07004720 g_object_set (self,
Aleksander Morgadobda0d0c2011-12-31 12:56:55 +01004721 MM_IFACE_MODEM_SIM, sim,
4722 NULL);
4723 g_object_unref (sim);
4724 }
Aleksander Morgadoba5321a2011-12-30 23:47:39 +01004725
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004726 /* Go on to next step */
4727 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004728 interface_initialization_step (task);
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004729}
4730
4731static void
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02004732sim_reinit_ready (MMBaseSim *sim,
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004733 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004734 GTask *task)
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004735{
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004736 MMIfaceModem *self;
Ben Chan66f10d62017-06-30 02:23:38 -07004737 InitializationContext *ctx;
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004738 GError *error = NULL;
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004739
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004740 self = g_task_get_source_object (task);
4741 ctx = g_task_get_task_data (task);
Ben Chan66f10d62017-06-30 02:23:38 -07004742
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02004743 if (!mm_base_sim_initialize_finish (sim, res, &error)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004744 mm_obj_warn (self, "SIM re-initialization failed: %s",
4745 error ? error->message : "Unknown error");
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004746 g_clear_error (&error);
4747 }
4748
4749 /* Go on to next step */
4750 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004751 interface_initialization_step (task);
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004752}
4753
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004754static void
4755setup_carrier_config_ready (MMIfaceModem *self,
4756 GAsyncResult *res,
4757 GTask *task)
4758{
4759 InitializationContext *ctx;
4760 GError *error = NULL;
4761
4762 ctx = g_task_get_task_data (task);
4763
4764 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->setup_carrier_config_finish (self, res, &error)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004765 mm_obj_warn (self, "couldn't setup carrier config: %s", error->message);
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004766 g_error_free (error);
4767 }
4768
4769 /* Go on to next step */
4770 ctx->step++;
4771 interface_initialization_step (task);
4772}
4773
4774static void
4775load_carrier_config_ready (MMIfaceModem *self,
4776 GAsyncResult *res,
4777 GTask *task)
4778{
4779 InitializationContext *ctx;
4780 GError *error = NULL;
Aleksander Morgado52b67dc2018-12-18 16:57:07 +01004781 gchar *name = NULL;
4782 gchar *revision = NULL;
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004783
4784 ctx = g_task_get_task_data (task);
4785
Aleksander Morgado52b67dc2018-12-18 16:57:07 +01004786 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_carrier_config_finish (self, res, &name, &revision, &error)) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004787 mm_obj_warn (self, "couldn't load carrier config: %s", error->message);
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004788 g_error_free (error);
4789 } else {
Aleksander Morgado52b67dc2018-12-18 16:57:07 +01004790 mm_gdbus_modem_set_carrier_configuration (ctx->skeleton, name);
4791 mm_gdbus_modem_set_carrier_configuration_revision (ctx->skeleton, revision);
4792 g_free (name);
4793 g_free (revision);
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01004794 }
4795
4796 /* Go on to next step */
4797 ctx->step++;
4798 interface_initialization_step (task);
4799}
4800
Thieu Lec21709b2013-11-19 13:06:19 -08004801void
4802mm_iface_modem_update_own_numbers (MMIfaceModem *self,
4803 const GStrv own_numbers)
4804{
4805 MmGdbusModem *skeleton = NULL;
4806
4807 g_object_get (self,
4808 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
4809 NULL);
4810 if (skeleton) {
4811 mm_gdbus_modem_set_own_numbers (skeleton, (const gchar * const *)own_numbers);
4812 g_object_unref (skeleton);
4813 }
4814}
4815
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01004816static void
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004817load_own_numbers_ready (MMIfaceModem *self,
4818 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004819 GTask *task)
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004820{
Ben Chan66f10d62017-06-30 02:23:38 -07004821 InitializationContext *ctx;
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004822 GError *error = NULL;
4823 GStrv str_list;
4824
Ben Chan66f10d62017-06-30 02:23:38 -07004825 ctx = g_task_get_task_data (task);
4826
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004827 str_list = MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers_finish (self, res, &error);
4828 if (error) {
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004829 mm_obj_warn (self, "couldn't load list of own numbers: %s", error->message);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004830 g_error_free (error);
4831 }
4832
4833 if (str_list) {
4834 mm_gdbus_modem_set_own_numbers (ctx->skeleton, (const gchar *const *) str_list);
4835 g_strfreev (str_list);
4836 }
4837
4838 /* Go on to next step */
4839 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004840 interface_initialization_step (task);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004841}
4842
4843static void
4844load_current_modes_ready (MMIfaceModem *self,
4845 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004846 GTask *task)
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004847{
Ben Chan66f10d62017-06-30 02:23:38 -07004848 InitializationContext *ctx;
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004849 MMModemMode allowed = MM_MODEM_MODE_NONE;
4850 MMModemMode preferred = MM_MODEM_MODE_NONE;
4851 GError *error = NULL;
4852
Ben Chan66f10d62017-06-30 02:23:38 -07004853 ctx = g_task_get_task_data (task);
4854
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004855 if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes_finish (self,
4856 res,
4857 &allowed,
4858 &preferred,
4859 &error)) {
4860 /* Errors when getting allowed/preferred won't be critical */
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004861 mm_obj_warn (self, "couldn't load current allowed/preferred modes: %s", error->message);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004862 g_error_free (error);
4863 } else
4864 mm_gdbus_modem_set_current_modes (ctx->skeleton, g_variant_new ("(uu)", allowed, preferred));
4865
4866 /* Done, Go on to next step */
4867 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004868 interface_initialization_step (task);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004869}
4870
4871static void
4872load_current_bands_ready (MMIfaceModem *self,
4873 GAsyncResult *res,
Ben Chan66f10d62017-06-30 02:23:38 -07004874 GTask *task)
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004875{
Ben Chan66f10d62017-06-30 02:23:38 -07004876 InitializationContext *ctx;
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004877 GArray *current_bands;
4878 GError *error = NULL;
4879
Ben Chan66f10d62017-06-30 02:23:38 -07004880 ctx = g_task_get_task_data (task);
4881
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004882 current_bands = MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands_finish (self, res, &error);
4883 if (!current_bands) {
4884 /* Errors when getting current bands won't be critical */
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01004885 mm_obj_warn (self, "couldn't load current bands: %s", error->message);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004886 g_error_free (error);
4887 } else {
4888 GArray *filtered_bands;
4889 GArray *supported_bands;
4890
4891 supported_bands = (mm_common_bands_variant_to_garray (
4892 mm_gdbus_modem_get_supported_bands (ctx->skeleton)));
4893 filtered_bands = mm_filter_current_bands (supported_bands, current_bands);
4894
4895 g_array_unref (current_bands);
4896 if (supported_bands)
4897 g_array_unref (supported_bands);
4898
4899 if (filtered_bands) {
Aleksander Morgado292914c2016-08-11 14:03:45 +02004900 mm_common_bands_garray_sort (filtered_bands);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004901 mm_gdbus_modem_set_current_bands (ctx->skeleton,
4902 mm_common_bands_garray_to_variant (filtered_bands));
4903 g_array_unref (filtered_bands);
4904 }
4905 }
4906
4907 /* Done, Go on to next step */
4908 ctx->step++;
Ben Chan66f10d62017-06-30 02:23:38 -07004909 interface_initialization_step (task);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02004910}
4911
4912static void
Ben Chan66f10d62017-06-30 02:23:38 -07004913interface_initialization_step (GTask *task)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004914{
Ben Chan66f10d62017-06-30 02:23:38 -07004915 MMIfaceModem *self;
4916 InitializationContext *ctx;
4917
4918 self = g_task_get_source_object (task);
4919 ctx = g_task_get_task_data (task);
4920
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004921 /* Don't run new steps if we're cancelled */
Ben Chan66f10d62017-06-30 02:23:38 -07004922 if (g_task_return_error_if_cancelled (task)) {
4923 /* Simply ignore any fatal error encountered as the initialization is cancelled anyway. */
4924 if (ctx->fatal_error) {
4925 g_error_free (ctx->fatal_error);
4926 ctx->fatal_error = NULL;
4927 }
4928 g_object_unref (task);
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004929 return;
Ben Chan66f10d62017-06-30 02:23:38 -07004930 }
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01004931
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01004932 switch (ctx->step) {
Aleksander Morgadofc195092011-11-25 14:53:35 +01004933 case INITIALIZATION_STEP_FIRST:
Aleksander Morgado88e6b0e2011-11-22 17:33:47 +01004934 /* Load device if not done before */
4935 if (!mm_gdbus_modem_get_device (ctx->skeleton)) {
4936 gchar *device;
4937
Ben Chan66f10d62017-06-30 02:23:38 -07004938 g_object_get (self,
Aleksander Morgado88e6b0e2011-11-22 17:33:47 +01004939 MM_BASE_MODEM_DEVICE, &device,
4940 NULL);
4941 mm_gdbus_modem_set_device (ctx->skeleton, device);
4942 g_free (device);
4943 }
4944 /* Load driver if not done before */
Aleksander Morgado0436b3e2012-08-24 13:28:22 +02004945 if (!mm_gdbus_modem_get_drivers (ctx->skeleton)) {
4946 gchar **drivers;
Aleksander Morgado88e6b0e2011-11-22 17:33:47 +01004947
Ben Chan66f10d62017-06-30 02:23:38 -07004948 g_object_get (self,
Aleksander Morgado0436b3e2012-08-24 13:28:22 +02004949 MM_BASE_MODEM_DRIVERS, &drivers,
Aleksander Morgado88e6b0e2011-11-22 17:33:47 +01004950 NULL);
Aleksander Morgado0436b3e2012-08-24 13:28:22 +02004951 mm_gdbus_modem_set_drivers (ctx->skeleton, (const gchar * const *)drivers);
4952 g_strfreev (drivers);
Aleksander Morgado88e6b0e2011-11-22 17:33:47 +01004953 }
4954 /* Load plugin if not done before */
4955 if (!mm_gdbus_modem_get_plugin (ctx->skeleton)) {
4956 gchar *plugin;
4957
Ben Chan66f10d62017-06-30 02:23:38 -07004958 g_object_get (self,
Aleksander Morgado88e6b0e2011-11-22 17:33:47 +01004959 MM_BASE_MODEM_PLUGIN, &plugin,
4960 NULL);
4961 mm_gdbus_modem_set_plugin (ctx->skeleton, plugin);
4962 g_free (plugin);
4963 }
Aleksander Morgado79fdddc2012-10-19 00:58:36 +02004964 /* Load primary port if not done before */
4965 if (!mm_gdbus_modem_get_primary_port (ctx->skeleton)) {
Aleksander Morgadocbee87f2013-04-06 22:58:08 +02004966 MMPort *primary = NULL;
Aleksander Morgado79fdddc2012-10-19 00:58:36 +02004967
4968#if defined WITH_QMI
Aleksander Morgadob8f6fb52020-10-22 12:07:09 +02004969 if (MM_IS_BROADBAND_MODEM_QMI (self))
4970 primary = MM_PORT (mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (self)));
Aleksander Morgadocbee87f2013-04-06 22:58:08 +02004971#endif
4972#if defined WITH_MBIM
Aleksander Morgado6defec22020-10-22 11:52:46 +02004973 if (!primary && MM_IS_BROADBAND_MODEM_MBIM (self))
4974 primary = MM_PORT (mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self)));
Aleksander Morgadocbee87f2013-04-06 22:58:08 +02004975#endif
Aleksander Morgado79fdddc2012-10-19 00:58:36 +02004976 if (!primary)
Ben Chan66f10d62017-06-30 02:23:38 -07004977 primary = MM_PORT (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)));
Aleksander Morgado79fdddc2012-10-19 00:58:36 +02004978
4979 g_assert (primary != NULL);
4980 mm_gdbus_modem_set_primary_port (ctx->skeleton, mm_port_get_device (primary));
4981 }
Aleksander Morgado3206e952013-06-20 23:45:12 +02004982 /* Load ports if not done before */
4983 if (!mm_gdbus_modem_get_ports (ctx->skeleton)) {
4984 MMModemPortInfo *port_infos;
4985 guint n_port_infos;
4986
Ben Chan66f10d62017-06-30 02:23:38 -07004987 port_infos = mm_base_modem_get_port_infos (MM_BASE_MODEM (self), &n_port_infos);
Aleksander Morgado3206e952013-06-20 23:45:12 +02004988 mm_gdbus_modem_set_ports (ctx->skeleton, mm_common_ports_array_to_variant (port_infos, n_port_infos));
4989 mm_modem_port_info_array_free (port_infos, n_port_infos);
4990 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01004991 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01004992 /* fall-through */
Aleksander Morgadob6539e92011-11-22 17:30:57 +01004993
Aleksander Morgado7b59a802011-11-25 14:36:26 +01004994 case INITIALIZATION_STEP_CURRENT_CAPABILITIES:
4995 /* Current capabilities may change during runtime, i.e. if new firmware reloaded; but we'll
4996 * try to handle that by making sure the capabilities are cleared when the new firmware is
4997 * reloaded. So if we're asked to re-initialize, if we already have current capabilities loaded,
4998 * don't try to load them again. */
4999 if (mm_gdbus_modem_get_current_capabilities (ctx->skeleton) == MM_MODEM_CAPABILITY_NONE &&
Ben Chan66f10d62017-06-30 02:23:38 -07005000 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_capabilities &&
5001 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_capabilities_finish) {
5002 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_capabilities (
5003 self,
Aleksander Morgado7b59a802011-11-25 14:36:26 +01005004 (GAsyncReadyCallback)load_current_capabilities_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005005 task);
Aleksander Morgado7b59a802011-11-25 14:36:26 +01005006 return;
5007 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005008 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005009 /* fall-through */
Aleksander Morgado7b59a802011-11-25 14:36:26 +01005010
Aleksander Morgado700ebc52013-05-24 12:35:44 +02005011 case INITIALIZATION_STEP_SUPPORTED_CAPABILITIES: {
5012 GArray *supported_capabilities;
5013
5014 supported_capabilities = (mm_common_capability_combinations_variant_to_garray (
5015 mm_gdbus_modem_get_supported_capabilities (ctx->skeleton)));
5016
5017 /* Supported capabilities are meant to be loaded only once during the whole
Aleksander Morgadob6539e92011-11-22 17:30:57 +01005018 * lifetime of the modem. Therefore, if we already have them loaded,
5019 * don't try to load them again. */
Aleksander Morgado700ebc52013-05-24 12:35:44 +02005020 if (supported_capabilities->len == 0 ||
5021 g_array_index (supported_capabilities, MMModemCapability, 0) == MM_MODEM_CAPABILITY_NONE) {
5022 MMModemCapability current;
5023
Ben Chan66f10d62017-06-30 02:23:38 -07005024 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_capabilities &&
5025 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_capabilities_finish) {
5026 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_capabilities (
5027 self,
Aleksander Morgado700ebc52013-05-24 12:35:44 +02005028 (GAsyncReadyCallback)load_supported_capabilities_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005029 task);
Aleksander Morgadoddb96912013-06-25 11:46:19 +02005030 g_array_unref (supported_capabilities);
Aleksander Morgado700ebc52013-05-24 12:35:44 +02005031 return;
5032 }
5033
5034 /* If no specific way of getting modem capabilities, default to the current ones */
5035 g_array_unref (supported_capabilities);
5036 supported_capabilities = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 1);
5037 current = mm_gdbus_modem_get_current_capabilities (ctx->skeleton);
5038 g_array_append_val (supported_capabilities, current);
5039 mm_gdbus_modem_set_supported_capabilities (
5040 ctx->skeleton,
5041 mm_common_capability_combinations_garray_to_variant (supported_capabilities));
Aleksander Morgadob6539e92011-11-22 17:30:57 +01005042 }
Aleksander Morgado700ebc52013-05-24 12:35:44 +02005043 g_array_unref (supported_capabilities);
5044
Aleksander Morgadofc195092011-11-25 14:53:35 +01005045 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005046 } /* fall-through */
Aleksander Morgadob6539e92011-11-22 17:30:57 +01005047
Giacinto Cifelli8e033ba2020-05-18 16:50:33 +02005048 case INITIALIZATION_STEP_SUPPORTED_CHARSETS:
5049 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets &&
5050 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets_finish) {
5051 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets (
5052 self,
5053 (GAsyncReadyCallback)load_supported_charsets_ready,
5054 task);
5055 return;
5056 }
5057 ctx->step++;
5058 /* fall-through */
5059
5060 case INITIALIZATION_STEP_CHARSET:
5061 /* Only try to set charsets if we were able to load supported ones */
5062 if (ctx->supported_charsets > 0 &&
5063 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset &&
5064 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset_finish) {
5065 gboolean next_to_try = FALSE;
5066
5067 while (!next_to_try) {
5068 if (!ctx->current_charset)
5069 /* Switch the device's charset; we prefer UTF-8, but UCS2 will do too */
5070 ctx->current_charset = &best_charsets[0];
5071 else
5072 /* Try with the next one */
5073 ctx->current_charset++;
5074
5075 if (*ctx->current_charset == MM_MODEM_CHARSET_UNKNOWN)
5076 break;
5077
5078 if (ctx->supported_charsets & (*ctx->current_charset))
5079 next_to_try = TRUE;
5080 }
5081
5082 if (next_to_try) {
5083 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset (
5084 self,
5085 *ctx->current_charset,
5086 (GAsyncReadyCallback)setup_charset_ready,
5087 task);
5088 return;
5089 }
5090
Frederic Martinsons2f53a082020-12-20 18:07:44 +01005091 mm_obj_warn (self, "Failed to find usable modem character set, let it to UNKNOWN");
Giacinto Cifelli8e033ba2020-05-18 16:50:33 +02005092 }
5093 ctx->step++;
5094 /* fall-through */
5095
Aleksander Morgado776cc662011-12-12 20:22:51 +01005096 case INITIALIZATION_STEP_BEARERS: {
5097 MMBearerList *list = NULL;
Aleksander Morgadob35be612011-11-22 17:37:15 +01005098
Aleksander Morgado776cc662011-12-12 20:22:51 +01005099 /* Bearers setup is meant to be loaded only once during the whole
5100 * lifetime of the modem. The list may have been created by the object
5101 * implementing the interface; if so use it. */
Ben Chan66f10d62017-06-30 02:23:38 -07005102 g_object_get (self,
Aleksander Morgado776cc662011-12-12 20:22:51 +01005103 MM_IFACE_MODEM_BEARER_LIST, &list,
5104 NULL);
5105
5106 if (!list) {
Aleksander Morgadoe2a6be32012-08-21 12:21:08 +02005107 guint n;
5108
5109 /* The maximum number of available/connected modems is guessed from
5110 * the size of the data ports list. */
Ben Chan66f10d62017-06-30 02:23:38 -07005111 n = g_list_length (mm_base_modem_peek_data_ports (MM_BASE_MODEM (self)));
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01005112 mm_obj_dbg (self, "allowed up to %u bearers", n);
Aleksander Morgado776cc662011-12-12 20:22:51 +01005113
5114 /* Create new default list */
Aleksander Morgadoe2a6be32012-08-21 12:21:08 +02005115 list = mm_bearer_list_new (n, n);
Aleksander Morgado7f442b72013-11-15 19:06:58 +01005116 g_signal_connect (list,
5117 "notify::" MM_BEARER_LIST_NUM_BEARERS,
5118 G_CALLBACK (bearer_list_updated),
Ben Chan66f10d62017-06-30 02:23:38 -07005119 self);
5120 g_object_set (self,
Aleksander Morgado776cc662011-12-12 20:22:51 +01005121 MM_IFACE_MODEM_BEARER_LIST, list,
5122 NULL);
Aleksander Morgadob35be612011-11-22 17:37:15 +01005123 }
Aleksander Morgado776cc662011-12-12 20:22:51 +01005124
5125 if (mm_gdbus_modem_get_max_bearers (ctx->skeleton) == 0)
5126 mm_gdbus_modem_set_max_bearers (
5127 ctx->skeleton,
5128 mm_bearer_list_get_max (list));
5129 if (mm_gdbus_modem_get_max_active_bearers (ctx->skeleton) == 0)
5130 mm_gdbus_modem_set_max_active_bearers (
5131 ctx->skeleton,
5132 mm_bearer_list_get_max_active (list));
5133 g_object_unref (list);
5134
Aleksander Morgadofc195092011-11-25 14:53:35 +01005135 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005136 } /* fall-through */
Aleksander Morgadob35be612011-11-22 17:37:15 +01005137
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005138 case INITIALIZATION_STEP_MANUFACTURER:
5139 /* Manufacturer is meant to be loaded only once during the whole
5140 * lifetime of the modem. Therefore, if we already have them loaded,
5141 * don't try to load them again. */
5142 if (mm_gdbus_modem_get_manufacturer (ctx->skeleton) == NULL &&
Ben Chan66f10d62017-06-30 02:23:38 -07005143 MM_IFACE_MODEM_GET_INTERFACE (self)->load_manufacturer &&
5144 MM_IFACE_MODEM_GET_INTERFACE (self)->load_manufacturer_finish) {
5145 MM_IFACE_MODEM_GET_INTERFACE (self)->load_manufacturer (
5146 self,
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005147 (GAsyncReadyCallback)load_manufacturer_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005148 task);
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005149 return;
5150 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005151 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005152 /* fall-through */
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005153
5154 case INITIALIZATION_STEP_MODEL:
5155 /* Model is meant to be loaded only once during the whole
5156 * lifetime of the modem. Therefore, if we already have them loaded,
5157 * don't try to load them again. */
5158 if (mm_gdbus_modem_get_model (ctx->skeleton) == NULL &&
Ben Chan66f10d62017-06-30 02:23:38 -07005159 MM_IFACE_MODEM_GET_INTERFACE (self)->load_model &&
5160 MM_IFACE_MODEM_GET_INTERFACE (self)->load_model_finish) {
5161 MM_IFACE_MODEM_GET_INTERFACE (self)->load_model (
5162 self,
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005163 (GAsyncReadyCallback)load_model_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005164 task);
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005165 return;
5166 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005167 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005168 /* fall-through */
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005169
5170 case INITIALIZATION_STEP_REVISION:
5171 /* Revision is meant to be loaded only once during the whole
5172 * lifetime of the modem. Therefore, if we already have them loaded,
5173 * don't try to load them again. */
5174 if (mm_gdbus_modem_get_revision (ctx->skeleton) == NULL &&
Ben Chan66f10d62017-06-30 02:23:38 -07005175 MM_IFACE_MODEM_GET_INTERFACE (self)->load_revision &&
5176 MM_IFACE_MODEM_GET_INTERFACE (self)->load_revision_finish) {
5177 MM_IFACE_MODEM_GET_INTERFACE (self)->load_revision (
5178 self,
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005179 (GAsyncReadyCallback)load_revision_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005180 task);
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005181 return;
5182 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005183 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005184 /* fall-through */
Aleksander Morgado7a9b0d92011-11-22 17:38:42 +01005185
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005186 case INITIALIZATION_STEP_CARRIER_CONFIG:
5187 /* Current carrier config is meant to be loaded only once during the whole
5188 * lifetime of the modem. Therefore, if we already have them loaded,
5189 * don't try to load them again. */
5190 if (mm_gdbus_modem_get_carrier_configuration (ctx->skeleton) == NULL &&
5191 MM_IFACE_MODEM_GET_INTERFACE (self)->load_carrier_config &&
5192 MM_IFACE_MODEM_GET_INTERFACE (self)->load_carrier_config_finish) {
5193 MM_IFACE_MODEM_GET_INTERFACE (self)->load_carrier_config (self,
5194 (GAsyncReadyCallback)load_carrier_config_ready,
5195 task);
5196 return;
5197 }
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005198 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005199 /* fall-through */
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005200
Ben Chandaa59ae2017-09-17 19:45:27 -07005201 case INITIALIZATION_STEP_HARDWARE_REVISION:
5202 /* HardwareRevision is meant to be loaded only once during the whole
5203 * lifetime of the modem. Therefore, if we already have them loaded,
5204 * don't try to load them again. */
5205 if (mm_gdbus_modem_get_hardware_revision (ctx->skeleton) == NULL &&
5206 MM_IFACE_MODEM_GET_INTERFACE (self)->load_hardware_revision &&
5207 MM_IFACE_MODEM_GET_INTERFACE (self)->load_hardware_revision_finish) {
5208 MM_IFACE_MODEM_GET_INTERFACE (self)->load_hardware_revision (
5209 self,
5210 (GAsyncReadyCallback)load_hardware_revision_ready,
5211 task);
5212 return;
5213 }
Ben Chandaa59ae2017-09-17 19:45:27 -07005214 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005215 /* fall-through */
Ben Chandaa59ae2017-09-17 19:45:27 -07005216
Aleksander Morgado98524332011-11-22 17:40:52 +01005217 case INITIALIZATION_STEP_EQUIPMENT_ID:
5218 /* Equipment ID is meant to be loaded only once during the whole
5219 * lifetime of the modem. Therefore, if we already have them loaded,
5220 * don't try to load them again. */
5221 if (mm_gdbus_modem_get_equipment_identifier (ctx->skeleton) == NULL &&
Ben Chan66f10d62017-06-30 02:23:38 -07005222 MM_IFACE_MODEM_GET_INTERFACE (self)->load_equipment_identifier &&
5223 MM_IFACE_MODEM_GET_INTERFACE (self)->load_equipment_identifier_finish) {
5224 MM_IFACE_MODEM_GET_INTERFACE (self)->load_equipment_identifier (
5225 self,
Aleksander Morgado98524332011-11-22 17:40:52 +01005226 (GAsyncReadyCallback)load_equipment_identifier_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005227 task);
Aleksander Morgado98524332011-11-22 17:40:52 +01005228 return;
5229 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005230 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005231 /* fall-through */
Aleksander Morgado98524332011-11-22 17:40:52 +01005232
5233 case INITIALIZATION_STEP_DEVICE_ID:
5234 /* Device ID is meant to be loaded only once during the whole
5235 * lifetime of the modem. Therefore, if we already have them loaded,
5236 * don't try to load them again. */
5237 if (mm_gdbus_modem_get_device_identifier (ctx->skeleton) == NULL &&
Ben Chan66f10d62017-06-30 02:23:38 -07005238 MM_IFACE_MODEM_GET_INTERFACE (self)->load_device_identifier &&
5239 MM_IFACE_MODEM_GET_INTERFACE (self)->load_device_identifier_finish) {
5240 MM_IFACE_MODEM_GET_INTERFACE (self)->load_device_identifier (
5241 self,
Aleksander Morgado98524332011-11-22 17:40:52 +01005242 (GAsyncReadyCallback)load_device_identifier_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005243 task);
Aleksander Morgado98524332011-11-22 17:40:52 +01005244 return;
5245 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005246 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005247 /* fall-through */
Aleksander Morgado98524332011-11-22 17:40:52 +01005248
Aleksander Morgado48babcf2011-11-22 17:53:49 +01005249 case INITIALIZATION_STEP_SUPPORTED_MODES:
Ben Chan66f10d62017-06-30 02:23:38 -07005250 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_modes != NULL &&
5251 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_modes_finish != NULL) {
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005252 GArray *supported_modes;
5253 MMModemModeCombination *mode = NULL;
Aleksander Morgadobf699302011-12-30 17:24:14 +01005254
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005255 supported_modes = (mm_common_mode_combinations_variant_to_garray (
5256 mm_gdbus_modem_get_supported_modes (ctx->skeleton)));
5257
5258 /* Supported modes are meant to be loaded only once during the whole
5259 * lifetime of the modem. Therefore, if we already have them loaded,
5260 * don't try to load them again. */
5261 if (supported_modes->len == 1)
5262 mode = &g_array_index (supported_modes, MMModemModeCombination, 0);
5263 if (supported_modes->len == 0 ||
5264 (mode && mode->allowed == MM_MODEM_MODE_ANY && mode->preferred == MM_MODEM_MODE_NONE)) {
Ben Chan66f10d62017-06-30 02:23:38 -07005265 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_modes (
5266 self,
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005267 (GAsyncReadyCallback)load_supported_modes_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005268 task);
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005269 g_array_unref (supported_modes);
5270 return;
5271 }
5272
5273 g_array_unref (supported_modes);
Aleksander Morgado48babcf2011-11-22 17:53:49 +01005274 }
Aleksander Morgadofc195092011-11-25 14:53:35 +01005275 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005276 /* fall-through */
Aleksander Morgado48babcf2011-11-22 17:53:49 +01005277
Aleksander Morgado0c009a22011-12-28 14:00:15 +01005278 case INITIALIZATION_STEP_SUPPORTED_BANDS: {
5279 GArray *supported_bands;
5280
5281 supported_bands = (mm_common_bands_variant_to_garray (
5282 mm_gdbus_modem_get_supported_bands (ctx->skeleton)));
5283
Aleksander Morgado48babcf2011-11-22 17:53:49 +01005284 /* Supported bands are meant to be loaded only once during the whole
5285 * lifetime of the modem. Therefore, if we already have them loaded,
5286 * don't try to load them again. */
Aleksander Morgado0c009a22011-12-28 14:00:15 +01005287 if (supported_bands->len == 0 ||
5288 g_array_index (supported_bands, MMModemBand, 0) == MM_MODEM_BAND_UNKNOWN) {
Ben Chan66f10d62017-06-30 02:23:38 -07005289 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_bands &&
5290 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_bands_finish) {
5291 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_bands (
5292 self,
Aleksander Morgado0c009a22011-12-28 14:00:15 +01005293 (GAsyncReadyCallback)load_supported_bands_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005294 task);
Aleksander Morgado0c009a22011-12-28 14:00:15 +01005295 g_array_unref (supported_bands);
5296 return;
5297 }
5298
Aleksander Morgado82f91f32012-10-22 18:57:42 +02005299 /* Loading supported bands not implemented, default to UNKNOWN */
5300 mm_gdbus_modem_set_supported_bands (ctx->skeleton, mm_common_build_bands_unknown ());
Aleksander Morgado212d00c2013-05-29 10:47:53 +02005301 mm_gdbus_modem_set_current_bands (ctx->skeleton, mm_common_build_bands_unknown ());
Aleksander Morgado48babcf2011-11-22 17:53:49 +01005302 }
Aleksander Morgado0c009a22011-12-28 14:00:15 +01005303 g_array_unref (supported_bands);
5304
Aleksander Morgadofc195092011-11-25 14:53:35 +01005305 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005306 } /* fall-through */
Aleksander Morgado48babcf2011-11-22 17:53:49 +01005307
Aleksander Morgadob3222202013-05-23 10:39:13 +02005308 case INITIALIZATION_STEP_SUPPORTED_IP_FAMILIES:
5309 /* Supported ip_families are meant to be loaded only once during the whole
5310 * lifetime of the modem. Therefore, if we already have them loaded,
5311 * don't try to load them again. */
Ben Chan66f10d62017-06-30 02:23:38 -07005312 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_ip_families != NULL &&
5313 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_ip_families_finish != NULL &&
Aleksander Morgadob3222202013-05-23 10:39:13 +02005314 mm_gdbus_modem_get_supported_ip_families (ctx->skeleton) == MM_BEARER_IP_FAMILY_NONE) {
Ben Chan66f10d62017-06-30 02:23:38 -07005315 MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_ip_families (
5316 self,
Aleksander Morgadob3222202013-05-23 10:39:13 +02005317 (GAsyncReadyCallback)load_supported_ip_families_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005318 task);
Aleksander Morgadob3222202013-05-23 10:39:13 +02005319 return;
5320 }
Aleksander Morgadob3222202013-05-23 10:39:13 +02005321 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005322 /* fall-through */
Aleksander Morgadob3222202013-05-23 10:39:13 +02005323
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01005324 case INITIALIZATION_STEP_POWER_STATE:
5325 /* Initial power state is meant to be loaded only once. Therefore, if we
5326 * already have it loaded, don't try to load it again. */
5327 if (mm_gdbus_modem_get_power_state (ctx->skeleton) == MM_MODEM_POWER_STATE_UNKNOWN) {
Ben Chan66f10d62017-06-30 02:23:38 -07005328 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state &&
5329 MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish) {
5330 MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state (
5331 self,
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01005332 (GAsyncReadyCallback)load_power_state_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005333 task);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01005334 return;
5335 }
5336
5337 /* We don't know how to load current power state; assume ON */
5338 mm_gdbus_modem_set_power_state (ctx->skeleton, MM_MODEM_POWER_STATE_ON);
5339 }
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01005340 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005341 /* fall-through */
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01005342
Aleksander Morgadoaf5c2422020-09-11 10:21:03 +02005343 case INITIALIZATION_STEP_SIM_HOT_SWAP: {
5344 gboolean sim_hot_swap_configured = FALSE;
5345
5346 g_object_get (self,
5347 MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, &sim_hot_swap_configured,
5348 NULL);
5349 if (!sim_hot_swap_configured &&
5350 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap &&
Ben Chan66f10d62017-06-30 02:23:38 -07005351 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish) {
5352 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap (
5353 MM_IFACE_MODEM (self),
Carlo Lobrano60f4f9e2016-08-08 15:47:18 +02005354 (GAsyncReadyCallback) setup_sim_hot_swap_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005355 task);
Carlo Lobrano60f4f9e2016-08-08 15:47:18 +02005356 return;
5357 }
Carlo Lobrano60f4f9e2016-08-08 15:47:18 +02005358 ctx->step++;
Aleksander Morgadoaf5c2422020-09-11 10:21:03 +02005359 } /* fall-through */
Carlo Lobrano60f4f9e2016-08-08 15:47:18 +02005360
Aleksander Morgadoe7409b62020-08-01 09:59:27 +02005361 case INITIALIZATION_STEP_SIM_SLOTS:
5362 /* If the modem doesn't need any SIM (not implemented by plugin, or not
5363 * needed in CDMA-only modems), or if we don't know how to query
5364 * for SIM slots */
5365 if (!mm_gdbus_modem_get_sim_slots (ctx->skeleton) &&
5366 !mm_iface_modem_is_cdma_only (self) &&
5367 MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots &&
5368 MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots_finish) {
5369 MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots (MM_IFACE_MODEM (self),
5370 (GAsyncReadyCallback)load_sim_slots_ready,
5371 task);
5372 return;
5373 }
5374 ctx->step++;
5375 /* fall-through */
5376
Ben Chanc204a8c2013-01-24 00:43:08 -08005377 case INITIALIZATION_STEP_UNLOCK_REQUIRED:
5378 /* Only check unlock required if we were previously not unlocked */
5379 if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE) {
Ben Chan66f10d62017-06-30 02:23:38 -07005380 mm_iface_modem_update_lock_info (self,
Ben Chanc204a8c2013-01-24 00:43:08 -08005381 MM_MODEM_LOCK_UNKNOWN, /* ask */
5382 (GAsyncReadyCallback)modem_update_lock_info_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005383 task);
Ben Chanc204a8c2013-01-24 00:43:08 -08005384 return;
5385 }
Ben Chanc204a8c2013-01-24 00:43:08 -08005386 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005387 /* fall-through */
Ben Chanc204a8c2013-01-24 00:43:08 -08005388
5389 case INITIALIZATION_STEP_SIM:
Aleksander Morgadob377a622013-03-26 16:40:54 +01005390 /* If the modem doesn't need any SIM (not implemented by plugin, or not
5391 * needed in CDMA-only modems) */
Ben Chan66f10d62017-06-30 02:23:38 -07005392 if (!mm_iface_modem_is_cdma_only (self) &&
5393 MM_IFACE_MODEM_GET_INTERFACE (self)->create_sim &&
5394 MM_IFACE_MODEM_GET_INTERFACE (self)->create_sim_finish) {
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02005395 MMBaseSim *sim = NULL;
Ben Chanc204a8c2013-01-24 00:43:08 -08005396
Ben Chan66f10d62017-06-30 02:23:38 -07005397 g_object_get (self,
Ben Chanc204a8c2013-01-24 00:43:08 -08005398 MM_IFACE_MODEM_SIM, &sim,
5399 NULL);
5400 if (!sim) {
Ben Chan66f10d62017-06-30 02:23:38 -07005401 MM_IFACE_MODEM_GET_INTERFACE (self)->create_sim (
5402 MM_IFACE_MODEM (self),
Ben Chanc204a8c2013-01-24 00:43:08 -08005403 (GAsyncReadyCallback)sim_new_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005404 task);
Ben Chanc204a8c2013-01-24 00:43:08 -08005405 return;
5406 }
5407
5408 /* If already available the sim object, relaunch initialization.
5409 * This will try to load any missing property value that couldn't be
5410 * retrieved before due to having the SIM locked. */
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02005411 mm_base_sim_initialize (sim,
Ben Chan66f10d62017-06-30 02:23:38 -07005412 g_task_get_cancellable (task),
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02005413 (GAsyncReadyCallback)sim_reinit_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005414 task);
Ben Chanc204a8c2013-01-24 00:43:08 -08005415 g_object_unref (sim);
5416 return;
5417 }
Ben Chan24b28d12013-01-30 12:32:25 -08005418 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005419 /* fall-through */
Ben Chanc204a8c2013-01-24 00:43:08 -08005420
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005421 case INITIALIZATION_STEP_SETUP_CARRIER_CONFIG:
5422 /* Setup and perform automatic carrier config switching as soon as the
5423 * SIM initialization has been performed, only applicable if there is
5424 * actually a SIM found with a valid IMSI read */
5425 if (!mm_iface_modem_is_cdma_only (self) &&
5426 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_carrier_config &&
5427 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_carrier_config_finish) {
5428 MMBaseSim *sim = NULL;
5429 gchar *carrier_config_mapping = NULL;
5430
5431 g_object_get (self,
5432 MM_IFACE_MODEM_SIM, &sim,
5433 MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING, &carrier_config_mapping,
5434 NULL);
5435
5436 /* If we have a SIM object, and carrier config switching is supported,
5437 * validate whether we're already using the best config or not. */
5438 if (!sim)
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01005439 mm_obj_dbg (self, "not setting up carrier config: SIM not found");
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005440 else if (!carrier_config_mapping)
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01005441 mm_obj_dbg (self, "not setting up carrier config: mapping file not configured");
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005442 else {
5443 const gchar *imsi;
5444
5445 imsi = mm_gdbus_sim_get_imsi (MM_GDBUS_SIM (sim));
5446 if (imsi) {
5447 MM_IFACE_MODEM_GET_INTERFACE (self)->setup_carrier_config (self,
5448 imsi,
5449 carrier_config_mapping,
5450 (GAsyncReadyCallback)setup_carrier_config_ready,
5451 task);
5452 g_object_unref (sim);
5453 g_free (carrier_config_mapping);
5454 return;
5455 }
Aleksander Morgadoaa5a77c2020-03-28 18:46:42 +01005456 mm_obj_warn (self, "couldn't setup carrier config: unknown IMSI");
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005457 }
5458 g_clear_object (&sim);
5459 g_free (carrier_config_mapping);
5460 }
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005461 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005462 /* fall-through */
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01005463
Ben Chanc204a8c2013-01-24 00:43:08 -08005464 case INITIALIZATION_STEP_OWN_NUMBERS:
5465 /* Own numbers is meant to be loaded only once during the whole
5466 * lifetime of the modem. Therefore, if we already have them loaded,
5467 * don't try to load them again. */
5468 if (mm_gdbus_modem_get_own_numbers (ctx->skeleton) == NULL &&
Ben Chan66f10d62017-06-30 02:23:38 -07005469 MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers &&
5470 MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers_finish) {
5471 MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers (
5472 self,
Ben Chanc204a8c2013-01-24 00:43:08 -08005473 (GAsyncReadyCallback)load_own_numbers_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005474 task);
Ben Chanc204a8c2013-01-24 00:43:08 -08005475 return;
5476 }
Ben Chanc204a8c2013-01-24 00:43:08 -08005477 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005478 /* fall-through */
Ben Chanc204a8c2013-01-24 00:43:08 -08005479
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005480 case INITIALIZATION_STEP_CURRENT_MODES: {
5481 MMModemMode allowed = MM_MODEM_MODE_ANY;
5482 MMModemMode preferred = MM_MODEM_MODE_NONE;
5483 GVariant *aux;
5484
5485 aux = mm_gdbus_modem_get_current_modes (ctx->skeleton);
5486 if (aux)
5487 g_variant_get (aux, "(uu)", &allowed, &preferred);
5488
5489 /* Current modes are only meant to be loaded once, so if we have them
5490 * loaded already, just skip re-loading */
5491 if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) {
5492 GArray *supported;
5493
5494 supported = (mm_common_mode_combinations_variant_to_garray (
5495 mm_gdbus_modem_get_supported_modes (ctx->skeleton)));
5496
5497 /* If there is only one item in the list of supported modes, we're done */
5498 if (supported && supported->len == 1) {
5499 MMModemModeCombination *supported_mode;
5500
5501 supported_mode = &g_array_index (supported, MMModemModeCombination, 0);
5502 mm_gdbus_modem_set_current_modes (ctx->skeleton, g_variant_new ("(uu)", supported_mode->allowed, supported_mode->preferred));
Ben Chan66f10d62017-06-30 02:23:38 -07005503 } else if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes &&
5504 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes_finish) {
5505 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_modes (
5506 self,
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005507 (GAsyncReadyCallback)load_current_modes_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005508 task);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005509 if (supported)
5510 g_array_unref (supported);
5511 return;
5512 }
5513
5514 if (supported)
5515 g_array_unref (supported);
5516 }
5517
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005518 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005519 } /* fall-through */
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005520
5521 case INITIALIZATION_STEP_CURRENT_BANDS: {
5522 GArray *current;
5523
5524 current = (mm_common_bands_variant_to_garray (
5525 mm_gdbus_modem_get_current_bands (ctx->skeleton)));
5526
5527 /* Current bands are only meant to be loaded once, so if we have them
5528 * loaded already, just skip re-loading */
5529 if (!current || (current->len == 1 && g_array_index (current, MMModemBand, 0) == MM_MODEM_BAND_UNKNOWN)) {
Ben Chan66f10d62017-06-30 02:23:38 -07005530 if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands &&
5531 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands_finish) {
5532 MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands (
5533 self,
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005534 (GAsyncReadyCallback)load_current_bands_ready,
Ben Chan66f10d62017-06-30 02:23:38 -07005535 task);
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005536 if (current)
5537 g_array_unref (current);
5538 return;
5539 }
5540
5541 /* If no way to get current bands, default to what supported has */
5542 mm_gdbus_modem_set_current_bands (ctx->skeleton, mm_gdbus_modem_get_supported_bands (ctx->skeleton));
5543 }
5544
5545 if (current)
5546 g_array_unref (current);
5547
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005548 ctx->step++;
Aleksander Morgado394df972019-11-28 22:48:31 +01005549 } /* fall-through */
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005550
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005551 case INITIALIZATION_STEP_LAST:
Aleksander Morgadocae73772018-12-06 14:54:19 +01005552 /* Setup all method handlers */
5553 g_object_connect (ctx->skeleton,
5554 "signal::handle-set-current-capabilities", G_CALLBACK (handle_set_current_capabilities), self,
5555 "signal::handle-set-power-state", G_CALLBACK (handle_set_power_state), self,
5556 "signal::handle-reset", G_CALLBACK (handle_reset), self,
5557 "signal::handle-factory-reset", G_CALLBACK (handle_factory_reset), self,
5558 "signal::handle-create-bearer", G_CALLBACK (handle_create_bearer), self,
5559 "signal::handle-command", G_CALLBACK (handle_command), self,
5560 "signal::handle-delete-bearer", G_CALLBACK (handle_delete_bearer), self,
5561 "signal::handle-list-bearers", G_CALLBACK (handle_list_bearers), self,
5562 "signal::handle-enable", G_CALLBACK (handle_enable), self,
5563 "signal::handle-set-current-bands", G_CALLBACK (handle_set_current_bands), self,
5564 "signal::handle-set-current-modes", G_CALLBACK (handle_set_current_modes), self,
Aleksander Morgado924cf1a2020-08-01 09:59:37 +02005565 "signal::handle-set-primary-sim-slot", G_CALLBACK (handle_set_primary_sim_slot), self,
Aleksander Morgadocae73772018-12-06 14:54:19 +01005566 NULL);
Aleksander Morgado78d788d2011-11-28 13:04:59 +01005567
Aleksander Morgadoe2d20972012-10-25 16:18:16 +02005568 /* Finally, export the new interface, even if we got errors, but only if not
5569 * done already */
Ben Chan66f10d62017-06-30 02:23:38 -07005570 if (!mm_gdbus_object_peek_modem (MM_GDBUS_OBJECT (self)))
5571 mm_gdbus_object_skeleton_set_modem (MM_GDBUS_OBJECT_SKELETON (self),
Aleksander Morgadoe2d20972012-10-25 16:18:16 +02005572 MM_GDBUS_MODEM (ctx->skeleton));
Ben Chan66f10d62017-06-30 02:23:38 -07005573
5574 if (ctx->fatal_error) {
5575 g_task_return_error (task, ctx->fatal_error);
5576 ctx->fatal_error = NULL;
5577 } else
5578 g_task_return_boolean (task, TRUE);
5579
5580 g_object_unref (task);
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005581 return;
Aleksander Morgadoeb04ead2019-11-28 22:46:04 +01005582
5583 default:
5584 break;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005585 }
5586
Aleksander Morgadofc195092011-11-25 14:53:35 +01005587 g_assert_not_reached ();
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005588}
5589
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005590gboolean
5591mm_iface_modem_initialize_finish (MMIfaceModem *self,
5592 GAsyncResult *res,
5593 GError **error)
5594{
Ben Chan99dd0372017-07-12 01:14:54 -07005595 return g_task_propagate_boolean (G_TASK (res), error);
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005596}
5597
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005598void
5599mm_iface_modem_initialize (MMIfaceModem *self,
Aleksander Morgadoe140ff32012-03-13 11:52:20 +01005600 GCancellable *cancellable,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005601 GAsyncReadyCallback callback,
5602 gpointer user_data)
5603{
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02005604 InitializationContext *ctx;
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005605 MmGdbusModem *skeleton = NULL;
Ben Chan66f10d62017-06-30 02:23:38 -07005606 GTask *task;
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005607
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005608 /* Did we already create it? */
5609 g_object_get (self,
5610 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005611 NULL);
5612 if (!skeleton) {
5613 skeleton = mm_gdbus_modem_skeleton_new ();
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005614
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005615 /* Set all initial property defaults */
5616 mm_gdbus_modem_set_sim (skeleton, NULL);
Aleksander Morgado700ebc52013-05-24 12:35:44 +02005617 mm_gdbus_modem_set_supported_capabilities (skeleton, mm_common_build_capability_combinations_none ());
Aleksander Morgadob49ddfe2012-04-10 17:17:42 +02005618 mm_gdbus_modem_set_current_capabilities (skeleton, MM_MODEM_CAPABILITY_NONE);
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005619 mm_gdbus_modem_set_max_bearers (skeleton, 0);
5620 mm_gdbus_modem_set_max_active_bearers (skeleton, 0);
5621 mm_gdbus_modem_set_manufacturer (skeleton, NULL);
5622 mm_gdbus_modem_set_model (skeleton, NULL);
5623 mm_gdbus_modem_set_revision (skeleton, NULL);
Aleksander Morgado2dcff552012-03-06 11:45:02 +01005624 mm_gdbus_modem_set_own_numbers (skeleton, NULL);
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005625 mm_gdbus_modem_set_device_identifier (skeleton, NULL);
5626 mm_gdbus_modem_set_device (skeleton, NULL);
Aleksander Morgado0436b3e2012-08-24 13:28:22 +02005627 mm_gdbus_modem_set_drivers (skeleton, NULL);
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005628 mm_gdbus_modem_set_plugin (skeleton, NULL);
5629 mm_gdbus_modem_set_equipment_identifier (skeleton, NULL);
5630 mm_gdbus_modem_set_unlock_required (skeleton, MM_MODEM_LOCK_UNKNOWN);
5631 mm_gdbus_modem_set_unlock_retries (skeleton, 0);
Aleksander Morgado516b0972011-12-20 18:43:43 +01005632 mm_gdbus_modem_set_access_technologies (skeleton, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005633 mm_gdbus_modem_set_signal_quality (skeleton, g_variant_new ("(ub)", 0, FALSE));
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005634 mm_gdbus_modem_set_supported_modes (skeleton, mm_common_build_mode_combinations_default ());
Aleksander Morgadof09eff62013-05-31 09:14:18 +02005635 mm_gdbus_modem_set_current_modes (skeleton, g_variant_new ("(uu)", MM_MODEM_MODE_ANY, MM_MODEM_MODE_NONE));
Aleksander Morgado0c009a22011-12-28 14:00:15 +01005636 mm_gdbus_modem_set_supported_bands (skeleton, mm_common_build_bands_unknown ());
Aleksander Morgado212d00c2013-05-29 10:47:53 +02005637 mm_gdbus_modem_set_current_bands (skeleton, mm_common_build_bands_unknown ());
Aleksander Morgadob3222202013-05-23 10:39:13 +02005638 mm_gdbus_modem_set_supported_ip_families (skeleton, MM_BEARER_IP_FAMILY_NONE);
Aleksander Morgadoe55b5432012-12-31 16:25:06 +01005639 mm_gdbus_modem_set_power_state (skeleton, MM_MODEM_POWER_STATE_UNKNOWN);
Aleksander Morgado75d20c12013-02-22 08:58:36 +01005640 mm_gdbus_modem_set_state_failed_reason (skeleton, MM_MODEM_STATE_FAILED_REASON_NONE);
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005641
5642 /* Bind our State property */
5643 g_object_bind_property (self, MM_IFACE_MODEM_STATE,
5644 skeleton, "state",
Aleksander Morgado8725fe52011-12-02 12:00:57 +01005645 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005646
5647 g_object_set (self,
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005648 MM_IFACE_MODEM_DBUS_SKELETON, skeleton,
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005649 NULL);
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005650 }
5651
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005652 /* Perform async initialization here */
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02005653 ctx = g_new0 (InitializationContext, 1);
Aleksander Morgadoc16bcdf2012-10-11 11:41:15 +02005654 ctx->step = INITIALIZATION_STEP_FIRST;
5655 ctx->skeleton = skeleton;
5656
Ben Chan66f10d62017-06-30 02:23:38 -07005657 task = g_task_new (self, NULL, callback, user_data);
5658 g_task_set_task_data (task, ctx, (GDestroyNotify)initialization_context_free);
5659
5660 interface_initialization_step (task);
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005661}
5662
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005663void
5664mm_iface_modem_shutdown (MMIfaceModem *self)
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005665{
Aleksander Morgado8ad868c2017-05-30 20:09:55 +02005666 /* Make sure signal polling is disabled. No real need to clear values, as
5667 * we're shutting down the interface anyway. */
5668 periodic_signal_check_disable (self, FALSE);
Ben Chan9ddcf922012-07-12 14:12:52 -07005669
5670 /* Remove SignalQualityUpdateContext object to make sure any pending
5671 * invocation of expire_signal_quality is canceled before the DBus skeleton
5672 * is removed. */
5673 if (G_LIKELY (signal_quality_update_context_quark))
5674 g_object_set_qdata (G_OBJECT (self),
5675 signal_quality_update_context_quark,
5676 NULL);
5677
Aleksander Morgado1cb58312013-04-05 08:54:09 +02005678 /* Remove running restart initialization idle, if any */
5679 if (G_LIKELY (restart_initialize_idle_quark))
5680 g_object_set_qdata (G_OBJECT (self),
5681 restart_initialize_idle_quark,
5682 NULL);
5683
Aleksander Morgadob9448b82011-11-28 12:21:48 +01005684 /* Remove SIM object */
5685 g_object_set (self,
5686 MM_IFACE_MODEM_SIM, NULL,
5687 NULL);
5688 /* Unexport DBus interface and remove the skeleton */
5689 mm_gdbus_object_skeleton_set_modem (MM_GDBUS_OBJECT_SKELETON (self), NULL);
5690 g_object_set (self,
5691 MM_IFACE_MODEM_DBUS_SKELETON, NULL,
5692 NULL);
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005693}
5694
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01005695/*****************************************************************************/
5696
Ben Chane9392212013-01-03 18:50:40 -08005697MMModemAccessTechnology
5698mm_iface_modem_get_access_technologies (MMIfaceModem *self)
5699{
5700 MMModemAccessTechnology access_tech = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
5701 MmGdbusModem *skeleton;
5702
5703 g_object_get (self,
5704 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
5705 NULL);
5706
5707 if (skeleton) {
5708 access_tech = mm_gdbus_modem_get_access_technologies (skeleton);
5709 g_object_unref (skeleton);
5710 }
5711
5712 return access_tech;
5713}
5714
5715/*****************************************************************************/
5716
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005717static gboolean
5718find_supported_mode (MMIfaceModem *self,
5719 MMModemMode mode,
5720 gboolean *only)
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005721{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005722 gboolean matched = FALSE;
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005723 MmGdbusModem *skeleton;
5724
5725 g_object_get (self,
5726 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
5727 NULL);
5728
5729 if (skeleton) {
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005730 GArray *supported;
5731 guint i;
5732 guint n_unmatched = 0;
5733
5734 supported = mm_common_mode_combinations_variant_to_garray (
5735 mm_gdbus_modem_get_supported_modes (skeleton));
5736
5737 /* Check if the given mode is supported */
5738 for (i = 0; i < supported->len; i++) {
5739 MMModemModeCombination *supported_mode;
5740
5741 supported_mode = &g_array_index (supported, MMModemModeCombination, i);
5742 if (supported_mode->allowed & mode) {
5743 matched = TRUE;
5744 if (supported_mode->allowed != mode)
5745 n_unmatched++;
5746 } else
5747 n_unmatched++;
5748
5749 if (matched && (only == NULL || n_unmatched > 0))
5750 break;
5751 }
5752
5753 if (only)
5754 *only = (n_unmatched == 0);
5755
5756 g_array_unref (supported);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005757 g_object_unref (skeleton);
5758 }
5759
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005760 return matched;
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005761}
5762
5763gboolean
5764mm_iface_modem_is_2g (MMIfaceModem *self)
5765{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005766 return find_supported_mode (self, MM_MODEM_MODE_2G, NULL);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005767}
5768
5769gboolean
5770mm_iface_modem_is_2g_only (MMIfaceModem *self)
5771{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005772 gboolean only;
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005773
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005774 return (find_supported_mode (self, MM_MODEM_MODE_2G, &only) ?
5775 only :
5776 FALSE);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005777}
5778
5779gboolean
5780mm_iface_modem_is_3g (MMIfaceModem *self)
5781{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005782 return find_supported_mode (self, MM_MODEM_MODE_3G, NULL);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005783}
5784
5785gboolean
5786mm_iface_modem_is_3g_only (MMIfaceModem *self)
5787{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005788 gboolean only;
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005789
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005790 return (find_supported_mode (self, MM_MODEM_MODE_3G, &only) ?
5791 only :
5792 FALSE);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005793}
5794
5795gboolean
5796mm_iface_modem_is_4g (MMIfaceModem *self)
5797{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005798 return find_supported_mode (self, MM_MODEM_MODE_4G, NULL);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005799}
5800
5801gboolean
5802mm_iface_modem_is_4g_only (MMIfaceModem *self)
5803{
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005804 gboolean only;
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005805
Aleksander Morgado45ceba72013-05-29 12:41:49 +02005806 return (find_supported_mode (self, MM_MODEM_MODE_4G, &only) ?
5807 only :
5808 FALSE);
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005809}
5810
Aleksander Morgado5db3fa82020-03-23 07:19:56 +01005811gboolean
5812mm_iface_modem_is_5g (MMIfaceModem *self)
5813{
5814 return find_supported_mode (self, MM_MODEM_MODE_5G, NULL);
5815}
5816
5817gboolean
5818mm_iface_modem_is_5g_only (MMIfaceModem *self)
5819{
5820 gboolean only;
5821
5822 return (find_supported_mode (self, MM_MODEM_MODE_5G, &only) ?
5823 only :
5824 FALSE);
5825}
5826
Aleksander Morgado83afd3d2012-04-10 17:25:34 +02005827/*****************************************************************************/
5828
Aleksander Morgadob49ddfe2012-04-10 17:17:42 +02005829MMModemCapability
5830mm_iface_modem_get_current_capabilities (MMIfaceModem *self)
5831{
5832 MMModemCapability current = MM_MODEM_CAPABILITY_NONE;
5833 MmGdbusModem *skeleton;
5834
5835 g_object_get (self,
5836 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
5837 NULL);
5838
5839 if (skeleton) {
5840 current = mm_gdbus_modem_get_current_capabilities (skeleton);
5841 g_object_unref (skeleton);
5842 }
5843
5844 return current;
5845}
5846
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01005847gboolean
5848mm_iface_modem_is_3gpp (MMIfaceModem *self)
5849{
Aleksander Morgadob49ddfe2012-04-10 17:17:42 +02005850 return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_3GPP);
Aleksander Morgadoc9c94212011-12-22 20:41:11 +01005851}
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005852
Aleksander Morgado0f771682011-12-31 11:12:19 +01005853gboolean
Aleksander Morgadoffae95a2012-01-03 17:06:45 +01005854mm_iface_modem_is_3gpp_lte (MMIfaceModem *self)
5855{
Aleksander Morgado0cd76bf2020-03-23 06:34:53 +01005856 return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_LTE);
Aleksander Morgadoffae95a2012-01-03 17:06:45 +01005857}
5858
5859gboolean
Aleksander Morgado569990f2020-06-12 09:25:09 +02005860mm_iface_modem_is_3gpp_5gnr (MMIfaceModem *self)
5861{
5862 return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_5GNR);
5863}
5864
5865gboolean
Aleksander Morgado0f771682011-12-31 11:12:19 +01005866mm_iface_modem_is_cdma (MMIfaceModem *self)
5867{
Aleksander Morgadob49ddfe2012-04-10 17:17:42 +02005868 return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_CDMA_EVDO);
Aleksander Morgado0f771682011-12-31 11:12:19 +01005869}
5870
5871gboolean
Aleksander Morgado0f771682011-12-31 11:12:19 +01005872mm_iface_modem_is_3gpp_only (MMIfaceModem *self)
5873{
Aleksander Morgadob49ddfe2012-04-10 17:17:42 +02005874 MMModemCapability capabilities;
Aleksander Morgado0f771682011-12-31 11:12:19 +01005875
Aleksander Morgadob49ddfe2012-04-10 17:17:42 +02005876 capabilities = mm_iface_modem_get_current_capabilities (self);
Aleksander Morgadof1372682016-07-20 07:51:54 +02005877 return (capabilities & MM_MODEM_CAPABILITY_3GPP) && !((MM_MODEM_CAPABILITY_3GPP ^ capabilities) & capabilities);
Aleksander Morgado0f771682011-12-31 11:12:19 +01005878}
5879
Aleksander Morgadoffae95a2012-01-03 17:06:45 +01005880gboolean
Aleksander Morgadoffae95a2012-01-03 17:06:45 +01005881mm_iface_modem_is_cdma_only (MMIfaceModem *self)
5882{
Aleksander Morgado78266ac2020-03-23 07:02:57 +01005883 return (mm_iface_modem_get_current_capabilities (self) == MM_MODEM_CAPABILITY_CDMA_EVDO);
Aleksander Morgadoffae95a2012-01-03 17:06:45 +01005884}
5885
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005886/*****************************************************************************/
5887
Ben Chanf515cd12013-08-14 00:01:28 -07005888const gchar *
5889mm_iface_modem_get_model (MMIfaceModem *self)
5890{
5891 const gchar *model = NULL;
5892 MmGdbusModem *skeleton;
5893
5894 g_object_get (self,
5895 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
5896 NULL);
5897
5898 if (skeleton) {
5899 model = mm_gdbus_modem_get_model (skeleton);
5900 g_object_unref (skeleton);
5901 }
5902
5903 return model;
5904}
5905
Aleksander Morgadof35d64a2018-12-18 15:50:53 +01005906const gchar *
5907mm_iface_modem_get_revision (MMIfaceModem *self)
5908{
5909 const gchar *revision = NULL;
5910 MmGdbusModem *skeleton;
5911
5912 g_object_get (self,
5913 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
5914 NULL);
5915
5916 if (skeleton) {
5917 revision = mm_gdbus_modem_get_revision (skeleton);
5918 g_object_unref (skeleton);
5919 }
5920
5921 return revision;
5922}
5923
Aleksander Morgado52b67dc2018-12-18 16:57:07 +01005924gboolean
5925mm_iface_modem_get_carrier_config (MMIfaceModem *self,
5926 const gchar **name,
5927 const gchar **revision)
Aleksander Morgadoc479d032018-12-18 16:22:52 +01005928{
Aleksander Morgadoc479d032018-12-18 16:22:52 +01005929 MmGdbusModem *skeleton;
5930
5931 g_object_get (self,
5932 MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
5933 NULL);
Aleksander Morgado52b67dc2018-12-18 16:57:07 +01005934 if (!skeleton)
5935 return FALSE;
Aleksander Morgadoc479d032018-12-18 16:22:52 +01005936
Aleksander Morgado52b67dc2018-12-18 16:57:07 +01005937 if (name)
5938 *name = mm_gdbus_modem_get_carrier_configuration (skeleton);
5939 if (revision)
5940 *revision = mm_gdbus_modem_get_carrier_configuration_revision (skeleton);
5941 g_object_unref (skeleton);
5942 return TRUE;
Aleksander Morgadoc479d032018-12-18 16:22:52 +01005943}
5944
Ben Chanf515cd12013-08-14 00:01:28 -07005945/*****************************************************************************/
5946
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01005947static void
5948iface_modem_init (gpointer g_iface)
5949{
5950 static gboolean initialized = FALSE;
5951
5952 if (initialized)
5953 return;
5954
5955 /* Properties */
5956 g_object_interface_install_property
5957 (g_iface,
5958 g_param_spec_object (MM_IFACE_MODEM_DBUS_SKELETON,
5959 "Modem DBus skeleton",
5960 "DBus skeleton for the Modem interface",
5961 MM_GDBUS_TYPE_MODEM_SKELETON,
5962 G_PARAM_READWRITE));
5963
Aleksander Morgadoca15a102011-11-22 18:01:09 +01005964 g_object_interface_install_property
5965 (g_iface,
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01005966 g_param_spec_object (MM_IFACE_MODEM_SIM,
5967 "SIM",
5968 "SIM object",
Aleksander Morgado5358d6f2014-07-06 16:50:30 +02005969 MM_TYPE_BASE_SIM,
Aleksander Morgado2a1465b2011-11-22 18:57:09 +01005970 G_PARAM_READWRITE));
5971
5972 g_object_interface_install_property
5973 (g_iface,
Aleksander Morgadoe7409b62020-08-01 09:59:27 +02005974 g_param_spec_boxed (MM_IFACE_MODEM_SIM_SLOTS,
5975 "SIM slots",
5976 "SIM objects in SIM slots",
5977 MM_TYPE_OBJECT_ARRAY,
5978 G_PARAM_READWRITE));
5979
5980 g_object_interface_install_property
5981 (g_iface,
Aleksander Morgadoca15a102011-11-22 18:01:09 +01005982 g_param_spec_enum (MM_IFACE_MODEM_STATE,
5983 "State",
5984 "State of the modem",
5985 MM_TYPE_MODEM_STATE,
5986 MM_MODEM_STATE_UNKNOWN,
5987 G_PARAM_READWRITE));
5988
Aleksander Morgado7b59a802011-11-25 14:36:26 +01005989 g_object_interface_install_property
5990 (g_iface,
Aleksander Morgado776cc662011-12-12 20:22:51 +01005991 g_param_spec_object (MM_IFACE_MODEM_BEARER_LIST,
5992 "Bearer list",
5993 "List of bearers handled by the modem",
5994 MM_TYPE_BEARER_LIST,
5995 G_PARAM_READWRITE));
Carlo Lobrano9cdc2372017-07-25 09:03:05 +02005996
Carlo Lobrano60f4f9e2016-08-08 15:47:18 +02005997 g_object_interface_install_property
5998 (g_iface,
5999 g_param_spec_boolean (MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED,
6000 "Sim Hot Swap Supported",
6001 "Whether the modem supports sim hot swap or not.",
6002 FALSE,
6003 G_PARAM_READWRITE));
Aleksander Morgado776cc662011-12-12 20:22:51 +01006004
Carlo Lobrano9cdc2372017-07-25 09:03:05 +02006005 g_object_interface_install_property
6006 (g_iface,
6007 g_param_spec_boolean (MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED,
6008 "Sim Hot Swap Configured",
6009 "Whether the sim hot swap support is configured correctly.",
6010 FALSE,
6011 G_PARAM_READWRITE));
Ben Chan708b00a2018-04-23 16:24:41 -07006012
6013 g_object_interface_install_property
6014 (g_iface,
6015 g_param_spec_boolean (MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED,
Aleksander Morgado1277ebb2019-09-17 11:59:34 +02006016 "Periodic signal quality check disabled",
6017 "Whether periodic signal quality check is disabled.",
6018 FALSE,
6019 G_PARAM_READWRITE));
6020
6021 g_object_interface_install_property
6022 (g_iface,
6023 g_param_spec_boolean (MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED,
6024 "Periodic access technology check disabled",
6025 "Whether periodic access technology check is disabled.",
Ben Chan708b00a2018-04-23 16:24:41 -07006026 FALSE,
Aleksander Morgado45a238b2019-09-17 12:46:41 +02006027 G_PARAM_READWRITE));
Ben Chan708b00a2018-04-23 16:24:41 -07006028
Aleksander Morgado94cf7f02018-12-18 14:52:44 +01006029 g_object_interface_install_property
6030 (g_iface,
6031 g_param_spec_string (MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING,
6032 "Carrier config mapping table",
6033 "Path to the file including the carrier mapping for the module",
6034 NULL,
6035 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
6036
Aleksander Morgado9e7cd2a2011-11-03 14:55:00 +01006037 initialized = TRUE;
6038}
6039
6040GType
6041mm_iface_modem_get_type (void)
6042{
6043 static GType iface_modem_type = 0;
6044
6045 if (!G_UNLIKELY (iface_modem_type)) {
6046 static const GTypeInfo info = {
6047 sizeof (MMIfaceModem), /* class_size */
6048 iface_modem_init, /* base_init */
6049 NULL, /* base_finalize */
6050 };
6051
6052 iface_modem_type = g_type_register_static (G_TYPE_INTERFACE,
6053 "MMIfaceModem",
6054 &info,
6055 0);
6056
6057 g_type_interface_add_prerequisite (iface_modem_type, MM_TYPE_BASE_MODEM);
6058 }
6059
6060 return iface_modem_type;
6061}