mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-11 12:48:10 +02:00
wwan: ofono: set modem capabilities when we receive them
Implement the `org.ofono.RadioSettings` interface, which sends modem capabilities after modem power on. As oFono only updates capabilities after power on, set the capabilities to ensure NetworkManager receives the update. On devices that don't support the RadioSettings interface, NM will default to no specific capabilities set. Signed-off-by: Muhammad Asif <thevancedgamer@mentallysanemainliners.org>
This commit is contained in:
parent
9c6cf71f4f
commit
3b264e830e
2 changed files with 213 additions and 3 deletions
|
|
@ -16,6 +16,7 @@
|
|||
#include "nm-modem.h"
|
||||
#include "libnm-platform/nm-platform.h"
|
||||
#include "nm-l3-config-data.h"
|
||||
#include "nm-device-modem.h"
|
||||
|
||||
#define VARIANT_IS_OF_TYPE_BOOLEAN(v) \
|
||||
((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_BOOLEAN)))
|
||||
|
|
@ -46,11 +47,13 @@ typedef struct {
|
|||
GDBusProxy *modem_proxy;
|
||||
GDBusProxy *connman_proxy;
|
||||
GDBusProxy *sim_proxy;
|
||||
GDBusProxy *rat_proxy;
|
||||
|
||||
GCancellable *modem_proxy_cancellable;
|
||||
GCancellable *connman_proxy_cancellable;
|
||||
GCancellable *connect_cancellable;
|
||||
GCancellable *sim_proxy_cancellable;
|
||||
GCancellable *rat_proxy_cancellable;
|
||||
|
||||
GError *property_error;
|
||||
|
||||
|
|
@ -69,6 +72,9 @@ typedef struct {
|
|||
OfonoContextData *current_octx;
|
||||
|
||||
GSource *deferred_connection_timeout_source;
|
||||
|
||||
gchar **available_technologies;
|
||||
char *preferred_technology;
|
||||
} NMModemOfonoPrivate;
|
||||
|
||||
struct _NMModemOfono {
|
||||
|
|
@ -137,9 +143,48 @@ get_capabilities(NMModem *_self,
|
|||
NMDeviceModemCapabilities *modem_caps,
|
||||
NMDeviceModemCapabilities *current_caps)
|
||||
{
|
||||
/* FIXME: auto-detect capabilities to allow LTE */
|
||||
*modem_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS;
|
||||
*current_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS;
|
||||
NMModemOfono *self = NM_MODEM_OFONO(_self);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
*modem_caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
|
||||
*current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
|
||||
|
||||
/* Example values:
|
||||
* AvailableTechnologies: "gsm umts lte"
|
||||
* TechnologyPreference: "lte"
|
||||
*/
|
||||
|
||||
if (!priv->available_technologies || !priv->preferred_technology) {
|
||||
_LOGD("no technology information available");
|
||||
return;
|
||||
}
|
||||
|
||||
for (gint i = 0; priv->available_technologies[i]; i++) {
|
||||
const char *tech = priv->available_technologies[i];
|
||||
|
||||
_LOGD("available technology: %s", tech);
|
||||
|
||||
if (nm_streq(tech, "gsm") || nm_streq(tech, "umts"))
|
||||
*modem_caps |= NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS;
|
||||
else if (nm_streq(tech, "lte"))
|
||||
*modem_caps |= NM_DEVICE_MODEM_CAPABILITY_LTE;
|
||||
}
|
||||
|
||||
if (nm_streq(priv->preferred_technology, "gsm") || nm_streq(priv->preferred_technology, "umts"))
|
||||
*current_caps |= NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS;
|
||||
else if (nm_streq(priv->preferred_technology, "lte"))
|
||||
*current_caps |= NM_DEVICE_MODEM_CAPABILITY_LTE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_capabilities_changed(NMModemOfono *self)
|
||||
{
|
||||
NMDeviceModemCapabilities modem_caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
|
||||
NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
|
||||
|
||||
get_capabilities(NM_MODEM(self), &modem_caps, ¤t_caps);
|
||||
|
||||
nm_modem_set_capabilities(NM_MODEM(self), modem_caps, current_caps);
|
||||
}
|
||||
|
||||
static void do_context_activate(NMModemOfono *self);
|
||||
|
|
@ -1082,6 +1127,154 @@ handle_connman_iface(NMModemOfono *self, gboolean found)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_rat_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self = NM_MODEM_OFONO(user_data);
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
if (nm_streq(property, "AvailableTechnologies") && VARIANT_IS_OF_TYPE_STRING_ARRAY(v)) {
|
||||
gchar **available_technologies = g_variant_dup_strv(v, NULL);
|
||||
|
||||
if (!priv->available_technologies) {
|
||||
priv->available_technologies = available_technologies;
|
||||
set_capabilities_changed(self);
|
||||
}
|
||||
} else if (nm_streq(property, "TechnologyPreference") && VARIANT_IS_OF_TYPE_STRING(v)) {
|
||||
const char *technology_preference = g_variant_get_string(v, NULL);
|
||||
|
||||
if (!priv->preferred_technology
|
||||
|| !nm_streq(priv->preferred_technology, technology_preference)) {
|
||||
g_free(priv->preferred_technology);
|
||||
priv->preferred_technology = g_strdup(technology_preference);
|
||||
set_capabilities_changed(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rat_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data)
|
||||
{
|
||||
GVariant *v_child = g_variant_get_child_value(v, 0);
|
||||
|
||||
handle_rat_property(proxy, property, v_child, user_data);
|
||||
g_variant_unref(v_child);
|
||||
}
|
||||
|
||||
static void
|
||||
rat_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self;
|
||||
NMModemOfonoPrivate *priv;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *v_properties = NULL;
|
||||
gs_unref_variant GVariant *v_dict = NULL;
|
||||
gs_unref_variant GVariant *v = NULL;
|
||||
GVariantIter i;
|
||||
const char *property;
|
||||
|
||||
v_properties =
|
||||
_nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error);
|
||||
if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
self = NM_MODEM_OFONO(user_data);
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
g_clear_object(&priv->rat_proxy_cancellable);
|
||||
|
||||
if (!v_properties) {
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGW("error getting RadioSettings properties: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGD("rat v_properties is type: %s", g_variant_get_type_string(v_properties));
|
||||
|
||||
v_dict = g_variant_get_child_value(v_properties, 0);
|
||||
if (!v_dict) {
|
||||
_LOGW("error getting RadioSettings properties: no v_dict");
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGD("rat v_dict is type: %s", g_variant_get_type_string(v_dict));
|
||||
|
||||
g_variant_iter_init(&i, v_dict);
|
||||
while (g_variant_iter_loop(&i, "{&sv}", &property, &v)) {
|
||||
handle_rat_property(NULL, property, v, self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_rat_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMModemOfono *self;
|
||||
NMModemOfonoPrivate *priv;
|
||||
gs_free_error GError *error = NULL;
|
||||
GDBusProxy *proxy;
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_finish(result, &error);
|
||||
if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
self = user_data;
|
||||
priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
if (!proxy) {
|
||||
_LOGW("failed to create RadioSettings proxy: %s", error->message);
|
||||
g_clear_object(&priv->rat_proxy_cancellable);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->rat_proxy = proxy;
|
||||
|
||||
/* Watch for custom ofono PropertyChanged signals */
|
||||
_nm_dbus_proxy_signal_connect(priv->rat_proxy,
|
||||
"PropertyChanged",
|
||||
G_VARIANT_TYPE("(sv)"),
|
||||
G_CALLBACK(rat_property_changed),
|
||||
self);
|
||||
|
||||
g_dbus_proxy_call(priv->rat_proxy,
|
||||
"GetProperties",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
20000,
|
||||
priv->rat_proxy_cancellable,
|
||||
rat_get_properties_done,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_rat_iface(NMModemOfono *self, gboolean found)
|
||||
{
|
||||
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self);
|
||||
|
||||
if (!found && (priv->rat_proxy || priv->rat_proxy_cancellable)) {
|
||||
_LOGI("RadioSettings interface disappeared");
|
||||
nm_clear_g_cancellable(&priv->rat_proxy_cancellable);
|
||||
if (priv->rat_proxy) {
|
||||
g_signal_handlers_disconnect_by_data(priv->rat_proxy, self);
|
||||
g_clear_object(&priv->rat_proxy);
|
||||
}
|
||||
} else if (found && (!priv->rat_proxy && !priv->rat_proxy_cancellable)) {
|
||||
_LOGI("found new RadioSettings interface");
|
||||
|
||||
priv->rat_proxy_cancellable = g_cancellable_new();
|
||||
|
||||
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,
|
||||
nm_modem_get_path(NM_MODEM(self)),
|
||||
OFONO_DBUS_INTERFACE_RADIO_SETTINGS,
|
||||
priv->rat_proxy_cancellable,
|
||||
_rat_proxy_new_cb,
|
||||
self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_modem_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data)
|
||||
{
|
||||
|
|
@ -1119,6 +1312,7 @@ handle_modem_property(GDBusProxy *proxy, const char *property, GVariant *v, gpoi
|
|||
const char **array, **iter;
|
||||
gboolean found_connman = FALSE;
|
||||
gboolean found_sim = FALSE;
|
||||
gboolean found_rat = FALSE;
|
||||
|
||||
_LOGD("Interfaces found");
|
||||
|
||||
|
|
@ -1129,12 +1323,15 @@ handle_modem_property(GDBusProxy *proxy, const char *property, GVariant *v, gpoi
|
|||
found_sim = TRUE;
|
||||
else if (g_strcmp0(OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, *iter) == 0)
|
||||
found_connman = TRUE;
|
||||
else if (g_strcmp0(OFONO_DBUS_INTERFACE_RADIO_SETTINGS, *iter) == 0)
|
||||
found_rat = TRUE;
|
||||
}
|
||||
g_free(array);
|
||||
}
|
||||
|
||||
handle_sim_iface(self, found_sim);
|
||||
handle_connman_iface(self, found_connman);
|
||||
handle_rat_iface(self, found_rat);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1713,6 +1910,7 @@ dispose(GObject *object)
|
|||
nm_clear_g_cancellable(&priv->connman_proxy_cancellable);
|
||||
nm_clear_g_cancellable(&priv->connect_cancellable);
|
||||
nm_clear_g_cancellable(&priv->sim_proxy_cancellable);
|
||||
nm_clear_g_cancellable(&priv->rat_proxy_cancellable);
|
||||
|
||||
if (priv->connect_properties) {
|
||||
g_hash_table_destroy(priv->connect_properties);
|
||||
|
|
@ -1746,6 +1944,11 @@ dispose(GObject *object)
|
|||
g_clear_object(&priv->sim_proxy);
|
||||
}
|
||||
|
||||
if (priv->rat_proxy) {
|
||||
g_signal_handlers_disconnect_by_data(priv->rat_proxy, self);
|
||||
g_clear_object(&priv->rat_proxy);
|
||||
}
|
||||
|
||||
if (priv->settings) {
|
||||
g_signal_handlers_disconnect_by_data(priv->settings, self);
|
||||
g_clear_object(&priv->settings);
|
||||
|
|
@ -1754,6 +1957,12 @@ dispose(GObject *object)
|
|||
g_free(priv->imsi);
|
||||
priv->imsi = NULL;
|
||||
|
||||
g_strfreev(priv->available_technologies);
|
||||
priv->available_technologies = NULL;
|
||||
|
||||
g_free(priv->preferred_technology);
|
||||
priv->preferred_technology = NULL;
|
||||
|
||||
nm_clear_g_source_inst(&priv->deferred_connection_timeout_source);
|
||||
|
||||
G_OBJECT_CLASS(nm_modem_ofono_parent_class)->dispose(object);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#define OFONO_DBUS_INTERFACE_CONNECTION_MANAGER "org.ofono.ConnectionManager"
|
||||
#define OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT "org.ofono.ConnectionContext"
|
||||
#define OFONO_DBUS_INTERFACE_SIM_MANAGER "org.ofono.SimManager"
|
||||
#define OFONO_DBUS_INTERFACE_RADIO_SETTINGS "org.ofono.RadioSettings"
|
||||
|
||||
#define OFONO_ERROR_IN_PROGRESS "org.ofono.Error.InProgress"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue