iface-modem: use external dispatcher to attempt FCC unlock

We remove the built-in FCC unlock procedures from the ModemManager, we
will no longer run them automatically, and instead rely on external
scripts/programs to do that.

Packages providing the external FCC unlock tools can install them in
${pkglibdir}/fcc-unlock.d.

Users manually enabling external FCC unlock tools can install them in
${pkgsysconfdir}/fcc-unlock.d.

The user-enabled path takes precedence over the package-enabled one.
This commit is contained in:
Aleksander Morgado
2021-10-25 21:39:46 +02:00
parent 21c775703c
commit 81302efa66
13 changed files with 439 additions and 139 deletions

View File

@@ -190,6 +190,10 @@ dnl-----------------------------------------------------------------------------
dnl System paths
dnl
dnl ModemManager configuration directory
pkgsysconfdir="${sysconfdir}/ModemManager"
AC_SUBST(pkgsysconfdir)
dnl DBus system directory
AC_ARG_WITH(dbus-sys-dir, AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is]))
if test -n "$with_dbus_sys_dir" ; then
@@ -618,6 +622,7 @@ echo "
System paths:
prefix: ${prefix}
configuration directory: ${pkgsysconfdir}
D-Bus system directory: ${DBUS_SYS_DIR}
udev base directory: ${UDEV_BASE_DIR}
systemd unit directory: ${with_systemdsystemunitdir}

View File

@@ -30,6 +30,7 @@ mm_sysconfdir = get_option('sysconfdir')
mm_pkgdatadir = mm_datadir / mm_name
mm_pkgincludedir = mm_includedir / mm_name
mm_pkglibdir = mm_libdir / mm_name
mm_pkgsysconfdir = mm_sysconfdir / mm_name
mm_glib_name = 'libmm-glib'
mm_glib_pkgincludedir = mm_includedir / mm_glib_name
@@ -400,6 +401,7 @@ summary({
summary({
'prefix': mm_prefix,
'configuration directory': mm_pkgsysconfdir,
'D-Bus policy directory': dbus_policy_dir,
'udev base directory': udev_udevdir,
'systemd user unit directory': systemd_systemdsystemunitdir,

View File

@@ -41,7 +41,6 @@
static void iface_modem_location_init (MMIfaceModemLocation *iface);
#if defined WITH_QMI
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
#endif
@@ -49,7 +48,6 @@ static MMIfaceModemLocation *iface_modem_location_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimFoxconn, mm_broadband_modem_mbim_foxconn, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
#if defined WITH_QMI
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init)
#endif
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init))
@@ -67,59 +65,6 @@ struct _MMBroadbandModemMbimFoxconnPrivate {
#if defined WITH_QMI
/*****************************************************************************/
/* FCC unlock (Modem interface) */
static gboolean
fcc_unlock_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
dms_foxconn_set_fcc_authentication_ready (QmiClientDms *client,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
g_autoptr(QmiMessageDmsFoxconnSetFccAuthenticationOutput) output = NULL;
output = qmi_client_dms_foxconn_set_fcc_authentication_finish (client, res, &error);
if (!output || !qmi_message_dms_foxconn_set_fcc_authentication_output_get_result (output, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
fcc_unlock (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
QmiClient *client = NULL;
g_autoptr(QmiMessageDmsFoxconnSetFccAuthenticationInput) input = NULL;
if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
QMI_SERVICE_DMS, &client,
callback, user_data))
return;
task = g_task_new (self, NULL, callback, user_data);
input = qmi_message_dms_foxconn_set_fcc_authentication_input_new ();
qmi_message_dms_foxconn_set_fcc_authentication_input_set_value (input, 0x00, NULL);
qmi_client_dms_foxconn_set_fcc_authentication (QMI_CLIENT_DMS (client),
input,
5,
NULL,
(GAsyncReadyCallback)dms_foxconn_set_fcc_authentication_ready,
task);
}
/*****************************************************************************/
/* Firmware update settings
*
@@ -554,13 +499,6 @@ iface_modem_location_init (MMIfaceModemLocation *iface)
#if defined WITH_QMI
static void
iface_modem_init (MMIfaceModem *iface)
{
iface->fcc_unlock = fcc_unlock;
iface->fcc_unlock_finish = fcc_unlock_finish;
}
static void
iface_modem_firmware_init (MMIfaceModemFirmware *iface)
{

View File

@@ -292,6 +292,8 @@ CLEANFILES += $(DAEMON_ENUMS_GENERATED)
ModemManager_CPPFLAGS = \
-DPLUGINDIR=\"$(pkglibdir)\" \
-DFCCUNLOCKDIRPACKAGE=\"${pkglibdir}/fcc-unlock.d\" \
-DFCCUNLOCKDIRUSER=\"${pkgsysconfdir}/fcc-unlock.d\" \
-DMM_COMPILATION \
$(NULL)
@@ -311,6 +313,8 @@ ModemManager_SOURCES = \
mm-private-boxed-types.c \
mm-auth-provider.h \
mm-auth-provider.c \
mm-fcc-unlock-dispatcher.h \
mm-fcc-unlock-dispatcher.c \
mm-filter.h \
mm-filter.c \
mm-base-manager.c \

View File

@@ -200,6 +200,7 @@ sources = files(
'mm-call-list.c',
'mm-context.c',
'mm-device.c',
'mm-fcc-unlock-dispatcher.c',
'mm-filter.c',
'mm-iface-modem-3gpp.c',
'mm-iface-modem-3gpp-profile-manager.c',
@@ -250,6 +251,8 @@ deps = [
c_args = [
'-DMM_COMPILATION',
'-DPLUGINDIR="@0@"'.format(mm_prefix / mm_pkglibdir),
'-DFCCUNLOCKDIRPACKAGE="@0@"'.format(mm_prefix / mm_pkglibdir / 'fcc-unlock.d'),
'-DFCCUNLOCKDIRUSER="@0@"'.format(mm_prefix / mm_pkgsysconfdir / 'fcc-unlock.d'),
]
if enable_qrtr

View File

@@ -7975,8 +7975,6 @@ iface_modem_init (MMIfaceModem *iface)
iface->load_current_bands_finish = mm_shared_qmi_load_current_bands_finish;
iface->set_current_bands = mm_shared_qmi_set_current_bands;
iface->set_current_bands_finish = mm_shared_qmi_set_current_bands_finish;
iface->fcc_unlock = mm_shared_qmi_fcc_unlock;
iface->fcc_unlock_finish = mm_shared_qmi_fcc_unlock_finish;
#endif
/* Additional actions */

View File

@@ -12381,8 +12381,6 @@ iface_modem_init (MMIfaceModem *iface)
/* Enabling/disabling */
iface->modem_power_up = modem_power_up;
iface->modem_power_up_finish = modem_power_up_down_off_finish;
iface->fcc_unlock = mm_shared_qmi_fcc_unlock;
iface->fcc_unlock_finish = mm_shared_qmi_fcc_unlock_finish;
iface->modem_after_power_up = NULL;
iface->modem_after_power_up_finish = NULL;
iface->modem_power_down = modem_power_down;

View File

@@ -0,0 +1,319 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
*/
#include <config.h>
#include <sys/stat.h>
#include <ModemManager.h>
#include "mm-errors-types.h"
#include "mm-utils.h"
#include "mm-log-object.h"
#include "mm-fcc-unlock-dispatcher.h"
#if !defined FCCUNLOCKDIRPACKAGE
# error FCCUNLOCKDIRPACKAGE must be defined at build time
#endif
#if !defined FCCUNLOCKDIRUSER
# error FCCUNLOCKDIRUSER must be defined at build time
#endif
/* Maximum time a FCC unlock command is allowed to run before
* us killing it */
#define MAX_FCC_UNLOCK_EXEC_TIME_SECS 5
struct _MMFccUnlockDispatcher {
GObject parent;
GSubprocessLauncher *launcher;
};
struct _MMFccUnlockDispatcherClass {
GObjectClass parent;
};
static void log_object_iface_init (MMLogObjectInterface *iface);
G_DEFINE_TYPE_EXTENDED (MMFccUnlockDispatcher, mm_fcc_unlock_dispatcher, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init))
/*****************************************************************************/
static gchar *
log_object_build_id (MMLogObject *_self)
{
return g_strdup ("fcc-unlock-dispatcher");
}
/*****************************************************************************/
typedef struct {
gchar *filename;
GSubprocess *subprocess;
guint timeout_id;
} RunContext;
static void
run_context_free (RunContext *ctx)
{
g_assert (!ctx->timeout_id);
g_clear_object (&ctx->subprocess);
g_free (ctx->filename);
g_slice_free (RunContext, ctx);
}
gboolean
mm_fcc_unlock_dispatcher_run_finish (MMFccUnlockDispatcher *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static gboolean
subprocess_wait_timed_out (GTask *task)
{
MMFccUnlockDispatcher *self;
RunContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
mm_obj_warn (self, "forcing exit on %s FCC unlock operation", ctx->filename);
g_subprocess_force_exit (ctx->subprocess);
ctx->timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
subprocess_wait_ready (GSubprocess *subprocess,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
RunContext *ctx;
/* cleanup timeout before any return */
ctx = g_task_get_task_data (task);
if (ctx->timeout_id) {
g_source_remove (ctx->timeout_id);
ctx->timeout_id = 0;
}
if (!g_subprocess_wait_finish (subprocess, res, &error)) {
g_prefix_error (&error, "FCC unlock operation wait failed: ");
g_task_return_error (task, error);
} else if (!g_subprocess_get_successful (subprocess)) {
if (g_subprocess_get_if_signaled (subprocess))
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"FCC unlock operation aborted with signal %d",
g_subprocess_get_term_sig (subprocess));
else if (g_subprocess_get_if_exited (subprocess))
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"FCC unlock operation finished with status %d",
g_subprocess_get_exit_status (subprocess));
else
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"FCC unlock operation failed");
} else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static gboolean
validate_file (const gchar *path,
GError **error)
{
g_autoptr(GFile) file = NULL;
g_autoptr(GFileInfo) file_info = NULL;
guint32 file_mode;
guint32 file_uid;
file = g_file_new_for_path (path);
file_info = g_file_query_info (file,
(G_FILE_ATTRIBUTE_STANDARD_SIZE ","
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
G_FILE_ATTRIBUTE_UNIX_MODE ","
G_FILE_ATTRIBUTE_UNIX_UID),
G_FILE_QUERY_INFO_NONE,
NULL,
error);
if (!file_info)
return FALSE;
if (g_file_info_get_is_symlink (file_info)) {
const gchar *link_target;
link_target = g_file_info_get_symlink_target (file_info);
if (g_strcmp0 (link_target, "/dev/null") == 0) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"Link '%s' to /dev/null is not executable", path);
return FALSE;
}
}
if (g_file_info_get_size (file_info) == 0) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"File '%s' is empty", path);
return FALSE;
}
file_uid = g_file_info_get_attribute_uint32 (file_info, G_FILE_ATTRIBUTE_UNIX_UID);
if (file_uid != 0) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"File '%s' not owned by root", path);
return FALSE;
}
file_mode = g_file_info_get_attribute_uint32 (file_info, G_FILE_ATTRIBUTE_UNIX_MODE);
if (!S_ISREG (file_mode)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"File '%s' is not regular", path);
return FALSE;
}
if (file_mode & (S_IWGRP | S_IWOTH)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"File '%s' is writable by group or other", path);
return FALSE;
}
if (file_mode & S_ISUID) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"File '%s' is set-UID", path);
return FALSE;
}
if (!(file_mode & S_IXUSR)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"File '%s' is not executable by the owner", path);
return FALSE;
}
return TRUE;
}
void
mm_fcc_unlock_dispatcher_run (MMFccUnlockDispatcher *self,
guint vid,
guint pid,
const gchar *modem_dbus_path,
const GStrv modem_ports,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
RunContext *ctx;
guint i;
const gchar *enabled_dirs[] = {
FCCUNLOCKDIRUSER, /* sysconfdir */
FCCUNLOCKDIRPACKAGE, /* libdir */
};
task = g_task_new (self, cancellable, callback, user_data);
ctx = g_slice_new0 (RunContext);
g_task_set_task_data (task, ctx, (GDestroyNotify) run_context_free);
ctx->filename = g_strdup_printf ("%04x:%04x", vid, pid);
for (i = 0; i < G_N_ELEMENTS (enabled_dirs); i++) {
GPtrArray *aux;
g_auto(GStrv) argv = NULL;
g_autofree gchar *path = NULL;
g_autoptr(GError) error = NULL;
guint j;
path = g_build_path (G_DIR_SEPARATOR_S, enabled_dirs[i], ctx->filename, NULL);
/* Validation checks to see if we should run it or not */
if (!validate_file (path, &error)) {
mm_obj_dbg (self, "Cannot run FCC unlock operation from %s: %s",
path, error->message);
continue;
}
/* build argv */
aux = g_ptr_array_new ();
g_ptr_array_add (aux, g_steal_pointer (&path));
g_ptr_array_add (aux, g_strdup (modem_dbus_path));
for (j = 0; modem_ports && modem_ports[j]; j++)
g_ptr_array_add (aux, g_strdup (modem_ports[j]));
g_ptr_array_add (aux, NULL);
argv = (GStrv) g_ptr_array_free (aux, FALSE);
/* create and launch subprocess */
ctx->subprocess = g_subprocess_launcher_spawnv (self->launcher,
(const gchar * const *)argv,
&error);
if (!ctx->subprocess) {
g_prefix_error (&error, "FCC unlock operation launch from %s failed: ", path);
g_task_return_error (task, error);
g_object_unref (task);
return;
}
/* setup timeout */
ctx->timeout_id = g_timeout_add_seconds (MAX_FCC_UNLOCK_EXEC_TIME_SECS,
(GSourceFunc)subprocess_wait_timed_out,
task);
/* wait for subprocess exit */
g_subprocess_wait_async (ctx->subprocess,
cancellable,
(GAsyncReadyCallback)subprocess_wait_ready,
task);
return;
}
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"FCC unlock operation launch aborted: no valid program found");
g_object_unref (task);
}
/*****************************************************************************/
static void
mm_fcc_unlock_dispatcher_init (MMFccUnlockDispatcher *self)
{
self->launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE);
/* inherit parent's environment */
g_subprocess_launcher_set_environ (self->launcher, NULL);
}
static void
dispose (GObject *object)
{
MMFccUnlockDispatcher *self = MM_FCC_UNLOCK_DISPATCHER (object);
g_clear_object (&self->launcher);
G_OBJECT_CLASS (mm_fcc_unlock_dispatcher_parent_class)->dispose (object);
}
static void
log_object_iface_init (MMLogObjectInterface *iface)
{
iface->build_id = log_object_build_id;
}
static void
mm_fcc_unlock_dispatcher_class_init (MMFccUnlockDispatcherClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = dispose;
}
MM_DEFINE_SINGLETON_GETTER (MMFccUnlockDispatcher, mm_fcc_unlock_dispatcher_get, MM_TYPE_FCC_UNLOCK_DISPATCHER)

View File

@@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
*/
#ifndef MM_FCC_UNLOCK_DISPATCHER_H
#define MM_FCC_UNLOCK_DISPATCHER_H
#include <config.h>
#include <gio/gio.h>
#define MM_TYPE_FCC_UNLOCK_DISPATCHER (mm_fcc_unlock_dispatcher_get_type ())
#define MM_FCC_UNLOCK_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_FCC_UNLOCK_DISPATCHER, MMFccUnlockDispatcher))
#define MM_FCC_UNLOCK_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_FCC_UNLOCK_DISPATCHER, MMFccUnlockDispatcherClass))
#define MM_IS_FCC_UNLOCK_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_FCC_UNLOCK_DISPATCHER))
#define MM_IS_FCC_UNLOCK_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_FCC_UNLOCK_DISPATCHER))
#define MM_FCC_UNLOCK_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_FCC_UNLOCK_DISPATCHER, MMFccUnlockDispatcherClass))
typedef struct _MMFccUnlockDispatcher MMFccUnlockDispatcher;
typedef struct _MMFccUnlockDispatcherClass MMFccUnlockDispatcherClass;
typedef struct _MMFccUnlockDispatcherPrivate MMFccUnlockDispatcherPrivate;
GType mm_fcc_unlock_dispatcher_get_type (void);
MMFccUnlockDispatcher *mm_fcc_unlock_dispatcher_get (void);
void mm_fcc_unlock_dispatcher_run (MMFccUnlockDispatcher *self,
guint vid,
guint pid,
const gchar *modem_dbus_path,
const GStrv ports,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_fcc_unlock_dispatcher_run_finish (MMFccUnlockDispatcher *self,
GAsyncResult *res,
GError **error);
#endif /* MM_FCC_UNLOCK_DISPATCHER_H */

View File

@@ -28,6 +28,7 @@
#include "mm-private-boxed-types.h"
#include "mm-log-object.h"
#include "mm-context.h"
#include "mm-fcc-unlock-dispatcher.h"
#if defined WITH_QMI
# include "mm-broadband-modem-qmi.h"
#endif
@@ -3844,15 +3845,18 @@ modem_after_power_up_ready (MMIfaceModem *self,
}
static void
fcc_unlock_ready (MMIfaceModem *self,
fcc_unlock_dispatcher_ready (MMFccUnlockDispatcher *dispatcher,
GAsyncResult *res,
GTask *task)
{
MMIfaceModem *self;
SetPowerStateContext *ctx;
g_autoptr(GError) error = NULL;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
if (!MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock_finish (self, res, &error))
if (!mm_fcc_unlock_dispatcher_run_finish (dispatcher, res, &error))
mm_obj_dbg (self, "couldn't run FCC unlock: %s", error->message);
/* always retry, even on reported error */
@@ -3860,6 +3864,54 @@ fcc_unlock_ready (MMIfaceModem *self,
set_power_state_step (task);
}
static void
fcc_unlock (GTask *task)
{
MMIfaceModem *self;
MMFccUnlockDispatcher *dispatcher;
MMModemPortInfo *port_infos;
guint n_port_infos = 0;
guint i;
GPtrArray *aux;
g_auto(GStrv) modem_ports = NULL;
self = g_task_get_source_object (task);
dispatcher = mm_fcc_unlock_dispatcher_get ();
aux = g_ptr_array_new ();
port_infos = mm_base_modem_get_port_infos (MM_BASE_MODEM (self), &n_port_infos);
for (i = 0; i < n_port_infos; i++) {
switch (port_infos[i].type) {
case MM_MODEM_PORT_TYPE_AT:
case MM_MODEM_PORT_TYPE_QMI:
case MM_MODEM_PORT_TYPE_MBIM:
g_ptr_array_add (aux, g_strdup (port_infos[i].name));
break;
case MM_MODEM_PORT_TYPE_UNKNOWN:
case MM_MODEM_PORT_TYPE_NET:
case MM_MODEM_PORT_TYPE_QCDM:
case MM_MODEM_PORT_TYPE_GPS:
case MM_MODEM_PORT_TYPE_AUDIO:
case MM_MODEM_PORT_TYPE_IGNORED:
default:
break;
}
}
mm_modem_port_info_array_free (port_infos, n_port_infos);
g_ptr_array_add (aux, NULL);
modem_ports = (GStrv) g_ptr_array_free (aux, FALSE);
mm_fcc_unlock_dispatcher_run (dispatcher,
mm_base_modem_get_vendor_id (MM_BASE_MODEM (self)),
mm_base_modem_get_product_id (MM_BASE_MODEM (self)),
g_dbus_object_get_object_path (G_DBUS_OBJECT (self)),
modem_ports,
g_task_get_cancellable (task),
(GAsyncReadyCallback)fcc_unlock_dispatcher_ready,
task);
}
static void
requested_power_setup_ready (MMIfaceModem *self,
GAsyncResult *res,
@@ -3959,13 +4011,11 @@ set_power_state_step (GTask *task)
if ((ctx->requested_power_state == MM_MODEM_POWER_STATE_ON) &&
ctx->saved_error &&
g_error_matches (ctx->saved_error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY) &&
!ctx->fcc_unlock_attempted &&
MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock &&
MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock_finish) {
!ctx->fcc_unlock_attempted) {
mm_obj_dbg (self, "attempting fcc unlock...");
ctx->fcc_unlock_attempted = TRUE;
g_clear_error (&ctx->saved_error);
MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock (self, (GAsyncReadyCallback)fcc_unlock_ready, task);
ctx->fcc_unlock_attempted = TRUE;
fcc_unlock (task);
return;
}
ctx->step++;

View File

@@ -270,14 +270,6 @@ struct _MMIfaceModem {
GAsyncResult *res,
GError **error);
/* Asynchronous FCC unlock operation */
void (* fcc_unlock) (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* fcc_unlock_finish) (MMIfaceModem *self,
GAsyncResult *res,
GError **error);
/* Asynchronous modem power-up operation */
void (*modem_power_up) (MMIfaceModem *self,
GAsyncReadyCallback callback,

View File

@@ -4220,56 +4220,6 @@ mm_shared_qmi_setup_sim_hot_swap (MMIfaceModem *self,
task);
}
/*****************************************************************************/
/* FCC unlock (Modem interface) */
gboolean
mm_shared_qmi_fcc_unlock_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
dms_set_fcc_authentication_ready (QmiClientDms *client,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
g_autoptr(QmiMessageDmsSetFccAuthenticationOutput) output = NULL;
output = qmi_client_dms_set_fcc_authentication_finish (client, res, &error);
if (!output || !qmi_message_dms_set_fcc_authentication_output_get_result (output, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
void
mm_shared_qmi_fcc_unlock (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
QmiClient *client = NULL;
if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
QMI_SERVICE_DMS, &client,
callback, user_data))
return;
task = g_task_new (self, NULL, callback, user_data);
qmi_client_dms_set_fcc_authentication (QMI_CLIENT_DMS (client),
NULL,
5,
NULL,
(GAsyncReadyCallback)dms_set_fcc_authentication_ready,
task);
}
/*****************************************************************************/
/* Location: Set SUPL server */

View File

@@ -191,12 +191,6 @@ void mm_shared_qmi_setup_sim_hot_swap (MMIfaceMode
gboolean mm_shared_qmi_setup_sim_hot_swap_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error);
void mm_shared_qmi_fcc_unlock (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_shared_qmi_fcc_unlock_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error);
/* Shared QMI location support */