mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-06 03:30:31 +01:00
merge: better take-over of existing connections on NM startup (bgo #702488)
Read more state of connections that exist before NM starts, and take those connections over more effectively. https://bugzilla.gnome.org/show_bug.cgi?id=702488
This commit is contained in:
commit
465458a206
41 changed files with 1593 additions and 844 deletions
|
|
@ -548,6 +548,9 @@ typedef enum {
|
|||
/* DCB or FCoE setup failed */
|
||||
NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED = 55,
|
||||
|
||||
/* teamd control failed */
|
||||
NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED = 56,
|
||||
|
||||
/* Unused */
|
||||
NM_DEVICE_STATE_REASON_LAST = 0xFFFF
|
||||
} NMDeviceStateReason;
|
||||
|
|
|
|||
|
|
@ -592,6 +592,11 @@
|
|||
DCB or FCoE setup failed.
|
||||
</tp:docstring>
|
||||
</tp:enumvalue>
|
||||
<tp:enumvalue suffix="TEAMD_CONTROL_FAILED" value="56">
|
||||
<tp:docstring>
|
||||
teamd control failed.
|
||||
</tp:docstring>
|
||||
</tp:enumvalue>
|
||||
</tp:enum>
|
||||
|
||||
<tp:struct name="NM_DEVICE_STATE_REASON_STRUCT">
|
||||
|
|
|
|||
|
|
@ -184,13 +184,6 @@ complete_connection (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_l2_config (NMDevice *self, NMConnection *connection)
|
||||
{
|
||||
/* FIXME */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static gboolean
|
||||
|
|
@ -207,6 +200,57 @@ set_bond_attr (NMDevice *device, const char *attr, const char *value)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Ignore certain bond options if they are zero (off/disabled) */
|
||||
static gboolean
|
||||
ignore_if_zero (const char *option, const char *value)
|
||||
{
|
||||
if (strcmp (option, "arp_interval") &&
|
||||
strcmp (option, "miimon") &&
|
||||
strcmp (option, "downdelay") &&
|
||||
strcmp (option, "updelay"))
|
||||
return FALSE;
|
||||
|
||||
return g_strcmp0 (value, "0") == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
NMSettingBond *s_bond = nm_connection_get_setting_bond (connection);
|
||||
const char *ifname = nm_device_get_iface (device);
|
||||
int ifindex = nm_device_get_ifindex (device);
|
||||
const char **options;
|
||||
|
||||
if (!s_bond) {
|
||||
s_bond = (NMSettingBond *) nm_setting_bond_new ();
|
||||
nm_connection_add_setting (connection, (NMSetting *) s_bond);
|
||||
g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, ifname, NULL);
|
||||
}
|
||||
|
||||
/* Read bond options from sysfs and update the Bond setting to match */
|
||||
options = nm_setting_bond_get_valid_options (s_bond);
|
||||
while (options && *options) {
|
||||
gs_free char *value = nm_platform_master_get_option (ifindex, *options);
|
||||
const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options);
|
||||
|
||||
if (value && !ignore_if_zero (*options, value) && (g_strcmp0 (value, defvalue) != 0)) {
|
||||
/* Replace " " with "," for arp_ip_targets from the kernel */
|
||||
if (strcmp (*options, "arp_ip_target") == 0) {
|
||||
char *p = value;
|
||||
|
||||
while (p && *p) {
|
||||
if (*p == ' ')
|
||||
*p = ',';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
nm_setting_bond_add_option (s_bond, *options, value);
|
||||
}
|
||||
options++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_arp_targets (NMDevice *device,
|
||||
const char *value,
|
||||
|
|
@ -369,20 +413,23 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
||||
enslave_slave (NMDevice *device,
|
||||
NMDevice *slave,
|
||||
NMConnection *connection,
|
||||
gboolean configure)
|
||||
{
|
||||
gboolean success, no_firmware = FALSE;
|
||||
gboolean success = TRUE, no_firmware = FALSE;
|
||||
const char *iface = nm_device_get_ip_iface (device);
|
||||
const char *slave_iface = nm_device_get_ip_iface (slave);
|
||||
|
||||
nm_device_master_check_slave_physical_port (device, slave, LOGD_BOND);
|
||||
|
||||
nm_device_take_down (slave, TRUE);
|
||||
|
||||
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
|
||||
nm_device_get_ip_ifindex (slave));
|
||||
|
||||
nm_device_bring_up (slave, TRUE, &no_firmware);
|
||||
if (configure) {
|
||||
nm_device_take_down (slave, TRUE);
|
||||
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
|
||||
nm_device_get_ip_ifindex (slave));
|
||||
nm_device_bring_up (slave, TRUE, &no_firmware);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
nm_log_info (LOGD_BOND, "(%s): enslaved bond slave %s", iface, slave_iface);
|
||||
|
|
@ -518,6 +565,8 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
|
|||
|
||||
g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate));
|
||||
|
||||
parent_class->connection_type = NM_SETTING_BOND_SETTING_NAME;
|
||||
|
||||
/* virtual methods */
|
||||
object_class->constructed = constructed;
|
||||
object_class->get_property = get_property;
|
||||
|
|
@ -529,7 +578,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
|
|||
parent_class->check_connection_available = check_connection_available;
|
||||
parent_class->complete_connection = complete_connection;
|
||||
|
||||
parent_class->match_l2_config = match_l2_config;
|
||||
parent_class->update_connection = update_connection;
|
||||
|
||||
parent_class->act_stage1_prepare = act_stage1_prepare;
|
||||
parent_class->enslave_slave = enslave_slave;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <glib/gi18n.h>
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include "nm-device-bridge.h"
|
||||
|
|
@ -180,13 +181,6 @@ complete_connection (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_l2_config (NMDevice *self, NMConnection *connection)
|
||||
{
|
||||
/* FIXME */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -290,6 +284,80 @@ commit_slave_options (NMDevice *device, NMSettingBridgePort *setting)
|
|||
g_clear_object (&s_clear);
|
||||
}
|
||||
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
NMSettingBridge *s_bridge = nm_connection_get_setting_bridge (connection);
|
||||
const char *ifname = nm_device_get_iface (device);
|
||||
int ifindex = nm_device_get_ifindex (device);
|
||||
const Option *option;
|
||||
|
||||
if (!s_bridge) {
|
||||
s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
|
||||
nm_connection_add_setting (connection, (NMSetting *) s_bridge);
|
||||
g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, ifname, NULL);
|
||||
}
|
||||
|
||||
for (option = master_options; option->name; option++) {
|
||||
gs_free char *str = nm_platform_master_get_option (ifindex, option->sysname);
|
||||
int value = strtol (str, NULL, 10);
|
||||
|
||||
/* See comments in set_sysfs_uint() about centiseconds. */
|
||||
if (option->user_hz_compensate)
|
||||
value /= 100;
|
||||
|
||||
g_object_set (s_bridge, option->name, value, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_bridge_update_slave_connection:
|
||||
* @slave: the slave #NMDevice, is *not* necessarily a bridge interface
|
||||
* @connection: the #NMConnection to update with the bridge port settings
|
||||
*
|
||||
* Reads bridge port configuration and updates @connection with those
|
||||
* properties.
|
||||
*
|
||||
* Returns: %TRUE if the port configuration was read and @connection updated,
|
||||
* %FALSE if not.
|
||||
*/
|
||||
gboolean
|
||||
nm_bridge_update_slave_connection (NMDevice *slave, NMConnection *connection)
|
||||
{
|
||||
NMSettingBridgePort *s_port;
|
||||
int ifindex = nm_device_get_ifindex (slave);
|
||||
const Option *option;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE);
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
|
||||
|
||||
s_port = nm_connection_get_setting_bridge_port (connection);
|
||||
if (!s_port) {
|
||||
s_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
|
||||
nm_connection_add_setting (connection, NM_SETTING (s_port));
|
||||
}
|
||||
|
||||
for (option = slave_options; option->name; option++) {
|
||||
gs_free char *str = nm_platform_slave_get_option (ifindex, option->sysname);
|
||||
int value;
|
||||
|
||||
if (str) {
|
||||
value = strtol (str, NULL, 10);
|
||||
|
||||
/* See comments in set_sysfs_uint() about centiseconds. */
|
||||
if (option->user_hz_compensate)
|
||||
value /= 100;
|
||||
|
||||
g_object_set (s_port, option->name, value, NULL);
|
||||
} else {
|
||||
nm_log_warn (LOGD_BRIDGE, "(%s): failed to read bridge port setting '%s'",
|
||||
nm_device_get_iface (slave), option->sysname);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
|
||||
{
|
||||
|
|
@ -308,12 +376,17 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
||||
enslave_slave (NMDevice *device,
|
||||
NMDevice *slave,
|
||||
NMConnection *connection,
|
||||
gboolean configure)
|
||||
{
|
||||
if (!nm_platform_link_enslave (nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)))
|
||||
return FALSE;
|
||||
if (configure) {
|
||||
if (!nm_platform_link_enslave (nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)))
|
||||
return FALSE;
|
||||
|
||||
commit_slave_options (slave, nm_connection_get_setting_bridge_port (connection));
|
||||
commit_slave_options (slave, nm_connection_get_setting_bridge_port (connection));
|
||||
}
|
||||
|
||||
nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s",
|
||||
nm_device_get_ip_iface (device),
|
||||
|
|
@ -439,6 +512,8 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
|
|||
|
||||
g_type_class_add_private (object_class, sizeof (NMDeviceBridgePrivate));
|
||||
|
||||
parent_class->connection_type = NM_SETTING_BRIDGE_SETTING_NAME;
|
||||
|
||||
/* virtual methods */
|
||||
object_class->constructed = constructed;
|
||||
object_class->get_property = get_property;
|
||||
|
|
@ -450,7 +525,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
|
|||
parent_class->check_connection_available = check_connection_available;
|
||||
parent_class->complete_connection = complete_connection;
|
||||
|
||||
parent_class->match_l2_config = match_l2_config;
|
||||
parent_class->update_connection = update_connection;
|
||||
|
||||
parent_class->act_stage1_prepare = act_stage1_prepare;
|
||||
parent_class->enslave_slave = enslave_slave;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ GType nm_device_bridge_get_type (void);
|
|||
NMDevice *nm_device_bridge_new (NMPlatformLink *platform_device);
|
||||
NMDevice *nm_device_bridge_new_for_connection (NMConnection *connection);
|
||||
|
||||
gboolean nm_bridge_update_slave_connection (NMDevice *slave, NMConnection *connection);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_DEVICE_BRIDGE_H */
|
||||
|
|
|
|||
|
|
@ -1238,19 +1238,38 @@ spec_match_list (NMDevice *device, const GSList *specs)
|
|||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
|
||||
NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
|
||||
guint maclen;
|
||||
gconstpointer mac = nm_device_get_hw_address (device, &maclen);
|
||||
static const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
|
||||
const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS;
|
||||
GByteArray *array;
|
||||
|
||||
if (!s_wired) {
|
||||
s_wired = (NMSettingWired *) nm_setting_wired_new ();
|
||||
nm_connection_add_setting (connection, (NMSetting *) s_wired);
|
||||
}
|
||||
|
||||
if (mac && maclen == 6) {
|
||||
GBytes *address = g_bytes_new (mac, maclen);
|
||||
/* If the device reports a permanent address, use that for the MAC address
|
||||
* and the current MAC, if different, is the cloned MAC.
|
||||
*/
|
||||
if (priv->perm_hw_addr && memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) {
|
||||
array = g_byte_array_sized_new (ETH_ALEN);
|
||||
g_byte_array_append (array, priv->perm_hw_addr, ETH_ALEN);
|
||||
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, array, NULL);
|
||||
g_byte_array_unref (array);
|
||||
|
||||
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, address, NULL);
|
||||
mac_prop = NULL;
|
||||
if (mac && memcmp (priv->perm_hw_addr, mac, ETH_ALEN))
|
||||
mac_prop = NM_SETTING_WIRED_CLONED_MAC_ADDRESS;
|
||||
}
|
||||
|
||||
if (mac_prop && mac && maclen == ETH_ALEN) {
|
||||
array = g_byte_array_sized_new (ETH_ALEN);
|
||||
g_byte_array_append (array, (guint8 *) mac, maclen);
|
||||
g_object_set (s_wired, mac_prop, array, NULL);
|
||||
g_byte_array_unref (array);
|
||||
}
|
||||
|
||||
/* We don't set the MTU as we don't know whether it was set explicitly */
|
||||
|
|
|
|||
|
|
@ -95,6 +95,13 @@ check_connection_compatible (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
if (!nm_connection_get_setting_generic (connection))
|
||||
nm_connection_add_setting (connection, nm_setting_generic_new ());
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
NMDevice *
|
||||
|
|
@ -184,6 +191,8 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass)
|
|||
|
||||
g_type_class_add_private (klass, sizeof (NMDeviceGenericPrivate));
|
||||
|
||||
parent_class->connection_type = NM_SETTING_GENERIC_SETTING_NAME;
|
||||
|
||||
object_class->constructed = constructed;
|
||||
object_class->dispose = dispose;
|
||||
object_class->get_property = get_property;
|
||||
|
|
@ -191,6 +200,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass)
|
|||
|
||||
parent_class->get_generic_capabilities = get_generic_capabilities;
|
||||
parent_class->check_connection_compatible = check_connection_compatible;
|
||||
parent_class->update_connection = update_connection;
|
||||
|
||||
/* properties */
|
||||
g_object_class_install_property
|
||||
|
|
|
|||
|
|
@ -307,11 +307,39 @@ complete_connection (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_l2_config (NMDevice *self, NMConnection *connection)
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
/* FIXME */
|
||||
return TRUE;
|
||||
NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
|
||||
guint maclen;
|
||||
gconstpointer mac = nm_device_get_hw_address (device, &maclen);
|
||||
static const guint8 null_mac[INFINIBAND_ALEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
GByteArray *array;
|
||||
char *mode_path, *contents;
|
||||
const char *transport_mode = "datagram";
|
||||
|
||||
if (!s_infiniband) {
|
||||
s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new ();
|
||||
nm_connection_add_setting (connection, (NMSetting *) s_infiniband);
|
||||
}
|
||||
|
||||
if (mac && (maclen == INFINIBAND_ALEN) && (memcmp (mac, null_mac, maclen) != 0)) {
|
||||
array = g_byte_array_sized_new (maclen);
|
||||
g_byte_array_append (array, (guint8 *) mac, maclen);
|
||||
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, array, NULL);
|
||||
g_byte_array_unref (array);
|
||||
}
|
||||
|
||||
mode_path = g_strdup_printf ("/sys/class/net/%s/mode", nm_device_get_iface (device));
|
||||
if (g_file_get_contents (mode_path, &contents, NULL, NULL)) {
|
||||
if (strstr (contents, "datagram"))
|
||||
transport_mode = "datagram";
|
||||
else if (strstr (contents, "connected"))
|
||||
transport_mode = "connected";
|
||||
}
|
||||
g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, transport_mode, NULL);
|
||||
g_free (mode_path);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -384,11 +412,11 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
|
|||
parent_class->get_generic_capabilities = get_generic_capabilities;
|
||||
parent_class->check_connection_compatible = check_connection_compatible;
|
||||
parent_class->complete_connection = complete_connection;
|
||||
parent_class->update_connection = update_connection;
|
||||
parent_class->spec_match_list = spec_match_list;
|
||||
|
||||
parent_class->act_stage1_prepare = act_stage1_prepare;
|
||||
parent_class->ip4_config_pre_commit = ip4_config_pre_commit;
|
||||
parent_class->match_l2_config = match_l2_config;
|
||||
|
||||
/* properties */
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#if WITH_TEAMDCTL
|
||||
#include <teamdctl.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nm-device-team.h"
|
||||
#include "nm-logging.h"
|
||||
|
|
@ -195,11 +196,108 @@ complete_connection (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#if WITH_TEAMDCTL
|
||||
static gboolean
|
||||
match_l2_config (NMDevice *self, NMConnection *connection)
|
||||
ensure_teamd_connection (NMDevice *self)
|
||||
{
|
||||
/* FIXME */
|
||||
return TRUE;
|
||||
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
|
||||
int err;
|
||||
|
||||
if (priv->tdc)
|
||||
return TRUE;
|
||||
|
||||
priv->tdc = teamdctl_alloc ();
|
||||
g_assert (priv->tdc);
|
||||
err = teamdctl_connect (priv->tdc, nm_device_get_iface (self), NULL, NULL);
|
||||
if (err) {
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to connect to teamd", nm_device_get_iface (self));
|
||||
teamdctl_free (priv->tdc);
|
||||
priv->tdc = NULL;
|
||||
}
|
||||
|
||||
return !!priv->tdc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
NMSettingTeam *s_team = nm_connection_get_setting_team (connection);
|
||||
const char *iface = nm_device_get_iface (device);
|
||||
|
||||
if (!s_team) {
|
||||
s_team = (NMSettingTeam *) nm_setting_team_new ();
|
||||
nm_connection_add_setting (connection, (NMSetting *) s_team);
|
||||
g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_INTERFACE_NAME, iface, NULL);
|
||||
}
|
||||
|
||||
#if WITH_TEAMDCTL
|
||||
if (ensure_teamd_connection (device)) {
|
||||
char *config;
|
||||
|
||||
config = teamdctl_config_get_raw (NM_DEVICE_TEAM_GET_PRIVATE (device)->tdc);
|
||||
if (config)
|
||||
g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, config, NULL);
|
||||
else
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to read teamd config", iface);
|
||||
g_free (config);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
gboolean
|
||||
nm_team_update_slave_connection (NMDevice *slave, NMConnection *connection)
|
||||
{
|
||||
NMSettingTeamPort *s_port;
|
||||
const char *iface = nm_device_get_iface (slave);
|
||||
char *port_config = NULL;
|
||||
gboolean success = FALSE;
|
||||
#if WITH_TEAMDCTL
|
||||
const char *master_iface;
|
||||
int master_ifindex;
|
||||
struct teamdctl *tdc;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE);
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
|
||||
|
||||
#if WITH_TEAMDCTL
|
||||
master_ifindex = nm_platform_link_get_master (nm_device_get_ifindex (slave));
|
||||
g_assert (master_ifindex > 0);
|
||||
master_iface = nm_platform_link_get_name (master_ifindex);
|
||||
g_assert (master_iface);
|
||||
|
||||
tdc = teamdctl_alloc ();
|
||||
g_assert (tdc);
|
||||
err = teamdctl_connect (tdc, master_iface, NULL, NULL);
|
||||
if (err) {
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to connect to teamd for master %s",
|
||||
iface, master_iface);
|
||||
teamdctl_free (tdc);
|
||||
return FALSE;
|
||||
}
|
||||
/* FIXME: wait for libteamd to implement getting port config */
|
||||
/* port_config = teamdctl_port_config_get_raw (tdc, iface); */
|
||||
teamdctl_free (tdc);
|
||||
#endif
|
||||
|
||||
s_port = nm_connection_get_setting_team_port (connection);
|
||||
if (!s_port) {
|
||||
s_port = (NMSettingTeamPort *) nm_setting_team_port_new ();
|
||||
nm_connection_add_setting (connection, NM_SETTING (s_port));
|
||||
}
|
||||
|
||||
if (port_config) {
|
||||
g_object_set (G_OBJECT (s_port), NM_SETTING_TEAM_PORT_CONFIG, port_config, NULL);
|
||||
free (port_config);
|
||||
success = TRUE;
|
||||
} else
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to read teamd port configuration", iface);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
|
@ -279,7 +377,7 @@ teamd_cleanup (NMDevice *dev, gboolean device_state_failed)
|
|||
if (device_state_failed) {
|
||||
if (nm_device_is_activating (dev) ||
|
||||
(nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED))
|
||||
nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE);
|
||||
nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -311,17 +409,9 @@ teamd_dbus_appeared (GDBusConnection *connection,
|
|||
nm_log_info (LOGD_TEAM, "(%s): teamd appeared on D-Bus", nm_device_get_iface (dev));
|
||||
teamd_timeout_remove (dev);
|
||||
#if WITH_TEAMDCTL
|
||||
if (!priv->tdc) {
|
||||
int err;
|
||||
|
||||
priv->tdc = teamdctl_alloc ();
|
||||
g_assert (priv->tdc);
|
||||
err = teamdctl_connect (priv->tdc, nm_device_get_iface (dev), NULL, NULL);
|
||||
if (err) {
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to connect to teamd", nm_device_get_iface (dev));
|
||||
teamdctl_free (priv->tdc);
|
||||
priv->tdc = NULL;
|
||||
}
|
||||
if (!ensure_teamd_connection (dev)) {
|
||||
nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
nm_device_activate_schedule_stage2_device_config (dev);
|
||||
|
|
@ -548,48 +638,52 @@ deactivate (NMDevice *dev)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
||||
enslave_slave (NMDevice *device,
|
||||
NMDevice *slave,
|
||||
NMConnection *connection,
|
||||
gboolean configure)
|
||||
{
|
||||
#if WITH_TEAMDCTL
|
||||
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);
|
||||
#endif
|
||||
gboolean success, no_firmware = FALSE;
|
||||
gboolean success = TRUE, no_firmware = FALSE;
|
||||
const char *iface = nm_device_get_ip_iface (device);
|
||||
const char *slave_iface = nm_device_get_ip_iface (slave);
|
||||
NMSettingTeamPort *s_team_port;
|
||||
|
||||
nm_device_master_check_slave_physical_port (device, slave, LOGD_TEAM);
|
||||
|
||||
nm_device_take_down (slave, TRUE);
|
||||
if (configure) {
|
||||
nm_device_take_down (slave, TRUE);
|
||||
|
||||
s_team_port = nm_connection_get_setting_team_port (connection);
|
||||
if (s_team_port) {
|
||||
const char *config = nm_setting_team_port_get_config (s_team_port);
|
||||
s_team_port = nm_connection_get_setting_team_port (connection);
|
||||
if (s_team_port) {
|
||||
const char *config = nm_setting_team_port_get_config (s_team_port);
|
||||
|
||||
if (config) {
|
||||
if (config) {
|
||||
#if WITH_TEAMDCTL
|
||||
if (!priv->tdc) {
|
||||
nm_log_warn (LOGD_TEAM, "(%s): enslaved team port %s config not changed, not connected to teamd",
|
||||
iface, slave_iface);
|
||||
} else {
|
||||
int err;
|
||||
if (!priv->tdc) {
|
||||
nm_log_warn (LOGD_TEAM, "(%s): enslaved team port %s config not changed, not connected to teamd",
|
||||
iface, slave_iface);
|
||||
} else {
|
||||
int err;
|
||||
|
||||
err = teamdctl_port_config_update_raw (priv->tdc, slave_iface, config);
|
||||
if (err) {
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to update config for port %s", iface, slave_iface);
|
||||
return FALSE;
|
||||
err = teamdctl_port_config_update_raw (priv->tdc, slave_iface, config);
|
||||
if (err) {
|
||||
nm_log_err (LOGD_TEAM, "(%s): failed to update config for port %s", iface, slave_iface);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
nm_log_warn (LOGD_TEAM, "(%s): enslaved team port %s config not changed due to lack of Teamd control support",
|
||||
iface, slave_iface);
|
||||
nm_log_warn (LOGD_TEAM, "(%s): enslaved team port %s config not changed due to lack of Teamd control support",
|
||||
iface, slave_iface);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
|
||||
nm_device_get_ip_ifindex (slave));
|
||||
nm_device_bring_up (slave, TRUE, &no_firmware);
|
||||
}
|
||||
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
|
||||
nm_device_get_ip_ifindex (slave));
|
||||
|
||||
nm_device_bring_up (slave, TRUE, &no_firmware);
|
||||
|
||||
if (success) {
|
||||
nm_log_info (LOGD_TEAM, "(%s): enslaved team port %s", iface, slave_iface);
|
||||
|
|
@ -744,8 +838,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass)
|
|||
parent_class->check_connection_compatible = check_connection_compatible;
|
||||
parent_class->check_connection_available = check_connection_available;
|
||||
parent_class->complete_connection = complete_connection;
|
||||
|
||||
parent_class->match_l2_config = match_l2_config;
|
||||
parent_class->update_connection = update_connection;
|
||||
|
||||
parent_class->act_stage1_prepare = act_stage1_prepare;
|
||||
parent_class->deactivate = deactivate;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ GType nm_device_team_get_type (void);
|
|||
NMDevice *nm_device_team_new (NMPlatformLink *platform_device);
|
||||
NMDevice *nm_device_team_new_for_connection (NMConnection *connection);
|
||||
|
||||
gboolean nm_team_update_slave_connection (NMDevice *slave, NMConnection *connection);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_DEVICE_TEAM_H */
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <netinet/ether.h>
|
||||
|
||||
#include "nm-device-vlan.h"
|
||||
#include "nm-manager.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-utils.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
|
@ -35,6 +36,7 @@
|
|||
#include "nm-enum-types.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-platform.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
#include "nm-device-vlan-glue.h"
|
||||
|
||||
|
|
@ -54,7 +56,7 @@ typedef struct {
|
|||
NMDevice *parent;
|
||||
guint parent_state_id;
|
||||
|
||||
guint vlan_id;
|
||||
int vlan_id;
|
||||
} NMDeviceVlanPrivate;
|
||||
|
||||
enum {
|
||||
|
|
@ -274,35 +276,76 @@ complete_connection (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_l2_config (NMDevice *device, NMConnection *connection)
|
||||
static void parent_state_changed (NMDevice *parent, NMDeviceState new_state,
|
||||
NMDeviceState old_state,
|
||||
NMDeviceStateReason reason,
|
||||
gpointer user_data);
|
||||
|
||||
static void
|
||||
nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent)
|
||||
{
|
||||
NMSettingVlan *s_vlan;
|
||||
gboolean fail_if_no_hwaddr = FALSE;
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
|
||||
|
||||
s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
g_assert (s_vlan);
|
||||
if (priv->parent_state_id) {
|
||||
g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
|
||||
priv->parent_state_id = 0;
|
||||
}
|
||||
g_clear_object (&priv->parent);
|
||||
|
||||
if ( !nm_setting_vlan_get_parent (s_vlan)
|
||||
&& !nm_setting_vlan_get_interface_name (s_vlan)) {
|
||||
/* If there's no parent and no interface name given, then the only way
|
||||
* we have to identify the VLAN interface the connection matches is
|
||||
* a hardware-specific setting's hardware address property, so we want
|
||||
* to fail the match below if we there is none.
|
||||
*/
|
||||
fail_if_no_hwaddr = TRUE;
|
||||
if (parent) {
|
||||
priv->parent = g_object_ref (parent);
|
||||
priv->parent_state_id = g_signal_connect (priv->parent,
|
||||
"state-changed",
|
||||
G_CALLBACK (parent_state_changed),
|
||||
device);
|
||||
}
|
||||
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT);
|
||||
}
|
||||
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
|
||||
NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
int ifindex = nm_device_get_ifindex (device);
|
||||
int parent_ifindex = -1, vlan_id = -1;
|
||||
NMDevice *parent;
|
||||
const char *setting_parent, *new_parent;
|
||||
|
||||
if (!s_vlan) {
|
||||
s_vlan = (NMSettingVlan *) nm_setting_vlan_new ();
|
||||
nm_connection_add_setting (connection, (NMSetting *) s_vlan);
|
||||
g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, nm_device_get_iface (device), NULL);
|
||||
}
|
||||
|
||||
/* MAC address check; we ask the parent to check our own MAC address,
|
||||
* because only the parent knows what kind of NMSetting the MAC
|
||||
* address will be in. The VLAN device shouldn't have to know what kind
|
||||
* of interface the parent is.
|
||||
*/
|
||||
if (!match_hwaddr (device, connection, fail_if_no_hwaddr))
|
||||
return FALSE;
|
||||
nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id);
|
||||
if (priv->vlan_id != vlan_id) {
|
||||
priv->vlan_id = vlan_id;
|
||||
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_ID);
|
||||
}
|
||||
|
||||
/* FIXME: any more L2 checks? */
|
||||
return TRUE;
|
||||
if (vlan_id != nm_setting_vlan_get_id (s_vlan))
|
||||
g_object_set (s_vlan, NM_SETTING_VLAN_ID, priv->vlan_id, NULL);
|
||||
|
||||
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
|
||||
g_assert (parent);
|
||||
if (priv->parent != parent)
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
|
||||
|
||||
/* Update parent in the connection; default to parent's interface name */
|
||||
new_parent = nm_device_get_iface (parent);
|
||||
setting_parent = nm_setting_vlan_get_parent (s_vlan);
|
||||
if (setting_parent && nm_utils_is_uuid (setting_parent)) {
|
||||
NMConnectionProvider *cp = nm_device_get_connection_provider (device);
|
||||
NMConnection *parent_connection;
|
||||
|
||||
/* Don't change a parent specified by UUID if it's still valid */
|
||||
parent_connection = nm_connection_provider_get_connection_by_uuid (cp, setting_parent);
|
||||
if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection, NULL))
|
||||
new_parent = NULL;
|
||||
}
|
||||
if (new_parent)
|
||||
g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL);
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
|
|
@ -558,11 +601,7 @@ set_property (GObject *object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_PARENT:
|
||||
priv->parent = g_value_dup_object (value);
|
||||
priv->parent_state_id = g_signal_connect (priv->parent,
|
||||
"state-changed",
|
||||
G_CALLBACK (parent_state_changed),
|
||||
object);
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value));
|
||||
break;
|
||||
case PROP_VLAN_ID:
|
||||
priv->vlan_id = g_value_get_uint (value);
|
||||
|
|
@ -585,8 +624,7 @@ dispose (GObject *object)
|
|||
}
|
||||
priv->disposed = TRUE;
|
||||
|
||||
g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
|
||||
g_object_unref (priv->parent);
|
||||
nm_device_vlan_set_parent (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object);
|
||||
}
|
||||
|
|
@ -597,6 +635,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
|
|||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
|
||||
|
||||
parent_class->connection_type = NM_SETTING_VLAN_SETTING_NAME;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (NMDeviceVlanPrivate));
|
||||
|
||||
/* virtual methods */
|
||||
|
|
@ -614,7 +654,7 @@ 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->update_connection = update_connection;
|
||||
|
||||
/* properties */
|
||||
g_object_class_install_property
|
||||
|
|
|
|||
|
|
@ -69,6 +69,10 @@
|
|||
#include "nm-config.h"
|
||||
#include "nm-platform.h"
|
||||
|
||||
#include "nm-device-bridge.h"
|
||||
#include "nm-device-bond.h"
|
||||
#include "nm-device-team.h"
|
||||
|
||||
static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context);
|
||||
|
||||
#include "nm-device-glue.h"
|
||||
|
|
@ -164,6 +168,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
NMDevice *slave;
|
||||
gboolean enslaved;
|
||||
gboolean configure;
|
||||
guint watch_id;
|
||||
} SlaveInfo;
|
||||
|
||||
|
|
@ -349,7 +354,7 @@ static void link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *
|
|||
static void check_carrier (NMDevice *device);
|
||||
|
||||
static void nm_device_queued_ip_config_change_clear (NMDevice *self);
|
||||
static void update_ip_config (NMDevice *self);
|
||||
static void update_ip_config (NMDevice *self, gboolean capture_dhcp);
|
||||
static void device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformReason reason, gpointer user_data);
|
||||
|
||||
static void nm_device_slave_notify_enslave (NMDevice *dev, gboolean success);
|
||||
|
|
@ -545,7 +550,6 @@ constructor (GType type,
|
|||
|
||||
update_accept_ra_save (dev);
|
||||
update_ip6_privacy_save (dev);
|
||||
update_ip_config (dev);
|
||||
|
||||
/* Watch for external IP config changes */
|
||||
platform = nm_platform_get ();
|
||||
|
|
@ -717,7 +721,10 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
|
|||
priv->ip_iface = g_strdup (iface);
|
||||
if (priv->ip_iface) {
|
||||
priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface);
|
||||
if (priv->ip_ifindex <= 0) {
|
||||
if (priv->ip_ifindex > 0) {
|
||||
if (!nm_platform_link_is_up (priv->ip_ifindex))
|
||||
nm_platform_link_set_up (priv->ip_ifindex);
|
||||
} else {
|
||||
/* Device IP interface must always be a kernel network interface */
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface);
|
||||
}
|
||||
|
|
@ -955,7 +962,7 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio
|
|||
return FALSE;
|
||||
|
||||
g_warn_if_fail (info->enslaved == FALSE);
|
||||
success = NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave, connection);
|
||||
success = NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave, connection, info->configure);
|
||||
|
||||
info->enslaved = success;
|
||||
nm_device_slave_notify_enslave (info->slave, success);
|
||||
|
|
@ -1242,6 +1249,8 @@ slave_state_changed (NMDevice *slave,
|
|||
* nm_device_master_add_slave:
|
||||
* @dev: the master device
|
||||
* @slave: the slave device to enslave
|
||||
* @configure: pass %TRUE if the slave should be configured by the master, or
|
||||
* %FALSE if it is already configured outside NetworkManager
|
||||
*
|
||||
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, team,
|
||||
* etc) then this function adds @slave to the slave list for later enslavement.
|
||||
|
|
@ -1249,7 +1258,7 @@ slave_state_changed (NMDevice *slave,
|
|||
* Returns: %TRUE on success, %FALSE on failure
|
||||
*/
|
||||
gboolean
|
||||
nm_device_master_add_slave (NMDevice *dev, NMDevice *slave)
|
||||
nm_device_master_add_slave (NMDevice *dev, NMDevice *slave, gboolean configure)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
|
||||
SlaveInfo *info;
|
||||
|
|
@ -1262,6 +1271,7 @@ nm_device_master_add_slave (NMDevice *dev, NMDevice *slave)
|
|||
if (!find_slave_info (dev, slave)) {
|
||||
info = g_malloc0 (sizeof (SlaveInfo));
|
||||
info->slave = g_object_ref (slave);
|
||||
info->configure = configure;
|
||||
info->watch_id = g_signal_connect (slave, "state-changed",
|
||||
G_CALLBACK (slave_state_changed), dev);
|
||||
priv->slaves = g_slist_prepend (priv->slaves, info);
|
||||
|
|
@ -1625,6 +1635,10 @@ device_has_config (NMDevice *device)
|
|||
if (nm_device_is_software (device))
|
||||
return TRUE;
|
||||
|
||||
/* Slaves are also configured by definition */
|
||||
if (nm_platform_link_get_master (priv->ifindex) > 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1634,12 +1648,15 @@ nm_device_generate_connection (NMDevice *device)
|
|||
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (device);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
const char *ifname = nm_device_get_iface (device);
|
||||
int ifindex = nm_device_get_ifindex (device);
|
||||
NMConnection *connection;
|
||||
NMSetting *s_con;
|
||||
NMSetting *s_ip4;
|
||||
NMSetting *s_ip6;
|
||||
gs_free char *uuid = NULL;
|
||||
gs_free char *name = NULL;
|
||||
int master_ifindex = 0;
|
||||
const char *ip4_method, *ip6_method;
|
||||
|
||||
/* If update_connection() is not implemented, just fail. */
|
||||
if (!klass->update_connection)
|
||||
|
|
@ -1649,12 +1666,8 @@ nm_device_generate_connection (NMDevice *device)
|
|||
if (!device_has_config (device))
|
||||
return NULL;
|
||||
|
||||
nm_log_info (LOGD_DEVICE, "(%s): Generating connection from current device status.", ifname);
|
||||
|
||||
connection = nm_connection_new ();
|
||||
s_con = nm_setting_connection_new ();
|
||||
s_ip4 = nm_setting_ip4_config_new ();
|
||||
s_ip6 = nm_setting_ip6_config_new ();
|
||||
uuid = nm_utils_uuid_generate ();
|
||||
name = g_strdup_printf ("%s", ifname);
|
||||
|
||||
|
|
@ -1666,18 +1679,75 @@ nm_device_generate_connection (NMDevice *device)
|
|||
NULL);
|
||||
if (klass->connection_type)
|
||||
g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type, NULL);
|
||||
nm_ip4_config_update_setting (priv->ip4_config, (NMSettingIP4Config *) s_ip4);
|
||||
nm_ip6_config_update_setting (priv->ip6_config, (NMSettingIP6Config *) s_ip6);
|
||||
|
||||
nm_connection_add_setting (connection, s_con);
|
||||
|
||||
/* If the device is a slave, update various slave settings */
|
||||
if (ifindex)
|
||||
master_ifindex = nm_platform_link_get_master (ifindex);
|
||||
if (master_ifindex) {
|
||||
const char *master_iface = nm_platform_link_get_name (master_ifindex);
|
||||
const char *slave_type = NULL;
|
||||
gboolean success = FALSE;
|
||||
|
||||
switch (nm_platform_link_get_type (master_ifindex)) {
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
slave_type = NM_SETTING_BRIDGE_SETTING_NAME;
|
||||
success = nm_bridge_update_slave_connection (device, connection);
|
||||
break;
|
||||
case NM_LINK_TYPE_BOND:
|
||||
slave_type = NM_SETTING_BOND_SETTING_NAME;
|
||||
success = TRUE;
|
||||
break;
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
slave_type = NM_SETTING_TEAM_SETTING_NAME;
|
||||
success = nm_team_update_slave_connection (device, connection);
|
||||
break;
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
nm_log_err (LOGD_DEVICE, "(%s): failed to read slave configuration", ifname);
|
||||
|
||||
g_object_set (s_con,
|
||||
NM_SETTING_CONNECTION_MASTER, master_iface,
|
||||
NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
s_ip4 = nm_setting_ip4_config_new ();
|
||||
nm_connection_add_setting (connection, s_ip4);
|
||||
if (priv->ip4_config)
|
||||
nm_ip4_config_update_setting (priv->ip4_config, (NMSettingIP4Config *) s_ip4);
|
||||
else
|
||||
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL);
|
||||
|
||||
s_ip6 = nm_setting_ip6_config_new ();
|
||||
nm_connection_add_setting (connection, s_ip6);
|
||||
if (priv->ip6_config)
|
||||
nm_ip6_config_update_setting (priv->ip6_config, (NMSettingIP6Config *) s_ip6);
|
||||
else
|
||||
g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
|
||||
|
||||
klass->update_connection (device, connection);
|
||||
|
||||
/* Check the connection in case of update_connection() bug. */
|
||||
g_return_val_if_fail (nm_connection_verify (connection, NULL), NULL);
|
||||
|
||||
/* Ignore the connection if it has no IP configuration,
|
||||
* no slave configuration, and is not a master interface.
|
||||
*/
|
||||
ip4_method = nm_setting_ip4_config_get_method (NM_SETTING_IP4_CONFIG (s_ip4));
|
||||
ip6_method = nm_setting_ip6_config_get_method (NM_SETTING_IP6_CONFIG (s_ip6));
|
||||
if ( strcmp (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0
|
||||
&& strcmp (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0
|
||||
&& !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))
|
||||
&& !nm_platform_link_supports_slaves (priv->ifindex)) {
|
||||
g_object_unref (connection);
|
||||
connection = NULL;
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
|
@ -1806,7 +1876,6 @@ nm_device_check_connection_compatible (NMDevice *device,
|
|||
* @device: #NMDevice instance
|
||||
*
|
||||
* This is a convenience function to determine whether connection assumption
|
||||
* via old match_l2_config() or new update_connection() virtual functions
|
||||
* is available for this device.
|
||||
*
|
||||
* Use this function when you need to determine whether full cleanup should
|
||||
|
|
@ -1821,9 +1890,7 @@ nm_device_check_connection_compatible (NMDevice *device,
|
|||
gboolean
|
||||
nm_device_can_assume_connections (NMDevice *device)
|
||||
{
|
||||
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (device);
|
||||
|
||||
return klass->match_l2_config || klass->update_connection;
|
||||
return !!NM_DEVICE_GET_CLASS (device)->update_connection;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1935,7 +2002,9 @@ master_ready_cb (NMActiveConnection *active,
|
|||
master = nm_active_connection_get_master (active);
|
||||
|
||||
priv->master = g_object_ref (nm_active_connection_get_device (master));
|
||||
nm_device_master_add_slave (priv->master, self);
|
||||
nm_device_master_add_slave (priv->master,
|
||||
self,
|
||||
nm_active_connection_get_assumed (active) ? FALSE : TRUE);
|
||||
|
||||
nm_log_dbg (LOGD_DEVICE, "(%s): master connection ready; master device %s",
|
||||
nm_device_get_iface (self),
|
||||
|
|
@ -1952,10 +2021,46 @@ master_ready_cb (NMActiveConnection *active,
|
|||
static NMActStageReturn
|
||||
act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
|
||||
{
|
||||
return NM_ACT_STAGE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_device_activate_stage1_device_prepare
|
||||
*
|
||||
* Prepare for device activation
|
||||
*
|
||||
*/
|
||||
static gboolean
|
||||
nm_device_activate_stage1_device_prepare (gpointer user_data)
|
||||
{
|
||||
NMDevice *self = NM_DEVICE (user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
const char *iface;
|
||||
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
|
||||
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
|
||||
NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
|
||||
|
||||
/* Clear the activation source ID now that this stage has run */
|
||||
activation_source_clear (self, FALSE, 0);
|
||||
|
||||
priv->ip4_state = priv->ip6_state = IP_NONE;
|
||||
|
||||
iface = nm_device_get_iface (self);
|
||||
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface);
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
|
||||
|
||||
/* Assumed connections were already set up outside NetworkManager */
|
||||
if (!nm_active_connection_get_assumed (active)) {
|
||||
ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason);
|
||||
if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
|
||||
goto out;
|
||||
} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
|
||||
goto out;
|
||||
}
|
||||
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
|
||||
}
|
||||
|
||||
if (nm_active_connection_get_master (active)) {
|
||||
/* If the master connection is ready for slaves, attach ourselves */
|
||||
if (nm_active_connection_get_master_ready (active))
|
||||
|
|
@ -1970,47 +2075,10 @@ act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
|
|||
"notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY,
|
||||
(GCallback) master_ready_cb,
|
||||
self);
|
||||
ret = NM_ACT_STAGE_RETURN_POSTPONE;
|
||||
/* Postpone */
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_device_activate_stage1_device_prepare
|
||||
*
|
||||
* Prepare for device activation
|
||||
*
|
||||
*/
|
||||
static gboolean
|
||||
nm_device_activate_stage1_device_prepare (gpointer user_data)
|
||||
{
|
||||
NMDevice *self = NM_DEVICE (user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
const char *iface;
|
||||
NMActStageReturn ret;
|
||||
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
|
||||
|
||||
/* Clear the activation source ID now that this stage has run */
|
||||
activation_source_clear (self, FALSE, 0);
|
||||
|
||||
priv->ip4_state = priv->ip6_state = IP_NONE;
|
||||
|
||||
iface = nm_device_get_iface (self);
|
||||
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface);
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
|
||||
|
||||
ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason);
|
||||
if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
|
||||
goto out;
|
||||
} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
|
||||
goto out;
|
||||
}
|
||||
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
|
||||
|
||||
nm_device_activate_schedule_stage2_device_config (self);
|
||||
} else
|
||||
nm_device_activate_schedule_stage2_device_config (self);
|
||||
|
||||
out:
|
||||
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 1 of 5 (Device Prepare) complete.", iface);
|
||||
|
|
@ -2043,17 +2111,6 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self)
|
|||
static NMActStageReturn
|
||||
act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
|
||||
GSList *iter;
|
||||
|
||||
/* If we have slaves that aren't yet enslaved, do that now */
|
||||
for (iter = priv->slaves; iter; iter = g_slist_next (iter)) {
|
||||
SlaveInfo *info = iter->data;
|
||||
|
||||
if (nm_device_get_state (info->slave) == NM_DEVICE_STATE_IP_CONFIG)
|
||||
nm_device_enslave_slave (dev, info->slave, nm_device_get_connection (info->slave));
|
||||
}
|
||||
|
||||
/* Nothing to do */
|
||||
return NM_ACT_STAGE_RETURN_SUCCESS;
|
||||
}
|
||||
|
|
@ -2069,10 +2126,13 @@ static gboolean
|
|||
nm_device_activate_stage2_device_config (gpointer user_data)
|
||||
{
|
||||
NMDevice *self = NM_DEVICE (user_data);
|
||||
const char * iface;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
const char *iface;
|
||||
NMActStageReturn ret;
|
||||
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
|
||||
gboolean no_firmware = FALSE;
|
||||
NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
|
||||
GSList *iter;
|
||||
|
||||
/* Clear the activation source ID now that this stage has run */
|
||||
activation_source_clear (self, FALSE, 0);
|
||||
|
|
@ -2081,23 +2141,33 @@ nm_device_activate_stage2_device_config (gpointer user_data)
|
|||
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 2 of 5 (Device Configure) starting...", iface);
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
|
||||
|
||||
if (!nm_device_bring_up (self, FALSE, &no_firmware)) {
|
||||
if (no_firmware)
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING);
|
||||
else
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
|
||||
goto out;
|
||||
/* Assumed connections were already set up outside NetworkManager */
|
||||
if (!nm_active_connection_get_assumed (active)) {
|
||||
if (!nm_device_bring_up (self, FALSE, &no_firmware)) {
|
||||
if (no_firmware)
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING);
|
||||
else
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &reason);
|
||||
if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
|
||||
goto out;
|
||||
else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
|
||||
goto out;
|
||||
}
|
||||
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
|
||||
}
|
||||
|
||||
ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &reason);
|
||||
if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
|
||||
goto out;
|
||||
else if (ret == NM_ACT_STAGE_RETURN_FAILURE)
|
||||
{
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
|
||||
goto out;
|
||||
/* If we have slaves that aren't yet enslaved, do that now */
|
||||
for (iter = priv->slaves; iter; iter = g_slist_next (iter)) {
|
||||
SlaveInfo *info = iter->data;
|
||||
|
||||
if (nm_device_get_state (info->slave) == NM_DEVICE_STATE_IP_CONFIG)
|
||||
nm_device_enslave_slave (self, info->slave, nm_device_get_connection (info->slave));
|
||||
}
|
||||
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
|
||||
|
||||
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 2 of 5 (Device Configure) successful.", iface);
|
||||
|
||||
|
|
@ -3602,7 +3672,6 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
|
|||
NMDevice *self = NM_DEVICE (user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
const char *iface;
|
||||
int ifindex;
|
||||
NMActiveConnection *master;
|
||||
NMDevice *master_device;
|
||||
|
||||
|
|
@ -3615,10 +3684,11 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
|
|||
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 3 of 5 (IP Configure Start) started...", iface);
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
|
||||
|
||||
/* Make sure the interface is up before trying to do anything with it */
|
||||
ifindex = nm_device_get_ip_ifindex (self);
|
||||
if (ifindex && !nm_platform_link_is_up (ifindex))
|
||||
nm_platform_link_set_up (ifindex);
|
||||
/* Device should be up before we can do anything with it */
|
||||
if (!nm_platform_link_is_up (nm_device_get_ip_ifindex (self))) {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s): interface %s not up for IP configuration",
|
||||
iface, nm_device_get_ip_iface (self));
|
||||
}
|
||||
|
||||
/* If the device is a slave, then we don't do any IP configuration but we
|
||||
* use the IP config stage to indicate to the master we're ready for
|
||||
|
|
@ -4009,7 +4079,6 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
|
|||
const char *iface, *method;
|
||||
NMConnection *connection;
|
||||
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
|
||||
int ifindex;
|
||||
|
||||
/* Clear the activation source ID now that this stage has run */
|
||||
activation_source_clear (self, FALSE, AF_INET);
|
||||
|
|
@ -4023,10 +4092,11 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
|
|||
connection = nm_act_request_get_connection (req);
|
||||
g_assert (connection);
|
||||
|
||||
/* Make sure the interface is up again just because */
|
||||
ifindex = nm_device_get_ip_ifindex (self);
|
||||
if (ifindex && !nm_platform_link_is_up (ifindex))
|
||||
nm_platform_link_set_up (ifindex);
|
||||
/* Device should be up before we can do anything with it */
|
||||
if (!nm_platform_link_is_up (nm_device_get_ip_ifindex (self))) {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s): interface %s not up for IP configuration",
|
||||
iface, nm_device_get_ip_iface (self));
|
||||
}
|
||||
|
||||
/* NULL to use the existing priv->dev_ip4_config */
|
||||
if (!ip4_config_merge_and_apply (self, NULL, TRUE, &reason)) {
|
||||
|
|
@ -4102,7 +4172,6 @@ nm_device_activate_ip6_config_commit (gpointer user_data)
|
|||
const char *iface;
|
||||
NMConnection *connection;
|
||||
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
|
||||
int ifindex;
|
||||
|
||||
/* Clear the activation source ID now that this stage has run */
|
||||
activation_source_clear (self, FALSE, AF_INET6);
|
||||
|
|
@ -4116,10 +4185,8 @@ nm_device_activate_ip6_config_commit (gpointer user_data)
|
|||
connection = nm_act_request_get_connection (req);
|
||||
g_assert (connection);
|
||||
|
||||
/* Make sure the interface is up again just because */
|
||||
ifindex = nm_device_get_ip_ifindex (self);
|
||||
if (ifindex && !nm_platform_link_is_up (ifindex))
|
||||
nm_platform_link_set_up (ifindex);
|
||||
/* Device should be up before we can do anything with it */
|
||||
g_warn_if_fail (nm_platform_link_is_up (nm_device_get_ip_ifindex (self)));
|
||||
|
||||
/* Allow setting MTU etc */
|
||||
if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
|
||||
|
|
@ -4571,28 +4638,17 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
|
|||
NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
||||
}
|
||||
|
||||
g_assert (nm_device_connection_is_available (self, connection));
|
||||
|
||||
priv->act_request = g_object_ref (req);
|
||||
g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
|
||||
|
||||
if (priv->state_reason == NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) {
|
||||
/* If it's an assumed connection, let the device subclass short-circuit
|
||||
* the normal connection process and just copy its IP configs from the
|
||||
* interface.
|
||||
*/
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
|
||||
nm_device_activate_schedule_stage3_ip_config_start (self);
|
||||
} else {
|
||||
/* HACK: update the state a bit early to avoid a race between the
|
||||
* scheduled stage1 handler and nm_policy_device_change_check() thinking
|
||||
* that the activation request isn't deferred because the deferred bit
|
||||
* gets cleared a bit too early, when the connection becomes valid.
|
||||
*/
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
|
||||
/* HACK: update the state a bit early to avoid a race between the
|
||||
* scheduled stage1 handler and nm_policy_device_change_check() thinking
|
||||
* that the activation request isn't deferred because the deferred bit
|
||||
* gets cleared a bit too early, when the connection becomes valid.
|
||||
*/
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
|
||||
|
||||
nm_device_activate_schedule_stage1_device_prepare (self);
|
||||
}
|
||||
nm_device_activate_schedule_stage1_device_prepare (self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -6339,8 +6395,107 @@ nm_device_get_state (NMDevice *device)
|
|||
return NM_DEVICE_GET_PRIVATE (device)->state;
|
||||
}
|
||||
|
||||
static NMIP4Config *
|
||||
find_ip4_lease_config (NMDevice *device,
|
||||
NMConnection *connection,
|
||||
NMIP4Config *ext_ip4_config)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
const char *ip_iface = nm_device_get_ip_iface (device);
|
||||
GSList *leases, *liter;
|
||||
NMIP4Config *found = NULL;
|
||||
|
||||
g_return_val_if_fail (NM_IS_IP4_CONFIG (ext_ip4_config), NULL);
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
||||
|
||||
leases = nm_dhcp_manager_get_lease_ip_configs (priv->dhcp_manager,
|
||||
ip_iface,
|
||||
nm_connection_get_uuid (connection),
|
||||
FALSE);
|
||||
for (liter = leases; liter && !found; liter = liter->next) {
|
||||
NMIP4Config *lease_config = liter->data;
|
||||
const NMPlatformIP4Address *address = nm_ip4_config_get_address (lease_config, 0);
|
||||
guint32 gateway = nm_ip4_config_get_gateway (lease_config);
|
||||
|
||||
g_assert (address);
|
||||
if (!nm_ip4_config_address_exists (ext_ip4_config, address))
|
||||
continue;
|
||||
if (gateway != nm_ip4_config_get_gateway (ext_ip4_config))
|
||||
continue;
|
||||
found = g_object_ref (lease_config);
|
||||
}
|
||||
|
||||
g_slist_free_full (leases, g_object_unref);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
update_ip_config (NMDevice *self)
|
||||
capture_lease_config (NMDevice *device,
|
||||
NMIP4Config *ext_ip4_config,
|
||||
NMIP4Config **out_ip4_config,
|
||||
NMIP6Config *ext_ip6_config,
|
||||
NMIP6Config **out_ip6_config)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
const GSList *connections, *citer;
|
||||
guint i;
|
||||
gboolean dhcp_used = FALSE;
|
||||
|
||||
/* Ensure at least one address on the device has a non-infinite lifetime,
|
||||
* otherwise DHCP cannot possibly be active on the device right now.
|
||||
*/
|
||||
if (ext_ip4_config && out_ip4_config) {
|
||||
for (i = 0; i < nm_ip4_config_get_num_addresses (ext_ip4_config); i++) {
|
||||
const NMPlatformIP4Address *addr = nm_ip4_config_get_address (ext_ip4_config, i);
|
||||
|
||||
if (addr->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) {
|
||||
dhcp_used = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (ext_ip6_config && out_ip6_config) {
|
||||
for (i = 0; i < nm_ip6_config_get_num_addresses (ext_ip6_config); i++) {
|
||||
const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ext_ip6_config, i);
|
||||
|
||||
if (addr->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) {
|
||||
dhcp_used = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g_return_if_fail ( (ext_ip6_config && out_ip6_config)
|
||||
|| (ext_ip4_config && out_ip4_config));
|
||||
}
|
||||
|
||||
if (!dhcp_used)
|
||||
return;
|
||||
|
||||
connections = nm_connection_provider_get_connections (priv->con_provider);
|
||||
for (citer = connections; citer; citer = citer->next) {
|
||||
NMConnection *candidate = citer->data;
|
||||
const char *method;
|
||||
|
||||
if (!nm_device_check_connection_compatible (device, candidate, NULL))
|
||||
continue;
|
||||
|
||||
/* IPv4 leases */
|
||||
method = nm_utils_get_ip_config_method (candidate, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if (out_ip4_config && strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) {
|
||||
*out_ip4_config = find_ip4_lease_config (device, candidate, ext_ip4_config);
|
||||
if (*out_ip4_config)
|
||||
return;
|
||||
}
|
||||
|
||||
/* IPv6 leases */
|
||||
method = nm_utils_get_ip_config_method (candidate, NM_TYPE_SETTING_IP6_CONFIG);
|
||||
if (out_ip6_config && strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
|
||||
/* FIXME: implement find_ip6_lease_config() */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_ip_config (NMDevice *self, gboolean capture_dhcp)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
int ifindex;
|
||||
|
|
@ -6353,7 +6508,12 @@ update_ip_config (NMDevice *self)
|
|||
/* IPv4 */
|
||||
g_clear_object (&priv->ext_ip4_config);
|
||||
priv->ext_ip4_config = nm_ip4_config_capture (ifindex);
|
||||
|
||||
if (priv->ext_ip4_config) {
|
||||
if (capture_dhcp) {
|
||||
g_clear_object (&priv->dev_ip4_config);
|
||||
capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL);
|
||||
}
|
||||
if (priv->dev_ip4_config)
|
||||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config);
|
||||
if (priv->vpn4_config)
|
||||
|
|
@ -6389,6 +6549,12 @@ update_ip_config (NMDevice *self)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_capture_initial_config (NMDevice *dev)
|
||||
{
|
||||
update_ip_config (dev, TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
queued_ip_config_change (gpointer user_data)
|
||||
{
|
||||
|
|
@ -6400,7 +6566,7 @@ queued_ip_config_change (gpointer user_data)
|
|||
return TRUE;
|
||||
|
||||
priv->queued_ip_config_id = 0;
|
||||
update_ip_config (self);
|
||||
update_ip_config (self, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -6562,125 +6728,6 @@ spec_match_list (NMDevice *device, const GSList *specs)
|
|||
return matched;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_match_config (NMDevice *self, NMConnection *connection)
|
||||
{
|
||||
NMSettingIP4Config *s_ip4;
|
||||
int i, num;
|
||||
GSList *leases, *iter;
|
||||
NMDHCPManager *dhcp_mgr;
|
||||
const char *method;
|
||||
|
||||
/* Get any saved leases that apply to this connection */
|
||||
dhcp_mgr = nm_dhcp_manager_get ();
|
||||
leases = nm_dhcp_manager_get_lease_config (dhcp_mgr,
|
||||
nm_device_get_iface (self),
|
||||
nm_connection_get_uuid (connection),
|
||||
FALSE);
|
||||
g_object_unref (dhcp_mgr);
|
||||
|
||||
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
|
||||
gboolean found = FALSE;
|
||||
|
||||
/* Find at least one lease's address on the device */
|
||||
for (iter = leases; iter; iter = g_slist_next (iter)) {
|
||||
NMIP4Config *ip4_config = iter->data;
|
||||
const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
|
||||
if (address && nm_platform_ip4_address_exists (nm_device_get_ip_ifindex (self),
|
||||
address->address,
|
||||
address->plen)) {
|
||||
found = TRUE; /* Yay, device has same address as a lease */
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_slist_free_full (leases, g_object_unref);
|
||||
return found;
|
||||
} else {
|
||||
/* Maybe the connection used to be DHCP and there are stale leases; ignore them */
|
||||
g_slist_free_full (leases, g_object_unref);
|
||||
}
|
||||
|
||||
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
|
||||
// FIXME: Enforce no ipv4 addresses?
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* 'shared' and 'link-local' aren't supported methods because 'shared'
|
||||
* requires too much iptables and dnsmasq state to be reclaimed, and
|
||||
* avahi-autoipd isn't smart enough to allow the link-local address to be
|
||||
* determined at any point other than when it was first assigned.
|
||||
*/
|
||||
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
|
||||
return FALSE;
|
||||
|
||||
/* Everything below for static addressing */
|
||||
|
||||
/* Find all IP4 addresses of this connection on the device */
|
||||
s_ip4 = nm_connection_get_setting_ip4_config (connection);
|
||||
if (s_ip4) {
|
||||
num = nm_setting_ip4_config_get_num_addresses (s_ip4);
|
||||
for (i = 0; i < num; i++) {
|
||||
NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i);
|
||||
|
||||
if (!nm_platform_ip4_address_exists (nm_device_get_ip_ifindex (self),
|
||||
nm_ip4_address_get_address (addr),
|
||||
nm_ip4_address_get_prefix (addr)))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Success; all the connection's static IP addresses are assigned to the device */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_find_assumable_connection:
|
||||
* @device: an #NMDevice
|
||||
* @connections: (element-type NMConnection): a list of connections
|
||||
*
|
||||
* Searches @connections for one that matches the currently-configured
|
||||
* state of @device (in both L2 and L3 configuration). That is, it
|
||||
* looks for the connection such that if you activated that connection
|
||||
* on @device, it would result in @device having the configuration
|
||||
* that it has now. This is used at startup to attempt to match
|
||||
* already-active devices with corresponding #NMConnections.
|
||||
*
|
||||
* Some device types (eg, Wi-Fi) and subtypes (eg, PPPoE) can't be
|
||||
* matched reliably, so this will always fail for those devices.
|
||||
*
|
||||
* Returns: (transfer none): an #NMConnection that matches @device's
|
||||
* current state, or %NULL if none match.
|
||||
*/
|
||||
NMConnection *
|
||||
nm_device_find_assumable_connection (NMDevice *device, const GSList *connections)
|
||||
{
|
||||
const GSList *iter;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
|
||||
|
||||
if (!NM_DEVICE_GET_CLASS (device)->match_l2_config)
|
||||
return NULL;
|
||||
|
||||
for (iter = connections; iter; iter = iter->next) {
|
||||
NMConnection *candidate = NM_CONNECTION (iter->data);
|
||||
|
||||
if (!nm_device_check_connection_compatible (device, candidate, NULL))
|
||||
continue;
|
||||
|
||||
if (!ip4_match_config (device, candidate))
|
||||
continue;
|
||||
|
||||
/* FIXME: match IPv6 config */
|
||||
|
||||
if (NM_DEVICE_GET_CLASS (device)->match_l2_config (device, candidate))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -180,28 +180,13 @@ typedef struct {
|
|||
|
||||
gboolean (* spec_match_list) (NMDevice *self, const GSList *specs);
|
||||
|
||||
/* FIXME: We currently support match_l2_config() virtual function for
|
||||
* compatibility. When match_l2_config() is not present, we use the
|
||||
* new update_connection() virtual function which should first call
|
||||
* NMDevice's implementation and then perform type-specific adjustments.
|
||||
*
|
||||
* Therefore subclasses that implement the new API *must* leave
|
||||
* match_l2_config set to NULL and implement update_connection, while
|
||||
* subclasses that implement the old API *must* set match_l2_config
|
||||
* (update_connection is ignored).
|
||||
*
|
||||
* Subclasses which don't implement any of the APIs for connection assumption
|
||||
* *should* leave generate_connection NULL.
|
||||
*
|
||||
* The update_connection() virtual function is also used for live
|
||||
* reconfiguration of the connection according to link level changes.
|
||||
*/
|
||||
gboolean (* match_l2_config) (NMDevice *self, NMConnection *connection);
|
||||
/* Update the connection with currently configured L2 settings */
|
||||
void (* update_connection) (NMDevice *device, NMConnection *connection);
|
||||
|
||||
gboolean (* enslave_slave) (NMDevice *self,
|
||||
NMDevice *slave,
|
||||
NMConnection *connection);
|
||||
NMConnection *connection,
|
||||
gboolean configure);
|
||||
|
||||
gboolean (* release_slave) (NMDevice *self,
|
||||
NMDevice *slave);
|
||||
|
|
@ -246,8 +231,10 @@ void nm_device_set_vpn4_config (NMDevice *dev, NMIP4Config *config)
|
|||
NMIP6Config * nm_device_get_ip6_config (NMDevice *dev);
|
||||
void nm_device_set_vpn6_config (NMDevice *dev, NMIP6Config *config);
|
||||
|
||||
void nm_device_capture_initial_config (NMDevice *dev);
|
||||
|
||||
/* Master */
|
||||
gboolean nm_device_master_add_slave (NMDevice *dev, NMDevice *slave);
|
||||
gboolean nm_device_master_add_slave (NMDevice *dev, NMDevice *slave, gboolean configure);
|
||||
GSList * nm_device_master_get_slaves (NMDevice *dev);
|
||||
gboolean nm_device_is_master (NMDevice *dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#include "nm-dhcp-dhclient-utils.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
#define CLIENTID_TAG "send dhcp-client-identifier"
|
||||
#define CLIENTID_FORMAT CLIENTID_TAG " \"%s\"; # added by NetworkManager"
|
||||
|
|
@ -424,3 +426,234 @@ nm_dhcp_dhclient_save_duid (const char *leasefile,
|
|||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
add_lease_option (GHashTable *hash, char *line)
|
||||
{
|
||||
char *spc;
|
||||
size_t len;
|
||||
|
||||
/* Find the space after "option" */
|
||||
spc = strchr (line, ' ');
|
||||
if (!spc)
|
||||
return;
|
||||
|
||||
/* Find the option tag's data, which is after the second space */
|
||||
if (g_str_has_prefix (line, "option ")) {
|
||||
while (g_ascii_isspace (*spc))
|
||||
spc++;
|
||||
spc = strchr (spc + 1, ' ');
|
||||
if (!spc)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Split the line at the space */
|
||||
*spc = '\0';
|
||||
spc++;
|
||||
|
||||
/* Kill the ';' at the end of the line, if any */
|
||||
len = strlen (spc);
|
||||
if (*(spc + len - 1) == ';')
|
||||
*(spc + len - 1) = '\0';
|
||||
|
||||
/* Strip leading quote */
|
||||
while (g_ascii_isspace (*spc))
|
||||
spc++;
|
||||
if (*spc == '"')
|
||||
spc++;
|
||||
|
||||
/* Strip trailing quote */
|
||||
len = strlen (spc);
|
||||
if (len > 0 && spc[len - 1] == '"')
|
||||
spc[len - 1] = '\0';
|
||||
|
||||
if (spc[0])
|
||||
g_hash_table_insert (hash, g_strdup (line), g_strdup (spc));
|
||||
}
|
||||
|
||||
#define LEASE_INVALID G_MININT64
|
||||
static GTimeSpan
|
||||
lease_validity_span (const char *str_expire, GDateTime *now)
|
||||
{
|
||||
GDateTime *expire = NULL;
|
||||
struct tm expire_tm;
|
||||
GTimeSpan span;
|
||||
|
||||
g_return_val_if_fail (now != NULL, LEASE_INVALID);
|
||||
g_return_val_if_fail (str_expire != NULL, LEASE_INVALID);
|
||||
|
||||
/* Skip initial number (day of week?) */
|
||||
if (!isdigit (*str_expire++))
|
||||
return LEASE_INVALID;
|
||||
if (!isspace (*str_expire++))
|
||||
return LEASE_INVALID;
|
||||
/* Read lease expiration (in UTC) */
|
||||
if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm))
|
||||
return LEASE_INVALID;
|
||||
|
||||
expire = g_date_time_new_utc (expire_tm.tm_year + 1900,
|
||||
expire_tm.tm_mon + 1,
|
||||
expire_tm.tm_mday,
|
||||
expire_tm.tm_hour,
|
||||
expire_tm.tm_min,
|
||||
expire_tm.tm_sec);
|
||||
if (!expire)
|
||||
return LEASE_INVALID;
|
||||
|
||||
span = g_date_time_difference (expire, now);
|
||||
g_date_time_unref (expire);
|
||||
|
||||
/* GDateTime only supports a range of less then 10000 years, so span can
|
||||
* not overflow or be equal to LEASE_INVALID */
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_dhcp_dhclient_read_lease_ip_configs:
|
||||
* @iface: the interface name to match leases with
|
||||
* @contents: the contents of a dhclient leasefile
|
||||
* @ipv6: whether to read IPv4 or IPv6 leases
|
||||
* @now: the current UTC date/time; pass %NULL to automatically use current
|
||||
* UTC time. Testcases may need a different value for 'now'
|
||||
*
|
||||
* Reads dhclient leases from @contents and parses them into either
|
||||
* #NMIP4Config or #NMIP6Config objects depending on the value of @ipv6.
|
||||
*
|
||||
* Returns: a #GSList of #NMIP4Config objects (if @ipv6 is %FALSE) or a list of
|
||||
* #NMIP6Config objects (if @ipv6 is %TRUE) containing the lease data.
|
||||
*/
|
||||
GSList *
|
||||
nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
|
||||
const char *contents,
|
||||
gboolean ipv6,
|
||||
GDateTime *now)
|
||||
{
|
||||
GSList *parsed = NULL, *iter, *leases = NULL;
|
||||
char **line, **split = NULL;
|
||||
GHashTable *hash = NULL;
|
||||
|
||||
g_return_val_if_fail (contents != NULL, NULL);
|
||||
|
||||
split = g_strsplit_set (contents, "\n\r", -1);
|
||||
if (!split)
|
||||
return NULL;
|
||||
|
||||
for (line = split; line && *line; line++) {
|
||||
*line = g_strstrip (*line);
|
||||
|
||||
if (*line[0] == '#') {
|
||||
/* Comment */
|
||||
} else if (!strcmp (*line, "}")) {
|
||||
/* Lease ends */
|
||||
parsed = g_slist_append (parsed, hash);
|
||||
hash = NULL;
|
||||
} else if (!strcmp (*line, "lease {")) {
|
||||
/* Beginning of a new lease */
|
||||
if (hash) {
|
||||
/* Ignore malformed lease that doesn't end before new one starts */
|
||||
g_hash_table_destroy (hash);
|
||||
}
|
||||
|
||||
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
} else if (hash && strlen (*line))
|
||||
add_lease_option (hash, *line);
|
||||
}
|
||||
g_strfreev (split);
|
||||
|
||||
/* Check if the last lease in the file was properly ended */
|
||||
if (hash) {
|
||||
/* Ignore malformed lease that doesn't end before new one starts */
|
||||
g_hash_table_destroy (hash);
|
||||
hash = NULL;
|
||||
}
|
||||
|
||||
if (now)
|
||||
g_date_time_ref (now);
|
||||
else
|
||||
now = g_date_time_new_now_utc ();
|
||||
|
||||
for (iter = parsed; iter; iter = g_slist_next (iter)) {
|
||||
NMIP4Config *ip4;
|
||||
NMPlatformIP4Address address;
|
||||
const char *value;
|
||||
GTimeSpan expiry;
|
||||
guint32 tmp, gw = 0;
|
||||
|
||||
hash = iter->data;
|
||||
|
||||
/* Make sure this lease is for the interface we want */
|
||||
value = g_hash_table_lookup (hash, "interface");
|
||||
if (!value || strcmp (value, iface))
|
||||
continue;
|
||||
|
||||
value = g_hash_table_lookup (hash, "expire");
|
||||
if (!value)
|
||||
continue;
|
||||
expiry = lease_validity_span (value, now);
|
||||
if (expiry == LEASE_INVALID)
|
||||
continue;
|
||||
|
||||
/* scale expiry to seconds (and CLAMP into the range of guint32) */
|
||||
expiry = CLAMP (expiry / G_TIME_SPAN_SECOND, 0, G_MAXUINT32-1);
|
||||
if (expiry <= 0) {
|
||||
/* the address is already expired. Don't even add it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
|
||||
/* IP4 address */
|
||||
value = g_hash_table_lookup (hash, "fixed-address");
|
||||
if (!value)
|
||||
continue;
|
||||
if (!inet_pton (AF_INET, value, &address.address))
|
||||
continue;
|
||||
|
||||
/* Gateway */
|
||||
value = g_hash_table_lookup (hash, "option routers");
|
||||
if (!value)
|
||||
continue;
|
||||
if (!inet_pton (AF_INET, value, &gw))
|
||||
continue;
|
||||
|
||||
/* Netmask */
|
||||
value = g_hash_table_lookup (hash, "option subnet-mask");
|
||||
if (value && inet_pton (AF_INET, value, &tmp))
|
||||
address.plen = nm_utils_ip4_netmask_to_prefix (tmp);
|
||||
|
||||
/* Get default netmask for the IP according to appropriate class. */
|
||||
if (!address.plen)
|
||||
address.plen = nm_utils_ip4_get_default_prefix (address.address);
|
||||
|
||||
address.lifetime = address.preferred = expiry;
|
||||
|
||||
ip4 = nm_ip4_config_new ();
|
||||
nm_ip4_config_add_address (ip4, &address);
|
||||
nm_ip4_config_set_gateway (ip4, gw);
|
||||
|
||||
value = g_hash_table_lookup (hash, "option domain-name-servers");
|
||||
if (value) {
|
||||
char **dns, **dns_iter;
|
||||
|
||||
dns = g_strsplit_set (value, ",", -1);
|
||||
for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) {
|
||||
if (inet_pton (AF_INET, *dns_iter, &tmp))
|
||||
nm_ip4_config_add_nameserver (ip4, tmp);
|
||||
}
|
||||
if (dns)
|
||||
g_strfreev (dns);
|
||||
}
|
||||
|
||||
value = g_hash_table_lookup (hash, "option domain-name");
|
||||
if (value && value[0])
|
||||
nm_ip4_config_add_domain (ip4, value);
|
||||
|
||||
/* FIXME: static routes */
|
||||
|
||||
leases = g_slist_append (leases, ip4);
|
||||
}
|
||||
|
||||
g_date_time_unref (now);
|
||||
g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy);
|
||||
return leases;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,5 +44,10 @@ gboolean nm_dhcp_dhclient_save_duid (const char *leasefile,
|
|||
const char *escaped_duid,
|
||||
GError **error);
|
||||
|
||||
GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
|
||||
const char *contents,
|
||||
gboolean ipv6,
|
||||
GDateTime *now);
|
||||
|
||||
#endif /* NM_DHCP_DHCLIENT_UTILS_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <config.h>
|
||||
|
||||
|
|
@ -135,215 +136,31 @@ get_dhclient_leasefile (const char *iface,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
add_lease_option (GHashTable *hash, char *line)
|
||||
{
|
||||
char *spc;
|
||||
|
||||
spc = strchr (line, ' ');
|
||||
if (!spc) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file line '%s' did not contain a space", line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it's an 'option' line, split at second space */
|
||||
if (g_str_has_prefix (line, "option ")) {
|
||||
spc = strchr (spc + 1, ' ');
|
||||
if (!spc) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file option line '%s' did not contain a second space",
|
||||
line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Split the line at the space */
|
||||
*spc = '\0';
|
||||
spc++;
|
||||
|
||||
/* Kill the ';' at the end of the line, if any */
|
||||
if (*(spc + strlen (spc) - 1) == ';')
|
||||
*(spc + strlen (spc) - 1) = '\0';
|
||||
|
||||
/* Treat 'interface' specially */
|
||||
if (g_str_has_prefix (line, "interface")) {
|
||||
if (*(spc) == '"')
|
||||
spc++; /* Jump past the " */
|
||||
if (*(spc + strlen (spc) - 1) == '"')
|
||||
*(spc + strlen (spc) - 1) = '\0'; /* Kill trailing " */
|
||||
}
|
||||
|
||||
g_hash_table_insert (hash, g_strdup (line), g_strdup (spc));
|
||||
}
|
||||
|
||||
GSList *
|
||||
nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid, gboolean ipv6)
|
||||
nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
{
|
||||
GSList *parsed = NULL, *iter, *leases = NULL;
|
||||
char *contents = NULL;
|
||||
char *leasefile;
|
||||
char **line, **split = NULL;
|
||||
GHashTable *hash = NULL;
|
||||
|
||||
/* IPv6 not supported */
|
||||
if (ipv6)
|
||||
return NULL;
|
||||
GSList *leases = NULL;
|
||||
|
||||
leasefile = get_dhclient_leasefile (iface, uuid, FALSE, NULL);
|
||||
if (!leasefile)
|
||||
return NULL;
|
||||
|
||||
if (!g_file_test (leasefile, G_FILE_TEST_EXISTS))
|
||||
goto out;
|
||||
if ( g_file_test (leasefile, G_FILE_TEST_EXISTS)
|
||||
&& g_file_get_contents (leasefile, &contents, NULL, NULL)
|
||||
&& contents
|
||||
&& contents[0])
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, contents, ipv6, NULL);
|
||||
|
||||
if (!g_file_get_contents (leasefile, &contents, NULL, NULL))
|
||||
goto out;
|
||||
|
||||
split = g_strsplit_set (contents, "\n\r", -1);
|
||||
g_free (contents);
|
||||
if (!split)
|
||||
goto out;
|
||||
|
||||
for (line = split; line && *line; line++) {
|
||||
*line = g_strstrip (*line);
|
||||
|
||||
if (!strcmp (*line, "}")) {
|
||||
/* Lease ends */
|
||||
parsed = g_slist_append (parsed, hash);
|
||||
hash = NULL;
|
||||
} else if (!strcmp (*line, "lease {")) {
|
||||
/* Beginning of a new lease */
|
||||
if (hash) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file %s malformed; new lease started "
|
||||
"without ending previous lease",
|
||||
leasefile);
|
||||
g_hash_table_destroy (hash);
|
||||
}
|
||||
|
||||
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
} else if (strlen (*line))
|
||||
add_lease_option (hash, *line);
|
||||
}
|
||||
g_strfreev (split);
|
||||
|
||||
/* Check if the last lease in the file was properly ended */
|
||||
if (hash) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file %s malformed; new lease started "
|
||||
"without ending previous lease",
|
||||
leasefile);
|
||||
g_hash_table_destroy (hash);
|
||||
hash = NULL;
|
||||
}
|
||||
|
||||
for (iter = parsed; iter; iter = g_slist_next (iter)) {
|
||||
NMIP4Config *ip4;
|
||||
NMPlatformIP4Address address;
|
||||
const char *data;
|
||||
guint32 tmp;
|
||||
guint32 plen;
|
||||
struct tm expire;
|
||||
|
||||
hash = iter->data;
|
||||
|
||||
/* Make sure this lease is for the interface we want */
|
||||
data = g_hash_table_lookup (hash, "interface");
|
||||
if (!data || strcmp (data, iface))
|
||||
continue;
|
||||
|
||||
data = g_hash_table_lookup (hash, "expire");
|
||||
if (data) {
|
||||
time_t now_tt;
|
||||
struct tm *now;
|
||||
|
||||
/* Read lease expiration (in UTC) */
|
||||
if (!strptime (data, "%w %Y/%m/%d %H:%M:%S", &expire)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file expire time '%s'",
|
||||
data);
|
||||
continue;
|
||||
}
|
||||
|
||||
now_tt = time (NULL);
|
||||
now = gmtime(&now_tt);
|
||||
|
||||
/* Ignore this lease if it's already expired */
|
||||
if (expire.tm_year < now->tm_year)
|
||||
continue;
|
||||
else if (expire.tm_year == now->tm_year) {
|
||||
if (expire.tm_mon < now->tm_mon)
|
||||
continue;
|
||||
else if (expire.tm_mon == now->tm_mon) {
|
||||
if (expire.tm_mday < now->tm_mday)
|
||||
continue;
|
||||
else if (expire.tm_mday == now->tm_mday) {
|
||||
if (expire.tm_hour < now->tm_hour)
|
||||
continue;
|
||||
else if (expire.tm_hour == now->tm_hour) {
|
||||
if (expire.tm_min < now->tm_min)
|
||||
continue;
|
||||
else if (expire.tm_min == now->tm_min) {
|
||||
if (expire.tm_sec <= now->tm_sec)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If we get this far, the lease hasn't expired */
|
||||
}
|
||||
|
||||
data = g_hash_table_lookup (hash, "fixed-address");
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
ip4 = nm_ip4_config_new ();
|
||||
memset (&address, 0, sizeof (address));
|
||||
|
||||
/* IP4 address */
|
||||
if (!inet_pton (AF_INET, data, &tmp)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 address '%s'", data);
|
||||
goto error;
|
||||
}
|
||||
address.address = tmp;
|
||||
|
||||
/* Netmask */
|
||||
data = g_hash_table_lookup (hash, "option subnet-mask");
|
||||
if (data) {
|
||||
if (!inet_pton (AF_INET, data, &tmp)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 subnet mask '%s'", data);
|
||||
goto error;
|
||||
}
|
||||
plen = nm_utils_ip4_netmask_to_prefix (tmp);
|
||||
} else {
|
||||
/* Get default netmask for the IP according to appropriate class. */
|
||||
plen = nm_utils_ip4_get_default_prefix (address.address);
|
||||
}
|
||||
address.plen = plen;
|
||||
|
||||
/* Gateway */
|
||||
data = g_hash_table_lookup (hash, "option routers");
|
||||
if (data) {
|
||||
if (!inet_pton (AF_INET, data, &tmp)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 gateway '%s'", data);
|
||||
goto error;
|
||||
}
|
||||
nm_ip4_config_set_gateway (ip4, tmp);
|
||||
}
|
||||
|
||||
nm_ip4_config_add_address (ip4, &address);
|
||||
leases = g_slist_append (leases, ip4);
|
||||
continue;
|
||||
|
||||
error:
|
||||
g_object_unref (ip4);
|
||||
}
|
||||
|
||||
out:
|
||||
g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy);
|
||||
g_free (leasefile);
|
||||
g_free (contents);
|
||||
|
||||
return leases;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
merge_dhclient_config (const char *iface,
|
||||
const char *conf_file,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ typedef struct {
|
|||
|
||||
GType nm_dhcp_dhclient_get_type (void);
|
||||
|
||||
GSList *nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid, gboolean ipv6);
|
||||
GSList *nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
|
||||
const char *nm_dhcp_dhclient_get_path (const char *try_first);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,12 +71,6 @@ nm_dhcp_dhcpcd_get_path (const char *try_first)
|
|||
return *path;
|
||||
}
|
||||
|
||||
GSList *
|
||||
nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid, gboolean ipv6)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@ typedef struct {
|
|||
|
||||
GType nm_dhcp_dhcpcd_get_type (void);
|
||||
|
||||
GSList *nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid, gboolean ipv6);
|
||||
|
||||
const char *nm_dhcp_dhcpcd_get_path (const char *try_first);
|
||||
|
||||
#endif /* NM_DHCP_DHCPCD_H */
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ typedef GSList * (*GetLeaseConfigFunc) (const char *iface, const char *uuid, gbo
|
|||
|
||||
typedef struct {
|
||||
GType client_type;
|
||||
GetLeaseConfigFunc get_lease_config_func;
|
||||
GetLeaseConfigFunc get_lease_ip_configs_func;
|
||||
|
||||
NMDBusManager * dbus_mgr;
|
||||
guint new_conn_id;
|
||||
|
|
@ -313,7 +313,7 @@ get_client_type (const char *client, GError **error)
|
|||
g_set_error_literal (error,
|
||||
NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
|
||||
_("no usable DHCP client could be found."));
|
||||
return 0;
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +322,7 @@ get_client_type (const char *client, GError **error)
|
|||
g_set_error_literal (error,
|
||||
NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
|
||||
_("'dhclient' could be found."));
|
||||
return 0;
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
return NM_TYPE_DHCP_DHCLIENT;
|
||||
}
|
||||
|
|
@ -332,7 +332,7 @@ get_client_type (const char *client, GError **error)
|
|||
g_set_error_literal (error,
|
||||
NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
|
||||
_("'dhcpcd' could be found."));
|
||||
return 0;
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
return NM_TYPE_DHCP_DHCPCD;
|
||||
}
|
||||
|
|
@ -340,7 +340,7 @@ get_client_type (const char *client, GError **error)
|
|||
g_set_error (error,
|
||||
NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
|
||||
_("unsupported DHCP client '%s'"), client);
|
||||
return 0;
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
NMDHCPManager *
|
||||
|
|
@ -362,15 +362,14 @@ nm_dhcp_manager_get (void)
|
|||
/* Client-specific setup */
|
||||
client = nm_config_get_dhcp_client (nm_config_get ());
|
||||
priv->client_type = get_client_type (client, &error);
|
||||
|
||||
if (priv->client_type == NM_TYPE_DHCP_DHCLIENT)
|
||||
priv->get_lease_config_func = nm_dhcp_dhclient_get_lease_config;
|
||||
else if (priv->client_type == NM_TYPE_DHCP_DHCPCD)
|
||||
priv->get_lease_config_func = nm_dhcp_dhcpcd_get_lease_config;
|
||||
else {
|
||||
priv->get_lease_ip_configs_func = nm_dhcp_dhclient_get_lease_ip_configs;
|
||||
else if (priv->client_type == G_TYPE_INVALID) {
|
||||
nm_log_warn (LOGD_DHCP, "No usable DHCP client found (%s)! DHCP configurations will fail.",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
|
||||
priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL,
|
||||
|
|
@ -610,10 +609,10 @@ nm_dhcp_manager_set_hostname_provider (NMDHCPManager *manager,
|
|||
}
|
||||
|
||||
GSList *
|
||||
nm_dhcp_manager_get_lease_config (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
{
|
||||
NMDHCPManagerPrivate *priv;
|
||||
|
||||
|
|
@ -623,10 +622,8 @@ nm_dhcp_manager_get_lease_config (NMDHCPManager *self,
|
|||
|
||||
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
if (priv->get_lease_config_func)
|
||||
return priv->get_lease_config_func (iface, uuid, ipv6);
|
||||
|
||||
nm_log_warn (LOGD_DHCP, "Cannot get a DHCP lease config (no usable DHCP client was found!)");
|
||||
if (priv->get_lease_ip_configs_func)
|
||||
return priv->get_lease_ip_configs_func (iface, uuid, ipv6);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,10 +82,10 @@ NMDHCPClient * nm_dhcp_manager_start_ip6 (NMDHCPManager *manager,
|
|||
guint8 *dhcp_anycast_addr,
|
||||
gboolean info_only);
|
||||
|
||||
GSList * nm_dhcp_manager_get_lease_config (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
GSList * nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
|
||||
/* For testing only */
|
||||
NMIP4Config *nm_dhcp_manager_test_ip4_options_to_config (const char *dhcp_client,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ AM_CPPFLAGS = \
|
|||
-I${top_srcdir}/libnm-util \
|
||||
-I${top_builddir}/libnm-util \
|
||||
-I$(top_srcdir)/src/dhcp-manager \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/platform \
|
||||
$(GLIB_CFLAGS) \
|
||||
-DTESTDIR="\"$(abs_srcdir)\""
|
||||
|
||||
|
|
@ -22,5 +24,9 @@ check-local: test-dhcp-dhclient
|
|||
|
||||
EXTRA_DIST = \
|
||||
test-dhclient-duid.leases \
|
||||
test-dhclient-commented-duid.leases
|
||||
test-dhclient-commented-duid.leases \
|
||||
leases/basic.leases \
|
||||
leases/malformed1.leases \
|
||||
leases/malformed2.leases \
|
||||
leases/malformed3.leases
|
||||
|
||||
|
|
|
|||
31
src/dhcp-manager/tests/leases/basic.leases
Normal file
31
src/dhcp-manager/tests/leases/basic.leases
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 192.168.1.180;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option routers 192.168.1.1;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
expire 5 2013/11/01 20:01:59;
|
||||
}
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 10.77.52.141;
|
||||
option subnet-mask 255.0.0.0;
|
||||
option dhcp-lease-time 1200;
|
||||
option routers 10.77.52.254;
|
||||
option dhcp-message-type 5;
|
||||
option dhcp-server-identifier 10.77.52.254;
|
||||
option domain-name-servers 8.8.8.8,8.8.4.4;
|
||||
option dhcp-renewal-time 600;
|
||||
option dhcp-rebinding-time 1050;
|
||||
option domain-name "morriesguest.local";
|
||||
renew 5 2013/11/01 20:01:08;
|
||||
rebind 5 2013/11/01 20:05:00;
|
||||
expire 5 2013/11/01 20:06:15;
|
||||
}
|
||||
|
||||
15
src/dhcp-manager/tests/leases/malformed1.leases
Normal file
15
src/dhcp-manager/tests/leases/malformed1.leases
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# missing fixed-address option
|
||||
lease {
|
||||
interface "wlan0";
|
||||
option subnet-mask 255.255.255.0;
|
||||
option routers 192.168.1.1;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
expire 5 2013/11/01 20:01:59;
|
||||
}
|
||||
|
||||
15
src/dhcp-manager/tests/leases/malformed2.leases
Normal file
15
src/dhcp-manager/tests/leases/malformed2.leases
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# missing routers option
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 192.168.1.180;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
expire 5 2013/11/01 20:01:59;
|
||||
}
|
||||
|
||||
15
src/dhcp-manager/tests/leases/malformed3.leases
Normal file
15
src/dhcp-manager/tests/leases/malformed3.leases
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# missing expire time
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 192.168.1.180;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option routers 192.168.1.1;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
}
|
||||
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "nm-dhcp-dhclient-utils.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-ip4-config.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
|
|
@ -454,6 +455,128 @@ test_write_existing_commented_duid (void)
|
|||
|
||||
/*******************************************/
|
||||
|
||||
static void
|
||||
test_read_lease_ip4_config_basic (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = TESTDIR "/leases/basic.leases";
|
||||
GSList *leases;
|
||||
GDateTime *now;
|
||||
NMIP4Config *config;
|
||||
const NMPlatformIP4Address *addr;
|
||||
guint32 expected_addr;
|
||||
|
||||
success = g_file_get_contents (path, &contents, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* Date from before the least expiration */
|
||||
now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32);
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
|
||||
g_assert_cmpint (g_slist_length (leases), ==, 2);
|
||||
|
||||
/* IP4Config #1 */
|
||||
config = g_slist_nth_data (leases, 0);
|
||||
g_assert (NM_IS_IP4_CONFIG (config));
|
||||
|
||||
/* Address */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1);
|
||||
g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr));
|
||||
addr = nm_ip4_config_get_address (config, 0);
|
||||
g_assert_cmpint (addr->address, ==, expected_addr);
|
||||
g_assert_cmpint (addr->plen, ==, 24);
|
||||
|
||||
/* Gateway */
|
||||
g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr);
|
||||
|
||||
/* DNS */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1);
|
||||
g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr);
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 0);
|
||||
|
||||
/* IP4Config #2 */
|
||||
config = g_slist_nth_data (leases, 1);
|
||||
g_assert (NM_IS_IP4_CONFIG (config));
|
||||
|
||||
/* Address */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1);
|
||||
g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr));
|
||||
addr = nm_ip4_config_get_address (config, 0);
|
||||
g_assert_cmpint (addr->address, ==, expected_addr);
|
||||
g_assert_cmpint (addr->plen, ==, 8);
|
||||
|
||||
/* Gateway */
|
||||
g_assert (inet_aton ("10.77.52.254", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr);
|
||||
|
||||
/* DNS */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2);
|
||||
g_assert (inet_aton ("8.8.8.8", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr);
|
||||
g_assert (inet_aton ("8.8.4.4", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_nameserver (config, 1), ==, expected_addr);
|
||||
|
||||
/* Domains */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 1);
|
||||
g_assert_cmpstr (nm_ip4_config_get_domain (config, 0), ==, "morriesguest.local");
|
||||
|
||||
g_slist_free_full (leases, g_object_unref);
|
||||
g_date_time_unref (now);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_lease_ip4_config_expired (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = TESTDIR "/leases/basic.leases";
|
||||
GSList *leases;
|
||||
GDateTime *now;
|
||||
|
||||
success = g_file_get_contents (path, &contents, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* Date from *after* the lease expiration */
|
||||
now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32);
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
|
||||
g_assert (leases == NULL);
|
||||
|
||||
g_date_time_unref (now);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_lease_ip4_config_expect_failure (gconstpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *contents = NULL;
|
||||
gboolean success;
|
||||
GSList *leases;
|
||||
GDateTime *now;
|
||||
|
||||
success = g_file_get_contents ((const char *) user_data, &contents, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* Date from before the least expiration */
|
||||
now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1);
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
|
||||
g_assert (leases == NULL);
|
||||
|
||||
g_date_time_unref (now);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
|
@ -477,6 +600,18 @@ main (int argc, char **argv)
|
|||
g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid);
|
||||
g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid);
|
||||
|
||||
g_test_add_func ("/dhcp/dhclient/leases/ip4-config/basic", test_read_lease_ip4_config_basic);
|
||||
g_test_add_func ("/dhcp/dhclient/leases/ip4-config/expired", test_read_lease_ip4_config_expired);
|
||||
g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-address",
|
||||
TESTDIR "/leases/malformed1.leases",
|
||||
test_read_lease_ip4_config_expect_failure);
|
||||
g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-gateway",
|
||||
TESTDIR "/leases/malformed2.leases",
|
||||
test_read_lease_ip4_config_expect_failure);
|
||||
g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-expire",
|
||||
TESTDIR "/leases/malformed3.leases",
|
||||
test_read_lease_ip4_config_expect_failure);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ typedef struct {
|
|||
NMActiveConnection *master;
|
||||
gboolean master_ready;
|
||||
|
||||
gboolean assumed;
|
||||
|
||||
NMAuthChain *chain;
|
||||
const char *wifi_shared_permission;
|
||||
NMActiveConnectionAuthResultFunc result_func;
|
||||
|
|
@ -498,6 +500,21 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m
|
|||
check_master_ready (self);
|
||||
}
|
||||
|
||||
void
|
||||
nm_active_connection_set_assumed (NMActiveConnection *self, gboolean assumed)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (priv->assumed == FALSE);
|
||||
priv->assumed = assumed;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_active_connection_get_assumed (NMActiveConnection *self)
|
||||
{
|
||||
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->assumed;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -129,4 +129,9 @@ gboolean nm_active_connection_get_master_ready (NMActiveConnection *self);
|
|||
void nm_active_connection_set_master (NMActiveConnection *self,
|
||||
NMActiveConnection *master);
|
||||
|
||||
void nm_active_connection_set_assumed (NMActiveConnection *self,
|
||||
gboolean assumed);
|
||||
|
||||
gboolean nm_active_connection_get_assumed (NMActiveConnection *self);
|
||||
|
||||
#endif /* NM_ACTIVE_CONNECTION_H */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "nm-connection-provider.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
GSList *
|
||||
nm_connection_provider_get_best_connections (NMConnectionProvider *self,
|
||||
|
|
@ -75,6 +76,25 @@ nm_connection_provider_add_connection (NMConnectionProvider *self,
|
|||
return NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->add_connection (self, connection, save_to_disk, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_connection_provider_get_connection_by_uuid:
|
||||
* @self: the #NMConnectionProvider
|
||||
* @uuid: the UUID to search for
|
||||
*
|
||||
* Returns: the connection with the given @uuid, or %NULL
|
||||
*/
|
||||
NMConnection *
|
||||
nm_connection_provider_get_connection_by_uuid (NMConnectionProvider *self,
|
||||
const char *uuid)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CONNECTION_PROVIDER (self), NULL);
|
||||
g_return_val_if_fail (uuid != NULL, NULL);
|
||||
g_return_val_if_fail (nm_utils_is_uuid (uuid), NULL);
|
||||
|
||||
g_assert (NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->get_connection_by_uuid);
|
||||
return NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->get_connection_by_uuid (self, uuid);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ struct _NMConnectionProvider {
|
|||
gboolean save_to_disk,
|
||||
GError **error);
|
||||
|
||||
NMConnection * (*get_connection_by_uuid) (NMConnectionProvider *self,
|
||||
const char *uuid);
|
||||
|
||||
/* Signals */
|
||||
void (*connection_added) (NMConnectionProvider *self, NMConnection *connection);
|
||||
|
||||
|
|
@ -137,4 +140,7 @@ NMConnection *nm_connection_provider_add_connection (NMConnectionProvider *self,
|
|||
gboolean save_to_disk,
|
||||
GError **error);
|
||||
|
||||
NMConnection *nm_connection_provider_get_connection_by_uuid (NMConnectionProvider *self,
|
||||
const char *uuid);
|
||||
|
||||
#endif /* NM_CONNECTION_PROVIDER_H */
|
||||
|
|
|
|||
|
|
@ -127,18 +127,44 @@ routes_are_duplicate (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b,
|
|||
NMIP4Config *
|
||||
nm_ip4_config_capture (int ifindex)
|
||||
{
|
||||
NMIP4Config *config = nm_ip4_config_new ();
|
||||
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
|
||||
NMIP4Config *config;
|
||||
NMIP4ConfigPrivate *priv;
|
||||
guint i;
|
||||
gboolean gateway_changed = FALSE;
|
||||
|
||||
/* Slaves have no IP configuration */
|
||||
if (nm_platform_link_get_master (ifindex) > 0)
|
||||
return NULL;
|
||||
|
||||
config = nm_ip4_config_new ();
|
||||
priv = NM_IP4_CONFIG_GET_PRIVATE (config);
|
||||
|
||||
g_array_unref (priv->addresses);
|
||||
g_array_unref (priv->routes);
|
||||
|
||||
priv->addresses = nm_platform_ip4_address_get_all (ifindex);
|
||||
priv->routes = nm_platform_ip4_route_get_all (ifindex, FALSE);
|
||||
priv->routes = nm_platform_ip4_route_get_all (ifindex, TRUE);
|
||||
|
||||
/* Extract gateway from default route */
|
||||
for (i = 0; i < priv->routes->len; i++) {
|
||||
const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i);
|
||||
|
||||
if (route->network == 0) {
|
||||
if (priv->gateway != route->gateway) {
|
||||
priv->gateway = route->gateway;
|
||||
gateway_changed = TRUE;
|
||||
}
|
||||
/* Remove the default route from the list */
|
||||
g_array_remove_index (priv->routes, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* actually, nobody should be connected to the signal, just to be sure, notify */
|
||||
_NOTIFY (config, PROP_ADDRESSES);
|
||||
_NOTIFY (config, PROP_ROUTES);
|
||||
if (gateway_changed)
|
||||
_NOTIFY (config, PROP_GATEWAY);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
|
@ -314,9 +340,12 @@ nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *set
|
|||
nm_setting_ip4_config_add_address (setting, s_addr);
|
||||
nm_ip4_address_unref (s_addr);
|
||||
}
|
||||
if (!method)
|
||||
|
||||
/* Only use 'disabled' if the method wasn't previously set */
|
||||
if (!method && !nm_setting_ip4_config_get_method (setting))
|
||||
method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
|
||||
g_object_set (setting, NM_SETTING_IP4_CONFIG_METHOD, method, NULL);
|
||||
if (method)
|
||||
g_object_set (setting, NM_SETTING_IP4_CONFIG_METHOD, method, NULL);
|
||||
|
||||
/* Routes */
|
||||
for (i = 0; i < nroutes; i++) {
|
||||
|
|
@ -955,6 +984,22 @@ nm_ip4_config_get_address (const NMIP4Config *config, guint i)
|
|||
return &g_array_index (priv->addresses, NMPlatformIP4Address, i);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ip4_config_address_exists (const NMIP4Config *config,
|
||||
const NMPlatformIP4Address *needle)
|
||||
{
|
||||
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < priv->addresses->len; i++) {
|
||||
const NMPlatformIP4Address *haystack = &g_array_index (priv->addresses, NMPlatformIP4Address, i);
|
||||
|
||||
if (needle->address == haystack->address && needle->plen == haystack->plen)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ void nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address
|
|||
void nm_ip4_config_del_address (NMIP4Config *config, guint i);
|
||||
guint nm_ip4_config_get_num_addresses (const NMIP4Config *config);
|
||||
const NMPlatformIP4Address *nm_ip4_config_get_address (const NMIP4Config *config, guint i);
|
||||
gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *address);
|
||||
|
||||
/* Routes */
|
||||
void nm_ip4_config_reset_routes (NMIP4Config *config);
|
||||
|
|
|
|||
|
|
@ -127,18 +127,44 @@ routes_are_duplicate (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b,
|
|||
NMIP6Config *
|
||||
nm_ip6_config_capture (int ifindex)
|
||||
{
|
||||
NMIP6Config *config = nm_ip6_config_new ();
|
||||
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
|
||||
NMIP6Config *config;
|
||||
NMIP6ConfigPrivate *priv;
|
||||
guint i;
|
||||
gboolean gateway_changed = FALSE;
|
||||
|
||||
/* Slaves have no IP configuration */
|
||||
if (nm_platform_link_get_master (ifindex) > 0)
|
||||
return NULL;
|
||||
|
||||
config = nm_ip6_config_new ();
|
||||
priv = NM_IP6_CONFIG_GET_PRIVATE (config);
|
||||
|
||||
g_array_unref (priv->addresses);
|
||||
g_array_unref (priv->routes);
|
||||
|
||||
priv->addresses = nm_platform_ip6_address_get_all (ifindex);
|
||||
priv->routes = nm_platform_ip6_route_get_all (ifindex, FALSE);
|
||||
priv->routes = nm_platform_ip6_route_get_all (ifindex, TRUE);
|
||||
|
||||
/* Extract gateway from default route */
|
||||
for (i = 0; i < priv->routes->len; i++) {
|
||||
const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i);
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED (&route->network)) {
|
||||
if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &route->gateway)) {
|
||||
priv->gateway = route->gateway;
|
||||
gateway_changed = TRUE;
|
||||
}
|
||||
/* Remove the default route from the list */
|
||||
g_array_remove_index (priv->routes, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* actually, nobody should be connected to the signal, just to be sure, notify */
|
||||
_NOTIFY (config, PROP_ADDRESSES);
|
||||
_NOTIFY (config, PROP_ROUTES);
|
||||
if (gateway_changed)
|
||||
_NOTIFY (config, PROP_GATEWAY);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
|
@ -285,8 +311,11 @@ nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *set
|
|||
NMIP6Address *s_addr;
|
||||
|
||||
/* Ignore link-local address. */
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&address->address))
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&address->address)) {
|
||||
if (!method)
|
||||
method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Detect dynamic address */
|
||||
if (address->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) {
|
||||
|
|
@ -295,7 +324,7 @@ nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *set
|
|||
}
|
||||
|
||||
/* Static address found. */
|
||||
if (!method)
|
||||
if (!method || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0)
|
||||
method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
|
||||
|
||||
s_addr = nm_ip6_address_new ();
|
||||
|
|
@ -308,9 +337,12 @@ nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *set
|
|||
nm_setting_ip6_config_add_address (setting, s_addr);
|
||||
nm_ip6_address_unref (s_addr);
|
||||
}
|
||||
if (!method)
|
||||
method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
|
||||
g_object_set (setting, NM_SETTING_IP6_CONFIG_METHOD, method, NULL);
|
||||
|
||||
/* Only use 'ignore' if the method wasn't previously set */
|
||||
if (!method && !nm_setting_ip6_config_get_method (setting))
|
||||
method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
|
||||
if (method)
|
||||
g_object_set (setting, NM_SETTING_IP6_CONFIG_METHOD, method, NULL);
|
||||
|
||||
/* Routes */
|
||||
for (i = 0; i < nroutes; i++) {
|
||||
|
|
@ -854,6 +886,23 @@ nm_ip6_config_get_address (const NMIP6Config *config, guint i)
|
|||
return &g_array_index (priv->addresses, NMPlatformIP6Address, i);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ip6_config_address_exists (const NMIP6Config *config,
|
||||
const NMPlatformIP6Address *needle)
|
||||
{
|
||||
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < priv->addresses->len; i++) {
|
||||
const NMPlatformIP6Address *haystack = &g_array_index (priv->addresses, NMPlatformIP6Address, i);
|
||||
|
||||
if ( IN6_ARE_ADDR_EQUAL (&needle->address, &haystack->address)
|
||||
&& needle->plen == haystack->plen)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address
|
|||
void nm_ip6_config_del_address (NMIP6Config *config, guint i);
|
||||
guint nm_ip6_config_get_num_addresses (const NMIP6Config *config);
|
||||
const NMPlatformIP6Address *nm_ip6_config_get_address (const NMIP6Config *config, guint i);
|
||||
gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *address);
|
||||
|
||||
/* Routes */
|
||||
void nm_ip6_config_reset_routes (NMIP6Config *config);
|
||||
|
|
|
|||
308
src/nm-manager.c
308
src/nm-manager.c
|
|
@ -151,7 +151,7 @@ static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
|
|||
const char *object_path,
|
||||
gpointer user_data);
|
||||
|
||||
static void add_device (NMManager *self, NMDevice *device);
|
||||
static void add_device (NMManager *self, NMDevice *device, gboolean nm_created);
|
||||
static void remove_device (NMManager *self, NMDevice *device, gboolean quitting);
|
||||
|
||||
static void hostname_provider_init (NMHostnameProvider *provider_class);
|
||||
|
|
@ -166,6 +166,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self,
|
|||
static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
|
||||
|
||||
static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
|
||||
static NMDevice *find_device_by_iface (NMManager *self, const gchar *iface);
|
||||
|
||||
static void rfkill_change_wifi (const char *desc, gboolean enabled);
|
||||
|
||||
|
|
@ -176,6 +177,14 @@ platform_link_added_cb (NMPlatform *platform,
|
|||
NMPlatformReason reason,
|
||||
gpointer user_data);
|
||||
|
||||
static gboolean find_master (NMManager *self,
|
||||
NMConnection *connection,
|
||||
NMDevice *device,
|
||||
NMConnection **out_master_connection,
|
||||
NMDevice **out_master_device);
|
||||
|
||||
static void nm_manager_update_state (NMManager *manager);
|
||||
|
||||
#define SSD_POKE_INTERVAL 120
|
||||
#define ORIGDEV_TAG "originating-device"
|
||||
|
||||
|
|
@ -241,8 +250,6 @@ typedef struct {
|
|||
|
||||
guint timestamp_update_id;
|
||||
|
||||
GHashTable *nm_bridges;
|
||||
|
||||
/* Track auto-activation for software devices */
|
||||
GHashTable *noauto_sw_devices;
|
||||
|
||||
|
|
@ -372,6 +379,8 @@ 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
|
||||
|
|
@ -572,7 +581,7 @@ modem_added (NMModemManager *modem_manager,
|
|||
/* Make the new modem device */
|
||||
device = nm_device_modem_new (modem, driver);
|
||||
if (device)
|
||||
add_device (self, device);
|
||||
add_device (self, device, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -640,12 +649,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));
|
||||
|
|
@ -654,30 +710,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,
|
||||
|
|
@ -710,8 +744,6 @@ manager_device_state_changed (NMDevice *device,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nm_manager_update_state (self);
|
||||
}
|
||||
|
||||
static void device_has_pending_action_changed (NMDevice *device,
|
||||
|
|
@ -764,18 +796,20 @@ 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.
|
||||
/* Leave configured interfaces up when quitting so they can be
|
||||
* taken over again if NM starts up, and to ensure connectivity while
|
||||
* NM is gone. Assumed connections don't get taken down even if they
|
||||
* haven't been fully activated.
|
||||
*/
|
||||
|
||||
if ( !nm_device_can_assume_connections (device)
|
||||
|| (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
|
||||
|| !quitting)
|
||||
nm_device_set_manager_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
|
||||
|| !quitting) {
|
||||
NMActRequest *req = nm_device_get_act_request (device);
|
||||
|
||||
if (!req || !nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (req)))
|
||||
nm_device_set_manager_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_matched (device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager);
|
||||
|
|
@ -1096,90 +1130,6 @@ connection_needs_virtual_device (NMConnection *connection)
|
|||
|
||||
/***************************/
|
||||
|
||||
/* 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_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;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/***************************/
|
||||
|
||||
/**
|
||||
* system_create_virtual_device:
|
||||
* @self: the #NMManager
|
||||
|
|
@ -1229,12 +1179,7 @@ system_create_virtual_device (NMManager *self, NMConnection *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)) {
|
||||
/* FIXME: remove when we handle bridges non-destructively */
|
||||
if (nm_platform_link_get_ifindex (iface) > 0 && !bridge_created_by_nm (self, iface)) {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s): cannot use existing bridge for '%s'",
|
||||
iface, nm_connection_get_id (connection));
|
||||
} else
|
||||
device = nm_device_bridge_new_for_connection (connection);
|
||||
device = nm_device_bridge_new_for_connection (connection);
|
||||
} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
|
||||
device = nm_device_vlan_new_for_connection (connection, parent);
|
||||
} else if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
|
||||
|
|
@ -1243,7 +1188,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
|
|||
|
||||
if (device) {
|
||||
nm_device_set_is_nm_owned (device, TRUE);
|
||||
add_device (self, device);
|
||||
add_device (self, device, TRUE);
|
||||
}
|
||||
|
||||
g_signal_handlers_unblock_by_func (nm_platform_get (), G_CALLBACK (platform_link_added_cb), self);
|
||||
|
|
@ -1756,24 +1701,15 @@ local_slist_free (void *loc)
|
|||
}
|
||||
|
||||
/**
|
||||
* get_connection:
|
||||
* get_existing_connection:
|
||||
* @manager: #NMManager instance
|
||||
* @device: #NMDevice instance
|
||||
*
|
||||
* Returns one of the following:
|
||||
*
|
||||
* 1) An existing #NMSettingsConnection to be assumed.
|
||||
*
|
||||
* 2) A generated #NMConnection to be assumed. You can distinguish this
|
||||
* case using NM_IS_SETTINGS_CONNECTION().
|
||||
*
|
||||
* 3) %NULL when no connection was detected or the @device doesn't support
|
||||
* generating connections.
|
||||
*
|
||||
* Supports both nm-device's match_l2_config() and update_connection().
|
||||
* Returns: a #NMSettingsConnection to be assumed by the device, or %NULL if
|
||||
* the device does not support assuming existing connections.
|
||||
*/
|
||||
static NMConnection *
|
||||
get_connection (NMManager *manager, NMDevice *device)
|
||||
get_existing_connection (NMManager *manager, NMDevice *device)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||
free_slist GSList *connections = nm_manager_get_activatable_connections (manager);
|
||||
|
|
@ -1782,24 +1718,7 @@ get_connection (NMManager *manager, NMDevice *device)
|
|||
GSList *iter;
|
||||
GError *error = NULL;
|
||||
|
||||
/* We still support the older API to match a NMDevice object to an
|
||||
* existing connection using nm_device_find_assumable_connection().
|
||||
*
|
||||
* When the older API is still available for a particular device
|
||||
* type, we use it. To opt for the newer interface, the NMDevice
|
||||
* subclass must omit the match_l2_config virtual function
|
||||
* implementation.
|
||||
*/
|
||||
if (NM_DEVICE_GET_CLASS (device)->match_l2_config) {
|
||||
NMConnection *candidate = nm_device_find_assumable_connection (device, connections);
|
||||
|
||||
if (candidate) {
|
||||
nm_log_info (LOGD_DEVICE, "(%s): Found matching connection '%s' (legacy API)",
|
||||
nm_device_get_iface (device),
|
||||
nm_connection_get_id (candidate));
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
@ -1808,11 +1727,8 @@ get_connection (NMManager *manager, NMDevice *device)
|
|||
* returns NULL.
|
||||
*/
|
||||
connection = nm_device_generate_connection (device);
|
||||
if (!connection) {
|
||||
nm_log_info (LOGD_DEVICE, "(%s): No existing connection detected.",
|
||||
nm_device_get_iface (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
|
||||
|
|
@ -1827,7 +1743,7 @@ get_connection (NMManager *manager, NMDevice *device)
|
|||
NMConnection *candidate = NM_CONNECTION (iter->data);
|
||||
|
||||
if (nm_connection_compare (connection, candidate, NM_SETTING_COMPARE_FLAG_CANDIDATE)) {
|
||||
nm_log_info (LOGD_DEVICE, "(%s): Found matching connection: '%s'",
|
||||
nm_log_info (LOGD_DEVICE, "(%s): found matching connection '%s'",
|
||||
nm_device_get_iface (device),
|
||||
nm_connection_get_id (candidate));
|
||||
g_object_unref (connection);
|
||||
|
|
@ -1835,9 +1751,9 @@ get_connection (NMManager *manager, NMDevice *device)
|
|||
}
|
||||
}
|
||||
|
||||
nm_log_info (LOGD_DEVICE, "(%s): Using generated connection: '%s'",
|
||||
nm_device_get_iface (device),
|
||||
nm_connection_get_id (connection));
|
||||
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) {
|
||||
|
|
@ -1853,14 +1769,14 @@ get_connection (NMManager *manager, NMDevice *device)
|
|||
}
|
||||
|
||||
static void
|
||||
add_device (NMManager *self, NMDevice *device)
|
||||
add_device (NMManager *self, NMDevice *device, gboolean nm_created)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
const char *iface, *driver, *type_desc;
|
||||
char *path;
|
||||
static guint32 devcount = 0;
|
||||
const GSList *unmanaged_specs;
|
||||
NMConnection *connection;
|
||||
NMConnection *connection = NULL;
|
||||
gboolean enabled = FALSE;
|
||||
RfKillType rtype;
|
||||
NMDeviceType devtype;
|
||||
|
|
@ -1946,7 +1862,9 @@ add_device (NMManager *self, NMDevice *device)
|
|||
nm_log_info (LOGD_CORE, "(%s): exported as %s", iface, path);
|
||||
g_free (path);
|
||||
|
||||
connection = get_connection (self, device);
|
||||
/* Don't bother generating a connection for devices NM just created */
|
||||
if (!nm_created)
|
||||
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);
|
||||
|
|
@ -1967,9 +1885,7 @@ add_device (NMManager *self, NMDevice *device)
|
|||
system_create_virtual_devices (self);
|
||||
|
||||
/* If the device has a connection it can assume, do that now */
|
||||
if ( connection
|
||||
&& nm_device_is_available (device)
|
||||
&& nm_device_connection_is_available (device, connection)) {
|
||||
if (connection) {
|
||||
NMActiveConnection *active;
|
||||
NMAuthSubject *subject;
|
||||
GError *error = NULL;
|
||||
|
|
@ -1985,6 +1901,22 @@ add_device (NMManager *self, NMDevice *device)
|
|||
subject = nm_auth_subject_new_internal ();
|
||||
active = _new_active_connection (self, connection, NULL, device, subject, &error);
|
||||
if (active) {
|
||||
NMDevice *master = NULL;
|
||||
NMActRequest *master_req;
|
||||
|
||||
/* If the device is a slave or VLAN, find the master ActiveConnection */
|
||||
if (find_master (self, connection, device, NULL, &master) && master) {
|
||||
master_req = nm_device_get_act_request (master);
|
||||
if (master_req)
|
||||
nm_active_connection_set_master (active, NM_ACTIVE_CONNECTION (master_req));
|
||||
else {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s): master device %s not activating!",
|
||||
nm_device_get_iface (device),
|
||||
nm_device_get_iface (master));
|
||||
}
|
||||
}
|
||||
|
||||
nm_active_connection_set_assumed (active, TRUE);
|
||||
nm_active_connection_export (active);
|
||||
active_connection_add (self, active);
|
||||
nm_device_activate (device, NM_ACT_REQUEST (active));
|
||||
|
|
@ -2031,7 +1963,7 @@ bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
|
|||
has_dun && has_nap ? " " : "",
|
||||
has_nap ? "NAP" : "");
|
||||
|
||||
add_device (manager, device);
|
||||
add_device (manager, device, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2277,11 +2209,7 @@ platform_link_added_cb (NMPlatform *platform,
|
|||
device = nm_device_team_new (plink);
|
||||
break;
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
/* FIXME: always create device when we handle bridges non-destructively */
|
||||
if (bridge_created_by_nm (self, plink->name))
|
||||
device = nm_device_bridge_new (plink);
|
||||
else
|
||||
nm_log_info (LOGD_BRIDGE, "(%s): ignoring bridge not created by NetworkManager", plink->name);
|
||||
device = nm_device_bridge_new (plink);
|
||||
break;
|
||||
case NM_LINK_TYPE_VLAN:
|
||||
/* Have to find the parent device */
|
||||
|
|
@ -2335,7 +2263,7 @@ platform_link_added_cb (NMPlatform *platform,
|
|||
}
|
||||
|
||||
if (device)
|
||||
add_device (self, device);
|
||||
add_device (self, device, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2372,7 +2300,7 @@ atm_device_added_cb (NMAtmManager *atm_mgr,
|
|||
|
||||
device = nm_device_adsl_new (sysfs_path, iface, driver);
|
||||
if (device)
|
||||
add_device (self, device);
|
||||
add_device (self, device, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4157,13 +4085,6 @@ 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_platform_query_devices ();
|
||||
nm_atm_manager_query_devices (priv->atm_mgr);
|
||||
nm_bluez_manager_query_devices (priv->bluez_mgr);
|
||||
|
|
@ -4174,10 +4095,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
@ -4623,9 +4540,6 @@ dispose (GObject *object)
|
|||
|
||||
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 (priv->devices)
|
||||
remove_device (manager, NM_DEVICE (priv->devices->data), TRUE);
|
||||
|
|
|
|||
|
|
@ -1060,14 +1060,18 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
|
|||
announce_object (platform, cached_object, REMOVED, reason);
|
||||
}
|
||||
} else {
|
||||
g_return_val_if_fail (kernel_object, FALSE);
|
||||
if (!kernel_object)
|
||||
return FALSE;
|
||||
|
||||
hack_empty_master_iff_lower_up (platform, kernel_object);
|
||||
|
||||
if (cached_object)
|
||||
nl_cache_remove (cached_object);
|
||||
nle = nl_cache_add (cache, kernel_object);
|
||||
g_return_val_if_fail (!nle, FALSE);
|
||||
if (nle) {
|
||||
nm_log_dbg (LOGD_PLATFORM, "refresh_object(reason %d) failed during nl_cache_add with %d", reason, nle);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
announce_object (platform, kernel_object, cached_object ? CHANGED : ADDED, reason);
|
||||
|
||||
|
|
|
|||
|
|
@ -267,37 +267,6 @@ nm_platform_query_devices (void)
|
|||
g_array_unref (links_array);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_links (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
NMPlatformLink *link_a = (NMPlatformLink *) a;
|
||||
NMPlatformLink *link_b = (NMPlatformLink *) b;
|
||||
int sortindex_a, sortindex_b;
|
||||
|
||||
/* We mostly want to sort by ifindex. However, slaves should sort
|
||||
* before their masters, and children (eg, VLANs) should sort after
|
||||
* their parents.
|
||||
*/
|
||||
if (link_a->master)
|
||||
sortindex_a = link_a->master * 3 - 1;
|
||||
else if (link_a->parent)
|
||||
sortindex_a = link_a->parent * 3 + 1;
|
||||
else
|
||||
sortindex_a = link_a->ifindex * 3;
|
||||
|
||||
if (link_b->master)
|
||||
sortindex_b = link_b->master * 3 - 1;
|
||||
else if (link_b->parent)
|
||||
sortindex_b = link_b->parent * 3 + 1;
|
||||
else
|
||||
sortindex_b = link_b->ifindex * 3;
|
||||
|
||||
if (sortindex_a == sortindex_b)
|
||||
return link_a->ifindex - link_b->ifindex;
|
||||
else
|
||||
return sortindex_a - sortindex_b;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_get_all:
|
||||
*
|
||||
|
|
@ -307,15 +276,100 @@ compare_links (gconstpointer a, gconstpointer b)
|
|||
GArray *
|
||||
nm_platform_link_get_all (void)
|
||||
{
|
||||
GArray *links;
|
||||
GArray *links, *result;
|
||||
guint i, j, nresult;
|
||||
GHashTable *unseen;
|
||||
NMPlatformLink *item;
|
||||
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (klass->link_get_all, NULL);
|
||||
|
||||
links = klass->link_get_all (platform);
|
||||
g_array_sort (links, compare_links);
|
||||
return links;
|
||||
|
||||
if (!links || links->len == 0)
|
||||
return links;
|
||||
|
||||
unseen = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
for (i = 0; i < links->len; i++) {
|
||||
item = &g_array_index (links, NMPlatformLink, i);
|
||||
|
||||
if (item->ifindex <= 0 || g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex))) {
|
||||
g_warn_if_reached ();
|
||||
item->ifindex = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL);
|
||||
}
|
||||
|
||||
#ifndef G_DISABLE_ASSERT
|
||||
/* Ensure that link_get_all returns a consistent and valid result. */
|
||||
for (i = 0; i < links->len; i++) {
|
||||
item = &g_array_index (links, NMPlatformLink, i);
|
||||
|
||||
if (!item->ifindex)
|
||||
continue;
|
||||
if (item->master != 0) {
|
||||
g_warn_if_fail (item->master > 0);
|
||||
g_warn_if_fail (item->master != item->ifindex);
|
||||
g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->master)));
|
||||
}
|
||||
if (item->parent != 0) {
|
||||
g_warn_if_fail (item->parent > 0);
|
||||
g_warn_if_fail (item->parent != item->ifindex);
|
||||
g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Re-order the links list such that children/slaves come after all ancestors */
|
||||
nresult = g_hash_table_size (unseen);
|
||||
result = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), nresult);
|
||||
g_array_set_size (result, nresult);
|
||||
|
||||
j = 0;
|
||||
do {
|
||||
gboolean found_something = FALSE;
|
||||
guint first_idx = G_MAXUINT;
|
||||
|
||||
for (i = 0; i < links->len; i++) {
|
||||
item = &g_array_index (links, NMPlatformLink, i);
|
||||
|
||||
if (!item->ifindex)
|
||||
continue;
|
||||
|
||||
if (first_idx == G_MAXUINT)
|
||||
first_idx = i;
|
||||
|
||||
g_assert (g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex)));
|
||||
|
||||
if (item->master > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->master)))
|
||||
continue;
|
||||
if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)))
|
||||
continue;
|
||||
|
||||
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
|
||||
g_array_index (result, NMPlatformLink, j++) = *item;
|
||||
item->ifindex = 0;
|
||||
found_something = TRUE;
|
||||
}
|
||||
|
||||
if (!found_something) {
|
||||
/* there is a circle, pop the first (remaining) element from the list */
|
||||
g_warn_if_reached ();
|
||||
item = &g_array_index (links, NMPlatformLink, first_idx);
|
||||
|
||||
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
|
||||
g_array_index (result, NMPlatformLink, j++) = *item;
|
||||
item->ifindex = 0;
|
||||
}
|
||||
} while (j < nresult);
|
||||
|
||||
g_hash_table_destroy (unseen);
|
||||
g_array_free (links, TRUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -124,16 +124,16 @@ typedef struct {
|
|||
in_addr_t address;
|
||||
int plen;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
guint32 preferred;
|
||||
guint32 lifetime; /* seconds */
|
||||
guint32 preferred; /* seconds */
|
||||
} NMPlatformIP4Address;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
struct in6_addr address;
|
||||
int plen;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
guint32 timestamp; /* seconds */
|
||||
guint32 lifetime; /* seconds */
|
||||
guint32 preferred;
|
||||
guint flags; /* ifa_flags from <linux/if_addr.h>, field type "unsigned int" is as used in rtnl_addr_get_flags. */
|
||||
} NMPlatformIP6Address;
|
||||
|
|
|
|||
|
|
@ -1730,6 +1730,12 @@ has_connections_loaded (NMConnectionProvider *provider)
|
|||
return priv->connections_loaded;
|
||||
}
|
||||
|
||||
static NMConnection *
|
||||
cp_get_connection_by_uuid (NMConnectionProvider *provider, const char *uuid)
|
||||
{
|
||||
return NM_CONNECTION (nm_settings_get_connection_by_uuid (NM_SETTINGS (provider), uuid));
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
|
||||
NMSettings *
|
||||
|
|
@ -1765,6 +1771,7 @@ connection_provider_init (NMConnectionProvider *cp_class)
|
|||
cp_class->get_connections = get_connections;
|
||||
cp_class->has_connections_loaded = has_connections_loaded;
|
||||
cp_class->add_connection = _nm_connection_provider_add_connection;
|
||||
cp_class->get_connection_by_uuid = cp_get_connection_by_uuid;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ find_by_path (SCPluginIfcfg *self, const char *path)
|
|||
|
||||
g_hash_table_iter_init (&iter, priv->connections);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
|
||||
if (g_str_equal (path, nm_ifcfg_connection_get_path (candidate)))
|
||||
if (g_strcmp0 (path, nm_ifcfg_connection_get_path (candidate)) == 0)
|
||||
return candidate;
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -445,8 +445,11 @@ read_connections (SCPluginIfcfg *plugin)
|
|||
|
||||
oldconns = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
g_hash_table_iter_init (&iter, priv->connections);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
g_hash_table_insert (oldconns, g_strdup (nm_ifcfg_connection_get_path (value)), value);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value)) {
|
||||
const char *ifcfg_path = nm_ifcfg_connection_get_path (value);
|
||||
if (ifcfg_path)
|
||||
g_hash_table_insert (oldconns, g_strdup (ifcfg_path), value);
|
||||
}
|
||||
|
||||
while ((item = g_dir_read_name (dir))) {
|
||||
char *full_path, *old_path;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue