summaryrefslogtreecommitdiff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c4531
1 files changed, 2293 insertions, 2238 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 9037e649c..09a1985a7 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -21,6 +21,7 @@
#include <config.h>
+#include <stdlib.h>
#include <netinet/ether.h>
#include <fcntl.h>
#include <errno.h>
@@ -38,37 +39,32 @@
#include "nm-logging.h"
#include "nm-dbus-manager.h"
#include "nm-vpn-manager.h"
-#include "nm-modem-manager.h"
-#include "nm-device-bt.h"
#include "nm-device.h"
#include "nm-device-ethernet.h"
-#include "nm-device-wifi.h"
-#include "nm-device-olpc-mesh.h"
-#include "nm-device-modem.h"
#include "nm-device-infiniband.h"
#include "nm-device-bond.h"
+#include "nm-device-team.h"
#include "nm-device-bridge.h"
#include "nm-device-vlan.h"
-#include "nm-device-adsl.h"
-#include "nm-system.h"
-#include "nm-properties-changed-signal.h"
-#include "nm-setting-bluetooth.h"
+#include "nm-device-generic.h"
+#include "nm-device-veth.h"
+#include "nm-device-tun.h"
+#include "nm-device-macvlan.h"
+#include "nm-device-vxlan.h"
+#include "nm-device-gre.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-udev-manager.h"
-#include "nm-hostname-provider.h"
-#include "nm-bluez-manager.h"
-#include "nm-bluez-common.h"
+#include "nm-platform.h"
+#include "nm-rfkill-manager.h"
+#include "nm-dhcp-manager.h"
#include "nm-settings.h"
#include "nm-settings-connection.h"
#include "nm-manager-auth.h"
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
#include "nm-device-factory.h"
-#include "wifi-utils.h"
#include "nm-enum-types.h"
#include "nm-sleep-monitor.h"
#include "nm-connectivity.h"
@@ -118,10 +114,10 @@ static gboolean impl_manager_get_state (NMManager *manager,
guint32 *state,
GError **error);
-static gboolean impl_manager_set_logging (NMManager *manager,
- const char *level,
- const char *domains,
- GError **error);
+static void impl_manager_set_logging (NMManager *manager,
+ const char *level,
+ const char *domains,
+ DBusGMethodInvocation *context);
static void impl_manager_get_logging (NMManager *manager,
char **level,
@@ -132,67 +128,37 @@ static void impl_manager_check_connectivity (NMManager *manager,
#include "nm-manager-glue.h"
-static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
- NMBluezDevice *bt_device,
- const char *bdaddr,
- const char *name,
- const char *object_path,
- guint32 uuids,
- NMManager *manager);
-
-static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
- const char *bdaddr,
- const char *object_path,
- gpointer user_data);
-
-static void add_device (NMManager *self, NMDevice *device);
-
-static void hostname_provider_init (NMHostnameProvider *provider_class);
-
-static NMActiveConnection *internal_activate_device (NMManager *manager,
- NMDevice *device,
- NMConnection *connection,
- const char *specific_object,
- gboolean user_requested,
- gulong sender_uid,
- const char *dbus_sender,
- gboolean assumed,
- NMActiveConnection *master,
- GError **error);
-
-static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
+static void add_device (NMManager *self, NMDevice *device, gboolean generate_con);
+static void remove_device (NMManager *self, NMDevice *device, gboolean quitting);
-static GSList * remove_one_device (NMManager *manager,
- GSList *list,
- NMDevice *device,
- gboolean quitting);
+static NMActiveConnection *_new_active_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMDevice *device,
+ NMAuthSubject *subject,
+ GError **error);
-static void rfkill_change_wifi (const char *desc, gboolean enabled);
+static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
-#define SSD_POKE_INTERVAL 120
-#define ORIGDEV_TAG "originating-device"
+static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
-typedef struct PendingActivation PendingActivation;
-typedef void (*PendingActivationFunc) (PendingActivation *pending,
- GError *error);
+static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled);
-struct PendingActivation {
- NMManager *manager;
+static gboolean find_master (NMManager *self,
+ NMConnection *connection,
+ NMDevice *device,
+ NMConnection **out_master_connection,
+ NMDevice **out_master_device,
+ NMActiveConnection **out_master_ac,
+ GError **error);
- DBusGMethodInvocation *context;
- PendingActivationFunc callback;
- NMAuthChain *chain;
- const char *wifi_shared_permission;
+static void nm_manager_update_state (NMManager *manager);
- char *connection_path;
- NMConnection *connection;
- char *specific_object_path;
- char *device_path;
-};
+#define SSD_POKE_INTERVAL 120
+#define ORIGDEV_TAG "originating-device"
typedef struct {
gboolean user_enabled;
- gboolean daemon_enabled;
gboolean sw_enabled;
gboolean hw_enabled;
RfKillType rtype;
@@ -200,8 +166,6 @@ typedef struct {
const char *key;
const char *prop;
const char *hw_prop;
- RfKillState (*other_enabled_func) (NMManager *);
- RfKillState (*daemon_enabled_func) (NMManager *);
} RadioState;
typedef struct {
@@ -216,13 +180,13 @@ typedef struct {
NMState state;
NMConnectivity *connectivity;
+ int ignore_link_added_cb;
+
NMPolicy *policy;
NMDBusManager *dbus_mgr;
- guint dbus_connection_changed_id;
- NMUdevManager *udev_mgr;
- NMBluezManager *bluez_mgr;
- NMSessionMonitor *session_monitor;
+ gboolean prop_filter_added;
+ NMRfkillManager *rfkill_mgr;
/* List of NMDeviceFactoryFunc pointers sorted in priority order */
GSList *factories;
@@ -236,10 +200,6 @@ typedef struct {
NMVPNManager *vpn_manager;
- NMModemManager *modem_manager;
- guint modem_added_id;
- guint modem_removed_id;
-
DBusGProxy *aipd_proxy;
NMSleepMonitor *sleep_monitor;
@@ -247,27 +207,21 @@ typedef struct {
/* Firmware dir monitor */
GFileMonitor *fw_monitor;
- guint fw_monitor_id;
guint fw_changed_id;
guint timestamp_update_id;
- GHashTable *nm_bridges;
-
- gboolean disposed;
+ gboolean startup;
} NMManagerPrivate;
#define NM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MANAGER, NMManagerPrivate))
-G_DEFINE_TYPE_EXTENDED (NMManager, nm_manager, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (NM_TYPE_HOSTNAME_PROVIDER,
- hostname_provider_init))
+G_DEFINE_TYPE (NMManager, nm_manager, G_TYPE_OBJECT)
enum {
DEVICE_ADDED,
DEVICE_REMOVED,
STATE_CHANGED,
- PROPERTIES_CHANGED,
CHECK_PERMISSIONS,
USER_PERMISSIONS_CHANGED,
ACTIVE_CONNECTION_ADDED,
@@ -282,6 +236,7 @@ enum {
PROP_0,
PROP_VERSION,
PROP_STATE,
+ PROP_STARTUP,
PROP_NETWORKING_ENABLED,
PROP_WIRELESS_ENABLED,
PROP_WIRELESS_HARDWARE_ENABLED,
@@ -293,6 +248,7 @@ enum {
PROP_CONNECTIVITY,
PROP_PRIMARY_CONNECTION,
PROP_ACTIVATING_CONNECTION,
+ PROP_DEVICES,
/* Not exported */
PROP_HOSTNAME,
@@ -320,13 +276,29 @@ nm_manager_error_quark (void)
static void active_connection_state_changed (NMActiveConnection *active,
GParamSpec *pspec,
NMManager *self);
+static void active_connection_default_changed (NMActiveConnection *active,
+ GParamSpec *pspec,
+ NMManager *self);
-static void
-active_connection_removed (NMManager *self, NMActiveConnection *active)
+/* Returns: whether to notify D-Bus of the removal or not */
+static gboolean
+active_connection_remove (NMManager *self, NMActiveConnection *active)
{
- g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active);
- g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self);
- g_object_unref (active);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ gboolean notify = !!nm_active_connection_get_path (active);
+ GSList *found;
+
+ /* FIXME: switch to a GList for faster removal */
+ found = g_slist_find (priv->active_connections, active);
+ if (found) {
+ priv->active_connections = g_slist_remove (priv->active_connections, active);
+ g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active);
+ g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self);
+ g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self);
+ g_object_unref (active);
+ }
+
+ return found && notify;
}
static gboolean
@@ -335,24 +307,21 @@ _active_connection_cleanup (gpointer user_data)
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
- gboolean changed = FALSE;
priv->ac_cleanup_id = 0;
+ g_object_freeze_notify (G_OBJECT (self));
iter = priv->active_connections;
while (iter) {
NMActiveConnection *ac = iter->data;
iter = iter->next;
if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
- priv->active_connections = g_slist_remove (priv->active_connections, ac);
- active_connection_removed (self, ac);
- changed = TRUE;
+ if (active_connection_remove (self, ac))
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
}
}
-
- if (changed)
- g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+ g_object_thaw_notify (G_OBJECT (self));
return FALSE;
}
@@ -375,8 +344,25 @@ active_connection_state_changed (NMActiveConnection *active,
if (!priv->ac_cleanup_id)
priv->ac_cleanup_id = g_idle_add (_active_connection_cleanup, self);
}
+
+ nm_manager_update_state (self);
+}
+
+static void
+active_connection_default_changed (NMActiveConnection *active,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ nm_manager_update_state (self);
}
+/**
+ * active_connection_add():
+ * @self: the #NMManager
+ * @active: the #NMActiveConnection to manage
+ *
+ * Begins to track and manage @active. Increases the refcount of @active.
+ */
static void
active_connection_add (NMManager *self, NMActiveConnection *active)
{
@@ -384,13 +370,27 @@ active_connection_add (NMManager *self, NMActiveConnection *active)
g_return_if_fail (g_slist_find (priv->active_connections, active) == FALSE);
- priv->active_connections = g_slist_prepend (priv->active_connections, active);
- g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
+ priv->active_connections = g_slist_prepend (priv->active_connections,
+ g_object_ref (active));
+
+ g_signal_connect (active,
+ "notify::" NM_ACTIVE_CONNECTION_STATE,
G_CALLBACK (active_connection_state_changed),
self);
+ g_signal_connect (active,
+ "notify::" NM_ACTIVE_CONNECTION_DEFAULT,
+ G_CALLBACK (active_connection_default_changed),
+ self);
+ g_signal_connect (active,
+ "notify::" NM_ACTIVE_CONNECTION_DEFAULT6,
+ G_CALLBACK (active_connection_default_changed),
+ self);
g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active);
- g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+
+ /* Only notify D-Bus if the active connection is actually exported */
+ if (nm_active_connection_get_path (active))
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
}
const GSList *
@@ -400,6 +400,55 @@ nm_manager_get_active_connections (NMManager *manager)
}
static NMActiveConnection *
+find_ac_for_connection (NMManager *manager, NMConnection *connection)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ GSList *iter;
+ NMActiveConnection *ac;
+ NMConnection *ac_connection;
+ NMActiveConnectionState ac_state;
+ const char *uuid;
+
+ uuid = nm_connection_get_uuid (connection);
+ for (iter = priv->active_connections; iter; iter = iter->next) {
+ ac = iter->data;
+ ac_connection = nm_active_connection_get_connection (ac);
+ ac_state = nm_active_connection_get_state (ac);
+
+ if ( !strcmp (nm_connection_get_uuid (ac_connection), uuid)
+ && (ac_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED))
+ return ac;
+ }
+
+ return NULL;
+}
+
+/* Filter out connections that are already active.
+ * nm_settings_get_connections() returns sorted list. We need to preserve the
+ * order so that we didn't change auto-activation order (recent timestamps
+ * are first).
+ * Caller is responsible for freeing the returned list with g_slist_free().
+ */
+GSList *
+nm_manager_get_activatable_connections (NMManager *manager)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ GSList *all_connections = nm_settings_get_connections (priv->settings);
+ GSList *connections = NULL, *iter;
+ NMConnection *connection;
+
+ for (iter = all_connections; iter; iter = iter->next) {
+ connection = iter->data;
+
+ if (!find_ac_for_connection (manager, connection))
+ connections = g_slist_prepend (connections, connection);
+ }
+
+ g_slist_free (all_connections);
+ return g_slist_reverse (connections);
+}
+
+static NMActiveConnection *
active_connection_get_by_path (NMManager *manager, const char *path)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
@@ -411,7 +460,7 @@ active_connection_get_by_path (NMManager *manager, const char *path)
for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
NMActiveConnection *candidate = iter->data;
- if (strcmp (path, nm_active_connection_get_path (candidate)) == 0)
+ if (g_strcmp0 (path, nm_active_connection_get_path (candidate)) == 0)
return candidate;
}
return NULL;
@@ -465,6 +514,21 @@ nm_manager_get_device_by_master (NMManager *manager, const char *master, const c
return NULL;
}
+NMDevice *
+nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
+{
+ GSList *iter;
+
+ for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+ NMDevice *device = NM_DEVICE (iter->data);
+
+ if (nm_device_get_ifindex (device) == ifindex)
+ return device;
+ }
+
+ return NULL;
+}
+
static gboolean
manager_sleeping (NMManager *self)
{
@@ -475,95 +539,41 @@ manager_sleeping (NMManager *self)
return FALSE;
}
-static void
-modem_added (NMModemManager *modem_manager,
- NMModem *modem,
- const char *driver,
- gpointer user_data)
+static const char *
+_nm_state_to_string (NMState state)
{
- NMManager *self = NM_MANAGER (user_data);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMDevice *replace_device, *device = NULL;
- const char *modem_iface;
- GSList *iter;
-
- /* Don't rely only on the data port; use the control port if available */
- modem_iface = nm_modem_get_data_port (modem);
- if (!modem_iface)
- modem_iface = nm_modem_get_control_port (modem);
- g_return_if_fail (modem_iface);
-
- replace_device = find_device_by_ip_iface (NM_MANAGER (user_data), modem_iface);
- if (replace_device) {
- priv->devices = remove_one_device (NM_MANAGER (user_data),
- priv->devices,
- replace_device,
- FALSE);
- }
-
- /* Give Bluetooth DUN devices first chance to claim the modem */
- for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) {
- if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver))
- return;
- }
- }
-
- /* If it was a Bluetooth modem and no bluetooth device claimed it, ignore
- * it. The rfcomm port (and thus the modem) gets created automatically
- * by the Bluetooth code during the connection process.
- */
- if (driver && !strcmp (driver, "bluetooth")) {
- nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", modem_iface);
- return;
+ switch (state) {
+ case NM_STATE_ASLEEP:
+ return "ASLEEP";
+ case NM_STATE_DISCONNECTED:
+ return "DISCONNECTED";
+ case NM_STATE_DISCONNECTING:
+ return "DISCONNECTING";
+ case NM_STATE_CONNECTING:
+ return "CONNECTING";
+ case NM_STATE_CONNECTED_LOCAL:
+ return "CONNECTED_LOCAL";
+ case NM_STATE_CONNECTED_SITE:
+ return "CONNECTED_SITE";
+ case NM_STATE_CONNECTED_GLOBAL:
+ return "CONNECTED_GLOBAL";
+ case NM_STATE_UNKNOWN:
+ default:
+ return "UNKNOWN";
}
-
- /* Make the new modem device */
- device = nm_device_modem_new (modem, driver);
- if (device)
- add_device (self, device);
}
static void
set_state (NMManager *manager, NMState state)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
- const char *state_str;
if (priv->state == state)
return;
priv->state = state;
- switch (state) {
- case NM_STATE_ASLEEP:
- state_str = "ASLEEP";
- break;
- case NM_STATE_DISCONNECTED:
- state_str = "DISCONNECTED";
- break;
- case NM_STATE_DISCONNECTING:
- state_str = "DISCONNECTING";
- break;
- case NM_STATE_CONNECTING:
- state_str = "CONNECTING";
- break;
- case NM_STATE_CONNECTED_LOCAL:
- state_str = "CONNECTED_LOCAL";
- break;
- case NM_STATE_CONNECTED_SITE:
- state_str = "CONNECTED_SITE";
- break;
- case NM_STATE_CONNECTED_GLOBAL:
- state_str = "CONNECTED_GLOBAL";
- break;
- case NM_STATE_UNKNOWN:
- default:
- state_str = "UNKNOWN";
- break;
- }
-
- nm_log_info (LOGD_CORE, "NetworkManager state is now %s", state_str);
+ nm_log_info (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (state));
g_object_notify (G_OBJECT (manager), NM_MANAGER_STATE);
g_signal_emit (manager, signals[STATE_CHANGED], 0, priv->state);
@@ -590,12 +600,59 @@ checked_connectivity (GObject *object, GAsyncResult *result, gpointer user_data)
g_object_unref (manager);
}
+static NMState
+find_best_device_state (NMManager *manager, gboolean *want_connectivity_check)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ NMState best_state = NM_STATE_DISCONNECTED;
+ GSList *iter;
+
+ for (iter = priv->active_connections; iter; iter = iter->next) {
+ NMActiveConnection *ac = NM_ACTIVE_CONNECTION (iter->data);
+ NMActiveConnectionState ac_state = nm_active_connection_get_state (ac);
+
+ switch (ac_state) {
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+ if ( nm_active_connection_get_default (ac)
+ || nm_active_connection_get_default6 (ac)) {
+ nm_connectivity_set_online (priv->connectivity, TRUE);
+ if (nm_connectivity_get_state (priv->connectivity) == NM_CONNECTIVITY_FULL) {
+ *want_connectivity_check = FALSE;
+ return NM_STATE_CONNECTED_GLOBAL;
+ }
+
+ best_state = NM_STATE_CONNECTING;
+ *want_connectivity_check = TRUE;
+ } else {
+ if (best_state < NM_STATE_CONNECTING)
+ best_state = NM_STATE_CONNECTED_LOCAL;
+ }
+ break;
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+ if (!nm_active_connection_get_assumed (ac)) {
+ if (best_state != NM_STATE_CONNECTED_GLOBAL)
+ best_state = NM_STATE_CONNECTING;
+ }
+ break;
+ case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
+ if (!nm_active_connection_get_assumed (ac)) {
+ if (best_state < NM_STATE_DISCONNECTING)
+ best_state = NM_STATE_DISCONNECTING;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return best_state;
+}
+
static void
nm_manager_update_state (NMManager *manager)
{
NMManagerPrivate *priv;
NMState new_state = NM_STATE_DISCONNECTED;
- GSList *iter;
gboolean want_connectivity_check = FALSE;
g_return_if_fail (NM_IS_MANAGER (manager));
@@ -604,30 +661,8 @@ nm_manager_update_state (NMManager *manager)
if (manager_sleeping (manager))
new_state = NM_STATE_ASLEEP;
- else {
- for (iter = priv->devices; iter; iter = iter->next) {
- NMDevice *dev = NM_DEVICE (iter->data);
- NMDeviceState state = nm_device_get_state (dev);
-
- if (state == NM_DEVICE_STATE_ACTIVATED) {
- nm_connectivity_set_online (priv->connectivity, TRUE);
- if (nm_connectivity_get_state (priv->connectivity) != NM_CONNECTIVITY_FULL) {
- new_state = NM_STATE_CONNECTING;
- want_connectivity_check = TRUE;
- } else {
- new_state = NM_STATE_CONNECTED_GLOBAL;
- break;
- }
- }
-
- if (nm_device_is_activating (dev))
- new_state = NM_STATE_CONNECTING;
- else if (new_state != NM_STATE_CONNECTING) {
- if (state == NM_DEVICE_STATE_DEACTIVATING)
- new_state = NM_STATE_DISCONNECTING;
- }
- }
- }
+ else
+ new_state = find_best_device_state (manager, &want_connectivity_check);
if (new_state == NM_STATE_CONNECTING && want_connectivity_check) {
nm_connectivity_check_async (priv->connectivity,
@@ -660,65 +695,99 @@ manager_device_state_changed (NMDevice *device,
default:
break;
}
+}
- nm_manager_update_state (self);
+static void device_has_pending_action_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self);
+
+static void
+check_if_startup_complete (NMManager *self)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ GSList *iter;
+
+ if (!priv->startup)
+ return;
+
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *dev = iter->data;
+
+ if (nm_device_has_pending_action (dev)) {
+ nm_log_dbg (LOGD_CORE, "check_if_startup_complete returns FALSE because of %s",
+ nm_device_get_iface (dev));
+ return;
+ }
+ }
+
+ nm_log_info (LOGD_CORE, "startup complete");
+
+ priv->startup = FALSE;
+ g_object_notify (G_OBJECT (self), "startup");
+
+ /* We don't have to watch notify::has-pending-action any more. */
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *dev = iter->data;
+
+ g_signal_handlers_disconnect_by_func (dev, G_CALLBACK (device_has_pending_action_changed), self);
+ }
+}
+
+static void
+device_has_pending_action_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ check_if_startup_complete (self);
}
-/* Removes a device from a device list; returns the start of the new device list */
-static GSList *
-remove_one_device (NMManager *manager,
- GSList *list,
- NMDevice *device,
- gboolean quitting)
+static void
+remove_device (NMManager *manager, NMDevice *device, gboolean quitting)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (nm_device_get_managed (device)) {
- /* When quitting, we want to leave up interfaces & connections
- * that can be taken over again (ie, "assumed") when NM restarts
- * so that '/etc/init.d/NetworkManager restart' will not distrupt
- * networking for interfaces that support connection assumption.
- * All other devices get unmanaged when NM quits so that their
- * connections get torn down and the interface is deactivated.
- */
+ NMActRequest *req = nm_device_get_act_request (device);
+ gboolean unmanage = FALSE;
- if ( !nm_device_can_assume_connections (device)
- || (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
- || !quitting)
- nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
+ /* Leave activated interfaces up when quitting so their configuration
+ * can be taken over when NM restarts. This ensures connectivity while
+ * NM is stopped. Devices which do not support connection assumption
+ * cannot be left up.
+ */
+ if (!quitting) /* Forced removal; device already gone */
+ unmanage = TRUE;
+ else if (!nm_device_can_assume_active_connection (device))
+ unmanage = TRUE;
+ else if (!req)
+ unmanage = TRUE;
+
+ if (unmanage) {
+ if (quitting)
+ nm_device_set_unmanaged_quitting (device);
+ else
+ nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_REMOVED);
+ }
}
- g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
+ g_signal_handlers_disconnect_matched (device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager);
+
+ nm_settings_device_removed (priv->settings, device, quitting);
+ priv->devices = g_slist_remove (priv->devices, device);
- nm_settings_device_removed (priv->settings, device);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
+ g_object_notify (G_OBJECT (manager), NM_MANAGER_DEVICES);
+
+ nm_dbus_manager_unregister_object (priv->dbus_mgr, device);
g_object_unref (device);
- return g_slist_remove (list, device);
+ check_if_startup_complete (manager);
}
static void
-modem_removed (NMModemManager *modem_manager,
- NMModem *modem,
- gpointer user_data)
+device_removed_cb (NMDevice *device, gpointer user_data)
{
- NMManager *self = NM_MANAGER (user_data);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMDevice *found;
- GSList *iter;
-
- /* Give Bluetooth DUN devices first chance to handle the modem removal */
- for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) {
- if (nm_device_bt_modem_removed (NM_DEVICE_BT (iter->data), modem))
- return;
- }
- }
-
- /* Otherwise remove the standalone modem */
- found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem));
- if (found)
- priv->devices = remove_one_device (self, priv->devices, found, FALSE);
+ remove_device (NM_MANAGER (user_data), device, FALSE);
}
static void
@@ -760,18 +829,6 @@ aipd_handle_event (DBusGProxy *proxy,
nm_log_warn (LOGD_AUTOIP4, "(%s): unhandled avahi-autoipd event", iface);
}
-static const char *
-hostname_provider_get_hostname (NMHostnameProvider *provider)
-{
- return NM_MANAGER_GET_PRIVATE (provider)->hostname;
-}
-
-static void
-hostname_provider_init (NMHostnameProvider *provider_class)
-{
- provider_class->get_hostname = hostname_provider_get_hostname;
-}
-
NMState
nm_manager_get_state (NMManager *manager)
{
@@ -780,316 +837,54 @@ nm_manager_get_state (NMManager *manager)
return NM_MANAGER_GET_PRIVATE (manager)->state;
}
-static gboolean
-might_be_vpn (NMConnection *connection)
-{
- NMSettingConnection *s_con;
- const char *ctype = NULL;
-
- if (nm_connection_get_setting_vpn (connection))
- return TRUE;
-
- /* Make sure it's not a VPN, which we can't autocomplete yet */
- s_con = nm_connection_get_setting_connection (connection);
- if (s_con)
- ctype = nm_setting_connection_get_connection_type (s_con);
-
- return (g_strcmp0 (ctype, NM_SETTING_VPN_SETTING_NAME) == 0);
-}
-
-static gboolean
-try_complete_vpn (NMConnection *connection, GSList *existing, GError **error)
-{
- g_assert (might_be_vpn (connection) == TRUE);
-
- if (!nm_connection_get_setting_vpn (connection)) {
- g_set_error_literal (error,
- NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
- "VPN connections require a 'vpn' setting");
- return FALSE;
- }
-
- nm_utils_complete_generic (connection,
- NM_SETTING_VPN_SETTING_NAME,
- existing,
- _("VPN connection %d"),
- NULL,
- FALSE); /* No IPv6 by default for now */
-
- return TRUE;
-}
-
-static PendingActivation *
-pending_activation_new (NMManager *manager,
- DBusGMethodInvocation *context,
- const char *device_path,
- const char *connection_path,
- GHashTable *settings,
- const char *specific_object_path,
- PendingActivationFunc callback,
- GError **error)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
- PendingActivation *pending;
- NMDevice *device = NULL;
- NMConnection *connection = NULL;
- GSList *all_connections = NULL;
- gboolean success;
-
- g_return_val_if_fail (manager != NULL, NULL);
- g_return_val_if_fail (context != NULL, NULL);
- g_return_val_if_fail (device_path != NULL, NULL);
-
- /* A object path of "/" means NULL */
- if (g_strcmp0 (specific_object_path, "/") == 0)
- specific_object_path = NULL;
- if (g_strcmp0 (device_path, "/") == 0)
- device_path = NULL;
-
- /* Create the partial connection from the given settings */
- if (settings) {
- if (device_path)
- device = nm_manager_get_device_by_path (manager, device_path);
- if (!device) {
- g_set_error_literal (error,
- NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Device not found");
- return NULL;
- }
-
- connection = nm_connection_new ();
- nm_connection_replace_settings (connection, settings, NULL);
-
- all_connections = nm_settings_get_connections (priv->settings);
-
- if (might_be_vpn (connection)) {
- /* Try to fill the VPN's connection setting and name at least */
- success = try_complete_vpn (connection, all_connections, error);
- } else {
- /* Let each device subclass complete the connection */
- success = nm_device_complete_connection (device,
- connection,
- specific_object_path,
- all_connections,
- error);
- }
- g_slist_free (all_connections);
-
- if (success == FALSE) {
- g_object_unref (connection);
- return NULL;
- }
- }
-
- pending = g_slice_new0 (PendingActivation);
- pending->manager = manager;
- pending->context = context;
- pending->callback = callback;
-
- pending->connection_path = g_strdup (connection_path);
- pending->connection = connection;
-
- /* "/" is special-cased to NULL to get through D-Bus */
- if (specific_object_path && strcmp (specific_object_path, "/"))
- pending->specific_object_path = g_strdup (specific_object_path);
- if (device_path && strcmp (device_path, "/"))
- pending->device_path = g_strdup (device_path);
-
- return pending;
-}
-
-static void
-pending_auth_done (NMAuthChain *chain,
- GError *error,
- DBusGMethodInvocation *context,
- gpointer user_data)
-{
- PendingActivation *pending = user_data;
- NMAuthCallResult result;
- GError *tmp_error = NULL;
-
- /* Caller has had a chance to obtain authorization, so we only need to
- * check for 'yes' here.
- */
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
- if (result != NM_AUTH_CALL_RESULT_YES) {
- tmp_error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- "Not authorized to control networking.");
- goto out;
- }
-
- if (pending->wifi_shared_permission) {
- result = nm_auth_chain_get_result (chain, pending->wifi_shared_permission);
- if (result != NM_AUTH_CALL_RESULT_YES) {
- tmp_error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- "Not authorized to share connections via wifi.");
- goto out;
- }
- }
-
- /* Otherwise authorized and available to activate */
-
-out:
- pending->callback (pending, tmp_error);
- g_clear_error (&tmp_error);
-}
-
-static void
-pending_activation_check_authorized (PendingActivation *pending,
- NMDBusManager *dbus_mgr)
-{
- NMManagerPrivate *priv;
- char *error_desc = NULL;
- gulong sender_uid = G_MAXULONG;
- GError *error;
- const char *wifi_permission = NULL;
- NMConnection *connection;
-
- g_return_if_fail (pending != NULL);
- g_return_if_fail (dbus_mgr != NULL);
-
- priv = NM_MANAGER_GET_PRIVATE (pending->manager);
-
- if (!nm_auth_get_caller_uid (pending->context,
- dbus_mgr,
- &sender_uid,
- &error_desc)) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- pending->callback (pending, error);
- g_error_free (error);
- g_free (error_desc);
- return;
- }
-
- /* Yay for root */
- if (0 == sender_uid) {
- pending->callback (pending, NULL);
- return;
- }
-
- /* By this point we have an auto-completed connection (for AddAndActivate)
- * or an existing connection (for Activate).
- */
- connection = pending->connection;
- if (!connection)
- connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, pending->connection_path);
-
- if (!connection) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
- "Connection could not be found.");
- pending->callback (pending, error);
- g_error_free (error);
- return;
- }
-
- /* Ensure the subject has permissions for this connection */
- if (!nm_auth_uid_in_acl (connection,
- priv->session_monitor,
- sender_uid,
- &error_desc)) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- pending->callback (pending, error);
- g_error_free (error);
- g_free (error_desc);
- return;
- }
-
- /* First check if the user is allowed to use networking at all, giving
- * the user a chance to authenticate to gain the permission.
- */
- pending->chain = nm_auth_chain_new (pending->context,
- NULL,
- pending_auth_done,
- pending);
- g_assert (pending->chain);
- nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
-
- /* Shared wifi connections require special permissions too */
- wifi_permission = nm_utils_get_shared_wifi_permission (connection);
- if (wifi_permission) {
- pending->wifi_shared_permission = wifi_permission;
- nm_auth_chain_add_call (pending->chain, wifi_permission, TRUE);
- }
-}
-
-static void
-pending_activation_destroy (PendingActivation *pending,
- GError *error,
- NMActiveConnection *ac)
-{
- g_return_if_fail (pending != NULL);
-
- if (error)
- dbus_g_method_return_error (pending->context, error);
- else if (ac) {
- if (pending->connection) {
- dbus_g_method_return (pending->context,
- pending->connection_path,
- nm_active_connection_get_path (ac));
- } else {
- dbus_g_method_return (pending->context,
- nm_active_connection_get_path (ac));
- }
- }
-
- g_free (pending->connection_path);
- g_free (pending->specific_object_path);
- g_free (pending->device_path);
- if (pending->connection)
- g_object_unref (pending->connection);
-
- if (pending->chain)
- nm_auth_chain_unref (pending->chain);
-
- memset (pending, 0, sizeof (PendingActivation));
- g_slice_free (PendingActivation, pending);
-}
-
/*******************************************************************/
/* Settings stuff via NMSettings */
/*******************************************************************/
static NMDevice *
-get_device_from_hwaddr (NMManager *self, NMConnection *connection)
+get_device_from_hwaddr (NMManager *self, const GByteArray *setting_mac)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ const guint8 *device_mac;
+ guint device_mac_len;
GSList *iter;
+ if (!setting_mac)
+ return NULL;
+
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- if (nm_device_hwaddr_matches (NM_DEVICE (iter->data), connection, NULL, 0, TRUE))
- return iter->data;
+ NMDevice *device = iter->data;
+
+ device_mac = nm_device_get_hw_address (iter->data, &device_mac_len);
+ if ( setting_mac->len == device_mac_len
+ && memcmp (setting_mac->data, device_mac, device_mac_len) == 0)
+ return device;
}
return NULL;
}
-static NMDevice*
+static NMDevice *
find_vlan_parent (NMManager *self,
- NMConnection *connection,
- gboolean check_hwaddr)
+ NMConnection *connection)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMSettingVlan *s_vlan;
+ NMSettingWired *s_wired;
NMConnection *parent_connection;
const char *parent_iface;
NMDevice *parent = NULL;
+ const GByteArray *setting_mac;
GSList *iter;
- /* The 'parent' property could be either an interface name, a connection
- * UUID, or even given by the MAC address of the connection's ethernet
- * or WiFi setting.
+ /* The 'parent' property could be given by an interface name, a
+ * connection UUID, or the MAC address of an NMSettingWired.
*/
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
+ s_wired = nm_connection_get_setting_wired (connection);
+ setting_mac = s_wired ? nm_setting_wired_get_mac_address (s_wired) : NULL;
+
parent_iface = nm_setting_vlan_get_parent (s_vlan);
if (parent_iface) {
parent = find_device_by_ip_iface (self, parent_iface);
@@ -1114,18 +909,37 @@ find_vlan_parent (NMManager *self,
}
/* Check the hardware address of the parent connection */
- if (check_hwaddr)
- return get_device_from_hwaddr (self, parent_connection);
+ return get_device_from_hwaddr (self, setting_mac);
}
return NULL;
}
}
/* Try the hardware address from the VLAN connection's hardware setting */
- if (check_hwaddr)
- return get_device_from_hwaddr (self, connection);
+ return get_device_from_hwaddr (self, setting_mac);
+}
- return NULL;
+static NMDevice *
+find_infiniband_parent (NMManager *self,
+ NMConnection *connection)
+{
+ NMSettingInfiniband *s_infiniband;
+ const char *parent_iface;
+ NMDevice *parent = NULL;
+ const GByteArray *setting_mac;
+
+ s_infiniband = nm_connection_get_setting_infiniband (connection);
+ g_return_val_if_fail (s_infiniband != NULL, NULL);
+
+ parent_iface = nm_setting_infiniband_get_parent (s_infiniband);
+ if (parent_iface) {
+ parent = find_device_by_ip_iface (self, parent_iface);
+ if (parent)
+ return parent;
+ }
+
+ setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+ return get_device_from_hwaddr (self, setting_mac);
}
/**
@@ -1146,7 +960,6 @@ get_virtual_iface_name (NMManager *self,
NMConnection *connection,
NMDevice **out_parent)
{
- char *vname = NULL;
NMDevice *parent = NULL;
if (out_parent)
@@ -1155,17 +968,21 @@ get_virtual_iface_name (NMManager *self,
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
return g_strdup (nm_connection_get_virtual_iface_name (connection));
+ if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME))
+ return g_strdup (nm_connection_get_virtual_iface_name (connection));
+
if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
return g_strdup (nm_connection_get_virtual_iface_name (connection));
if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
NMSettingVlan *s_vlan;
const char *ifname;
+ char *vname;
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
- parent = find_vlan_parent (self, connection, TRUE);
+ parent = find_vlan_parent (self, connection);
if (parent) {
ifname = nm_connection_get_virtual_iface_name (connection);
@@ -1189,113 +1006,56 @@ get_virtual_iface_name (NMManager *self,
}
if (out_parent)
*out_parent = parent;
+ return vname;
}
}
- return vname;
+ if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+ const char *ifname;
+ char *name;
+
+ parent = find_infiniband_parent (self, connection);
+ if (parent) {
+ ifname = nm_connection_get_virtual_iface_name (connection);
+ if (ifname)
+ name = g_strdup (ifname);
+ else {
+ NMSettingInfiniband *s_infiniband;
+ int p_key;
+
+ ifname = nm_device_get_iface (parent);
+ s_infiniband = nm_connection_get_setting_infiniband (connection);
+ p_key = nm_setting_infiniband_get_p_key (s_infiniband);
+ name = g_strdup_printf ("%s.%04x", ifname, p_key);
+ }
+ if (out_parent)
+ *out_parent = parent;
+ return name;
+ }
+ }
+
+ return NULL;
}
static gboolean
connection_needs_virtual_device (NMConnection *connection)
{
if ( nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
+ || nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
return TRUE;
- return FALSE;
-}
-
-static char *
-get_virtual_iface_placeholder_udi (void)
-{
- static guint32 id = 0;
-
- return g_strdup_printf ("/virtual/device/placeholder/%d", id++);
-}
-
-/***************************/
-
-/* FIXME: remove when we handle bridges non-destructively */
-
-#define NM_BRIDGE_FILE NMRUNDIR "/nm-bridges"
-
-static void
-read_nm_created_bridges (NMManager *self)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- char *contents;
- char **lines, **iter;
- GTimeVal tv;
- glong ts;
-
- if (!g_file_get_contents (NM_BRIDGE_FILE, &contents, NULL, NULL))
- return;
-
- g_get_current_time (&tv);
-
- lines = g_strsplit_set (contents, "\n", 0);
- g_free (contents);
-
- for (iter = lines; iter && *iter; iter++) {
- if (g_str_has_prefix (*iter, "ts=")) {
- errno = 0;
- ts = strtol (*iter + 3, NULL, 10);
- /* allow 30 minutes time difference before we ignore the file */
- if (errno || ABS (tv.tv_sec - ts) > 1800)
- goto out;
- } else if (g_str_has_prefix (*iter, "iface="))
- g_hash_table_insert (priv->nm_bridges, g_strdup (*iter + 6), GUINT_TO_POINTER (1));
- }
-
-out:
- g_strfreev (lines);
- unlink (NM_BRIDGE_FILE);
-}
-
-static void
-write_nm_created_bridges (NMManager *self)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GString *br_list;
- GSList *iter;
- GError *error = NULL;
- GTimeVal tv;
- gboolean found = FALSE;
-
- /* write out nm-created bridges list */
- br_list = g_string_sized_new (50);
-
- /* Timestamp is first line */
- g_get_current_time (&tv);
- g_string_append_printf (br_list, "ts=%ld\n", tv.tv_sec);
-
- for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- NMDevice *device = iter->data;
+ if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+ NMSettingInfiniband *s_infiniband;
- if (nm_device_get_device_type (device) == NM_DEVICE_TYPE_BRIDGE) {
- g_string_append_printf (br_list, "iface=%s\n", nm_device_get_iface (device));
- found = TRUE;
- }
+ s_infiniband = nm_connection_get_setting_infiniband (connection);
+ g_return_val_if_fail (s_infiniband != NULL, FALSE);
+ if (nm_setting_infiniband_get_p_key (s_infiniband) != -1)
+ return TRUE;
}
- if (found) {
- if (!g_file_set_contents (NM_BRIDGE_FILE, br_list->str, -1, &error)) {
- nm_log_warn (LOGD_BRIDGE, "Failed to write NetworkManager-created bridge list; "
- "on restart bridges may not be recognized. (%s)",
- error ? error->message : "unknown");
- g_clear_error (&error);
- }
- }
- g_string_free (br_list, TRUE);
-}
-
-static gboolean
-bridge_created_by_nm (NMManager *self, const char *iface)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-
- return (priv->nm_bridges && g_hash_table_lookup (priv->nm_bridges, iface));
+ return FALSE;
}
/***************************/
@@ -1315,7 +1075,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
- char *iface = NULL, *udi;
+ char *iface = NULL;
NMDevice *device = NULL, *parent = NULL;
iface = get_virtual_iface_name (self, connection, &parent);
@@ -1328,60 +1088,37 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
/* Make sure we didn't create a device for this connection already */
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *candidate = iter->data;
- GError *error = NULL;
if ( g_strcmp0 (nm_device_get_iface (candidate), iface) == 0
- || nm_device_check_connection_compatible (candidate, connection, &error)) {
- g_clear_error (&error);
+ || nm_device_check_connection_compatible (candidate, connection))
goto out;
- }
- g_clear_error (&error);
}
- if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
- if (!nm_system_add_bonding_master (iface)) {
- nm_log_warn (LOGD_DEVICE, "(%s): failed to add bonding master interface for '%s'",
- iface, nm_connection_get_id (connection));
- goto out;
- }
+ /* Block notification of link added since we're creating the device
+ * explicitly here, otherwise adding the platform/kernel device would
+ * create it before this function can do the rest of the setup.
+ */
+ priv->ignore_link_added_cb++;
- udi = get_virtual_iface_placeholder_udi ();
- device = nm_device_bond_new (udi, iface);
- g_free (udi);
+ if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
+ device = nm_device_bond_new_for_connection (connection);
+ } else if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) {
+ device = nm_device_team_new_for_connection (connection);
} else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) {
- gboolean exists = FALSE;
-
- if (!nm_system_create_bridge (iface, &exists)) {
- nm_log_warn (LOGD_DEVICE, "(%s): failed to add bridging interface for '%s'",
- iface, nm_connection_get_id (connection));
- goto out;
- }
-
- /* FIXME: remove when we handle bridges non-destructively */
- if (exists && !bridge_created_by_nm (self, iface)) {
- nm_log_warn (LOGD_DEVICE, "(%s): cannot use existing bridge for '%s'",
- iface, nm_connection_get_id (connection));
- goto out;
- }
-
- udi = get_virtual_iface_placeholder_udi ();
- device = nm_device_bridge_new (udi, iface);
- g_free (udi);
+ device = nm_device_bridge_new_for_connection (connection);
} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
- g_return_val_if_fail (parent != NULL, FALSE);
+ device = nm_device_vlan_new_for_connection (connection, parent);
+ } else if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+ device = nm_device_infiniband_new_partition (connection, parent);
+ }
- if (!nm_system_add_vlan_iface (connection, iface, nm_device_get_ip_ifindex (parent))) {
- nm_log_warn (LOGD_DEVICE, "(%s): failed to add VLAN interface for '%s'",
- iface, nm_connection_get_id (connection));
- goto out;
- }
- udi = get_virtual_iface_placeholder_udi ();
- device = nm_device_vlan_new (udi, iface, parent);
- g_free (udi);
+ if (device) {
+ nm_device_set_nm_owned (device);
+ add_device (self, device, FALSE);
+ g_object_unref (device);
}
- if (device)
- add_device (self, device);
+ priv->ignore_link_added_cb--;
out:
g_free (iface);
@@ -1399,14 +1136,11 @@ system_create_virtual_devices (NMManager *self)
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *connection = iter->data;
- NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
- g_assert (s_con);
- if (connection_needs_virtual_device (connection)) {
- /* We only create a virtual interface if the connection can autoconnect */
- if (nm_setting_connection_get_autoconnect (s_con))
- system_create_virtual_device (self, connection);
- }
+ /* We only create a virtual interface if the connection can autoconnect */
+ if ( connection_needs_virtual_device (connection)
+ && nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection)))
+ system_create_virtual_device (self, connection);
}
g_slist_free (connections);
}
@@ -1458,13 +1192,14 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *device = NM_DEVICE (iter->data);
- gboolean managed;
+ gboolean unmanaged;
- managed = !nm_device_spec_match_list (device, unmanaged_specs);
- nm_device_set_managed (device,
- managed,
- managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
- NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
+ unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
+ nm_device_set_unmanaged (device,
+ NM_UNMANAGED_USER,
+ unmanaged,
+ unmanaged ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED :
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
}
@@ -1487,6 +1222,8 @@ system_hostname_changed_cb (NMSettings *settings,
priv->hostname = (hostname && strlen (hostname)) ? g_strdup (hostname) : NULL;
g_object_notify (G_OBJECT (self), NM_MANAGER_HOSTNAME);
+ nm_dhcp_manager_set_default_hostname (nm_dhcp_manager_get (), priv->hostname);
+
g_free (hostname);
}
@@ -1517,8 +1254,6 @@ write_value_to_state_file (const char *filename,
FALSE);
key_file = g_key_file_new ();
- if (!key_file)
- return FALSE;
g_key_file_set_list_separator (key_file, ',');
g_key_file_load_from_file (key_file, filename, G_KEY_FILE_KEEP_COMMENTS, NULL);
@@ -1550,11 +1285,8 @@ radio_enabled_for_rstate (RadioState *rstate, gboolean check_changeable)
gboolean enabled;
enabled = rstate->user_enabled && rstate->hw_enabled;
- if (check_changeable) {
+ if (check_changeable)
enabled &= rstate->sw_enabled;
- if (rstate->daemon_enabled_func)
- enabled &= rstate->daemon_enabled;
- }
return enabled;
}
@@ -1598,95 +1330,24 @@ manager_update_radio_enabled (NMManager *self,
}
static void
-manager_hidden_ap_found (NMDevice *device,
- NMAccessPoint *ap,
- gpointer user_data)
-{
- NMManager *manager = NM_MANAGER (user_data);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
- const struct ether_addr *bssid;
- GSList *iter;
- GSList *connections;
- gboolean done = FALSE;
-
- g_return_if_fail (nm_ap_get_ssid (ap) == NULL);
-
- bssid = nm_ap_get_address (ap);
- g_assert (bssid);
-
- /* 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_settings_get_connections (priv->settings);
- for (iter = connections; iter && !done; iter = g_slist_next (iter)) {
- NMConnection *connection = NM_CONNECTION (iter->data);
- NMSettingWireless *s_wifi;
-
- s_wifi = nm_connection_get_setting_wireless (connection);
- if (s_wifi) {
- if (nm_settings_connection_has_seen_bssid (NM_SETTINGS_CONNECTION (connection), bssid))
- nm_ap_set_ssid (ap, nm_setting_wireless_get_ssid (s_wifi));
- }
- }
- g_slist_free (connections);
-}
-
-static RfKillState
-nm_manager_get_ipw_rfkill_state (NMManager *self)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GSList *iter;
- RfKillState ipw_state = RFKILL_UNBLOCKED;
-
- for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- NMDevice *candidate = NM_DEVICE (iter->data);
- RfKillState candidate_state;
-
- if (nm_device_get_device_type (candidate) == NM_DEVICE_TYPE_WIFI) {
- candidate_state = nm_device_wifi_get_ipw_rfkill_state (NM_DEVICE_WIFI (candidate));
-
- if (candidate_state > ipw_state)
- ipw_state = candidate_state;
- }
- }
-
- return ipw_state;
-}
-
-static RfKillState
-nm_manager_get_modem_enabled_state (NMManager *self)
+update_rstate_from_rfkill (NMRfkillManager *rfkill_mgr, RadioState *rstate)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GSList *iter;
- RfKillState wwan_state = RFKILL_UNBLOCKED;
-
- for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- NMDevice *candidate = NM_DEVICE (iter->data);
- RfKillState candidate_state = RFKILL_UNBLOCKED;
-
- if (nm_device_get_rfkill_type (candidate) == RFKILL_TYPE_WWAN) {
- if (!nm_device_get_enabled (candidate))
- candidate_state = RFKILL_SOFT_BLOCKED;
-
- if (candidate_state > wwan_state)
- wwan_state = candidate_state;
- }
- }
-
- return wwan_state;
-}
-
-static void
-update_rstate_from_rfkill (RadioState *rstate, RfKillState rfkill)
-{
- if (rfkill == RFKILL_UNBLOCKED) {
+ switch (nm_rfkill_manager_get_rfkill_state (rfkill_mgr, rstate->rtype)) {
+ case RFKILL_UNBLOCKED:
rstate->sw_enabled = TRUE;
rstate->hw_enabled = TRUE;
- } else if (rfkill == RFKILL_SOFT_BLOCKED) {
+ break;
+ case RFKILL_SOFT_BLOCKED:
rstate->sw_enabled = FALSE;
rstate->hw_enabled = TRUE;
- } else if (rfkill == RFKILL_HARD_BLOCKED) {
+ break;
+ case RFKILL_HARD_BLOCKED:
rstate->sw_enabled = FALSE;
rstate->hw_enabled = FALSE;
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
}
}
@@ -1696,51 +1357,19 @@ manager_rfkill_update_one_type (NMManager *self,
RfKillType rtype)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- RfKillState udev_state = RFKILL_UNBLOCKED;
- RfKillState other_state = RFKILL_UNBLOCKED;
- RfKillState composite;
- gboolean old_enabled, new_enabled, old_rfkilled, new_rfkilled;
- gboolean old_hwe, old_daemon_enabled = FALSE;
+ gboolean old_enabled, new_enabled, old_rfkilled, new_rfkilled, old_hwe;
old_enabled = radio_enabled_for_rstate (rstate, TRUE);
old_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
old_hwe = rstate->hw_enabled;
- udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, rtype);
-
- if (rstate->other_enabled_func)
- other_state = rstate->other_enabled_func (self);
-
- /* The composite state is the "worst" of either udev or other states */
- if (udev_state == RFKILL_HARD_BLOCKED || other_state == RFKILL_HARD_BLOCKED)
- composite = RFKILL_HARD_BLOCKED;
- else if (udev_state == RFKILL_SOFT_BLOCKED || other_state == RFKILL_SOFT_BLOCKED)
- composite = RFKILL_SOFT_BLOCKED;
- else
- composite = RFKILL_UNBLOCKED;
-
- update_rstate_from_rfkill (rstate, composite);
-
- /* If the device has a management daemon that can affect enabled state, check that now */
- if (rstate->daemon_enabled_func) {
- old_daemon_enabled = rstate->daemon_enabled;
- rstate->daemon_enabled = (rstate->daemon_enabled_func (self) == RFKILL_UNBLOCKED);
- if (old_daemon_enabled != rstate->daemon_enabled) {
- nm_log_info (LOGD_RFKILL, "%s now %s by management service",
- rstate->desc,
- rstate->daemon_enabled ? "enabled" : "disabled");
- }
- }
+ /* recheck kernel rfkill state */
+ update_rstate_from_rfkill (priv->rfkill_mgr, rstate);
/* Print out all states affecting device enablement */
if (rstate->desc) {
- if (rstate->daemon_enabled_func) {
- nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d daemon-enabled %d",
- rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->daemon_enabled);
- } else {
- nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
- rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
- }
+ nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
+ rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
}
/* Log new killswitch state */
@@ -1783,20 +1412,6 @@ nm_manager_rfkill_update (NMManager *self, RfKillType rtype)
}
static void
-manager_ipw_rfkill_state_changed (NMDeviceWifi *device,
- GParamSpec *pspec,
- gpointer user_data)
-{
- nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WLAN);
-}
-
-static void
-manager_modem_enabled_changed (NMDevice *device, gpointer user_data)
-{
- nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WWAN);
-}
-
-static void
device_auth_done_cb (NMAuthChain *chain,
GError *auth_error,
DBusGMethodInvocation *context,
@@ -1810,6 +1425,8 @@ device_auth_done_cb (NMAuthChain *chain,
const char *permission;
NMDeviceAuthRequestFunc callback;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
permission = nm_auth_chain_get_data (chain, "requested-permission");
@@ -1819,7 +1436,8 @@ device_auth_done_cb (NMAuthChain *chain,
device = nm_auth_chain_get_data (chain, "device");
g_assert (device);
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
+ result = nm_auth_chain_get_result (chain, permission);
+
if (auth_error) {
/* translate the auth error into a manager permission denied error */
nm_log_dbg (LOGD_CORE, "%s request failed: %s", permission, auth_error->message);
@@ -1858,112 +1476,283 @@ device_auth_request_cb (NMDevice *device,
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
- gulong sender_uid = G_MAXULONG;
+ NMAuthSubject *subject = NULL;
char *error_desc = NULL;
NMAuthChain *chain;
- /* Get the caller's UID for the root check */
- if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &sender_uid, &error_desc)) {
+ /* Validate the caller */
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- callback (device, context, error, user_data);
- g_error_free (error);
- g_free (error_desc);
- return;
+ "Failed to get request UID.");
+ goto done;
}
/* Ensure the subject has permissions for this connection */
- if (!nm_auth_uid_in_acl (connection,
- priv->session_monitor,
- sender_uid,
- &error_desc)) {
+ if (connection && !nm_auth_uid_in_acl (connection,
+ nm_session_monitor_get (),
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
+ g_free (error_desc);
+ goto done;
+ }
+
+ /* Validate the request */
+ chain = nm_auth_chain_new_subject (subject, context, device_auth_done_cb, self);
+ if (!chain) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Unable to authenticate request.");
+ goto done;
+ }
+
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
+ nm_auth_chain_set_data (chain, "requested-permission", g_strdup (permission), g_free);
+ nm_auth_chain_set_data (chain, "callback", callback, NULL);
+ nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
+ nm_auth_chain_add_call (chain, permission, allow_interaction);
+
+done:
+ g_clear_object (&subject);
+ if (error)
callback (device, context, error, user_data);
+ g_clear_error (&error);
+}
+
+/* This should really be moved to gsystem. */
+#define free_slist __attribute__ ((cleanup(local_slist_free)))
+static void
+local_slist_free (void *loc)
+{
+ GSList **location = loc;
+
+ if (location)
+ g_slist_free (*location);
+}
+
+static gboolean
+match_connection_filter (NMConnection *connection, gpointer user_data)
+{
+ return nm_device_check_connection_compatible (NM_DEVICE (user_data), connection);
+}
+
+/**
+ * get_existing_connection:
+ * @manager: #NMManager instance
+ * @device: #NMDevice instance
+ *
+ * Returns: a #NMSettingsConnection to be assumed by the device, or %NULL if
+ * the device does not support assuming existing connections.
+ */
+static NMConnection *
+get_existing_connection (NMManager *manager, NMDevice *device)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ free_slist GSList *connections = nm_manager_get_activatable_connections (manager);
+ NMConnection *connection = NULL, *matched;
+ NMSettingsConnection *added = NULL;
+ GError *error = NULL;
+
+ nm_device_capture_initial_config (device);
+
+ /* The core of the API is nm_device_generate_connection() function and
+ * update_connection() virtual method and the convenient connection_type
+ * class attribute. Subclasses supporting the new API must have
+ * update_connection() implemented, otherwise nm_device_generate_connection()
+ * returns NULL.
+ */
+ connection = nm_device_generate_connection (device);
+ if (!connection)
+ return NULL;
+
+ /* Now we need to compare the generated connection to each configured
+ * connection. The comparison function is the heart of the connection
+ * assumption implementation and it must compare the connections very
+ * carefully to sort out various corner cases. Also, the comparison is
+ * not entirely symmetric.
+ *
+ * When no configured connection matches the generated connection, we keep
+ * the generated connection instead.
+ */
+ connections = g_slist_reverse (g_slist_sort (connections, nm_settings_sort_connections));
+ matched = nm_utils_match_connection (connections,
+ connection,
+ nm_device_has_carrier (device),
+ match_connection_filter,
+ device);
+ if (matched) {
+ nm_log_info (LOGD_DEVICE, "(%s): found matching connection '%s'",
+ nm_device_get_iface (device),
+ nm_connection_get_id (matched));
+ g_object_unref (connection);
+ return matched;
+ }
+
+ nm_log_dbg (LOGD_DEVICE, "(%s): generated connection '%s'",
+ nm_device_get_iface (device),
+ nm_connection_get_id (connection));
+
+ added = nm_settings_add_connection (priv->settings, connection, FALSE, &error);
+ if (added)
+ nm_settings_connection_set_nm_generated (added);
+ else {
+ nm_log_warn (LOGD_SETTINGS, "(%s) Couldn't save generated connection '%s': %s",
+ nm_device_get_iface (device),
+ nm_connection_get_id (connection),
+ (error && error->message) ? error->message : "(unknown)");
+ g_clear_error (&error);
+ }
+ g_object_unref (connection);
+
+ return added ? NM_CONNECTION (added) : NULL;
+}
+
+static gboolean
+assume_connection (NMManager *self, NMDevice *device, NMConnection *connection)
+{
+ NMActiveConnection *active, *master_ac;
+ NMAuthSubject *subject;
+ GError *error = NULL;
+
+ nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection",
+ nm_device_get_iface (device));
+
+ /* Move device to DISCONNECTED to activate the connection */
+ if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
+ }
+ g_return_val_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
+
+ subject = nm_auth_subject_new_internal ();
+ active = _new_active_connection (self, connection, NULL, device, subject, &error);
+ g_object_unref (subject);
+
+ if (!active) {
+ nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
+ nm_connection_get_path (connection),
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
g_error_free (error);
- g_free (error_desc);
+ return FALSE;
+ }
+
+ /* If the device is a slave or VLAN, find the master ActiveConnection */
+ master_ac = NULL;
+ if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac)
+ nm_active_connection_set_master (active, master_ac);
+
+ nm_active_connection_set_assumed (active, TRUE);
+ nm_active_connection_export (active);
+ active_connection_add (self, active);
+ nm_device_queue_activation (device, NM_ACT_REQUEST (active));
+ g_object_unref (active);
+
+ return TRUE;
+}
+
+static void
+recheck_assume_connection (NMDevice *device, gpointer user_data)
+{
+ NMManager *self = user_data;
+ NMConnection *connection;
+ gboolean was_unmanaged = FALSE;
+
+ if (manager_sleeping (self))
+ return;
+ if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_USER))
+ return;
+
+ connection = get_existing_connection (self, device);
+ if (!connection) {
+ nm_log_dbg (LOGD_DEVICE, "(%s): can't assume; no connection",
+ nm_device_get_iface (device));
return;
}
- /* Yay for root */
- if (0 == sender_uid)
- callback (device, context, NULL, user_data);
- else {
- /* Otherwise validate the non-root request */
- chain = nm_auth_chain_new (context, NULL, device_auth_done_cb, self);
- g_assert (chain);
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ if (nm_device_get_state (device) == NM_DEVICE_STATE_UNMANAGED) {
+ was_unmanaged = TRUE;
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_UNAVAILABLE,
+ NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
+ }
- nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
- nm_auth_chain_set_data (chain, "requested-permission", g_strdup (permission), g_free);
- nm_auth_chain_set_data (chain, "callback", callback, NULL);
- nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
- nm_auth_chain_add_call (chain, permission, allow_interaction);
+ if (!assume_connection (self, device, connection)) {
+ if (was_unmanaged) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_UNAVAILABLE,
+ NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_UNMANAGED,
+ NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+ }
}
}
+/**
+ * add_device:
+ * @self: the #NMManager
+ * @device: the #NMDevice to add
+ * @generate_con: %TRUE if existing connection (if any) should be assumed
+ *
+ * If successful, this function will increase the references count of @device.
+ * Callers should decrease the reference count.
+ */
static void
-add_device (NMManager *self, NMDevice *device)
+add_device (NMManager *self, NMDevice *device, gboolean generate_con)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const char *iface, *driver, *type_desc;
- char *path;
- static guint32 devcount = 0;
const GSList *unmanaged_specs;
- NMConnection *existing = NULL;
- gboolean managed = FALSE, enabled = FALSE;
+ gboolean user_unmanaged, sleeping;
+ NMConnection *connection = NULL;
+ gboolean enabled = FALSE;
RfKillType rtype;
- NMDeviceType devtype;
+ GSList *iter, *remove = NULL;
- iface = nm_device_get_ip_iface (device);
- g_assert (iface);
-
- devtype = nm_device_get_device_type (device);
+ /* No duplicates */
+ if (nm_manager_get_device_by_udi (self, nm_device_get_udi (device)))
+ return;
- /* Ignore the device if we already know about it. But some modems will
- * provide pseudo-ethernet devices that NM has already claimed while
- * ModemManager is still detecting the modem's serial ports, so when the
- * MM modem object finally shows up it may have the same IP interface as the
- * ethernet interface we've already detected. In this case we skip the
- * check for an existing device with the same IP interface name and kill
- * the ethernet device later in favor of the modem device.
+ /* Remove existing devices owned by the new device; eg remove ethernet
+ * ports that are owned by a WWAN modem, since udev may announce them
+ * before the modem is fully discovered.
+ *
+ * FIXME: use parent/child device relationships instead of removing
+ * the child NMDevice entirely
*/
- if ((devtype != NM_DEVICE_TYPE_MODEM) && find_device_by_ip_iface (self, iface)) {
- g_object_unref (device);
- return;
+ for (iter = priv->devices; iter; iter = iter->next) {
+ iface = nm_device_get_ip_iface (iter->data);
+ if (nm_device_owns_iface (device, iface))
+ remove = g_slist_prepend (remove, iter->data);
}
+ for (iter = remove; iter; iter = iter->next)
+ remove_device (self, NM_DEVICE (iter->data), FALSE);
+ g_slist_free (remove);
- nm_device_set_connection_provider (device, NM_CONNECTION_PROVIDER (priv->settings));
-
- priv->devices = g_slist_append (priv->devices, device);
+ priv->devices = g_slist_append (priv->devices, g_object_ref (device));
g_signal_connect (device, "state-changed",
- G_CALLBACK (manager_device_state_changed),
- self);
+ G_CALLBACK (manager_device_state_changed),
+ self);
g_signal_connect (device, NM_DEVICE_AUTH_REQUEST,
G_CALLBACK (device_auth_request_cb),
self);
- if (devtype == NM_DEVICE_TYPE_WIFI) {
- /* Attach to the access-point-added signal so that the manager can fill
- * non-SSID-broadcasting APs with an SSID.
- */
- g_signal_connect (device, "hidden-ap-found",
- G_CALLBACK (manager_hidden_ap_found),
- self);
+ g_signal_connect (device, NM_DEVICE_REMOVED,
+ G_CALLBACK (device_removed_cb),
+ self);
- /* Hook up rfkill handling for ipw-based cards until they get converted
- * to use the kernel's rfkill subsystem in 2.6.33.
- */
- g_signal_connect (device, "notify::" NM_DEVICE_WIFI_IPW_RFKILL_STATE,
- G_CALLBACK (manager_ipw_rfkill_state_changed),
- self);
- } else if (devtype == NM_DEVICE_TYPE_MODEM) {
- g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED,
- G_CALLBACK (manager_modem_enabled_changed),
+ if (priv->startup) {
+ g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
+ G_CALLBACK (device_has_pending_action_changed),
self);
}
@@ -1978,6 +1767,9 @@ add_device (NMManager *self, NMDevice *device)
nm_device_set_enabled (device, enabled);
}
+ iface = nm_device_get_iface (device);
+ g_assert (iface);
+
type_desc = nm_device_get_type_desc (device);
g_assert (type_desc);
driver = nm_device_get_driver (device);
@@ -1986,121 +1778,47 @@ add_device (NMManager *self, NMDevice *device)
nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)",
iface, type_desc, driver, nm_device_get_ifindex (device));
- path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++);
- nm_device_set_path (device, path);
- dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
- path,
- G_OBJECT (device));
- nm_log_info (LOGD_CORE, "(%s): exported as %s", iface, path);
- g_free (path);
+ unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
+ user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
+ nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged);
- /* Check if we should assume the device's active connection by matching its
- * config with an existing system connection.
- */
- if (nm_device_can_assume_connections (device)) {
- GSList *connections = NULL;
+ sleeping = manager_sleeping (self);
+ nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);
- connections = nm_settings_get_connections (priv->settings);
- existing = nm_device_connection_match_config (device, (const GSList *) connections);
- g_slist_free (connections);
+ nm_device_dbus_export (device);
- if (existing)
- nm_log_dbg (LOGD_DEVICE, "(%s): found existing device connection '%s'",
- nm_device_get_iface (device),
- nm_connection_get_id (existing));
- }
+ /* Don't generate a connection e.g. for devices NM just created, or
+ * for the loopback, or when we're sleeping. */
+ if (generate_con && !user_unmanaged && !sleeping)
+ connection = get_existing_connection (self, device);
- /* Start the device if it's supposed to be managed */
- unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
- if ( !manager_sleeping (self)
- && !nm_device_spec_match_list (device, unmanaged_specs)) {
- nm_device_set_managed (device,
- TRUE,
- existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
- NM_DEVICE_STATE_REASON_NOW_MANAGED);
- managed = TRUE;
+ /* Start the device if it's supposed to be managed. Note that this will
+ * manage default-unmanaged devices if they have a generated connection.
+ */
+ if (nm_device_get_managed (device) || connection) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_UNAVAILABLE,
+ connection ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
nm_settings_device_added (priv->settings, device);
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
+ g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
/* New devices might be master interfaces for virtual interfaces; so we may
* need to create new virtual interfaces now.
*/
system_create_virtual_devices (self);
- /* If the device has a connection it can assume, do that now */
- if (existing && managed && nm_device_is_available (device)) {
- NMActiveConnection *ac;
- GError *error = NULL;
-
- nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume existing connection",
- nm_device_get_iface (device));
-
- ac = internal_activate_device (self, device, existing, NULL, FALSE, 0, NULL, TRUE, NULL, &error);
- if (!ac) {
- nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
- nm_connection_get_path (existing),
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_error_free (error);
- }
- }
-}
-
-static void
-bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
- NMBluezDevice *bt_device,
- const char *bdaddr,
- const char *name,
- const char *object_path,
- guint32 capabilities,
- NMManager *manager)
-{
- NMDevice *device;
- gboolean has_dun = (capabilities & NM_BT_CAPABILITY_DUN);
- gboolean has_nap = (capabilities & NM_BT_CAPABILITY_NAP);
-
- g_return_if_fail (bdaddr != NULL);
- g_return_if_fail (name != NULL);
- g_return_if_fail (object_path != NULL);
- g_return_if_fail (capabilities != NM_BT_CAPABILITY_NONE);
- g_return_if_fail (NM_IS_BLUEZ_DEVICE (bt_device));
-
- /* Make sure the device is not already in the device list */
- if (nm_manager_get_device_by_udi (manager, object_path))
- return;
-
- device = nm_device_bt_new (bt_device, object_path, bdaddr, name, capabilities, FALSE);
- if (device) {
- nm_log_info (LOGD_HW, "BT device %s (%s) added (%s%s%s)",
- name,
- bdaddr,
- has_dun ? "DUN" : "",
- has_dun && has_nap ? " " : "",
- has_nap ? "NAP" : "");
-
- add_device (manager, device);
- }
-}
-
-static void
-bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
- const char *bdaddr,
- const char *object_path,
- gpointer user_data)
-{
- NMManager *self = NM_MANAGER (user_data);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMDevice *device;
-
- g_return_if_fail (bdaddr != NULL);
- g_return_if_fail (object_path != NULL);
-
- device = nm_manager_get_device_by_udi (self, object_path);
- if (device) {
- nm_log_info (LOGD_HW, "BT device %s removed", bdaddr);
- priv->devices = remove_one_device (self, priv->devices, device, FALSE);
+ /* If the device has a connection it can assume, do that now. If it's a
+ * device that we might ever want to assume a connection on, then set that up.
+ */
+ if (connection)
+ assume_connection (self, device, connection);
+ if (generate_con) {
+ g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
+ G_CALLBACK (recheck_assume_connection), self);
}
}
@@ -2134,25 +1852,33 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex)
return NULL;
}
-#define PLUGIN_PREFIX "libnm-device-plugin-"
-
-typedef struct {
- NMDeviceType t;
- guint priority;
- NMDeviceFactoryCreateFunc create_func;
-} PluginInfo;
+static void
+factory_device_added_cb (NMDeviceFactory *factory,
+ NMDevice *device,
+ gpointer user_data)
+{
+ add_device (NM_MANAGER (user_data), device, FALSE);
+}
-static gint
-plugin_sort (PluginInfo *a, PluginInfo *b)
+static gboolean
+factory_component_added_cb (NMDeviceFactory *factory,
+ GObject *component,
+ gpointer user_data)
{
- /* Higher priority means sort earlier in the list (ie, return -1) */
- if (a->priority > b->priority)
- return -1;
- else if (a->priority < b->priority)
- return 1;
- return 0;
+ NMManager *self = NM_MANAGER (user_data);
+ GSList *iter;
+
+ for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
+ if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
+ return TRUE;
+ }
+ return FALSE;
}
+#define PLUGIN_PREFIX "libnm-device-plugin-"
+#define PLUGIN_PATH_TAG "NMManager-plugin-path"
+#define PLUGIN_TYPEFUNC_TAG "typefunc"
+
static void
load_device_factories (NMManager *self)
{
@@ -2161,7 +1887,7 @@ load_device_factories (NMManager *self)
GError *error = NULL;
const char *item;
char *path;
- GSList *list = NULL, *iter;
+ GSList *iter;
dir = g_dir_open (NMPLUGINDIR, 0, &error);
if (!dir) {
@@ -2174,14 +1900,16 @@ load_device_factories (NMManager *self)
while ((item = g_dir_read_name (dir))) {
GModule *plugin;
+ NMDeviceFactory *factory;
NMDeviceFactoryCreateFunc create_func;
- NMDeviceFactoryPriorityFunc priority_func;
- NMDeviceFactoryTypeFunc type_func;
- PluginInfo *info = NULL;
- NMDeviceType plugin_type;
+ NMDeviceFactoryDeviceTypeFunc type_func;
+ NMDeviceType dev_type;
+ const char *found = NULL;
if (!g_str_has_prefix (item, PLUGIN_PREFIX))
continue;
+ if (g_str_has_suffix (item, ".la"))
+ continue;
path = g_module_build_path (NMPLUGINDIR, item);
g_assert (path);
@@ -2193,158 +1921,92 @@ load_device_factories (NMManager *self)
continue;
}
- if (!g_module_symbol (plugin, "nm_device_factory_get_type", (gpointer) (&type_func))) {
- nm_log_warn (LOGD_HW, "(%s): failed to find device factory: %s", item, g_module_error ());
+ if (!g_module_symbol (plugin, "nm_device_factory_get_device_type", (gpointer) &type_func)) {
+ nm_log_warn (LOGD_HW, "(%s): failed to find device factory type: %s", item, g_module_error ());
g_module_close (plugin);
continue;
}
/* Make sure we don't double-load plugins */
- plugin_type = type_func ();
- for (iter = list; iter; iter = g_slist_next (iter)) {
- PluginInfo *candidate = iter->data;
+ dev_type = type_func ();
+ for (iter = priv->factories; iter; iter = iter->next) {
+ NMDeviceFactoryDeviceTypeFunc loaded_type_func;
- if (plugin_type == candidate->t) {
- info = candidate;
+ loaded_type_func = g_object_get_data (G_OBJECT (iter->data), PLUGIN_TYPEFUNC_TAG);
+ if (dev_type == loaded_type_func ()) {
+ found = g_object_get_data (G_OBJECT (iter->data), PLUGIN_PATH_TAG);
break;
}
}
- if (info) {
+ if (found) {
+ nm_log_warn (LOGD_HW, "Found multiple device plugins for same type: %s vs %s",
+ found, g_module_name (plugin));
g_module_close (plugin);
continue;
}
- if (!g_module_symbol (plugin, "nm_device_factory_create_device", (gpointer) (&create_func))) {
- nm_log_warn (LOGD_HW, "(%s): failed to find device creator: %s", item, g_module_error ());
+ if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) {
+ nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ());
g_module_close (plugin);
continue;
}
- info = g_malloc0 (sizeof (*info));
- info->create_func = create_func;
- info->t = plugin_type;
-
- /* Grab priority; higher number equals higher priority */
- if (g_module_symbol (plugin, "nm_device_factory_get_priority", (gpointer) (&priority_func)))
- info->priority = priority_func ();
- else {
- nm_log_dbg (LOGD_HW, "(%s): failed to find device factory priority func: %s",
- item, g_module_error ());
+ factory = create_func (&error);
+ if (!factory) {
+ nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s",
+ item, error ? error->message : "unknown");
+ g_clear_error (&error);
+ g_module_close (plugin);
+ continue;
}
+ g_clear_error (&error);
g_module_make_resident (plugin);
- list = g_slist_insert_sorted (list, info, (GCompareFunc) plugin_sort);
+ priv->factories = g_slist_prepend (priv->factories, factory);
- nm_log_info (LOGD_HW, "Loaded device factory: %s", g_module_name (plugin));
+ g_signal_connect (factory,
+ NM_DEVICE_FACTORY_DEVICE_ADDED,
+ G_CALLBACK (factory_device_added_cb),
+ self);
+ g_signal_connect (factory,
+ NM_DEVICE_FACTORY_COMPONENT_ADDED,
+ G_CALLBACK (factory_component_added_cb),
+ self);
+ g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG,
+ g_strdup (g_module_name (plugin)), g_free);
+ g_object_set_data (G_OBJECT (factory), PLUGIN_TYPEFUNC_TAG, type_func);
+
+ nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin));
};
g_dir_close (dir);
- /* Ditch the priority info and copy the factory functions to our private data */
- for (iter = list; iter; iter = g_slist_next (iter)) {
- PluginInfo *info = iter->data;
-
- priv->factories = g_slist_append (priv->factories, info->create_func);
- g_free (info);
- }
- g_slist_free (list);
-}
-
-static gboolean
-is_wireless (GUdevDevice *device)
-{
- const char *tmp;
-
- /* Check devtype, newer kernels (2.6.32+) have this */
- tmp = g_udev_device_get_property (device, "DEVTYPE");
- if (g_strcmp0 (tmp, "wlan") == 0)
- return TRUE;
-
- /* Otherwise hit up WEXT directly */
- return wifi_utils_is_wifi (g_udev_device_get_name (device),
- g_udev_device_get_sysfs_path (device));
-}
-
-static gboolean
-is_olpc_mesh (GUdevDevice *device)
-{
- const gchar *prop = g_udev_device_get_property (device, "ID_NM_OLPC_MESH");
- return (prop != NULL);
-}
-
-static gboolean
-is_infiniband (GUdevDevice *device)
-{
- gint etype = g_udev_device_get_sysfs_attr_as_int (device, "type");
- return etype == ARPHRD_INFINIBAND;
-}
-
-static gboolean
-is_bond (int ifindex)
-{
- return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_BOND);
-}
-
-static gboolean
-is_bridge (int ifindex)
-{
- return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_BRIDGE);
-}
-
-static gboolean
-is_vlan (int ifindex)
-{
- return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_VLAN);
-}
-
-static gboolean
-is_adsl (GUdevDevice *device)
-{
- return (g_strcmp0 (g_udev_device_get_subsystem (device), "atm") == 0);
+ priv->factories = g_slist_reverse (priv->factories);
}
static void
-udev_device_added_cb (NMUdevManager *udev_mgr,
- GUdevDevice *udev_device,
- const char *iface,
- const char *sysfs_path,
- const char *driver,
- int ifindex,
- gpointer user_data)
+platform_link_added (NMManager *self,
+ int ifindex,
+ NMPlatformLink *plink,
+ NMPlatformReason reason)
{
- NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDevice *device = NULL;
GSList *iter;
GError *error = NULL;
- g_return_if_fail (udev_device != NULL);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (sysfs_path != NULL);
- g_return_if_fail (driver != NULL);
+ g_return_if_fail (ifindex > 0);
- /* Most devices will have an ifindex here */
- if (ifindex > 0) {
- device = find_device_by_ifindex (self, ifindex);
- if (device) {
- /* If it's a virtual device we may need to update its UDI */
- if (nm_system_get_iface_type (ifindex, iface) != NM_IFACE_TYPE_UNSPEC)
- g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
- return;
- }
- } else {
- /* But ATM/ADSL devices don't */
- g_return_if_fail (is_adsl (udev_device));
- device = find_device_by_ip_iface (self, iface);
- if (device)
- return;
- }
+ if (priv->ignore_link_added_cb > 0)
+ return;
+
+ if (find_device_by_ifindex (self, ifindex))
+ return;
/* Try registered device factories */
- for (iter = priv->factories; iter; iter = g_slist_next (iter)) {
- NMDeviceFactoryCreateFunc create_func = iter->data;
+ for (iter = priv->factories; iter; iter = iter->next) {
+ NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data);
- g_clear_error (&error);
- device = (NMDevice *) create_func (udev_device, sysfs_path, iface, driver, &error);
+ device = nm_device_factory_new_link (factory, plink, &error);
if (device && NM_IS_DEVICE (device)) {
g_assert_no_error (error);
break; /* success! */
@@ -2352,7 +2014,7 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
if (error) {
nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s",
- sysfs_path,
+ plink->udi,
error ? error->code : -1,
error ? error->message : "(unknown)");
g_clear_error (&error);
@@ -2360,102 +2022,128 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
}
}
+ /* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt
+ * parent and don't get a separate interface.
+ */
+ if (!strncmp (plink->name, "bnep", STRLEN ("bnep")))
+ return;
+
if (device == NULL) {
- if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
- device = nm_device_olpc_mesh_new (sysfs_path, iface, driver);
- else if (is_wireless (udev_device))
- device = nm_device_wifi_new (sysfs_path, iface, driver);
- else if (is_infiniband (udev_device))
- device = nm_device_infiniband_new (sysfs_path, iface, driver);
- else if (is_bond (ifindex))
- device = nm_device_bond_new (sysfs_path, iface);
- else if (is_bridge (ifindex)) {
-
- /* FIXME: always create device when we handle bridges non-destructively */
- if (bridge_created_by_nm (self, iface))
- device = nm_device_bridge_new (sysfs_path, iface);
- else
- nm_log_info (LOGD_BRIDGE, "(%s): ignoring bridge not created by NetworkManager", iface);
- } else if (is_vlan (ifindex)) {
- int parent_ifindex = -1;
- NMDevice *parent;
+ int parent_ifindex = -1;
+ NMDevice *parent;
+ switch (plink->type) {
+ case NM_LINK_TYPE_ETHERNET:
+ device = nm_device_ethernet_new (plink);
+ break;
+ case NM_LINK_TYPE_INFINIBAND:
+ device = nm_device_infiniband_new (plink);
+ break;
+ case NM_LINK_TYPE_BOND:
+ device = nm_device_bond_new (plink);
+ break;
+ case NM_LINK_TYPE_TEAM:
+ device = nm_device_team_new (plink);
+ break;
+ case NM_LINK_TYPE_BRIDGE:
+ device = nm_device_bridge_new (plink);
+ break;
+ case NM_LINK_TYPE_VLAN:
/* Have to find the parent device */
- if (nm_system_get_iface_vlan_info (ifindex, &parent_ifindex, NULL)) {
+ if (nm_platform_vlan_get_info (ifindex, &parent_ifindex, NULL)) {
parent = find_device_by_ifindex (self, parent_ifindex);
if (parent)
- device = nm_device_vlan_new (sysfs_path, iface, parent);
+ device = nm_device_vlan_new (plink, parent);
else {
/* If udev signaled the VLAN interface before it signaled
* the VLAN's parent at startup we may not know about the
* parent device yet. But we'll find it on the second pass
* from nm_manager_start().
*/
- nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", iface);
+ nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name);
}
} else
- nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", iface);
- } else if (is_adsl (udev_device))
- device = nm_device_adsl_new (sysfs_path, iface, driver);
- else
- device = nm_device_ethernet_new (sysfs_path, iface, driver);
+ nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", plink->name);
+ break;
+ case NM_LINK_TYPE_VETH:
+ device = nm_device_veth_new (plink);
+ break;
+ case NM_LINK_TYPE_TUN:
+ case NM_LINK_TYPE_TAP:
+ device = nm_device_tun_new (plink);
+ break;
+ case NM_LINK_TYPE_MACVLAN:
+ case NM_LINK_TYPE_MACVTAP:
+ device = nm_device_macvlan_new (plink);
+ break;
+ case NM_LINK_TYPE_VXLAN:
+ device = nm_device_vxlan_new (plink);
+ break;
+ case NM_LINK_TYPE_GRE:
+ case NM_LINK_TYPE_GRETAP:
+ device = nm_device_gre_new (plink);
+ break;
+
+ case NM_LINK_TYPE_WWAN_ETHERNET:
+ /* WWAN pseudo-ethernet interfaces are handled automatically by
+ * their NMDeviceModem and don't get a separate NMDevice object.
+ */
+ break;
+
+ case NM_LINK_TYPE_OLPC_MESH:
+ case NM_LINK_TYPE_WIFI:
+ case NM_LINK_TYPE_WIMAX:
+ nm_log_info (LOGD_HW, "(%s): '%s' plugin not available; creating generic device",
+ plink->name, plink->type_name);
+ /* fall through */
+ default:
+ device = nm_device_generic_new (plink);
+ break;
+ }
}
- if (device)
- add_device (self, device);
+ if (device) {
+ add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK);
+ g_object_unref (device);
+ }
}
static void
-udev_device_removed_cb (NMUdevManager *manager,
- GUdevDevice *udev_device,
- gpointer user_data)
-{
- NMManager *self = NM_MANAGER (user_data);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMDevice *device;
- guint32 ifindex;
-
- ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
- device = find_device_by_ifindex (self, ifindex);
- if (!device) {
- GSList *iter;
- const char *iface = g_udev_device_get_name (udev_device);
-
- /* On removal we aren't always be able to read properties like IFINDEX
- * anymore, as they may have already been removed from sysfs. So we
- * have to fall back on device name (eg, interface name).
- *
- * Also, some devices (namely PPPoE (pppX), ADSL (nasX, pppX), and
- * mobile broadband (pppX, bnepX)) create a kernel netdevice for IP
- * communication (called the "IP interface" in NM) as part of the
- * connection process and thus the IP interface lifetime does not
- * correspond to the NMDevice lifetime. For these devices we must
- * ignore removal events for the IP interface name otherwise the
- * NMDevice would be removed. Hence the usage here of
- * nm_device_get_iface() rather than nm_device_get_ip_iface().
- */
- for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
- if (g_strcmp0 (nm_device_get_iface (NM_DEVICE (iter->data)), iface) == 0) {
- device = iter->data;
- break;
- }
- }
- }
+platform_link_cb (NMPlatform *platform,
+ int ifindex,
+ NMPlatformLink *plink,
+ NMPlatformSignalChangeType change_type,
+ NMPlatformReason reason,
+ gpointer user_data)
+{
+ switch (change_type) {
+ case NM_PLATFORM_SIGNAL_ADDED:
+ platform_link_added (NM_MANAGER (user_data), ifindex, plink, reason);
+ break;
+ case NM_PLATFORM_SIGNAL_REMOVED: {
+ NMManager *self = NM_MANAGER (user_data);
+ NMDevice *device;
- if (device)
- priv->devices = remove_one_device (self, priv->devices, device, FALSE);
+ device = find_device_by_ifindex (self, ifindex);
+ if (device)
+ remove_device (self, device, FALSE);
+ break;
+ }
+ default:
+ break;
+ }
}
static void
-udev_manager_rfkill_changed_cb (NMUdevManager *udev_mgr,
- RfKillType rtype,
- RfKillState udev_state,
- gpointer user_data)
+rfkill_manager_rfkill_changed_cb (NMRfkillManager *rfkill_mgr,
+ RfKillType rtype,
+ RfKillState udev_state,
+ gpointer user_data)
{
nm_manager_rfkill_update (NM_MANAGER (user_data), rtype);
}
-GSList *
+const GSList *
nm_manager_get_devices (NMManager *manager)
{
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
@@ -2503,54 +2191,18 @@ impl_manager_get_device_by_ip_iface (NMManager *self,
return path ? TRUE : FALSE;
}
-static NMActiveConnection *
-internal_activate_device (NMManager *manager,
- NMDevice *device,
- NMConnection *connection,
- const char *specific_object,
- gboolean user_requested,
- gulong sender_uid,
- const char *dbus_sender,
- gboolean assumed,
- NMActiveConnection *master,
- GError **error)
+static gboolean
+is_compatible_with_slave (NMConnection *master, NMConnection *slave)
{
- NMActRequest *req;
- NMDevice *master_device = NULL;
-
- 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);
-
- /* Ensure the requested connection is compatible with the device */
- if (!nm_device_check_connection_compatible (device, connection, error))
- return NULL;
-
- /* Tear down any existing connection */
- if (nm_device_get_act_request (device)) {
- nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.",
- nm_device_get_iface (device));
- nm_device_state_changed (device,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- }
+ NMSettingConnection *s_con;
- if (master)
- master_device = nm_active_connection_get_device (master);
+ g_return_val_if_fail (master, FALSE);
+ g_return_val_if_fail (slave, FALSE);
- req = nm_act_request_new (connection,
- specific_object,
- user_requested,
- sender_uid,
- dbus_sender,
- assumed,
- device,
- master_device);
- g_assert (req);
- active_connection_add (manager, NM_ACTIVE_CONNECTION (req));
- nm_device_activate (device, req);
+ s_con = nm_connection_get_setting_connection (slave);
+ g_assert (s_con);
- return NM_ACTIVE_CONNECTION (req);
+ return nm_connection_is_type (master, nm_setting_connection_get_slave_type (s_con));
}
/**
@@ -2562,14 +2214,35 @@ internal_activate_device (NMManager *manager,
* that master connection was found
* @out_master_device: on success, the master device of @connection if that
* master device was found
+ * @out_master_ac: on success, the master ActiveConnection of @connection if
+ * there already is one
+ * @error: the error, if an error occurred
+ *
+ * Given an #NMConnection, attempts to find its master. If @connection has
+ * no master, this will return %TRUE and @out_master_connection and
+ * @out_master_device will be untouched.
*
- * Given an #NMConnection, attempts to find its master connection and/or its
- * master device. This function may return a master connection, a master device,
- * or both. If only a connection is returned, that master connection is not
- * currently active on any device. If only a device is returned, that device
- * is not currently activated with any connection. If both are returned, then
- * the device is currently activated or activating with the returned master
- * connection.
+ * If @connection does have a master, then the outputs depend on what is in its
+ * #NMSettingConnection:master property:
+ *
+ * If "master" is the ifname of an existing #NMDevice, and that device has a
+ * compatible master connection activated or activating on it, then
+ * @out_master_device, @out_master_connection, and @out_master_ac will all be
+ * set. If the device exists and is idle, only @out_master_device will be set.
+ * If the device exists and has an incompatible connection on it, an error
+ * will be returned.
+ *
+ * If "master" is the ifname of a non-existent device, then @out_master_device
+ * will be %NULL, and @out_master_connection will be a connection whose
+ * activation would cause the creation of that device. @out_master_ac MAY be
+ * set in this case as well (if the connection has started activating, but has
+ * not yet created its device).
+ *
+ * If "master" is the UUID of a compatible master connection, then
+ * @out_master_connection will be the identified connection, and @out_master_device
+ * and/or @out_master_ac will be set if the connection is currently activating.
+ * (@out_master_device will not be set if the device exists but does not have
+ * @out_master_connection active/activating on it.)
*
* Returns: %TRUE if the master device and/or connection could be found or if
* the connection did not require a master, %FALSE otherwise
@@ -2579,7 +2252,9 @@ find_master (NMManager *self,
NMConnection *connection,
NMDevice *device,
NMConnection **out_master_connection,
- NMDevice **out_master_device)
+ NMDevice **out_master_device,
+ NMActiveConnection **out_master_ac,
+ GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMSettingConnection *s_con;
@@ -2598,9 +2273,20 @@ find_master (NMManager *self,
/* Try as an interface name first */
master_device = find_device_by_ip_iface (self, master);
if (master_device) {
- /* A device obviously can't be its own master */
- if (master_device == device)
+ if (master_device == device) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
+ "Device cannot be its own master");
return FALSE;
+ }
+
+ master_connection = nm_device_get_connection (master_device);
+ if (master_connection && !is_compatible_with_slave (master_connection, connection)) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
+ "The active connection on %s is not a valid master for '%s'",
+ nm_device_get_iface (master_device),
+ nm_connection_get_id (connection));
+ return FALSE;
+ }
} else {
/* Try master as a connection UUID */
master_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, master);
@@ -2623,14 +2309,15 @@ find_master (NMManager *self,
* virtual interfaces and see if one of their virtual interface
* names matches the master.
*/
- connections = nm_settings_get_connections (priv->settings);
+ connections = nm_manager_get_activatable_connections (self);
for (iter = connections; iter && !master_connection; iter = g_slist_next (iter)) {
NMConnection *candidate = iter->data;
char *vname;
if (connection_needs_virtual_device (candidate)) {
vname = get_virtual_iface_name (self, candidate, NULL);
- if (g_strcmp0 (master, vname) == 0)
+ if ( g_strcmp0 (master, vname) == 0
+ && is_compatible_with_slave (candidate, connection))
master_connection = candidate;
g_free (vname);
}
@@ -2643,46 +2330,49 @@ find_master (NMManager *self,
*out_master_connection = master_connection;
if (out_master_device)
*out_master_device = master_device;
+ if (out_master_ac && master_connection)
+ *out_master_ac = find_ac_for_connection (self, master_connection);
- return master_device || master_connection;
-}
-
-static gboolean
-is_compatible_with_slave (NMConnection *master, NMConnection *slave)
-{
- NMSettingConnection *s_con;
-
- g_return_val_if_fail (master, FALSE);
- g_return_val_if_fail (slave, FALSE);
-
- s_con = nm_connection_get_setting_connection (slave);
- g_assert (s_con);
-
- return nm_connection_is_type (master, nm_setting_connection_get_slave_type (s_con));
+ if (master_device || master_connection)
+ return TRUE;
+ else {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Master connection not found or invalid");
+ return FALSE;
+ }
}
/**
* ensure_master_active_connection:
- *
* @self: the #NMManager
- * @dbus_sender: if the request was initiated by a user via D-Bus, the
- * dbus sender name of the client that requested the activation; for auto
- * activated connections use %NULL
+ * @subject: the #NMAuthSubject representing the requestor of this activation
* @connection: the connection that should depend on @master_connection
* @device: the #NMDevice, if any, which will activate @connection
- * @master_connection: the master connection
- * @master_device: the master device
+ * @master_connection: the master connection, or %NULL
+ * @master_device: the master device, or %NULL
* @error: the error, if an error occurred
*
* Determines whether a given #NMConnection depends on another connection to
* be activated, and if so, finds that master connection or creates it.
*
+ * If @master_device and @master_connection are both set then @master_connection
+ * MUST already be activated or activating on @master_device, and the function will
+ * return the existing #NMActiveConnection.
+ *
+ * If only @master_device is set, and it has an #NMActiveConnection, then the
+ * function will return it if it is a compatible master, or an error if not. If it
+ * doesn't have an AC, then the function will create one if a compatible master
+ * connection exists, or return an error if not.
+ *
+ * If only @master_connection is set, then this will try to find or create a compatible
+ * #NMDevice, and either activate @master_connection on that device or return an error.
+ *
* Returns: the master #NMActiveConnection that the caller should depend on, or
* %NULL if an error occurred
*/
static NMActiveConnection *
ensure_master_active_connection (NMManager *self,
- const char *dbus_sender,
+ NMAuthSubject *subject,
NMConnection *connection,
NMDevice *device,
NMConnection *master_connection,
@@ -2701,20 +2391,29 @@ ensure_master_active_connection (NMManager *self,
* compatible connection. If it's already activating we can just proceed.
*/
if (master_device) {
+ NMConnection *device_connection = nm_device_get_connection (master_device);
+
/* If we're passed a connection and a device, we require that connection
* be already activated on the device, eg returned from find_master().
*/
- if (master_connection)
- g_assert (nm_device_get_connection (master_device) == master_connection);
+ g_assert (!master_connection || master_connection == device_connection);
+ if (device_connection && !is_compatible_with_slave (device_connection, connection)) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
+ "The active connection on %s is not a valid master for '%s'",
+ nm_device_get_iface (master_device),
+ nm_connection_get_id (connection));
+ return NULL;
+ }
master_state = nm_device_get_state (master_device);
if ( (master_state == NM_DEVICE_STATE_ACTIVATED)
|| nm_device_is_activating (master_device)) {
/* Device already using master_connection */
+ g_assert (device_connection);
return NM_ACTIVE_CONNECTION (nm_device_get_act_request (master_device));
}
- /* If the device is disconnected, find a compabile connection and
+ /* If the device is disconnected, find a compatible connection and
* activate it on the device.
*/
if (master_state == NM_DEVICE_STATE_DISCONNECTED) {
@@ -2723,20 +2422,22 @@ ensure_master_active_connection (NMManager *self,
g_assert (master_connection == NULL);
/* Find a compatible connection and activate this device using it */
- connections = nm_settings_get_connections (priv->settings);
+ connections = nm_manager_get_activatable_connections (self);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
- /* Ensure eg bond slave and the candidate master is a bond master */
+ /* Ensure eg bond/team slave and the candidate master is a
+ * bond/team master
+ */
if (!is_compatible_with_slave (candidate, connection))
continue;
- if (nm_device_check_connection_compatible (master_device, candidate, NULL)) {
+ if (nm_device_connection_is_available (master_device, candidate, TRUE)) {
master_ac = nm_manager_activate_connection (self,
candidate,
NULL,
- nm_device_get_path (master_device),
- dbus_sender,
+ master_device,
+ subject,
error);
if (!master_ac)
g_prefix_error (error, "%s", "Master device activation failed: ");
@@ -2772,7 +2473,7 @@ ensure_master_active_connection (NMManager *self,
continue;
}
- if (!nm_device_check_connection_compatible (candidate, master_connection, NULL))
+ if (!nm_device_connection_is_available (candidate, master_connection, TRUE))
continue;
found_device = TRUE;
@@ -2783,8 +2484,8 @@ ensure_master_active_connection (NMManager *self,
master_ac = nm_manager_activate_connection (self,
master_connection,
NULL,
- nm_device_get_path (candidate),
- dbus_sender,
+ candidate,
+ subject,
error);
if (!master_ac)
g_prefix_error (error, "%s", "Master device activation failed: ");
@@ -2799,7 +2500,7 @@ ensure_master_active_connection (NMManager *self,
master_connection,
NULL,
NULL,
- dbus_sender,
+ subject,
error);
if (!master_ac)
g_prefix_error (error, "%s", "Master device activation failed: ");
@@ -2817,239 +2518,133 @@ ensure_master_active_connection (NMManager *self,
return NULL;
}
-static NMActiveConnection *
-activate_vpn_connection (NMManager *self,
- NMConnection *connection,
- const char *specific_object,
- gulong sender_uid,
- GError **error)
+static gboolean
+_internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **error)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMActiveConnection *parent = NULL, *ac;
- NMDevice *device = NULL;
- GSList *iter;
-
- if (specific_object) {
- /* Find the specifc connection the client requested we use */
- parent = active_connection_get_by_path (self, specific_object);
- if (!parent) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
- "Base connection for VPN connection not active.");
- return NULL;
- }
- } else {
- for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
- NMActiveConnection *candidate = iter->data;
-
- if (nm_active_connection_get_default (candidate)) {
- parent = candidate;
- break;
- }
- }
- }
+ gboolean success;
- if (!parent) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
- "Could not find source connection.");
- return NULL;
- }
+ g_assert (NM_IS_VPN_CONNECTION (active));
- device = nm_active_connection_get_device (parent);
- if (!device) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Source connection had no active device.");
- return NULL;
+ success = nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager,
+ NM_VPN_CONNECTION (active),
+ error);
+ if (success) {
+ nm_active_connection_export (active);
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
}
-
- ac = nm_vpn_manager_activate_connection (priv->vpn_manager,
- connection,
- device,
- nm_active_connection_get_path (parent),
- TRUE,
- sender_uid,
- error);
- if (ac)
- active_connection_add (self, ac);
- return ac;
+ return success;
}
-NMActiveConnection *
-nm_manager_activate_connection (NMManager *manager,
- NMConnection *connection,
- const char *specific_object,
- const char *device_path,
- const char *dbus_sender,
- GError **error)
+static gboolean
+_internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error)
{
- NMManagerPrivate *priv;
- NMDevice *device = NULL;
- gulong sender_uid = 0;
- DBusError dbus_error;
- NMDeviceState state;
- char *iface;
- NMDevice *master_device = NULL;
+ NMDevice *device, *master_device = NULL;
+ NMConnection *connection;
NMConnection *master_connection = NULL;
- NMConnection *existing_connection = NULL;
NMActiveConnection *master_ac = NULL;
- gboolean matched;
- char *error_desc = NULL;
- 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);
+ g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
+ g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- priv = NM_MANAGER_GET_PRIVATE (manager);
+ g_assert (NM_IS_VPN_CONNECTION (active) == FALSE);
- /* Get the UID of the user that originated the request, if any */
- if (dbus_sender) {
- dbus_error_init (&dbus_error);
- sender_uid = dbus_bus_get_unix_user (nm_dbus_manager_get_dbus_connection (priv->dbus_mgr),
- dbus_sender,
- &dbus_error);
- if (dbus_error_is_set (&dbus_error)) {
- g_set_error_literal (error,
- NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED,
- "Failed to get unix user for dbus sender");
- dbus_error_free (&dbus_error);
- return NULL;
+ connection = nm_active_connection_get_connection (active);
+ g_assert (connection);
+
+ device = nm_active_connection_get_device (active);
+ if (!device) {
+ if (!connection_needs_virtual_device (connection)) {
+ NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
+
+ g_assert (s_con);
+ g_set_error (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Unsupported virtual interface type '%s'",
+ nm_setting_connection_get_connection_type (s_con));
+ return FALSE;
}
- /* Ensure the subject has permissions for this connection */
- if (!nm_auth_uid_in_acl (connection,
- priv->session_monitor,
- sender_uid,
- &error_desc)) {
+ device = system_create_virtual_device (self, connection);
+ if (!device) {
g_set_error_literal (error,
NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- g_free (error_desc);
- return NULL;
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Failed to create virtual interface");
+ return FALSE;
}
- }
-
- /* VPN ? */
- if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
- return activate_vpn_connection (manager, connection, specific_object, sender_uid, error);
- /* Device-based connection */
- if (device_path) {
- device = nm_manager_get_device_by_path (manager, device_path);
- if (!device) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Device not found");
- return NULL;
+ if (!nm_active_connection_set_device (active, device)) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "The device could not be activated with this connection");
+ return FALSE;
}
- /* If it's a virtual interface make sure the device given by the
- * path matches the connection's interface details.
+ /* A newly created device, if allowed to be managed by NM, will be
+ * in the UNAVAILABLE state here. To ensure it can be activated
+ * immediately, we transition it to DISCONNECTED.
*/
- if (connection_needs_virtual_device (connection)) {
- iface = get_virtual_iface_name (manager, connection, NULL);
- if (!iface) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to determine connection's virtual interface name");
- return NULL;
- }
-
- matched = g_str_equal (iface, nm_device_get_ip_iface (device));
- g_free (iface);
- if (!matched) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Device given by path did not match connection's virtual interface name");
- return NULL;
- }
+ if ( nm_device_is_available (device)
+ && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_NONE);
}
} else {
- /* Virtual connections (VLAN, bond, etc) may not specify a device
- * path because the device may not be created yet, or it be given
- * by the connection's properties instead. Find the device the
- * connection refers to, or create it if needed.
- */
- if (!connection_needs_virtual_device (connection)) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "This connection requires an existing device.");
- return NULL;
- }
-
- iface = get_virtual_iface_name (manager, connection, NULL);
- if (!iface) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to determine connection's virtual interface name");
- return NULL;
- }
-
- device = find_device_by_ip_iface (manager, iface);
- g_free (iface);
- if (!device) {
- /* Create it */
- device = system_create_virtual_device (manager, connection);
- if (!device) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to create virtual interface");
- return NULL;
- }
-
- /* A newly created device, if allowed to be managed by NM, will be
- * in the UNAVAILABLE state here. Since we want to use it right
- * away, we transition it immediately to DISCONNECTED.
- */
- if ( nm_device_is_available (device)
- && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- }
- }
- }
+ NMConnection *existing_connection = NULL;
+ NMAuthSubject *subject;
+ char *error_desc = NULL;
- state = nm_device_get_state (device);
- if (state < NM_DEVICE_STATE_DISCONNECTED) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
- "Device not managed by NetworkManager or unavailable");
- return NULL;
- }
-
- /* If this is an autoconnect request, but the device isn't allowing autoconnect
- * right now, we reject it.
- */
- if (!dbus_sender && !nm_device_autoconnect_allowed (device)) {
- g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
- "%s does not allow automatic connections at this time",
- nm_device_get_iface (device));
- return NULL;
- }
-
- if (dbus_sender) {
/* If the device is active and its connection is not visible to the
* user that's requesting this new activation, fail, since other users
* should not be allowed to implicitly deactivate private connections
* by activating a connection of their own.
*/
existing_connection = nm_device_get_connection (device);
+ subject = nm_active_connection_get_subject (active);
if (existing_connection &&
!nm_auth_uid_in_acl (existing_connection,
- priv->session_monitor,
- sender_uid,
- &error_desc)) {
+ nm_session_monitor_get (),
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
g_set_error (error,
- NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- "Private connection already active on the device: %s",
- error_desc);
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Private connection already active on the device: %s",
+ error_desc);
g_free (error_desc);
return FALSE;
}
}
- /* Try to find the master connection/device if the connection has a dependency */
- if (!find_master (manager, connection, device, &master_connection, &master_device)) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Master connection not found or invalid");
- return NULL;
+ /* Final connection must be available on device */
+ if (!nm_device_connection_is_available (device, connection, TRUE)) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "Connection '%s' is not available on the device %s at this time.",
+ nm_connection_get_id (connection), nm_device_get_iface (device));
+ return FALSE;
+ }
+
+ /* If this is an autoconnect request, but the device isn't allowing autoconnect
+ * right now, we reject it.
+ */
+ if (!nm_active_connection_get_user_requested (active) &&
+ !nm_device_autoconnect_allowed (device)) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
+ "%s does not allow automatic connections at this time",
+ nm_device_get_iface (device));
+ return FALSE;
}
+ /* Try to find the master connection/device if the connection has a dependency */
+ if (!find_master (self, connection, device,
+ &master_connection, &master_device, &master_ac,
+ error))
+ return FALSE;
+
/* Ensure there's a master active connection the new connection we're
* activating can depend on.
*/
@@ -3068,94 +2663,395 @@ nm_manager_activate_connection (NMManager *manager,
/* Ensure eg bond slave and the candidate master is a bond master */
if (master_connection && !is_compatible_with_slave (master_connection, connection)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
- "The master connection was not compatible");
- return NULL;
+ "The master connection was not compatible");
+ return FALSE;
}
- master_ac = ensure_master_active_connection (manager,
- dbus_sender,
- connection,
- device,
- master_connection,
- master_device,
- error);
if (!master_ac) {
- if (error)
- g_assert (*error);
- return NULL;
+ master_ac = ensure_master_active_connection (self,
+ nm_active_connection_get_subject (active),
+ connection,
+ device,
+ master_connection,
+ master_device,
+ error);
+ if (!master_ac) {
+ if (error)
+ g_assert (*error);
+ return FALSE;
+ }
}
+ nm_active_connection_set_master (active, master_ac);
nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %s",
nm_connection_get_id (connection),
nm_active_connection_get_path (master_ac));
}
- return internal_activate_device (manager,
- device,
+ /* Export the new ActiveConnection to clients and start it on the device */
+ nm_active_connection_export (active);
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+ nm_device_queue_activation (device, NM_ACT_REQUEST (active));
+ return TRUE;
+}
+
+static gboolean
+_internal_activate_generic (NMManager *self, NMActiveConnection *active, GError **error)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ gboolean success = FALSE;
+
+ /* Ensure activation request is still valid, eg that its device hasn't gone
+ * away or that some other dependency has not failed.
+ */
+ if (nm_active_connection_get_state (active) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_DEPENDENCY_FAILED,
+ "Activation failed because dependencies failed.");
+ return FALSE;
+ }
+
+ if (NM_IS_VPN_CONNECTION (active))
+ success = _internal_activate_vpn (self, active, error);
+ else
+ success = _internal_activate_device (self, active, error);
+
+ if (success) {
+ /* Force an update of the Manager's activating-connection property.
+ * The device changes state before the AC gets exported, which causes
+ * the manager's 'activating-connection' property to be NULL since the
+ * AC only gets a D-Bus path when it's exported. So now that the AC
+ * is exported, make sure the manager's activating-connection property
+ * is up-to-date.
+ */
+ policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self);
+ }
+
+ return success;
+}
+
+static NMActiveConnection *
+_new_vpn_active_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMAuthSubject *subject,
+ GError **error)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ NMActiveConnection *parent = NULL;
+ NMDevice *device = NULL;
+
+ if (specific_object) {
+ /* Find the specific connection the client requested we use */
+ parent = active_connection_get_by_path (self, specific_object);
+ if (!parent) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+ "Base connection for VPN connection not active.");
+ return NULL;
+ }
+ } else
+ parent = priv->primary_connection;
+
+ if (!parent) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "Could not find source connection.");
+ return NULL;
+ }
+
+ device = nm_active_connection_get_device (parent);
+ if (!device) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Source connection had no active device.");
+ return NULL;
+ }
+
+ return (NMActiveConnection *) nm_vpn_connection_new (connection,
+ device,
+ nm_active_connection_get_path (parent),
+ subject);
+}
+
+static NMActiveConnection *
+_new_active_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMDevice *device,
+ NMAuthSubject *subject,
+ GError **error)
+{
+ NMActiveConnection *existing_ac;
+
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
+
+ /* Can't create new AC for already-active connection */
+ existing_ac = find_ac_for_connection (self, connection);
+ if (NM_IS_VPN_CONNECTION (existing_ac)) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE,
+ "Connection '%s' is already active",
+ nm_connection_get_id (connection));
+ return NULL;
+ }
+
+ if (existing_ac) {
+ NMDevice *existing_device = nm_active_connection_get_device (existing_ac);
+
+ if (existing_device != device) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE,
+ "Connection '%s' is already active on %s",
+ nm_connection_get_id (connection),
+ nm_device_get_iface (existing_device));
+ return NULL;
+ }
+ }
+
+ /* Normalize the specific object */
+ if (specific_object && g_strcmp0 (specific_object, "/") == 0)
+ specific_object = NULL;
+
+ if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) {
+ return _new_vpn_active_connection (self,
+ connection,
+ specific_object,
+ subject,
+ error);
+ }
+
+ return (NMActiveConnection *) nm_act_request_new (connection,
+ specific_object,
+ subject,
+ device);
+}
+
+static void
+_internal_activation_failed (NMManager *self,
+ NMActiveConnection *active,
+ const char *error_desc)
+{
+ nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s",
+ nm_connection_get_id (nm_active_connection_get_connection (active)),
+ error_desc);
+
+ if (nm_active_connection_get_state (active) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+ nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING);
+ nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
+ }
+ active_connection_remove (self, active);
+}
+
+static void
+_internal_activation_auth_done (NMActiveConnection *active,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2)
+{
+ NMManager *self = user_data1;
+ GError *error = NULL;
+
+ if (success) {
+ if (_internal_activate_generic (self, active, &error)) {
+ g_object_unref (active);
+ return;
+ }
+ }
+
+ g_assert (error_desc || error);
+ _internal_activation_failed (self, active, error_desc ? error_desc : error->message);
+ g_object_unref (active);
+ g_clear_error (&error);
+}
+
+/**
+ * nm_manager_activate_connection():
+ * @self: the #NMManager
+ * @connection: the #NMConnection to activate on @device
+ * @specific_object: the specific object path, if any, for the activation
+ * @device: the #NMDevice to activate @connection on
+ * @subject: the subject which requested activation
+ * @error: return location for an error
+ *
+ * Begins a new internally-initiated activation of @connection on @device.
+ * @subject should be the subject of the activation that triggered this
+ * one, or if this is an autoconnect request, a new internal subject.
+ * The returned #NMActiveConnection is owned by the Manager and should be
+ * referenced by the caller if the caller continues to use it.
+ *
+ * Returns: (transfer none): the new #NMActiveConnection that tracks
+ * activation of @connection on @device
+ */
+NMActiveConnection *
+nm_manager_activate_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMDevice *device,
+ NMAuthSubject *subject,
+ GError **error)
+{
+ NMActiveConnection *active;
+ char *error_desc = NULL;
+
+ g_return_val_if_fail (self != 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);
+
+ /* Ensure the subject has permissions for this connection */
+ if (!nm_auth_uid_in_acl (connection,
+ nm_session_monitor_get (),
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ error_desc);
+ g_free (error_desc);
+ return NULL;
+ }
+
+ active = _new_active_connection (self,
connection,
specific_object,
- dbus_sender ? TRUE : FALSE,
- dbus_sender ? sender_uid : 0,
- dbus_sender,
- FALSE,
- master_ac,
+ device,
+ subject,
error);
+ if (active) {
+ nm_active_connection_authorize (active, _internal_activation_auth_done, self, NULL);
+ active_connection_add (self, active);
+ }
+ return active;
}
-/*
- * TODO this function was created and named in the era of user settings, where
- * we could get activation requests for a connection before we got the settings
- * data of that connection. Now that user settings are gone, flatten or rename
- * it.
- */
-static void
-pending_activate (NMManager *self, PendingActivation *pending)
+static NMAuthSubject *
+validate_activation_request (NMManager *self,
+ DBusGMethodInvocation *context,
+ NMConnection *connection,
+ const char *device_path,
+ NMDevice **out_device,
+ gboolean *out_vpn,
+ GError **error)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMSettingsConnection *connection;
- NMActiveConnection *ac = NULL;
- GError *error = NULL;
- char *sender;
+ NMDevice *device = NULL;
+ gboolean vpn = FALSE;
+ NMAuthSubject *subject = NULL;
+ char *error_desc = NULL;
- /* Ok, we're authorized */
+ g_assert (connection);
+ g_assert (out_device);
+ g_assert (out_vpn);
- connection = nm_settings_get_connection_by_path (priv->settings, pending->connection_path);
- if (!connection) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
- "Connection could not be found.");
- goto out;
+ /* Validate the caller */
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Failed to get request UID.");
+ return NULL;
}
- sender = dbus_g_method_get_sender (pending->context);
- g_assert (sender);
- ac = nm_manager_activate_connection (self,
- NM_CONNECTION (connection),
- pending->specific_object_path,
- pending->device_path,
- sender,
- &error);
- g_free (sender);
+ /* Ensure the subject has permissions for this connection */
+ if (!nm_auth_uid_in_acl (connection,
+ nm_session_monitor_get (),
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ error_desc);
+ g_free (error_desc);
+ goto error;
+ }
- if (!ac) {
- nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s",
- pending->connection_path,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
+ /* Check whether it's a VPN or not */
+ if ( nm_connection_get_setting_vpn (connection)
+ || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
+ vpn = TRUE;
+
+ /* Normalize device path */
+ if (device_path && g_strcmp0 (device_path, "/") == 0)
+ device_path = NULL;
+
+ /* And validate it */
+ if (device_path) {
+ device = nm_manager_get_device_by_path (self, device_path);
+ if (!device) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Device not found");
+ goto error;
+ }
+ } else {
+ gboolean is_software = connection_needs_virtual_device (connection);
+
+ /* VPN and software-device connections don't need a device yet */
+ if (!vpn && !is_software) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "This connection requires an existing device.");
+ goto error;
+ }
+
+ if (is_software) {
+ /* Look for an existing device with the connection's interface name */
+ char *iface;
+
+ iface = get_virtual_iface_name (self, connection, NULL);
+ if (!iface) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Failed to determine connection's virtual interface name");
+ goto error;
+ }
+
+ device = find_device_by_ip_iface (self, iface);
+ g_free (iface);
+ }
}
-out:
- pending_activation_destroy (pending, error, ac);
- g_clear_error (&error);
+ *out_device = device;
+ *out_vpn = vpn;
+ return subject;
+
+error:
+ g_object_unref (subject);
+ return NULL;
}
+/***********************************************************************/
+
static void
-activation_auth_done (PendingActivation *pending, GError *error)
-{
- if (error)
- pending_activation_destroy (pending, error, NULL);
- else
- pending_activate (pending->manager, pending);
+_activation_auth_done (NMActiveConnection *active,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2)
+{
+ NMManager *self = user_data1;
+ DBusGMethodInvocation *context = user_data2;
+ GError *error = NULL;
+
+ if (success) {
+ if (_internal_activate_generic (self, active, &error)) {
+ dbus_g_method_return (context, nm_active_connection_get_path (active));
+ g_object_unref (active);
+ return;
+ }
+ } else {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ error_desc);
+ }
+
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ _internal_activation_failed (self, active, error->message);
+ g_object_unref (active);
+ g_error_free (error);
}
static void
@@ -3166,64 +3062,185 @@ impl_manager_activate_connection (NMManager *self,
DBusGMethodInvocation *context)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- PendingActivation *pending;
+ NMActiveConnection *active = NULL;
+ NMAuthSubject *subject = NULL;
+ NMConnection *connection;
+ NMDevice *device = NULL;
+ gboolean is_vpn = FALSE;
GError *error = NULL;
- /* Need to check the caller's permissions and stuff before we can
- * activate the connection.
+ /* Normalize object paths */
+ if (g_strcmp0 (connection_path, "/") == 0)
+ connection_path = NULL;
+ if (g_strcmp0 (specific_object_path, "/") == 0)
+ specific_object_path = NULL;
+ if (g_strcmp0 (device_path, "/") == 0)
+ device_path = NULL;
+
+ /* If the connection path is given and valid, that connection is activated.
+ * Otherwise the "best" connection for the device is chosen and activated,
+ * regardless of whether that connection is autoconnect-enabled or not
+ * (since this is an explicit request, not an auto-activation request).
*/
- pending = pending_activation_new (self,
- context,
- device_path,
- connection_path,
- NULL,
- specific_object_path,
- activation_auth_done,
- &error);
- if (pending)
- pending_activation_check_authorized (pending, priv->dbus_mgr);
- else {
- g_assert (error);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
+ if (!connection_path) {
+ GPtrArray *available;
+ guint64 best_timestamp = 0;
+ guint i;
+
+ /* If no connection is given, find a suitable connection for the given device path */
+ if (!device_path) {
+ error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Only devices may be activated without a specifying a connection");
+ goto error;
+ }
+ device = nm_manager_get_device_by_path (self, device_path);
+ if (!device) {
+ error = g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Cannot activate unknown device %s", device_path);
+ goto error;
+ }
+
+ available = nm_device_get_available_connections (device, specific_object_path);
+ for (i = 0; available && i < available->len; i++) {
+ NMSettingsConnection *candidate = g_ptr_array_index (available, i);
+ guint64 candidate_timestamp = 0;
+
+ nm_settings_connection_get_timestamp (candidate, &candidate_timestamp);
+ if (!connection_path || (candidate_timestamp > best_timestamp)) {
+ connection_path = nm_connection_get_path (NM_CONNECTION (candidate));
+ best_timestamp = candidate_timestamp;
+ }
+ }
+
+ if (available)
+ g_ptr_array_free (available, TRUE);
+
+ if (!connection_path) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "The device has no connections available.");
+ goto error;
+ }
+ }
+
+ g_assert (connection_path);
+ connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path);
+ if (!connection) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "Connection could not be found.");
+ goto error;
}
+
+ subject = validate_activation_request (self,
+ context,
+ connection,
+ device_path,
+ &device,
+ &is_vpn,
+ &error);
+ if (!subject)
+ goto error;
+
+ active = _new_active_connection (self,
+ connection,
+ specific_object_path,
+ device,
+ subject,
+ &error);
+ if (!active)
+ goto error;
+
+ nm_active_connection_authorize (active, _activation_auth_done, self, context);
+ active_connection_add (self, active);
+ g_clear_object (&subject);
+ return;
+
+error:
+ g_clear_object (&active);
+ g_clear_object (&subject);
+
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
+/***********************************************************************/
+
+typedef struct {
+ NMManager *manager;
+ NMActiveConnection *active;
+} AddAndActivateInfo;
+
static void
activation_add_done (NMSettings *self,
- NMSettingsConnection *connection,
+ NMSettingsConnection *new_connection,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
- PendingActivation *pending = user_data;
+ AddAndActivateInfo *info = user_data;
+ GError *local = NULL;
- if (error)
- pending_activation_destroy (pending, error, NULL);
- else {
- /* Save the new connection's D-Bus path */
- pending->connection_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection)));
+ if (!error) {
+ nm_active_connection_set_connection (info->active, NM_CONNECTION (new_connection));
- /* And activate it */
- pending_activate (pending->manager, pending);
+ if (_internal_activate_generic (info->manager, info->active, &local)) {
+ dbus_g_method_return (context,
+ nm_connection_get_path (NM_CONNECTION (new_connection)),
+ nm_active_connection_get_path (info->active));
+ goto done;
+ }
+ error = local;
}
+
+ g_assert (error);
+ _internal_activation_failed (info->manager, info->active, error->message);
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&local);
+
+done:
+ g_object_unref (info->active);
+ g_free (info);
}
static void
-add_and_activate_auth_done (PendingActivation *pending, GError *error)
+_add_and_activate_auth_done (NMActiveConnection *active,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2)
{
- if (error)
- pending_activation_destroy (pending, error, NULL);
- else {
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager);
+ NMManager *self = user_data1;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ DBusGMethodInvocation *context = user_data2;
+ AddAndActivateInfo *info;
+ GError *error = NULL;
+
+ if (success) {
+ info = g_malloc0 (sizeof (*info));
+ info->manager = self;
+ info->active = g_object_ref (active);
/* Basic sender auth checks performed; try to add the connection */
- nm_settings_add_connection (priv->settings,
- pending->connection,
- pending->context,
- activation_add_done,
- pending);
+ nm_settings_add_connection_dbus (priv->settings,
+ nm_active_connection_get_connection (active),
+ TRUE,
+ context,
+ activation_add_done,
+ info);
+ } else {
+ active_connection_remove (self, active);
+
+ g_assert (error_desc);
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ error_desc);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
+
+ g_object_unref (active);
}
static void
@@ -3234,29 +3251,105 @@ impl_manager_add_and_activate_connection (NMManager *self,
DBusGMethodInvocation *context)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- PendingActivation *pending;
+ NMConnection *connection = NULL;
+ GSList *all_connections = NULL;
+ NMActiveConnection *active = NULL;
+ NMAuthSubject *subject = NULL;
GError *error = NULL;
+ NMDevice *device = NULL;
+ gboolean vpn = FALSE;
- /* Need to check the caller's permissions and stuff before we can
- * activate the connection.
+ /* Normalize object paths */
+ if (g_strcmp0 (specific_object_path, "/") == 0)
+ specific_object_path = NULL;
+ if (g_strcmp0 (device_path, "/") == 0)
+ device_path = NULL;
+
+ /* Try to create a new connection with the given settings.
+ * We allow empty settings for AddAndActivateConnection(). In that case,
+ * the connection will be completed in nm_utils_complete_generic() or
+ * nm_device_complete_connection() below. Just make sure we don't expect
+ * specific data being in the connection till then (especially in
+ * validate_activation_request()).
*/
- pending = pending_activation_new (self,
- context,
- device_path,
- NULL,
- settings,
- specific_object_path,
- add_and_activate_auth_done,
- &error);
- if (pending)
- pending_activation_check_authorized (pending, priv->dbus_mgr);
- else {
- g_assert (error);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- }
+ connection = nm_connection_new ();
+ if (settings && g_hash_table_size (settings))
+ nm_connection_replace_settings (connection, settings, NULL);
+
+ subject = validate_activation_request (self,
+ context,
+ connection,
+ device_path,
+ &device,
+ &vpn,
+ &error);
+ if (!subject)
+ goto error;
+
+ /* AddAndActivate() requires a device to complete the connection with */
+ if (!device) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "This connection requires an existing device.");
+ goto error;
+ }
+
+ all_connections = nm_settings_get_connections (priv->settings);
+ if (vpn) {
+ /* Try to fill the VPN's connection setting and name at least */
+ if (!nm_connection_get_setting_vpn (connection)) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
+ "VPN connections require a 'vpn' setting");
+ goto error;
+ }
+
+ nm_utils_complete_generic (connection,
+ NM_SETTING_VPN_SETTING_NAME,
+ all_connections,
+ _("VPN connection %d"),
+ NULL,
+ FALSE); /* No IPv6 by default for now */
+ } else {
+ /* Let each device subclass complete the connection */
+ if (!nm_device_complete_connection (device,
+ connection,
+ specific_object_path,
+ all_connections,
+ &error))
+ goto error;
+ }
+ g_slist_free (all_connections);
+ all_connections = NULL;
+
+ active = _new_active_connection (self,
+ connection,
+ specific_object_path,
+ device,
+ subject,
+ &error);
+ if (!active)
+ goto error;
+
+ nm_active_connection_authorize (active, _add_and_activate_auth_done, self, context);
+ active_connection_add (self, active);
+ g_object_unref (connection);
+ g_object_unref (subject);
+ return;
+
+error:
+ g_clear_object (&connection);
+ g_slist_free (all_connections);
+ g_clear_object (&subject);
+ g_clear_object (&active);
+
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
+/***********************************************************************/
+
gboolean
nm_manager_deactivate_connection (NMManager *manager,
const char *connection_path,
@@ -3286,9 +3379,8 @@ nm_manager_deactivate_connection (NMManager *manager,
"The VPN connection was not active.");
} else {
g_assert (NM_IS_ACT_REQUEST (active));
- /* FIXME: use DEACTIVATING state */
nm_device_state_changed (nm_active_connection_get_device (active),
- NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_DEACTIVATING,
reason);
success = TRUE;
}
@@ -3309,11 +3401,13 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
NMAuthCallResult result;
- const char *active_path;
+
+ g_assert (context);
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
+ result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL);
+
if (auth_error) {
nm_log_dbg (LOGD_CORE, "Disconnect request failed: %s", auth_error->message);
error = g_error_new (NM_MANAGER_ERROR,
@@ -3326,9 +3420,8 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
"Not authorized to deactivate connections");
} else {
/* success; deactivation allowed */
- active_path = nm_auth_chain_get_data (chain, "path");
if (!nm_manager_deactivate_connection (self,
- active_path,
+ nm_auth_chain_get_data (chain, "path"),
NM_DEVICE_STATE_REASON_USER_REQUESTED,
&error))
g_assert (error);
@@ -3351,9 +3444,9 @@ impl_manager_deactivate_connection (NMManager *self,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMConnection *connection = NULL;
GError *error = NULL;
+ NMAuthSubject *subject = NULL;
GSList *iter;
NMAuthChain *chain;
- gulong sender_uid = G_MAXULONG;
char *error_desc = NULL;
/* Find the connection by its object path */
@@ -3370,85 +3463,100 @@ impl_manager_deactivate_connection (NMManager *self,
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
"The connection was not active.");
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
+ goto done;
}
- /* Need to check the caller's permissions and stuff before we can
- * deactivate the connection.
- */
- if (!nm_auth_get_caller_uid (context,
- priv->dbus_mgr,
- &sender_uid,
- &error_desc)) {
+ /* Validate the caller */
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- g_free (error_desc);
- return;
+ "Failed to get request UID.");
+ goto done;
}
/* Ensure the subject has permissions for this connection */
if (!nm_auth_uid_in_acl (connection,
- priv->session_monitor,
- sender_uid,
+ nm_session_monitor_get (),
+ nm_auth_subject_get_uid (subject),
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
g_free (error_desc);
- return;
+ goto done;
}
- /* Yay for root */
- if (0 == sender_uid) {
- if (!nm_manager_deactivate_connection (self,
- active_path,
- NM_DEVICE_STATE_REASON_USER_REQUESTED,
- &error)) {
- dbus_g_method_return_error (context, error);
- g_clear_error (&error);
- } else
- dbus_g_method_return (context);
-
- return;
+ /* Validate the user request */
+ chain = nm_auth_chain_new_subject (subject, context, deactivate_net_auth_done_cb, self);
+ if (!chain) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Unable to authenticate request.");
+ goto done;
}
- /* Otherwise validate the user request */
- chain = nm_auth_chain_new (context, NULL, deactivate_net_auth_done_cb, self);
- g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
+
+done:
+ g_clear_object (&subject);
+ if (error)
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
+}
+
+static gboolean
+device_is_wake_on_lan (NMDevice *device)
+{
+ return nm_platform_link_get_wake_on_lan (nm_device_get_ip_ifindex (device));
}
static void
-do_sleep_wake (NMManager *self)
+do_sleep_wake (NMManager *self, gboolean sleeping_changed)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- const GSList *unmanaged_specs;
+ gboolean suspending, waking_from_suspend;
GSList *iter;
+ suspending = sleeping_changed && priv->sleeping;
+ waking_from_suspend = sleeping_changed && !priv->sleeping;
+
if (manager_sleeping (self)) {
- nm_log_info (LOGD_SUSPEND, "sleeping or disabling...");
+ nm_log_info (LOGD_SUSPEND, suspending ? "sleeping..." : "disabling...");
- /* Just deactivate and down all devices from the device list,
- * to keep things fast the device list will get resynced when
- * the manager wakes up.
+ /* FIXME: are there still hardware devices that need to be disabled around
+ * suspend/resume?
*/
- for (iter = priv->devices; iter; iter = iter->next)
- nm_device_set_managed (NM_DEVICE (iter->data), FALSE, NM_DEVICE_STATE_REASON_SLEEPING);
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *device = iter->data;
+ /* FIXME: shouldn't we be unmanaging software devices if !suspending? */
+ if (nm_device_is_software (device))
+ continue;
+ /* Wake-on-LAN devices will be taken down post-suspend rather than pre- */
+ if (suspending && device_is_wake_on_lan (device))
+ continue;
+
+ nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+ }
} else {
- nm_log_info (LOGD_SUSPEND, "waking up and re-enabling...");
+ nm_log_info (LOGD_SUSPEND, waking_from_suspend ? "waking up..." : "re-enabling...");
+
+ if (waking_from_suspend) {
+ /* Belatedly take down Wake-on-LAN devices; ideally we wouldn't have to do this
+ * but for now it's the only way to make sure we re-check their connectivity.
+ */
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *device = iter->data;
- unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
+ if (nm_device_is_software (device))
+ continue;
+ if (device_is_wake_on_lan (device))
+ nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+ }
+ }
/* Ensure rfkill state is up-to-date since we don't respond to state
* changes during sleep.
@@ -3460,6 +3568,9 @@ do_sleep_wake (NMManager *self)
NMDevice *device = NM_DEVICE (iter->data);
guint i;
+ if (nm_device_is_software (device))
+ continue;
+
/* enable/disable wireless devices since that we don't respond
* to killswitch changes during sleep.
*/
@@ -3479,10 +3590,7 @@ do_sleep_wake (NMManager *self)
g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, TRUE, NULL);
- if (nm_device_spec_match_list (device, unmanaged_specs))
- nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
- else
- nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
}
@@ -3504,7 +3612,7 @@ _internal_sleep (NMManager *self, gboolean do_sleep)
priv->sleeping = do_sleep;
- do_sleep_wake (self);
+ do_sleep_wake (self, TRUE);
g_object_notify (G_OBJECT (self), NM_MANAGER_SLEEPING);
}
@@ -3524,7 +3632,7 @@ sleep_auth_done_cb (NMAuthChain *chain,
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_SLEEP_WAKE));
+ result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SLEEP_WAKE);
if (error) {
nm_log_dbg (LOGD_SUSPEND, "Sleep/wake request failed: %s", error->message);
ret_error = g_error_new (NM_MANAGER_ERROR,
@@ -3559,7 +3667,6 @@ impl_manager_sleep (NMManager *self,
GError *error = NULL;
#if 0
NMAuthChain *chain;
- gulong sender_uid = G_MAXULONG;
const char *error_desc = NULL;
#endif
@@ -3589,28 +3696,18 @@ impl_manager_sleep (NMManager *self,
return;
#if 0
- if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &sender_uid, &error_desc)) {
+ chain = nm_auth_chain_new (context, sleep_auth_done_cb, self, &error_desc);
+ if (chain) {
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_set_data (chain, "sleep", GUINT_TO_POINTER (do_sleep), NULL);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, TRUE);
+ } else {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
dbus_g_method_return_error (context, error);
g_error_free (error);
- return;
}
-
- /* Root doesn't need PK authentication */
- if (0 == sender_uid) {
- _internal_sleep (self, do_sleep);
- dbus_g_method_return (context);
- return;
- }
-
- chain = nm_auth_chain_new (context, NULL, sleep_auth_done_cb, self);
- g_assert (chain);
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
- nm_auth_chain_set_data (chain, "sleep", GUINT_TO_POINTER (do_sleep), NULL);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, TRUE);
#endif
}
@@ -3655,7 +3752,7 @@ _internal_enable (NMManager *self, gboolean enable)
priv->net_enabled = enable;
- do_sleep_wake (self);
+ do_sleep_wake (self, FALSE);
g_object_notify (G_OBJECT (self), NM_MANAGER_NETWORKING_ENABLED);
}
@@ -3668,27 +3765,25 @@ enable_net_done_cb (NMAuthChain *chain,
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GError *ret_error;
+ GError *ret_error = NULL;
NMAuthCallResult result;
gboolean enable;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK));
+ result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
if (error) {
nm_log_dbg (LOGD_CORE, "Enable request failed: %s", error->message);
ret_error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Enable request failed: %s",
error->message);
- dbus_g_method_return_error (context, ret_error);
- g_error_free (ret_error);
} else if (result != NM_AUTH_CALL_RESULT_YES) {
ret_error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Not authorized to enable/disable networking");
- dbus_g_method_return_error (context, ret_error);
- g_error_free (ret_error);
} else {
/* Auth success */
enable = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enable"));
@@ -3696,6 +3791,11 @@ enable_net_done_cb (NMAuthChain *chain,
dbus_g_method_return (context);
}
+ if (ret_error) {
+ dbus_g_method_return_error (context, ret_error);
+ g_error_free (ret_error);
+ }
+
nm_auth_chain_unref (chain);
}
@@ -3707,8 +3807,6 @@ impl_manager_enable (NMManager *self,
NMManagerPrivate *priv;
NMAuthChain *chain;
GError *error = NULL;
- gulong sender_uid = G_MAXULONG;
- char *error_desc = NULL;
g_return_if_fail (NM_IS_MANAGER (self));
@@ -3718,34 +3816,25 @@ impl_manager_enable (NMManager *self,
error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
"Already %s", enable ? "enabled" : "disabled");
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
+ goto done;
}
- if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &sender_uid, &error_desc)) {
+ chain = nm_auth_chain_new_context (context, enable_net_done_cb, self);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- g_free (error_desc);
- return;
- }
-
- /* Root doesn't need PK authentication */
- if (0 == sender_uid) {
- _internal_enable (self, enable);
- dbus_g_method_return (context);
- return;
+ "Unable to authenticate request.");
+ goto done;
}
- chain = nm_auth_chain_new (context, NULL, enable_net_done_cb, self);
- g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
nm_auth_chain_set_data (chain, "enable", GUINT_TO_POINTER (enable), NULL);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, TRUE);
+
+done:
+ if (error)
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
}
/* Permissions */
@@ -3755,7 +3844,7 @@ get_perm_add_result (NMAuthChain *chain, GHashTable *results, const char *permis
{
NMAuthCallResult result;
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
+ result = nm_auth_chain_get_result (chain, permission);
if (result == NM_AUTH_CALL_RESULT_YES)
g_hash_table_insert (results, (char *) permission, "yes");
else if (result == NM_AUTH_CALL_RESULT_NO)
@@ -3778,6 +3867,8 @@ get_permissions_done_cb (NMAuthChain *chain,
GError *ret_error;
GHashTable *results;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
if (error) {
nm_log_dbg (LOGD_CORE, "Permissions request failed: %s", error->message);
@@ -3789,6 +3880,7 @@ get_permissions_done_cb (NMAuthChain *chain,
g_error_free (ret_error);
} else {
results = g_hash_table_new (g_str_hash, g_str_equal);
+
get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SLEEP_WAKE);
get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI);
@@ -3800,6 +3892,7 @@ get_permissions_done_cb (NMAuthChain *chain,
get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM);
get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN);
get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
+
dbus_g_method_return (context, results);
g_hash_table_destroy (results);
}
@@ -3813,11 +3906,19 @@ impl_manager_get_permissions (NMManager *self,
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMAuthChain *chain;
+ GError *error = NULL;
- chain = nm_auth_chain_new (context, NULL, get_permissions_done_cb, self);
- g_assert (chain);
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ chain = nm_auth_chain_new_context (context, get_permissions_done_cb, self);
+ if (!chain) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Unable to authenticate request.");
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
+ return;
+ }
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE);
@@ -3839,22 +3940,46 @@ impl_manager_get_state (NMManager *manager, guint32 *state, GError **error)
return TRUE;
}
-static gboolean
+static void
impl_manager_set_logging (NMManager *manager,
const char *level,
const char *domains,
- GError **error)
+ DBusGMethodInvocation *context)
{
- if (nm_logging_setup (level, domains, error)) {
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ GError *error = NULL;
+ gulong caller_uid = G_MAXULONG;
+
+ if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Failed to get request UID.");
+ goto done;
+ }
+
+ if (0 != caller_uid) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Permission denied");
+ goto done;
+ }
+
+ if (nm_logging_setup (level, domains, NULL, &error)) {
+ char *new_level = nm_logging_level_to_string ();
char *new_domains = nm_logging_domains_to_string ();
nm_log_info (LOGD_CORE, "logging: level '%s' domains '%s'",
- nm_logging_level_to_string (),
- new_domains);
+ new_level, new_domains);
+ g_free (new_level);
g_free (new_domains);
- return TRUE;
}
- return FALSE;
+
+done:
+ if (error) {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ } else
+ dbus_g_method_return (context);
}
static void
@@ -3862,8 +3987,8 @@ impl_manager_get_logging (NMManager *manager,
char **level,
char **domains)
{
- *level = g_strdup (nm_logging_level_to_string ());
- *domains = g_strdup (nm_logging_domains_to_string ());
+ *level = nm_logging_level_to_string ();
+ *domains = nm_logging_domains_to_string ();
}
static void
@@ -3929,37 +4054,20 @@ impl_manager_check_connectivity (NMManager *manager,
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
NMAuthChain *chain;
- gulong sender_uid = G_MAXULONG;
- char *error_desc = NULL;
- GError *error;
+ GError *error = NULL;
- /* Need to check the caller's permissions and stuff first */
- if (!nm_auth_get_caller_uid (context,
- priv->dbus_mgr,
- &sender_uid,
- &error_desc)) {
+ /* Validate the request */
+ chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, manager);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
+ "Unable to authenticate request.");
dbus_g_method_return_error (context, error);
- g_error_free (error);
- g_free (error_desc);
- return;
- }
-
- /* Yay for root */
- if (0 == sender_uid) {
- nm_connectivity_check_async (priv->connectivity,
- connectivity_check_done,
- context);
+ g_clear_error (&error);
return;
}
- /* Validate the user request */
- chain = nm_auth_chain_new (context, NULL, check_connectivity_auth_done_cb, manager);
- g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
}
@@ -3972,14 +4080,13 @@ nm_manager_start (NMManager *self)
/* Set initial radio enabled/disabled state */
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
RadioState *rstate = &priv->radio_states[i];
- RfKillState udev_state;
gboolean enabled;
if (!rstate->desc)
continue;
- udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, i);
- update_rstate_from_rfkill (rstate, udev_state);
+ /* recheck kernel rfkill state */
+ update_rstate_from_rfkill (priv->rfkill_mgr, rstate);
if (rstate->desc) {
nm_log_info (LOGD_RFKILL, "%s %s by radio killswitch; %s by state file",
@@ -3998,23 +4105,7 @@ nm_manager_start (NMManager *self)
system_unmanaged_devices_changed_cb (priv->settings, NULL, self);
system_hostname_changed_cb (priv->settings, NULL, self);
- /* FIXME: remove when we handle bridges non-destructively */
- /* Read a list of bridges NM managed when it last quit, and only
- * manage those bridges to avoid conflicts with external tools.
- */
- priv->nm_bridges = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- read_nm_created_bridges (self);
-
- nm_udev_manager_query_devices (priv->udev_mgr);
- nm_bluez_manager_query_devices (priv->bluez_mgr);
-
- /* Query devices again to ensure that we catch all virtual interfaces (like
- * VLANs) that require a parent. If during the first pass the VLAN
- * interface was detected first, the parent wouldn't exist yet and creating
- * the VLAN would fail. The second query ensures that we'll have a valid
- * parent for the VLAN during the second pass.
- */
- nm_udev_manager_query_devices (priv->udev_mgr);
+ nm_platform_query_devices ();
/*
* Connections added before the manager is started do not emit
@@ -4022,9 +4113,7 @@ nm_manager_start (NMManager *self)
*/
system_create_virtual_devices (self);
- /* FIXME: remove when we handle bridges non-destructively */
- g_hash_table_unref (priv->nm_bridges);
- priv->nm_bridges = NULL;
+ check_if_startup_complete (self);
}
static gboolean
@@ -4089,9 +4178,7 @@ firmware_dir_changed (GFileMonitor *monitor,
switch (event_type) {
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGED:
-#if GLIB_CHECK_VERSION(2,23,4)
case G_FILE_MONITOR_EVENT_MOVED:
-#endif
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
if (!priv->fw_changed_id) {
@@ -4129,7 +4216,7 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user
if (ac != priv->primary_connection) {
g_clear_object (&priv->primary_connection);
priv->primary_connection = ac ? g_object_ref (ac) : NULL;
- nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_name (ac) : "(none)");
+ nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_id (ac) : "(none)");
g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION);
}
}
@@ -4162,7 +4249,7 @@ policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer u
if (ac != priv->activating_connection) {
g_clear_object (&priv->activating_connection);
priv->activating_connection = ac ? g_object_ref (ac) : NULL;
- nm_log_dbg (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_name (ac) : "(none)");
+ nm_log_dbg (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_id (ac) : "(none)");
g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVATING_CONNECTION);
}
}
@@ -4178,73 +4265,37 @@ prop_set_auth_done_cb (NMAuthChain *chain,
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- DBusGConnection *bus;
- DBusConnection *dbus_connection;
+ DBusConnection *connection;
NMAuthCallResult result;
- DBusMessage *reply = NULL, *request;
- GError *ret_error;
- const char *permission, *prop, *objpath;
+ DBusMessage *reply = NULL, *message;
+ const char *permission, *prop;
+ GObject *obj;
gboolean set_enabled = TRUE;
- gboolean is_device = FALSE;
- size_t objpath_len;
- size_t devpath_len;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
- request = nm_auth_chain_get_data (chain, "message");
+ message = nm_auth_chain_get_data (chain, "message");
permission = nm_auth_chain_get_data (chain, "permission");
prop = nm_auth_chain_get_data (chain, "prop");
set_enabled = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enabled"));
- objpath = nm_auth_chain_get_data (chain, "objectpath");
+ obj = nm_auth_chain_get_data (chain, "object");
- objpath_len = strlen (objpath);
- devpath_len = strlen (NM_DBUS_PATH "/Devices");
- if ( strncmp (objpath, NM_DBUS_PATH "/Devices", devpath_len) == 0
- && objpath_len > devpath_len)
- is_device = TRUE;
-
- if (error) {
- reply = dbus_message_new_error (request, is_device ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR,
+ result = nm_auth_chain_get_result (chain, permission);
+ if (error || (result != NM_AUTH_CALL_RESULT_YES)) {
+ reply = dbus_message_new_error (message,
+ NM_IS_DEVICE (obj) ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR,
"Not authorized to perform this operation");
} else {
- /* Caller has had a chance to obtain authorization, so we only need to
- * check for 'yes' here.
- */
- result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
- if (result != NM_AUTH_CALL_RESULT_YES) {
- reply = dbus_message_new_error (request, is_device ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR,
- "Not authorized to perform this operation");
- } else {
- if (is_device) {
- /* Find the device */
- NMDevice *device = nm_manager_get_device_by_path (self, objpath);
- if (device) {
- g_object_set (device, prop, set_enabled, NULL);
- reply = dbus_message_new_method_return (request);
- }
- else {
- ret_error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Can't find device for this operation");
- dbus_g_method_return_error (context, ret_error);
- g_error_free (ret_error);
- }
- } else {
- g_object_set (self, prop, set_enabled, NULL);
- reply = dbus_message_new_method_return (request);
- }
- }
+ g_object_set (obj, prop, set_enabled, NULL);
+ reply = dbus_message_new_method_return (message);
}
- if (reply) {
- bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
- g_assert (bus);
- dbus_connection = dbus_g_connection_get_connection (bus);
- g_assert (dbus_connection);
+ g_assert (reply);
+ connection = nm_auth_chain_get_data (chain, "connection");
+ g_assert (connection);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
- dbus_connection_send (dbus_connection, reply, NULL);
- dbus_message_unref (reply);
- }
nm_auth_chain_unref (chain);
}
@@ -4259,14 +4310,12 @@ prop_filter (DBusConnection *connection,
DBusMessageIter sub;
const char *propiface = NULL;
const char *propname = NULL;
- const char *sender = NULL;
- const char *objpath = NULL;
const char *glib_propname = NULL, *permission = NULL;
- DBusError dbus_error;
- gulong uid = G_MAXULONG;
DBusMessage *reply = NULL;
gboolean set_enabled = FALSE;
+ NMAuthSubject *subject = NULL;
NMAuthChain *chain;
+ GObject *obj;
/* The sole purpose of this function is to validate property accesses
* on the NMManager object since dbus-glib doesn't yet give us this
@@ -4315,173 +4364,47 @@ prop_filter (DBusConnection *connection,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_get_basic (&sub, &set_enabled);
- sender = dbus_message_get_sender (message);
- if (!sender) {
+ /* Make sure the object exists */
+ obj = dbus_g_connection_lookup_g_object (dbus_connection_get_g_connection (connection),
+ dbus_message_get_path (message));
+ if (!obj) {
reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
- "Could not determine D-Bus requestor");
+ "Object does not exist");
goto out;
}
- objpath = dbus_message_get_path (message);
- if (!objpath) {
+ subject = nm_auth_subject_new_from_message (connection, message);
+ if (!subject) {
reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
- "Could not determine D-Bus object path");
+ "Could not determine request UID.");
goto out;
}
- dbus_error_init (&dbus_error);
- uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
- if (dbus_error_is_set (&dbus_error)) {
+ /* Validate the user request */
+ chain = nm_auth_chain_new_subject (subject, NULL, prop_set_auth_done_cb, self);
+ if (!chain) {
reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
- "Could not determine the user ID of the requestor");
- dbus_error_free (&dbus_error);
+ "Could not authenticate request.");
goto out;
}
- if (uid > 0) {
- /* Otherwise validate the user request */
- chain = nm_auth_chain_new_raw_message (message, prop_set_auth_done_cb, self);
- g_assert (chain);
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
- nm_auth_chain_set_data (chain, "prop", g_strdup (glib_propname), g_free);
- nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free);
- nm_auth_chain_set_data (chain, "enabled", GUINT_TO_POINTER (set_enabled), NULL);
- nm_auth_chain_set_data (chain, "message", dbus_message_ref (message), (GDestroyNotify) dbus_message_unref);
- nm_auth_chain_set_data (chain, "objectpath", g_strdup (objpath), g_free);
- nm_auth_chain_add_call (chain, permission, TRUE);
- } else {
- /* Yay for root */
- g_object_set (self, glib_propname, set_enabled, NULL);
- reply = dbus_message_new_method_return (message);
- }
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_set_data (chain, "prop", g_strdup (glib_propname), g_free);
+ nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free);
+ nm_auth_chain_set_data (chain, "enabled", GUINT_TO_POINTER (set_enabled), NULL);
+ nm_auth_chain_set_data (chain, "message", dbus_message_ref (message), (GDestroyNotify) dbus_message_unref);
+ nm_auth_chain_set_data (chain, "connection", dbus_connection_ref (connection), (GDestroyNotify) dbus_connection_unref);
+ nm_auth_chain_set_data (chain, "object", g_object_ref (obj), (GDestroyNotify) g_object_unref);
+ nm_auth_chain_add_call (chain, permission, TRUE);
out:
if (reply) {
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static NMManager *singleton = NULL;
-
-NMManager *
-nm_manager_get (void)
-{
- g_assert (singleton);
- return g_object_ref (singleton);
-}
-
-NMManager *
-nm_manager_new (NMSettings *settings,
- const char *state_file,
- gboolean initial_net_enabled,
- gboolean initial_wifi_enabled,
- gboolean initial_wwan_enabled,
- gboolean initial_wimax_enabled,
- const gchar *connectivity_uri,
- gint connectivity_interval,
- const gchar *connectivity_response,
- GError **error)
-{
- NMManagerPrivate *priv;
- DBusGConnection *bus;
- DBusConnection *dbus_connection;
-
- g_assert (settings);
-
- /* Can only be called once */
- g_assert (singleton == NULL);
- singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL);
- g_assert (singleton);
-
- priv = NM_MANAGER_GET_PRIVATE (singleton);
-
- priv->policy = nm_policy_new (singleton, settings);
- g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE,
- G_CALLBACK (policy_default_device_changed), singleton);
- g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_DEVICE,
- G_CALLBACK (policy_default_device_changed), singleton);
- g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_DEVICE,
- G_CALLBACK (policy_activating_device_changed), singleton);
- g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE,
- G_CALLBACK (policy_activating_device_changed), singleton);
-
- priv->connectivity = nm_connectivity_new (connectivity_uri, connectivity_interval, connectivity_response);
- g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE,
- G_CALLBACK (connectivity_changed), singleton);
-
- bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
- g_assert (bus);
- dbus_connection = dbus_g_connection_get_connection (bus);
- g_assert (dbus_connection);
-
- if (!dbus_connection_add_filter (dbus_connection, prop_filter, singleton, NULL)) {
- nm_log_err (LOGD_CORE, "failed to register DBus connection filter");
- g_object_unref (singleton);
- return NULL;
- }
-
- priv->settings = g_object_ref (settings);
-
- priv->state_file = g_strdup (state_file);
-
- priv->net_enabled = initial_net_enabled;
-
- priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = initial_wifi_enabled;
- priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = initial_wwan_enabled;
- priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = initial_wimax_enabled;
-
- g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS,
- G_CALLBACK (system_unmanaged_devices_changed_cb), singleton);
- g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
- G_CALLBACK (system_hostname_changed_cb), singleton);
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
- G_CALLBACK (connection_added), singleton);
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
- G_CALLBACK (connection_changed), singleton);
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
- G_CALLBACK (connection_removed), singleton);
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
- G_CALLBACK (connection_changed), singleton);
-
- dbus_g_connection_register_g_object (bus, NM_DBUS_PATH, G_OBJECT (singleton));
-
- priv->udev_mgr = nm_udev_manager_new ();
- g_signal_connect (priv->udev_mgr,
- "device-added",
- G_CALLBACK (udev_device_added_cb),
- singleton);
- g_signal_connect (priv->udev_mgr,
- "device-removed",
- G_CALLBACK (udev_device_removed_cb),
- singleton);
- g_signal_connect (priv->udev_mgr,
- "rfkill-changed",
- G_CALLBACK (udev_manager_rfkill_changed_cb),
- singleton);
-
- priv->bluez_mgr = nm_bluez_manager_get (NM_CONNECTION_PROVIDER (priv->settings));
-
- g_signal_connect (priv->bluez_mgr,
- NM_BLUEZ_MANAGER_BDADDR_ADDED,
- G_CALLBACK (bluez_manager_bdaddr_added_cb),
- singleton);
-
- g_signal_connect (priv->bluez_mgr,
- NM_BLUEZ_MANAGER_BDADDR_REMOVED,
- G_CALLBACK (bluez_manager_bdaddr_removed_cb),
- singleton);
-
- priv->session_monitor = nm_session_monitor_get ();
-
- /* Force kernel WiFi rfkill state to follow NM saved wifi state in case
- * the BIOS doesn't save rfkill state, and to be consistent with user
- * changes to the WirelessEnabled property which toggles kernel rfkill.
- */
- rfkill_change_wifi (priv->radio_states[RFKILL_TYPE_WLAN].desc, initial_wifi_enabled);
+ g_clear_object (&subject);
- return singleton;
+ return DBUS_HANDLER_RESULT_HANDLED;
}
static void
@@ -4491,113 +4414,9 @@ authority_changed_cb (gpointer user_data)
g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0);
}
-static void
-dispose (GObject *object)
-{
- NMManager *manager = NM_MANAGER (object);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
- DBusGConnection *bus;
- DBusConnection *dbus_connection;
- GSList *iter;
-
- if (priv->disposed) {
- G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
- return;
- }
- priv->disposed = TRUE;
-
- g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL);
- g_slist_free (priv->auth_chains);
-
- nm_auth_changed_func_unregister (authority_changed_cb, manager);
-
- /* FIXME: remove when we handle bridges non-destructively */
- write_nm_created_bridges (manager);
-
- /* Remove all devices */
- while (g_slist_length (priv->devices)) {
- priv->devices = remove_one_device (manager,
- priv->devices,
- NM_DEVICE (priv->devices->data),
- TRUE);
- }
-
- if (priv->ac_cleanup_id) {
- g_source_remove (priv->ac_cleanup_id);
- priv->ac_cleanup_id = 0;
- }
-
- for (iter = priv->active_connections; iter; iter = g_slist_next (iter))
- active_connection_removed (manager, NM_ACTIVE_CONNECTION (iter->data));
- g_slist_free (priv->active_connections);
- priv->active_connections = NULL;
- g_clear_object (&priv->primary_connection);
- g_clear_object (&priv->activating_connection);
-
- g_clear_object (&priv->connectivity);
-
- g_free (priv->hostname);
-
- g_signal_handlers_disconnect_by_func (priv->policy, G_CALLBACK (policy_default_device_changed), singleton);
- g_signal_handlers_disconnect_by_func (priv->policy, G_CALLBACK (policy_activating_device_changed), singleton);
- g_object_unref (priv->policy);
-
- g_object_unref (priv->settings);
- g_object_unref (priv->vpn_manager);
- g_object_unref (priv->session_monitor);
-
- if (priv->modem_added_id) {
- g_source_remove (priv->modem_added_id);
- priv->modem_added_id = 0;
- }
- if (priv->modem_removed_id) {
- g_source_remove (priv->modem_removed_id);
- priv->modem_removed_id = 0;
- }
- g_object_unref (priv->modem_manager);
-
- /* Unregister property filter */
- bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
- if (bus) {
- dbus_connection = dbus_g_connection_get_connection (bus);
- g_assert (dbus_connection);
- dbus_connection_remove_filter (dbus_connection, prop_filter, manager);
- }
- g_signal_handler_disconnect (priv->dbus_mgr, priv->dbus_connection_changed_id);
- g_object_unref (priv->dbus_mgr);
-
- if (priv->bluez_mgr)
- g_object_unref (priv->bluez_mgr);
-
- if (priv->aipd_proxy)
- g_object_unref (priv->aipd_proxy);
-
- if (priv->sleep_monitor)
- g_object_unref (priv->sleep_monitor);
-
- if (priv->fw_monitor) {
- if (priv->fw_monitor_id)
- g_signal_handler_disconnect (priv->fw_monitor, priv->fw_monitor_id);
-
- if (priv->fw_changed_id)
- g_source_remove (priv->fw_changed_id);
-
- g_file_monitor_cancel (priv->fw_monitor);
- g_object_unref (priv->fw_monitor);
- }
-
- g_slist_free (priv->factories);
-
- if (priv->timestamp_update_id) {
- g_source_remove (priv->timestamp_update_id);
- priv->timestamp_update_id = 0;
- }
-
- G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
-}
-
#define KERN_RFKILL_OP_CHANGE_ALL 3
#define KERN_RFKILL_TYPE_WLAN 1
+#define KERN_RFKILL_TYPE_WWAN 5
struct rfkill_event {
__u32 idx;
__u8 type;
@@ -4606,18 +4425,19 @@ struct rfkill_event {
} __attribute__((packed));
static void
-rfkill_change_wifi (const char *desc, gboolean enabled)
+rfkill_change (const char *desc, RfKillType rtype, gboolean enabled)
{
int fd;
struct rfkill_event event;
ssize_t len;
+ g_return_if_fail (rtype == RFKILL_TYPE_WLAN || rtype == RFKILL_TYPE_WWAN);
+
errno = 0;
fd = open ("/dev/rfkill", O_RDWR);
if (fd < 0) {
if (errno == EACCES)
- nm_log_warn (LOGD_RFKILL, "(%s): failed to open killswitch device "
- "for WiFi radio control", desc);
+ nm_log_warn (LOGD_RFKILL, "(%s): failed to open killswitch device", desc);
return;
}
@@ -4630,7 +4450,16 @@ rfkill_change_wifi (const char *desc, gboolean enabled)
memset (&event, 0, sizeof (event));
event.op = KERN_RFKILL_OP_CHANGE_ALL;
- event.type = KERN_RFKILL_TYPE_WLAN;
+ switch (rtype) {
+ case RFKILL_TYPE_WLAN:
+ event.type = KERN_RFKILL_TYPE_WLAN;
+ break;
+ case RFKILL_TYPE_WWAN:
+ event.type = KERN_RFKILL_TYPE_WWAN;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
event.soft = enabled ? 0 : 1;
len = write (fd, &event, sizeof (event));
@@ -4657,6 +4486,10 @@ manager_radio_user_toggled (NMManager *self,
GError *error = NULL;
gboolean old_enabled, new_enabled;
+ /* Don't touch devices if asleep/networking disabled */
+ if (manager_sleeping (self))
+ return;
+
if (rstate->desc) {
nm_log_dbg (LOGD_RFKILL, "(%s): setting radio %s by user",
rstate->desc,
@@ -4690,114 +4523,11 @@ manager_radio_user_toggled (NMManager *self,
rstate->user_enabled = enabled;
new_enabled = radio_enabled_for_rstate (rstate, FALSE);
if (new_enabled != old_enabled) {
- manager_update_radio_enabled (self, rstate, new_enabled);
-
- /* For WiFi only (for now) set the actual kernel rfkill state */
- if (rstate->rtype == RFKILL_TYPE_WLAN)
- rfkill_change_wifi (rstate->desc, new_enabled);
- }
-}
-
-static void
-set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- NMManager *self = NM_MANAGER (object);
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-
- switch (prop_id) {
- case PROP_NETWORKING_ENABLED:
- /* Construct only for now */
- priv->net_enabled = g_value_get_boolean (value);
- break;
- case PROP_WIRELESS_ENABLED:
- manager_radio_user_toggled (NM_MANAGER (object),
- &priv->radio_states[RFKILL_TYPE_WLAN],
- g_value_get_boolean (value));
- break;
- case PROP_WWAN_ENABLED:
- manager_radio_user_toggled (NM_MANAGER (object),
- &priv->radio_states[RFKILL_TYPE_WWAN],
- g_value_get_boolean (value));
- break;
- case PROP_WIMAX_ENABLED:
- manager_radio_user_toggled (NM_MANAGER (object),
- &priv->radio_states[RFKILL_TYPE_WIMAX],
- g_value_get_boolean (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
+ /* Try to change the kernel rfkill state */
+ if (rstate->rtype == RFKILL_TYPE_WLAN || rstate->rtype == RFKILL_TYPE_WWAN)
+ rfkill_change (rstate->desc, rstate->rtype, new_enabled);
-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);
- GSList *iter;
- GPtrArray *active;
- const char *path;
-
- switch (prop_id) {
- case PROP_VERSION:
- g_value_set_string (value, VERSION);
- break;
- case PROP_STATE:
- nm_manager_update_state (self);
- g_value_set_uint (value, priv->state);
- break;
- case PROP_NETWORKING_ENABLED:
- g_value_set_boolean (value, priv->net_enabled);
- break;
- case PROP_WIRELESS_ENABLED:
- g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN, TRUE));
- break;
- case PROP_WIRELESS_HARDWARE_ENABLED:
- g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
- break;
- case PROP_WWAN_ENABLED:
- g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN, TRUE));
- break;
- case PROP_WWAN_HARDWARE_ENABLED:
- g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
- break;
- case PROP_WIMAX_ENABLED:
- g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WIMAX, TRUE));
- break;
- case PROP_WIMAX_HARDWARE_ENABLED:
- g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WIMAX].hw_enabled);
- break;
- case PROP_ACTIVE_CONNECTIONS:
- active = g_ptr_array_sized_new (3);
- for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
- path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (iter->data));
- g_ptr_array_add (active, g_strdup (path));
- }
- g_value_take_boxed (value, active);
- break;
- case PROP_CONNECTIVITY:
- g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity));
- break;
- case PROP_PRIMARY_CONNECTION:
- path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : "/";
- g_value_set_boxed (value, path);
- break;
- case PROP_ACTIVATING_CONNECTION:
- path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : "/";
- g_value_set_boxed (value, path);
- break;
- case PROP_HOSTNAME:
- g_value_set_string (value, priv->hostname);
- break;
- case PROP_SLEEPING:
- g_value_set_boolean (value, priv->sleeping);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ manager_update_radio_enabled (self, rstate, new_enabled);
}
}
@@ -4827,14 +4557,140 @@ dbus_connection_changed_cb (NMDBusManager *dbus_mgr,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
+ gboolean success = FALSE;
if (dbus_connection) {
/* Register property filter on new connection; there's no reason this
* should fail except out-of-memory or program error; if it does fail
* then there's no Manager property access control, which is bad.
*/
- g_assert (dbus_connection_add_filter (dbus_connection, prop_filter, self, NULL));
+ success = dbus_connection_add_filter (dbus_connection, prop_filter, self, NULL);
+ g_assert (success);
}
+ NM_MANAGER_GET_PRIVATE (self)->prop_filter_added = success;
+}
+
+/**********************************************************************/
+
+static NMManager *singleton = NULL;
+
+NMManager *
+nm_manager_get (void)
+{
+ g_assert (singleton);
+ return singleton;
+}
+
+NMConnectionProvider *
+nm_connection_provider_get (void)
+{
+ g_assert (singleton);
+ g_assert (NM_MANAGER_GET_PRIVATE (singleton)->settings);
+ return NM_CONNECTION_PROVIDER (NM_MANAGER_GET_PRIVATE (singleton)->settings);
+}
+
+NMManager *
+nm_manager_new (NMSettings *settings,
+ const char *state_file,
+ gboolean initial_net_enabled,
+ gboolean initial_wifi_enabled,
+ gboolean initial_wwan_enabled,
+ gboolean initial_wimax_enabled,
+ GError **error)
+{
+ NMManagerPrivate *priv;
+ DBusGConnection *bus;
+ DBusConnection *dbus_connection;
+
+ g_assert (settings);
+
+ /* Can only be called once */
+ g_assert (singleton == NULL);
+ singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL);
+ g_assert (singleton);
+
+ priv = NM_MANAGER_GET_PRIVATE (singleton);
+
+ bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
+ if (!bus) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INTERNAL,
+ "Failed to initialize D-Bus connection");
+ g_object_unref (singleton);
+ return NULL;
+ }
+
+ dbus_connection = dbus_g_connection_get_connection (bus);
+ g_assert (dbus_connection);
+
+ priv->policy = nm_policy_new (singleton, settings);
+ g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE,
+ G_CALLBACK (policy_default_device_changed), singleton);
+ g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_DEVICE,
+ G_CALLBACK (policy_default_device_changed), singleton);
+ g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_DEVICE,
+ G_CALLBACK (policy_activating_device_changed), singleton);
+ g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE,
+ G_CALLBACK (policy_activating_device_changed), singleton);
+
+ priv->connectivity = nm_connectivity_new ();
+ g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE,
+ G_CALLBACK (connectivity_changed), singleton);
+
+ if (!dbus_connection_add_filter (dbus_connection, prop_filter, singleton, NULL)) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INTERNAL,
+ "Failed to register DBus connection filter");
+ g_object_unref (singleton);
+ return NULL;
+ }
+ priv->prop_filter_added = TRUE;
+
+ priv->settings = g_object_ref (settings);
+
+ priv->state_file = g_strdup (state_file);
+
+ priv->net_enabled = initial_net_enabled;
+
+ priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = initial_wifi_enabled;
+ priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = initial_wwan_enabled;
+ priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = initial_wimax_enabled;
+
+ g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS,
+ G_CALLBACK (system_unmanaged_devices_changed_cb), singleton);
+ g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
+ G_CALLBACK (system_hostname_changed_cb), singleton);
+ g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
+ G_CALLBACK (connection_added), singleton);
+ g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
+ G_CALLBACK (connection_changed), singleton);
+ g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
+ G_CALLBACK (connection_removed), singleton);
+ g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
+ G_CALLBACK (connection_changed), singleton);
+
+ nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH, singleton);
+
+ g_signal_connect (nm_platform_get (),
+ NM_PLATFORM_SIGNAL_LINK_CHANGED,
+ G_CALLBACK (platform_link_cb),
+ singleton);
+
+ priv->rfkill_mgr = nm_rfkill_manager_new ();
+ g_signal_connect (priv->rfkill_mgr,
+ "rfkill-changed",
+ G_CALLBACK (rfkill_manager_rfkill_changed_cb),
+ singleton);
+
+ /* Force kernel WiFi/WWAN rfkill state to follow NM saved WiFi/WWAN state
+ * in case the BIOS doesn't save rfkill state, and to be consistent with user
+ * changes to the WirelessEnabled/WWANEnabled properties which toggle kernel
+ * rfkill.
+ */
+ rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, initial_wifi_enabled);
+ rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, initial_wwan_enabled);
+
+ load_device_factories (singleton);
+
+ return singleton;
}
static void
@@ -4853,7 +4709,6 @@ nm_manager_init (NMManager *manager)
priv->radio_states[RFKILL_TYPE_WLAN].prop = NM_MANAGER_WIRELESS_ENABLED;
priv->radio_states[RFKILL_TYPE_WLAN].hw_prop = NM_MANAGER_WIRELESS_HARDWARE_ENABLED;
priv->radio_states[RFKILL_TYPE_WLAN].desc = "WiFi";
- priv->radio_states[RFKILL_TYPE_WLAN].other_enabled_func = nm_manager_get_ipw_rfkill_state;
priv->radio_states[RFKILL_TYPE_WLAN].rtype = RFKILL_TYPE_WLAN;
priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = TRUE;
@@ -4861,7 +4716,6 @@ nm_manager_init (NMManager *manager)
priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED;
priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED;
priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN";
- priv->radio_states[RFKILL_TYPE_WWAN].daemon_enabled_func = nm_manager_get_modem_enabled_state;
priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = TRUE;
@@ -4869,7 +4723,6 @@ nm_manager_init (NMManager *manager)
priv->radio_states[RFKILL_TYPE_WIMAX].prop = NM_MANAGER_WIMAX_ENABLED;
priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NM_MANAGER_WIMAX_HARDWARE_ENABLED;
priv->radio_states[RFKILL_TYPE_WIMAX].desc = "WiMAX";
- priv->radio_states[RFKILL_TYPE_WIMAX].other_enabled_func = NULL;
priv->radio_states[RFKILL_TYPE_WIMAX].rtype = RFKILL_TYPE_WIMAX;
for (i = 0; i < RFKILL_TYPE_MAX; i++)
@@ -4877,18 +4730,13 @@ nm_manager_init (NMManager *manager)
priv->sleeping = FALSE;
priv->state = NM_STATE_DISCONNECTED;
+ priv->startup = TRUE;
priv->dbus_mgr = nm_dbus_manager_get ();
- priv->dbus_connection_changed_id = g_signal_connect (priv->dbus_mgr,
- NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED,
- G_CALLBACK (dbus_connection_changed_cb),
- manager);
-
- priv->modem_manager = nm_modem_manager_get ();
- priv->modem_added_id = g_signal_connect (priv->modem_manager, "modem-added",
- G_CALLBACK (modem_added), manager);
- priv->modem_removed_id = g_signal_connect (priv->modem_manager, "modem-removed",
- G_CALLBACK (modem_removed), manager);
+ g_signal_connect (priv->dbus_mgr,
+ NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED,
+ G_CALLBACK (dbus_connection_changed_cb),
+ manager);
priv->vpn_manager = nm_vpn_manager_get ();
@@ -4900,7 +4748,7 @@ nm_manager_init (NMManager *manager)
"/",
NM_AUTOIP_DBUS_IFACE);
if (priv->aipd_proxy) {
- dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING,
+ dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
G_TYPE_NONE,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INVALID);
@@ -4935,9 +4783,9 @@ nm_manager_init (NMManager *manager)
}
if (priv->fw_monitor) {
- priv->fw_monitor_id = g_signal_connect (priv->fw_monitor, "changed",
- G_CALLBACK (firmware_dir_changed),
- manager);
+ g_signal_connect (priv->fw_monitor, "changed",
+ G_CALLBACK (firmware_dir_changed),
+ manager);
nm_log_info (LOGD_CORE, "monitoring kernel firmware directory '%s'.",
KERNEL_FIRMWARE_DIR);
} else {
@@ -4945,13 +4793,214 @@ nm_manager_init (NMManager *manager)
KERNEL_FIRMWARE_DIR);
}
- load_device_factories (manager);
-
/* Update timestamps in active connections */
priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, manager);
}
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);
+ GSList *iter;
+ GPtrArray *array;
+ const char *path;
+
+ switch (prop_id) {
+ case PROP_VERSION:
+ g_value_set_string (value, VERSION);
+ break;
+ case PROP_STATE:
+ nm_manager_update_state (self);
+ g_value_set_uint (value, priv->state);
+ break;
+ case PROP_STARTUP:
+ g_value_set_boolean (value, priv->startup);
+ break;
+ case PROP_NETWORKING_ENABLED:
+ g_value_set_boolean (value, priv->net_enabled);
+ break;
+ case PROP_WIRELESS_ENABLED:
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN, TRUE));
+ break;
+ case PROP_WIRELESS_HARDWARE_ENABLED:
+ g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
+ break;
+ case PROP_WWAN_ENABLED:
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN, TRUE));
+ break;
+ case PROP_WWAN_HARDWARE_ENABLED:
+ g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
+ break;
+ case PROP_WIMAX_ENABLED:
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WIMAX, TRUE));
+ break;
+ case PROP_WIMAX_HARDWARE_ENABLED:
+ g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WIMAX].hw_enabled);
+ break;
+ case PROP_ACTIVE_CONNECTIONS:
+ array = g_ptr_array_sized_new (3);
+ for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
+ path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (iter->data));
+ if (path)
+ g_ptr_array_add (array, g_strdup (path));
+ }
+ g_value_take_boxed (value, array);
+ break;
+ case PROP_CONNECTIVITY:
+ g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity));
+ break;
+ case PROP_PRIMARY_CONNECTION:
+ path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : NULL;
+ g_value_set_boxed (value, path ? path : "/");
+ break;
+ case PROP_ACTIVATING_CONNECTION:
+ path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : NULL;
+ g_value_set_boxed (value, path ? path : "/");
+ break;
+ case PROP_HOSTNAME:
+ g_value_set_string (value, priv->hostname);
+ break;
+ case PROP_SLEEPING:
+ g_value_set_boolean (value, priv->sleeping);
+ break;
+ case PROP_DEVICES:
+ array = g_ptr_array_sized_new (5);
+ for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+ path = nm_device_get_path (NM_DEVICE (iter->data));
+ if (path)
+ g_ptr_array_add (array, g_strdup (path));
+ }
+ g_value_take_boxed (value, array);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMManager *self = NM_MANAGER (object);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+ switch (prop_id) {
+ case PROP_NETWORKING_ENABLED:
+ /* Construct only for now */
+ priv->net_enabled = g_value_get_boolean (value);
+ break;
+ case PROP_WIRELESS_ENABLED:
+ manager_radio_user_toggled (NM_MANAGER (object),
+ &priv->radio_states[RFKILL_TYPE_WLAN],
+ g_value_get_boolean (value));
+ break;
+ case PROP_WWAN_ENABLED:
+ manager_radio_user_toggled (NM_MANAGER (object),
+ &priv->radio_states[RFKILL_TYPE_WWAN],
+ g_value_get_boolean (value));
+ break;
+ case PROP_WIMAX_ENABLED:
+ manager_radio_user_toggled (NM_MANAGER (object),
+ &priv->radio_states[RFKILL_TYPE_WIMAX],
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+dispose (GObject *object)
+{
+ NMManager *manager = NM_MANAGER (object);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ DBusGConnection *bus;
+ DBusConnection *dbus_connection;
+ GSList *iter;
+
+ g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref);
+ priv->auth_chains = NULL;
+
+ nm_auth_changed_func_unregister (authority_changed_cb, manager);
+
+ /* Remove all devices */
+ while (priv->devices)
+ remove_device (manager, NM_DEVICE (priv->devices->data), TRUE);
+
+ if (priv->ac_cleanup_id) {
+ g_source_remove (priv->ac_cleanup_id);
+ priv->ac_cleanup_id = 0;
+ }
+
+ while (priv->active_connections)
+ active_connection_remove (manager, NM_ACTIVE_CONNECTION (priv->active_connections->data));
+ g_clear_pointer (&priv->active_connections, g_slist_free);
+ g_clear_object (&priv->primary_connection);
+ g_clear_object (&priv->activating_connection);
+
+ g_clear_object (&priv->connectivity);
+
+ g_free (priv->hostname);
+
+ if (priv->policy) {
+ g_signal_handlers_disconnect_by_func (priv->policy, policy_default_device_changed, manager);
+ g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_device_changed, manager);
+ g_clear_object (&priv->policy);
+ }
+
+ g_clear_object (&priv->settings);
+ g_clear_object (&priv->vpn_manager);
+
+ /* Unregister property filter */
+ if (priv->dbus_mgr) {
+ bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
+ if (bus) {
+ dbus_connection = dbus_g_connection_get_connection (bus);
+ if (dbus_connection && priv->prop_filter_added) {
+ dbus_connection_remove_filter (dbus_connection, prop_filter, manager);
+ priv->prop_filter_added = FALSE;
+ }
+ }
+ g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, manager);
+ priv->dbus_mgr = NULL;
+ }
+
+ g_clear_object (&priv->aipd_proxy);
+ g_clear_object (&priv->sleep_monitor);
+
+ if (priv->fw_monitor) {
+ g_signal_handlers_disconnect_by_func (priv->fw_monitor, firmware_dir_changed, manager);
+
+ if (priv->fw_changed_id) {
+ g_source_remove (priv->fw_changed_id);
+ priv->fw_changed_id = 0;
+ }
+
+ g_file_monitor_cancel (priv->fw_monitor);
+ g_clear_object (&priv->fw_monitor);
+ }
+
+ for (iter = priv->factories; iter; iter = iter->next) {
+ NMDeviceFactory *factory = iter->data;
+
+ g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager);
+ g_object_unref (factory);
+ }
+ g_clear_pointer (&priv->factories, g_slist_free);
+
+ if (priv->timestamp_update_id) {
+ g_source_remove (priv->timestamp_update_id);
+ priv->timestamp_update_id = 0;
+ }
+
+ G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
+}
+
+static void
nm_manager_class_init (NMManagerClass *manager_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
@@ -4981,6 +5030,14 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_PARAM_READABLE));
g_object_class_install_property
+ (object_class, PROP_STARTUP,
+ g_param_spec_boolean (NM_MANAGER_STARTUP,
+ "Startup",
+ "Is NetworkManager still starting up",
+ TRUE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property
(object_class, PROP_NETWORKING_ENABLED,
g_param_spec_boolean (NM_MANAGER_NETWORKING_ENABLED,
"NetworkingEnabled",
@@ -5075,7 +5132,7 @@ nm_manager_class_init (NMManagerClass *manager_class)
"Hostname",
"Hostname",
NULL,
- G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
+ G_PARAM_READABLE));
/* Sleeping is not exported over D-Bus */
g_object_class_install_property
@@ -5084,7 +5141,15 @@ nm_manager_class_init (NMManagerClass *manager_class)
"Sleeping",
"Sleeping",
FALSE,
- G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
+ G_PARAM_READABLE));
+
+ g_object_class_install_property
+ (object_class, PROP_DEVICES,
+ g_param_spec_boxed (NM_MANAGER_DEVICES,
+ "Devices",
+ "Devices",
+ DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
+ G_PARAM_READABLE));
/* signals */
signals[DEVICE_ADDED] =
@@ -5092,8 +5157,7 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMManagerClass, device_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
+ NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
signals[DEVICE_REMOVED] =
@@ -5101,8 +5165,7 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMManagerClass, device_removed),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
+ NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
signals[STATE_CHANGED] =
@@ -5110,48 +5173,40 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMManagerClass, state_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__UINT,
+ NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_UINT);
- signals[PROPERTIES_CHANGED] =
- nm_properties_changed_signal_new (object_class,
- G_STRUCT_OFFSET (NMManagerClass, properties_changed));
-
signals[CHECK_PERMISSIONS] =
g_signal_new ("check-permissions",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
+ 0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[USER_PERMISSIONS_CHANGED] =
g_signal_new ("user-permissions-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
+ 0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[ACTIVE_CONNECTION_ADDED] =
g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_ADDED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
+ 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
signals[ACTIVE_CONNECTION_REMOVED] =
g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_REMOVED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
+ 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
- dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
- &dbus_glib_nm_manager_object_info);
+ nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
+ 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);
dbus_g_error_domain_register (NM_LOGGING_ERROR, "org.freedesktop.NetworkManager.Logging", NM_TYPE_LOGGING_ERROR);