summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-06-06 12:43:57 -0300
committerDan Winship <danw@gnome.org>2013-06-27 14:17:42 -0400
commit004c5c3df5634af7bdfd9f8ef8d32c34b4340166 (patch)
tree5d410a2de84030541a86b54874fb0037209e8764
parent0d873dc4f563228558b59667c97e1017ccd7ecce (diff)
downloadNetworkManager-danw/live-reconfig.tar.gz
live-reconfig [wip]danw/live-reconfig
-rw-r--r--src/devices/nm-device-bridge.c64
-rw-r--r--src/devices/nm-device-bt.c14
-rw-r--r--src/devices/nm-device-ethernet.c40
-rw-r--r--src/devices/nm-device-infiniband.c82
-rw-r--r--src/devices/nm-device-vlan.c46
-rw-r--r--src/devices/nm-device-wifi.c39
-rw-r--r--src/devices/nm-device.c141
-rw-r--r--src/devices/nm-device.h7
-rw-r--r--src/devices/wimax/nm-device-wimax.c14
9 files changed, 411 insertions, 36 deletions
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index 85986f64ae..94fe5e131d 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -233,6 +233,26 @@ set_sysfs_uint (const char *iface,
g_free (s);
}
+static void
+set_bridge_properties (NMDevice *dev, NMConnection *connection)
+{
+ GObject *s_bridge;
+ const char *iface;
+
+ s_bridge = (GObject *) nm_connection_get_setting_bridge (connection);
+ g_assert (s_bridge);
+
+ iface = nm_device_get_ip_iface (dev);
+ g_assert (iface);
+
+ set_sysfs_uint (iface, s_bridge, NM_SETTING_BRIDGE_STP, "bridge", "stp_state", FALSE, FALSE);
+ set_sysfs_uint (iface, s_bridge, NM_SETTING_BRIDGE_PRIORITY, "bridge", "priority", TRUE, FALSE);
+ set_sysfs_uint (iface, s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, "bridge", "forward_delay", TRUE, TRUE);
+ set_sysfs_uint (iface, s_bridge, NM_SETTING_BRIDGE_HELLO_TIME, "bridge", "hello_time", TRUE, TRUE);
+ set_sysfs_uint (iface, s_bridge, NM_SETTING_BRIDGE_MAX_AGE, "bridge", "max_age", TRUE, TRUE);
+ set_sysfs_uint (iface, s_bridge, NM_SETTING_BRIDGE_AGEING_TIME, "bridge", "ageing_time", TRUE, TRUE);
+}
+
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
@@ -248,18 +268,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
connection = nm_device_get_connection (dev);
g_assert (connection);
- s_bridge = nm_connection_get_setting_bridge (connection);
- g_assert (s_bridge);
-
- iface = nm_device_get_ip_iface (dev);
- g_assert (iface);
-
- set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_STP, "bridge", "stp_state", FALSE, FALSE);
- set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_PRIORITY, "bridge", "priority", TRUE, FALSE);
- set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY, "bridge", "forward_delay", TRUE, TRUE);
- set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME, "bridge", "hello_time", TRUE, TRUE);
- set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_MAX_AGE, "bridge", "max_age", TRUE, TRUE);
- set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME, "bridge", "ageing_time", TRUE, TRUE);
+ set_bridge_properties (dev, connection);
}
return ret;
}
@@ -309,6 +318,35 @@ release_slave (NMDevice *device, NMDevice *slave)
return success;
}
+static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *bridge_diff;
+
+ bridge_diff = g_hash_table_lookup (diff, NM_SETTING_BRIDGE_SETTING_NAME);
+ if (bridge_diff) {
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_MTU);
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_STP);
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_PRIORITY);
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_FORWARD_DELAY);
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_HELLO_TIME);
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_MAX_AGE);
+ g_hash_table_remove (bridge_diff, NM_SETTING_BRIDGE_AGEING_TIME);
+ }
+}
+
+static gboolean
+reconfigure (NMDevice *device, NMConnection *connection,
+ NMDeviceStateReason *reason)
+{
+ if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->reconfigure (device, connection, reason))
+ return FALSE;
+
+ set_bridge_properties (device, connection);
+ return TRUE;
+}
+
/******************************************************************/
NMDevice *
@@ -399,6 +437,8 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
parent_class->act_stage1_prepare = act_stage1_prepare;
parent_class->enslave_slave = enslave_slave;
parent_class->release_slave = release_slave;
+ parent_class->test_reconfigure = test_reconfigure;
+ parent_class->reconfigure = reconfigure;
/* properties */
g_object_class_install_property
diff --git a/src/devices/nm-device-bt.c b/src/devices/nm-device-bt.c
index 5c87ba9537..47c7ece152 100644
--- a/src/devices/nm-device-bt.c
+++ b/src/devices/nm-device-bt.c
@@ -1014,6 +1014,19 @@ deactivate (NMDevice *device)
NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate (device);
}
+static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *bluetooth_diff;
+
+ bluetooth_diff = g_hash_table_lookup (diff, NM_SETTING_BLUETOOTH_SETTING_NAME);
+ if (bluetooth_diff) {
+ /* This only affects matching and has already been taken into account. */
+ g_hash_table_remove (bluetooth_diff, NM_SETTING_BLUETOOTH_BDADDR);
+ }
+}
+
/*****************************************************************************/
static gboolean
@@ -1280,6 +1293,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass)
device_class->is_available = is_available;
device_class->state_changed = device_state_changed;
+ device_class->test_reconfigure = test_reconfigure;
/* Properties */
g_object_class_install_property
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 22f3e6b319..5961286d3d 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -286,6 +286,44 @@ device_state_changed (NMDevice *device,
}
static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *wired_diff;
+
+ wired_diff = g_hash_table_lookup (diff, NM_SETTING_WIRED_SETTING_NAME);
+ if (wired_diff) {
+ g_hash_table_remove (wired_diff, NM_SETTING_WIRED_MTU);
+
+ /* These only affect matching and have already been taken into account. */
+ g_hash_table_remove (wired_diff, NM_SETTING_WIRED_MAC_ADDRESS);
+ g_hash_table_remove (wired_diff, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
+ g_hash_table_remove (wired_diff, NM_SETTING_WIRED_S390_SUBCHANNELS);
+ }
+}
+
+static gboolean
+reconfigure (NMDevice *device, NMConnection *connection,
+ NMDeviceStateReason *reason)
+{
+ NMSettingWired *s_wired;
+ guint32 mtu;
+
+ if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->reconfigure (device, connection, reason))
+ return FALSE;
+
+ s_wired = nm_connection_get_setting_wired (connection);
+ if (s_wired) {
+ mtu = nm_setting_wired_get_mtu (s_wired);
+ /* FIXME: this is wrong; we need to reset the MTU if it's 0. */
+ if (mtu)
+ nm_platform_link_set_mtu (nm_device_get_ifindex (device), mtu);
+ }
+
+ return TRUE;
+}
+
+static void
nm_device_ethernet_init (NMDeviceEthernet * self)
{
}
@@ -1410,6 +1448,8 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
parent_class->carrier_changed = carrier_changed;
parent_class->state_changed = device_state_changed;
+ parent_class->test_reconfigure = test_reconfigure;
+ parent_class->reconfigure = reconfigure;
/* properties */
g_object_class_install_property
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index f41a8cac93..964edca8ad 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -128,47 +128,55 @@ get_generic_capabilities (NMDevice *dev)
return NM_DEVICE_CAP_CARRIER_DETECT;
}
-static NMActStageReturn
-act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+static gboolean
+set_transport_mode (NMDevice *device, NMConnection *connection, NMDeviceStateReason *reason)
{
- NMActRequest *req;
- NMConnection *connection;
NMSettingInfiniband *s_infiniband;
const char *transport_mode;
char *mode_path;
gboolean ok;
- g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
- req = nm_device_get_act_request (dev);
- g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
- connection = nm_act_request_get_connection (req);
- g_assert (connection);
s_infiniband = nm_connection_get_setting_infiniband (connection);
g_assert (s_infiniband);
transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
- mode_path = g_strdup_printf ("/sys/class/net/%s/mode", nm_device_get_iface (dev));
+ mode_path = g_strdup_printf ("/sys/class/net/%s/mode", nm_device_get_iface (device));
if (!g_file_test (mode_path, G_FILE_TEST_EXISTS)) {
g_free (mode_path);
if (!strcmp (transport_mode, "datagram"))
- return NM_ACT_STAGE_RETURN_SUCCESS;
+ return TRUE;
else {
*reason = NM_DEVICE_STATE_REASON_INFINIBAND_MODE;
- return NM_ACT_STAGE_RETURN_FAILURE;
+ return FALSE;
}
}
ok = nm_utils_do_sysctl (mode_path, transport_mode);
g_free (mode_path);
- if (!ok) {
+ if (!ok)
*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
+ return ok;
+}
+
+static NMActStageReturn
+act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+{
+ NMActRequest *req;
+ NMConnection *connection;
+
+ g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
+ req = nm_device_get_act_request (dev);
+ g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
+ connection = nm_act_request_get_connection (req);
+ g_assert (connection);
+
+ if (!set_transport_mode (dev, connection, reason))
return NM_ACT_STAGE_RETURN_FAILURE;
- }
return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
}
@@ -301,6 +309,46 @@ get_connection_hw_address (NMDevice *device,
}
static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *infiniband_diff;
+
+ infiniband_diff = g_hash_table_lookup (diff, NM_SETTING_INFINIBAND_SETTING_NAME);
+ if (infiniband_diff) {
+ g_hash_table_remove (infiniband_diff, NM_SETTING_INFINIBAND_TRANSPORT_MODE);
+ g_hash_table_remove (infiniband_diff, NM_SETTING_INFINIBAND_MTU);
+
+ /* This only affects matching and has already been taken into account. */
+ g_hash_table_remove (infiniband_diff, NM_SETTING_INFINIBAND_MAC_ADDRESS);
+ }
+}
+
+static gboolean
+reconfigure (NMDevice *device, NMConnection *connection,
+ NMDeviceStateReason *reason)
+{
+ NMSettingInfiniband *s_infiniband;
+ guint32 mtu;
+
+ if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->reconfigure (device, connection, reason))
+ return FALSE;
+
+ s_infiniband = nm_connection_get_setting_infiniband (connection);
+ g_assert (s_infiniband);
+
+ if (!set_transport_mode (device, connection, reason))
+ return FALSE;
+
+ mtu = nm_setting_infiniband_get_mtu (s_infiniband);
+ /* FIXME: this is wrong; we need to reset the MTU if it's 0. */
+ if (mtu)
+ nm_platform_link_set_mtu (nm_device_get_ifindex (device), mtu);
+
+ return TRUE;
+}
+
+static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
@@ -343,6 +391,8 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
parent_class->ip4_config_pre_commit = ip4_config_pre_commit;
parent_class->match_l2_config = match_l2_config;
parent_class->get_connection_hw_address = get_connection_hw_address;
+ parent_class->test_reconfigure = test_reconfigure;
+ parent_class->reconfigure = reconfigure;
/* properties */
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 19ac76e9f1..2e91935185 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -96,17 +96,13 @@ bring_up (NMDevice *dev, gboolean *no_firmware)
return success;
}
-static NMActStageReturn
-act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+static void
+set_vlan_properties (NMDevice *dev, NMConnection *connection)
{
- NMConnection *connection;
NMSettingVlan *s_vlan;
int ifindex = nm_device_get_ifindex (dev), num, i;
guint32 from, to;
- connection = nm_device_get_connection (dev);
- g_assert (connection);
-
s_vlan = nm_connection_get_setting_vlan (connection);
nm_platform_vlan_set_flags (ifindex, nm_setting_vlan_get_flags (s_vlan));
@@ -121,10 +117,46 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
nm_platform_vlan_set_egress_map (ifindex, from, to);
}
+}
+
+static NMActStageReturn
+act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+{
+ NMConnection *connection;
+
+ connection = nm_device_get_connection (dev);
+ g_assert (connection);
+
+ set_vlan_properties (dev, connection);
return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->act_stage1_prepare (dev, reason);
}
+static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *vlan_diff;
+
+ vlan_diff = g_hash_table_lookup (diff, NM_SETTING_VLAN_SETTING_NAME);
+ if (vlan_diff) {
+ g_hash_table_remove (vlan_diff, NM_SETTING_VLAN_FLAGS);
+ g_hash_table_remove (vlan_diff, NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
+ g_hash_table_remove (vlan_diff, NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
+ }
+}
+
+static gboolean
+reconfigure (NMDevice *device, NMConnection *connection,
+ NMDeviceStateReason *reason)
+{
+ if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->reconfigure (device, connection, reason))
+ return FALSE;
+
+ set_vlan_properties (device, connection);
+ return TRUE;
+}
+
/******************************************************************/
static gboolean
@@ -466,6 +498,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection;
parent_class->match_l2_config = match_l2_config;
+ parent_class->test_reconfigure = test_reconfigure;
+ parent_class->reconfigure = reconfigure;
/* properties */
g_object_class_install_property
diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c
index aae85cd3a4..40aa9879a8 100644
--- a/src/devices/nm-device-wifi.c
+++ b/src/devices/nm-device-wifi.c
@@ -3408,6 +3408,43 @@ device_state_changed (NMDevice *device,
remove_all_aps (self);
}
+static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *wireless_diff;
+
+ wireless_diff = g_hash_table_lookup (diff, NM_SETTING_WIRELESS_SETTING_NAME);
+ if (wireless_diff) {
+ g_hash_table_remove (wireless_diff, NM_SETTING_WIRELESS_MTU);
+
+ /* These only affect matching and have already been taken into account. */
+ g_hash_table_remove (wireless_diff, NM_SETTING_WIRELESS_MAC_ADDRESS);
+ g_hash_table_remove (wireless_diff, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
+ }
+}
+
+static gboolean
+reconfigure (NMDevice *device, NMConnection *connection,
+ NMDeviceStateReason *reason)
+{
+ NMSettingWireless *s_wireless;
+ guint32 mtu;
+
+ if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->reconfigure (device, connection, reason))
+ return FALSE;
+
+ s_wireless = nm_connection_get_setting_wireless (connection);
+ if (s_wireless) {
+ mtu = nm_setting_wireless_get_mtu (s_wireless);
+ /* FIXME: this is wrong; we need to reset the MTU if it's 0. */
+ if (mtu)
+ nm_platform_link_set_mtu (nm_device_get_ifindex (device), mtu);
+ }
+
+ return TRUE;
+}
+
NMAccessPoint *
nm_device_wifi_get_activation_ap (NMDeviceWifi *self)
{
@@ -3634,6 +3671,8 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
parent_class->get_connection_hw_address = get_connection_hw_address;
parent_class->state_changed = device_state_changed;
+ parent_class->test_reconfigure = test_reconfigure;
+ parent_class->reconfigure = reconfigure;
klass->scanning_allowed = scanning_allowed;
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 9cd2271620..84374887ff 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -213,6 +213,7 @@ typedef struct {
gpointer act_source6_func;
gulong secrets_updated_id;
gulong secrets_failed_id;
+ NMConnection * current_connection;
/* Link stuff */
guint link_connected_id;
@@ -1604,6 +1605,131 @@ nm_device_can_assume_connections (NMDevice *device)
}
static void
+test_reconfigure (NMDevice *self, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *conn_diff, *ip4_diff, *ip6_diff;
+
+ conn_diff = g_hash_table_lookup (diff, NM_SETTING_CONNECTION_SETTING_NAME);
+ ip4_diff = g_hash_table_lookup (diff, NM_SETTING_IP4_CONFIG_SETTING_NAME);
+ ip6_diff = g_hash_table_lookup (diff, NM_SETTING_IP6_CONFIG_SETTING_NAME);
+
+ /* These only affect matching and have already been taken into account. */
+ if (conn_diff)
+ g_hash_table_remove (conn_diff, NM_SETTING_CONNECTION_INTERFACE_NAME);
+ if (ip4_diff)
+ g_hash_table_remove (ip4_diff, NM_SETTING_IP4_CONFIG_MAY_FAIL);
+ if (ip6_diff)
+ g_hash_table_remove (ip6_diff, NM_SETTING_IP6_CONFIG_MAY_FAIL);
+
+ /* FIXME: remove reconfigurable ip4/ip6 properties */
+}
+
+static gboolean
+nm_device_can_reconfigure (NMDevice *self, NMConnection *connection,
+ GHashTable *diff)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ /* If the changes would make the connection incompatible, then we
+ * can always "reconfigure" the device (by deactivating the
+ * connection).
+ */
+ if (!nm_device_check_connection_compatible (self, connection, NULL))
+ return TRUE;
+ if ( (!priv->ip4_config && nm_device_ip_config_should_fail (self, FALSE))
+ || (!priv->ip6_config && nm_device_ip_config_should_fail (self, TRUE)))
+ return TRUE;
+
+ klass->test_reconfigure (self, connection, diff);
+
+ /* test_reconfigure() will have removed any properties it can
+ * reconfigure; clear out any now-empty settings diffs.
+ */
+ g_hash_table_iter_init (&iter, diff);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ if (g_hash_table_size (value) == 0)
+ g_hash_table_iter_remove (&iter);
+ }
+
+ /* If the diff is now empty, that means all of the changed
+ * properties are reconfigurable.
+ */
+ return g_hash_table_size (diff) == 0;
+}
+
+static gboolean
+reconfigure (NMDevice *device, NMConnection *connection,
+ NMDeviceStateReason *reason)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+ if (!nm_device_check_connection_compatible (device, connection, NULL)) {
+ nm_log_info ("(%s): connection '%s' is no longer compatible with device",
+ nm_device_get_iface (self), nm_connection_get_id (connection));
+ *reason = NM_DEVICE_STATE_REASON_CONNECTION_REMOVED;
+ return FALSE;
+ }
+
+ if (!priv->ip4_config && nm_device_ip_config_should_fail (device, FALSE)) {
+ nm_log_info ("(%s): connection '%s' now requires IPv4 connectivity",
+ nm_device_get_iface (self), nm_connection_get_id (connection));
+ *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
+ return FALSE;
+ }
+
+ if (!priv->ip6_config && nm_device_ip_config_should_fail (device, TRUE)) {
+ nm_log_info ("(%s): connection '%s' now requires IPv6 connectivity",
+ nm_device_get_iface (self), nm_connection_get_id (connection));
+ *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
+ return FALSE;
+ }
+
+ /* FIXME: reconfigure IP4 and IP6 properties, by re-merging the
+ * settings properties with the DHCP/SLAAC/AIPD/etc-provided
+ * configs.
+ */
+
+ return TRUE;
+}
+
+static void
+connection_updated (NMSettingsConnection *settings_connection, gpointer user_data)
+{
+ NMDevice *self = NM_DEVICE (user_data);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMConnection *connection = NM_CONNECTION (settings_connection);
+ NMDeviceStateReason reason;
+ GHashTable *diff = NULL;
+
+ if (!nm_connection_diff (priv->current_connection, connection,
+ NM_SETTING_COMPARE_FLAG_FUZZY,
+ &diff)) {
+ if (nm_device_can_reconfigure (self, connection, diff)) {
+ if (!NM_DEVICE_GET_CLASS (self)->reconfigure (self, connection, &reason)) {
+ nm_device_queue_state (self,
+ NM_DEVICE_STATE_DISCONNECTED,
+ reason);
+ }
+ } else {
+ nm_log_info ("(%s): connection '%s' changed, but device cannot be updated for those changes while active",
+ nm_device_get_iface (self), nm_connection_get_id (connection));
+ }
+
+ g_hash_table_destroy (diff);
+ } else {
+ nm_log_dbg ("(%s): connection '%s' changed, but the changes do not affect the device",
+ nm_device_get_iface (self), nm_connection_get_id (connection));
+ }
+
+ g_clear_object (&priv->current_connection);
+ priv->current_connection = nm_connection_duplicate (connection);
+}
+
+static void
dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
@@ -3881,7 +4007,8 @@ nm_device_activate_ip6_state_in_wait (NMDevice *self)
static void
clear_act_request (NMDevice *self)
{
- NMDevicePrivate * priv;
+ NMDevicePrivate *priv;
+ NMConnection *connection;
g_return_if_fail (self != NULL);
@@ -3902,6 +4029,10 @@ clear_act_request (NMDevice *self)
priv->secrets_failed_id = 0;
}
+ connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request));
+ g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), self);
+ g_clear_object (&priv->current_connection);
+
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE);
g_object_unref (priv->act_request);
@@ -4213,6 +4344,10 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
priv->act_request = g_object_ref (req);
g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
+ g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED,
+ G_CALLBACK (connection_updated), self);
+ priv->current_connection = g_object_ref (connection);
+
if (nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (req))) {
/* If it's an assumed connection, let the device subclass short-circuit
* the normal connection process and just copy its IP configs from the
@@ -4827,6 +4962,8 @@ dispose (GObject *object)
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self);
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
+ g_clear_object (&priv->current_connection);
+
out:
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
}
@@ -5132,6 +5269,8 @@ nm_device_class_init (NMDeviceClass *klass)
klass->carrier_changed = carrier_changed;
klass->can_interrupt_activation = can_interrupt_activation;
klass->get_hw_address_length = get_hw_address_length;
+ klass->test_reconfigure = test_reconfigure;
+ klass->reconfigure = reconfigure;
/* Properties */
g_object_class_install_property
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 7fcb768a5b..9f21d25bb6 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -187,7 +187,12 @@ typedef struct {
gboolean (* have_any_ready_slaves) (NMDevice *self,
const GSList *slaves);
- void (* link_changed) (NMDevice *self);
+ void (* link_changed) (NMDevice *self);
+
+ void (* test_reconfigure) (NMDevice *self, NMConnection *connection,
+ GHashTable *diff);
+ gboolean (* reconfigure) (NMDevice *self, NMConnection *connection,
+ NMDeviceStateReason *reason);
} NMDeviceClass;
diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c
index 9e9fae2cd1..c6325a5ccf 100644
--- a/src/devices/wimax/nm-device-wimax.c
+++ b/src/devices/wimax/nm-device-wimax.c
@@ -1205,6 +1205,19 @@ device_state_changed (NMDevice *device,
}
}
+static void
+test_reconfigure (NMDevice *device, NMConnection *connection,
+ GHashTable *diff)
+{
+ GHashTable *wimax_diff;
+
+ wimax_diff = g_hash_table_lookup (diff, NM_SETTING_WIMAX_SETTING_NAME);
+ if (wimax_diff) {
+ /* This only affects matching and has already been taken into account. */
+ g_hash_table_remove (wimax_diff, NM_SETTING_WIMAX_MAC_ADDRESS);
+ }
+}
+
/*************************************************************************/
static gboolean
@@ -1395,6 +1408,7 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *klass)
device_class->get_connection_hw_address = get_connection_hw_address;
device_class->state_changed = device_state_changed;
+ device_class->test_reconfigure = test_reconfigure;
/* Properties */
g_object_class_install_property (object_class, PROP_ACTIVE_NSP,