wwan/ofono: create connections based on available contexts
Downstream patches for this does it through NMSettings plugin, however settings plugin are hard to maintain and complicated architecture wise as well. So directly create a connection profiles in-memory from the nm-modem-ofono side. Those profiles are created in /run, and are not added as a persistent connection, because connection state quite depends on the state of ofono This also allows us to drop the hack where we are keeping track of active context/APN through the connection name, i.e if connection name was in /imsi/context1 format, it was used. Instead now, Connection name is actual context name which is user friendly ("Vodafone Connect" e.g. in my case), and details like IMSI and context are stored internally. [ratchanan@ubports.com: - forward-ported to main branch. - fold "wwan/ofono: handle context removal" into this commit. - track the "preferred"-ness of the context and react accordingly. Creates proxies for all retrived contexts to listen to changes. While at it, also track name and type. - use, instead of ignore, internet APN. Also support internet+mms APN. - correct priv->contexts' value destroy function. - factor out UUID generation as a helper function. - handle the case where context dictionary is missing required keys. - simplify nm_ofono_connection_new's arguments and rename to add_or_update_connection. Makes it handle the case where the connection already exists. - also simplify other functions' arguments. - clean up code and comments. Fix memory problems. Get rid of warnings. ] Co-authored-by: Ratchanan Srirattanamet <ratchanan@ubports.com>
This commit is contained in:

committed by
Thomas Haller

parent
9e2ff9dabd
commit
9fc72bf75d
@@ -8,7 +8,10 @@
|
||||
#include "nm-modem-ofono.h"
|
||||
|
||||
#include "libnm-core-intern/nm-core-internal.h"
|
||||
#include "libnm-glib-aux/nm-uuid.h"
|
||||
#include "devices/nm-device-private.h"
|
||||
#include "nm-setting-gsm.h"
|
||||
#include "settings/nm-settings.h"
|
||||
#include "nm-modem.h"
|
||||
#include "libnm-platform/nm-platform.h"
|
||||
#include "nm-l3-config-data.h"
|
||||
@@ -26,28 +29,42 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
NMModemOfono *self;
|
||||
char *name;
|
||||
char *type;
|
||||
gboolean preferred;
|
||||
GDBusProxy *proxy;
|
||||
} OfonoContextData;
|
||||
|
||||
typedef struct {
|
||||
GHashTable *connect_properties;
|
||||
GHashTable *connections;
|
||||
GHashTable *contexts;
|
||||
|
||||
GDBusProxy *modem_proxy;
|
||||
GDBusProxy *connman_proxy;
|
||||
GDBusProxy *context_proxy;
|
||||
GDBusProxy *sim_proxy;
|
||||
|
||||
GCancellable *modem_proxy_cancellable;
|
||||
GCancellable *connman_proxy_cancellable;
|
||||
GCancellable *context_proxy_cancellable;
|
||||
GCancellable *connect_cancellable;
|
||||
GCancellable *sim_proxy_cancellable;
|
||||
|
||||
GError *property_error;
|
||||
|
||||
char *context_path;
|
||||
char *imsi;
|
||||
|
||||
gboolean modem_online;
|
||||
gboolean gprs_attached;
|
||||
|
||||
NML3ConfigData *l3cd_4;
|
||||
NMSettings *settings;
|
||||
|
||||
guint n_context_proxy_pending;
|
||||
|
||||
/* unowned; reference held by 'contexts' above. */
|
||||
OfonoContextData *current_octx;
|
||||
} NMModemOfonoPrivate;
|
||||
|
||||
struct _NMModemOfono {
|
||||
@@ -96,6 +113,21 @@ G_DEFINE_TYPE(NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Deterministic UUID is used to pair imsi+context with exported connection
|
||||
* (via a pair of hash tables).
|
||||
*/
|
||||
|
||||
static char *
|
||||
_generate_uuid(const char *imsi, const char *object_path)
|
||||
{
|
||||
return nm_uuid_generate_from_strings(
|
||||
NM_UUID_TYPE_VERSION5,
|
||||
&NM_UUID_INIT(b5, 6b, ad, f5, ef, 9d, 4a, 21, a8, e7, 7d, db, 69, bb, 6b, ee),
|
||||
imsi,
|
||||
object_path);
|
||||
}
|
||||
|
||||
static void
|
||||
get_capabilities(NMModem *_self,
|
||||
NMDeviceModemCapabilities *modem_caps,
|
||||
@@ -213,7 +245,8 @@ disconnect(NMModem *modem,
|
||||
ctx->callback = callback;
|
||||
ctx->callback_user_data = user_data;
|
||||
|
||||
if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)) {
|
||||
if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)
|
||||
|| priv->current_octx == NULL) {
|
||||
nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx);
|
||||
return;
|
||||
}
|
||||
@@ -222,7 +255,7 @@ disconnect(NMModem *modem,
|
||||
NM_MODEM_STATE_DISCONNECTING,
|
||||
nm_modem_state_to_string(NM_MODEM_STATE_DISCONNECTING));
|
||||
|
||||
g_dbus_proxy_call(priv->context_proxy,
|
||||
g_dbus_proxy_call(priv->current_octx->proxy,
|
||||
"SetProperty",
|
||||
g_variant_new("(sv)", "Active", g_variant_new("b", warn)),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
@@ -251,7 +284,7 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection,
|
||||
{
|
||||
NMModemOfono *self = NM_MODEM_OFONO(modem);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
const char *id;
|
||||
const char *uuid;
|
||||
|
||||
if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL)) {
|
||||
nm_utils_error_set(error,
|
||||
@@ -268,19 +301,12 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
id = nm_connection_get_id(connection);
|
||||
uuid = nm_connection_get_uuid(connection);
|
||||
|
||||
if (!strstr(id, "/context")) {
|
||||
if (!g_hash_table_contains(priv->contexts, uuid)) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||
"the connection ID has no context");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!strstr(id, priv->imsi)) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||
"the connection ID does not contain the IMSI");
|
||||
"connection ID does not match known contexts");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -500,8 +526,6 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user
|
||||
self = NM_MODEM_OFONO(user_data);
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
g_clear_object(&priv->connman_proxy_cancellable);
|
||||
|
||||
if (!v_properties) {
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGW("error getting connman properties: %s", error->message);
|
||||
@@ -525,6 +549,366 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ofono_context_data_free(OfonoContextData *octx)
|
||||
{
|
||||
g_free(octx->name);
|
||||
g_free(octx->type);
|
||||
|
||||
if (octx->proxy) {
|
||||
g_signal_handlers_disconnect_by_data(octx->proxy, octx);
|
||||
g_object_unref(octx->proxy);
|
||||
}
|
||||
|
||||
g_slice_free(OfonoContextData, octx);
|
||||
}
|
||||
|
||||
static void
|
||||
add_or_update_connection(NMModemOfono *self, const char *context_name, const char *uuid)
|
||||
{
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
NMSetting *setting;
|
||||
NMSettingsConnection *sett_conn;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
/*
|
||||
* See first if we have an existing connection (from previous or current
|
||||
* run of NM) that we can update in-place.
|
||||
*/
|
||||
|
||||
sett_conn = nm_settings_get_connection_by_uuid(priv->settings, uuid);
|
||||
if (sett_conn
|
||||
&& !NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn),
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) {
|
||||
/*
|
||||
* Either we have a coliding connection, or our connection has been
|
||||
* modified by user. For the latter case it's safe to leave it alone;
|
||||
* the UUID will still let it connect. However, for the first case,
|
||||
* we can't really do anything about it unless we re-write the way we
|
||||
* track connection <-> context, which I (Ratchanan) don't want to do
|
||||
* right now...
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
connection = nm_simple_connection_new();
|
||||
setting = nm_setting_connection_new();
|
||||
g_object_set(setting,
|
||||
NM_SETTING_CONNECTION_ID,
|
||||
context_name,
|
||||
NM_SETTING_CONNECTION_UUID,
|
||||
uuid,
|
||||
NM_SETTING_CONNECTION_AUTOCONNECT,
|
||||
TRUE,
|
||||
NM_SETTING_CONNECTION_TYPE,
|
||||
NM_SETTING_GSM_SETTING_NAME,
|
||||
NULL);
|
||||
nm_connection_add_setting(connection, setting);
|
||||
|
||||
setting = nm_setting_gsm_new();
|
||||
|
||||
/*
|
||||
* oFono should already know how to handle placing the call, but NM
|
||||
* insists on having a number. Pass the usual *99#.
|
||||
*/
|
||||
g_object_set(setting, NM_SETTING_GSM_NUMBER, "*99#", NULL);
|
||||
nm_connection_add_setting(connection, setting);
|
||||
|
||||
if (!nm_connection_normalize(connection, NULL, NULL, &error)) {
|
||||
nm_log_err(LOGD_MB,
|
||||
"ofono: could not not generate a connection for %s: %s",
|
||||
context_name,
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sett_conn) {
|
||||
nm_settings_add_connection(priv->settings,
|
||||
NULL, /* plugin */
|
||||
connection,
|
||||
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
|
||||
NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
|
||||
&sett_conn,
|
||||
&error);
|
||||
} else {
|
||||
nm_settings_update_connection(priv->settings,
|
||||
sett_conn,
|
||||
NULL, /* plugin_name */
|
||||
connection,
|
||||
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,
|
||||
NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE,
|
||||
/* log_context_name */ "ofono",
|
||||
&error);
|
||||
}
|
||||
|
||||
if (!sett_conn) {
|
||||
nm_log_warn(LOGD_MB,
|
||||
"ofono: could not add or update new connection for '%s' (%s): %s",
|
||||
context_name,
|
||||
uuid,
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
g_hash_table_insert(priv->connections, g_strdup(uuid), g_object_ref(sett_conn));
|
||||
}
|
||||
|
||||
/*
|
||||
* Used when we decide a connection is not needed. Rationale being that the
|
||||
* connection could have been modified by user since it's created by us,
|
||||
* after which we don't want to delete, but we don't want to track it either.
|
||||
*/
|
||||
|
||||
static void
|
||||
untrack_connection_and_delete_if_generated(NMModemOfono *self, char const *uuid)
|
||||
{
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
NMSettingsConnection *sett_conn;
|
||||
|
||||
sett_conn = g_hash_table_lookup(priv->connections, uuid);
|
||||
if (!sett_conn)
|
||||
return;
|
||||
|
||||
if (NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn),
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED))
|
||||
nm_settings_connection_delete(sett_conn, FALSE);
|
||||
|
||||
g_hash_table_remove(priv->connections, uuid);
|
||||
}
|
||||
|
||||
static void
|
||||
update_connection_list(NMModemOfono *self)
|
||||
{
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
GHashTableIter iter;
|
||||
char *uuid;
|
||||
OfonoContextData *octx;
|
||||
OfonoContextData *octx_preferred = NULL;
|
||||
|
||||
_LOGI("(re-)checking which context needs a connection");
|
||||
|
||||
g_hash_table_iter_init(&iter, priv->contexts);
|
||||
while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) {
|
||||
if (octx->preferred) {
|
||||
octx_preferred = octx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_iter_init(&iter, priv->contexts);
|
||||
while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) {
|
||||
gboolean connection_should_exist =
|
||||
(!octx_preferred || octx_preferred == octx)
|
||||
&& (nm_streq(octx->type, "internet") || nm_streq(octx->type, "internet+mms"));
|
||||
gboolean connection_exists = g_hash_table_contains(priv->connections, uuid);
|
||||
|
||||
if (connection_should_exist && !connection_exists) {
|
||||
_LOGI("creating connection for %s%s",
|
||||
octx_preferred ? "preferred context " : "",
|
||||
g_dbus_proxy_get_object_path(octx->proxy));
|
||||
add_or_update_connection(self, octx->name, uuid);
|
||||
} else if (!connection_should_exist && connection_exists) {
|
||||
_LOGI("removing connection for %s", g_dbus_proxy_get_object_path(octx->proxy));
|
||||
untrack_connection_and_delete_if_generated(self, uuid);
|
||||
|
||||
/* priv->current_octx is deliberately not cleared here because the
|
||||
* disconnection chain happens in another main loop iteration.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_settings(NMModemOfono *self, GVariant *v_dict);
|
||||
|
||||
static void
|
||||
context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data)
|
||||
{
|
||||
OfonoContextData *octx = user_data;
|
||||
NMModemOfono *self = octx->self;
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
gs_unref_variant GVariant *v_inner = g_variant_get_child_value(v, 0);
|
||||
|
||||
if (!v_inner) {
|
||||
_LOGW("ofono: (%s): error handling PropertyChanged signal",
|
||||
nm_modem_get_uid(NM_MODEM(self)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq(property, "Name")) {
|
||||
gs_free char *uuid = NULL;
|
||||
|
||||
g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING));
|
||||
g_free(octx->name);
|
||||
octx->name = g_variant_dup_string(v_inner, /* &length */ NULL);
|
||||
|
||||
uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy));
|
||||
if (g_hash_table_contains(priv->connections, uuid))
|
||||
add_or_update_connection(self, octx->name, uuid);
|
||||
} else if (nm_streq(property, "Type")) {
|
||||
g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING));
|
||||
g_free(octx->type);
|
||||
octx->type = g_variant_dup_string(v_inner, /* &length */ NULL);
|
||||
|
||||
update_connection_list(self);
|
||||
} else if (nm_streq(property, "Preferred")) {
|
||||
g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_BOOLEAN));
|
||||
octx->preferred = g_variant_get_boolean(v_inner);
|
||||
|
||||
update_connection_list(self);
|
||||
} else if (nm_streq(property, "Settings") && priv->current_octx == octx) {
|
||||
g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_VARDICT));
|
||||
handle_settings(self, v_inner);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
OfonoContextData *octx = user_data;
|
||||
NMModemOfono *self;
|
||||
NMModemOfonoPrivate *priv;
|
||||
gs_free_error GError *error = NULL;
|
||||
GDBusProxy *proxy;
|
||||
char *uuid;
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_finish(result, &error);
|
||||
if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
ofono_context_data_free(octx);
|
||||
return;
|
||||
}
|
||||
|
||||
self = octx->self;
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
if (!proxy) {
|
||||
_LOGW("failed to create ConnectionContext proxy: %s", error->message);
|
||||
ofono_context_data_free(octx);
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGD("recieved proxy for %s", g_dbus_proxy_get_object_path(proxy));
|
||||
octx->proxy = proxy;
|
||||
|
||||
_nm_dbus_signal_connect(proxy,
|
||||
"PropertyChanged",
|
||||
G_VARIANT_TYPE("(sv)"),
|
||||
G_CALLBACK(context_property_changed),
|
||||
octx);
|
||||
|
||||
uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy));
|
||||
g_hash_table_insert(priv->contexts, uuid, octx);
|
||||
priv->n_context_proxy_pending--;
|
||||
|
||||
if (priv->n_context_proxy_pending == 0)
|
||||
update_connection_list(self);
|
||||
}
|
||||
|
||||
static void
|
||||
connman_context_removed(GDBusProxy *proxy, const char *object_path, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self = NM_MODEM_OFONO(user_data);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
gs_free char *uuid = NULL;
|
||||
OfonoContextData *octx;
|
||||
|
||||
/* look up the connction, and if we have connection disconnect and remove it */
|
||||
uuid = _generate_uuid(priv->imsi, object_path);
|
||||
untrack_connection_and_delete_if_generated(self, uuid);
|
||||
|
||||
octx = g_hash_table_lookup(priv->contexts, uuid);
|
||||
if (octx) {
|
||||
gboolean preferred = octx->preferred;
|
||||
|
||||
if (octx == priv->current_octx)
|
||||
priv->current_octx = NULL;
|
||||
|
||||
g_hash_table_remove(priv->contexts, uuid);
|
||||
|
||||
if (preferred)
|
||||
update_connection_list(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
connman_context_added(GDBusProxy *proxy, const char *object_path, GVariant *v, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self = user_data;
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
OfonoContextData *octx;
|
||||
gs_unref_variant GVariant *v_context_type = NULL;
|
||||
gs_unref_variant GVariant *v_context_name = NULL;
|
||||
gs_unref_variant GVariant *v_context_preferred = NULL;
|
||||
|
||||
nm_log_info(LOGD_MB, "ofono: processing context %s", object_path);
|
||||
|
||||
v_context_name = g_variant_lookup_value(v, "Name", G_VARIANT_TYPE_STRING);
|
||||
v_context_type = g_variant_lookup_value(v, "Type", G_VARIANT_TYPE_STRING);
|
||||
if (!v_context_name || !v_context_type) {
|
||||
nm_log_err(LOGD_MB, "ofono: context dictionary is missing required key(s).");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Preferred property exists in some oFono fork only (mostly Ubuntu Touch's). */
|
||||
v_context_preferred = g_variant_lookup_value(v, "Preferred", G_VARIANT_TYPE_BOOLEAN);
|
||||
|
||||
octx = g_slice_new0(OfonoContextData);
|
||||
octx->self = self;
|
||||
octx->name = g_variant_dup_string(v_context_name, NULL);
|
||||
octx->type = g_variant_dup_string(v_context_type, NULL);
|
||||
octx->preferred = v_context_preferred && g_variant_get_boolean(v_context_preferred);
|
||||
|
||||
priv->n_context_proxy_pending++;
|
||||
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
||||
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL, /* GDBusInterfaceInfo */
|
||||
OFONO_DBUS_SERVICE,
|
||||
object_path,
|
||||
OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT,
|
||||
priv->connman_proxy_cancellable,
|
||||
_context_proxy_new_cb,
|
||||
octx);
|
||||
}
|
||||
|
||||
static void
|
||||
connman_get_contexts_done(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *v_contexts = NULL;
|
||||
gs_unref_variant GVariant *v_objects = NULL;
|
||||
gs_unref_variant GVariant *v = NULL;
|
||||
GVariantIter i;
|
||||
const char *object_path;
|
||||
|
||||
v_contexts = _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source),
|
||||
result,
|
||||
G_VARIANT_TYPE("(a(oa{sv}))"),
|
||||
&error);
|
||||
if (!v_contexts && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
self = user_data;
|
||||
|
||||
if (!v_contexts) {
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGW("Error getting list of contexts: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
nm_log_info(LOGD_MB, "ofono: printing %s", g_variant_get_type_string(v_contexts));
|
||||
|
||||
v_objects = g_variant_get_child_value(v_contexts, 0);
|
||||
|
||||
g_variant_iter_init(&i, v_objects);
|
||||
while (g_variant_iter_loop(&i, "(&o@a{sv})", &object_path, &v))
|
||||
connman_context_added(NULL, object_path, v, self);
|
||||
}
|
||||
|
||||
static void
|
||||
_connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
@@ -554,6 +938,18 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
G_CALLBACK(connman_property_changed),
|
||||
self);
|
||||
|
||||
_nm_dbus_signal_connect(priv->connman_proxy,
|
||||
"ContextAdded",
|
||||
G_VARIANT_TYPE("(oa{sv})"),
|
||||
G_CALLBACK(connman_context_added),
|
||||
self);
|
||||
|
||||
_nm_dbus_signal_connect(priv->connman_proxy,
|
||||
"ContextRemoved",
|
||||
G_VARIANT_TYPE("(o)"),
|
||||
G_CALLBACK(connman_context_removed),
|
||||
self);
|
||||
|
||||
g_dbus_proxy_call(priv->connman_proxy,
|
||||
"GetProperties",
|
||||
NULL,
|
||||
@@ -562,6 +958,15 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
priv->connman_proxy_cancellable,
|
||||
connman_get_properties_done,
|
||||
self);
|
||||
|
||||
g_dbus_proxy_call(priv->connman_proxy,
|
||||
"GetContexts",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
20000,
|
||||
priv->connman_proxy_cancellable,
|
||||
connman_get_contexts_done,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -572,6 +977,9 @@ handle_connman_iface(NMModemOfono *self, gboolean found)
|
||||
_LOGD("ConnectionManager interface %sfound", found ? "" : "not ");
|
||||
|
||||
if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) {
|
||||
GHashTableIter iter;
|
||||
NMSettingsConnection *conn;
|
||||
|
||||
_LOGI("ConnectionManager interface disappeared");
|
||||
nm_clear_g_cancellable(&priv->connman_proxy_cancellable);
|
||||
if (priv->connman_proxy) {
|
||||
@@ -584,6 +992,18 @@ handle_connman_iface(NMModemOfono *self, gboolean found)
|
||||
*/
|
||||
priv->gprs_attached = FALSE;
|
||||
|
||||
g_hash_table_iter_init(&iter, priv->connections);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &conn)) {
|
||||
if (NM_FLAGS_HAS(nm_settings_connection_get_flags(conn),
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) {
|
||||
nm_settings_connection_delete(conn, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
priv->current_octx = NULL;
|
||||
g_hash_table_remove_all(priv->connections);
|
||||
g_hash_table_remove_all(priv->contexts);
|
||||
|
||||
update_modem_state(self);
|
||||
} else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) {
|
||||
_LOGI("found new ConnectionManager interface");
|
||||
@@ -716,7 +1136,7 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
self = NM_MODEM_OFONO(user_data);
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
g_clear_object(&priv->context_proxy_cancellable);
|
||||
g_clear_object(&priv->connect_cancellable);
|
||||
|
||||
nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy);
|
||||
|
||||
@@ -730,9 +1150,8 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
}
|
||||
|
||||
static void
|
||||
handle_settings(GVariant *v_dict, gpointer user_data)
|
||||
handle_settings(NMModemOfono *self, GVariant *v_dict)
|
||||
{
|
||||
NMModemOfono *self = NM_MODEM_OFONO(user_data);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
NMPlatformIP4Address address;
|
||||
@@ -890,28 +1309,6 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self = NM_MODEM_OFONO(user_data);
|
||||
gs_unref_variant GVariant *v_dict = NULL;
|
||||
|
||||
_LOGD("PropertyChanged: %s", property);
|
||||
|
||||
if (g_strcmp0(property, "Settings") != 0)
|
||||
return;
|
||||
|
||||
v_dict = g_variant_get_child_value(v, 0);
|
||||
if (!v_dict) {
|
||||
_LOGW("ofono: (%s): error getting IPv4 Settings", nm_modem_get_uid(NM_MODEM(self)));
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert(g_variant_is_of_type(v_dict, G_VARIANT_TYPE_VARDICT));
|
||||
|
||||
handle_settings(v_dict, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_method)
|
||||
{
|
||||
@@ -946,17 +1343,14 @@ out:
|
||||
static void
|
||||
context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self;
|
||||
NMModemOfonoPrivate *priv;
|
||||
NMModemOfono *self = user_data;
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *properties = NULL;
|
||||
gs_unref_variant GVariant *settings = NULL;
|
||||
gs_unref_variant GVariant *v_dict = NULL;
|
||||
gboolean active;
|
||||
|
||||
self = NM_MODEM_OFONO(user_data);
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
properties = g_dbus_proxy_call_finish(proxy, result, &error);
|
||||
|
||||
if (!properties) {
|
||||
@@ -976,13 +1370,6 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Watch for custom ofono PropertyChanged signals */
|
||||
_nm_dbus_signal_connect(priv->context_proxy,
|
||||
"PropertyChanged",
|
||||
G_VARIANT_TYPE("(sv)"),
|
||||
G_CALLBACK(context_property_changed),
|
||||
self);
|
||||
|
||||
if (active) {
|
||||
_LOGD("ofono: connection is already Active");
|
||||
|
||||
@@ -992,9 +1379,9 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle_settings(settings, user_data);
|
||||
handle_settings(self, settings);
|
||||
} else {
|
||||
g_dbus_proxy_call(priv->context_proxy,
|
||||
g_dbus_proxy_call(proxy,
|
||||
"SetProperty",
|
||||
g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
@@ -1010,36 +1397,15 @@ error:
|
||||
}
|
||||
|
||||
static void
|
||||
context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
do_context_activate(NMModemOfono *self)
|
||||
{
|
||||
NMModemOfono *self;
|
||||
NMModemOfonoPrivate *priv;
|
||||
gs_free_error GError *error = NULL;
|
||||
GDBusProxy *proxy;
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_finish(result, &error);
|
||||
if (!proxy || g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
g_return_if_fail(NM_IS_MODEM_OFONO(self));
|
||||
|
||||
self = NM_MODEM_OFONO(user_data);
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
nm_clear_g_cancellable(&priv->connect_cancellable);
|
||||
|
||||
if (!proxy) {
|
||||
_LOGE("failed to create ofono ConnectionContext DBus proxy: %s", error->message);
|
||||
g_clear_object(&priv->context_proxy_cancellable);
|
||||
nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->context_proxy = proxy;
|
||||
|
||||
if (!priv->gprs_attached) {
|
||||
g_clear_object(&priv->context_proxy_cancellable);
|
||||
nm_modem_emit_prepare_result(NM_MODEM(self),
|
||||
FALSE,
|
||||
NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER);
|
||||
return;
|
||||
}
|
||||
priv->connect_cancellable = g_cancellable_new();
|
||||
|
||||
/* We have an old copy of the settings from a previous activation,
|
||||
* clear it so that we can gate getting the IP config from oFono
|
||||
@@ -1049,39 +1415,16 @@ context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
|
||||
/* We need to directly query ConnectionContextinteface to get the current
|
||||
* property values */
|
||||
g_dbus_proxy_call(priv->context_proxy,
|
||||
g_dbus_proxy_call(priv->current_octx->proxy,
|
||||
"GetProperties",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
20000,
|
||||
NULL,
|
||||
priv->connect_cancellable,
|
||||
(GAsyncReadyCallback) context_properties_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
do_context_activate(NMModemOfono *self)
|
||||
{
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
g_return_if_fail(NM_IS_MODEM_OFONO(self));
|
||||
|
||||
nm_clear_g_cancellable(&priv->context_proxy_cancellable);
|
||||
g_clear_object(&priv->context_proxy);
|
||||
|
||||
priv->context_proxy_cancellable = g_cancellable_new();
|
||||
|
||||
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
OFONO_DBUS_SERVICE,
|
||||
priv->context_path,
|
||||
OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT,
|
||||
priv->context_proxy_cancellable,
|
||||
context_proxy_new_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
create_connect_properties(NMConnection *connection)
|
||||
{
|
||||
@@ -1114,20 +1457,10 @@ modem_act_stage1_prepare(NMModem *modem,
|
||||
{
|
||||
NMModemOfono *self = NM_MODEM_OFONO(modem);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
const char *context_id;
|
||||
char **id = NULL;
|
||||
const char *uuid = nm_connection_get_uuid(connection);
|
||||
OfonoContextData *octx = g_hash_table_lookup(priv->contexts, uuid);
|
||||
|
||||
context_id = nm_connection_get_id(connection);
|
||||
id = g_strsplit(context_id, "/", 0);
|
||||
g_return_val_if_fail(id[2], NM_ACT_STAGE_RETURN_FAILURE);
|
||||
|
||||
_LOGD("trying %s %s", id[1], id[2]);
|
||||
|
||||
g_free(priv->context_path);
|
||||
priv->context_path = g_strdup_printf("%s/%s", nm_modem_get_path(modem), id[2]);
|
||||
g_strfreev(id);
|
||||
|
||||
if (!priv->context_path) {
|
||||
if (!octx) {
|
||||
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED);
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
}
|
||||
@@ -1137,7 +1470,8 @@ modem_act_stage1_prepare(NMModem *modem,
|
||||
|
||||
priv->connect_properties = create_connect_properties(connection);
|
||||
|
||||
_LOGI("activating context %s", priv->context_path);
|
||||
_LOGI("activating context %s", g_dbus_proxy_get_object_path(octx->proxy));
|
||||
priv->current_octx = octx;
|
||||
|
||||
update_modem_state(self);
|
||||
if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) {
|
||||
@@ -1194,7 +1528,17 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
|
||||
static void
|
||||
nm_modem_ofono_init(NMModemOfono *self)
|
||||
{}
|
||||
{
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
priv->modem_proxy_cancellable = g_cancellable_new();
|
||||
priv->connections = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
priv->contexts = g_hash_table_new_full(nm_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
(GDestroyNotify) ofono_context_data_free);
|
||||
priv->settings = g_object_ref(NM_SETTINGS_GET);
|
||||
}
|
||||
|
||||
static void
|
||||
constructed(GObject *object)
|
||||
@@ -1202,8 +1546,6 @@ constructed(GObject *object)
|
||||
NMModemOfono *self = NM_MODEM_OFONO(object);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
priv->modem_proxy_cancellable = g_cancellable_new();
|
||||
|
||||
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
@@ -1255,7 +1597,7 @@ dispose(GObject *object)
|
||||
|
||||
nm_clear_g_cancellable(&priv->modem_proxy_cancellable);
|
||||
nm_clear_g_cancellable(&priv->connman_proxy_cancellable);
|
||||
nm_clear_g_cancellable(&priv->context_proxy_cancellable);
|
||||
nm_clear_g_cancellable(&priv->connect_cancellable);
|
||||
nm_clear_g_cancellable(&priv->sim_proxy_cancellable);
|
||||
|
||||
if (priv->connect_properties) {
|
||||
@@ -1263,6 +1605,16 @@ dispose(GObject *object)
|
||||
priv->connect_properties = NULL;
|
||||
}
|
||||
|
||||
if (priv->connections) {
|
||||
g_hash_table_destroy(priv->connections);
|
||||
priv->connections = NULL;
|
||||
}
|
||||
|
||||
if (priv->contexts) {
|
||||
g_hash_table_destroy(priv->contexts);
|
||||
priv->contexts = NULL;
|
||||
}
|
||||
|
||||
nm_clear_l3cd(&priv->l3cd_4);
|
||||
|
||||
if (priv->modem_proxy) {
|
||||
@@ -1275,16 +1627,16 @@ dispose(GObject *object)
|
||||
g_clear_object(&priv->connman_proxy);
|
||||
}
|
||||
|
||||
if (priv->context_proxy) {
|
||||
g_signal_handlers_disconnect_by_data(priv->context_proxy, self);
|
||||
g_clear_object(&priv->context_proxy);
|
||||
}
|
||||
|
||||
if (priv->sim_proxy) {
|
||||
g_signal_handlers_disconnect_by_data(priv->sim_proxy, self);
|
||||
g_clear_object(&priv->sim_proxy);
|
||||
}
|
||||
|
||||
if (priv->settings) {
|
||||
g_signal_handlers_disconnect_by_data(priv->settings, self);
|
||||
g_clear_object(&priv->settings);
|
||||
}
|
||||
|
||||
g_free(priv->imsi);
|
||||
priv->imsi = NULL;
|
||||
|
||||
|
Reference in New Issue
Block a user