mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-01 16:30:12 +01:00
For now, handle multiple serial ports on a vendor/driver basis in the modem creator function; HAL emits device added signals for the ttys in random order, so just using the first serial port doesn't work. This was mainly added for 'hso' devices anyway, for which multiple serial ports are already handled correctly by the creator.
2391 lines
72 KiB
C
2391 lines
72 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/* NetworkManager -- Network link manager
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright (C) 2007 - 2008 Novell, Inc.
|
|
* Copyright (C) 2007 - 2008 Red Hat, Inc.
|
|
*/
|
|
|
|
#include <netinet/ether.h>
|
|
#include <string.h>
|
|
#include <dbus/dbus-glib-lowlevel.h>
|
|
#include <dbus/dbus-glib.h>
|
|
|
|
#include "nm-glib-compat.h"
|
|
#include "nm-manager.h"
|
|
#include "nm-utils.h"
|
|
#include "nm-dbus-manager.h"
|
|
#include "nm-vpn-manager.h"
|
|
#include "nm-device-interface.h"
|
|
#include "nm-device-private.h"
|
|
#include "nm-device-ethernet.h"
|
|
#include "nm-device-wifi.h"
|
|
#include "nm-serial-device.h"
|
|
#include "NetworkManagerSystem.h"
|
|
#include "nm-properties-changed-signal.h"
|
|
#include "nm-setting-connection.h"
|
|
#include "nm-setting-wireless.h"
|
|
#include "nm-setting-vpn.h"
|
|
#include "nm-marshal.h"
|
|
#include "nm-dbus-glib-types.h"
|
|
#include "nm-hal-manager.h"
|
|
|
|
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
|
|
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
|
|
|
|
static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err);
|
|
static void impl_manager_activate_connection (NMManager *manager,
|
|
const char *service_name,
|
|
const char *connection_path,
|
|
const char *device_path,
|
|
const char *specific_object_path,
|
|
DBusGMethodInvocation *context);
|
|
|
|
static gboolean impl_manager_deactivate_connection (NMManager *manager,
|
|
const char *connection_path,
|
|
GError **error);
|
|
|
|
static gboolean impl_manager_sleep (NMManager *manager, gboolean sleep, GError **err);
|
|
|
|
static gboolean poke_system_settings_daemon_cb (gpointer user_data);
|
|
|
|
/* Legacy 0.6 compatibility interface */
|
|
|
|
static gboolean impl_manager_legacy_sleep (NMManager *manager, GError **err);
|
|
static gboolean impl_manager_legacy_wake (NMManager *manager, GError **err);
|
|
static gboolean impl_manager_legacy_state (NMManager *manager, guint32 *state, GError **err);
|
|
|
|
#include "nm-manager-glue.h"
|
|
|
|
static void nm_manager_connections_destroy (NMManager *manager, NMConnectionScope scope);
|
|
static void manager_set_wireless_enabled (NMManager *manager, gboolean enabled);
|
|
|
|
static void connection_added_default_handler (NMManager *manager,
|
|
NMConnection *connection,
|
|
NMConnectionScope scope);
|
|
|
|
static void hal_manager_udi_added_cb (NMHalManager *hal_mgr,
|
|
const char *udi,
|
|
const char *originating_device,
|
|
gpointer general_type_ptr,
|
|
NMDeviceCreatorFn creator_fn,
|
|
gpointer user_data);
|
|
|
|
static void hal_manager_udi_removed_cb (NMHalManager *hal_mgr,
|
|
const char *udi,
|
|
gpointer user_data);
|
|
|
|
static void hal_manager_rfkill_changed_cb (NMHalManager *hal_mgr,
|
|
gboolean rfkilled,
|
|
gpointer user_data);
|
|
|
|
static void hal_manager_hal_reappeared_cb (NMHalManager *hal_mgr,
|
|
gpointer user_data);
|
|
|
|
static void system_settings_properties_changed_cb (DBusGProxy *proxy,
|
|
GHashTable *properties,
|
|
gpointer user_data);
|
|
|
|
#define SSD_POKE_INTERVAL 120
|
|
#define ORIGDEV_TAG "originating-device"
|
|
|
|
typedef struct {
|
|
DBusGMethodInvocation *context;
|
|
NMConnectionScope scope;
|
|
char *connection_path;
|
|
char *specific_object_path;
|
|
char *device_path;
|
|
guint timeout_id;
|
|
} PendingConnectionInfo;
|
|
|
|
typedef struct {
|
|
GSList *devices;
|
|
NMState state;
|
|
|
|
NMDBusManager *dbus_mgr;
|
|
NMHalManager *hal_mgr;
|
|
|
|
GHashTable *user_connections;
|
|
DBusGProxy *user_proxy;
|
|
|
|
GHashTable *system_connections;
|
|
DBusGProxy *system_proxy;
|
|
DBusGProxy *system_props_proxy;
|
|
GSList *unmanaged_udis;
|
|
char *hostname;
|
|
|
|
PendingConnectionInfo *pending_connection_info;
|
|
gboolean wireless_enabled;
|
|
gboolean wireless_hw_enabled;
|
|
gboolean sleeping;
|
|
|
|
guint poke_id;
|
|
guint sync_devices_id;
|
|
|
|
NMVPNManager *vpn_manager;
|
|
guint vpn_manager_id;
|
|
|
|
DBusGProxy *aipd_proxy;
|
|
|
|
gboolean disposed;
|
|
} NMManagerPrivate;
|
|
|
|
#define NM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MANAGER, NMManagerPrivate))
|
|
|
|
G_DEFINE_TYPE (NMManager, nm_manager, G_TYPE_OBJECT)
|
|
|
|
enum {
|
|
DEVICE_ADDED,
|
|
DEVICE_REMOVED,
|
|
STATE_CHANGED,
|
|
STATE_CHANGE, /* DEPRECATED */
|
|
PROPERTIES_CHANGED,
|
|
CONNECTIONS_ADDED,
|
|
CONNECTION_ADDED,
|
|
CONNECTION_UPDATED,
|
|
CONNECTION_REMOVED,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_STATE,
|
|
PROP_WIRELESS_ENABLED,
|
|
PROP_WIRELESS_HARDWARE_ENABLED,
|
|
PROP_ACTIVE_CONNECTIONS,
|
|
|
|
/* Not exported */
|
|
PROP_HOSTNAME,
|
|
|
|
LAST_PROP
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0,
|
|
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
|
|
NM_MANAGER_ERROR_UNMANAGED_DEVICE,
|
|
NM_MANAGER_ERROR_INVALID_SERVICE,
|
|
NM_MANAGER_ERROR_SYSTEM_CONNECTION,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
|
|
NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
|
|
} NMManagerError;
|
|
|
|
#define NM_MANAGER_ERROR (nm_manager_error_quark ())
|
|
#define NM_TYPE_MANAGER_ERROR (nm_manager_error_get_type ())
|
|
|
|
static GQuark
|
|
nm_manager_error_quark (void)
|
|
{
|
|
static GQuark quark = 0;
|
|
if (!quark)
|
|
quark = g_quark_from_static_string ("nm-manager-error");
|
|
return quark;
|
|
}
|
|
|
|
/* This should really be standard. */
|
|
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
|
|
|
|
static GType
|
|
nm_manager_error_get_type (void)
|
|
{
|
|
static GType etype = 0;
|
|
|
|
if (etype == 0) {
|
|
static const GEnumValue values[] = {
|
|
/* Connection was not provided by any known settings service. */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "UnknownConnection"),
|
|
/* Unknown device. */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_DEVICE, "UnknownDevice"),
|
|
/* Unmanaged device. */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_UNMANAGED_DEVICE, "UnmanagedDevice"),
|
|
/* Invalid settings service (not a recognized system or user
|
|
* settings service name)
|
|
*/
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_INVALID_SERVICE, "InvalidService"),
|
|
/* Connection was superceded by a system connection. */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_SYSTEM_CONNECTION, "SystemConnection"),
|
|
/* User does not have the permission to activate this connection. */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_PERMISSION_DENIED, "PermissionDenied"),
|
|
/* The connection was not active. */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "ConnectionNotActive"),
|
|
/* The manager is already in the requested sleep state */
|
|
ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "AlreadyAsleepOrAwake"),
|
|
{ 0, 0, 0 },
|
|
};
|
|
etype = g_enum_register_static ("NMManagerError", values);
|
|
}
|
|
return etype;
|
|
}
|
|
|
|
static void
|
|
vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
|
|
NMVPNConnection *vpn,
|
|
NMVPNConnectionState state,
|
|
NMVPNConnectionStateReason reason,
|
|
gpointer user_data)
|
|
{
|
|
g_object_notify (G_OBJECT (user_data), NM_MANAGER_ACTIVE_CONNECTIONS);
|
|
}
|
|
|
|
static void
|
|
aipd_handle_event (DBusGProxy *proxy,
|
|
const char *event,
|
|
const char *iface,
|
|
const char *address,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
GSList *iter;
|
|
gboolean handled;
|
|
|
|
if (!event || !iface) {
|
|
nm_warning ("Incomplete message received from avahi-autoipd");
|
|
return;
|
|
}
|
|
|
|
if ( (strcmp (event, "BIND") != 0)
|
|
&& (strcmp (event, "CONFLICT") != 0)
|
|
&& (strcmp (event, "UNBIND") != 0)
|
|
&& (strcmp (event, "STOP") != 0)) {
|
|
nm_warning ("Unknown event '%s' received from avahi-autoipd", event);
|
|
return;
|
|
}
|
|
|
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
|
NMDevice *candidate = NM_DEVICE (iter->data);
|
|
|
|
if (!strcmp (nm_device_get_iface (candidate), iface)) {
|
|
nm_device_handle_autoip4_event (candidate, event, address);
|
|
handled = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!handled)
|
|
nm_warning ("Unhandled avahi-autoipd event for '%s'", iface);
|
|
}
|
|
|
|
static void
|
|
nm_manager_init (NMManager *manager)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
DBusGConnection *g_connection;
|
|
guint id;
|
|
|
|
priv->wireless_enabled = TRUE;
|
|
priv->wireless_hw_enabled = TRUE;
|
|
priv->sleeping = FALSE;
|
|
priv->state = NM_STATE_DISCONNECTED;
|
|
|
|
priv->dbus_mgr = nm_dbus_manager_get ();
|
|
|
|
priv->user_connections = g_hash_table_new_full (g_str_hash,
|
|
g_str_equal,
|
|
g_free,
|
|
g_object_unref);
|
|
|
|
priv->system_connections = g_hash_table_new_full (g_str_hash,
|
|
g_str_equal,
|
|
g_free,
|
|
g_object_unref);
|
|
|
|
priv->vpn_manager = nm_vpn_manager_get ();
|
|
id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
|
|
G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
|
|
priv->vpn_manager_id = id;
|
|
|
|
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
|
|
|
/* avahi-autoipd stuff */
|
|
priv->aipd_proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
NM_AUTOIP_DBUS_SERVICE,
|
|
"/",
|
|
NM_AUTOIP_DBUS_IFACE);
|
|
if (priv->aipd_proxy) {
|
|
dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING,
|
|
G_TYPE_NONE,
|
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_INVALID);
|
|
|
|
dbus_g_proxy_add_signal (priv->aipd_proxy,
|
|
"Event",
|
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_INVALID);
|
|
|
|
dbus_g_proxy_connect_signal (priv->aipd_proxy, "Event",
|
|
G_CALLBACK (aipd_handle_event),
|
|
manager,
|
|
NULL);
|
|
} else
|
|
nm_warning ("%s: could not initialize avahi-autoipd D-Bus proxy", __func__);
|
|
|
|
/* System settings stuff */
|
|
priv->system_props_proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
NM_DBUS_SERVICE_SYSTEM_SETTINGS,
|
|
NM_DBUS_PATH_SETTINGS,
|
|
"org.freedesktop.NetworkManagerSettings.System");
|
|
if (priv->system_props_proxy) {
|
|
dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
|
|
G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID);
|
|
dbus_g_proxy_add_signal (priv->system_props_proxy, "PropertiesChanged",
|
|
DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
|
|
dbus_g_proxy_connect_signal (priv->system_props_proxy, "PropertiesChanged",
|
|
G_CALLBACK (system_settings_properties_changed_cb),
|
|
manager,
|
|
NULL);
|
|
} else
|
|
nm_warning ("%s: could not initialize system settings properties D-Bus proxy", __func__);
|
|
}
|
|
|
|
NMState
|
|
nm_manager_get_state (NMManager *manager)
|
|
{
|
|
g_return_val_if_fail (NM_IS_MANAGER (manager), NM_STATE_UNKNOWN);
|
|
|
|
return NM_MANAGER_GET_PRIVATE (manager)->state;
|
|
}
|
|
|
|
static void
|
|
nm_manager_update_state (NMManager *manager)
|
|
{
|
|
NMManagerPrivate *priv;
|
|
NMState new_state = NM_STATE_DISCONNECTED;
|
|
|
|
g_return_if_fail (NM_IS_MANAGER (manager));
|
|
|
|
priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (priv->sleeping) {
|
|
new_state = NM_STATE_ASLEEP;
|
|
} else {
|
|
GSList *iter;
|
|
|
|
for (iter = priv->devices; iter; iter = iter->next) {
|
|
NMDevice *dev = NM_DEVICE (iter->data);
|
|
|
|
if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
|
|
new_state = NM_STATE_CONNECTED;
|
|
break;
|
|
} else if (nm_device_is_activating (dev)) {
|
|
new_state = NM_STATE_CONNECTING;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (priv->state != new_state) {
|
|
priv->state = new_state;
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_STATE);
|
|
|
|
g_signal_emit (manager, signals[STATE_CHANGED], 0, priv->state);
|
|
|
|
/* Emit StateChange too for backwards compatibility */
|
|
g_signal_emit (manager, signals[STATE_CHANGE], 0, priv->state);
|
|
}
|
|
}
|
|
|
|
static void
|
|
pending_connection_info_destroy (PendingConnectionInfo *info)
|
|
{
|
|
if (!info)
|
|
return;
|
|
|
|
if (info->timeout_id)
|
|
g_source_remove (info->timeout_id);
|
|
|
|
g_free (info->connection_path);
|
|
g_free (info->specific_object_path);
|
|
g_free (info->device_path);
|
|
|
|
g_slice_free (PendingConnectionInfo, info);
|
|
}
|
|
|
|
static void
|
|
manager_device_state_changed (NMDevice *device,
|
|
NMDeviceState new_state,
|
|
NMDeviceState old_state,
|
|
NMDeviceStateReason reason,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
|
|
switch (new_state) {
|
|
case NM_DEVICE_STATE_UNMANAGED:
|
|
case NM_DEVICE_STATE_UNAVAILABLE:
|
|
case NM_DEVICE_STATE_DISCONNECTED:
|
|
case NM_DEVICE_STATE_PREPARE:
|
|
case NM_DEVICE_STATE_FAILED:
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
nm_manager_update_state (manager);
|
|
}
|
|
|
|
static void
|
|
remove_one_device (NMManager *manager, NMDevice *device)
|
|
{
|
|
if (nm_device_get_managed (device))
|
|
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
|
|
|
|
g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
|
|
|
|
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
|
|
g_object_unref (device);
|
|
}
|
|
|
|
static void
|
|
dispose (GObject *object)
|
|
{
|
|
NMManager *manager = NM_MANAGER (object);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (priv->disposed) {
|
|
G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
|
|
return;
|
|
}
|
|
priv->disposed = TRUE;
|
|
|
|
pending_connection_info_destroy (priv->pending_connection_info);
|
|
priv->pending_connection_info = NULL;
|
|
|
|
if (priv->sync_devices_id) {
|
|
g_source_remove (priv->sync_devices_id);
|
|
priv->sync_devices_id = 0;
|
|
}
|
|
|
|
while (g_slist_length (priv->devices)) {
|
|
remove_one_device (manager, NM_DEVICE (priv->devices->data));
|
|
priv->devices = g_slist_remove_link (priv->devices, priv->devices);
|
|
}
|
|
|
|
nm_manager_connections_destroy (manager, NM_CONNECTION_SCOPE_USER);
|
|
g_hash_table_destroy (priv->user_connections);
|
|
priv->user_connections = NULL;
|
|
|
|
nm_manager_connections_destroy (manager, NM_CONNECTION_SCOPE_SYSTEM);
|
|
g_hash_table_destroy (priv->system_connections);
|
|
priv->system_connections = NULL;
|
|
|
|
g_free (priv->hostname);
|
|
|
|
if (priv->system_props_proxy) {
|
|
g_object_unref (priv->system_props_proxy);
|
|
priv->system_props_proxy = NULL;
|
|
}
|
|
g_slist_foreach (priv->unmanaged_udis, (GFunc) g_free, NULL);
|
|
g_slist_free (priv->unmanaged_udis);
|
|
|
|
if (priv->poke_id) {
|
|
g_source_remove (priv->poke_id);
|
|
priv->poke_id = 0;
|
|
}
|
|
|
|
if (priv->vpn_manager_id) {
|
|
g_source_remove (priv->vpn_manager_id);
|
|
priv->vpn_manager_id = 0;
|
|
}
|
|
g_object_unref (priv->vpn_manager);
|
|
|
|
g_object_unref (priv->dbus_mgr);
|
|
g_object_unref (priv->hal_mgr);
|
|
|
|
G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
switch (prop_id) {
|
|
case PROP_WIRELESS_ENABLED:
|
|
manager_set_wireless_enabled (NM_MANAGER (object), g_value_get_boolean (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static GPtrArray *
|
|
get_active_connections (NMManager *manager, NMConnection *filter)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
NMVPNManager *vpn_manager;
|
|
GPtrArray *active;
|
|
GSList *iter;
|
|
|
|
active = g_ptr_array_sized_new (3);
|
|
|
|
/* Add active device connections */
|
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
|
NMActRequest *req;
|
|
const char *path;
|
|
|
|
req = nm_device_get_act_request (NM_DEVICE (iter->data));
|
|
if (!req)
|
|
continue;
|
|
|
|
if (!filter || (nm_act_request_get_connection (req) == filter)) {
|
|
path = nm_act_request_get_active_connection_path (req);
|
|
g_ptr_array_add (active, g_strdup (path));
|
|
}
|
|
}
|
|
|
|
/* Add active VPN connections */
|
|
vpn_manager = nm_vpn_manager_get ();
|
|
nm_vpn_manager_add_active_connections (vpn_manager, filter, active);
|
|
g_object_unref (vpn_manager);
|
|
|
|
return active;
|
|
}
|
|
|
|
static void
|
|
get_property (GObject *object, guint prop_id,
|
|
GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMManager *self = NM_MANAGER (object);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
|
|
switch (prop_id) {
|
|
case PROP_STATE:
|
|
nm_manager_update_state (self);
|
|
g_value_set_uint (value, priv->state);
|
|
break;
|
|
case PROP_WIRELESS_ENABLED:
|
|
g_value_set_boolean (value, priv->wireless_enabled);
|
|
break;
|
|
case PROP_WIRELESS_HARDWARE_ENABLED:
|
|
g_value_set_boolean (value, priv->wireless_hw_enabled);
|
|
break;
|
|
case PROP_ACTIVE_CONNECTIONS:
|
|
g_value_take_boxed (value, get_active_connections (self, NULL));
|
|
break;
|
|
case PROP_HOSTNAME:
|
|
g_value_set_string (value, priv->hostname);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nm_manager_class_init (NMManagerClass *manager_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
|
|
|
|
g_type_class_add_private (manager_class, sizeof (NMManagerPrivate));
|
|
|
|
/* virtual methods */
|
|
manager_class->connection_added = connection_added_default_handler;
|
|
|
|
object_class->set_property = set_property;
|
|
object_class->get_property = get_property;
|
|
object_class->dispose = dispose;
|
|
|
|
/* properties */
|
|
g_object_class_install_property
|
|
(object_class, PROP_STATE,
|
|
g_param_spec_uint (NM_MANAGER_STATE,
|
|
"State",
|
|
"Current state",
|
|
0, 5, 0, /* FIXME */
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property
|
|
(object_class, PROP_WIRELESS_ENABLED,
|
|
g_param_spec_boolean (NM_MANAGER_WIRELESS_ENABLED,
|
|
"WirelessEnabled",
|
|
"Is wireless enabled",
|
|
TRUE,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property
|
|
(object_class, PROP_WIRELESS_HARDWARE_ENABLED,
|
|
g_param_spec_boolean (NM_MANAGER_WIRELESS_HARDWARE_ENABLED,
|
|
"WirelessHardwareEnabled",
|
|
"RF kill state",
|
|
TRUE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property
|
|
(object_class, PROP_ACTIVE_CONNECTIONS,
|
|
g_param_spec_boxed (NM_MANAGER_ACTIVE_CONNECTIONS,
|
|
"Active connections",
|
|
"Active connections",
|
|
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
|
|
G_PARAM_READABLE));
|
|
|
|
/* Hostname is not exported over D-Bus */
|
|
g_object_class_install_property
|
|
(object_class, PROP_HOSTNAME,
|
|
g_param_spec_string (NM_MANAGER_HOSTNAME,
|
|
"Hostname",
|
|
"Hostname",
|
|
NULL,
|
|
G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
|
|
|
|
/* signals */
|
|
signals[DEVICE_ADDED] =
|
|
g_signal_new ("device-added",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, device_added),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_OBJECT);
|
|
|
|
signals[DEVICE_REMOVED] =
|
|
g_signal_new ("device-removed",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, device_removed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_OBJECT);
|
|
|
|
signals[STATE_CHANGED] =
|
|
g_signal_new ("state-changed",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, state_changed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__UINT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_UINT);
|
|
|
|
signals[PROPERTIES_CHANGED] =
|
|
nm_properties_changed_signal_new (object_class,
|
|
G_STRUCT_OFFSET (NMManagerClass, properties_changed));
|
|
|
|
signals[CONNECTIONS_ADDED] =
|
|
g_signal_new ("connections-added",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, connections_added),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__UINT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_UINT);
|
|
|
|
signals[CONNECTION_ADDED] =
|
|
g_signal_new ("connection-added",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, connection_added),
|
|
NULL, NULL,
|
|
_nm_marshal_VOID__OBJECT_UINT,
|
|
G_TYPE_NONE, 2,
|
|
G_TYPE_OBJECT, G_TYPE_UINT);
|
|
|
|
signals[CONNECTION_UPDATED] =
|
|
g_signal_new ("connection-updated",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, connection_updated),
|
|
NULL, NULL,
|
|
_nm_marshal_VOID__OBJECT_UINT,
|
|
G_TYPE_NONE, 2,
|
|
G_TYPE_OBJECT, G_TYPE_UINT);
|
|
|
|
signals[CONNECTION_REMOVED] =
|
|
g_signal_new ("connection-removed",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMManagerClass, connection_removed),
|
|
NULL, NULL,
|
|
_nm_marshal_VOID__OBJECT_UINT,
|
|
G_TYPE_NONE, 2,
|
|
G_TYPE_OBJECT, G_TYPE_UINT);
|
|
|
|
/* StateChange is DEPRECATED */
|
|
signals[STATE_CHANGE] =
|
|
g_signal_new ("state-change",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__UINT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_UINT);
|
|
|
|
|
|
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
|
|
&dbus_glib_nm_manager_object_info);
|
|
|
|
dbus_g_error_domain_register (NM_MANAGER_ERROR, NULL, NM_TYPE_MANAGER_ERROR);
|
|
}
|
|
|
|
static NMConnectionScope
|
|
get_scope_for_proxy (DBusGProxy *proxy)
|
|
{
|
|
const char *bus_name = dbus_g_proxy_get_bus_name (proxy);
|
|
|
|
if (strcmp (bus_name, NM_DBUS_SERVICE_USER_SETTINGS) == 0)
|
|
return NM_CONNECTION_SCOPE_USER;
|
|
else if (strcmp (bus_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS) == 0)
|
|
return NM_CONNECTION_SCOPE_SYSTEM;
|
|
|
|
return NM_CONNECTION_SCOPE_UNKNOWN;
|
|
}
|
|
|
|
typedef struct GetSettingsInfo {
|
|
NMManager *manager;
|
|
NMConnection *connection;
|
|
DBusGProxy *proxy;
|
|
DBusGProxyCall *call;
|
|
DBusGProxy *secrets_proxy;
|
|
GSList **calls;
|
|
NMConnectionScope scope;
|
|
} GetSettingsInfo;
|
|
|
|
static void
|
|
free_get_settings_info (gpointer data)
|
|
{
|
|
GetSettingsInfo *info = (GetSettingsInfo *) data;
|
|
|
|
/* If this was the last pending call for a batch of GetSettings calls,
|
|
* send out the connections-added signal.
|
|
*/
|
|
if (info->calls) {
|
|
*(info->calls) = g_slist_remove (*(info->calls), info->call);
|
|
if (g_slist_length (*(info->calls)) == 0) {
|
|
g_slist_free (*(info->calls));
|
|
g_slice_free (GSList, (gpointer) info->calls);
|
|
g_signal_emit (info->manager, signals[CONNECTIONS_ADDED], 0, info->scope);
|
|
}
|
|
}
|
|
|
|
if (info->manager) {
|
|
g_object_unref (info->manager);
|
|
info->manager = NULL;
|
|
}
|
|
if (info->connection) {
|
|
g_object_unref (info->connection);
|
|
info->connection = NULL;
|
|
}
|
|
|
|
g_slice_free (GetSettingsInfo, data);
|
|
}
|
|
|
|
static void
|
|
connection_get_settings_cb (DBusGProxy *proxy,
|
|
DBusGProxyCall *call_id,
|
|
gpointer user_data)
|
|
{
|
|
GetSettingsInfo *info = (GetSettingsInfo *) user_data;
|
|
GError *err = NULL;
|
|
GHashTable *settings = NULL;
|
|
NMConnection *connection;
|
|
NMConnectionScope scope;
|
|
NMManager *manager;
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
if (!dbus_g_proxy_end_call (proxy, call_id, &err,
|
|
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
|
|
G_TYPE_INVALID)) {
|
|
nm_warning ("Couldn't retrieve connection settings: %s.", err->message);
|
|
g_error_free (err);
|
|
goto out;
|
|
}
|
|
|
|
manager = info->manager;
|
|
connection = info->connection;
|
|
if (connection == NULL) {
|
|
const char *path = dbus_g_proxy_get_path (proxy);
|
|
NMManagerPrivate *priv;
|
|
GError *error = NULL;
|
|
NMConnection *existing = NULL;
|
|
|
|
connection = nm_connection_new_from_hash (settings, &error);
|
|
if (connection == NULL) {
|
|
nm_warning ("%s: Invalid connection: '%s' / '%s' invalid: %d",
|
|
__func__,
|
|
g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
|
|
error->message, error->code);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
scope = get_scope_for_proxy (proxy);
|
|
|
|
nm_connection_set_path (connection, path);
|
|
nm_connection_set_scope (connection, scope);
|
|
|
|
g_object_set_data_full (G_OBJECT (connection),
|
|
NM_MANAGER_CONNECTION_PROXY_TAG,
|
|
proxy,
|
|
(GDestroyNotify) g_object_unref);
|
|
|
|
g_object_set_data_full (G_OBJECT (connection),
|
|
NM_MANAGER_CONNECTION_SECRETS_PROXY_TAG,
|
|
info->secrets_proxy,
|
|
(GDestroyNotify) g_object_unref);
|
|
|
|
/* Add the new connection to the internal hashes only if the same
|
|
* connection isn't already there.
|
|
*/
|
|
priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
switch (scope) {
|
|
case NM_CONNECTION_SCOPE_USER:
|
|
existing = g_hash_table_lookup (priv->user_connections, path);
|
|
if (!existing || !nm_connection_compare (existing, connection, NM_SETTING_COMPARE_FLAG_EXACT)) {
|
|
g_hash_table_insert (priv->user_connections,
|
|
g_strdup (path),
|
|
connection);
|
|
existing = NULL;
|
|
} else {
|
|
g_object_unref (connection);
|
|
}
|
|
break;
|
|
case NM_CONNECTION_SCOPE_SYSTEM:
|
|
existing = g_hash_table_lookup (priv->system_connections, path);
|
|
if (!existing || !nm_connection_compare (existing, connection, NM_SETTING_COMPARE_FLAG_EXACT)) {
|
|
g_hash_table_insert (priv->system_connections,
|
|
g_strdup (path),
|
|
connection);
|
|
existing = NULL;
|
|
} else {
|
|
g_object_unref (connection);
|
|
}
|
|
break;
|
|
default:
|
|
nm_warning ("Connection wasn't a user connection or a system connection.");
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
|
|
/* If the connection-added signal is supposed to be batched, don't
|
|
* emit the single connection-added here. Also, don't emit the signal
|
|
* if the connection wasn't actually added to the system or user hashes.
|
|
*/
|
|
if (!info->calls && !existing)
|
|
g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, scope);
|
|
} else {
|
|
// FIXME: merge settings? or just replace?
|
|
nm_warning ("%s (#%d): implement merge settings", __func__, __LINE__);
|
|
}
|
|
|
|
out:
|
|
if (settings)
|
|
g_hash_table_destroy (settings);
|
|
|
|
return;
|
|
}
|
|
|
|
static NMConnection *
|
|
get_connection_for_proxy (NMManager *manager,
|
|
DBusGProxy *proxy,
|
|
GHashTable **out_hash)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
NMConnection *connection = NULL;
|
|
const char *path = dbus_g_proxy_get_path (proxy);
|
|
|
|
switch (get_scope_for_proxy (proxy)) {
|
|
case NM_CONNECTION_SCOPE_USER:
|
|
*out_hash = priv->user_connections;
|
|
connection = g_hash_table_lookup (priv->user_connections, path);
|
|
break;
|
|
case NM_CONNECTION_SCOPE_SYSTEM:
|
|
*out_hash = priv->system_connections;
|
|
connection = g_hash_table_lookup (priv->system_connections, path);
|
|
break;
|
|
default:
|
|
nm_warning ("Connection wasn't a user connection or a system connection.");
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
return connection;
|
|
}
|
|
|
|
static void
|
|
remove_connection (NMManager *manager,
|
|
NMConnection *connection,
|
|
GHashTable *hash)
|
|
{
|
|
/* Destroys the connection, then associated DBusGProxy due to the
|
|
* weak reference notify function placed on the connection when it
|
|
* was created.
|
|
*/
|
|
g_object_ref (connection);
|
|
g_hash_table_remove (hash, nm_connection_get_path (connection));
|
|
g_signal_emit (manager, signals[CONNECTION_REMOVED], 0,
|
|
connection,
|
|
nm_connection_get_scope (connection));
|
|
g_object_unref (connection);
|
|
}
|
|
|
|
static void
|
|
connection_removed_cb (DBusGProxy *proxy, gpointer user_data)
|
|
{
|
|
NMManager * manager = NM_MANAGER (user_data);
|
|
NMConnection *connection = NULL;
|
|
GHashTable *hash = NULL;
|
|
|
|
connection = get_connection_for_proxy (manager, proxy, &hash);
|
|
if (connection)
|
|
remove_connection (manager, connection, hash);
|
|
}
|
|
|
|
static void
|
|
connection_updated_cb (DBusGProxy *proxy, GHashTable *settings, gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
NMConnection *new_connection;
|
|
NMConnection *old_connection;
|
|
GHashTable *hash;
|
|
gboolean valid = FALSE;
|
|
GError *error = NULL;
|
|
|
|
old_connection = get_connection_for_proxy (manager, proxy, &hash);
|
|
g_return_if_fail (old_connection != NULL);
|
|
|
|
new_connection = nm_connection_new_from_hash (settings, &error);
|
|
if (!new_connection) {
|
|
/* New connection invalid, remove existing connection */
|
|
nm_warning ("%s: Invalid connection: '%s' / '%s' invalid: %d",
|
|
__func__,
|
|
g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
|
|
error->message, error->code);
|
|
g_error_free (error);
|
|
remove_connection (manager, old_connection, hash);
|
|
return;
|
|
}
|
|
g_object_unref (new_connection);
|
|
|
|
valid = nm_connection_replace_settings (old_connection, settings, NULL);
|
|
if (valid) {
|
|
g_signal_emit (manager, signals[CONNECTION_UPDATED], 0,
|
|
old_connection,
|
|
nm_connection_get_scope (old_connection));
|
|
} else {
|
|
remove_connection (manager, old_connection, hash);
|
|
}
|
|
}
|
|
|
|
static void
|
|
internal_new_connection_cb (DBusGProxy *proxy,
|
|
const char *path,
|
|
NMManager *manager,
|
|
GSList **calls)
|
|
{
|
|
struct GetSettingsInfo *info;
|
|
DBusGProxy *con_proxy;
|
|
DBusGConnection * g_connection;
|
|
DBusGProxyCall *call;
|
|
DBusGProxy *secrets_proxy;
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
|
con_proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
dbus_g_proxy_get_bus_name (proxy),
|
|
path,
|
|
NM_DBUS_IFACE_SETTINGS_CONNECTION);
|
|
if (!con_proxy) {
|
|
nm_warning ("Error: could not init user connection proxy");
|
|
return;
|
|
}
|
|
|
|
secrets_proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
dbus_g_proxy_get_bus_name (proxy),
|
|
path,
|
|
NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS);
|
|
if (!secrets_proxy) {
|
|
nm_warning ("Error: could not init user connection secrets proxy");
|
|
g_object_unref (con_proxy);
|
|
return;
|
|
}
|
|
|
|
dbus_g_proxy_add_signal (con_proxy, "Updated",
|
|
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT,
|
|
G_TYPE_INVALID);
|
|
dbus_g_proxy_connect_signal (con_proxy, "Updated",
|
|
G_CALLBACK (connection_updated_cb),
|
|
manager,
|
|
NULL);
|
|
|
|
dbus_g_proxy_add_signal (con_proxy, "Removed", G_TYPE_INVALID, G_TYPE_INVALID);
|
|
dbus_g_proxy_connect_signal (con_proxy, "Removed",
|
|
G_CALLBACK (connection_removed_cb),
|
|
manager,
|
|
NULL);
|
|
|
|
info = g_slice_new0 (GetSettingsInfo);
|
|
info->manager = g_object_ref (manager);
|
|
info->calls = calls;
|
|
info->scope = get_scope_for_proxy (con_proxy);
|
|
call = dbus_g_proxy_begin_call (con_proxy, "GetSettings",
|
|
connection_get_settings_cb,
|
|
info,
|
|
free_get_settings_info,
|
|
G_TYPE_INVALID);
|
|
info->call = call;
|
|
info->proxy = con_proxy;
|
|
info->secrets_proxy = secrets_proxy;
|
|
if (info->calls)
|
|
*(info->calls) = g_slist_prepend (*(info->calls), call);
|
|
}
|
|
|
|
static void
|
|
list_connections_cb (DBusGProxy *proxy,
|
|
DBusGProxyCall *call_id,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
GError *err = NULL;
|
|
GPtrArray *ops;
|
|
GSList **calls = NULL;
|
|
int i;
|
|
|
|
if (!dbus_g_proxy_end_call (proxy, call_id, &err,
|
|
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &ops,
|
|
G_TYPE_INVALID)) {
|
|
nm_warning ("Couldn't retrieve connections: %s.", err->message);
|
|
g_error_free (err);
|
|
goto out;
|
|
}
|
|
|
|
/* Keep track of all calls made here; don't want to emit connection-added for
|
|
* each one, but emit connections-added when they are all done.
|
|
*/
|
|
calls = g_slice_new0 (GSList *);
|
|
|
|
for (i = 0; i < ops->len; i++) {
|
|
char *op = g_ptr_array_index (ops, i);
|
|
|
|
internal_new_connection_cb (proxy, op, manager, calls);
|
|
g_free (op);
|
|
}
|
|
|
|
g_ptr_array_free (ops, TRUE);
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data)
|
|
{
|
|
internal_new_connection_cb (proxy, path, NM_MANAGER (user_data), NULL);
|
|
}
|
|
|
|
static void
|
|
query_connections (NMManager *manager,
|
|
NMConnectionScope scope)
|
|
{
|
|
NMManagerPrivate *priv;
|
|
DBusGProxyCall *call;
|
|
DBusGProxy ** proxy;
|
|
const char * service;
|
|
|
|
g_return_if_fail (NM_IS_MANAGER (manager));
|
|
|
|
priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
if (scope == NM_CONNECTION_SCOPE_USER) {
|
|
proxy = &priv->user_proxy;
|
|
service = NM_DBUS_SERVICE_USER_SETTINGS;
|
|
} else if (scope == NM_CONNECTION_SCOPE_SYSTEM) {
|
|
proxy = &priv->system_proxy;
|
|
service = NM_DBUS_SERVICE_SYSTEM_SETTINGS;
|
|
} else {
|
|
nm_warning ("Unknown NMConnectionScope %d", scope);
|
|
return;
|
|
}
|
|
|
|
if (!*proxy) {
|
|
DBusGConnection * g_connection;
|
|
|
|
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
|
*proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
service,
|
|
NM_DBUS_PATH_SETTINGS,
|
|
NM_DBUS_IFACE_SETTINGS);
|
|
if (!*proxy) {
|
|
nm_warning ("Error: could not init settings proxy");
|
|
return;
|
|
}
|
|
|
|
dbus_g_proxy_add_signal (*proxy,
|
|
"NewConnection",
|
|
DBUS_TYPE_G_OBJECT_PATH,
|
|
G_TYPE_INVALID);
|
|
|
|
dbus_g_proxy_connect_signal (*proxy, "NewConnection",
|
|
G_CALLBACK (new_connection_cb),
|
|
manager,
|
|
NULL);
|
|
}
|
|
|
|
/* grab connections */
|
|
call = dbus_g_proxy_begin_call (*proxy, "ListConnections",
|
|
list_connections_cb,
|
|
manager,
|
|
NULL,
|
|
G_TYPE_INVALID);
|
|
}
|
|
|
|
static NMDevice *
|
|
nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
|
|
{
|
|
GSList *iter;
|
|
|
|
for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
|
|
if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
|
|
return NM_DEVICE (iter->data);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static gboolean
|
|
nm_manager_udi_is_managed (NMManager *self, const char *udi)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
GSList *iter;
|
|
|
|
for (iter = priv->unmanaged_udis; iter; iter = iter->next) {
|
|
if (!strcmp (udi, iter->data))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
handle_unmanaged_devices (NMManager *manager, GPtrArray *ops)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
int i;
|
|
GSList *unmanaged = NULL, *iter;
|
|
|
|
g_slist_foreach (priv->unmanaged_udis, (GFunc) g_free, NULL);
|
|
g_slist_free (priv->unmanaged_udis);
|
|
priv->unmanaged_udis = NULL;
|
|
|
|
/* Mark unmanaged devices */
|
|
for (i = 0; ops && (i < ops->len); i++) {
|
|
NMDevice *device;
|
|
const char *udi = g_ptr_array_index (ops, i);
|
|
|
|
priv->unmanaged_udis = g_slist_prepend (priv->unmanaged_udis, g_strdup (udi));
|
|
|
|
device = nm_manager_get_device_by_udi (manager, udi);
|
|
if (device) {
|
|
unmanaged = g_slist_prepend (unmanaged, device);
|
|
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
|
|
}
|
|
}
|
|
|
|
/* Mark managed devices */
|
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
|
NMDevice *device = NM_DEVICE (iter->data);
|
|
|
|
if (!g_slist_find (unmanaged, device))
|
|
nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
|
}
|
|
|
|
g_slist_free (unmanaged);
|
|
}
|
|
|
|
static void
|
|
handle_hostname (NMManager *manager, const char *hostname)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (!hostname && !priv->hostname)
|
|
return;
|
|
|
|
if (hostname && priv->hostname && !strcmp (hostname, priv->hostname))
|
|
return;
|
|
|
|
g_free (priv->hostname);
|
|
priv->hostname = (hostname && strlen (hostname)) ? g_strdup (hostname) : NULL;
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_HOSTNAME);
|
|
}
|
|
|
|
static void
|
|
system_settings_properties_changed_cb (DBusGProxy *proxy,
|
|
GHashTable *properties,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
GValue *value;
|
|
|
|
value = g_hash_table_lookup (properties, "UnmanagedDevices");
|
|
if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH))
|
|
handle_unmanaged_devices (manager, g_value_get_boxed (value));
|
|
|
|
value = g_hash_table_lookup (properties, "Hostname");
|
|
if (value && G_VALUE_HOLDS (value, G_TYPE_STRING))
|
|
handle_hostname (manager, g_value_get_string (value));
|
|
}
|
|
|
|
static void
|
|
system_settings_get_unmanaged_devices_cb (DBusGProxy *proxy,
|
|
DBusGProxyCall *call_id,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
GError *error = NULL;
|
|
GValue value = { 0, };
|
|
|
|
if (!dbus_g_proxy_end_call (proxy, call_id, &error,
|
|
G_TYPE_VALUE, &value,
|
|
G_TYPE_INVALID)) {
|
|
nm_warning ("%s: Error getting unmanaged devices from the system "
|
|
"settings service: (%d) %s",
|
|
__func__, error->code, error->message);
|
|
g_error_free (error);
|
|
g_object_unref (proxy);
|
|
return;
|
|
}
|
|
|
|
if (G_VALUE_HOLDS (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH))
|
|
handle_unmanaged_devices (manager, g_value_get_boxed (&value));
|
|
|
|
g_value_unset (&value);
|
|
g_object_unref (proxy);
|
|
}
|
|
|
|
static void
|
|
system_settings_get_hostname_cb (DBusGProxy *proxy,
|
|
DBusGProxyCall *call_id,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
GError *error = NULL;
|
|
GValue value = { 0, };
|
|
|
|
if (!dbus_g_proxy_end_call (proxy, call_id, &error,
|
|
G_TYPE_VALUE, &value,
|
|
G_TYPE_INVALID)) {
|
|
nm_warning ("%s: Error getting hostname from the system settings service: (%d) %s",
|
|
__func__, error->code, error->message);
|
|
g_error_free (error);
|
|
g_object_unref (proxy);
|
|
return;
|
|
}
|
|
|
|
if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
|
|
handle_hostname (manager, g_value_get_string (&value));
|
|
|
|
g_value_unset (&value);
|
|
g_object_unref (proxy);
|
|
}
|
|
|
|
static void
|
|
query_system_settings_property (NMManager *manager,
|
|
const char *property,
|
|
DBusGProxyCallNotify callback)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
DBusGConnection *g_connection;
|
|
DBusGProxy *get_proxy;
|
|
|
|
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
|
|
|
/* Get unmanaged devices */
|
|
get_proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
NM_DBUS_SERVICE_SYSTEM_SETTINGS,
|
|
NM_DBUS_PATH_SETTINGS,
|
|
"org.freedesktop.DBus.Properties");
|
|
|
|
dbus_g_proxy_begin_call (get_proxy, "Get", callback, manager, NULL,
|
|
G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS_SYSTEM,
|
|
G_TYPE_STRING, property,
|
|
G_TYPE_INVALID);
|
|
}
|
|
|
|
static void
|
|
nm_manager_name_owner_changed (NMDBusManager *mgr,
|
|
const char *name,
|
|
const char *old,
|
|
const char *new,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
gboolean old_owner_good = (old && (strlen (old) > 0));
|
|
gboolean new_owner_good = (new && (strlen (new) > 0));
|
|
|
|
if (strcmp (name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) {
|
|
if (!old_owner_good && new_owner_good) {
|
|
/* User Settings service appeared, update stuff */
|
|
query_connections (manager, NM_CONNECTION_SCOPE_USER);
|
|
} else {
|
|
/* User Settings service disappeared, throw them away (?) */
|
|
nm_manager_connections_destroy (manager, NM_CONNECTION_SCOPE_USER);
|
|
}
|
|
} else if (strcmp (name, NM_DBUS_SERVICE_SYSTEM_SETTINGS) == 0) {
|
|
if (!old_owner_good && new_owner_good) {
|
|
if (priv->poke_id) {
|
|
g_source_remove (priv->poke_id);
|
|
priv->poke_id = 0;
|
|
}
|
|
|
|
/* System Settings service appeared, update stuff */
|
|
query_system_settings_property (manager, "UnmanagedDevices", system_settings_get_unmanaged_devices_cb);
|
|
query_system_settings_property (manager, "Hostname", system_settings_get_hostname_cb);
|
|
query_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
|
|
} else {
|
|
/* System Settings service disappeared, throw them away (?) */
|
|
nm_manager_connections_destroy (manager, NM_CONNECTION_SCOPE_SYSTEM);
|
|
|
|
if (priv->system_props_proxy) {
|
|
g_object_unref (priv->system_props_proxy);
|
|
priv->system_props_proxy = NULL;
|
|
}
|
|
|
|
if (priv->poke_id)
|
|
g_source_remove (priv->poke_id);
|
|
|
|
/* Poke the system settings daemon so that it gets activated by dbus
|
|
* system bus activation.
|
|
*/
|
|
priv->poke_id = g_idle_add (poke_system_settings_daemon_cb, (gpointer) manager);
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
poke_system_settings_daemon_cb (gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
DBusGConnection *g_connection;
|
|
DBusGProxy *proxy;
|
|
|
|
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
|
proxy = dbus_g_proxy_new_for_name (g_connection,
|
|
NM_DBUS_SERVICE_SYSTEM_SETTINGS,
|
|
NM_DBUS_PATH_SETTINGS,
|
|
NM_DBUS_IFACE_SETTINGS);
|
|
if (!proxy) {
|
|
nm_warning ("Error: could not init system settings daemon proxy");
|
|
goto out;
|
|
}
|
|
|
|
nm_info ("Trying to start the system settings daemon...");
|
|
dbus_g_proxy_call_no_reply (proxy, "ListConnections", G_TYPE_INVALID);
|
|
g_object_unref (proxy);
|
|
|
|
out:
|
|
/* Reschedule the poke */
|
|
priv->poke_id = g_timeout_add_seconds (SSD_POKE_INTERVAL, poke_system_settings_daemon_cb, (gpointer) manager);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
initial_get_connections (gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (nm_dbus_manager_name_has_owner (priv->dbus_mgr,
|
|
NM_DBUS_SERVICE_SYSTEM_SETTINGS)) {
|
|
query_system_settings_property (manager, "UnmanagedDevices", system_settings_get_unmanaged_devices_cb);
|
|
query_system_settings_property (manager, "Hostname", system_settings_get_hostname_cb);
|
|
query_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
|
|
} else {
|
|
/* Try to activate the system settings daemon */
|
|
priv->poke_id = g_idle_add (poke_system_settings_daemon_cb, (gpointer) manager);
|
|
}
|
|
|
|
if (nm_dbus_manager_name_has_owner (priv->dbus_mgr,
|
|
NM_DBUS_SERVICE_USER_SETTINGS))
|
|
query_connections (manager, NM_CONNECTION_SCOPE_USER);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
sync_devices (NMManager *self)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
GSList *devices;
|
|
GSList *iter;
|
|
|
|
/* Remove devices which are no longer known to HAL */
|
|
devices = g_slist_copy (priv->devices);
|
|
for (iter = devices; iter; iter = iter->next) {
|
|
NMDevice *device = NM_DEVICE (iter->data);
|
|
const char *udi = nm_device_get_udi (device);
|
|
|
|
if (nm_hal_manager_udi_exists (priv->hal_mgr, udi)) {
|
|
if (nm_manager_udi_is_managed (self, udi))
|
|
nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
|
else
|
|
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
|
|
} else {
|
|
priv->devices = g_slist_delete_link (priv->devices, iter);
|
|
remove_one_device (self, device);
|
|
}
|
|
}
|
|
|
|
g_slist_free (devices);
|
|
|
|
/* Get any new ones */
|
|
nm_hal_manager_query_devices (priv->hal_mgr);
|
|
}
|
|
|
|
static gboolean
|
|
deferred_sync_devices (gpointer user_data)
|
|
{
|
|
NMManager *self = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
|
|
priv->sync_devices_id = 0;
|
|
sync_devices (self);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NMManager *
|
|
nm_manager_get (void)
|
|
{
|
|
static NMManager *singleton = NULL;
|
|
NMManagerPrivate *priv;
|
|
|
|
if (singleton)
|
|
return g_object_ref (singleton);
|
|
|
|
singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL);
|
|
g_assert (singleton);
|
|
|
|
priv = NM_MANAGER_GET_PRIVATE (singleton);
|
|
|
|
dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
|
|
NM_DBUS_PATH,
|
|
G_OBJECT (singleton));
|
|
|
|
g_signal_connect (priv->dbus_mgr,
|
|
"name-owner-changed",
|
|
G_CALLBACK (nm_manager_name_owner_changed),
|
|
singleton);
|
|
|
|
g_idle_add ((GSourceFunc) initial_get_connections, singleton);
|
|
|
|
priv->hal_mgr = nm_hal_manager_new ();
|
|
priv->sync_devices_id = g_idle_add (deferred_sync_devices, singleton);
|
|
|
|
g_signal_connect (priv->hal_mgr,
|
|
"udi-added",
|
|
G_CALLBACK (hal_manager_udi_added_cb),
|
|
singleton);
|
|
|
|
g_signal_connect (priv->hal_mgr,
|
|
"udi-removed",
|
|
G_CALLBACK (hal_manager_udi_removed_cb),
|
|
singleton);
|
|
|
|
g_signal_connect (priv->hal_mgr,
|
|
"rfkill-changed",
|
|
G_CALLBACK (hal_manager_rfkill_changed_cb),
|
|
singleton);
|
|
|
|
g_signal_connect (priv->hal_mgr,
|
|
"hal-reappeared",
|
|
G_CALLBACK (hal_manager_hal_reappeared_cb),
|
|
singleton);
|
|
|
|
return singleton;
|
|
}
|
|
|
|
static void
|
|
emit_removed (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
NMConnection *connection = NM_CONNECTION (value);
|
|
|
|
g_signal_emit (manager, signals[CONNECTION_REMOVED], 0,
|
|
connection,
|
|
nm_connection_get_scope (connection));
|
|
}
|
|
|
|
static void
|
|
nm_manager_connections_destroy (NMManager *manager,
|
|
NMConnectionScope scope)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (scope == NM_CONNECTION_SCOPE_USER) {
|
|
if (priv->user_connections) {
|
|
g_hash_table_foreach (priv->user_connections, emit_removed, manager);
|
|
g_hash_table_remove_all (priv->user_connections);
|
|
}
|
|
|
|
if (priv->user_proxy) {
|
|
g_object_unref (priv->user_proxy);
|
|
priv->user_proxy = NULL;
|
|
}
|
|
} else if (scope == NM_CONNECTION_SCOPE_SYSTEM) {
|
|
if (priv->system_connections) {
|
|
g_hash_table_foreach (priv->system_connections, emit_removed, manager);
|
|
g_hash_table_remove_all (priv->system_connections);
|
|
}
|
|
|
|
if (priv->system_proxy) {
|
|
g_object_unref (priv->system_proxy);
|
|
priv->system_proxy = NULL;
|
|
}
|
|
} else {
|
|
nm_warning ("Unknown NMConnectionScope %d", scope);
|
|
}
|
|
}
|
|
|
|
static void
|
|
manager_set_wireless_enabled (NMManager *manager, gboolean enabled)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
GSList *iter;
|
|
|
|
if (priv->wireless_enabled == enabled)
|
|
return;
|
|
|
|
/* Can't set wireless enabled if it's disabled in hardware */
|
|
if (!priv->wireless_hw_enabled && enabled)
|
|
return;
|
|
|
|
priv->wireless_enabled = enabled;
|
|
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_WIRELESS_ENABLED);
|
|
|
|
/* Don't touch devices if asleep/networking disabled */
|
|
if (priv->sleeping)
|
|
return;
|
|
|
|
/* enable/disable wireless devices as required */
|
|
for (iter = priv->devices; iter; iter = iter->next) {
|
|
if (NM_IS_DEVICE_WIFI (iter->data))
|
|
nm_device_wifi_set_enabled (NM_DEVICE_WIFI (iter->data), enabled);
|
|
}
|
|
}
|
|
|
|
static void
|
|
manager_hidden_ap_found (NMDeviceInterface *device,
|
|
NMAccessPoint *ap,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (user_data);
|
|
const struct ether_addr *ap_addr;
|
|
const GByteArray *ap_ssid;
|
|
GSList *iter;
|
|
GSList *connections;
|
|
gboolean done = FALSE;
|
|
|
|
ap_ssid = nm_ap_get_ssid (ap);
|
|
if (ap_ssid && ap_ssid->len)
|
|
return;
|
|
|
|
ap_addr = nm_ap_get_address (ap);
|
|
g_assert (ap_addr);
|
|
|
|
/* Look for this AP's BSSID in the seen-bssids list of a connection,
|
|
* and if a match is found, copy over the SSID */
|
|
connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
|
|
connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER));
|
|
|
|
for (iter = connections; iter && !done; iter = g_slist_next (iter)) {
|
|
NMConnection *connection = NM_CONNECTION (iter->data);
|
|
NMSettingWireless *s_wireless;
|
|
const GByteArray *ssid;
|
|
guint32 num_bssids;
|
|
guint32 i;
|
|
|
|
s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
|
|
if (!s_wireless)
|
|
goto next;
|
|
|
|
num_bssids = nm_setting_wireless_get_num_seen_bssids (s_wireless);
|
|
if (num_bssids < 1)
|
|
goto next;
|
|
|
|
ssid = nm_setting_wireless_get_ssid (s_wireless);
|
|
g_assert (ssid);
|
|
|
|
for (i = 0; i < num_bssids; i++) {
|
|
const char *seen_bssid = nm_setting_wireless_get_seen_bssid (s_wireless, i);
|
|
struct ether_addr seen_addr;
|
|
|
|
if (!ether_aton_r (seen_bssid, &seen_addr))
|
|
continue;
|
|
|
|
if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr)))
|
|
continue;
|
|
|
|
/* Copy the SSID from the connection to the AP */
|
|
nm_ap_set_ssid (ap, ssid);
|
|
done = TRUE;
|
|
}
|
|
|
|
next:
|
|
g_object_unref (connection);
|
|
}
|
|
g_slist_free (connections);
|
|
}
|
|
|
|
static void
|
|
hal_manager_udi_added_cb (NMHalManager *hal_mgr,
|
|
const char *udi,
|
|
const char *originating_device,
|
|
gpointer general_type_ptr,
|
|
NMDeviceCreatorFn creator_fn,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *self = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
GObject *device;
|
|
const char *iface, *driver;
|
|
GType general_type = GPOINTER_TO_SIZE (general_type_ptr);
|
|
|
|
if (priv->sleeping)
|
|
return;
|
|
|
|
/* Make sure the device is not already in the device list */
|
|
if (nm_manager_get_device_by_udi (self, udi))
|
|
return;
|
|
|
|
device = creator_fn (hal_mgr, udi, originating_device, nm_manager_udi_is_managed (self, udi));
|
|
if (!device)
|
|
return;
|
|
|
|
priv->devices = g_slist_append (priv->devices, device);
|
|
|
|
g_signal_connect (device, "state-changed",
|
|
G_CALLBACK (manager_device_state_changed),
|
|
self);
|
|
|
|
/* Attach to the access-point-added signal so that the manager can fill
|
|
* non-SSID-broadcasting APs with an SSID.
|
|
*/
|
|
if (NM_IS_DEVICE_WIFI (device)) {
|
|
g_signal_connect (device, "hidden-ap-found",
|
|
G_CALLBACK (manager_hidden_ap_found),
|
|
self);
|
|
|
|
/* Set initial rfkill state */
|
|
nm_device_wifi_set_enabled (NM_DEVICE_WIFI (device), priv->wireless_enabled);
|
|
}
|
|
|
|
iface = nm_device_get_iface (NM_DEVICE (device));
|
|
driver = nm_device_get_driver (NM_DEVICE (device));
|
|
if (!driver)
|
|
driver = "unknown";
|
|
|
|
if (general_type == NM_TYPE_DEVICE_ETHERNET)
|
|
nm_info ("(%s): new Ethernet device (driver: '%s')", iface, driver);
|
|
else if (general_type == NM_TYPE_DEVICE_WIFI)
|
|
nm_info ("(%s): new 802.11 WiFi device (driver: '%s')", iface, driver);
|
|
else if (general_type == NM_TYPE_SERIAL_DEVICE)
|
|
nm_info ("(%s): new Modem device (driver: '%s')", iface, driver);
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
|
|
nm_device_get_udi (NM_DEVICE (device)),
|
|
device);
|
|
nm_info ("(%s): exported as %s", iface, udi);
|
|
|
|
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
|
|
}
|
|
|
|
static void
|
|
hal_manager_udi_removed_cb (NMHalManager *manager,
|
|
const char *udi,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *self = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
GSList *iter;
|
|
|
|
g_return_if_fail (udi != NULL);
|
|
|
|
for (iter = priv->devices; iter; iter = iter->next) {
|
|
NMDevice *device = NM_DEVICE (iter->data);
|
|
|
|
if (!strcmp (nm_device_get_udi (device), udi)) {
|
|
priv->devices = g_slist_delete_link (priv->devices, iter);
|
|
remove_one_device (self, device);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
hal_manager_rfkill_changed_cb (NMHalManager *hal_mgr,
|
|
gboolean rfkilled,
|
|
gpointer user_data)
|
|
{
|
|
NMManager *self = NM_MANAGER (user_data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
|
gboolean enabled = !rfkilled;
|
|
|
|
if (priv->wireless_hw_enabled != enabled) {
|
|
nm_info ("Wireless now %s by radio killswitch", enabled ? "enabled" : "disabled");
|
|
priv->wireless_hw_enabled = enabled;
|
|
g_object_notify (G_OBJECT (self), NM_MANAGER_WIRELESS_HARDWARE_ENABLED);
|
|
|
|
manager_set_wireless_enabled (self, enabled);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hal_manager_hal_reappeared_cb (NMHalManager *hal_mgr,
|
|
gpointer user_data)
|
|
{
|
|
sync_devices (NM_MANAGER (user_data));
|
|
}
|
|
|
|
GSList *
|
|
nm_manager_get_devices (NMManager *manager)
|
|
{
|
|
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
|
|
|
|
return NM_MANAGER_GET_PRIVATE (manager)->devices;
|
|
}
|
|
|
|
static gboolean
|
|
impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
GSList *iter;
|
|
|
|
*devices = g_ptr_array_sized_new (g_slist_length (priv->devices));
|
|
|
|
for (iter = priv->devices; iter; iter = iter->next)
|
|
g_ptr_array_add (*devices, g_strdup (nm_device_get_udi (NM_DEVICE (iter->data))));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static NMActRequest *
|
|
nm_manager_get_act_request_by_path (NMManager *manager,
|
|
const char *path,
|
|
NMDevice **device)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
GSList *iter;
|
|
|
|
g_return_val_if_fail (manager != NULL, NULL);
|
|
g_return_val_if_fail (path != NULL, NULL);
|
|
g_return_val_if_fail (device != NULL, NULL);
|
|
g_return_val_if_fail (*device == NULL, NULL);
|
|
|
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
|
NMActRequest *req;
|
|
const char *ac_path;
|
|
|
|
req = nm_device_get_act_request (NM_DEVICE (iter->data));
|
|
if (!req)
|
|
continue;
|
|
|
|
ac_path = nm_act_request_get_active_connection_path (req);
|
|
if (!strcmp (path, ac_path)) {
|
|
*device = NM_DEVICE (iter->data);
|
|
return req;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const char *
|
|
internal_activate_device (NMManager *manager,
|
|
NMDevice *device,
|
|
NMConnection *connection,
|
|
const char *specific_object,
|
|
gboolean user_requested,
|
|
GError **error)
|
|
{
|
|
NMActRequest *req;
|
|
NMDeviceInterface *dev_iface;
|
|
gboolean success;
|
|
|
|
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
|
|
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
|
|
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
|
|
|
dev_iface = NM_DEVICE_INTERFACE (device);
|
|
|
|
/* Ensure the requested connection is compatible with the device */
|
|
if (!nm_device_interface_check_connection_compatible (dev_iface, connection, error))
|
|
return NULL;
|
|
|
|
/* Tear down any existing connection */
|
|
if (nm_device_get_act_request (device)) {
|
|
nm_device_state_changed (device,
|
|
NM_DEVICE_STATE_DISCONNECTED,
|
|
NM_DEVICE_STATE_REASON_NONE);
|
|
}
|
|
|
|
req = nm_act_request_new (connection, specific_object, user_requested, (gpointer) device);
|
|
success = nm_device_interface_activate (dev_iface, req, error);
|
|
g_object_unref (req);
|
|
|
|
return success ? nm_act_request_get_active_connection_path (req) : NULL;
|
|
}
|
|
|
|
static gboolean
|
|
wait_for_connection_expired (gpointer data)
|
|
{
|
|
NMManager *manager = NM_MANAGER (data);
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
PendingConnectionInfo *info = priv->pending_connection_info;
|
|
GError *error = NULL;
|
|
|
|
g_return_val_if_fail (info != NULL, FALSE);
|
|
|
|
g_set_error (&error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
|
|
"%s", "Connection was not provided by any settings service");
|
|
nm_warning ("Connection (%d) %s failed to activate (timeout): (%d) %s",
|
|
info->scope, info->connection_path, error->code, error->message);
|
|
dbus_g_method_return_error (info->context, error);
|
|
g_error_free (error);
|
|
|
|
info->timeout_id = 0;
|
|
pending_connection_info_destroy (priv->pending_connection_info);
|
|
priv->pending_connection_info = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
const char *
|
|
nm_manager_activate_connection (NMManager *manager,
|
|
NMConnection *connection,
|
|
const char *specific_object,
|
|
const char *device_path,
|
|
gboolean user_requested,
|
|
GError **error)
|
|
{
|
|
NMDevice *device = NULL;
|
|
char *path = NULL;
|
|
NMSettingConnection *s_con;
|
|
|
|
g_return_val_if_fail (manager != NULL, NULL);
|
|
g_return_val_if_fail (connection != NULL, NULL);
|
|
g_return_val_if_fail (error != NULL, NULL);
|
|
g_return_val_if_fail (*error == NULL, NULL);
|
|
|
|
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
|
|
g_assert (s_con);
|
|
|
|
if (!strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_VPN_SETTING_NAME)) {
|
|
NMActRequest *req;
|
|
NMVPNManager *vpn_manager;
|
|
|
|
/* VPN connection */
|
|
req = nm_manager_get_act_request_by_path (manager, specific_object, &device);
|
|
if (!req) {
|
|
g_set_error (error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
|
|
"%s", "Base connection for VPN connection not active.");
|
|
return NULL;
|
|
}
|
|
|
|
if (!device) {
|
|
g_set_error (error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
|
|
"%s", "Source connection had no active device.");
|
|
return NULL;
|
|
}
|
|
|
|
vpn_manager = nm_vpn_manager_get ();
|
|
path = (char *) nm_vpn_manager_activate_connection (vpn_manager,
|
|
connection,
|
|
req,
|
|
device,
|
|
error);
|
|
g_object_unref (vpn_manager);
|
|
} else {
|
|
NMDeviceState state;
|
|
|
|
/* Device-based connection */
|
|
device = nm_manager_get_device_by_udi (manager, device_path);
|
|
if (!device) {
|
|
g_set_error (error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
|
|
"%s", "Device not found");
|
|
return NULL;
|
|
}
|
|
|
|
state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
|
|
if (state < NM_DEVICE_STATE_DISCONNECTED) {
|
|
g_set_error (error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
|
|
"%s", "Device not managed by NetworkManager");
|
|
return NULL;
|
|
}
|
|
|
|
path = (char *) internal_activate_device (manager,
|
|
device,
|
|
connection,
|
|
specific_object,
|
|
user_requested,
|
|
error);
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
static void
|
|
connection_added_default_handler (NMManager *manager,
|
|
NMConnection *connection,
|
|
NMConnectionScope scope)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
PendingConnectionInfo *info = priv->pending_connection_info;
|
|
const char *path;
|
|
GError *error = NULL;
|
|
|
|
if (!info)
|
|
return;
|
|
|
|
if (scope != info->scope)
|
|
return;
|
|
|
|
if (strcmp (info->connection_path, nm_connection_get_path (connection)))
|
|
return;
|
|
|
|
/* Will destroy below; can't be valid during the initial activation start */
|
|
priv->pending_connection_info = NULL;
|
|
|
|
path = nm_manager_activate_connection (manager,
|
|
connection,
|
|
info->specific_object_path,
|
|
info->device_path,
|
|
TRUE,
|
|
&error);
|
|
if (path) {
|
|
dbus_g_method_return (info->context, path);
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
|
|
} else {
|
|
dbus_g_method_return_error (info->context, error);
|
|
nm_warning ("Connection (%d) %s failed to activate: (%d) %s",
|
|
scope, info->connection_path, error->code, error->message);
|
|
g_error_free (error);
|
|
}
|
|
|
|
pending_connection_info_destroy (info);
|
|
}
|
|
|
|
static gboolean
|
|
is_user_request_authorized (NMManager *manager,
|
|
DBusGMethodInvocation *context,
|
|
GError **error)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
DBusConnection *connection;
|
|
char *sender = NULL;
|
|
gulong sender_uid = G_MAXULONG;
|
|
DBusError dbus_error;
|
|
char *service_owner = NULL;
|
|
const char *service_name;
|
|
gulong service_uid = G_MAXULONG;
|
|
gboolean success = FALSE;
|
|
|
|
/* Ensure the request to activate the user connection came from the
|
|
* same session as the user settings service. FIXME: use ConsoleKit
|
|
* too.
|
|
*/
|
|
if (!priv->user_proxy) {
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_INVALID_SERVICE,
|
|
"%s", "No user settings service available");
|
|
goto out;
|
|
}
|
|
|
|
sender = dbus_g_method_get_sender (context);
|
|
if (!sender) {
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Could not determine D-Bus requestor");
|
|
goto out;
|
|
}
|
|
|
|
connection = nm_dbus_manager_get_dbus_connection (priv->dbus_mgr);
|
|
if (!connection) {
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Could not get the D-Bus system bus");
|
|
goto out;
|
|
}
|
|
|
|
dbus_error_init (&dbus_error);
|
|
/* FIXME: do this async */
|
|
sender_uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
|
|
if (dbus_error_is_set (&dbus_error)) {
|
|
dbus_error_free (&dbus_error);
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Could not determine the Unix user ID of the requestor");
|
|
goto out;
|
|
}
|
|
|
|
/* Let root activate anything.
|
|
* FIXME: use a PolicyKit permission instead
|
|
*/
|
|
if (0 == sender_uid) {
|
|
success = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
service_name = dbus_g_proxy_get_bus_name (priv->user_proxy);
|
|
if (!service_name) {
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Could not determine user settings service name");
|
|
goto out;
|
|
}
|
|
|
|
service_owner = nm_dbus_manager_get_name_owner (priv->dbus_mgr, service_name, NULL);
|
|
if (!service_owner) {
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Could not determine D-Bus owner of the user settings service");
|
|
goto out;
|
|
}
|
|
|
|
dbus_error_init (&dbus_error);
|
|
/* FIXME: do this async */
|
|
service_uid = dbus_bus_get_unix_user (connection, service_owner, &dbus_error);
|
|
if (dbus_error_is_set (&dbus_error)) {
|
|
dbus_error_free (&dbus_error);
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Could not determine the Unix UID of the sender of the request");
|
|
goto out;
|
|
}
|
|
|
|
/* And finally, the actual UID check */
|
|
if (sender_uid != service_uid) {
|
|
g_set_error (error, NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
|
"%s", "Requestor UID does not match the UID of the user settings service");
|
|
goto out;
|
|
}
|
|
|
|
success = TRUE;
|
|
|
|
out:
|
|
g_free (sender);
|
|
g_free (service_owner);
|
|
return success;
|
|
}
|
|
|
|
static void
|
|
impl_manager_activate_connection (NMManager *manager,
|
|
const char *service_name,
|
|
const char *connection_path,
|
|
const char *device_path,
|
|
const char *specific_object_path,
|
|
DBusGMethodInvocation *context)
|
|
{
|
|
NMConnectionScope scope = NM_CONNECTION_SCOPE_UNKNOWN;
|
|
NMConnection *connection;
|
|
GError *error = NULL;
|
|
char *real_sop = NULL;
|
|
char *path = NULL;
|
|
|
|
if (!strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS)) {
|
|
if (!is_user_request_authorized (manager, context, &error))
|
|
goto err;
|
|
|
|
scope = NM_CONNECTION_SCOPE_USER;
|
|
} else if (!strcmp (service_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS))
|
|
scope = NM_CONNECTION_SCOPE_SYSTEM;
|
|
else {
|
|
g_set_error (&error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_SERVICE,
|
|
"%s", "Invalid settings service name");
|
|
goto err;
|
|
}
|
|
|
|
/* "/" is special-cased to NULL to get through D-Bus */
|
|
if (specific_object_path && strcmp (specific_object_path, "/"))
|
|
real_sop = g_strdup (specific_object_path);
|
|
|
|
connection = nm_manager_get_connection_by_object_path (manager, scope, connection_path);
|
|
if (connection) {
|
|
path = (char *) nm_manager_activate_connection (manager,
|
|
connection,
|
|
real_sop,
|
|
device_path,
|
|
TRUE,
|
|
&error);
|
|
if (path) {
|
|
dbus_g_method_return (context, path);
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
|
|
}
|
|
} else {
|
|
PendingConnectionInfo *info;
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (priv->pending_connection_info) {
|
|
pending_connection_info_destroy (priv->pending_connection_info);
|
|
priv->pending_connection_info = NULL;
|
|
}
|
|
|
|
/* Don't have the connection quite yet, probably created by
|
|
* the client on-the-fly. Defer the activation until we have it
|
|
*/
|
|
|
|
info = g_slice_new0 (PendingConnectionInfo);
|
|
info->context = context;
|
|
info->device_path = g_strdup (device_path);
|
|
info->scope = scope;
|
|
info->connection_path = g_strdup (connection_path);
|
|
info->specific_object_path = g_strdup (real_sop);
|
|
info->timeout_id = g_timeout_add_seconds (5, wait_for_connection_expired, manager);
|
|
|
|
// FIXME: should probably be per-device, not global to the manager
|
|
NM_MANAGER_GET_PRIVATE (manager)->pending_connection_info = info;
|
|
}
|
|
|
|
err:
|
|
if (error) {
|
|
dbus_g_method_return_error (context, error);
|
|
nm_warning ("Connection (%d) %s failed to activate: (%d) %s",
|
|
scope, connection_path, error->code, error->message);
|
|
g_error_free (error);
|
|
}
|
|
|
|
g_free (real_sop);
|
|
}
|
|
|
|
gboolean
|
|
nm_manager_deactivate_connection (NMManager *manager,
|
|
const char *connection_path,
|
|
NMDeviceStateReason reason,
|
|
GError **error)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
NMVPNManager *vpn_manager;
|
|
GSList *iter;
|
|
gboolean success = FALSE;
|
|
NMVPNConnectionStateReason vpn_reason = NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED;
|
|
|
|
/* Check for device connections first */
|
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
|
NMDevice *device = NM_DEVICE (iter->data);
|
|
NMActRequest *req;
|
|
|
|
req = nm_device_get_act_request (device);
|
|
if (!req)
|
|
continue;
|
|
|
|
if (!strcmp (connection_path, nm_act_request_get_active_connection_path (req))) {
|
|
nm_device_state_changed (device,
|
|
NM_DEVICE_STATE_DISCONNECTED,
|
|
reason);
|
|
success = TRUE;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Check for VPN connections next */
|
|
vpn_manager = nm_vpn_manager_get ();
|
|
if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
|
|
vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
|
|
if (nm_vpn_manager_deactivate_connection (vpn_manager, connection_path, vpn_reason)) {
|
|
success = TRUE;
|
|
} else {
|
|
g_set_error (error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
|
|
"%s", "The connection was not active.");
|
|
}
|
|
g_object_unref (vpn_manager);
|
|
|
|
done:
|
|
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
|
|
return success;
|
|
}
|
|
|
|
static gboolean
|
|
impl_manager_deactivate_connection (NMManager *manager,
|
|
const char *connection_path,
|
|
GError **error)
|
|
{
|
|
return nm_manager_deactivate_connection (manager,
|
|
connection_path,
|
|
NM_DEVICE_STATE_REASON_USER_REQUESTED,
|
|
error);
|
|
}
|
|
|
|
static gboolean
|
|
impl_manager_sleep (NMManager *manager, gboolean sleep, GError **error)
|
|
{
|
|
NMManagerPrivate *priv;
|
|
|
|
g_return_val_if_fail (NM_IS_MANAGER (manager), FALSE);
|
|
|
|
priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
if (priv->sleeping == sleep) {
|
|
g_set_error (error,
|
|
NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
|
|
"Already %s", sleep ? "asleep" : "awake");
|
|
return FALSE;
|
|
}
|
|
|
|
priv->sleeping = sleep;
|
|
|
|
if (sleep) {
|
|
GSList *iter;
|
|
|
|
nm_info ("Sleeping...");
|
|
|
|
/* Just deactivate and down all devices from the device list,
|
|
* we'll remove them in 'wake' for speed's sake.
|
|
*/
|
|
for (iter = priv->devices; iter; iter = iter->next)
|
|
nm_device_set_managed (NM_DEVICE (iter->data), FALSE, NM_DEVICE_STATE_REASON_SLEEPING);
|
|
} else {
|
|
nm_info ("Waking up...");
|
|
|
|
sync_devices (manager);
|
|
if (priv->sync_devices_id) {
|
|
g_source_remove (priv->sync_devices_id);
|
|
priv->sync_devices_id = 0;
|
|
}
|
|
}
|
|
|
|
nm_manager_update_state (manager);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Legacy 0.6 compatibility interface */
|
|
|
|
static gboolean
|
|
impl_manager_legacy_sleep (NMManager *manager, GError **error)
|
|
{
|
|
return impl_manager_sleep (manager, TRUE, error);
|
|
}
|
|
|
|
static gboolean
|
|
impl_manager_legacy_wake (NMManager *manager, GError **error)
|
|
{
|
|
return impl_manager_sleep (manager, FALSE, error);
|
|
}
|
|
|
|
static gboolean
|
|
impl_manager_legacy_state (NMManager *manager, guint32 *state, GError **err)
|
|
{
|
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
|
|
nm_manager_update_state (manager);
|
|
*state = priv->state;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Connections */
|
|
|
|
static int
|
|
connection_sort (gconstpointer pa, gconstpointer pb)
|
|
{
|
|
NMConnection *a = NM_CONNECTION (pa);
|
|
NMSettingConnection *con_a;
|
|
NMConnection *b = NM_CONNECTION (pb);
|
|
NMSettingConnection *con_b;
|
|
|
|
con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION);
|
|
g_assert (con_a);
|
|
con_b = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION);
|
|
g_assert (con_b);
|
|
|
|
if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) {
|
|
if (nm_setting_connection_get_autoconnect (con_a))
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
if (nm_setting_connection_get_timestamp (con_a) > nm_setting_connection_get_timestamp (con_b))
|
|
return -1;
|
|
else if (nm_setting_connection_get_timestamp (con_a) == nm_setting_connection_get_timestamp (con_b))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
connections_to_slist (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
GSList **list = (GSList **) user_data;
|
|
|
|
*list = g_slist_insert_sorted (*list, g_object_ref (value), connection_sort);
|
|
}
|
|
|
|
/* Returns a GSList of referenced NMConnection objects, caller must
|
|
* unref the connections in the list and destroy the list.
|
|
*/
|
|
GSList *
|
|
nm_manager_get_connections (NMManager *manager,
|
|
NMConnectionScope scope)
|
|
{
|
|
NMManagerPrivate *priv;
|
|
GSList *list = NULL;
|
|
|
|
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
|
|
|
|
priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
if (scope == NM_CONNECTION_SCOPE_USER)
|
|
g_hash_table_foreach (priv->user_connections, connections_to_slist, &list);
|
|
else if (scope == NM_CONNECTION_SCOPE_SYSTEM)
|
|
g_hash_table_foreach (priv->system_connections, connections_to_slist, &list);
|
|
else
|
|
nm_warning ("Unknown NMConnectionScope %d", scope);
|
|
return list;
|
|
}
|
|
|
|
NMConnection *
|
|
nm_manager_get_connection_by_object_path (NMManager *manager,
|
|
NMConnectionScope scope,
|
|
const char *path)
|
|
{
|
|
NMManagerPrivate *priv;
|
|
NMConnection *connection = NULL;
|
|
|
|
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
|
|
g_return_val_if_fail (path != NULL, NULL);
|
|
|
|
priv = NM_MANAGER_GET_PRIVATE (manager);
|
|
if (scope == NM_CONNECTION_SCOPE_USER)
|
|
connection = (NMConnection *) g_hash_table_lookup (priv->user_connections, path);
|
|
else if (scope == NM_CONNECTION_SCOPE_SYSTEM)
|
|
connection = (NMConnection *) g_hash_table_lookup (priv->system_connections, path);
|
|
else
|
|
nm_warning ("Unknown NMConnectionScope %d", scope);
|
|
return connection;
|
|
}
|
|
|
|
GPtrArray *
|
|
nm_manager_get_active_connections_by_connection (NMManager *manager,
|
|
NMConnection *connection)
|
|
{
|
|
return get_active_connections (manager, connection);
|
|
}
|
|
|