NetworkManager/src/devices/nm-device.c

10775 lines
338 KiB
C
Raw Normal View History

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
2013-12-16 15:16:43 +01:00
* Copyright (C) 2005 - 2013 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
#include "config.h"
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netlink/route/addr.h>
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
#include <linux/if_addr.h>
#include "nm-default.h"
2007-05-07 Tambet Ingo <tambet@ximian.com> * libnm-glib/Makefile.am: Link with libnm-util to gain access to NMConnection. * libnm-glib/nm-device-802-11-wireless.c: (nm_device_802_3_ethernet_activate): Remove. * libnm-glib/nm-device-802-3-ethernet.c (nm_device_802_3_ethernet_activate): Remove. * libnm-glib/nm-device.c (nm_device_activate): Implement. * src/nm-device-802-3-ethernet.c: Implement the new activation using NMConnection. * src/nm-device-802-11-wireless.c: Store an activation AP once the activation has started. Implement the new activation using NMConnection. * src/nm-activation-request.c: Store a generic connection object instead of a wireless-specific AP. * src/NetworkManagerPolicy.c (create_connection): Implement. Depending on device type, create a device specific connection object suitable for device activation. * src/nm-device.c (nm_device_activate): Re-implement. Call the device specific check to validate the connection and on success start the activation. * src/nm-device-interface.h: Add a activate virtual function to the interface definition. * src/nm-device-interface.c (nm_device_interface_activate): Implement. (impl_device_activate): Implement. * introspection/nm-device.xml: Add a generic device activation interface that accepts an abstract NMConnection structure that has device-specific information in it. * introspection/nm-device-802-3-ethernet.xml: Remove the wired-specific activation interface. * introspection/nm-device-802-11-wireless.xml: Remove the wireless-specific activation interface. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2569 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-05-07 15:17:45 +00:00
#include "nm-device.h"
#include "nm-device-private.h"
#include "NetworkManagerUtils.h"
#include "nm-manager.h"
#include "nm-platform.h"
#include "nm-rdisc.h"
#include "nm-lndp-rdisc.h"
#include "nm-dhcp-manager.h"
#include "nm-activation-request.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
#include "nm-dnsmasq-manager.h"
#include "nm-dhcp4-config.h"
#include "nm-dhcp6-config.h"
#include "nm-rfkill-manager.h"
#include "nm-firewall-manager.h"
#include "nm-enum-types.h"
#include "nm-settings-connection.h"
#include "nm-connection-provider.h"
#include "nm-auth-utils.h"
#include "nm-dispatcher.h"
#include "nm-config.h"
#include "nm-dns-manager.h"
#include "nm-core-internal.h"
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "nm-lldp-listener.h"
2015-04-20 18:13:41 +02:00
#include "sd-ipv4ll.h"
2015-07-14 10:19:19 +02:00
#include "nm-audit-manager.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
#include "nmdbus-device.h"
static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data);
static gboolean ip_config_valid (NMDeviceState state);
static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, NMDeviceStateReason *reason);
static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason);
static void nm_device_start_ip_check (NMDevice *self);
G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT)
#define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate))
enum {
STATE_CHANGED,
AUTOCONNECT_ALLOWED,
AUTH_REQUEST,
IP4_CONFIG_CHANGED,
IP6_CONFIG_CHANGED,
REMOVED,
RECHECK_AUTO_ACTIVATE,
RECHECK_ASSUME,
LINK_INITIALIZED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_0,
PROP_UDI,
PROP_IFACE,
PROP_IP_IFACE,
PROP_DRIVER,
PROP_DRIVER_VERSION,
PROP_FIRMWARE_VERSION,
PROP_CAPABILITIES,
PROP_CARRIER,
2013-12-16 15:16:43 +01:00
PROP_MTU,
PROP_IP4_ADDRESS,
PROP_IP4_CONFIG,
PROP_DHCP4_CONFIG,
PROP_IP6_CONFIG,
PROP_DHCP6_CONFIG,
PROP_STATE,
PROP_STATE_REASON,
PROP_ACTIVE_CONNECTION,
PROP_DEVICE_TYPE,
PROP_MANAGED,
PROP_AUTOCONNECT,
PROP_FIRMWARE_MISSING,
PROP_NM_PLUGIN_MISSING,
PROP_TYPE_DESC,
PROP_RFKILL_TYPE,
PROP_IFINDEX,
PROP_AVAILABLE_CONNECTIONS,
PROP_PHYSICAL_PORT_ID,
PROP_IS_MASTER,
PROP_MASTER,
PROP_HW_ADDRESS,
PROP_HAS_PENDING_ACTION,
PROP_METERED,
PROP_LLDP_NEIGHBORS,
PROP_REAL,
LAST_PROP
};
/***********************************************************/
#define PENDING_ACTION_DHCP4 "dhcp4"
#define PENDING_ACTION_DHCP6 "dhcp6"
#define PENDING_ACTION_AUTOCONF6 "autoconf6"
typedef void (*ActivationHandleFunc) (NMDevice *self);
typedef struct {
ActivationHandleFunc func;
guint id;
} ActivationHandleData;
typedef enum {
CLEANUP_TYPE_DECONFIGURE,
CLEANUP_TYPE_KEEP,
CLEANUP_TYPE_REMOVED,
} CleanupType;
typedef enum {
IP_NONE = 0,
IP_WAIT,
IP_CONF,
IP_DONE,
IP_FAIL
} IpState;
typedef struct {
NMDeviceState state;
NMDeviceStateReason reason;
guint id;
} QueuedState;
2012-11-14 14:05:30 -06:00
typedef struct {
NMDevice *slave;
gboolean slave_is_enslaved;
gboolean configure;
2012-11-14 14:05:30 -06:00
guint watch_id;
} SlaveInfo;
typedef struct {
NMLogDomain log_domain;
guint timeout;
guint watch;
GPid pid;
const char *binary;
const char *address;
guint deadline;
} PingInfo;
typedef struct {
NMDevice *device;
guint idle_add_id;
int ifindex;
} DeleteOnDeactivateData;
2009-07-07 14:34:01 -04:00
typedef struct {
gboolean in_state_changed;
gboolean initialized;
gboolean platform_link_initialized;
guint device_link_changed_id;
guint device_ip_link_changed_id;
NMDeviceState state;
NMDeviceStateReason state_reason;
QueuedState queued_state;
guint queued_ip4_config_id;
guint queued_ip6_config_id;
GSList *pending_actions;
GSList *dad6_failed_addrs;
2009-07-07 14:34:01 -04:00
char * udi;
char * iface; /* may change, could be renamed by user */
int ifindex;
gboolean real;
2009-07-07 14:34:01 -04:00
char * ip_iface;
int ip_ifindex;
2009-07-07 14:34:01 -04:00
NMDeviceType type;
char * type_desc;
char * type_description;
NMDeviceCapabilities capabilities;
2009-07-07 14:34:01 -04:00
char * driver;
char * driver_version;
char * firmware_version;
RfKillType rfkill_type;
gboolean firmware_missing;
gboolean nm_plugin_missing;
GHashTable * available_connections;
char * hw_addr;
guint hw_addr_len;
char * perm_hw_addr;
char * initial_hw_addr;
char * physical_port_id;
guint dev_id;
gboolean managed_touched_by_user;
NMUnmanagedFlags unmanaged_flags;
gboolean is_nm_owned; /* whether the device is a device owned and created by NM */
DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */
GCancellable *deactivating_cancellable;
2009-07-07 14:34:01 -04:00
guint32 ip4_address;
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
NMActRequest * queued_act_request;
gboolean queued_act_request_is_waiting_for_carrier;
2009-07-07 14:34:01 -04:00
NMActRequest * act_request;
ActivationHandleData act_handle4; /* for layer2 and IPv4. */
ActivationHandleData act_handle6;
guint recheck_assume_id;
struct {
guint call_id;
NMDeviceStateReason available_reason;
NMDeviceStateReason unavailable_reason;
} recheck_available;
struct {
guint call_id;
NMDeviceState post_state;
NMDeviceStateReason post_state_reason;
} dispatcher;
/* Link stuff */
guint link_connected_id;
guint link_disconnected_id;
guint carrier_defer_id;
gboolean carrier;
guint carrier_wait_id;
gboolean ignore_carrier;
2013-12-16 15:16:43 +01:00
guint32 mtu;
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
gboolean up; /* IFF_UP */
/* Generic DHCP stuff */
guint32 dhcp_timeout;
char * dhcp_anycast_address;
/* IP4 configuration info */
NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */
IpState ip4_state;
NMIP4Config * con_ip4_config; /* config from the setting */
NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */
NMIP4Config * ext_ip4_config; /* Stuff added outside NM */
NMIP4Config * wwan_ip4_config; /* WWAN configuration */
GSList * vpn4_configs; /* VPNs which use this device */
struct {
gboolean v4_has;
gboolean v4_is_assumed;
NMPlatformIP4Route v4;
gboolean v6_has;
gboolean v6_is_assumed;
NMPlatformIP6Route v6;
} default_route;
gboolean v4_commit_first_time;
gboolean v6_commit_first_time;
/* DHCPv4 tracking */
NMDhcpClient * dhcp4_client;
gulong dhcp4_state_sigid;
NMDhcp4Config * dhcp4_config;
guint dhcp4_restart_id;
guint arp_round2_id;
PingInfo gw_ping;
/* dnsmasq stuff for shared connections */
2009-07-07 14:34:01 -04:00
NMDnsMasqManager *dnsmasq_manager;
gulong dnsmasq_state_id;
/* Firewall */
gboolean fw_ready;
NMFirewallManagerCallId fw_call;
/* IPv4LL stuff */
2015-04-20 18:13:41 +02:00
sd_ipv4ll * ipv4ll;
guint ipv4ll_timeout;
/* IP6 configuration info */
NMIP6Config * ip6_config;
IpState ip6_state;
NMIP6Config * con_ip6_config; /* config from the setting */
NMIP6Config * wwan_ip6_config;
NMIP6Config * ext_ip6_config; /* Stuff added outside NM */
GSList * vpn6_configs; /* VPNs which use this device */
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */
guint32 ip6_mtu;
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
NMRDisc * rdisc;
gulong rdisc_changed_id;
gulong rdisc_timeout_id;
NMSettingIP6ConfigPrivacy rdisc_use_tempaddr;
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
/* IP6 config from autoconf */
NMIP6Config * ac_ip6_config;
guint linklocal6_timeout_id;
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
guint8 linklocal6_dad_counter;
GHashTable * ip6_saved_properties;
NMDhcpClient * dhcp6_client;
NMRDiscDHCPLevel dhcp6_mode;
gulong dhcp6_state_sigid;
NMDhcp6Config * dhcp6_config;
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
/* IP6 config from DHCP */
NMIP6Config * dhcp6_ip6_config;
/* Event ID of the current IP6 config from DHCP */
char * dhcp6_event_id;
guint dhcp6_restart_id;
/* allow autoconnect feature */
gboolean autoconnect;
/* master interface for bridge/bond/team slave */
2012-11-14 14:05:30 -06:00
NMDevice * master;
gboolean is_enslaved;
gboolean master_ready_handled;
guint master_ready_id;
2012-11-14 14:05:30 -06:00
/* slave management */
gboolean is_master;
GSList * slaves; /* list of SlaveInfo */
NMMetered metered;
NMConnectionProvider *con_provider;
NMLldpListener *lldp_listener;
2009-07-07 14:34:01 -04:00
} NMDevicePrivate;
static gboolean nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *config,
guint32 default_route_metric,
gboolean commit,
gboolean routes_full_sync,
NMDeviceStateReason *reason);
static gboolean ip4_config_merge_and_apply (NMDevice *self,
NMIP4Config *config,
gboolean commit,
NMDeviceStateReason *out_reason);
static gboolean nm_device_set_ip6_config (NMDevice *self,
NMIP6Config *config,
gboolean commit,
gboolean routes_full_sync,
NMDeviceStateReason *reason);
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure);
static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success);
static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason);
static gboolean addrconf6_start_with_link_ready (NMDevice *self);
static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection);
static NMActStageReturn linklocal6_start (NMDevice *self);
static void _carrier_wait_check_queued_act_request (NMDevice *self);
static gboolean nm_device_get_default_unmanaged (NMDevice *self);
static const char *_activation_func_to_string (ActivationHandleFunc func);
static void activation_source_handle_cb (NMDevice *self, int family);
static void _set_state_full (NMDevice *self,
NMDeviceState state,
NMDeviceStateReason reason,
gboolean quitting);
static void nm_device_update_hw_address (NMDevice *self);
static gboolean queued_ip4_config_change (gpointer user_data);
static gboolean queued_ip6_config_change (gpointer user_data);
static void _set_unmanaged_flags (NMDevice *self,
NMUnmanagedFlags flags,
gboolean unmanaged);
/***********************************************************/
#define QUEUED_PREFIX "queued state change to "
static const char *state_table[] = {
[NM_DEVICE_STATE_UNKNOWN] = QUEUED_PREFIX "unknown",
[NM_DEVICE_STATE_UNMANAGED] = QUEUED_PREFIX "unmanaged",
[NM_DEVICE_STATE_UNAVAILABLE] = QUEUED_PREFIX "unavailable",
[NM_DEVICE_STATE_DISCONNECTED] = QUEUED_PREFIX "disconnected",
[NM_DEVICE_STATE_PREPARE] = QUEUED_PREFIX "prepare",
[NM_DEVICE_STATE_CONFIG] = QUEUED_PREFIX "config",
[NM_DEVICE_STATE_NEED_AUTH] = QUEUED_PREFIX "need-auth",
[NM_DEVICE_STATE_IP_CONFIG] = QUEUED_PREFIX "ip-config",
[NM_DEVICE_STATE_IP_CHECK] = QUEUED_PREFIX "ip-check",
[NM_DEVICE_STATE_SECONDARIES] = QUEUED_PREFIX "secondaries",
[NM_DEVICE_STATE_ACTIVATED] = QUEUED_PREFIX "activated",
[NM_DEVICE_STATE_DEACTIVATING] = QUEUED_PREFIX "deactivating",
[NM_DEVICE_STATE_FAILED] = QUEUED_PREFIX "failed",
};
static const char *
queued_state_to_string (NMDeviceState state)
{
if ((gsize) state < G_N_ELEMENTS (state_table))
return state_table[state];
return state_table[NM_DEVICE_STATE_UNKNOWN];
}
static const char *
state_to_string (NMDeviceState state)
{
return queued_state_to_string (state) + strlen (QUEUED_PREFIX);
}
2009-07-07 14:34:01 -04:00
static const char *reason_table[] = {
[NM_DEVICE_STATE_REASON_UNKNOWN] = "unknown",
[NM_DEVICE_STATE_REASON_NONE] = "none",
[NM_DEVICE_STATE_REASON_NOW_MANAGED] = "managed",
[NM_DEVICE_STATE_REASON_NOW_UNMANAGED] = "unmanaged",
[NM_DEVICE_STATE_REASON_CONFIG_FAILED] = "config-failed",
[NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE] = "ip-config-unavailable",
[NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED] = "ip-config-expired",
[NM_DEVICE_STATE_REASON_NO_SECRETS] = "no-secrets",
[NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT] = "supplicant-disconnect",
[NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED] = "supplicant-config-failed",
[NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED] = "supplicant-failed",
[NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT] = "supplicant-timeout",
[NM_DEVICE_STATE_REASON_PPP_START_FAILED] = "ppp-start-failed",
[NM_DEVICE_STATE_REASON_PPP_DISCONNECT] = "ppp-disconnect",
[NM_DEVICE_STATE_REASON_PPP_FAILED] = "ppp-failed",
[NM_DEVICE_STATE_REASON_DHCP_START_FAILED] = "dhcp-start-failed",
[NM_DEVICE_STATE_REASON_DHCP_ERROR] = "dhcp-error",
[NM_DEVICE_STATE_REASON_DHCP_FAILED] = "dhcp-failed",
[NM_DEVICE_STATE_REASON_SHARED_START_FAILED] = "sharing-start-failed",
[NM_DEVICE_STATE_REASON_SHARED_FAILED] = "sharing-failed",
[NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED] = "autoip-start-failed",
[NM_DEVICE_STATE_REASON_AUTOIP_ERROR] = "autoip-error",
[NM_DEVICE_STATE_REASON_AUTOIP_FAILED] = "autoip-failed",
[NM_DEVICE_STATE_REASON_MODEM_BUSY] = "modem-busy",
[NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE] = "modem-no-dialtone",
[NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER] = "modem-no-carrier",
[NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT] = "modem-dial-timeout",
[NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED] = "modem-dial-failed",
[NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED] = "modem-init-failed",
[NM_DEVICE_STATE_REASON_GSM_APN_FAILED] = "gsm-apn-failed",
[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING] = "gsm-registration-idle",
[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED] = "gsm-registration-denied",
[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT] = "gsm-registration-timeout",
[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED] = "gsm-registration-failed",
[NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED] = "gsm-pin-check-failed",
[NM_DEVICE_STATE_REASON_FIRMWARE_MISSING] = "firmware-missing",
[NM_DEVICE_STATE_REASON_REMOVED] = "removed",
[NM_DEVICE_STATE_REASON_SLEEPING] = "sleeping",
[NM_DEVICE_STATE_REASON_CONNECTION_REMOVED] = "connection-removed",
[NM_DEVICE_STATE_REASON_USER_REQUESTED] = "user-requested",
[NM_DEVICE_STATE_REASON_CARRIER] = "carrier-changed",
[NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED] = "connection-assumed",
[NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE] = "supplicant-available",
[NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND] = "modem-not-found",
[NM_DEVICE_STATE_REASON_BT_FAILED] = "bluetooth-failed",
[NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED] = "gsm-sim-not-inserted",
[NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED] = "gsm-sim-pin-required",
[NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED] = "gsm-sim-puk-required",
[NM_DEVICE_STATE_REASON_GSM_SIM_WRONG] = "gsm-sim-wrong",
[NM_DEVICE_STATE_REASON_INFINIBAND_MODE] = "infiniband-mode",
[NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED] = "dependency-failed",
[NM_DEVICE_STATE_REASON_BR2684_FAILED] = "br2684-bridge-failed",
[NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE] = "modem-manager-unavailable",
[NM_DEVICE_STATE_REASON_SSID_NOT_FOUND] = "ssid-not-found",
[NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED] = "secondary-connection-failed",
[NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED] = "dcb-fcoe-failed",
[NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED] = "teamd-control-failed",
[NM_DEVICE_STATE_REASON_MODEM_FAILED] = "modem-failed",
[NM_DEVICE_STATE_REASON_MODEM_AVAILABLE] = "modem-available",
[NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT] = "sim-pin-incorrect",
[NM_DEVICE_STATE_REASON_NEW_ACTIVATION] = "new-activation",
[NM_DEVICE_STATE_REASON_PARENT_CHANGED] = "parent-changed",
[NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED] = "parent-managed-changed",
};
static const char *
reason_to_string (NMDeviceStateReason reason)
{
if ((gsize) reason < G_N_ELEMENTS (reason_table))
return reason_table[reason];
return reason_table[NM_DEVICE_STATE_REASON_UNKNOWN];
}
/***********************************************************/
gboolean
nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value);
}
static guint32
nm_device_ipv6_sysctl_get_int32 (NMDevice *self, const char *property, gint32 fallback)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), fallback);
}
gboolean
nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps)
{
return NM_FLAGS_ANY (NM_DEVICE_GET_PRIVATE (self)->capabilities, caps);
}
/***********************************************************/
const char *
nm_device_get_udi (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
2009-07-07 14:34:01 -04:00
return NM_DEVICE_GET_PRIVATE (self)->udi;
}
const char *
nm_device_get_iface (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
2009-07-07 14:34:01 -04:00
return NM_DEVICE_GET_PRIVATE (self)->iface;
}
int
nm_device_get_ifindex (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), 0);
return NM_DEVICE_GET_PRIVATE (self)->ifindex;
}
/**
* nm_device_is_software:
* @self: the #NMDevice
*
* Indicates if the device is a software-based virtual device without
* backing hardware, which can be added and removed programmatically.
*
* Returns: %TRUE if the device is a software-based device
*/
gboolean
nm_device_is_software (NMDevice *self)
{
return NM_FLAGS_HAS (NM_DEVICE_GET_PRIVATE (self)->capabilities, NM_DEVICE_CAP_IS_SOFTWARE);
}
/**
* nm_device_is_real:
* @self: the #NMDevice
*
* Returns: %TRUE if the device exists, %FALSE if the device is a placeholder
*/
gboolean
nm_device_is_real (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->real;
}
2008-03-07 Dan Williams <dcbw@redhat.com> First pass of multiple active device support. Expect bugs. * src/nm-ip4-config.c src/nm-ip4-config.h - (nm_ip4_config_get_secondary, nm_ip4_config_set_secondary): remove; there are better ways to do this in the named manager * src/nm-device.c src/nm-device.h - (nm_device_can_activate): return whether the device can activate a connection right now; taking into account things like carrier state and rfkill state - (nm_device_get_best_auto_connection): renamed from nm_device_get_best_connection - (real_act_stage4_get_ip4_config): MTU stuff is now handled in the device subclasses themselves, so that each device can override the MTU from it's NMSetting subclass if needed - (nm_device_set_ip4_config): set MTU when setting up routes and stuff in NetworkManagerSystem.c, not here * src/named-manager/nm-named-manager.c src/named-manager/nm-named-manager.h - (nm_named_manager_name_owner_changed, nm_named_manager_dbus_connection_changed): fix for changes to rewrite_resolv_conf() - (compute_nameservers): don't need the NMNamedManager at all, remove from parameter list - (merge_one_ip4_config): new function; merge ip4 configs together - (rewrite_resolv_conf): write out resolv.conf from all the stored ip4 configs; the VPN config takes precedence, then the best device config, then the rest of the configs - (get_domain_for_config): take the NMNamedManager as an argument to check whether the config is the VPN config - (add_ip4_config_to_named): fixups for removal of the 'secondary' attribute from ip4 configs - (add_all_ip4_configs_to_named): add all the configs in priority order - (remove_ip4_config_from_named): fix for changes to get_domain_for_config() - (nm_named_manager_add_ip4_config): assign the config to the right slot based on its type; callers must pass in the type now - (get_last_default_domain): remove, unused - (nm_named_manager_remove_ip4_config): handle config slots correctly * src/nm-device-802-11-wireless.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): handle MTU override * src/nm-device-802-3-ethernet.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): new function; handle MTU override * src/vpn-manager/nm-vpn-connection.c - (nm_vpn_connection_ip4_config_get): don't need to set the 'secondary' attribute on the ip4 config * src/NetworkManagerPolicy.c - (nm_policy_auto_get_best_device): remove - (nm_policy_device_change_check): remove - (update_default_route): new function; set the default route via the specified device - (get_device_priority): new function; return the priority number of a device type WRT which one should have the default route. Order is (highest to lowest) wired, wireless, GSM, CDMA. - (update_routing_and_dns): new function; determine which device should have the default route, then update the routing table and DNS - (maybe_auto_activate_device): new function; if a device is now available for activation, find out what connection it would like to activate and do it - (schedule_activate_check): new function; if a device can be activated now, schedule the activation. Each device may have only one pending activation at a given time. - (device_state_changed): if activation was canceled, try again, possibly with another connection; if the device was activated, update routing and DNS; if the device was deactivated, try again with another connection - (device_carrier_changed): if there is no carrier, deactivate the device; otherwise schedule an activation check for the device - (wireless_networks_changed): schedule an activation check for the device - (device_added): keep track of the signal handler IDs so they can be removed when the device goes away - (device_removed): remove any signal handlers that might be attached to the device; update routing and DNS - (schedule_activate_all): new function - (connections_added, connection_added, connection_updated): when connections change, schedule all devices for an activation check - (connection_removed): when a device is deactivated because its connection was removed, schedule another activation check for it - (nm_policy_destroy): destroy pending activations and disconnect all device signal handlers * src/nm-manager.c - (nm_manager_activate_device): if the device was already actived, deactivate it - (deactivate_old_device): remove - (connection_added_default_handler, impl_manager_activate_device): don't deactivate other devices when activating this one * src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerArch.c src/backends/NetworkManagerSuSE.c src/backends/NetworkManagerDebian.c - (nm_system_get_mtu): remove; MTU should be provided through the distro's system settings service plugin instead - (nm_system_device_add_default_route_via_device): remove - (nm_system_device_add_default_route_via_device_with_iface): remove - (nm_system_device_replace_default_route): new function; call generic implementation * src/backends/NetworkManagerGeneric.c src/backends/NetworkManagerGeneric.h - (nm_generic_device_add_default_route_via_device, nm_generic_device_add_default_route_via_device_with_iface): remove - (nm_generic_device_replace_default_route): replace the default route with the given route via some gateway * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_from_ip4_config): let the policy handle updates to routing and DNS; but set the MTU here - (nm_system_vpn_device_set_from_ip4_config): set the route with the ip_iface of the active device; use the standard MTU setting function - (nm_system_set_mtu): remove - (nm_system_device_set_mtu): consolidate MTU setting code in one place git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3391 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-03-07 19:41:32 +00:00
const char *
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
nm_device_get_ip_iface (NMDevice *self)
{
2009-07-07 14:34:01 -04:00
NMDevicePrivate *priv;
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
g_return_val_if_fail (self != NULL, NULL);
2009-07-07 14:34:01 -04:00
priv = NM_DEVICE_GET_PRIVATE (self);
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
/* If it's not set, default to iface */
2009-07-07 14:34:01 -04:00
return priv->ip_iface ? priv->ip_iface : priv->iface;
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
}
int
nm_device_get_ip_ifindex (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_val_if_fail (self != NULL, 0);
priv = NM_DEVICE_GET_PRIVATE (self);
/* If it's not set, default to ifindex */
return priv->ip_iface ? priv->ip_ifindex : priv->ifindex;
}
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
void
nm_device_set_ip_iface (NMDevice *self, const char *iface)
{
NMDevicePrivate *priv;
char *old_ip_iface;
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
if (!g_strcmp0 (iface, priv->ip_iface))
return;
old_ip_iface = priv->ip_iface;
priv->ip_ifindex = 0;
priv->ip_iface = g_strdup (iface);
if (priv->ip_iface) {
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface);
if (priv->ip_ifindex > 0) {
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET))
nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ip_ifindex, TRUE);
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_is_up (NM_PLATFORM_GET, priv->ip_ifindex))
nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL);
} else {
/* Device IP interface must always be a kernel network interface */
_LOGW (LOGD_HW, "failed to look up interface index");
}
}
/* We don't care about any saved values from the old iface */
g_hash_table_remove_all (priv->ip6_saved_properties);
/* Emit change notification */
if (g_strcmp0 (old_ip_iface, priv->ip_iface))
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
g_free (old_ip_iface);
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
}
static gboolean
get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMLinkType link_type;
const guint8 *hwaddr = NULL;
size_t hwaddr_len = 0;
int ifindex;
gboolean success;
/* If we get here, we *must* have a kernel netdev, which implies an ifindex */
ifindex = nm_device_get_ip_ifindex (self);
g_assert (ifindex);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
link_type = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex);
g_return_val_if_fail (link_type > NM_LINK_TYPE_UNKNOWN, 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddr_len);
if (!hwaddr_len)
return FALSE;
success = nm_utils_get_ipv6_interface_identifier (link_type,
hwaddr,
hwaddr_len,
priv->dev_id,
out_iid);
if (!success) {
_LOGW (LOGD_HW, "failed to generate interface identifier "
"for link type %u hwaddr_len %zu", link_type, hwaddr_len);
}
return success;
}
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
static gboolean
nm_device_get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *iid)
{
return NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, iid);
}
const char *
nm_device_get_driver (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
2009-07-07 14:34:01 -04:00
return NM_DEVICE_GET_PRIVATE (self)->driver;
}
const char *
nm_device_get_driver_version (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
return NM_DEVICE_GET_PRIVATE (self)->driver_version;
}
NMDeviceType
nm_device_get_device_type (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_TYPE_UNKNOWN);
2009-07-07 14:34:01 -04:00
return NM_DEVICE_GET_PRIVATE (self)->type;
}
/**
* nm_device_get_metered:
* @setting: the #NMDevice
*
* Returns: the #NMDevice:metered property of the device.
*
* Since: 1.2
**/
NMMetered
nm_device_get_metered (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NM_METERED_UNKNOWN);
return NM_DEVICE_GET_PRIVATE (self)->metered;
}
/**
* nm_device_get_priority():
* @self: the #NMDevice
*
* Returns: the device's routing priority. Lower numbers means a "better"
* device, eg higher priority.
*/
int
nm_device_get_priority (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), 1000);
/* Device 'priority' is used for the default route-metric and is based on
* the device type. The settings ipv4.route-metric and ipv6.route-metric
* can overwrite this default.
*
* Currently for both IPv4 and IPv6 we use the same default values.
*
* The route-metric is used for the metric of the routes of device.
* This also applies to the default route. Therefore it affects also
* which device is the "best".
*
* For comparison, note that iproute2 by default adds IPv4 routes with
* metric 0, and IPv6 routes with metric 1024. The latter is the IPv6
* "user default" in the kernel (NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6).
* In kernel, the full uint32_t range is available for route
* metrics (except for IPv6, where 0 means 1024).
*/
switch (nm_device_get_device_type (self)) {
/* 50 is reserved for VPN (NM_VPN_ROUTE_METRIC_DEFAULT) */
case NM_DEVICE_TYPE_ETHERNET:
return 100;
case NM_DEVICE_TYPE_INFINIBAND:
return 150;
case NM_DEVICE_TYPE_ADSL:
return 200;
case NM_DEVICE_TYPE_WIMAX:
return 250;
case NM_DEVICE_TYPE_BOND:
return 300;
case NM_DEVICE_TYPE_TEAM:
return 350;
case NM_DEVICE_TYPE_VLAN:
return 400;
case NM_DEVICE_TYPE_BRIDGE:
return 425;
case NM_DEVICE_TYPE_TUN:
return 450;
case NM_DEVICE_TYPE_WIFI:
return 600;
case NM_DEVICE_TYPE_OLPC_MESH:
return 650;
case NM_DEVICE_TYPE_IP_TUNNEL:
return 675;
case NM_DEVICE_TYPE_MODEM:
return 700;
case NM_DEVICE_TYPE_BT:
return 750;
case NM_DEVICE_TYPE_GENERIC:
return 950;
case NM_DEVICE_TYPE_UNKNOWN:
return 10000;
case NM_DEVICE_TYPE_UNUSED1:
case NM_DEVICE_TYPE_UNUSED2:
/* omit default: to get compiler warning about missing switch cases */
break;
}
return 11000;
}
static guint32
_get_ipx_route_metric (NMDevice *self,
gboolean is_v4)
{
char *value;
gint64 route_metric;
NMSettingIPConfig *s_ip;
NMConnection *connection;
g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32);
connection = nm_device_get_applied_connection (self);
if (connection) {
s_ip = is_v4
? nm_connection_get_setting_ip4_config (connection)
: nm_connection_get_setting_ip6_config (connection);
/* Slave interfaces don't have IP settings, but we may get here when
* external changes are made or when noticing IP changes when starting
* the slave connection.
*/
if (s_ip) {
route_metric = nm_setting_ip_config_get_route_metric (s_ip);
if (route_metric >= 0)
goto out;
}
}
/* use the current NMConfigData, which makes this configuration reloadable.
* Note that that means that the route-metric might change between SIGHUP.
* You must cache the returned value if that is a problem. */
value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
is_v4 ? "ipv4.route-metric" : "ipv6.route-metric", self);
if (value) {
route_metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
g_free (value);
if (route_metric >= 0)
goto out;
}
route_metric = nm_device_get_priority (self);
out:
if (!is_v4)
route_metric = nm_utils_ip6_route_metric_normalize (route_metric);
return route_metric;
}
guint32
nm_device_get_ip4_route_metric (NMDevice *self)
{
return _get_ipx_route_metric (self, TRUE);
}
guint32
nm_device_get_ip6_route_metric (NMDevice *self)
{
return _get_ipx_route_metric (self, FALSE);
}
const NMPlatformIP4Route *
nm_device_get_ip4_default_route (NMDevice *self, gboolean *out_is_assumed)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
priv = NM_DEVICE_GET_PRIVATE (self);
if (out_is_assumed)
*out_is_assumed = priv->default_route.v4_is_assumed;
return priv->default_route.v4_has ? &priv->default_route.v4 : NULL;
}
const NMPlatformIP6Route *
nm_device_get_ip6_default_route (NMDevice *self, gboolean *out_is_assumed)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
priv = NM_DEVICE_GET_PRIVATE (self);
if (out_is_assumed)
*out_is_assumed = priv->default_route.v6_is_assumed;
return priv->default_route.v6_has ? &priv->default_route.v6 : NULL;
}
const char *
nm_device_get_type_desc (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
2009-07-07 14:34:01 -04:00
return NM_DEVICE_GET_PRIVATE (self)->type_desc;
}
const char *
nm_device_get_type_description (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
/* Beware: this function should return the same
* value as nm_device_get_type_description() in libnm. */
return NM_DEVICE_GET_CLASS (self)->get_type_description (self);
}
static const char *
get_type_description (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->type_description) {
const char *typename;
typename = G_OBJECT_TYPE_NAME (self);
if (g_str_has_prefix (typename, "NMDevice"))
typename += 8;
priv->type_description = g_ascii_strdown (typename, -1);
}
return priv->type_description;
}
gboolean
nm_device_has_carrier (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->carrier;
}
NMActRequest *
nm_device_get_act_request (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
return NM_DEVICE_GET_PRIVATE (self)->act_request;
}
NMSettingsConnection *
nm_device_get_settings_connection (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
return priv->act_request ? nm_act_request_get_settings_connection (priv->act_request) : NULL;
}
NMConnection *
nm_device_get_applied_connection (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
return priv->act_request ? nm_act_request_get_applied_connection (priv->act_request) : NULL;
}
gboolean
nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFlags compare_flags)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->act_request)
return FALSE;
return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request, compare_flags);
}
RfKillType
nm_device_get_rfkill_type (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
return NM_DEVICE_GET_PRIVATE (self)->rfkill_type;
}
static const char *
nm_device_get_physical_port_id (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->physical_port_id;
}
/***********************************************************/
static gboolean
nm_device_uses_generated_assumed_connection (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingsConnection *connection;
if ( priv->act_request
&& nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (priv->act_request))) {
connection = nm_act_request_get_settings_connection (priv->act_request);
if ( connection
&& nm_settings_connection_get_nm_generated_assumed (connection))
return TRUE;
}
return FALSE;
}
gboolean
nm_device_uses_assumed_connection (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if ( priv->act_request
&& nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (priv->act_request)))
return TRUE;
return FALSE;
}
2012-11-14 14:05:30 -06:00
static SlaveInfo *
find_slave_info (NMDevice *self, NMDevice *slave)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
SlaveInfo *info;
GSList *iter;
for (iter = priv->slaves; iter; iter = g_slist_next (iter)) {
info = iter->data;
if (info->slave == slave)
return info;
}
return NULL;
}
static void
free_slave_info (SlaveInfo *info)
{
g_signal_handler_disconnect (info->slave, info->watch_id);
g_clear_object (&info->slave);
memset (info, 0, sizeof (*info));
g_free (info);
}
/**
* nm_device_master_enslave_slave:
* @self: the master device
* @slave: the slave device to enslave
* @connection: (allow-none): the slave device's connection
*
* If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function enslaves @slave.
*
* Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave
* other devices.
*/
2012-11-14 14:05:30 -06:00
static gboolean
nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connection)
{
2012-11-14 14:05:30 -06:00
SlaveInfo *info;
gboolean success = FALSE;
gboolean configure;
2012-11-14 14:05:30 -06:00
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (slave != NULL, FALSE);
g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE);
info = find_slave_info (self, slave);
2012-11-14 14:05:30 -06:00
if (!info)
return FALSE;
if (info->slave_is_enslaved)
success = TRUE;
else {
configure = (info->configure && connection != NULL);
if (configure)
g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
success = NM_DEVICE_GET_CLASS (self)->enslave_slave (self, slave, connection, configure);
info->slave_is_enslaved = success;
}
nm_device_slave_notify_enslave (info->slave, success);
/* Ensure the device's hardware address is up-to-date; it often changes
* when slaves change.
*/
nm_device_update_hw_address (self);
/* Restart IP configuration if we're waiting for slaves. Do this
* after updating the hardware address as IP config may need the
* new address.
*/
if (success) {
if (NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_WAIT)
nm_device_activate_stage3_ip4_start (self);
if (NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_WAIT)
nm_device_activate_stage3_ip6_start (self);
}
2012-11-14 14:05:30 -06:00
return success;
}
/**
* nm_device_master_release_one_slave:
* @self: the master device
* @slave: the slave device to release
* @configure: whether @self needs to actually release @slave
device: fix warning releasing of slave when slave device gets removed When the slave device gets removed, the master is not in a state-change when calling nm_device_release_one_slave(). This triggers a warning [1]. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c144c "NetworkManager", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fff8b1d35b0) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x3370cc1fdc "%s") at gmessages.c:1025 #2 0x0000003370c50956 in g_warn_message (domain=domain@entry=0x4c144c "NetworkManager", file=file@entry=0x4b14d5 "devices/nm-device.c", line=line@entry=841, func=func@entry=0x4b48f0 <__FUNCTION__.35456> "nm_device_release_one_slave", warnexpr=warnexpr@entry=0x0) at gmessages.c:1058 #3 0x0000000000436c30 in nm_device_release_one_slave (dev=dev@entry=0xd92540, slave=slave@entry=0xdb0e50, configure=configure@entry=1) at devices/nm-device.c:841 #4 0x000000000043a779 in slave_state_changed (slave=0xdb0e50, slave_new_state=NM_DEVICE_STATE_UNMANAGED, slave_old_state=NM_DEVICE_STATE_ACTIVATED, reason=<optimized out>, self=0xd92540) at devices/nm-device.c:1214 #5 0x0000003371805d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #6 0x00000033718056bc in ffi_call (cif=cif@entry=0x7fff8b1d3a00, fn=0x43a677 <slave_state_changed>, rvalue=0x7fff8b1d3970, avalue=avalue@entry=0x7fff8b1d38f0) at ../src/x86/ffi64.c:522 #7 0x0000003371c10ad8 in g_cclosure_marshal_generic (closure=0xd76120, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #8 0x0000003371c10298 in g_closure_invoke (closure=0xd76120, return_value=return_value@entry=0x0, n_param_values=4, param_values=param_values@entry=0x7fff8b1d3c00, invocation_hint=invocation_hint@entry=0x7fff8b1d3ba0) at gclosure.c:777 #9 0x0000003371c2235d in signal_emit_unlocked_R (node=node@entry=0xd9d850, detail=detail@entry=0, instance=instance@entry=0xdb0e50, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff8b1d3c00) at gsignal.c:3586 #10 0x0000003371c2a0f2 in g_signal_emit_valist (instance=instance@entry=0xdb0e50, signal_id=signal_id@entry=68, detail=detail@entry=0, var_args=var_args@entry=0x7fff8b1d3e38) at gsignal.c:3330 #11 0x0000003371c2a8f8 in g_signal_emit_by_name (instance=instance@entry=0xdb0e50, detailed_signal=detailed_signal@entry=0x4c3ce2 "state-changed") at gsignal.c:3426 #12 0x000000000043754f in _set_state_full (device=device@entry=0xdb0e50, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6689 #13 0x000000000043797c in nm_device_state_changed (device=device@entry=0xdb0e50, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #14 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0xdb0e50, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #15 0x00000000004799c2 in remove_device (manager=manager@entry=0xd86150, device=0xdb0e50, quitting=quitting@entry=0) at nm-manager.c:769 #16 0x000000000047e3bf in platform_link_cb (platform=<optimized out>, ifindex=35, plink=<optimized out>, change_type=<optimized out>, reason=<optimized out>, user_data=<optimized out>) at nm-manager.c:2123 #17 0x0000003371805d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #18 0x00000033718056bc in ffi_call (cif=cif@entry=0x7fff8b1d4320, fn=0x47e34b <platform_link_cb>, rvalue=0x7fff8b1d4290, avalue=avalue@entry=0x7fff8b1d4210) at ../src/x86/ffi64.c:522 #19 0x0000003371c10ad8 in g_cclosure_marshal_generic (closure=0xd32e40, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #20 0x0000003371c10298 in g_closure_invoke (closure=0xd32e40, return_value=return_value@entry=0x0, n_param_values=5, param_values=param_values@entry=0x7fff8b1d4520, invocation_hint=invocation_hint@entry=0x7fff8b1d44c0) at gclosure.c:777 #21 0x0000003371c2235d in signal_emit_unlocked_R (node=node@entry=0xcf5780, detail=detail@entry=0, instance=instance@entry=0xcf78a0, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff8b1d4520) at gsignal.c:3586 #22 0x0000003371c2a0f2 in g_signal_emit_valist (instance=instance@entry=0xcf78a0, signal_id=signal_id@entry=2, detail=detail@entry=0, var_args=var_args@entry=0x7fff8b1d4778) at gsignal.c:3330 #23 0x0000003371c2a8f8 in g_signal_emit_by_name (instance=instance@entry=0xcf78a0, detailed_signal=detailed_signal@entry=0x4b183d "link-changed") at gsignal.c:3426 #24 0x000000000044c6f3 in announce_object (platform=platform@entry=0xcf78a0, object=0xde1720, change_type=change_type@entry=NM_PLATFORM_SIGNAL_REMOVED, reason=reason@entry=NM_PLATFORM_REASON_EXTERNAL) at platform/nm-linux-platform.c:1572 #25 0x000000000044ec07 in event_notification (msg=<optimized out>, user_data=<optimized out>) at platform/nm-linux-platform.c:1886 #26 0x0000003844c1117f in nl_cb_call (msg=<optimized out>, type=<optimized out>, cb=<optimized out>) at ../include/netlink-private/netlink.h:141 #27 recvmsgs (cb=0xcf7240, sk=0xcf7330) at nl.c:952 #28 nl_recvmsgs_report (sk=0xcf7330, cb=0xcf7240) at nl.c:1003 #29 0x0000003844c11549 in nl_recvmsgs (sk=<optimized out>, cb=<optimized out>) at nl.c:1027 #30 0x0000003844c11569 in nl_recvmsgs_default (sk=<optimized out>) at nl.c:1041 #31 0x000000000044e955 in event_handler (channel=<optimized out>, io_condition=<optimized out>, user_data=0xcf78a0) at platform/nm-linux-platform.c:3804 #32 0x0000003370c492a6 in g_main_dispatch (context=0xcf5190) at gmain.c:3066 #33 g_main_context_dispatch (context=context@entry=0xcf5190) at gmain.c:3642 #34 0x0000003370c49628 in g_main_context_iterate (context=0xcf5190, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713 #35 0x0000003370c49a3a in g_main_loop_run (loop=0xcf4e30) at gmain.c:3907 #36 0x0000000000429f15 in main (argc=1, argv=0x7fff8b1d4f38) at main.c:678 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 11:18:45 +02:00
* @reason: the state change reason for the @slave
*
* If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function releases the previously enslaved @slave and/or
* updates the state of @self and @slave to reflect its release.
*
* Returns: %TRUE on success, %FALSE on failure, if this device cannot enslave
* other devices, or if @slave was never enslaved.
*/
2012-11-14 14:05:30 -06:00
static gboolean
nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure, NMDeviceStateReason reason)
2012-11-14 14:05:30 -06:00
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2012-11-14 14:05:30 -06:00
SlaveInfo *info;
gboolean success = FALSE;
g_return_val_if_fail (slave != NULL, FALSE);
g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->release_slave != NULL, FALSE);
2012-11-14 14:05:30 -06:00
info = find_slave_info (self, slave);
2012-11-14 14:05:30 -06:00
if (!info)
return FALSE;
priv->slaves = g_slist_remove (priv->slaves, info);
2012-11-14 14:05:30 -06:00
if (info->slave_is_enslaved)
NM_DEVICE_GET_CLASS (self)->release_slave (self, slave, configure);
nm_device_slave_notify_release (info->slave, reason);
2012-11-14 14:05:30 -06:00
free_slave_info (info);
/* Ensure the device's hardware address is up-to-date; it often changes
* when slaves change.
*/
nm_device_update_hw_address (self);
2012-11-14 14:05:30 -06:00
return success;
}
/**
* can_unmanaged_external_down:
* @self: the device
*
* Check whether the device should stay NM_UNMANAGED_EXTERNAL_DOWN unless
* IFF_UP-ed externally.
*/
static gboolean
can_unmanaged_external_down (NMDevice *self)
{
return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
}
/**
* nm_device_finish_init:
* @self: the master device
*
* Whatever needs to be done post-initialization, when the device has a DBus
* object name.
*/
void
nm_device_finish_init (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_assert (priv->initialized == FALSE);
/* Do not manage externally created software devices until they are IFF_UP */
if ( NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)
&& priv->ifindex > 0
&& ( !priv->up
|| !priv->platform_link_initialized))
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE);
if (priv->master)
nm_device_master_enslave_slave (priv->master, self, NULL);
if (priv->ifindex > 0) {
if (priv->ifindex == 1) {
/* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag.
* Later we might want to manage 'lo' too. Currently that doesn't work because
* NetworkManager might down the interface or remove the 127.0.0.1 address. */
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_LOOPBACK, TRUE);
} else if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) {
gboolean platform_unmanaged = FALSE;
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged))
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_DEFAULT, platform_unmanaged);
} else {
/* Hardware and externally-created software links stay unmanaged
* until they are fully initialized by the platform. NM created
* links must be available for activation immediately and thus
* do not get the PLATFORM_INIT unmanaged flag set.
*/
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
}
}
priv->initialized = TRUE;
}
static void
update_dynamic_ip_setup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GError *error;
gconstpointer addr;
size_t addr_length;
g_hash_table_remove_all (priv->ip6_saved_properties);
if (priv->dhcp4_client) {
if (!nm_device_dhcp4_renew (self, FALSE)) {
nm_device_state_changed (self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_DHCP_FAILED);
return;
}
}
if (priv->dhcp6_client) {
if (!nm_device_dhcp6_renew (self, FALSE)) {
nm_device_state_changed (self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_DHCP_FAILED);
return;
}
}
if (priv->rdisc) {
/* FIXME: todo */
}
if (priv->dnsmasq_manager) {
/* FIXME: todo */
}
if (priv->lldp_listener && nm_lldp_listener_is_running (priv->lldp_listener)) {
nm_lldp_listener_stop (priv->lldp_listener);
addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length);
if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self),
nm_device_get_iface (self), addr, addr_length, &error)) {
_LOGD (LOGD_DEVICE, "LLDP listener %p could not be restarted: %s",
priv->lldp_listener, error->message);
g_clear_error (&error);
}
}
}
static void
carrier_changed (NMDevice *self, gboolean carrier)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!nm_device_get_managed (self))
return;
nm_device_recheck_available_connections (self);
/* ignore-carrier devices ignore all carrier-down events */
if (priv->ignore_carrier && !carrier)
return;
if (priv->is_master) {
/* Bridge/bond/team carrier does not affect its own activation,
* but when carrier comes on, if there are slaves waiting,
* it will restart them.
*/
if (!carrier)
return;
if (nm_device_activate_ip4_state_in_wait (self))
nm_device_activate_stage3_ip4_start (self);
if (nm_device_activate_ip6_state_in_wait (self))
nm_device_activate_stage3_ip6_start (self);
return;
} else if (nm_device_get_enslaved (self) && !carrier) {
/* Slaves don't deactivate when they lose carrier; for
* bonds/teams in particular that would be actively
* counterproductive.
*/
return;
}
if (carrier) {
g_warn_if_fail (priv->state >= NM_DEVICE_STATE_UNAVAILABLE);
if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) {
nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_CARRIER);
} else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) {
/* If the device is already in DISCONNECTED state without a carrier
* (probably because it is tagged for carrier ignore) ensure that
* when the carrier appears, auto connections are rechecked for
* the device.
*/
nm_device_emit_recheck_auto_activate (self);
} else if (priv->state == NM_DEVICE_STATE_ACTIVATED) {
/* If the device is active without a carrier (probably because it is
* tagged for carrier ignore) ensure that when the carrier appears we
* renew DHCP leases and such.
*/
update_dynamic_ip_setup (self);
}
} else {
g_return_if_fail (priv->state >= NM_DEVICE_STATE_UNAVAILABLE);
if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) {
if (nm_device_queued_state_peek (self) >= NM_DEVICE_STATE_DISCONNECTED)
nm_device_queued_state_clear (self);
} else {
nm_device_queue_state (self, NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_CARRIER);
}
}
}
#define LINK_DISCONNECT_DELAY 4
static gboolean
link_disconnect_action_cb (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
_LOGD (LOGD_DEVICE, "link disconnected (calling deferred action) (id=%u)", priv->carrier_defer_id);
priv->carrier_defer_id = 0;
_LOGI (LOGD_DEVICE, "link disconnected (calling deferred action)");
NM_DEVICE_GET_CLASS (self)->carrier_changed (self, FALSE);
return FALSE;
}
static void
link_disconnect_action_cancel (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->carrier_defer_id) {
g_source_remove (priv->carrier_defer_id);
_LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)", priv->carrier_defer_id);
priv->carrier_defer_id = 0;
}
}
void
nm_device_set_carrier (NMDevice *self, gboolean carrier)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
NMDeviceState state = nm_device_get_state (self);
if (priv->carrier == carrier)
return;
priv->carrier = carrier;
g_object_notify (G_OBJECT (self), NM_DEVICE_CARRIER);
if (priv->carrier) {
_LOGI (LOGD_DEVICE, "link connected");
link_disconnect_action_cancel (self);
klass->carrier_changed (self, TRUE);
if (nm_clear_g_source (&priv->carrier_wait_id)) {
nm_device_remove_pending_action (self, "carrier wait", TRUE);
_carrier_wait_check_queued_act_request (self);
}
} else if (state <= NM_DEVICE_STATE_DISCONNECTED) {
_LOGI (LOGD_DEVICE, "link disconnected");
klass->carrier_changed (self, FALSE);
} else {
_LOGI (LOGD_DEVICE, "link disconnected (deferring action for %d seconds)", LINK_DISCONNECT_DELAY);
priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY,
link_disconnect_action_cb, self);
_LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)",
LINK_DISCONNECT_DELAY, priv->carrier_defer_id);
}
}
static void
device_recheck_slave_status (NMDevice *self, NMPlatformLink *plink)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (plink != NULL);
if (priv->is_enslaved && plink->master != nm_device_get_ifindex (priv->master))
nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
if (plink->master && !priv->is_enslaved) {
NMDevice *master;
master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master);
if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) {
g_clear_object (&priv->master);
priv->master = g_object_ref (master);
nm_device_master_add_slave (master, self, FALSE);
} else if (master) {
_LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring",
nm_device_get_iface (master));
} else {
_LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s",
plink->master,
nm_platform_link_get_name (NM_PLATFORM_GET, plink->master));
}
}
}
static gboolean
device_link_changed (NMDevice *self)
{
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMUtilsIPv6IfaceId token_iid;
gboolean ip_ifname_changed = FALSE;
const char *udi;
NMPlatformLink info;
const NMPlatformLink *pllink;
int ifindex;
gboolean emit_link_initialized = FALSE;
gboolean was_up;
priv->device_link_changed_id = 0;
ifindex = nm_device_get_ifindex (self);
pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
if (!pllink)
return G_SOURCE_REMOVE;
info = *pllink;
udi = nm_platform_link_get_udi (NM_PLATFORM_GET, info.ifindex);
if (udi && g_strcmp0 (udi, priv->udi)) {
/* Update UDI to what udev gives us */
g_free (priv->udi);
priv->udi = g_strdup (udi);
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
}
if (g_strcmp0 (info.driver, priv->driver)) {
/* Update driver to what udev gives us */
g_free (priv->driver);
priv->driver = g_strdup (info.driver);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
/* Update MTU if it has changed. */
if (priv->mtu != info.mtu) {
priv->mtu = info.mtu;
g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
}
if (info.driver && g_strcmp0 (priv->driver, info.driver) != 0) {
g_free (priv->driver);
priv->driver = g_strdup (info.driver);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
if (info.name[0] && strcmp (priv->iface, info.name) != 0) {
_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
priv->ifindex, priv->iface, info.name);
g_free (priv->iface);
priv->iface = g_strdup (info.name);
/* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */
ip_ifname_changed = !priv->ip_iface;
g_object_notify (G_OBJECT (self), NM_DEVICE_IFACE);
if (ip_ifname_changed)
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
/* Re-match available connections against the new interface name */
nm_device_recheck_available_connections (self);
/* Let any connections that use the new interface name have a chance
* to auto-activate on the device.
*/
nm_device_emit_recheck_auto_activate (self);
2013-12-16 15:16:43 +01:00
}
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) {
_LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
if (nm_rdisc_set_iid (priv->rdisc, token_iid))
nm_rdisc_start (priv->rdisc);
}
if (klass->link_changed)
klass->link_changed (self, &info);
/* Update DHCP, etc, if needed */
if (ip_ifname_changed)
update_dynamic_ip_setup (self);
if (priv->ifindex > 0 && !priv->platform_link_initialized && info.initialized) {
gboolean platform_unmanaged = FALSE;
priv->platform_link_initialized = TRUE;
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_DEFAULT,
platform_unmanaged,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
}
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_PLATFORM_INIT,
FALSE,
NM_DEVICE_STATE_REASON_NOW_MANAGED);
emit_link_initialized = TRUE;
}
was_up = priv->up;
priv->up = NM_FLAGS_HAS (info.flags, IFF_UP);
if ( priv->platform_link_initialized
&& (emit_link_initialized || priv->up != was_up)) {
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
/* Manage externally-created software interfaces only when they are IFF_UP */
g_assert (priv->ifindex > 0);
if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
gboolean external_down = !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN);
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
if (external_down && NM_FLAGS_HAS (info.flags, IFF_UP)) {
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) {
/* Ensure the assume check is queued before any queued state changes
* from the transition to UNAVAILABLE.
*/
nm_device_queue_recheck_assume (self);
/* Resetting the EXTERNAL_DOWN flag may change the device's state
* to UNAVAILABLE. To ensure that the state change doesn't touch
* the device before assumption occurs, pass
* NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED as the reason.
*/
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_EXTERNAL_DOWN,
FALSE,
NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
} else {
/* Don't trigger a state change; if the device is in a
* state higher than UNAVAILABLE, it is already IFF_UP
* or an explicit activation request was received.
*/
_set_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN, FALSE);
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
}
} else if (!external_down && !NM_FLAGS_HAS (info.flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
/* If the device is already disconnected and is set !IFF_UP,
* unmanage it.
*/
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_EXTERNAL_DOWN,
TRUE,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
core: fix re-activation of connections on EXTERNAL_DOWN interfaces (bgo #741742) When userspace IPv6LL capability is compiled into NetworkManager, during deactivation NM will toggle userspace IPv6LL in some cases. This causes link change events in the platform, which show up in nm-device.c::device_link_changed(). When an EXTERNAL_DOWN interface was activated, the EXTERNAL_DOWN flag was never cleared even if the device was set IFF_UP or if a connection was activated via D-Bus (which explicitly sets the device up). Second, the device_link_changed() code changed device state whether or not IFF_UP had actually changed, it simply looked at the current value. Together, this caused the first activation of an EXTERNAL_DOWN device to succeed, but the EXTERNAL_DOWN flag was never cleared even though the activation set the device IFF_UP. When a second activation request came in, the device was moved to DISCONNECTED state and IPv6LL genmode was reset, causing device_link_changed() to run. Since the device had EXTERNAL_DOWN and IFF_UP were still set, nm_device_set_unmanaged_flag() code was triggered to clear EXTERNAL_DOWN, which resulted in a state transition to UNAVAILABLE with a reason of CONNECTION_ASSUMED. This caused the second activation request to fail because UNAVAILABLE devices cannot activate connections by definition. The fix has three parts: 1) Only change EXTERNAL_DOWN if IFF_UP actually changes, to prevent spurious changes when something other than IFF_UP changes 2) Only clear EXTERNAL_DOWN when IFF_UP changes while the device is UNMANAGED, since any state higher than UNMANAGED implies that either an activation request was received (and thus the device should be managed) or IFF_UP was set 3) Clear EXTERNAL_DOWN (without triggering state changes) when any state higher than UNAVAILABLE is entered, since this implies that a connection is activating or the device is no longer IFF_UP fixes:NetworkManager_Test108_testcase_303655 https://bugzilla.gnome.org/show_bug.cgi?id=741742
2014-12-18 23:38:37 -06:00
}
}
}
if (emit_link_initialized)
g_signal_emit (self, signals[LINK_INITIALIZED], 0);
device_recheck_slave_status (self, &info);
return G_SOURCE_REMOVE;
}
static gboolean
device_ip_link_changed (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const NMPlatformLink *pllink;
int ip_ifindex;
priv->device_ip_link_changed_id = 0;
ip_ifindex = nm_device_get_ip_ifindex (self);
pllink = nm_platform_link_get (NM_PLATFORM_GET, ip_ifindex);
if (!pllink)
return G_SOURCE_REMOVE;
if (pllink->name[0] && g_strcmp0 (priv->ip_iface, pllink->name)) {
_LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'",
priv->ifindex, nm_device_get_ip_ifindex (self),
priv->ip_iface, pllink->name);
g_free (priv->ip_iface);
priv->ip_iface = g_strdup (pllink->name);
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
update_dynamic_ip_setup (self);
}
return G_SOURCE_REMOVE;
}
static void
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
link_changed_cb (NMPlatform *platform,
NMPObjectType obj_type,
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
int ifindex,
NMPlatformLink *info,
NMPlatformSignalChangeType change_type,
NMDevice *self)
{
NMDevicePrivate *priv;
if (change_type != NM_PLATFORM_SIGNAL_CHANGED)
return;
priv = NM_DEVICE_GET_PRIVATE (self);
if (ifindex == nm_device_get_ifindex (self)) {
if (!priv->device_link_changed_id) {
priv->device_link_changed_id = g_idle_add ((GSourceFunc) device_link_changed, self);
_LOGD (LOGD_DEVICE, "queued link change for ifindex %d", ifindex);
}
} else if (ifindex == nm_device_get_ip_ifindex (self)) {
if (!priv->device_ip_link_changed_id) {
priv->device_ip_link_changed_id = g_idle_add ((GSourceFunc) device_ip_link_changed, self);
_LOGD (LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex);
}
}
}
static void
link_changed (NMDevice *self, NMPlatformLink *info)
{
/* Update carrier from link event if applicable. */
if ( nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)
&& !nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER))
nm_device_set_carrier (self, info->connected);
}
static gboolean
link_type_compatible (NMDevice *self,
NMLinkType link_type,
gboolean *out_compatible,
GError **error)
{
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
guint i = 0;
if (!klass->link_types) {
NM_SET_OUT (out_compatible, FALSE);
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"Device does not support platform links");
return FALSE;
}
for (i = 0; klass->link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) {
if (klass->link_types[i] == link_type)
return TRUE;
if (klass->link_types[i] == NM_LINK_TYPE_ANY)
return TRUE;
}
NM_SET_OUT (out_compatible, FALSE);
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"Device does not support platform link type 0x%X",
link_type);
return FALSE;
}
/**
* nm_device_realize():
* @self: the #NMDevice
* @plink: an existing platform link or %NULL
* @out_compatible: %TRUE on return if @self is compatible with @plink
* @error: location to store error, or %NULL
*
* Initializes and sets up the device using existing backing resources. Before
* the device is ready for use nm_device_setup_finish() must be called.
* @out_compatible will only be set if @plink is not %NULL, and
*
* Returns: %TRUE on success, %FALSE on error
*/
gboolean
nm_device_realize (NMDevice *self,
NMPlatformLink *plink,
gboolean *out_compatible,
GError **error)
{
NM_SET_OUT (out_compatible, TRUE);
if (plink) {
if (g_strcmp0 (nm_device_get_iface (self), plink->name) != 0) {
NM_SET_OUT (out_compatible, FALSE);
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"Device interface name does not match platform link");
return FALSE;
}
if (!link_type_compatible (self, plink->type, out_compatible, error))
return FALSE;
}
/* Try to realize the device from existing resources */
if (NM_DEVICE_GET_CLASS (self)->realize) {
if (!NM_DEVICE_GET_CLASS (self)->realize (self, plink, error))
return FALSE;
}
NM_DEVICE_GET_CLASS (self)->setup_start (self, plink);
return TRUE;
}
/**
* nm_device_create_and_realize():
* @self: the #NMDevice
* @connection: the #NMConnection being activated
* @parent: the parent #NMDevice if any
* @error: location to store error, or %NULL
*
* Creates any backing resources needed to realize the device to proceed
* with activating @connection.
*
* Returns: %TRUE on success, %FALSE on error
*/
gboolean
nm_device_create_and_realize (NMDevice *self,
NMConnection *connection,
NMDevice *parent,
GError **error)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMPlatformLink plink = { .type = NM_LINK_TYPE_UNKNOWN };
/* Must be set before device is realized */
priv->is_nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface);
/* Create any resources the device needs */
if (NM_DEVICE_GET_CLASS (self)->create_and_realize) {
if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error))
return FALSE;
}
NM_DEVICE_GET_CLASS (self)->setup_start (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
nm_device_setup_finish (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE);
return TRUE;
}
static void
update_device_from_platform_link (NMDevice *self, NMPlatformLink *plink)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *udi;
g_return_if_fail (plink != NULL);
udi = nm_platform_link_get_udi (NM_PLATFORM_GET, plink->ifindex);
if (udi && !g_strcmp0 (udi, priv->udi)) {
g_free (priv->udi);
priv->udi = g_strdup (udi);
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
}
if (!g_strcmp0 (plink->name, priv->iface)) {
g_free (priv->iface);
priv->iface = g_strdup (plink->name);
g_object_notify (G_OBJECT (self), NM_DEVICE_IFACE);
}
priv->ifindex = plink->ifindex;
g_object_notify (G_OBJECT (self), NM_DEVICE_IFINDEX);
priv->up = NM_FLAGS_HAS (plink->flags, IFF_UP);
if (plink->driver && g_strcmp0 (plink->driver, priv->driver) != 0) {
g_free (priv->driver);
priv->driver = g_strdup (plink->driver);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
priv->platform_link_initialized = plink->initialized;
}
static void
config_changed_update_ignore_carrier (NMConfig *config,
NMConfigData *config_data,
NMConfigChangeFlags changes,
NMConfigData *old_data,
NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if ( priv->state <= NM_DEVICE_STATE_DISCONNECTED
|| priv->state > NM_DEVICE_STATE_ACTIVATED)
priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self);
}
static void
check_carrier (NMDevice *self)
{
int ifindex = nm_device_get_ip_ifindex (self);
if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER))
nm_device_set_carrier (self, nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
}
static void
setup_start (NMDevice *self, NMPlatformLink *plink)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
static guint32 id = 0;
/* The device should not be realized */
g_return_if_fail (priv->ip_ifindex <= 0);
g_return_if_fail (priv->ip_iface == NULL);
/* Balanced by a thaw in nm_device_setup_finish() */
g_object_freeze_notify (G_OBJECT (self));
if (plink) {
g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL));
update_device_from_platform_link (self, plink);
}
if (priv->ifindex > 0) {
_LOGD (LOGD_DEVICE, "setup_start(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex);
priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex);
g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID);
priv->dev_id = nm_platform_link_get_dev_id (NM_PLATFORM_GET, priv->ifindex);
if (nm_platform_link_is_software (NM_PLATFORM_GET, priv->ifindex))
priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE;
priv->mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex);
g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
nm_platform_link_get_driver_info (NM_PLATFORM_GET,
priv->ifindex,
NULL,
&priv->driver_version,
&priv->firmware_version);
if (priv->driver_version)
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER_VERSION);
if (priv->firmware_version)
g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_VERSION);
if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET))
priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ifindex);
}
if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities)
priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self);
if (!priv->udi) {
/* Use a placeholder UDI until we get a real one */
priv->udi = g_strdup_printf ("/virtual/device/placeholder/%d", id++);
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
}
/* trigger initial ip config change to initialize ip-config */
priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self);
priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
nm_device_update_hw_address (self);
if (priv->hw_addr_len) {
priv->initial_hw_addr = g_strdup (priv->hw_addr);
_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr);
if (priv->ifindex > 0) {
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
size_t len = 0;
if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) {
g_warn_if_fail (len == priv->hw_addr_len);
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s",
priv->perm_hw_addr);
} else {
/* Fall back to current address */
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address");
priv->perm_hw_addr = g_strdup (priv->hw_addr);
}
}
}
/* Note: initial hardware address must be read before calling get_ignore_carrier() */
if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
NMConfig *config = nm_config_get ();
priv->ignore_carrier = nm_config_data_get_ignore_carrier (nm_config_get_data (config), self);
g_signal_connect (G_OBJECT (config),
NM_CONFIG_SIGNAL_CONFIG_CHANGED,
G_CALLBACK (config_changed_update_ignore_carrier),
self);
check_carrier (self);
_LOGD (LOGD_HW,
"carrier is %s%s",
priv->carrier ? "ON" : "OFF",
priv->ignore_carrier ? " (but ignored)" : "");
} else {
/* Fake online link when carrier detection is not available. */
priv->carrier = TRUE;
}
g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
priv->real = TRUE;
}
static void
setup_finish (NMDevice *self, NMPlatformLink *plink)
{
if (plink) {
update_device_from_platform_link (self, plink);
device_recheck_slave_status (self, plink);
}
}
void
nm_device_setup_finish (NMDevice *self, NMPlatformLink *plink)
{
g_return_if_fail (!plink || link_type_compatible (self, plink->type, NULL, NULL));
NM_DEVICE_GET_CLASS (self)->setup_finish (self, plink);
NM_DEVICE_GET_PRIVATE (self)->real = TRUE;
g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
nm_device_recheck_available_connections (self);
/* Balanced by a freeze in setup_start() */
g_object_thaw_notify (G_OBJECT (self));
}
static void
unrealize (NMDevice *self, gboolean remove_resources)
{
int ifindex;
if (remove_resources) {
ifindex = nm_device_get_ifindex (self);
if ( ifindex > 0
&& nm_device_is_software (self))
nm_platform_link_delete (NM_PLATFORM_GET, ifindex);
}
}
/**
* nm_device_unrealize():
* @self: the #NMDevice
* @remove_resources: if %TRUE, remove backing resources
* @error: location to store error, or %NULL
*
* Clears any properties that depend on backing resources (kernel devices,
* etc) and removes those resources if @remove_resources is %TRUE.
*
* Returns: %TRUE on success, %FALSE on error
*/
gboolean
nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
if (!nm_device_is_software (self) || !nm_device_is_real (self)) {
g_set_error_literal (error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_NOT_SOFTWARE,
"This device is not a software device or is not realized");
return FALSE;
}
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_val_if_fail (priv->iface != NULL, FALSE);
g_object_freeze_notify (G_OBJECT (self));
if (NM_DEVICE_GET_CLASS (self)->unrealize)
NM_DEVICE_GET_CLASS (self)->unrealize (self, remove_resources);
if (priv->ifindex > 0) {
priv->ifindex = 0;
g_object_notify (G_OBJECT (self), NM_DEVICE_IFINDEX);
}
priv->ip_ifindex = 0;
if (priv->ip_iface) {
g_clear_pointer (&priv->ip_iface, g_free);
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
}
if (priv->driver_version) {
g_clear_pointer (&priv->driver_version, g_free);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER_VERSION);
}
if (priv->firmware_version) {
g_clear_pointer (&priv->firmware_version, g_free);
g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_VERSION);
}
if (priv->udi) {
g_clear_pointer (&priv->udi, g_free);
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
}
if (priv->hw_addr) {
g_clear_pointer (&priv->hw_addr, g_free);
g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS);
}
if (priv->physical_port_id) {
g_clear_pointer (&priv->physical_port_id, g_free);
g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID);
}
g_clear_pointer (&priv->perm_hw_addr, g_free);
g_clear_pointer (&priv->initial_hw_addr, g_free);
priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
priv->real = FALSE;
g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
g_object_thaw_notify (G_OBJECT (self));
nm_device_state_changed (self,
NM_DEVICE_STATE_UNMANAGED,
remove_resources ?
NM_DEVICE_STATE_REASON_USER_REQUESTED : NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
return TRUE;
}
/**
* nm_device_notify_new_device_added():
* @self: the #NMDevice
* @device: the newly added device
*
* Called by the manager to notify the device that a new device has
* been found and added.
*/
void
nm_device_notify_new_device_added (NMDevice *self, NMDevice *device)
{
NMDeviceClass *klass;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (NM_IS_DEVICE (device));
klass = NM_DEVICE_GET_CLASS (self);
if (klass->notify_new_device_added)
klass->notify_new_device_added (self, device);
}
/**
* nm_device_notify_component_added():
* @self: the #NMDevice
* @component: the component being added by a plugin
*
* Called by the manager to notify the device that a new component has
* been found. The device implementation should return %TRUE if it
* wishes to claim the component, or %FALSE if it cannot.
*
* Returns: %TRUE to claim the component, %FALSE if the component cannot be
* claimed.
*/
gboolean
nm_device_notify_component_added (NMDevice *self, GObject *component)
{
NMDeviceClass *klass;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (G_IS_OBJECT (component), FALSE);
klass = NM_DEVICE_GET_CLASS (self);
if (klass->component_added)
return klass->component_added (self, component);
return FALSE;
}
/**
* nm_device_owns_iface():
* @self: the #NMDevice
* @iface: an interface name
*
* Called by the manager to ask if the device or any of its components owns
* @iface. For example, a WWAN implementation would return %TRUE for an
* ethernet interface name that was owned by the WWAN device's modem component,
* because that ethernet interface is controlled by the WWAN device and cannot
* be used independently of the WWAN device.
*
* Returns: %TRUE if @self or it's components owns the interface name,
* %FALSE if not
*/
gboolean
nm_device_owns_iface (NMDevice *self, const char *iface)
{
if (NM_DEVICE_GET_CLASS (self)->owns_iface)
return NM_DEVICE_GET_CLASS (self)->owns_iface (self, iface);
return FALSE;
}
NMConnection *
nm_device_new_default_connection (NMDevice *self)
{
if (NM_DEVICE_GET_CLASS (self)->new_default_connection)
return NM_DEVICE_GET_CLASS (self)->new_default_connection (self);
return NULL;
}
2012-11-14 14:05:30 -06:00
static void
slave_state_changed (NMDevice *slave,
NMDeviceState slave_new_state,
NMDeviceState slave_old_state,
NMDeviceStateReason reason,
NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean release = FALSE;
_LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)",
nm_device_get_iface (slave),
slave_old_state,
state_to_string (slave_old_state),
slave_new_state,
state_to_string (slave_new_state));
2012-11-14 14:05:30 -06:00
/* Don't try to enslave slaves until the master is ready */
if (priv->state < NM_DEVICE_STATE_CONFIG)
return;
if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG)
nm_device_master_enslave_slave (self, slave, nm_device_get_applied_connection (slave));
2012-11-14 14:05:30 -06:00
else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED)
release = TRUE;
else if ( slave_new_state <= NM_DEVICE_STATE_DISCONNECTED
&& slave_old_state > NM_DEVICE_STATE_DISCONNECTED) {
/* Catch failures due to unavailable or unmanaged */
release = TRUE;
}
if (release) {
nm_device_master_release_one_slave (self, slave, TRUE, reason);
/* Bridge/bond/team interfaces are left up until manually deactivated */
if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED)
_LOGD (LOGD_DEVICE, "last slave removed; remaining activated");
2012-11-14 14:05:30 -06:00
}
}
/**
* nm_device_master_add_slave:
* @self: the master device
2012-11-14 14:05:30 -06:00
* @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
2012-11-14 14:05:30 -06:00
*
* If @self 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.
2012-11-14 14:05:30 -06:00
*
* Returns: %TRUE on success, %FALSE on failure
*/
static gboolean
nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2012-11-14 14:05:30 -06:00
SlaveInfo *info;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (slave != NULL, FALSE);
g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE);
2012-11-14 14:05:30 -06:00
if (configure)
g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
if (!find_slave_info (self, slave)) {
2012-11-14 14:05:30 -06:00
info = g_malloc0 (sizeof (SlaveInfo));
info->slave = g_object_ref (slave);
info->configure = configure;
2012-11-14 14:05:30 -06:00
info->watch_id = g_signal_connect (slave, "state-changed",
G_CALLBACK (slave_state_changed), self);
priv->slaves = g_slist_append (priv->slaves, info);
2012-11-14 14:05:30 -06:00
}
nm_device_queue_recheck_assume (self);
2012-11-14 14:05:30 -06:00
return TRUE;
}
/**
* nm_device_master_get_slaves:
* @self: the master device
2012-11-14 14:05:30 -06:00
*
* Returns: any slaves of which @self is the master. Caller owns returned list.
2012-11-14 14:05:30 -06:00
*/
GSList *
nm_device_master_get_slaves (NMDevice *self)
2012-11-14 14:05:30 -06:00
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2012-11-14 14:05:30 -06:00
GSList *slaves = NULL, *iter;
for (iter = priv->slaves; iter; iter = g_slist_next (iter))
slaves = g_slist_prepend (slaves, ((SlaveInfo *) iter->data)->slave);
return slaves;
}
/**
* nm_device_master_get_slave_by_ifindex:
* @self: the master device
* @ifindex: the slave's interface index
*
* Returns: the slave with the given @ifindex of which @self is the master,
* or %NULL if no device with @ifindex is a slave of @self.
*/
NMDevice *
nm_device_master_get_slave_by_ifindex (NMDevice *self, int ifindex)
{
GSList *iter;
for (iter = NM_DEVICE_GET_PRIVATE (self)->slaves; iter; iter = g_slist_next (iter)) {
SlaveInfo *info = iter->data;
if (nm_device_get_ip_ifindex (info->slave) == ifindex)
return info->slave;
}
return NULL;
}
/**
* nm_device_master_check_slave_physical_port:
* @self: the master device
* @slave: a slave device
* @log_domain: domain to log a warning in
*
* Checks if @self already has a slave with the same #NMDevice:physical-port-id
* as @slave, and logs a warning if so.
*/
void
nm_device_master_check_slave_physical_port (NMDevice *self, NMDevice *slave,
NMLogDomain log_domain)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *slave_physical_port_id, *existing_physical_port_id;
SlaveInfo *info;
GSList *iter;
slave_physical_port_id = nm_device_get_physical_port_id (slave);
if (!slave_physical_port_id)
return;
for (iter = priv->slaves; iter; iter = iter->next) {
info = iter->data;
if (info->slave == slave)
continue;
existing_physical_port_id = nm_device_get_physical_port_id (info->slave);
if (!g_strcmp0 (slave_physical_port_id, existing_physical_port_id)) {
_LOGW (log_domain, "slave %s shares a physical port with existing slave %s",
nm_device_get_ip_iface (slave),
nm_device_get_ip_iface (info->slave));
/* Since this function will get called for every slave, we only have
* to warn about the first match we find; if there are other matches
* later in the list, we will have already warned about them matching
* @existing earlier.
*/
return;
}
}
}
2012-11-14 14:05:30 -06:00
/* release all slaves */
static void
nm_device_master_release_slaves (NMDevice *self)
2012-11-14 14:05:30 -06:00
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
device: fix warning releasing of slave when slave device gets removed When the slave device gets removed, the master is not in a state-change when calling nm_device_release_one_slave(). This triggers a warning [1]. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c144c "NetworkManager", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fff8b1d35b0) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x3370cc1fdc "%s") at gmessages.c:1025 #2 0x0000003370c50956 in g_warn_message (domain=domain@entry=0x4c144c "NetworkManager", file=file@entry=0x4b14d5 "devices/nm-device.c", line=line@entry=841, func=func@entry=0x4b48f0 <__FUNCTION__.35456> "nm_device_release_one_slave", warnexpr=warnexpr@entry=0x0) at gmessages.c:1058 #3 0x0000000000436c30 in nm_device_release_one_slave (dev=dev@entry=0xd92540, slave=slave@entry=0xdb0e50, configure=configure@entry=1) at devices/nm-device.c:841 #4 0x000000000043a779 in slave_state_changed (slave=0xdb0e50, slave_new_state=NM_DEVICE_STATE_UNMANAGED, slave_old_state=NM_DEVICE_STATE_ACTIVATED, reason=<optimized out>, self=0xd92540) at devices/nm-device.c:1214 #5 0x0000003371805d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #6 0x00000033718056bc in ffi_call (cif=cif@entry=0x7fff8b1d3a00, fn=0x43a677 <slave_state_changed>, rvalue=0x7fff8b1d3970, avalue=avalue@entry=0x7fff8b1d38f0) at ../src/x86/ffi64.c:522 #7 0x0000003371c10ad8 in g_cclosure_marshal_generic (closure=0xd76120, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #8 0x0000003371c10298 in g_closure_invoke (closure=0xd76120, return_value=return_value@entry=0x0, n_param_values=4, param_values=param_values@entry=0x7fff8b1d3c00, invocation_hint=invocation_hint@entry=0x7fff8b1d3ba0) at gclosure.c:777 #9 0x0000003371c2235d in signal_emit_unlocked_R (node=node@entry=0xd9d850, detail=detail@entry=0, instance=instance@entry=0xdb0e50, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff8b1d3c00) at gsignal.c:3586 #10 0x0000003371c2a0f2 in g_signal_emit_valist (instance=instance@entry=0xdb0e50, signal_id=signal_id@entry=68, detail=detail@entry=0, var_args=var_args@entry=0x7fff8b1d3e38) at gsignal.c:3330 #11 0x0000003371c2a8f8 in g_signal_emit_by_name (instance=instance@entry=0xdb0e50, detailed_signal=detailed_signal@entry=0x4c3ce2 "state-changed") at gsignal.c:3426 #12 0x000000000043754f in _set_state_full (device=device@entry=0xdb0e50, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6689 #13 0x000000000043797c in nm_device_state_changed (device=device@entry=0xdb0e50, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #14 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0xdb0e50, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #15 0x00000000004799c2 in remove_device (manager=manager@entry=0xd86150, device=0xdb0e50, quitting=quitting@entry=0) at nm-manager.c:769 #16 0x000000000047e3bf in platform_link_cb (platform=<optimized out>, ifindex=35, plink=<optimized out>, change_type=<optimized out>, reason=<optimized out>, user_data=<optimized out>) at nm-manager.c:2123 #17 0x0000003371805d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #18 0x00000033718056bc in ffi_call (cif=cif@entry=0x7fff8b1d4320, fn=0x47e34b <platform_link_cb>, rvalue=0x7fff8b1d4290, avalue=avalue@entry=0x7fff8b1d4210) at ../src/x86/ffi64.c:522 #19 0x0000003371c10ad8 in g_cclosure_marshal_generic (closure=0xd32e40, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #20 0x0000003371c10298 in g_closure_invoke (closure=0xd32e40, return_value=return_value@entry=0x0, n_param_values=5, param_values=param_values@entry=0x7fff8b1d4520, invocation_hint=invocation_hint@entry=0x7fff8b1d44c0) at gclosure.c:777 #21 0x0000003371c2235d in signal_emit_unlocked_R (node=node@entry=0xcf5780, detail=detail@entry=0, instance=instance@entry=0xcf78a0, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff8b1d4520) at gsignal.c:3586 #22 0x0000003371c2a0f2 in g_signal_emit_valist (instance=instance@entry=0xcf78a0, signal_id=signal_id@entry=2, detail=detail@entry=0, var_args=var_args@entry=0x7fff8b1d4778) at gsignal.c:3330 #23 0x0000003371c2a8f8 in g_signal_emit_by_name (instance=instance@entry=0xcf78a0, detailed_signal=detailed_signal@entry=0x4b183d "link-changed") at gsignal.c:3426 #24 0x000000000044c6f3 in announce_object (platform=platform@entry=0xcf78a0, object=0xde1720, change_type=change_type@entry=NM_PLATFORM_SIGNAL_REMOVED, reason=reason@entry=NM_PLATFORM_REASON_EXTERNAL) at platform/nm-linux-platform.c:1572 #25 0x000000000044ec07 in event_notification (msg=<optimized out>, user_data=<optimized out>) at platform/nm-linux-platform.c:1886 #26 0x0000003844c1117f in nl_cb_call (msg=<optimized out>, type=<optimized out>, cb=<optimized out>) at ../include/netlink-private/netlink.h:141 #27 recvmsgs (cb=0xcf7240, sk=0xcf7330) at nl.c:952 #28 nl_recvmsgs_report (sk=0xcf7330, cb=0xcf7240) at nl.c:1003 #29 0x0000003844c11549 in nl_recvmsgs (sk=<optimized out>, cb=<optimized out>) at nl.c:1027 #30 0x0000003844c11569 in nl_recvmsgs_default (sk=<optimized out>) at nl.c:1041 #31 0x000000000044e955 in event_handler (channel=<optimized out>, io_condition=<optimized out>, user_data=0xcf78a0) at platform/nm-linux-platform.c:3804 #32 0x0000003370c492a6 in g_main_dispatch (context=0xcf5190) at gmain.c:3066 #33 g_main_context_dispatch (context=context@entry=0xcf5190) at gmain.c:3642 #34 0x0000003370c49628 in g_main_context_iterate (context=0xcf5190, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713 #35 0x0000003370c49a3a in g_main_loop_run (loop=0xcf4e30) at gmain.c:3907 #36 0x0000000000429f15 in main (argc=1, argv=0x7fff8b1d4f38) at main.c:678 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 11:18:45 +02:00
NMDeviceStateReason reason;
2012-11-14 14:05:30 -06:00
/* Don't release the slaves if this connection doesn't belong to NM. */
if (nm_device_uses_generated_assumed_connection (self))
return;
device: fix warning releasing of slave when slave device gets removed When the slave device gets removed, the master is not in a state-change when calling nm_device_release_one_slave(). This triggers a warning [1]. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c144c "NetworkManager", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fff8b1d35b0) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x3370cc1fdc "%s") at gmessages.c:1025 #2 0x0000003370c50956 in g_warn_message (domain=domain@entry=0x4c144c "NetworkManager", file=file@entry=0x4b14d5 "devices/nm-device.c", line=line@entry=841, func=func@entry=0x4b48f0 <__FUNCTION__.35456> "nm_device_release_one_slave", warnexpr=warnexpr@entry=0x0) at gmessages.c:1058 #3 0x0000000000436c30 in nm_device_release_one_slave (dev=dev@entry=0xd92540, slave=slave@entry=0xdb0e50, configure=configure@entry=1) at devices/nm-device.c:841 #4 0x000000000043a779 in slave_state_changed (slave=0xdb0e50, slave_new_state=NM_DEVICE_STATE_UNMANAGED, slave_old_state=NM_DEVICE_STATE_ACTIVATED, reason=<optimized out>, self=0xd92540) at devices/nm-device.c:1214 #5 0x0000003371805d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #6 0x00000033718056bc in ffi_call (cif=cif@entry=0x7fff8b1d3a00, fn=0x43a677 <slave_state_changed>, rvalue=0x7fff8b1d3970, avalue=avalue@entry=0x7fff8b1d38f0) at ../src/x86/ffi64.c:522 #7 0x0000003371c10ad8 in g_cclosure_marshal_generic (closure=0xd76120, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #8 0x0000003371c10298 in g_closure_invoke (closure=0xd76120, return_value=return_value@entry=0x0, n_param_values=4, param_values=param_values@entry=0x7fff8b1d3c00, invocation_hint=invocation_hint@entry=0x7fff8b1d3ba0) at gclosure.c:777 #9 0x0000003371c2235d in signal_emit_unlocked_R (node=node@entry=0xd9d850, detail=detail@entry=0, instance=instance@entry=0xdb0e50, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff8b1d3c00) at gsignal.c:3586 #10 0x0000003371c2a0f2 in g_signal_emit_valist (instance=instance@entry=0xdb0e50, signal_id=signal_id@entry=68, detail=detail@entry=0, var_args=var_args@entry=0x7fff8b1d3e38) at gsignal.c:3330 #11 0x0000003371c2a8f8 in g_signal_emit_by_name (instance=instance@entry=0xdb0e50, detailed_signal=detailed_signal@entry=0x4c3ce2 "state-changed") at gsignal.c:3426 #12 0x000000000043754f in _set_state_full (device=device@entry=0xdb0e50, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6689 #13 0x000000000043797c in nm_device_state_changed (device=device@entry=0xdb0e50, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #14 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0xdb0e50, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #15 0x00000000004799c2 in remove_device (manager=manager@entry=0xd86150, device=0xdb0e50, quitting=quitting@entry=0) at nm-manager.c:769 #16 0x000000000047e3bf in platform_link_cb (platform=<optimized out>, ifindex=35, plink=<optimized out>, change_type=<optimized out>, reason=<optimized out>, user_data=<optimized out>) at nm-manager.c:2123 #17 0x0000003371805d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #18 0x00000033718056bc in ffi_call (cif=cif@entry=0x7fff8b1d4320, fn=0x47e34b <platform_link_cb>, rvalue=0x7fff8b1d4290, avalue=avalue@entry=0x7fff8b1d4210) at ../src/x86/ffi64.c:522 #19 0x0000003371c10ad8 in g_cclosure_marshal_generic (closure=0xd32e40, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #20 0x0000003371c10298 in g_closure_invoke (closure=0xd32e40, return_value=return_value@entry=0x0, n_param_values=5, param_values=param_values@entry=0x7fff8b1d4520, invocation_hint=invocation_hint@entry=0x7fff8b1d44c0) at gclosure.c:777 #21 0x0000003371c2235d in signal_emit_unlocked_R (node=node@entry=0xcf5780, detail=detail@entry=0, instance=instance@entry=0xcf78a0, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff8b1d4520) at gsignal.c:3586 #22 0x0000003371c2a0f2 in g_signal_emit_valist (instance=instance@entry=0xcf78a0, signal_id=signal_id@entry=2, detail=detail@entry=0, var_args=var_args@entry=0x7fff8b1d4778) at gsignal.c:3330 #23 0x0000003371c2a8f8 in g_signal_emit_by_name (instance=instance@entry=0xcf78a0, detailed_signal=detailed_signal@entry=0x4b183d "link-changed") at gsignal.c:3426 #24 0x000000000044c6f3 in announce_object (platform=platform@entry=0xcf78a0, object=0xde1720, change_type=change_type@entry=NM_PLATFORM_SIGNAL_REMOVED, reason=reason@entry=NM_PLATFORM_REASON_EXTERNAL) at platform/nm-linux-platform.c:1572 #25 0x000000000044ec07 in event_notification (msg=<optimized out>, user_data=<optimized out>) at platform/nm-linux-platform.c:1886 #26 0x0000003844c1117f in nl_cb_call (msg=<optimized out>, type=<optimized out>, cb=<optimized out>) at ../include/netlink-private/netlink.h:141 #27 recvmsgs (cb=0xcf7240, sk=0xcf7330) at nl.c:952 #28 nl_recvmsgs_report (sk=0xcf7330, cb=0xcf7240) at nl.c:1003 #29 0x0000003844c11549 in nl_recvmsgs (sk=<optimized out>, cb=<optimized out>) at nl.c:1027 #30 0x0000003844c11569 in nl_recvmsgs_default (sk=<optimized out>) at nl.c:1041 #31 0x000000000044e955 in event_handler (channel=<optimized out>, io_condition=<optimized out>, user_data=0xcf78a0) at platform/nm-linux-platform.c:3804 #32 0x0000003370c492a6 in g_main_dispatch (context=0xcf5190) at gmain.c:3066 #33 g_main_context_dispatch (context=context@entry=0xcf5190) at gmain.c:3642 #34 0x0000003370c49628 in g_main_context_iterate (context=0xcf5190, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713 #35 0x0000003370c49a3a in g_main_loop_run (loop=0xcf4e30) at gmain.c:3907 #36 0x0000000000429f15 in main (argc=1, argv=0x7fff8b1d4f38) at main.c:678 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 11:18:45 +02:00
reason = priv->state_reason;
if (priv->state == NM_DEVICE_STATE_FAILED)
reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED;
while (priv->slaves) {
SlaveInfo *info = priv->slaves->data;
nm_device_master_release_one_slave (self, info->slave, TRUE, reason);
}
2012-11-14 14:05:30 -06:00
}
/**
* nm_device_is_master:
* @self: the device
*
* Returns: %TRUE if the device can have slaves
*/
gboolean
nm_device_is_master (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->is_master;
}
/**
* nm_device_get_master:
* @self: the device
*
* If @self has been enslaved by another device, this returns that
* device. Otherwise it returns %NULL. (In particular, note that if
* @self is in the process of activating as a slave, but has not yet
* been enslaved by its master, this will return %NULL.)
*
* Returns: (transfer none): @self's master, or %NULL
*/
NMDevice *
nm_device_get_master (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->is_enslaved)
return priv->master;
else
return NULL;
}
2012-11-14 14:05:30 -06:00
/**
* nm_device_slave_notify_enslave:
* @self: the slave device
* @success: whether the enslaving operation succeeded
2012-11-14 14:05:30 -06:00
*
* Notifies a slave that either it has been enslaved, or else its master tried
* to enslave it and failed.
2012-11-14 14:05:30 -06:00
*/
2013-11-18 12:06:10 -06:00
static void
nm_device_slave_notify_enslave (NMDevice *self, gboolean success)
2012-11-14 14:05:30 -06:00
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection = nm_device_get_applied_connection (self);
gboolean activating = (priv->state == NM_DEVICE_STATE_IP_CONFIG);
2012-11-14 14:05:30 -06:00
g_assert (priv->master);
2012-11-14 14:05:30 -06:00
if (!priv->is_enslaved) {
if (success) {
if (activating) {
_LOGI (LOGD_DEVICE, "Activation: connection '%s' enslaved, continuing activation",
nm_connection_get_id (connection));
} else
_LOGI (LOGD_DEVICE, "enslaved to %s", nm_device_get_iface (priv->master));
priv->is_enslaved = TRUE;
g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER);
} else if (activating) {
_LOGW (LOGD_DEVICE, "Activation: connection '%s' could not be enslaved",
nm_connection_get_id (connection));
}
}
if (activating) {
priv->ip4_state = IP_DONE;
priv->ip6_state = IP_DONE;
device: set a reason when device enslave fails Otherwise we'd hit an assert and rightly so! Program received signal SIGTRAP, Trace/breakpoint trap. g_logv (log_domain=0x5555556b2f80 "NetworkManager", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fffffffcd10) at gmessages.c:1046 1046 g_private_set (&g_log_depth, GUINT_TO_POINTER (depth)); (gdb) bt #0 g_logv (log_domain=0x5555556b2f80 "NetworkManager", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fffffffcd10) at gmessages.c:1046 #1 0x00007ffff4a4ea3f in g_log (log_domain=log_domain@entry=0x5555556b2f80 "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x7ffff4ac1e4c "%s") at gmessages.c:1079 #2 0x00007ffff4a4ed56 in g_warn_message (domain=domain@entry=0x5555556b2f80 "NetworkManager", file=file@entry=0x5555556aca93 "devices/nm-device.c", line=line@entry=1101, func=func@entry=0x5555556b22e0 <__FUNCTION__.35443> "nm_device_release_one_slave", warnexpr=warnexpr@entry=0x0) at gmessages.c:1112 #3 0x00005555555ba80a in nm_device_release_one_slave (self=self@entry=0x5555559ec4c0, slave=slave@entry=0x5555559f7800, configure=configure@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:1101 #4 0x00005555555c264b in slave_state_changed (slave=0x5555559f7800, slave_new_state=NM_DEVICE_STATE_FAILED, slave_old_state=NM_DEVICE_STATE_IP_CONFIG, reason=NM_DEVICE_STATE_REASON_NONE, self=0x5555559ec4c0) at devices/nm-device.c:1700 #5 0x00007ffff339cdac in ffi_call_unix64 () at ../src/x86/unix64.S:76 #6 0x00007ffff339c6d5 in ffi_call (cif=cif@entry=0x7fffffffd1c0, fn=<optimized out>, rvalue=0x7fffffffd130, avalue=avalue@entry=0x7fffffffd0b0) at ../src/x86/ffi64.c:522 #7 0x00007ffff4d45678 in g_cclosure_marshal_generic (closure=0x5555559b0160, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #8 0x00007ffff4d44e38 in g_closure_invoke (closure=0x5555559b0160, return_value=return_value@entry=0x0, n_param_values=4, param_values=param_values@entry=0x7fffffffd3c0, invocation_hint=invocation_hint@entry=0x7fffffffd360) at gclosure.c:768 #9 0x00007ffff4d5675d in signal_emit_unlocked_R (node=node@entry=0x55555598a6f0, detail=detail@entry=0, instance=instance@entry=0x5555559f7800, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffd3c0) at gsignal.c:3553 #10 0x00007ffff4d5e4c1 in g_signal_emit_valist (instance=instance@entry=0x5555559f7800, signal_id=signal_id@entry=72, detail=detail@entry=0, var_args=var_args@entry=0x7fffffffd5f8) at gsignal.c:3309 #11 0x00007ffff4d5ecc8 in g_signal_emit_by_name (instance=instance@entry=0x5555559f7800, detailed_signal=detailed_signal@entry=0x5555556c0405 "state-changed") at gsignal.c:3405 #12 0x00005555555bd0e0 in _set_state_full (self=self@entry=0x5555559f7800, state=state@entry=NM_DEVICE_STATE_FAILED, reason=reason@entry=NM_DEVICE_STATE_REASON_NONE, quitting=quitting@entry=0) at devices/nm-device.c:8580 #13 0x00005555555be0e7 in nm_device_state_changed (self=self@entry=0x5555559f7800, state=state@entry=NM_DEVICE_STATE_FAILED, reason=reason@entry=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:8741 #14 0x00005555555c0a45 in queued_set_state (user_data=<optimized out>) at devices/nm-device.c:8765 #15 0x00007ffff4a4779a in g_main_dispatch (context=0x5555559433c0) at gmain.c:3109 #16 g_main_context_dispatch (context=context@entry=0x5555559433c0) at gmain.c:3708 #17 0x00007ffff4a47ae8 in g_main_context_iterate (context=0x5555559433c0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3779 #18 0x00007ffff4a47dba in g_main_loop_run (loop=0x555555943480) at gmain.c:3973 #19 0x000055555559713d in main (argc=1, argv=0x7fffffffdb78) at main.c:512 (gdb)
2015-11-06 14:30:32 +01:00
if (success)
nm_device_queue_state (self, NM_DEVICE_STATE_SECONDARIES, NM_DEVICE_STATE_REASON_NONE);
else
nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
} else
nm_device_queue_recheck_assume (self);
}
/**
* nm_device_slave_notify_release:
* @self: the slave device
* @reason: the reason associated with the state change
*
* Notifies a slave that it has been released, and why.
*/
2013-11-18 12:06:10 -06:00
static void
nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection = nm_device_get_applied_connection (self);
NMDeviceState new_state;
const char *master_status;
device: fix disconnecting slave-device when master gets deleted When deleting a master-device either via `nmcli device delete` or `ip link delete`, the slave-device would hang. This seems to be broken for a very long time already. This is due to the following: #0 0x00005555555f548c in nm_device_slave_notify_release (self=0x555555dc1300, reason=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:2175 #1 0x00005555555d6de2 in nm_device_release_one_slave (self=0x555555de3dd0, slave=0x555555dc1300, configure=0, reason=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:1117 #2 0x00005555555f02b7 in device_link_changed (self=0x555555dc1300) at devices/nm-device.c:1460 Previously, nm_device_slave_notify_release() being called with reason "NONE" did not actually transition the device-state, thus keeping the device wrongly in activated state. There were two callers that passed configure=FALSE to nm_device_release_one_slave(), (and thus reason=NONE to nm_device_slave_notify_release()): - (1) device_link_changed(): nm_device_release_one_slave (priv->master, self, FALSE, /*wrong reason NONE*/); - (2) nm_device_removed(): nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); We should always change the device-state during nm_device_slave_notify_release() regardless of the reason. (2) was added by commit c83b40aca76fc0ed624a6c9e71dbd7b0abfa13f2, later refined by commit 5dd48f7527c67b399ac144f594e035216771d61c. In a way change the second fix to perform some of the configuration (but still not unenslaving the device).
2015-12-03 17:18:50 +01:00
if ( priv->state > NM_DEVICE_STATE_DISCONNECTED
&& priv->state <= NM_DEVICE_STATE_ACTIVATED) {
if (reason == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) {
new_state = NM_DEVICE_STATE_FAILED;
master_status = "failed";
} else if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) {
new_state = NM_DEVICE_STATE_DEACTIVATING;
master_status = "deactivated by user request";
} else {
new_state = NM_DEVICE_STATE_DISCONNECTED;
master_status = "deactivated";
2012-11-14 14:05:30 -06:00
}
_LOGD (LOGD_DEVICE, "Activation: connection '%s' master %s",
nm_connection_get_id (connection),
master_status);
nm_device_queue_state (self, new_state, reason);
device: fix assertion in nm_device_slave_notify_release() logging the master device #0 0x00007f6c3aed34e9 in g_logv (log_domain=0x7f6c3ea7341c "NetworkManager", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff0a33fb60) at gmessages.c:989 #1 0x00007f6c3aed363f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007f6c3e8ead4f in nm_device_get_iface (self=0x0) at devices/nm-device.c:502 #3 0x00007f6c3e904f59 in nm_device_slave_notify_release (self=0x7f6c3fb48e60, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:1618 #4 0x00007f6c3e8ed69f in nm_device_release_one_slave (self=0x7f6c3fb22670, slave=0x7f6c3fb48e60, configure=1, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:968 #5 0x00007f6c3e904bf7 in slave_state_changed (slave=0x7f6c3fb48e60, slave_new_state=NM_DEVICE_STATE_UNMANAGED, slave_old_state=NM_DEVICE_STATE_ACTIVATED, reason=NM_DEVICE_STATE_REASON_REMOVED, self=0x7f6c3fb22670) at devices/nm-device.c:1368 #6 0x00007f6c39829d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #7 0x00007f6c398296bc in ffi_call (cif=cif@entry=0x7fff0a340070, fn=0x7f6c3e9049d0 <slave_state_changed>, rvalue=0x7fff0a33ffe0, avalue=avalue@entry=0x7fff0a33ff60) at ../src/x86/ffi64.c:522 #8 0x00007f6c3b1bfad8 in g_cclosure_marshal_generic (closure=0x7f6c3fb5c8c0, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #9 0x00007f6c3b1bf298 in g_closure_invoke (closure=0x7f6c3fb5c8c0, return_value=return_value@entry=0x0, n_param_values=4, param_values=param_values@entry=0x7fff0a340270, invocation_hint=invocation_hint@entry=0x7fff0a340210) at gclosure.c:777 #10 0x00007f6c3b1d135d in signal_emit_unlocked_R (node=node@entry=0x7f6c3faf5d10, detail=detail@entry=0, instance=instance@entry=0x7f6c3fb48e60, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff0a340270) at gsignal.c:3586 #11 0x00007f6c3b1d90f2 in g_signal_emit_valist (instance=instance@entry=0x7f6c3fb48e60, signal_id=signal_id@entry=64, detail=detail@entry=0, var_args=var_args@entry=0x7fff0a3404a8) at gsignal.c:3330 #12 0x00007f6c3b1d98f8 in g_signal_emit_by_name (instance=0x7f6c3fb48e60, detailed_signal=0x7f6c3ea70f83 "state-changed") at gsignal.c:3426 #13 0x00007f6c3e8f894f in _set_state_full (self=0x7f6c3fb48e60, state=NM_DEVICE_STATE_UNMANAGED, reason=NM_DEVICE_STATE_REASON_REMOVED, quitting=0) at devices/nm-device.c:7486 #14 0x00007f6c3e8f0706 in nm_device_state_changed (self=0x7f6c3fb48e60, state=NM_DEVICE_STATE_UNMANAGED, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:7623 #15 0x00007f6c3e8f808b in nm_device_set_unmanaged (self=0x7f6c3fb48e60, flag=NM_UNMANAGED_INTERNAL, unmanaged=1, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6652 #16 0x00007f6c3e9943d0 in remove_device (manager=0x7f6c3fb20150, device=0x7f6c3fb48e60, quitting=0, allow_unmanage=1) at nm-manager.c:752 #17 0x00007f6c3e995c29 in platform_link_cb (platform=0x7f6c3fa7a870, ifindex=73, plink=0x7fff0a341260, change_type=NM_PLATFORM_SIGNAL_REMOVED, reason=NM_PLATFORM_REASON_EXTERNAL, user_data=0x7f6c3fb20150) at nm-manager.c:2182 #18 0x00007f6c39829d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #19 0x00007f6c398296bc in ffi_call (cif=cif@entry=0x7fff0a340bc0, fn=0x7f6c3e995b60 <platform_link_cb>, rvalue=0x7fff0a340b30, avalue=avalue@entry=0x7fff0a340ab0) at ../src/x86/ffi64.c:522 #20 0x00007f6c3b1bfad8 in g_cclosure_marshal_generic (closure=0x7f6c3fb14cf0, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #21 0x00007f6c3b1bf298 in g_closure_invoke (closure=0x7f6c3fb14cf0, return_value=return_value@entry=0x0, n_param_values=5, param_values=param_values@entry=0x7fff0a340dc0, invocation_hint=invocation_hint@entry=0x7fff0a340d60) at gclosure.c:777 #22 0x00007f6c3b1d135d in signal_emit_unlocked_R (node=node@entry=0x7f6c3fa76f00, detail=detail@entry=0, instance=instance@entry=0x7f6c3fa7a870, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff0a340dc0) at gsignal.c:3586 #23 0x00007f6c3b1d90f2 in g_signal_emit_valist (instance=instance@entry=0x7f6c3fa7a870, signal_id=signal_id@entry=2, detail=detail@entry=0, var_args=var_args@entry=0x7fff0a341018) at gsignal.c:3330 #24 0x00007f6c3b1d98f8 in g_signal_emit_by_name (instance=0x7f6c3fa7a870, detailed_signal=0x7f6c3ea5f1fa "link-changed") at gsignal.c:3426 #25 0x00007f6c3e92412a in announce_object (platform=0x7f6c3fa7a870, object=0x7f6c3fbb6fd0, change_type=NM_PLATFORM_SIGNAL_REMOVED, reason=NM_PLATFORM_REASON_EXTERNAL) at platform/nm-linux-platform.c:1625 #26 0x00007f6c3e92b0f9 in event_notification (msg=0x7f6c3fa946f0, user_data=0x7f6c3fa7a870) at platform/nm-linux-platform.c:1986 #27 0x00007f6c3c35812f in nl_cb_call (msg=<optimized out>, type=<optimized out>, cb=<optimized out>) at ../include/netlink-private/netlink.h:141 #28 recvmsgs (cb=0x7f6c3fa7a620, sk=0x7f6c3fa7a710) at nl.c:952 #29 nl_recvmsgs_report (sk=0x7f6c3fa7a710, cb=0x7f6c3fa7a620) at nl.c:1003 #30 0x00007f6c3c3584f9 in nl_recvmsgs (sk=<optimized out>, cb=<optimized out>) at nl.c:1027 #31 0x00007f6c3e929dca in event_handler (channel=0x7f6c3fa78810, io_condition=G_IO_IN, user_data=0x7f6c3fa7a870) at platform/nm-linux-platform.c:4127 #32 0x00007f6c3aecc2a6 in g_main_dispatch (context=0x7f6c3fa68490) at gmain.c:3066 #33 g_main_context_dispatch (context=context@entry=0x7f6c3fa68490) at gmain.c:3642 #34 0x00007f6c3aecc628 in g_main_context_iterate (context=0x7f6c3fa68490, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713 #35 0x00007f6c3aecca3a in g_main_loop_run (loop=0x7f6c3fa68550) at gmain.c:3907 #36 0x00007f6c3e8e9fff in main (argc=1, argv=0x7fff0a341c88) at main.c:483 https://bugzilla.gnome.org/show_bug.cgi?id=741651
2014-12-17 00:40:05 +01:00
} else if (priv->master)
_LOGI (LOGD_DEVICE, "released from master %s", nm_device_get_iface (priv->master));
device: fix assertion in nm_device_slave_notify_release() logging the master device #0 0x00007f6c3aed34e9 in g_logv (log_domain=0x7f6c3ea7341c "NetworkManager", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff0a33fb60) at gmessages.c:989 #1 0x00007f6c3aed363f in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at gmessages.c:1025 #2 0x00007f6c3e8ead4f in nm_device_get_iface (self=0x0) at devices/nm-device.c:502 #3 0x00007f6c3e904f59 in nm_device_slave_notify_release (self=0x7f6c3fb48e60, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:1618 #4 0x00007f6c3e8ed69f in nm_device_release_one_slave (self=0x7f6c3fb22670, slave=0x7f6c3fb48e60, configure=1, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:968 #5 0x00007f6c3e904bf7 in slave_state_changed (slave=0x7f6c3fb48e60, slave_new_state=NM_DEVICE_STATE_UNMANAGED, slave_old_state=NM_DEVICE_STATE_ACTIVATED, reason=NM_DEVICE_STATE_REASON_REMOVED, self=0x7f6c3fb22670) at devices/nm-device.c:1368 #6 0x00007f6c39829d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #7 0x00007f6c398296bc in ffi_call (cif=cif@entry=0x7fff0a340070, fn=0x7f6c3e9049d0 <slave_state_changed>, rvalue=0x7fff0a33ffe0, avalue=avalue@entry=0x7fff0a33ff60) at ../src/x86/ffi64.c:522 #8 0x00007f6c3b1bfad8 in g_cclosure_marshal_generic (closure=0x7f6c3fb5c8c0, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #9 0x00007f6c3b1bf298 in g_closure_invoke (closure=0x7f6c3fb5c8c0, return_value=return_value@entry=0x0, n_param_values=4, param_values=param_values@entry=0x7fff0a340270, invocation_hint=invocation_hint@entry=0x7fff0a340210) at gclosure.c:777 #10 0x00007f6c3b1d135d in signal_emit_unlocked_R (node=node@entry=0x7f6c3faf5d10, detail=detail@entry=0, instance=instance@entry=0x7f6c3fb48e60, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff0a340270) at gsignal.c:3586 #11 0x00007f6c3b1d90f2 in g_signal_emit_valist (instance=instance@entry=0x7f6c3fb48e60, signal_id=signal_id@entry=64, detail=detail@entry=0, var_args=var_args@entry=0x7fff0a3404a8) at gsignal.c:3330 #12 0x00007f6c3b1d98f8 in g_signal_emit_by_name (instance=0x7f6c3fb48e60, detailed_signal=0x7f6c3ea70f83 "state-changed") at gsignal.c:3426 #13 0x00007f6c3e8f894f in _set_state_full (self=0x7f6c3fb48e60, state=NM_DEVICE_STATE_UNMANAGED, reason=NM_DEVICE_STATE_REASON_REMOVED, quitting=0) at devices/nm-device.c:7486 #14 0x00007f6c3e8f0706 in nm_device_state_changed (self=0x7f6c3fb48e60, state=NM_DEVICE_STATE_UNMANAGED, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:7623 #15 0x00007f6c3e8f808b in nm_device_set_unmanaged (self=0x7f6c3fb48e60, flag=NM_UNMANAGED_INTERNAL, unmanaged=1, reason=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6652 #16 0x00007f6c3e9943d0 in remove_device (manager=0x7f6c3fb20150, device=0x7f6c3fb48e60, quitting=0, allow_unmanage=1) at nm-manager.c:752 #17 0x00007f6c3e995c29 in platform_link_cb (platform=0x7f6c3fa7a870, ifindex=73, plink=0x7fff0a341260, change_type=NM_PLATFORM_SIGNAL_REMOVED, reason=NM_PLATFORM_REASON_EXTERNAL, user_data=0x7f6c3fb20150) at nm-manager.c:2182 #18 0x00007f6c39829d8c in ffi_call_unix64 () at ../src/x86/unix64.S:76 #19 0x00007f6c398296bc in ffi_call (cif=cif@entry=0x7fff0a340bc0, fn=0x7f6c3e995b60 <platform_link_cb>, rvalue=0x7fff0a340b30, avalue=avalue@entry=0x7fff0a340ab0) at ../src/x86/ffi64.c:522 #20 0x00007f6c3b1bfad8 in g_cclosure_marshal_generic (closure=0x7f6c3fb14cf0, return_gvalue=0x0, n_param_values=<optimized out>, param_values=<optimized out>, invocation_hint=<optimized out>, marshal_data=0x0) at gclosure.c:1454 #21 0x00007f6c3b1bf298 in g_closure_invoke (closure=0x7f6c3fb14cf0, return_value=return_value@entry=0x0, n_param_values=5, param_values=param_values@entry=0x7fff0a340dc0, invocation_hint=invocation_hint@entry=0x7fff0a340d60) at gclosure.c:777 #22 0x00007f6c3b1d135d in signal_emit_unlocked_R (node=node@entry=0x7f6c3fa76f00, detail=detail@entry=0, instance=instance@entry=0x7f6c3fa7a870, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff0a340dc0) at gsignal.c:3586 #23 0x00007f6c3b1d90f2 in g_signal_emit_valist (instance=instance@entry=0x7f6c3fa7a870, signal_id=signal_id@entry=2, detail=detail@entry=0, var_args=var_args@entry=0x7fff0a341018) at gsignal.c:3330 #24 0x00007f6c3b1d98f8 in g_signal_emit_by_name (instance=0x7f6c3fa7a870, detailed_signal=0x7f6c3ea5f1fa "link-changed") at gsignal.c:3426 #25 0x00007f6c3e92412a in announce_object (platform=0x7f6c3fa7a870, object=0x7f6c3fbb6fd0, change_type=NM_PLATFORM_SIGNAL_REMOVED, reason=NM_PLATFORM_REASON_EXTERNAL) at platform/nm-linux-platform.c:1625 #26 0x00007f6c3e92b0f9 in event_notification (msg=0x7f6c3fa946f0, user_data=0x7f6c3fa7a870) at platform/nm-linux-platform.c:1986 #27 0x00007f6c3c35812f in nl_cb_call (msg=<optimized out>, type=<optimized out>, cb=<optimized out>) at ../include/netlink-private/netlink.h:141 #28 recvmsgs (cb=0x7f6c3fa7a620, sk=0x7f6c3fa7a710) at nl.c:952 #29 nl_recvmsgs_report (sk=0x7f6c3fa7a710, cb=0x7f6c3fa7a620) at nl.c:1003 #30 0x00007f6c3c3584f9 in nl_recvmsgs (sk=<optimized out>, cb=<optimized out>) at nl.c:1027 #31 0x00007f6c3e929dca in event_handler (channel=0x7f6c3fa78810, io_condition=G_IO_IN, user_data=0x7f6c3fa7a870) at platform/nm-linux-platform.c:4127 #32 0x00007f6c3aecc2a6 in g_main_dispatch (context=0x7f6c3fa68490) at gmain.c:3066 #33 g_main_context_dispatch (context=context@entry=0x7f6c3fa68490) at gmain.c:3642 #34 0x00007f6c3aecc628 in g_main_context_iterate (context=0x7f6c3fa68490, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713 #35 0x00007f6c3aecca3a in g_main_loop_run (loop=0x7f6c3fa68550) at gmain.c:3907 #36 0x00007f6c3e8e9fff in main (argc=1, argv=0x7fff0a341c88) at main.c:483 https://bugzilla.gnome.org/show_bug.cgi?id=741651
2014-12-17 00:40:05 +01:00
else
_LOGD (LOGD_DEVICE, "released from master%s", priv->is_enslaved ? "" : " (was not enslaved)");
if (priv->is_enslaved) {
priv->is_enslaved = FALSE;
g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER);
}
}
/**
* nm_device_get_enslaved:
* @self: the #NMDevice
*
* Returns: %TRUE if the device is enslaved to a master device (eg bridge or
* bond or team), %FALSE if not
*/
gboolean
nm_device_get_enslaved (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->is_enslaved;
}
/**
* nm_device_removed:
* @self: the #NMDevice
*
* Called by the manager when the device was removed. Releases the device from
* the master in case it's enslaved.
*/
void
nm_device_removed (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->is_enslaved) {
device: fix disconnecting slave-device when master gets deleted When deleting a master-device either via `nmcli device delete` or `ip link delete`, the slave-device would hang. This seems to be broken for a very long time already. This is due to the following: #0 0x00005555555f548c in nm_device_slave_notify_release (self=0x555555dc1300, reason=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:2175 #1 0x00005555555d6de2 in nm_device_release_one_slave (self=0x555555de3dd0, slave=0x555555dc1300, configure=0, reason=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:1117 #2 0x00005555555f02b7 in device_link_changed (self=0x555555dc1300) at devices/nm-device.c:1460 Previously, nm_device_slave_notify_release() being called with reason "NONE" did not actually transition the device-state, thus keeping the device wrongly in activated state. There were two callers that passed configure=FALSE to nm_device_release_one_slave(), (and thus reason=NONE to nm_device_slave_notify_release()): - (1) device_link_changed(): nm_device_release_one_slave (priv->master, self, FALSE, /*wrong reason NONE*/); - (2) nm_device_removed(): nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); We should always change the device-state during nm_device_slave_notify_release() regardless of the reason. (2) was added by commit c83b40aca76fc0ed624a6c9e71dbd7b0abfa13f2, later refined by commit 5dd48f7527c67b399ac144f594e035216771d61c. In a way change the second fix to perform some of the configuration (but still not unenslaving the device).
2015-12-03 17:18:50 +01:00
/* this is called when something externally messes with the slave or during shut-down.
* Release the slave from master, but don't touch the device. */
nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
device: fix disconnecting slave-device when master gets deleted When deleting a master-device either via `nmcli device delete` or `ip link delete`, the slave-device would hang. This seems to be broken for a very long time already. This is due to the following: #0 0x00005555555f548c in nm_device_slave_notify_release (self=0x555555dc1300, reason=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:2175 #1 0x00005555555d6de2 in nm_device_release_one_slave (self=0x555555de3dd0, slave=0x555555dc1300, configure=0, reason=NM_DEVICE_STATE_REASON_NONE) at devices/nm-device.c:1117 #2 0x00005555555f02b7 in device_link_changed (self=0x555555dc1300) at devices/nm-device.c:1460 Previously, nm_device_slave_notify_release() being called with reason "NONE" did not actually transition the device-state, thus keeping the device wrongly in activated state. There were two callers that passed configure=FALSE to nm_device_release_one_slave(), (and thus reason=NONE to nm_device_slave_notify_release()): - (1) device_link_changed(): nm_device_release_one_slave (priv->master, self, FALSE, /*wrong reason NONE*/); - (2) nm_device_removed(): nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); We should always change the device-state during nm_device_slave_notify_release() regardless of the reason. (2) was added by commit c83b40aca76fc0ed624a6c9e71dbd7b0abfa13f2, later refined by commit 5dd48f7527c67b399ac144f594e035216771d61c. In a way change the second fix to perform some of the configuration (but still not unenslaving the device).
2015-12-03 17:18:50 +01:00
}
}
static gboolean
is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->carrier || priv->ignore_carrier)
return TRUE;
if (NM_FLAGS_HAS (flags, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER))
return TRUE;
return FALSE;
}
/**
* nm_device_is_available:
* @self: the #NMDevice
* @flags: additional flags to influence the check. Flags have the
* meaning to increase the availability of a device.
*
* Checks if @self would currently be capable of activating a
* connection. In particular, it checks that the device is ready (eg,
* is not missing firmware), that it has carrier (if necessary), and
* that any necessary external software (eg, ModemManager,
* wpa_supplicant) is available.
*
* @self can only be in a state higher than
* %NM_DEVICE_STATE_UNAVAILABLE when nm_device_is_available() returns
* %TRUE. (But note that it can still be %NM_DEVICE_STATE_UNMANAGED
* when it is available.)
*
* Returns: %TRUE or %FALSE
*/
2008-03-07 Dan Williams <dcbw@redhat.com> First pass of multiple active device support. Expect bugs. * src/nm-ip4-config.c src/nm-ip4-config.h - (nm_ip4_config_get_secondary, nm_ip4_config_set_secondary): remove; there are better ways to do this in the named manager * src/nm-device.c src/nm-device.h - (nm_device_can_activate): return whether the device can activate a connection right now; taking into account things like carrier state and rfkill state - (nm_device_get_best_auto_connection): renamed from nm_device_get_best_connection - (real_act_stage4_get_ip4_config): MTU stuff is now handled in the device subclasses themselves, so that each device can override the MTU from it's NMSetting subclass if needed - (nm_device_set_ip4_config): set MTU when setting up routes and stuff in NetworkManagerSystem.c, not here * src/named-manager/nm-named-manager.c src/named-manager/nm-named-manager.h - (nm_named_manager_name_owner_changed, nm_named_manager_dbus_connection_changed): fix for changes to rewrite_resolv_conf() - (compute_nameservers): don't need the NMNamedManager at all, remove from parameter list - (merge_one_ip4_config): new function; merge ip4 configs together - (rewrite_resolv_conf): write out resolv.conf from all the stored ip4 configs; the VPN config takes precedence, then the best device config, then the rest of the configs - (get_domain_for_config): take the NMNamedManager as an argument to check whether the config is the VPN config - (add_ip4_config_to_named): fixups for removal of the 'secondary' attribute from ip4 configs - (add_all_ip4_configs_to_named): add all the configs in priority order - (remove_ip4_config_from_named): fix for changes to get_domain_for_config() - (nm_named_manager_add_ip4_config): assign the config to the right slot based on its type; callers must pass in the type now - (get_last_default_domain): remove, unused - (nm_named_manager_remove_ip4_config): handle config slots correctly * src/nm-device-802-11-wireless.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): handle MTU override * src/nm-device-802-3-ethernet.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): new function; handle MTU override * src/vpn-manager/nm-vpn-connection.c - (nm_vpn_connection_ip4_config_get): don't need to set the 'secondary' attribute on the ip4 config * src/NetworkManagerPolicy.c - (nm_policy_auto_get_best_device): remove - (nm_policy_device_change_check): remove - (update_default_route): new function; set the default route via the specified device - (get_device_priority): new function; return the priority number of a device type WRT which one should have the default route. Order is (highest to lowest) wired, wireless, GSM, CDMA. - (update_routing_and_dns): new function; determine which device should have the default route, then update the routing table and DNS - (maybe_auto_activate_device): new function; if a device is now available for activation, find out what connection it would like to activate and do it - (schedule_activate_check): new function; if a device can be activated now, schedule the activation. Each device may have only one pending activation at a given time. - (device_state_changed): if activation was canceled, try again, possibly with another connection; if the device was activated, update routing and DNS; if the device was deactivated, try again with another connection - (device_carrier_changed): if there is no carrier, deactivate the device; otherwise schedule an activation check for the device - (wireless_networks_changed): schedule an activation check for the device - (device_added): keep track of the signal handler IDs so they can be removed when the device goes away - (device_removed): remove any signal handlers that might be attached to the device; update routing and DNS - (schedule_activate_all): new function - (connections_added, connection_added, connection_updated): when connections change, schedule all devices for an activation check - (connection_removed): when a device is deactivated because its connection was removed, schedule another activation check for it - (nm_policy_destroy): destroy pending activations and disconnect all device signal handlers * src/nm-manager.c - (nm_manager_activate_device): if the device was already actived, deactivate it - (deactivate_old_device): remove - (connection_added_default_handler, impl_manager_activate_device): don't deactivate other devices when activating this one * src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerArch.c src/backends/NetworkManagerSuSE.c src/backends/NetworkManagerDebian.c - (nm_system_get_mtu): remove; MTU should be provided through the distro's system settings service plugin instead - (nm_system_device_add_default_route_via_device): remove - (nm_system_device_add_default_route_via_device_with_iface): remove - (nm_system_device_replace_default_route): new function; call generic implementation * src/backends/NetworkManagerGeneric.c src/backends/NetworkManagerGeneric.h - (nm_generic_device_add_default_route_via_device, nm_generic_device_add_default_route_via_device_with_iface): remove - (nm_generic_device_replace_default_route): replace the default route with the given route via some gateway * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_from_ip4_config): let the policy handle updates to routing and DNS; but set the MTU here - (nm_system_vpn_device_set_from_ip4_config): set the route with the ip_iface of the active device; use the standard MTU setting function - (nm_system_set_mtu): remove - (nm_system_device_set_mtu): consolidate MTU setting code in one place git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3391 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-03-07 19:41:32 +00:00
gboolean
nm_device_is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags)
2008-03-07 Dan Williams <dcbw@redhat.com> First pass of multiple active device support. Expect bugs. * src/nm-ip4-config.c src/nm-ip4-config.h - (nm_ip4_config_get_secondary, nm_ip4_config_set_secondary): remove; there are better ways to do this in the named manager * src/nm-device.c src/nm-device.h - (nm_device_can_activate): return whether the device can activate a connection right now; taking into account things like carrier state and rfkill state - (nm_device_get_best_auto_connection): renamed from nm_device_get_best_connection - (real_act_stage4_get_ip4_config): MTU stuff is now handled in the device subclasses themselves, so that each device can override the MTU from it's NMSetting subclass if needed - (nm_device_set_ip4_config): set MTU when setting up routes and stuff in NetworkManagerSystem.c, not here * src/named-manager/nm-named-manager.c src/named-manager/nm-named-manager.h - (nm_named_manager_name_owner_changed, nm_named_manager_dbus_connection_changed): fix for changes to rewrite_resolv_conf() - (compute_nameservers): don't need the NMNamedManager at all, remove from parameter list - (merge_one_ip4_config): new function; merge ip4 configs together - (rewrite_resolv_conf): write out resolv.conf from all the stored ip4 configs; the VPN config takes precedence, then the best device config, then the rest of the configs - (get_domain_for_config): take the NMNamedManager as an argument to check whether the config is the VPN config - (add_ip4_config_to_named): fixups for removal of the 'secondary' attribute from ip4 configs - (add_all_ip4_configs_to_named): add all the configs in priority order - (remove_ip4_config_from_named): fix for changes to get_domain_for_config() - (nm_named_manager_add_ip4_config): assign the config to the right slot based on its type; callers must pass in the type now - (get_last_default_domain): remove, unused - (nm_named_manager_remove_ip4_config): handle config slots correctly * src/nm-device-802-11-wireless.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): handle MTU override * src/nm-device-802-3-ethernet.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): new function; handle MTU override * src/vpn-manager/nm-vpn-connection.c - (nm_vpn_connection_ip4_config_get): don't need to set the 'secondary' attribute on the ip4 config * src/NetworkManagerPolicy.c - (nm_policy_auto_get_best_device): remove - (nm_policy_device_change_check): remove - (update_default_route): new function; set the default route via the specified device - (get_device_priority): new function; return the priority number of a device type WRT which one should have the default route. Order is (highest to lowest) wired, wireless, GSM, CDMA. - (update_routing_and_dns): new function; determine which device should have the default route, then update the routing table and DNS - (maybe_auto_activate_device): new function; if a device is now available for activation, find out what connection it would like to activate and do it - (schedule_activate_check): new function; if a device can be activated now, schedule the activation. Each device may have only one pending activation at a given time. - (device_state_changed): if activation was canceled, try again, possibly with another connection; if the device was activated, update routing and DNS; if the device was deactivated, try again with another connection - (device_carrier_changed): if there is no carrier, deactivate the device; otherwise schedule an activation check for the device - (wireless_networks_changed): schedule an activation check for the device - (device_added): keep track of the signal handler IDs so they can be removed when the device goes away - (device_removed): remove any signal handlers that might be attached to the device; update routing and DNS - (schedule_activate_all): new function - (connections_added, connection_added, connection_updated): when connections change, schedule all devices for an activation check - (connection_removed): when a device is deactivated because its connection was removed, schedule another activation check for it - (nm_policy_destroy): destroy pending activations and disconnect all device signal handlers * src/nm-manager.c - (nm_manager_activate_device): if the device was already actived, deactivate it - (deactivate_old_device): remove - (connection_added_default_handler, impl_manager_activate_device): don't deactivate other devices when activating this one * src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerArch.c src/backends/NetworkManagerSuSE.c src/backends/NetworkManagerDebian.c - (nm_system_get_mtu): remove; MTU should be provided through the distro's system settings service plugin instead - (nm_system_device_add_default_route_via_device): remove - (nm_system_device_add_default_route_via_device_with_iface): remove - (nm_system_device_replace_default_route): new function; call generic implementation * src/backends/NetworkManagerGeneric.c src/backends/NetworkManagerGeneric.h - (nm_generic_device_add_default_route_via_device, nm_generic_device_add_default_route_via_device_with_iface): remove - (nm_generic_device_replace_default_route): replace the default route with the given route via some gateway * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_from_ip4_config): let the policy handle updates to routing and DNS; but set the MTU here - (nm_system_vpn_device_set_from_ip4_config): set the route with the ip_iface of the active device; use the standard MTU setting function - (nm_system_set_mtu): remove - (nm_system_device_set_mtu): consolidate MTU setting code in one place git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3391 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-03-07 19:41:32 +00:00
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->firmware_missing)
return FALSE;
return NM_DEVICE_GET_CLASS (self)->is_available (self, flags);
2008-03-07 Dan Williams <dcbw@redhat.com> First pass of multiple active device support. Expect bugs. * src/nm-ip4-config.c src/nm-ip4-config.h - (nm_ip4_config_get_secondary, nm_ip4_config_set_secondary): remove; there are better ways to do this in the named manager * src/nm-device.c src/nm-device.h - (nm_device_can_activate): return whether the device can activate a connection right now; taking into account things like carrier state and rfkill state - (nm_device_get_best_auto_connection): renamed from nm_device_get_best_connection - (real_act_stage4_get_ip4_config): MTU stuff is now handled in the device subclasses themselves, so that each device can override the MTU from it's NMSetting subclass if needed - (nm_device_set_ip4_config): set MTU when setting up routes and stuff in NetworkManagerSystem.c, not here * src/named-manager/nm-named-manager.c src/named-manager/nm-named-manager.h - (nm_named_manager_name_owner_changed, nm_named_manager_dbus_connection_changed): fix for changes to rewrite_resolv_conf() - (compute_nameservers): don't need the NMNamedManager at all, remove from parameter list - (merge_one_ip4_config): new function; merge ip4 configs together - (rewrite_resolv_conf): write out resolv.conf from all the stored ip4 configs; the VPN config takes precedence, then the best device config, then the rest of the configs - (get_domain_for_config): take the NMNamedManager as an argument to check whether the config is the VPN config - (add_ip4_config_to_named): fixups for removal of the 'secondary' attribute from ip4 configs - (add_all_ip4_configs_to_named): add all the configs in priority order - (remove_ip4_config_from_named): fix for changes to get_domain_for_config() - (nm_named_manager_add_ip4_config): assign the config to the right slot based on its type; callers must pass in the type now - (get_last_default_domain): remove, unused - (nm_named_manager_remove_ip4_config): handle config slots correctly * src/nm-device-802-11-wireless.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): handle MTU override * src/nm-device-802-3-ethernet.c - (real_can_activate): new function - (real_get_best_auto_connection): renamed from real_get_best_connection - (real_act_stage4_get_ip4_config): new function; handle MTU override * src/vpn-manager/nm-vpn-connection.c - (nm_vpn_connection_ip4_config_get): don't need to set the 'secondary' attribute on the ip4 config * src/NetworkManagerPolicy.c - (nm_policy_auto_get_best_device): remove - (nm_policy_device_change_check): remove - (update_default_route): new function; set the default route via the specified device - (get_device_priority): new function; return the priority number of a device type WRT which one should have the default route. Order is (highest to lowest) wired, wireless, GSM, CDMA. - (update_routing_and_dns): new function; determine which device should have the default route, then update the routing table and DNS - (maybe_auto_activate_device): new function; if a device is now available for activation, find out what connection it would like to activate and do it - (schedule_activate_check): new function; if a device can be activated now, schedule the activation. Each device may have only one pending activation at a given time. - (device_state_changed): if activation was canceled, try again, possibly with another connection; if the device was activated, update routing and DNS; if the device was deactivated, try again with another connection - (device_carrier_changed): if there is no carrier, deactivate the device; otherwise schedule an activation check for the device - (wireless_networks_changed): schedule an activation check for the device - (device_added): keep track of the signal handler IDs so they can be removed when the device goes away - (device_removed): remove any signal handlers that might be attached to the device; update routing and DNS - (schedule_activate_all): new function - (connections_added, connection_added, connection_updated): when connections change, schedule all devices for an activation check - (connection_removed): when a device is deactivated because its connection was removed, schedule another activation check for it - (nm_policy_destroy): destroy pending activations and disconnect all device signal handlers * src/nm-manager.c - (nm_manager_activate_device): if the device was already actived, deactivate it - (deactivate_old_device): remove - (connection_added_default_handler, impl_manager_activate_device): don't deactivate other devices when activating this one * src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerArch.c src/backends/NetworkManagerSuSE.c src/backends/NetworkManagerDebian.c - (nm_system_get_mtu): remove; MTU should be provided through the distro's system settings service plugin instead - (nm_system_device_add_default_route_via_device): remove - (nm_system_device_add_default_route_via_device_with_iface): remove - (nm_system_device_replace_default_route): new function; call generic implementation * src/backends/NetworkManagerGeneric.c src/backends/NetworkManagerGeneric.h - (nm_generic_device_add_default_route_via_device, nm_generic_device_add_default_route_via_device_with_iface): remove - (nm_generic_device_replace_default_route): replace the default route with the given route via some gateway * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_from_ip4_config): let the policy handle updates to routing and DNS; but set the MTU here - (nm_system_vpn_device_set_from_ip4_config): set the route with the ip_iface of the active device; use the standard MTU setting function - (nm_system_set_mtu): remove - (nm_system_device_set_mtu): consolidate MTU setting code in one place git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3391 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-03-07 19:41:32 +00:00
}
gboolean
nm_device_get_enabled (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
if (NM_DEVICE_GET_CLASS (self)->get_enabled)
return NM_DEVICE_GET_CLASS (self)->get_enabled (self);
return TRUE;
}
void
nm_device_set_enabled (NMDevice *self, gboolean enabled)
{
g_return_if_fail (NM_IS_DEVICE (self));
if (NM_DEVICE_GET_CLASS (self)->set_enabled)
NM_DEVICE_GET_CLASS (self)->set_enabled (self, enabled);
}
/**
* nm_device_get_autoconnect:
* @self: the #NMDevice
*
* Returns: %TRUE if the device allows autoconnect connections, or %FALSE if the
* device is explicitly blocking all autoconnect connections. Does not take
* into account transient conditions like companion devices that may wish to
* block the device.
*/
gboolean
nm_device_get_autoconnect (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
return NM_DEVICE_GET_PRIVATE (self)->autoconnect;
}
void
nm_device_set_autoconnect (NMDevice *self, gboolean autoconnect)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->autoconnect == autoconnect)
return;
if (autoconnect) {
/* Default-unmanaged devices never autoconnect */
if (!nm_device_get_default_unmanaged (self)) {
priv->autoconnect = TRUE;
g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
}
} else {
priv->autoconnect = FALSE;
g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
}
}
static gboolean
autoconnect_allowed_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return, gpointer data)
{
if (!g_value_get_boolean (handler_return))
g_value_set_boolean (return_accu, FALSE);
return TRUE;
}
/**
* nm_device_autoconnect_allowed:
* @self: the #NMDevice
*
* Returns: %TRUE if the device can be auto-connected immediately, taking
* transient conditions into account (like companion devices that may wish to
* block autoconnect for a time).
*/
gboolean
nm_device_autoconnect_allowed (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GValue instance = G_VALUE_INIT;
GValue retval = G_VALUE_INIT;
if (priv->state < NM_DEVICE_STATE_DISCONNECTED || !priv->autoconnect)
return FALSE;
/* The 'autoconnect-allowed' signal is emitted on a device to allow
* other listeners to block autoconnect on the device if they wish.
* This is mainly used by the OLPC Mesh devices to block autoconnect
* on their companion WiFi device as they share radio resources and
* cannot be connected at the same time.
*/
g_value_init (&instance, G_TYPE_OBJECT);
g_value_set_object (&instance, self);
g_value_init (&retval, G_TYPE_BOOLEAN);
if (priv->autoconnect)
g_value_set_boolean (&retval, TRUE);
else
g_value_set_boolean (&retval, FALSE);
/* Use g_signal_emitv() rather than g_signal_emit() to avoid the return
* value being changed if no handlers are connected */
g_signal_emitv (&instance, signals[AUTOCONNECT_ALLOWED], 0, &retval);
g_value_unset (&instance);
return g_value_get_boolean (&retval);
}
static gboolean
can_auto_connect (NMDevice *self,
NMConnection *connection,
char **specific_object)
{
NMSettingConnection *s_con;
s_con = nm_connection_get_setting_connection (connection);
if (!nm_setting_connection_get_autoconnect (s_con))
return FALSE;
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
return nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL);
}
/**
* nm_device_can_auto_connect:
* @self: an #NMDevice
* @connection: a #NMConnection
* @specific_object: (out) (transfer full): on output, the path of an
* object associated with the returned connection, to be passed to
* nm_manager_activate_connection(), or %NULL.
*
* Checks if @connection can be auto-activated on @self right now.
* This requires, at a minimum, that the connection be compatible with
* @self, and that it have the #NMSettingConnection:autoconnect property
* set, and that the device allow auto connections. Some devices impose
* additional requirements. (Eg, a Wi-Fi connection can only be activated
* if its SSID was seen in the last scan.)
*
* Returns: %TRUE, if the @connection can be auto-activated.
**/
gboolean
nm_device_can_auto_connect (NMDevice *self,
NMConnection *connection,
char **specific_object)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
g_return_val_if_fail (specific_object && !*specific_object, FALSE);
if (nm_device_autoconnect_allowed (self))
return NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object);
return FALSE;
}
static gboolean
device_has_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* Check for IP configuration. */
if (priv->ip4_config && nm_ip4_config_get_num_addresses (priv->ip4_config))
return TRUE;
if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config))
return TRUE;
/* The existence of a software device is good enough. */
if (nm_device_is_software (self) && nm_device_is_real (self))
return TRUE;
/* Slaves are also configured by definition */
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) > 0)
return TRUE;
return FALSE;
}
/**
* nm_device_master_update_slave_connection:
* @self: the master #NMDevice
* @slave: the slave #NMDevice
* @connection: the #NMConnection to update with the slave settings
* @GError: (out): error description
*
* Reads the slave configuration for @slave and updates @connection with those
* properties. This invokes a virtual function on the master device @self.
*
* Returns: %TRUE if the configuration was read and @connection updated,
* %FALSE on failure.
*/
gboolean
nm_device_master_update_slave_connection (NMDevice *self,
NMDevice *slave,
NMConnection *connection,
GError **error)
{
NMDeviceClass *klass;
gboolean success;
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (slave, FALSE);
g_return_val_if_fail (connection, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
g_return_val_if_fail (nm_connection_get_setting_connection (connection), FALSE);
g_return_val_if_fail (nm_device_get_iface (self), FALSE);
klass = NM_DEVICE_GET_CLASS (self);
if (klass->master_update_slave_connection) {
success = klass->master_update_slave_connection (self, slave, connection, error);
g_return_val_if_fail (!error || (success && !*error) || *error, success);
return success;
}
g_set_error (error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_FAILED,
"master device '%s' cannot update a slave connection for slave device '%s' (master type not supported?)",
nm_device_get_iface (self), nm_device_get_iface (slave));
return FALSE;
}
NMConnection *
nm_device_generate_connection (NMDevice *self, NMDevice *master)
{
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *ifname = nm_device_get_iface (self);
NMConnection *connection;
NMSetting *s_con;
NMSetting *s_ip4;
NMSetting *s_ip6;
gs_free char *uuid = NULL;
const char *ip4_method, *ip6_method;
GError *error = NULL;
/* If update_connection() is not implemented, just fail. */
if (!klass->update_connection)
return NULL;
/* Return NULL if device is unconfigured. */
if (!device_has_config (self)) {
_LOGD (LOGD_DEVICE, "device has no existing configuration");
return NULL;
}
connection = nm_simple_connection_new ();
s_con = nm_setting_connection_new ();
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_ID, ifname,
NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL),
NULL);
if (klass->connection_type)
g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type, NULL);
nm_connection_add_setting (connection, s_con);
/* If the device is a slave, update various slave settings */
if (master) {
if (!nm_device_master_update_slave_connection (master,
self,
connection,
&error))
{
_LOGE (LOGD_DEVICE, "master device '%s' failed to update slave connection: %s",
nm_device_get_iface (master), error ? error->message : "(unknown error)");
g_error_free (error);
g_object_unref (connection);
return NULL;
}
} else {
/* Only regular and master devices get IP configuration; slaves do not */
s_ip4 = nm_ip4_config_create_setting (priv->ip4_config);
nm_connection_add_setting (connection, s_ip4);
s_ip6 = nm_ip6_config_create_setting (priv->ip6_config);
nm_connection_add_setting (connection, s_ip6);
}
klass->update_connection (self, connection);
/* Check the connection in case of update_connection() bug. */
if (!nm_connection_verify (connection, &error)) {
_LOGE (LOGD_DEVICE, "Generated connection does not verify: %s", error->message);
g_clear_error (&error);
g_object_unref (connection);
return NULL;
}
/* Ignore the connection if it has no IP configuration,
* no slave configuration, and is not a master interface.
*/
ip4_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
ip6_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
if ( g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0
&& g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0
&& !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))
&& !priv->slaves) {
_LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not in master-slave relationship)");
g_object_unref (connection);
connection = NULL;
}
/* Ignore any IPv6LL-only, not master connections without slaves,
* unless they are in the assume-ipv6ll-only list.
*/
if ( connection
&& g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0
&& g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0
&& !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))
&& !priv->slaves
&& !nm_config_data_get_assume_ipv6ll_only (NM_CONFIG_GET_DATA, self)) {
_LOGD (LOGD_DEVICE, "ignoring generated connection (IPv6LL-only and not in master-slave relationship)");
g_object_unref (connection);
connection = NULL;
}
return connection;
}
gboolean
nm_device_complete_connection (NMDevice *self,
NMConnection *connection,
const char *specific_object,
const GSList *existing_connections,
GError **error)
{
gboolean success = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (connection != NULL, FALSE);
if (!NM_DEVICE_GET_CLASS (self)->complete_connection) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
"Device class %s had no complete_connection method",
G_OBJECT_TYPE_NAME (self));
return FALSE;
}
success = NM_DEVICE_GET_CLASS (self)->complete_connection (self,
connection,
specific_object,
existing_connections,
error);
if (success)
success = nm_connection_verify (connection, error);
return success;
}
static gboolean
check_connection_compatible (NMDevice *self, NMConnection *connection)
{
NMSettingConnection *s_con;
const char *config_iface, *device_iface;
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
config_iface = nm_setting_connection_get_interface_name (s_con);
device_iface = nm_device_get_iface (self);
if (config_iface && strcmp (config_iface, device_iface) != 0)
return FALSE;
return TRUE;
}
2013-03-13 13:52:55 -04:00
/**
* nm_device_check_connection_compatible:
* @self: an #NMDevice
2013-03-13 13:52:55 -04:00
* @connection: an #NMConnection
*
* Checks if @connection could potentially be activated on @self.
* This means only that @self has the proper capabilities, and that
2013-03-13 13:52:55 -04:00
* @connection is not locked to some other device. It does not
* necessarily mean that @connection could be activated on @self
2013-03-13 13:52:55 -04:00
* right now. (Eg, it might refer to a Wi-Fi network that is not
* currently available.)
*
* Returns: #TRUE if @connection could potentially be activated on
* @self.
2013-03-13 13:52:55 -04:00
*/
gboolean
nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection);
}
gboolean
nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave)
{
NMDevicePrivate *priv;
NMSettingConnection *s_con;
const char *connection_type, *slave_type;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (slave), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->is_master)
return FALSE;
/* All masters should have connection type set */
connection_type = NM_DEVICE_GET_CLASS (self)->connection_type;
g_return_val_if_fail (connection_type, FALSE);
s_con = nm_connection_get_setting_connection (slave);
g_assert (s_con);
slave_type = nm_setting_connection_get_slave_type (s_con);
if (!slave_type)
return FALSE;
return strcmp (connection_type, slave_type) == 0;
}
/**
* nm_device_can_assume_connections:
* @self: #NMDevice instance
*
* This is a convenience function to determine whether connection assumption
* is available for this device.
*
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
* Returns: %TRUE if the device is capable of assuming connections, %FALSE if not
*/
static gboolean
nm_device_can_assume_connections (NMDevice *self)
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
{
return !!NM_DEVICE_GET_CLASS (self)->update_connection
&& !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
}
/**
* nm_device_can_assume_active_connection:
* @self: #NMDevice instance
*
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
* This is a convenience function to determine whether the device's active
* connection can be assumed if NetworkManager restarts. This method returns
* %TRUE if and only if the device can assume connections, and the device has
* an active connection, and that active connection can be assumed.
*
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
* Returns: %TRUE if the device's active connection can be assumed, or %FALSE
* if there is no active connection or the active connection cannot be
* assumed.
*/
gboolean
nm_device_can_assume_active_connection (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
NMConnection *connection;
const char *method;
const char *assumable_ip6_methods[] = {
NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
NM_SETTING_IP6_CONFIG_METHOD_AUTO,
NM_SETTING_IP6_CONFIG_METHOD_DHCP,
NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
NULL
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
};
const char *assumable_ip4_methods[] = {
NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
NM_SETTING_IP6_CONFIG_METHOD_AUTO,
NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
NULL
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
};
if (!nm_device_can_assume_connections (self))
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
return FALSE;
connection = nm_device_get_applied_connection (self);
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
if (!connection)
return FALSE;
/* Can't assume connections that aren't yet configured
* FIXME: what about bridges/bonds waiting for slaves?
*/
if (priv->state < NM_DEVICE_STATE_IP_CONFIG)
return FALSE;
if (priv->ip4_state != IP_DONE && priv->ip6_state != IP_DONE)
return FALSE;
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (!_nm_utils_string_in_list (method, assumable_ip6_methods))
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
return FALSE;
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (!_nm_utils_string_in_list (method, assumable_ip4_methods))
core: don't do anything interesting in NMDevice dispose() The NMDevice dispose() function contained some badly-duplicated logic about when to deactivate a device on its last ref. This logic should only run when the device is removed by the manager, since the manager controls the device's life-cycle, and the manager knows best when to clean up the device. But since it was tied to the device's refcount, it could have run later than the manager wanted, or not at all. It gets better. Dispose duplicated logic that was already done in nm_device_cleanup(), and then *called* nm_device_cleanup() if the device was still activated and managed. But the manager already unmanages the device when removing it, which triggers a call to nm_device_cleanup(), takes the device down, and resets the IPv6 sysctl properties, which dispose() duplicated too. So by the time dispose() runs, the device should already be unmanaged if the manager wants to deconfigure it, and most of the dispose() code should be a no-op. Clean all that up and remove duplicated functions. Now, the flow should be like this: 1) manager decides to remove the device and calls remove_device() 2) if the device should be deconfigured, the manager unmanages the device 3) the NMDevice state change handler tears down the active connection via nm_device_cleanup() and resets IPv6 sysctl properties 4) when the device's last reference is finally released, only internal data members are freed in dispose() because the device should already have been cleaned up by the manager and be unmanaged 5) if the device should be left running because it has an assumable connection, then the device is not unmanaged, and no cleanup happens in the state change handler or in dispose()
2014-05-23 15:41:46 -05:00
return FALSE;
return TRUE;
}
static gboolean
nm_device_emit_recheck_assume (gpointer self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->recheck_assume_id = 0;
if (!nm_device_get_act_request (self)) {
_LOGD (LOGD_DEVICE, "emit RECHECK_ASSUME signal");
g_signal_emit (self, signals[RECHECK_ASSUME], 0);
}
return G_SOURCE_REMOVE;
}
void
nm_device_queue_recheck_assume (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (nm_device_can_assume_connections (self) && !priv->recheck_assume_id)
priv->recheck_assume_id = g_idle_add (nm_device_emit_recheck_assume, self);
}
static gboolean
recheck_available (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean now_available = nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
NMDeviceState state = nm_device_get_state (self);
NMDeviceState new_state = NM_DEVICE_STATE_UNKNOWN;
priv->recheck_available.call_id = 0;
if (state == NM_DEVICE_STATE_UNAVAILABLE && now_available) {
new_state = NM_DEVICE_STATE_DISCONNECTED;
nm_device_queue_state (self, new_state, priv->recheck_available.available_reason);
} else if (state >= NM_DEVICE_STATE_DISCONNECTED && !now_available) {
new_state = NM_DEVICE_STATE_UNAVAILABLE;
nm_device_queue_state (self, new_state, priv->recheck_available.unavailable_reason);
}
if (new_state > NM_DEVICE_STATE_UNKNOWN) {
_LOGD (LOGD_DEVICE, "device is %savailable, %s %s",
now_available ? "" : "not ",
new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to",
state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state));
priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE;
priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE;
}
return G_SOURCE_REMOVE;
}
void
nm_device_queue_recheck_available (NMDevice *self,
NMDeviceStateReason available_reason,
NMDeviceStateReason unavailable_reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->recheck_available.available_reason = available_reason;
priv->recheck_available.unavailable_reason = unavailable_reason;
if (!priv->recheck_available.call_id)
priv->recheck_available.call_id = g_idle_add (recheck_available, self);
}
void
nm_device_emit_recheck_auto_activate (NMDevice *self)
{
g_signal_emit (self, signals[RECHECK_AUTO_ACTIVATE], 0);
}
static void
dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
switch (status) {
case NM_DNSMASQ_STATUS_DEAD:
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
break;
default:
break;
}
}
/*****************************************************************************/
static gboolean
activation_source_handle_cb4 (gpointer user_data)
{
activation_source_handle_cb (user_data, AF_INET);
return G_SOURCE_REMOVE;
}
static gboolean
activation_source_handle_cb6 (gpointer user_data)
{
activation_source_handle_cb (user_data, AF_INET6);
return G_SOURCE_REMOVE;
}
static ActivationHandleData *
activation_source_get_by_family (NMDevice *self,
int family,
GSourceFunc *out_idle_func)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (family == AF_INET6) {
NM_SET_OUT (out_idle_func, activation_source_handle_cb6);
return &priv->act_handle6;
} else {
NM_SET_OUT (out_idle_func, activation_source_handle_cb4);
g_return_val_if_fail (family == AF_INET, &priv->act_handle4);
return &priv->act_handle4;
}
}
static void
activation_source_clear (NMDevice *self, int family)
{
ActivationHandleData *act_data;
act_data = activation_source_get_by_family (self, family, NULL);
if (act_data->id) {
_LOGD (LOGD_DEVICE, "activation-stage: clear %s,%d (id %u)",
_activation_func_to_string (act_data->func), family, act_data->id);
nm_clear_g_source (&act_data->id);
act_data->func = NULL;
}
}
static void
activation_source_handle_cb (NMDevice *self, int family)
{
ActivationHandleData *act_data, a;
g_return_if_fail (NM_IS_DEVICE (self));
act_data = activation_source_get_by_family (self, family, NULL);
g_return_if_fail (act_data->id);
g_return_if_fail (act_data->func);
a = *act_data;
act_data->func = NULL;
act_data->id = 0;
_LOGD (LOGD_DEVICE, "activation-stage: invoke %s,%d (id %u)",
_activation_func_to_string (a.func), family, a.id);
a.func (self);
_LOGD (LOGD_DEVICE, "activation-stage: complete %s,%d (id %u)",
_activation_func_to_string (a.func), family, a.id);
}
static void
activation_source_schedule (NMDevice *self, ActivationHandleFunc func, int family)
{
ActivationHandleData *act_data;
GSourceFunc source_func;
guint new_id = 0;
act_data = activation_source_get_by_family (self, family, &source_func);
if (act_data->id && act_data->func != func) {
/* Don't bother rescheduling the same function that's about to
* run anyway. Fixes issues with crappy wireless drivers sending
* streams of associate events before NM has had a chance to process
* the first one.
*/
_LOGD (LOGD_DEVICE, "activation-stage: already scheduled %s,%d (id %u)",
_activation_func_to_string (func), family, act_data->id);
return;
}
new_id = g_idle_add (source_func, self);
if (act_data->id) {
_LOGW (LOGD_DEVICE, "activation-stage: schedule %s,%d which replaces %s,%d (id %u -> %u)",
_activation_func_to_string (func), family,
_activation_func_to_string (act_data->func), family,
act_data->id, new_id);
nm_clear_g_source (&act_data->id);
} else {
_LOGD (LOGD_DEVICE, "activation-stage: schedule %s,%d (id %u)",
_activation_func_to_string (func), family, new_id);
}
act_data->func = func;
act_data->id = new_id;
}
/*****************************************************************************/
static gboolean
get_ip_config_may_fail (NMDevice *self, int family)
{
NMConnection *connection;
NMSettingIPConfig *s_ip = NULL;
g_return_val_if_fail (self != NULL, TRUE);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
/* Fail the connection if the failed IP method is required to complete */
switch (family) {
case AF_INET:
s_ip = nm_connection_get_setting_ip4_config (connection);
break;
case AF_INET6:
s_ip = nm_connection_get_setting_ip6_config (connection);
break;
default:
g_assert_not_reached ();
}
return nm_setting_ip_config_get_may_fail (s_ip);
}
static void
master_ready (NMDevice *self,
NMActiveConnection *active)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActiveConnection *master;
g_return_if_fail (priv->state == NM_DEVICE_STATE_PREPARE);
g_return_if_fail (!priv->master_ready_handled);
/* Notify a master device that it has a new slave */
g_return_if_fail (nm_active_connection_get_master_ready (active));
master = nm_active_connection_get_master (active);
priv->master_ready_handled = TRUE;
nm_clear_g_signal_handler (active, &priv->master_ready_id);
priv->master = g_object_ref (nm_active_connection_get_device (master));
nm_device_master_add_slave (priv->master,
self,
nm_active_connection_get_assumed (active) ? FALSE : TRUE);
_LOGD (LOGD_DEVICE, "master connection ready; master device %s",
nm_device_get_iface (priv->master));
}
static void
master_ready_cb (NMActiveConnection *active,
GParamSpec *pspec,
NMDevice *self)
{
master_ready (self, active);
nm_device_activate_schedule_stage2_device_config (self);
}
static void
lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec,
gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
g_object_notify (G_OBJECT (self), NM_DEVICE_LLDP_NEIGHBORS);
}
static gboolean
lldp_rx_enabled (NMDevice *self)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT;
connection = nm_device_get_applied_connection (self);
g_return_val_if_fail (connection, FALSE);
s_con = nm_connection_get_setting_connection (connection);
g_return_val_if_fail (s_con, FALSE);
lldp = nm_setting_connection_get_lldp (s_con);
if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) {
gs_free char *value = NULL;
value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"connection.lldp",
self);
lldp = _nm_utils_ascii_str_to_int64 (value, 10,
NM_SETTING_CONNECTION_LLDP_DEFAULT,
NM_SETTING_CONNECTION_LLDP_ENABLE_RX,
NM_SETTING_CONNECTION_LLDP_DEFAULT);
if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT)
lldp = NM_SETTING_CONNECTION_LLDP_DISABLE;
}
return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX;
}
static NMActStageReturn
act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
{
return NM_ACT_STAGE_RETURN_SUCCESS;
}
/*
* activate_stage1_device_prepare
*
* Prepare for device activation
*
*/
static void
activate_stage1_device_prepare (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
priv->ip4_state = priv->ip6_state = IP_NONE;
/* Notify the new ActiveConnection along with the state change */
g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
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) {
return;
} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return;
}
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
}
nm_device_activate_schedule_stage2_device_config (self);
}
/*
* nm_device_activate_schedule_stage1_device_prepare
*
* Prepare a device for activation
*
*/
void
nm_device_activate_schedule_stage1_device_prepare (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->act_request);
activation_source_schedule (self, activate_stage1_device_prepare, AF_INET);
}
static NMActStageReturn
act_stage2_config (NMDevice *self, NMDeviceStateReason *reason)
{
/* Nothing to do */
return NM_ACT_STAGE_RETURN_SUCCESS;
}
/*
* activate_stage2_device_config
*
* Determine device parameters and set those on the device, ie
* for wireless devices, set SSID, keys, etc.
*
*/
static void
activate_stage2_device_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
gboolean no_firmware = FALSE;
NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
GSList *iter;
nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
/* 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);
return;
}
ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &reason);
if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
return;
else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return;
}
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
}
/* 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;
NMDeviceState slave_state = nm_device_get_state (info->slave);
if (slave_state == NM_DEVICE_STATE_IP_CONFIG)
nm_device_master_enslave_slave (self, info->slave, nm_device_get_applied_connection (info->slave));
else if ( nm_device_uses_generated_assumed_connection (self)
&& slave_state <= NM_DEVICE_STATE_DISCONNECTED)
nm_device_queue_recheck_assume (info->slave);
}
if (lldp_rx_enabled (self)) {
gs_free_error GError *error = NULL;
gconstpointer addr;
size_t addr_length;
if (priv->lldp_listener)
nm_lldp_listener_stop (priv->lldp_listener);
else {
priv->lldp_listener = nm_lldp_listener_new ();
g_signal_connect (priv->lldp_listener,
"notify::" NM_LLDP_LISTENER_NEIGHBORS,
G_CALLBACK (lldp_neighbors_changed),
self);
}
addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length);
if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self),
nm_device_get_iface (self), addr, addr_length, &error))
_LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener);
else {
_LOGD (LOGD_DEVICE, "LLDP listener %p could not be started: %s",
priv->lldp_listener, error->message);
}
}
nm_device_activate_schedule_stage3_ip_config_start (self);
}
/*
* nm_device_activate_schedule_stage2_device_config
*
* Schedule setup of the hardware device
*
*/
void
nm_device_activate_schedule_stage2_device_config (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->act_request);
if (!priv->master_ready_handled) {
NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
if (!nm_active_connection_get_master (active)) {
g_warn_if_fail (!priv->master_ready_id);
priv->master_ready_handled = TRUE;
} else {
/* If the master connection is ready for slaves, attach ourselves */
if (nm_active_connection_get_master_ready (active))
master_ready (self, active);
else {
_LOGD (LOGD_DEVICE, "waiting for master connection to become ready");
if (priv->master_ready_id == 0) {
priv->master_ready_id = g_signal_connect (active,
"notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY,
(GCallback) master_ready_cb,
self);
}
/* Postpone */
return;
}
}
}
activation_source_schedule (self, activate_stage2_device_config, AF_INET);
}
/*
* nm_device_check_ip_failed
*
* Progress the device to appropriate state if both IPv4 and IPv6 failed
*/
static void
nm_device_check_ip_failed (NMDevice *self, gboolean may_fail)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceState state;
if ( priv->ip4_state != IP_FAIL
|| priv->ip6_state != IP_FAIL)
return;
if (nm_device_uses_assumed_connection (self)) {
/* We have assumed configuration, but couldn't
* redo it. No problem, move to check state. */
priv->ip4_state = priv->ip6_state = IP_DONE;
state = NM_DEVICE_STATE_IP_CHECK;
} else if ( may_fail
&& get_ip_config_may_fail (self, AF_INET)
&& get_ip_config_may_fail (self, AF_INET6)) {
/* Couldn't start either IPv6 and IPv4 autoconfiguration,
* but both are allowed to fail. */
state = NM_DEVICE_STATE_SECONDARIES;
} else {
/* Autoconfiguration attempted without success. */
state = NM_DEVICE_STATE_FAILED;
}
nm_device_state_changed (self,
state,
NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
}
/*********************************************/
/* IPv4LL stuff */
static void
ipv4ll_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2015-04-20 18:13:41 +02:00
if (priv->ipv4ll) {
sd_ipv4ll_set_callback (priv->ipv4ll, NULL, NULL);
sd_ipv4ll_stop (priv->ipv4ll);
priv->ipv4ll = sd_ipv4ll_unref (priv->ipv4ll);
}
nm_clear_g_source (&priv->ipv4ll_timeout);
}
static NMIP4Config *
ipv4ll_get_ip4_config (NMDevice *self, guint32 lla)
{
NMIP4Config *config = NULL;
NMPlatformIP4Address address;
NMPlatformIP4Route route;
config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
g_assert (config);
memset (&address, 0, sizeof (address));
nm_platform_ip4_address_set_addr (&address, lla, 16);
address.source = NM_IP_CONFIG_SOURCE_IP4LL;
nm_ip4_config_add_address (config, &address);
/* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */
memset (&route, 0, sizeof (route));
route.network = htonl (0xE0000000L);
route.plen = 4;
route.source = NM_IP_CONFIG_SOURCE_IP4LL;
route.metric = nm_device_get_ip4_route_metric (self);
nm_ip4_config_add_route (config, &route);
return config;
}
#define IPV4LL_NETWORK (htonl (0xA9FE0000L))
#define IPV4LL_NETMASK (htonl (0xFFFF0000L))
2015-04-20 18:13:41 +02:00
static void
nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data)
{
2015-04-20 18:13:41 +02:00
NMDevice *self = data;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection = NULL;
const char *method;
2015-04-20 18:13:41 +02:00
struct in_addr address;
NMIP4Config *config;
int r;
if (priv->act_request == NULL)
return;
connection = nm_act_request_get_applied_connection (priv->act_request);
g_assert (connection);
/* Ignore if the connection isn't an AutoIP connection */
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) != 0)
return;
2015-04-20 18:13:41 +02:00
switch (event) {
case SD_IPV4LL_EVENT_BIND:
2015-04-20 18:13:41 +02:00
r = sd_ipv4ll_get_address (ll, &address);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r);
priv->ip4_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
return;
}
2015-04-20 18:13:41 +02:00
if ((address.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) {
_LOGE (LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr);
priv->ip4_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
return;
}
2015-04-20 18:13:41 +02:00
config = ipv4ll_get_ip4_config (self, address.s_addr);
if (config == NULL) {
_LOGE (LOGD_AUTOIP4, "failed to get IPv4LL config");
priv->ip4_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
return;
}
if (priv->ip4_state == IP_CONF) {
nm_clear_g_source (&priv->ipv4ll_timeout);
nm_device_activate_schedule_ip4_config_result (self, config);
} else if (priv->ip4_state == IP_DONE) {
if (!ip4_config_merge_and_apply (self, config, TRUE, NULL)) {
_LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change.");
priv->ip4_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
}
} else
g_assert_not_reached ();
g_object_unref (config);
2015-04-20 18:13:41 +02:00
break;
default:
_LOGW (LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event);
priv->ip4_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
}
}
static gboolean
ipv4ll_timeout_cb (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->ipv4ll_timeout) {
2015-04-20 18:13:41 +02:00
_LOGI (LOGD_AUTOIP4, "IPv4LL configuration timed out.");
priv->ipv4ll_timeout = 0;
ipv4ll_cleanup (self);
if (priv->ip4_state == IP_CONF)
nm_device_activate_schedule_ip4_config_timeout (self);
}
return FALSE;
}
static NMActStageReturn
ipv4ll_start (NMDevice *self, NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2015-04-20 18:13:41 +02:00
const struct ether_addr *addr;
int ifindex, r;
size_t addr_len;
ipv4ll_cleanup (self);
2015-04-20 18:13:41 +02:00
r = sd_ipv4ll_new (&priv->ipv4ll);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r);
goto fail;
}
2015-04-20 18:13:41 +02:00
r = sd_ipv4ll_attach_event (priv->ipv4ll, NULL, 0);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r);
goto fail;
}
ifindex = nm_device_get_ip_ifindex (self);
addr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &addr_len);
if (!addr || addr_len != ETH_ALEN) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address");
goto fail;
}
r = sd_ipv4ll_set_mac (priv->ipv4ll, addr);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r);
goto fail;
}
r = sd_ipv4ll_set_index (priv->ipv4ll, ifindex);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: set_index() failed with error %d", r);
goto fail;
}
r = sd_ipv4ll_set_callback (priv->ipv4ll, nm_device_handle_ipv4ll_event, self);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r);
goto fail;
}
r = sd_ipv4ll_start (priv->ipv4ll);
if (r < 0) {
_LOGE (LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r);
goto fail;
}
_LOGI (LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started");
/* Start a timeout to bound the address attempt */
priv->ipv4ll_timeout = g_timeout_add_seconds (20, ipv4ll_timeout_cb, self);
return NM_ACT_STAGE_RETURN_POSTPONE;
2015-04-20 18:13:41 +02:00
fail:
*reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED;
return NM_ACT_STAGE_RETURN_FAILURE;
}
/*********************************************/
static gboolean
_device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route)
{
gboolean success = FALSE;
int ifindex = nm_device_get_ip_ifindex (self);
GArray *routes;
if (addr_family == AF_INET)
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
else
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
if (routes) {
guint route_metric = G_MAXUINT32, m;
const NMPlatformIPRoute *route = NULL, *r;
guint i;
/* if there are several default routes, find the one with the best metric */
for (i = 0; i < routes->len; i++) {
if (addr_family == AF_INET) {
r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, i);
m = r->metric;
} else {
r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, i);
m = nm_utils_ip6_route_metric_normalize (r->metric);
}
if (!route || m < route_metric) {
route = r;
route_metric = m;
}
}
if (route) {
if (addr_family == AF_INET)
*((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
else
*((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
success = TRUE;
}
g_array_free (routes, TRUE);
}
return success;
}
/*********************************************/
static void
ensure_con_ip4_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
NMConnection *connection;
if (priv->con_ip4_config)
return;
connection = nm_device_get_applied_connection (self);
if (!connection)
return;
priv->con_ip4_config = nm_ip4_config_new (ip_ifindex);
nm_ip4_config_merge_setting (priv->con_ip4_config,
nm_connection_get_setting_ip4_config (connection),
nm_device_get_ip4_route_metric (self));
if (nm_device_uses_assumed_connection (self)) {
/* For assumed connections ignore all addresses and routes. */
nm_ip4_config_reset_addresses (priv->con_ip4_config);
nm_ip4_config_reset_routes (priv->con_ip4_config);
}
}
static void
ensure_con_ip6_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
NMConnection *connection;
if (priv->con_ip6_config)
return;
connection = nm_device_get_applied_connection (self);
if (!connection)
return;
priv->con_ip6_config = nm_ip6_config_new (ip_ifindex);
nm_ip6_config_merge_setting (priv->con_ip6_config,
nm_connection_get_setting_ip6_config (connection),
nm_device_get_ip6_route_metric (self));
if (nm_device_uses_assumed_connection (self)) {
/* For assumed connections ignore all addresses and routes. */
nm_ip6_config_reset_addresses (priv->con_ip6_config);
nm_ip6_config_reset_routes (priv->con_ip6_config);
}
}
/*********************************************/
/* DHCPv4 stuff */
static void
dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
nm_clear_g_source (&priv->dhcp4_restart_id);
if (priv->dhcp4_client) {
/* Stop any ongoing DHCP transaction on this device */
if (priv->dhcp4_state_sigid) {
g_signal_handler_disconnect (priv->dhcp4_client, priv->dhcp4_state_sigid);
priv->dhcp4_state_sigid = 0;
}
nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE);
if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE
|| cleanup_type == CLEANUP_TYPE_REMOVED)
nm_dhcp_client_stop (priv->dhcp4_client, release);
g_clear_object (&priv->dhcp4_client);
}
core: fix dhcp4_cleanup() to clear dhcp4_client first (avoids assert accessing NM_DEVICE_DHCP4_CONFIG) dhcp4_cleanup() should first clear @dhcp4_client variables before clearing @dhcp4_config. Otherwise the following assert fails [1] and the DBUS property NM_DEVICE_DHCP4_CONFIG is set to %NULL. Analog to dhcp6_cleanup(), dhcp6_client, and NM_DEVICE_DHCP6_CONFIG. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c148c "unrecognized-specs-changed", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff4710ed60) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x3370cbc89a "%s: assertion '%s' failed") at gmessages.c:1025 #2 0x0000003370c50679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x4c144c "NetworkManager", pretty_function=pretty_function@entry=0x4c6140 <__PRETTY_FUNCTION__.15969> "nm_dhcp4_config_get_dbus_path", expression=expression@entry=0x4c60d9 "NM_IS_DHCP4_CONFIG (self)") at gmessages.c:1034 #3 0x000000000046b1d4 in nm_dhcp4_config_get_dbus_path (self=0x0) at nm-dhcp4-config.c:115 #4 0x0000000000434791 in get_property (object=0x9d2320, prop_id=13, value=0x9618a0, pspec=0x9bbc20) at devices/nm-device.c:7539 #5 0x0000003371c18e73 in object_get_property (value=0x9618a0, pspec=<optimized out>, object=0x9d2320) at gobject.c:1303 #6 g_object_get_property (object=0x9d2320, property_name=<optimized out>, value=0x9618a0) at gobject.c:2402 #7 0x000000000048482c in idle_id_reset (data=<optimized out>) at nm-properties-changed-signal.c:123 #8 0x0000003371c13055 in g_cclosure_marshal_VOID__PARAM (closure=0x9618a0, return_value=0xffffffff, n_param_values=0, param_values=0x7fff4710f130, invocation_hint=0x0, marshal_data=0x4b5201) at gmarshal.c:1037 #9 0x0000003371c10298 in g_closure_invoke (closure=0x2, closure@entry=0x919d00, return_value=return_value@entry=0x0, n_param_values=1192292656, param_values=0x9d2320, param_values@entry=0x7fff4710f130, invocation_hint=invocation_hint@entry=0x7fff4710f0d0) at gclosure.c:777 #10 0x0000003371c21b87 in signal_emit_unlocked_R (node=node@entry=0x919d90, detail=detail@entry=667, instance=instance@entry=0x9d2320, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff4710f130) at gsignal.c:3516 #11 0x0000003371c2a0f2 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fff4710f2c0) at gsignal.c:3330 #12 0x0000003371c2a3af in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386 #13 0x0000003371c14945 in g_object_dispatch_properties_changed (object=0x9d2320, n_pspecs=4294967295, pspecs=0x0) at gobject.c:1047 #14 0x0000003371c17019 in g_object_notify_by_spec_internal (pspec=<optimized out>, object=0x9d2320) at gobject.c:1141 #15 g_object_notify (object=0x9d2320, property_name=property_name@entry=0x4c400f "dhcp4-config") at gobject.c:1183 #16 0x0000000000434332 in dhcp4_cleanup (self=self@entry=0x9d2320, stop=stop@entry=1, release=release@entry=0) at devices/nm-device.c:2581 #17 0x0000000000434cab in _cleanup_generic_pre (self=self@entry=0x9d2320, deconfigure=deconfigure@entry=1) at devices/nm-device.c:6448 #18 0x0000000000436db1 in nm_device_cleanup (self=self@entry=0x9d2320, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6524 #19 0x0000000000437358 in _set_state_full (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6641 #20 0x000000000043797c in nm_device_state_changed (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #21 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0x9d2320, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #22 0x000000000043a193 in nm_device_set_unmanaged_quitting (device=0x9d2320) at devices/nm-device.c:5998 #23 0x00000000004799f9 in remove_device (manager=0x9b2150, device=0x9d2320, quitting=1) at nm-manager.c:775 #24 0x000000000047bf47 in dispose (object=0x9b2150) at nm-manager.c:4935 #25 0x0000003371c14ee8 in g_object_unref (_object=0x9b2150) at gobject.c:3160 #26 0x0000000000429f43 in main (argc=1, argv=0x7fff4710f9a8) at main.c:681 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 10:32:32 +02:00
if (priv->dhcp4_config) {
nm_exported_object_clear_and_unexport (&priv->dhcp4_config);
core: fix dhcp4_cleanup() to clear dhcp4_client first (avoids assert accessing NM_DEVICE_DHCP4_CONFIG) dhcp4_cleanup() should first clear @dhcp4_client variables before clearing @dhcp4_config. Otherwise the following assert fails [1] and the DBUS property NM_DEVICE_DHCP4_CONFIG is set to %NULL. Analog to dhcp6_cleanup(), dhcp6_client, and NM_DEVICE_DHCP6_CONFIG. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c148c "unrecognized-specs-changed", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff4710ed60) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x3370cbc89a "%s: assertion '%s' failed") at gmessages.c:1025 #2 0x0000003370c50679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x4c144c "NetworkManager", pretty_function=pretty_function@entry=0x4c6140 <__PRETTY_FUNCTION__.15969> "nm_dhcp4_config_get_dbus_path", expression=expression@entry=0x4c60d9 "NM_IS_DHCP4_CONFIG (self)") at gmessages.c:1034 #3 0x000000000046b1d4 in nm_dhcp4_config_get_dbus_path (self=0x0) at nm-dhcp4-config.c:115 #4 0x0000000000434791 in get_property (object=0x9d2320, prop_id=13, value=0x9618a0, pspec=0x9bbc20) at devices/nm-device.c:7539 #5 0x0000003371c18e73 in object_get_property (value=0x9618a0, pspec=<optimized out>, object=0x9d2320) at gobject.c:1303 #6 g_object_get_property (object=0x9d2320, property_name=<optimized out>, value=0x9618a0) at gobject.c:2402 #7 0x000000000048482c in idle_id_reset (data=<optimized out>) at nm-properties-changed-signal.c:123 #8 0x0000003371c13055 in g_cclosure_marshal_VOID__PARAM (closure=0x9618a0, return_value=0xffffffff, n_param_values=0, param_values=0x7fff4710f130, invocation_hint=0x0, marshal_data=0x4b5201) at gmarshal.c:1037 #9 0x0000003371c10298 in g_closure_invoke (closure=0x2, closure@entry=0x919d00, return_value=return_value@entry=0x0, n_param_values=1192292656, param_values=0x9d2320, param_values@entry=0x7fff4710f130, invocation_hint=invocation_hint@entry=0x7fff4710f0d0) at gclosure.c:777 #10 0x0000003371c21b87 in signal_emit_unlocked_R (node=node@entry=0x919d90, detail=detail@entry=667, instance=instance@entry=0x9d2320, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff4710f130) at gsignal.c:3516 #11 0x0000003371c2a0f2 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fff4710f2c0) at gsignal.c:3330 #12 0x0000003371c2a3af in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386 #13 0x0000003371c14945 in g_object_dispatch_properties_changed (object=0x9d2320, n_pspecs=4294967295, pspecs=0x0) at gobject.c:1047 #14 0x0000003371c17019 in g_object_notify_by_spec_internal (pspec=<optimized out>, object=0x9d2320) at gobject.c:1141 #15 g_object_notify (object=0x9d2320, property_name=property_name@entry=0x4c400f "dhcp4-config") at gobject.c:1183 #16 0x0000000000434332 in dhcp4_cleanup (self=self@entry=0x9d2320, stop=stop@entry=1, release=release@entry=0) at devices/nm-device.c:2581 #17 0x0000000000434cab in _cleanup_generic_pre (self=self@entry=0x9d2320, deconfigure=deconfigure@entry=1) at devices/nm-device.c:6448 #18 0x0000000000436db1 in nm_device_cleanup (self=self@entry=0x9d2320, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6524 #19 0x0000000000437358 in _set_state_full (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6641 #20 0x000000000043797c in nm_device_state_changed (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #21 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0x9d2320, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #22 0x000000000043a193 in nm_device_set_unmanaged_quitting (device=0x9d2320) at devices/nm-device.c:5998 #23 0x00000000004799f9 in remove_device (manager=0x9b2150, device=0x9d2320, quitting=1) at nm-manager.c:775 #24 0x000000000047bf47 in dispose (object=0x9b2150) at nm-manager.c:4935 #25 0x0000003371c14ee8 in g_object_unref (_object=0x9b2150) at gobject.c:3160 #26 0x0000000000429f43 in main (argc=1, argv=0x7fff4710f9a8) at main.c:681 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 10:32:32 +02:00
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
}
}
static void
_ip4_config_merge_default (gpointer value, gpointer user_data)
{
NMIP4Config *src = (NMIP4Config *) value;
NMIP4Config *dst = (NMIP4Config *) user_data;
nm_ip4_config_merge (dst, src, NM_IP_CONFIG_MERGE_DEFAULT);
}
static gboolean
ip4_config_merge_and_apply (NMDevice *self,
NMIP4Config *config,
gboolean commit,
NMDeviceStateReason *out_reason)
2010-01-12 22:09:28 -08:00
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2010-01-12 22:09:28 -08:00
NMConnection *connection;
gboolean success;
NMIP4Config *composite;
gboolean has_direct_route;
const guint32 default_route_metric = nm_device_get_ip4_route_metric (self);
guint32 gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean routes_full_sync;
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
2010-01-12 22:09:28 -08:00
/* Merge all the configs into the composite config */
if (config) {
g_clear_object (&priv->dev_ip4_config);
priv->dev_ip4_config = g_object_ref (config);
}
/* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self);
if (connection) {
NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (s_ip4) {
ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4);
ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4);
}
}
composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
if (commit)
ensure_con_ip4_config (self);
if (priv->dev_ip4_config) {
nm_ip4_config_merge (composite, priv->dev_ip4_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
}
g_slist_foreach (priv->vpn4_configs, _ip4_config_merge_default, composite);
if (priv->ext_ip4_config)
nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
/* Merge WWAN config *last* to ensure modem-given settings overwrite
* any external stuff set by pppd or other scripts.
*/
if (priv->wwan_ip4_config) {
nm_ip4_config_merge (composite, priv->wwan_ip4_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
}
/* Merge user overrides into the composite config. For assumed connections,
* con_ip4_config is empty. */
if (priv->con_ip4_config)
nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
/* Add the default route.
*
* We keep track of the default route of a device in a private field.
* NMDevice needs to know the default route at this point, because the gateway
* might require a direct route (see below).
*
* But also, we don't want to add the default route to priv->ip4_config,
* because the default route from the setting might not be the same that
* NMDefaultRouteManager eventually configures (because the it might
* tweak the effective metric).
*/
/* unless we come to a different conclusion below, we have no default route and
* the route is assumed. */
priv->default_route.v4_has = FALSE;
priv->default_route.v4_is_assumed = TRUE;
if (!commit) {
/* during a non-commit event, we always pickup whatever is configured. */
goto END_ADD_DEFAULT_ROUTE;
}
if (nm_device_uses_generated_assumed_connection (self)) {
/* a generate-assumed-connection always detects the default route from platform */
goto END_ADD_DEFAULT_ROUTE;
}
/* At this point, we treat assumed and non-assumed connections alike.
* For assumed connections we do that because we still manage RA and DHCP
* leases for them, so we must extend/update the default route on commits.
*/
connection_has_default_route
= nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (),
connection, &connection_is_never_default);
if ( !priv->v4_commit_first_time
&& connection_is_never_default) {
/* If the connection is explicitly configured as never-default, we enforce the (absence of the)
* default-route only once. That allows the user to configure a connection as never-default,
* but he can add default routes externally (via a dispatcher script) and NM will not interfere. */
goto END_ADD_DEFAULT_ROUTE;
}
/* we are about to commit (for a non-assumed connection). Enforce whatever we have
* configured. */
priv->default_route.v4_is_assumed = FALSE;
if (!connection_has_default_route)
goto END_ADD_DEFAULT_ROUTE;
if (!nm_ip4_config_get_num_addresses (composite)) {
/* without addresses we can have no default route. */
goto END_ADD_DEFAULT_ROUTE;
}
gateway = nm_ip4_config_get_gateway (composite);
if ( !nm_ip4_config_has_gateway (composite)
&& nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM)
goto END_ADD_DEFAULT_ROUTE;
has_direct_route = ( gateway == 0
|| nm_ip4_config_destination_is_direct (composite, gateway, 32)
|| nm_ip4_config_get_direct_route_for_host (composite, gateway));
priv->default_route.v4_has = TRUE;
memset (&priv->default_route.v4, 0, sizeof (priv->default_route.v4));
priv->default_route.v4.source = NM_IP_CONFIG_SOURCE_USER;
priv->default_route.v4.gateway = gateway;
priv->default_route.v4.metric = default_route_metric;
priv->default_route.v4.mss = nm_ip4_config_get_mss (composite);
if (!has_direct_route) {
NMPlatformIP4Route r = priv->default_route.v4;
/* add a direct route to the gateway */
r.network = gateway;
r.plen = 32;
r.gateway = 0;
nm_ip4_config_add_route (composite, &r);
}
END_ADD_DEFAULT_ROUTE:
if (priv->default_route.v4_is_assumed) {
/* If above does not explicitly assign a default route, we always pick up the
* default route based on what is currently configured.
* That means that even managed connections with never-default, can
* get a default route (if configured externally).
*/
priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4);
}
/* Allow setting MTU etc */
if (commit) {
if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite);
}
routes_full_sync = commit
&& priv->v4_commit_first_time
&& !nm_device_uses_assumed_connection (self);
success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync, out_reason);
g_object_unref (composite);
if (commit)
priv->v4_commit_first_time = FALSE;
return success;
}
static void
dhcp4_lease_change (NMDevice *self, NMIP4Config *config)
{
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
g_return_if_fail (config != NULL);
if (!ip4_config_merge_and_apply (self, config, TRUE, &reason)) {
_LOGW (LOGD_DHCP4, "failed to update IPv4 config for DHCP change.");
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
} else {
/* Notify dispatcher scripts of new DHCP4 config */
nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE,
nm_device_get_settings_connection (self),
nm_device_get_applied_connection (self),
self,
NULL,
NULL,
NULL);
}
2010-01-12 22:09:28 -08:00
}
static gboolean
dhcp4_restart_cb (gpointer user_data)
{
NMDevice *self = user_data;
NMDevicePrivate *priv;
NMDeviceStateReason reason;
NMConnection *connection;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
priv->dhcp4_restart_id = 0;
connection = nm_device_get_applied_connection (self);
if (dhcp4_start (self, connection, &reason) == NM_ACT_STAGE_RETURN_FAILURE)
priv->dhcp4_restart_id = g_timeout_add_seconds (120, dhcp4_restart_cb, self);
return FALSE;
}
static void
dhcp4_fail (NMDevice *self, gboolean timeout)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
/* Don't fail if there are static addresses configured on
* the device, instead retry after some time.
*/
if ( priv->ip4_state == IP_DONE
&& priv->con_ip4_config
&& nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0) {
_LOGI (LOGD_DHCP4, "Scheduling DHCPv4 restart because device has IP addresses");
priv->dhcp4_restart_id = g_timeout_add_seconds (120, dhcp4_restart_cb, self);
return;
}
/* Instead of letting an assumed connection fail (which means that the
* device will transition to the ACTIVATED state without IP configuration),
* retry DHCP again.
*/
if (nm_device_uses_assumed_connection (self)) {
_LOGI (LOGD_DHCP4, "Scheduling DHCPv4 restart because the connection is assumed");
priv->dhcp4_restart_id = g_timeout_add_seconds (120, dhcp4_restart_cb, self);
return;
}
if (timeout || (priv->ip4_state == IP_CONF))
nm_device_activate_schedule_ip4_config_timeout (self);
else if (priv->ip4_state == IP_DONE)
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
else
g_warn_if_reached ();
}
2010-01-12 22:09:28 -08:00
static void
dhcp4_state_changed (NMDhcpClient *client,
NMDhcpState state,
NMIP4Config *ip4_config,
GHashTable *options,
const char *event_id,
gpointer user_data)
2010-01-12 22:09:28 -08:00
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2010-01-12 22:09:28 -08:00
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == FALSE);
g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
2010-01-12 22:09:28 -08:00
_LOGD (LOGD_DHCP4, "new DHCPv4 client state %d", state);
2010-01-12 22:09:28 -08:00
switch (state) {
case NM_DHCP_STATE_BOUND:
if (!ip4_config) {
_LOGW (LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event.");
nm_device_state_changed (self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
break;
}
nm_dhcp4_config_set_options (priv->dhcp4_config, options);
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
if (priv->ip4_state == IP_CONF)
nm_device_activate_schedule_ip4_config_result (self, ip4_config);
else if (priv->ip4_state == IP_DONE) {
dhcp4_lease_change (self, ip4_config);
nm_device_update_metered (self);
}
2010-01-12 22:09:28 -08:00
break;
case NM_DHCP_STATE_TIMEOUT:
dhcp4_fail (self, TRUE);
2010-01-12 22:09:28 -08:00
break;
case NM_DHCP_STATE_EXPIRE:
/* Ignore expiry before we even have a lease (NAK, old lease, etc) */
if (priv->ip4_state == IP_CONF)
break;
/* Fall through */
case NM_DHCP_STATE_DONE:
case NM_DHCP_STATE_FAIL:
dhcp4_fail (self, FALSE);
2010-01-12 22:09:28 -08:00
break;
default:
break;
}
}
static int
dhcp4_get_timeout (NMDevice *self, NMSettingIP4Config *s_ip4)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_free char *value = NULL;
int timeout;
timeout = nm_setting_ip4_config_get_dhcp_timeout (s_ip4);
if (timeout)
return timeout;
value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"ipv4.dhcp-timeout",
self);
timeout = _nm_utils_ascii_str_to_int64 (value, 10,
0, G_MAXINT32, 0);
if (timeout)
return timeout;
return priv->dhcp_timeout;
}
2011-01-05 14:07:32 -06:00
static NMActStageReturn
dhcp4_start (NMDevice *self,
NMConnection *connection,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingIPConfig *s_ip4;
const guint8 *hw_addr;
size_t hw_addr_len = 0;
GByteArray *tmp = NULL;
2011-01-05 14:07:32 -06:00
s_ip4 = nm_connection_get_setting_ip4_config (connection);
2011-01-05 14:07:32 -06:00
/* Clear old exported DHCP options */
nm_exported_object_clear_and_unexport (&priv->dhcp4_config);
2011-01-05 14:07:32 -06:00
priv->dhcp4_config = nm_dhcp4_config_new ();
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), &hw_addr_len);
if (hw_addr_len) {
tmp = g_byte_array_sized_new (hw_addr_len);
g_byte_array_append (tmp, hw_addr, hw_addr_len);
}
/* Begin DHCP on the interface */
2011-01-05 14:07:32 -06:00
g_warn_if_fail (priv->dhcp4_client == NULL);
priv->dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
2011-01-05 14:07:32 -06:00
nm_device_get_ip_iface (self),
2014-04-03 13:13:17 -05:00
nm_device_get_ip_ifindex (self),
tmp,
nm_connection_get_uuid (connection),
nm_device_get_ip4_route_metric (self),
nm_setting_ip_config_get_dhcp_send_hostname (s_ip4),
nm_setting_ip_config_get_dhcp_hostname (s_ip4),
nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)),
nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)),
dhcp4_get_timeout (self, NM_SETTING_IP4_CONFIG (s_ip4)),
priv->dhcp_anycast_address,
NULL);
if (tmp)
g_byte_array_free (tmp, TRUE);
2011-01-05 14:07:32 -06:00
if (!priv->dhcp4_client) {
*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
return NM_ACT_STAGE_RETURN_FAILURE;
}
priv->dhcp4_state_sigid = g_signal_connect (priv->dhcp4_client,
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
G_CALLBACK (dhcp4_state_changed),
2011-01-05 14:07:32 -06:00
self);
nm_device_add_pending_action (self, PENDING_ACTION_DHCP4, TRUE);
2011-01-05 14:07:32 -06:00
/* DHCP devices will be notified by the DHCP manager when stuff happens */
return NM_ACT_STAGE_RETURN_POSTPONE;
}
gboolean
nm_device_dhcp4_renew (NMDevice *self, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret;
NMDeviceStateReason reason;
NMConnection *connection;
g_return_val_if_fail (priv->dhcp4_client != NULL, FALSE);
_LOGI (LOGD_DHCP4, "DHCPv4 lease renewal requested");
/* Terminate old DHCP instance and release the old lease */
dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
/* Start DHCP again on the interface */
ret = dhcp4_start (self, connection, &reason);
return (ret != NM_ACT_STAGE_RETURN_FAILURE);
}
/*********************************************/
static GHashTable *shared_ips = NULL;
static void
release_shared_ip (gpointer data)
{
g_hash_table_remove (shared_ips, data);
}
static gboolean
reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Address *address)
{
if (G_UNLIKELY (shared_ips == NULL))
shared_ips = g_hash_table_new (g_direct_hash, g_direct_equal);
memset (address, 0, sizeof (*address));
if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) {
/* Use the first user-supplied address */
NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0);
in_addr_t a;
g_assert (user);
nm_ip_address_get_address_binary (user, &a);
nm_platform_ip4_address_set_addr (address, a, nm_ip_address_get_prefix (user));
} else {
/* Find an unused address in the 10.42.x.x range */
guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */
guint32 count = 0;
while (g_hash_table_lookup (shared_ips, GUINT_TO_POINTER (start + count))) {
count += ntohl (0x100);
if (count > ntohl (0xFE00)) {
_LOGE (LOGD_SHARING, "ran out of shared IP addresses!");
return FALSE;
}
}
nm_platform_ip4_address_set_addr (address, start + count, 24);
g_hash_table_insert (shared_ips,
GUINT_TO_POINTER (address->address),
GUINT_TO_POINTER (TRUE));
}
return TRUE;
}
static NMIP4Config *
shared4_new_config (NMDevice *self, NMConnection *connection, NMDeviceStateReason *reason)
{
NMIP4Config *config = NULL;
NMPlatformIP4Address address;
g_return_val_if_fail (self != NULL, NULL);
if (!reserve_shared_ip (self, nm_connection_get_setting_ip4_config (connection), &address)) {
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
return NULL;
}
config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
address.source = NM_IP_CONFIG_SOURCE_SHARED;
nm_ip4_config_add_address (config, &address);
/* Remove the address lock when the object gets disposed */
g_object_set_data_full (G_OBJECT (config), "shared-ip",
GUINT_TO_POINTER (address.address),
release_shared_ip);
return config;
}
/*********************************************/
static gboolean
connection_ip4_method_requires_carrier (NMConnection *connection,
gboolean *out_ip4_enabled)
{
const char *method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
static const char *ip4_carrier_methods[] = {
NM_SETTING_IP4_CONFIG_METHOD_AUTO,
NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
NULL
};
if (out_ip4_enabled)
*out_ip4_enabled = !!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
return _nm_utils_string_in_list (method, ip4_carrier_methods);
}
static gboolean
connection_ip6_method_requires_carrier (NMConnection *connection,
gboolean *out_ip6_enabled)
{
const char *method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
static const char *ip6_carrier_methods[] = {
NM_SETTING_IP6_CONFIG_METHOD_AUTO,
NM_SETTING_IP6_CONFIG_METHOD_DHCP,
NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
NULL
};
if (out_ip6_enabled)
*out_ip6_enabled = !!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
return _nm_utils_string_in_list (method, ip6_carrier_methods);
}
static gboolean
connection_requires_carrier (NMConnection *connection)
{
NMSettingIPConfig *s_ip4, *s_ip6;
gboolean ip4_carrier_wanted, ip6_carrier_wanted;
gboolean ip4_used = FALSE, ip6_used = FALSE;
ip4_carrier_wanted = connection_ip4_method_requires_carrier (connection, &ip4_used);
if (ip4_carrier_wanted) {
/* If IPv4 wants a carrier and cannot fail, the whole connection
* requires a carrier regardless of the IPv6 method.
*/
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (s_ip4 && !nm_setting_ip_config_get_may_fail (s_ip4))
return TRUE;
}
ip6_carrier_wanted = connection_ip6_method_requires_carrier (connection, &ip6_used);
if (ip6_carrier_wanted) {
/* If IPv6 wants a carrier and cannot fail, the whole connection
* requires a carrier regardless of the IPv4 method.
*/
s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6 && !nm_setting_ip_config_get_may_fail (s_ip6))
return TRUE;
}
/* If an IP version wants a carrier and and the other IP version isn't
* used, the connection requires carrier since it will just fail without one.
*/
if (ip4_carrier_wanted && !ip6_used)
return TRUE;
if (ip6_carrier_wanted && !ip4_used)
return TRUE;
/* If both want a carrier, the whole connection wants a carrier */
return ip4_carrier_wanted && ip6_carrier_wanted;
}
static gboolean
have_any_ready_slaves (NMDevice *self, const GSList *slaves)
{
const GSList *iter;
/* Any enslaved slave is "ready" in the generic case as it's
* at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2
* properties set up.
*/
for (iter = slaves; iter; iter = g_slist_next (iter)) {
if (nm_device_get_enslaved (iter->data))
return TRUE;
}
return FALSE;
}
static gboolean
ip4_requires_slaves (NMConnection *connection)
{
const char *method;
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
return strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0;
}
static NMActStageReturn
act_stage3_ip4_config_start (NMDevice *self,
NMIP4Config **out_config,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
const char *method;
GSList *slaves;
gboolean ready_slaves;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
if ( connection_ip4_method_requires_carrier (connection, NULL)
&& priv->is_master
&& !priv->carrier) {
_LOGI (LOGD_IP4 | LOGD_DEVICE,
"IPv4 config waiting until carrier is on");
return NM_ACT_STAGE_RETURN_WAIT;
}
if (priv->is_master && ip4_requires_slaves (connection)) {
/* If the master has no ready slaves, and depends on slaves for
* a successful IPv4 attempt, then postpone IPv4 addressing.
*/
slaves = nm_device_master_get_slaves (self);
ready_slaves = NM_DEVICE_GET_CLASS (self)->have_any_ready_slaves (self, slaves);
g_slist_free (slaves);
if (ready_slaves == FALSE) {
_LOGI (LOGD_DEVICE | LOGD_IP4,
"IPv4 config waiting until slaves are ready");
return NM_ACT_STAGE_RETURN_WAIT;
}
}
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
/* Start IPv4 addressing based on the method requested */
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0)
ret = dhcp4_start (self, connection, reason);
else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0)
ret = ipv4ll_start (self, reason);
else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) {
/* Use only IPv4 config from the connection data */
*out_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
g_assert (*out_config);
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) {
*out_config = shared4_new_config (self, connection, reason);
if (*out_config) {
priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self));
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else
ret = NM_ACT_STAGE_RETURN_FAILURE;
} else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) {
/* Nothing to do... */
ret = NM_ACT_STAGE_RETURN_STOP;
} else
_LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method);
return ret;
}
/*********************************************/
/* DHCPv6 stuff */
static void
dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE;
g_clear_object (&priv->dhcp6_ip6_config);
g_clear_pointer (&priv->dhcp6_event_id, g_free);
nm_clear_g_source (&priv->dhcp6_restart_id);
if (priv->dhcp6_client) {
if (priv->dhcp6_state_sigid) {
g_signal_handler_disconnect (priv->dhcp6_client, priv->dhcp6_state_sigid);
priv->dhcp6_state_sigid = 0;
}
if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE
|| cleanup_type == CLEANUP_TYPE_REMOVED)
nm_dhcp_client_stop (priv->dhcp6_client, release);
g_clear_object (&priv->dhcp6_client);
}
core: fix dhcp4_cleanup() to clear dhcp4_client first (avoids assert accessing NM_DEVICE_DHCP4_CONFIG) dhcp4_cleanup() should first clear @dhcp4_client variables before clearing @dhcp4_config. Otherwise the following assert fails [1] and the DBUS property NM_DEVICE_DHCP4_CONFIG is set to %NULL. Analog to dhcp6_cleanup(), dhcp6_client, and NM_DEVICE_DHCP6_CONFIG. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c148c "unrecognized-specs-changed", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff4710ed60) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x3370cbc89a "%s: assertion '%s' failed") at gmessages.c:1025 #2 0x0000003370c50679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x4c144c "NetworkManager", pretty_function=pretty_function@entry=0x4c6140 <__PRETTY_FUNCTION__.15969> "nm_dhcp4_config_get_dbus_path", expression=expression@entry=0x4c60d9 "NM_IS_DHCP4_CONFIG (self)") at gmessages.c:1034 #3 0x000000000046b1d4 in nm_dhcp4_config_get_dbus_path (self=0x0) at nm-dhcp4-config.c:115 #4 0x0000000000434791 in get_property (object=0x9d2320, prop_id=13, value=0x9618a0, pspec=0x9bbc20) at devices/nm-device.c:7539 #5 0x0000003371c18e73 in object_get_property (value=0x9618a0, pspec=<optimized out>, object=0x9d2320) at gobject.c:1303 #6 g_object_get_property (object=0x9d2320, property_name=<optimized out>, value=0x9618a0) at gobject.c:2402 #7 0x000000000048482c in idle_id_reset (data=<optimized out>) at nm-properties-changed-signal.c:123 #8 0x0000003371c13055 in g_cclosure_marshal_VOID__PARAM (closure=0x9618a0, return_value=0xffffffff, n_param_values=0, param_values=0x7fff4710f130, invocation_hint=0x0, marshal_data=0x4b5201) at gmarshal.c:1037 #9 0x0000003371c10298 in g_closure_invoke (closure=0x2, closure@entry=0x919d00, return_value=return_value@entry=0x0, n_param_values=1192292656, param_values=0x9d2320, param_values@entry=0x7fff4710f130, invocation_hint=invocation_hint@entry=0x7fff4710f0d0) at gclosure.c:777 #10 0x0000003371c21b87 in signal_emit_unlocked_R (node=node@entry=0x919d90, detail=detail@entry=667, instance=instance@entry=0x9d2320, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff4710f130) at gsignal.c:3516 #11 0x0000003371c2a0f2 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fff4710f2c0) at gsignal.c:3330 #12 0x0000003371c2a3af in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386 #13 0x0000003371c14945 in g_object_dispatch_properties_changed (object=0x9d2320, n_pspecs=4294967295, pspecs=0x0) at gobject.c:1047 #14 0x0000003371c17019 in g_object_notify_by_spec_internal (pspec=<optimized out>, object=0x9d2320) at gobject.c:1141 #15 g_object_notify (object=0x9d2320, property_name=property_name@entry=0x4c400f "dhcp4-config") at gobject.c:1183 #16 0x0000000000434332 in dhcp4_cleanup (self=self@entry=0x9d2320, stop=stop@entry=1, release=release@entry=0) at devices/nm-device.c:2581 #17 0x0000000000434cab in _cleanup_generic_pre (self=self@entry=0x9d2320, deconfigure=deconfigure@entry=1) at devices/nm-device.c:6448 #18 0x0000000000436db1 in nm_device_cleanup (self=self@entry=0x9d2320, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6524 #19 0x0000000000437358 in _set_state_full (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6641 #20 0x000000000043797c in nm_device_state_changed (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #21 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0x9d2320, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #22 0x000000000043a193 in nm_device_set_unmanaged_quitting (device=0x9d2320) at devices/nm-device.c:5998 #23 0x00000000004799f9 in remove_device (manager=0x9b2150, device=0x9d2320, quitting=1) at nm-manager.c:775 #24 0x000000000047bf47 in dispose (object=0x9b2150) at nm-manager.c:4935 #25 0x0000003371c14ee8 in g_object_unref (_object=0x9b2150) at gobject.c:3160 #26 0x0000000000429f43 in main (argc=1, argv=0x7fff4710f9a8) at main.c:681 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 10:32:32 +02:00
nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE);
core: fix dhcp4_cleanup() to clear dhcp4_client first (avoids assert accessing NM_DEVICE_DHCP4_CONFIG) dhcp4_cleanup() should first clear @dhcp4_client variables before clearing @dhcp4_config. Otherwise the following assert fails [1] and the DBUS property NM_DEVICE_DHCP4_CONFIG is set to %NULL. Analog to dhcp6_cleanup(), dhcp6_client, and NM_DEVICE_DHCP6_CONFIG. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c148c "unrecognized-specs-changed", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff4710ed60) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x3370cbc89a "%s: assertion '%s' failed") at gmessages.c:1025 #2 0x0000003370c50679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x4c144c "NetworkManager", pretty_function=pretty_function@entry=0x4c6140 <__PRETTY_FUNCTION__.15969> "nm_dhcp4_config_get_dbus_path", expression=expression@entry=0x4c60d9 "NM_IS_DHCP4_CONFIG (self)") at gmessages.c:1034 #3 0x000000000046b1d4 in nm_dhcp4_config_get_dbus_path (self=0x0) at nm-dhcp4-config.c:115 #4 0x0000000000434791 in get_property (object=0x9d2320, prop_id=13, value=0x9618a0, pspec=0x9bbc20) at devices/nm-device.c:7539 #5 0x0000003371c18e73 in object_get_property (value=0x9618a0, pspec=<optimized out>, object=0x9d2320) at gobject.c:1303 #6 g_object_get_property (object=0x9d2320, property_name=<optimized out>, value=0x9618a0) at gobject.c:2402 #7 0x000000000048482c in idle_id_reset (data=<optimized out>) at nm-properties-changed-signal.c:123 #8 0x0000003371c13055 in g_cclosure_marshal_VOID__PARAM (closure=0x9618a0, return_value=0xffffffff, n_param_values=0, param_values=0x7fff4710f130, invocation_hint=0x0, marshal_data=0x4b5201) at gmarshal.c:1037 #9 0x0000003371c10298 in g_closure_invoke (closure=0x2, closure@entry=0x919d00, return_value=return_value@entry=0x0, n_param_values=1192292656, param_values=0x9d2320, param_values@entry=0x7fff4710f130, invocation_hint=invocation_hint@entry=0x7fff4710f0d0) at gclosure.c:777 #10 0x0000003371c21b87 in signal_emit_unlocked_R (node=node@entry=0x919d90, detail=detail@entry=667, instance=instance@entry=0x9d2320, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff4710f130) at gsignal.c:3516 #11 0x0000003371c2a0f2 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fff4710f2c0) at gsignal.c:3330 #12 0x0000003371c2a3af in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386 #13 0x0000003371c14945 in g_object_dispatch_properties_changed (object=0x9d2320, n_pspecs=4294967295, pspecs=0x0) at gobject.c:1047 #14 0x0000003371c17019 in g_object_notify_by_spec_internal (pspec=<optimized out>, object=0x9d2320) at gobject.c:1141 #15 g_object_notify (object=0x9d2320, property_name=property_name@entry=0x4c400f "dhcp4-config") at gobject.c:1183 #16 0x0000000000434332 in dhcp4_cleanup (self=self@entry=0x9d2320, stop=stop@entry=1, release=release@entry=0) at devices/nm-device.c:2581 #17 0x0000000000434cab in _cleanup_generic_pre (self=self@entry=0x9d2320, deconfigure=deconfigure@entry=1) at devices/nm-device.c:6448 #18 0x0000000000436db1 in nm_device_cleanup (self=self@entry=0x9d2320, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6524 #19 0x0000000000437358 in _set_state_full (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6641 #20 0x000000000043797c in nm_device_state_changed (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #21 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0x9d2320, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #22 0x000000000043a193 in nm_device_set_unmanaged_quitting (device=0x9d2320) at devices/nm-device.c:5998 #23 0x00000000004799f9 in remove_device (manager=0x9b2150, device=0x9d2320, quitting=1) at nm-manager.c:775 #24 0x000000000047bf47 in dispose (object=0x9b2150) at nm-manager.c:4935 #25 0x0000003371c14ee8 in g_object_unref (_object=0x9b2150) at gobject.c:3160 #26 0x0000000000429f43 in main (argc=1, argv=0x7fff4710f9a8) at main.c:681 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 10:32:32 +02:00
if (priv->dhcp6_config) {
nm_exported_object_clear_and_unexport (&priv->dhcp6_config);
core: fix dhcp4_cleanup() to clear dhcp4_client first (avoids assert accessing NM_DEVICE_DHCP4_CONFIG) dhcp4_cleanup() should first clear @dhcp4_client variables before clearing @dhcp4_config. Otherwise the following assert fails [1] and the DBUS property NM_DEVICE_DHCP4_CONFIG is set to %NULL. Analog to dhcp6_cleanup(), dhcp6_client, and NM_DEVICE_DHCP6_CONFIG. [1] backtrace: #0 0x0000003370c504e9 in g_logv (log_domain=0x4c148c "unrecognized-specs-changed", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff4710ed60) at gmessages.c:989 #1 0x0000003370c5063f in g_log (log_domain=log_domain@entry=0x4c144c "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x3370cbc89a "%s: assertion '%s' failed") at gmessages.c:1025 #2 0x0000003370c50679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x4c144c "NetworkManager", pretty_function=pretty_function@entry=0x4c6140 <__PRETTY_FUNCTION__.15969> "nm_dhcp4_config_get_dbus_path", expression=expression@entry=0x4c60d9 "NM_IS_DHCP4_CONFIG (self)") at gmessages.c:1034 #3 0x000000000046b1d4 in nm_dhcp4_config_get_dbus_path (self=0x0) at nm-dhcp4-config.c:115 #4 0x0000000000434791 in get_property (object=0x9d2320, prop_id=13, value=0x9618a0, pspec=0x9bbc20) at devices/nm-device.c:7539 #5 0x0000003371c18e73 in object_get_property (value=0x9618a0, pspec=<optimized out>, object=0x9d2320) at gobject.c:1303 #6 g_object_get_property (object=0x9d2320, property_name=<optimized out>, value=0x9618a0) at gobject.c:2402 #7 0x000000000048482c in idle_id_reset (data=<optimized out>) at nm-properties-changed-signal.c:123 #8 0x0000003371c13055 in g_cclosure_marshal_VOID__PARAM (closure=0x9618a0, return_value=0xffffffff, n_param_values=0, param_values=0x7fff4710f130, invocation_hint=0x0, marshal_data=0x4b5201) at gmarshal.c:1037 #9 0x0000003371c10298 in g_closure_invoke (closure=0x2, closure@entry=0x919d00, return_value=return_value@entry=0x0, n_param_values=1192292656, param_values=0x9d2320, param_values@entry=0x7fff4710f130, invocation_hint=invocation_hint@entry=0x7fff4710f0d0) at gclosure.c:777 #10 0x0000003371c21b87 in signal_emit_unlocked_R (node=node@entry=0x919d90, detail=detail@entry=667, instance=instance@entry=0x9d2320, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fff4710f130) at gsignal.c:3516 #11 0x0000003371c2a0f2 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fff4710f2c0) at gsignal.c:3330 #12 0x0000003371c2a3af in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386 #13 0x0000003371c14945 in g_object_dispatch_properties_changed (object=0x9d2320, n_pspecs=4294967295, pspecs=0x0) at gobject.c:1047 #14 0x0000003371c17019 in g_object_notify_by_spec_internal (pspec=<optimized out>, object=0x9d2320) at gobject.c:1141 #15 g_object_notify (object=0x9d2320, property_name=property_name@entry=0x4c400f "dhcp4-config") at gobject.c:1183 #16 0x0000000000434332 in dhcp4_cleanup (self=self@entry=0x9d2320, stop=stop@entry=1, release=release@entry=0) at devices/nm-device.c:2581 #17 0x0000000000434cab in _cleanup_generic_pre (self=self@entry=0x9d2320, deconfigure=deconfigure@entry=1) at devices/nm-device.c:6448 #18 0x0000000000436db1 in nm_device_cleanup (self=self@entry=0x9d2320, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6524 #19 0x0000000000437358 in _set_state_full (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED, quitting=quitting@entry=0) at devices/nm-device.c:6641 #20 0x000000000043797c in nm_device_state_changed (device=device@entry=0x9d2320, state=state@entry=NM_DEVICE_STATE_UNMANAGED, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:6823 #21 0x0000000000439fe7 in nm_device_set_unmanaged (device=device@entry=0x9d2320, flag=flag@entry=NM_UNMANAGED_INTERNAL, unmanaged=unmanaged@entry=1, reason=reason@entry=NM_DEVICE_STATE_REASON_REMOVED) at devices/nm-device.c:5983 #22 0x000000000043a193 in nm_device_set_unmanaged_quitting (device=0x9d2320) at devices/nm-device.c:5998 #23 0x00000000004799f9 in remove_device (manager=0x9b2150, device=0x9d2320, quitting=1) at nm-manager.c:775 #24 0x000000000047bf47 in dispose (object=0x9b2150) at nm-manager.c:4935 #25 0x0000003371c14ee8 in g_object_unref (_object=0x9b2150) at gobject.c:3160 #26 0x0000000000429f43 in main (argc=1, argv=0x7fff4710f9a8) at main.c:681 Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-06-23 10:32:32 +02:00
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
}
}
static void
_ip6_config_merge_default (gpointer value, gpointer user_data)
{
NMIP6Config *src = (NMIP6Config *) value;
NMIP6Config *dst = (NMIP6Config *) user_data;
nm_ip6_config_merge (dst, src, NM_IP_CONFIG_MERGE_DEFAULT);
}
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
static gboolean
ip6_config_merge_and_apply (NMDevice *self,
gboolean commit,
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
NMDeviceStateReason *out_reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
gboolean success;
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
NMIP6Config *composite;
gboolean has_direct_route;
const struct in6_addr *gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean routes_full_sync;
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
/* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self);
if (connection) {
NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6) {
ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6);
ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6);
}
}
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
/* If no config was passed in, create a new one */
composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
if (commit)
ensure_con_ip6_config (self);
g_assert (composite);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
/* Merge all the IP configs into the composite config */
if (priv->ac_ip6_config) {
nm_ip6_config_merge (composite, priv->ac_ip6_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
}
if (priv->dhcp6_ip6_config) {
nm_ip6_config_merge (composite, priv->dhcp6_ip6_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
}
g_slist_foreach (priv->vpn6_configs, _ip6_config_merge_default, composite);
if (priv->ext_ip6_config)
nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
/* Merge WWAN config *last* to ensure modem-given settings overwrite
* any external stuff set by pppd or other scripts.
*/
if (priv->wwan_ip6_config) {
nm_ip6_config_merge (composite, priv->wwan_ip6_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
}
/* Merge user overrides into the composite config. For assumed connections,
* con_ip6_config is empty. */
if (priv->con_ip6_config)
nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT);
/* Add the default route.
*
* We keep track of the default route of a device in a private field.
* NMDevice needs to know the default route at this point, because the gateway
* might require a direct route (see below).
*
* But also, we don't want to add the default route to priv->ip6_config,
* because the default route from the setting might not be the same that
* NMDefaultRouteManager eventually configures (because the it might
* tweak the effective metric).
*/
/* unless we come to a different conclusion below, we have no default route and
* the route is assumed. */
priv->default_route.v6_has = FALSE;
priv->default_route.v6_is_assumed = TRUE;
if (!commit) {
/* during a non-commit event, we always pickup whatever is configured. */
goto END_ADD_DEFAULT_ROUTE;
}
if (nm_device_uses_generated_assumed_connection (self)) {
/* a generate-assumed-connection always detects the default route from platform */
goto END_ADD_DEFAULT_ROUTE;
}
/* At this point, we treat assumed and non-assumed connections alike.
* For assumed connections we do that because we still manage RA and DHCP
* leases for them, so we must extend/update the default route on commits.
*/
connection_has_default_route
= nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (),
connection, &connection_is_never_default);
if ( !priv->v6_commit_first_time
&& connection_is_never_default) {
/* If the connection is explicitly configured as never-default, we enforce the (absence of the)
* default-route only once. That allows the user to configure a connection as never-default,
* but he can add default routes externally (via a dispatcher script) and NM will not interfere. */
goto END_ADD_DEFAULT_ROUTE;
}
/* we are about to commit (for a non-assumed connection). Enforce whatever we have
* configured. */
priv->default_route.v6_is_assumed = FALSE;
if (!connection_has_default_route)
goto END_ADD_DEFAULT_ROUTE;
if (!nm_ip6_config_get_num_addresses (composite)) {
/* without addresses we can have no default route. */
goto END_ADD_DEFAULT_ROUTE;
}
gateway = nm_ip6_config_get_gateway (composite);
if (!gateway)
goto END_ADD_DEFAULT_ROUTE;
has_direct_route = nm_ip6_config_get_direct_route_for_host (composite, gateway) != NULL;
priv->default_route.v6_has = TRUE;
memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6));
priv->default_route.v6.source = NM_IP_CONFIG_SOURCE_USER;
priv->default_route.v6.gateway = *gateway;
priv->default_route.v6.metric = nm_device_get_ip6_route_metric (self);
priv->default_route.v6.mss = nm_ip6_config_get_mss (composite);
if (!has_direct_route) {
NMPlatformIP6Route r = priv->default_route.v6;
/* add a direct route to the gateway */
r.network = *gateway;
r.plen = 128;
r.gateway = in6addr_any;
nm_ip6_config_add_route (composite, &r);
}
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
END_ADD_DEFAULT_ROUTE:
if (priv->default_route.v6_is_assumed) {
/* If above does not explicitly assign a default route, we always pick up the
* default route based on what is currently configured.
* That means that even managed connections with never-default, can
* get a default route (if configured externally).
*/
priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6);
}
nm_ip6_config_addresses_sort (composite,
priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
/* Allow setting MTU etc */
if (commit) {
if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, composite);
}
routes_full_sync = commit
&& priv->v6_commit_first_time
&& !nm_device_uses_assumed_connection (self);
success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync, out_reason);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
g_object_unref (composite);
if (commit)
priv->v6_commit_first_time = FALSE;
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
return success;
}
static void
dhcp6_lease_change (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingsConnection *settings_connection;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
if (priv->dhcp6_ip6_config == NULL) {
_LOGW (LOGD_DHCP6, "failed to get DHCPv6 config for rebind");
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
return;
}
g_assert (priv->dhcp6_client); /* sanity check */
settings_connection = nm_device_get_settings_connection (self);
g_assert (settings_connection);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
/* Apply the updated config */
if (ip6_config_merge_and_apply (self, TRUE, &reason) == FALSE) {
_LOGW (LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event.");
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
} else {
/* Notify dispatcher scripts of new DHCPv6 config */
nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE,
settings_connection,
nm_device_get_applied_connection (self),
self, NULL, NULL, NULL);
}
}
static gboolean
dhcp6_restart_cb (gpointer user_data)
{
NMDevice *self = user_data;
NMDevicePrivate *priv;
NMDeviceStateReason reason;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
priv->dhcp6_restart_id = 0;
if (!dhcp6_start (self, FALSE, &reason))
priv->dhcp6_restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self);
return FALSE;
}
static void
dhcp6_fail (NMDevice *self, gboolean timeout)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) {
/* Don't fail if there are static addresses configured on
* the device, instead retry after some time.
*/
if ( priv->ip6_state == IP_DONE
&& priv->con_ip6_config
&& nm_ip6_config_get_num_addresses (priv->con_ip6_config)) {
_LOGI (LOGD_DHCP6, "Scheduling DHCPv6 restart because device has IP addresses");
priv->dhcp6_restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self);
return;
}
/* Instead of letting an assumed connection fail (which means that the
* device will transition to the ACTIVATED state without IP configuration),
* retry DHCP again.
*/
if (nm_device_uses_assumed_connection (self)) {
_LOGI (LOGD_DHCP6, "Scheduling DHCPv6 restart because the connection is assumed");
priv->dhcp6_restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self);
return;
}
if (timeout || (priv->ip6_state == IP_CONF))
nm_device_activate_schedule_ip6_config_timeout (self);
else if (priv->ip6_state == IP_DONE)
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
else
g_warn_if_reached ();
} else {
/* not a hard failure; just live with the RA info */
if (priv->ip6_state == IP_CONF)
nm_device_activate_schedule_ip6_config_result (self);
}
}
static void
dhcp6_timeout (NMDevice *self, NMDhcpClient *client)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED)
dhcp6_fail (self, TRUE);
else {
/* not a hard failure; just live with the RA info */
dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
if (priv->ip6_state == IP_CONF)
nm_device_activate_schedule_ip6_config_result (self);
}
}
static void
dhcp6_state_changed (NMDhcpClient *client,
NMDhcpState state,
NMIP6Config *ip6_config,
GHashTable *options,
const char *event_id,
gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint i;
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE);
g_return_if_fail (!ip6_config || NM_IS_IP6_CONFIG (ip6_config));
_LOGD (LOGD_DHCP6, "new DHCPv6 client state %d", state);
switch (state) {
case NM_DHCP_STATE_BOUND:
/* If the server sends multiple IPv6 addresses, we receive a state
* changed event for each of them. Use the event ID to merge IPv6
* addresses from the same transaction into a single configuration.
*/
if ( ip6_config
&& event_id
&& priv->dhcp6_event_id
&& !strcmp (event_id, priv->dhcp6_event_id)) {
for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
nm_ip6_config_add_address (priv->dhcp6_ip6_config,
nm_ip6_config_get_address (ip6_config, i));
}
} else {
g_clear_object (&priv->dhcp6_ip6_config);
g_clear_pointer (&priv->dhcp6_event_id, g_free);
if (ip6_config) {
priv->dhcp6_ip6_config = g_object_ref (ip6_config);
priv->dhcp6_event_id = g_strdup (event_id);
nm_dhcp6_config_set_options (priv->dhcp6_config, options);
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
}
}
if (priv->ip6_state == IP_CONF) {
if (priv->dhcp6_ip6_config == NULL) {
/* FIXME: Initial DHCP failed; should we fail IPv6 entirely then? */
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED);
break;
}
nm_device_activate_schedule_ip6_config_result (self);
} else if (priv->ip6_state == IP_DONE)
dhcp6_lease_change (self);
break;
case NM_DHCP_STATE_TIMEOUT:
dhcp6_timeout (self, client);
break;
case NM_DHCP_STATE_EXPIRE:
/* Ignore expiry before we even have a lease (NAK, old lease, etc) */
if (priv->ip6_state != IP_CONF)
dhcp6_fail (self, FALSE);
break;
case NM_DHCP_STATE_DONE:
/* In IPv6 info-only mode, the client doesn't handle leases so it
* may exit right after getting a response from the server. That's
* normal. In that case we just ignore the exit.
*/
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_OTHERCONF)
break;
/* Otherwise, fall through */
case NM_DHCP_STATE_FAIL:
dhcp6_fail (self, FALSE);
break;
default:
break;
}
}
static gboolean
dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingIPConfig *s_ip6;
GByteArray *tmp = NULL;
const guint8 *hw_addr;
size_t hw_addr_len = 0;
const struct in6_addr *ll_addr = NULL;
NMIP6Config *ip6_config;
int i;
g_assert (connection);
s_ip6 = nm_connection_get_setting_ip6_config (connection);
g_assert (s_ip6);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), &hw_addr_len);
if (hw_addr_len) {
tmp = g_byte_array_sized_new (hw_addr_len);
g_byte_array_append (tmp, hw_addr, hw_addr_len);
}
ip6_config = priv->ext_ip6_config;
for (i = 0; ip6_config && i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i);
if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
ll_addr = &addr->address;
break;
}
}
g_return_val_if_fail (ll_addr, FALSE);
priv->dhcp6_client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
nm_device_get_ip_iface (self),
2014-04-03 13:13:17 -05:00
nm_device_get_ip_ifindex (self),
tmp,
ll_addr,
nm_connection_get_uuid (connection),
nm_device_get_ip6_route_metric (self),
nm_setting_ip_config_get_dhcp_send_hostname (s_ip6),
nm_setting_ip_config_get_dhcp_hostname (s_ip6),
priv->dhcp_timeout,
priv->dhcp_anycast_address,
(priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)));
if (tmp)
g_byte_array_free (tmp, TRUE);
if (priv->dhcp6_client) {
priv->dhcp6_state_sigid = g_signal_connect (priv->dhcp6_client,
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
G_CALLBACK (dhcp6_state_changed),
self);
}
return !!priv->dhcp6_client;
}
static gboolean
dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMSettingIPConfig *s_ip6;
nm_exported_object_clear_and_unexport (&priv->dhcp6_config);
priv->dhcp6_config = nm_dhcp6_config_new ();
g_warn_if_fail (priv->dhcp6_ip6_config == NULL);
g_clear_object (&priv->dhcp6_ip6_config);
g_clear_pointer (&priv->dhcp6_event_id, g_free);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (!nm_setting_ip_config_get_may_fail (s_ip6) ||
!strcmp (nm_setting_ip_config_get_method (s_ip6), NM_SETTING_IP6_CONFIG_METHOD_DHCP))
nm_device_add_pending_action (self, PENDING_ACTION_DHCP6, TRUE);
if (wait_for_ll) {
NMActStageReturn ret;
/* ensure link local is ready... */
ret = linklocal6_start (self);
if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
/* success; wait for the LL address to show up */
return TRUE;
}
/* success; already have the LL address; kick off DHCP */
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH);
}
if (!dhcp6_start_with_link_ready (self, connection)) {
*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
return FALSE;
}
return TRUE;
}
gboolean
nm_device_dhcp6_renew (NMDevice *self, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_return_val_if_fail (priv->dhcp6_client != NULL, FALSE);
_LOGI (LOGD_DHCP6, "DHCPv6 lease renewal requested");
/* Terminate old DHCP instance and release the old lease */
dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release);
/* Start DHCP again on the interface */
return dhcp6_start (self, FALSE, NULL);
}
/******************************************/
static gboolean
have_ip6_address (const NMIP6Config *ip6_config, gboolean linklocal)
{
guint i;
if (!ip6_config)
return FALSE;
linklocal = !!linklocal;
for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i);
if ((IN6_IS_ADDR_LINKLOCAL (&addr->address) == linklocal) &&
!(addr->flags & IFA_F_TENTATIVE))
return TRUE;
}
return FALSE;
}
static void
linklocal6_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->linklocal6_timeout_id) {
g_source_remove (priv->linklocal6_timeout_id);
priv->linklocal6_timeout_id = 0;
}
}
static void
linklocal6_failed (NMDevice *self)
{
linklocal6_cleanup (self);
nm_device_activate_schedule_ip6_config_timeout (self);
}
static gboolean
linklocal6_timeout_cb (gpointer user_data)
{
NMDevice *self = user_data;
_LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout");
linklocal6_failed (self);
return G_SOURCE_REMOVE;
}
static void
linklocal6_complete (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
const char *method;
g_assert (priv->linklocal6_timeout_id);
g_assert (have_ip6_address (priv->ip6_config, TRUE));
linklocal6_cleanup (self);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
_LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses successful, continue with method %s", method);
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
if (!addrconf6_start_with_link_ready (self)) {
/* Time out IPv6 instead of failing the entire activation */
nm_device_activate_schedule_ip6_config_timeout (self);
}
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) {
if (!dhcp6_start_with_link_ready (self, connection)) {
/* Time out IPv6 instead of failing the entire activation */
nm_device_activate_schedule_ip6_config_timeout (self);
}
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0)
nm_device_activate_schedule_ip6_config_result (self);
else
g_return_if_fail (FALSE);
}
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
static void
check_and_add_ipv6ll_addr (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
struct in6_addr lladdr;
guint i, n;
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
NMConnection *connection;
NMSettingIP6Config *s_ip6 = NULL;
GError *error = NULL;
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
if (priv->nm_ipv6ll == FALSE)
return;
if (priv->ip6_config) {
n = nm_ip6_config_get_num_addresses (priv->ip6_config);
for (i = 0; i < n; i++) {
const NMPlatformIP6Address *addr;
addr = nm_ip6_config_get_address (priv->ip6_config, i);
if ( IN6_IS_ADDR_LINKLOCAL (&addr->address)
&& !(addr->flags & IFA_F_DADFAILED)) {
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
/* Already have an LL address, nothing to do */
return;
}
}
}
memset (&lladdr, 0, sizeof (lladdr));
lladdr.s6_addr16[0] = htons (0xfe80);
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
connection = nm_device_get_applied_connection (self);
if (connection)
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
if (!nm_utils_ipv6_addr_set_stable_privacy (&lladdr,
nm_device_get_iface (self),
nm_connection_get_uuid (connection),
priv->linklocal6_dad_counter++,
&error)) {
_LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message);
g_clear_error (&error);
linklocal6_failed (self);
return;
}
_LOGD (LOGD_IP6, "linklocal6: using IPv6 stable-privacy addressing");
} else {
NMUtilsIPv6IfaceId iid;
if (priv->linklocal6_timeout_id) {
/* We already started and attempt to add a LL address. For the EUI-64
* mode we can't pick a new one, we'll just fail. */
_LOGW (LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address");
linklocal6_failed (self);
return;
}
if (!nm_device_get_ip_iface_identifier (self, &iid)) {
_LOGW (LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue");
return;
}
_LOGD (LOGD_IP6, "linklocal6: using EUI-64 identifier to generate IPv6LL address");
nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid);
}
_LOGD (LOGD_IP6, "linklocal6: adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL));
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_ip6_address_add (NM_PLATFORM_GET,
ip_ifindex,
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
lladdr,
64,
in6addr_any,
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
NM_PLATFORM_LIFETIME_PERMANENT,
NM_PLATFORM_LIFETIME_PERMANENT,
0)) {
_LOGW (LOGD_IP6, "failed to add IPv6 link-local address %s",
nm_utils_inet6_ntop (&lladdr, NULL));
}
}
static NMActStageReturn
linklocal6_start (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
const char *method;
linklocal6_cleanup (self);
if (have_ip6_address (priv->ip6_config, TRUE))
return NM_ACT_STAGE_RETURN_FINISH;
connection = nm_device_get_applied_connection (self);
g_assert (connection);
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
_LOGD (LOGD_DEVICE, "linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses configured. Wait.", method);
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
check_and_add_ipv6ll_addr (self);
/* Depending on the network and what the 'dad_transmits' and 'retrans_time_ms'
* sysctl values are, DAD for the IPv6LL address may take quite a while.
* FIXME: use dad/retrans sysctl values if they are higher than a minimum time.
* (rh #1101809)
*/
priv->linklocal6_timeout_id = g_timeout_add_seconds (15, linklocal6_timeout_cb, self);
return NM_ACT_STAGE_RETURN_POSTPONE;
}
/******************************************/
static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu);
static void
nm_device_set_mtu (NMDevice *self, guint32 mtu)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ip_ifindex (self);
if (mtu)
priv->mtu = mtu;
/* Ensure the IPv6 MTU is still alright. */
if (priv->ip6_mtu)
nm_device_ipv6_set_mtu (self, priv->ip6_mtu);
if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex))
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, priv->mtu);
}
static void
nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint32 plat_mtu = nm_device_ipv6_sysctl_get_int32 (self, "mtu", priv->mtu);
char val[16];
priv->ip6_mtu = mtu ?: plat_mtu;
if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) {
_LOGI (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)",
priv->ip6_mtu, priv->mtu);
priv->ip6_mtu = priv->mtu;
}
if (priv->ip6_mtu && priv->ip6_mtu < 1280) {
_LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 MTU (%d) smaller than 1280, adjusting",
priv->ip6_mtu);
priv->ip6_mtu = 1280;
}
if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) {
_LOGI (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)",
priv->mtu, priv->ip6_mtu);
nm_device_set_mtu (self, priv->ip6_mtu);
}
if (priv->ip6_mtu != plat_mtu) {
g_snprintf (val, sizeof (val), "%d", mtu);
nm_device_ipv6_sysctl_set (self, "mtu", val);
}
}
static void
rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int i;
platform: create netlink messages directly without libnl-route-3 Instead of using libnl-route-3 library to serialize netlink messages, construct the netlink messages ourselves. This has several advantages: - Creating the netlink message ourself is actually more straight forward then having an intermediate layer between NM and the kernel. Now it is immediately clear, how a platform request translates to a netlink/kernel request. You can look at the kernel sources how a certain netlink attribute behaves, and then it's immediately clear how to set that (and vice versa). - Older libnl versions might have bugs or missing features for which we needed to workaround (often by offering a reduced/broken/untested functionality). Now we can get rid or workaround like _nl_has_capability(), check_support_libnl_extended_ifa_flags(), HAVE_LIBNL_INET6_TOKEN. Another example is a libnl bug when setting vlan ingress map which isn't even yet fixed in libnl upstream. - We no longer need libnl-route-3 at all and can drop that runtime requirement, saving some 400k. Constructing the messages ourselves also gives better performance because we don't have to create the intermediate libnl object. - In the future we will add more link-type support which is easier to support by basing directly on the plain kernel/netlink API, instead of requiring also libnl3 to expose this functionality. E.g. adding macvtap support: we already parsed macvtap properties ourselves because of missing libnl support. To *add* macvtap support, we also would have to do it ourself (or extend libnl).
2015-10-20 09:27:16 +02:00
int system_support;
guint ifa_flags = 0x00;
platform: create netlink messages directly without libnl-route-3 Instead of using libnl-route-3 library to serialize netlink messages, construct the netlink messages ourselves. This has several advantages: - Creating the netlink message ourself is actually more straight forward then having an intermediate layer between NM and the kernel. Now it is immediately clear, how a platform request translates to a netlink/kernel request. You can look at the kernel sources how a certain netlink attribute behaves, and then it's immediately clear how to set that (and vice versa). - Older libnl versions might have bugs or missing features for which we needed to workaround (often by offering a reduced/broken/untested functionality). Now we can get rid or workaround like _nl_has_capability(), check_support_libnl_extended_ifa_flags(), HAVE_LIBNL_INET6_TOKEN. Another example is a libnl bug when setting vlan ingress map which isn't even yet fixed in libnl upstream. - We no longer need libnl-route-3 at all and can drop that runtime requirement, saving some 400k. Constructing the messages ourselves also gives better performance because we don't have to create the intermediate libnl object. - In the future we will add more link-type support which is easier to support by basing directly on the plain kernel/netlink API, instead of requiring also libnl3 to expose this functionality. E.g. adding macvtap support: we already parsed macvtap properties ourselves because of missing libnl support. To *add* macvtap support, we also would have to do it ourself (or extend libnl).
2015-10-20 09:27:16 +02:00
/*
* Check, whether kernel is recent enough to help user space handling RA.
* If it's not supported, we have no ipv6-privacy and must add autoconf
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address.
**/
system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
if (system_support)
ifa_flags = IFA_F_NOPREFIXROUTE;
platform: create netlink messages directly without libnl-route-3 Instead of using libnl-route-3 library to serialize netlink messages, construct the netlink messages ourselves. This has several advantages: - Creating the netlink message ourself is actually more straight forward then having an intermediate layer between NM and the kernel. Now it is immediately clear, how a platform request translates to a netlink/kernel request. You can look at the kernel sources how a certain netlink attribute behaves, and then it's immediately clear how to set that (and vice versa). - Older libnl versions might have bugs or missing features for which we needed to workaround (often by offering a reduced/broken/untested functionality). Now we can get rid or workaround like _nl_has_capability(), check_support_libnl_extended_ifa_flags(), HAVE_LIBNL_INET6_TOKEN. Another example is a libnl bug when setting vlan ingress map which isn't even yet fixed in libnl upstream. - We no longer need libnl-route-3 at all and can drop that runtime requirement, saving some 400k. Constructing the messages ourselves also gives better performance because we don't have to create the intermediate libnl object. - In the future we will add more link-type support which is easier to support by basing directly on the plain kernel/netlink API, instead of requiring also libnl3 to expose this functionality. E.g. adding macvtap support: we already parsed macvtap properties ourselves because of missing libnl support. To *add* macvtap support, we also would have to do it ourself (or extend libnl).
2015-10-20 09:27:16 +02:00
if ( priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|| priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
{
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
ifa_flags |= IFA_F_MANAGETEMPADDR;
}
g_return_if_fail (priv->act_request);
if (!priv->ac_ip6_config)
priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
if (changed & NM_RDISC_CONFIG_GATEWAYS) {
/* Use the first gateway as ordered in router discovery cache. */
if (rdisc->gateways->len) {
NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, 0);
nm_ip6_config_set_gateway (priv->ac_ip6_config, &gateway->address);
} else
nm_ip6_config_set_gateway (priv->ac_ip6_config, NULL);
}
if (changed & NM_RDISC_CONFIG_ADDRESSES) {
/* Rebuild address list from router discovery cache. */
nm_ip6_config_reset_addresses (priv->ac_ip6_config);
/* rdisc->addresses contains at most max_addresses entries.
* This is different from what the kernel does, which
* also counts static and temporary addresses when checking
* max_addresses.
**/
for (i = 0; i < rdisc->addresses->len; i++) {
NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
NMPlatformIP6Address address;
memset (&address, 0, sizeof (address));
address.address = discovered_address->address;
address.plen = system_support ? 64 : 128;
address.timestamp = discovered_address->timestamp;
address.lifetime = discovered_address->lifetime;
address.preferred = discovered_address->preferred;
if (address.preferred > address.lifetime)
address.preferred = address.lifetime;
address.source = NM_IP_CONFIG_SOURCE_RDISC;
address.flags = ifa_flags;
nm_ip6_config_add_address (priv->ac_ip6_config, &address);
}
}
if (changed & NM_RDISC_CONFIG_ROUTES) {
/* Rebuild route list from router discovery cache. */
nm_ip6_config_reset_routes (priv->ac_ip6_config);
for (i = 0; i < rdisc->routes->len; i++) {
NMRDiscRoute *discovered_route = &g_array_index (rdisc->routes, NMRDiscRoute, i);
NMPlatformIP6Route route;
/* Only accept non-default routes. The router has no idea what the
* local configuration or user preferences are, so sending routes
* with a prefix length of 0 is quite rude and thus ignored.
*/
if (discovered_route->plen > 0) {
memset (&route, 0, sizeof (route));
route.network = discovered_route->network;
route.plen = discovered_route->plen;
route.gateway = discovered_route->gateway;
route.source = NM_IP_CONFIG_SOURCE_RDISC;
route.metric = nm_device_get_ip6_route_metric (self);
nm_ip6_config_add_route (priv->ac_ip6_config, &route);
}
}
}
if (changed & NM_RDISC_CONFIG_DNS_SERVERS) {
/* Rebuild DNS server list from router discovery cache. */
nm_ip6_config_reset_nameservers (priv->ac_ip6_config);
for (i = 0; i < rdisc->dns_servers->len; i++) {
NMRDiscDNSServer *discovered_server = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
nm_ip6_config_add_nameserver (priv->ac_ip6_config, &discovered_server->address);
}
}
if (changed & NM_RDISC_CONFIG_DNS_DOMAINS) {
/* Rebuild domain list from router discovery cache. */
nm_ip6_config_reset_domains (priv->ac_ip6_config);
for (i = 0; i < rdisc->dns_domains->len; i++) {
NMRDiscDNSDomain *discovered_domain = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
nm_ip6_config_add_domain (priv->ac_ip6_config, discovered_domain->domain);
}
}
if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) {
dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, TRUE);
priv->dhcp6_mode = rdisc->dhcp_level;
if (priv->dhcp6_mode != NM_RDISC_DHCP_LEVEL_NONE) {
NMDeviceStateReason reason;
_LOGD (LOGD_DEVICE | LOGD_DHCP6,
"Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6"
" as requested by IPv6 router...");
if (!dhcp6_start (self, FALSE, &reason)) {
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED)
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
}
return;
}
}
if (changed & NM_RDISC_CONFIG_HOP_LIMIT)
nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, nm_device_get_ip_iface (self), rdisc->hop_limit);
if (changed & NM_RDISC_CONFIG_MTU)
priv->ip6_mtu = rdisc->mtu;
nm_device_activate_schedule_ip6_config_result (self);
}
static void
rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* We don't want to stop listening for router advertisements completely,
* but instead let device activation continue activating. If an RA
* shows up later, we'll use it as long as the device is not disconnected.
*/
_LOGD (LOGD_IP6, "timed out waiting for IPv6 router advertisement");
if (priv->ip6_state == IP_CONF) {
/* If RA is our only source of addressing information and we don't
* ever receive one, then time out IPv6. But if there is other
* IPv6 configuration, like manual IPv6 addresses or external IPv6
* config, consider that sufficient for IPv6 success.
*/
if (have_ip6_address (priv->ip6_config, FALSE))
nm_device_activate_schedule_ip6_config_result (self);
else
nm_device_activate_schedule_ip6_config_timeout (self);
}
}
static gboolean
addrconf6_start_with_link_ready (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMUtilsIPv6IfaceId iid;
g_assert (priv->rdisc);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &iid)) {
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
_LOGD (LOGD_IP6, "addrconf6: IPv6 tokenized identifier present");
nm_rdisc_set_iid (priv->rdisc, iid);
} else if (nm_device_get_ip_iface_identifier (self, &iid)) {
_LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier");
nm_rdisc_set_iid (priv->rdisc, iid);
} else {
/* Don't abort the addrconf at this point -- if rdisc needs the iid
* it will notice this itself. */
_LOGI (LOGD_IP6, "addrconf6: no interface identifier; IPv6 adddress creation may fail");
}
/* Apply any manual configuration before starting RA */
if (!ip6_config_merge_and_apply (self, TRUE, NULL))
_LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration");
nm_device_ipv6_sysctl_set (self, "accept_ra", "1");
nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0");
priv->rdisc_changed_id = g_signal_connect (priv->rdisc,
NM_RDISC_CONFIG_CHANGED,
G_CALLBACK (rdisc_config_changed),
self);
priv->rdisc_timeout_id = g_signal_connect (priv->rdisc,
NM_RDISC_RA_TIMEOUT,
G_CALLBACK (rdisc_ra_timeout),
self);
nm_rdisc_start (priv->rdisc);
return TRUE;
}
static gboolean
addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMActStageReturn ret;
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
NMSettingIP6Config *s_ip6 = NULL;
connection = nm_device_get_applied_connection (self);
g_assert (connection);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
g_warn_if_fail (priv->ac_ip6_config == NULL);
if (priv->ac_ip6_config) {
g_object_unref (priv->ac_ip6_config);
priv->ac_ip6_config = NULL;
}
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
g_assert (s_ip6);
priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self),
nm_device_get_ip_iface (self),
nm_connection_get_uuid (connection),
nm_setting_ip6_config_get_addr_gen_mode (s_ip6));
if (!priv->rdisc) {
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
_LOGE (LOGD_IP6, "addrconf6: failed to start router discovery");
return FALSE;
}
priv->rdisc_use_tempaddr = use_tempaddr;
platform: create netlink messages directly without libnl-route-3 Instead of using libnl-route-3 library to serialize netlink messages, construct the netlink messages ourselves. This has several advantages: - Creating the netlink message ourself is actually more straight forward then having an intermediate layer between NM and the kernel. Now it is immediately clear, how a platform request translates to a netlink/kernel request. You can look at the kernel sources how a certain netlink attribute behaves, and then it's immediately clear how to set that (and vice versa). - Older libnl versions might have bugs or missing features for which we needed to workaround (often by offering a reduced/broken/untested functionality). Now we can get rid or workaround like _nl_has_capability(), check_support_libnl_extended_ifa_flags(), HAVE_LIBNL_INET6_TOKEN. Another example is a libnl bug when setting vlan ingress map which isn't even yet fixed in libnl upstream. - We no longer need libnl-route-3 at all and can drop that runtime requirement, saving some 400k. Constructing the messages ourselves also gives better performance because we don't have to create the intermediate libnl object. - In the future we will add more link-type support which is easier to support by basing directly on the plain kernel/netlink API, instead of requiring also libnl3 to expose this functionality. E.g. adding macvtap support: we already parsed macvtap properties ourselves because of missing libnl support. To *add* macvtap support, we also would have to do it ourself (or extend libnl).
2015-10-20 09:27:16 +02:00
if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
&& !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) {
_LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
"IPv6 private addresses. This feature is not available");
}
if (!nm_setting_ip_config_get_may_fail (nm_connection_get_setting_ip6_config (connection)))
nm_device_add_pending_action (self, PENDING_ACTION_AUTOCONF6, TRUE);
/* ensure link local is ready... */
ret = linklocal6_start (self);
if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
/* success; wait for the LL address to show up */
return TRUE;
}
/* success; already have the LL address; kick off router discovery */
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH);
return addrconf6_start_with_link_ready (self);
}
static void
addrconf6_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->rdisc_changed_id) {
g_signal_handler_disconnect (priv->rdisc, priv->rdisc_changed_id);
priv->rdisc_changed_id = 0;
}
if (priv->rdisc_timeout_id) {
g_signal_handler_disconnect (priv->rdisc, priv->rdisc_timeout_id);
priv->rdisc_timeout_id = 0;
}
nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE);
g_clear_object (&priv->ac_ip6_config);
g_clear_object (&priv->rdisc);
}
/******************************************/
static const char *ip6_properties_to_save[] = {
"accept_ra",
"accept_ra_defrtr",
"accept_ra_pinfo",
"accept_ra_rtr_pref",
"disable_ipv6",
"hop_limit",
"use_tempaddr",
};
static void
save_ip6_properties (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *ifname = nm_device_get_ip_iface (self);
char *value;
int i;
g_hash_table_remove_all (priv->ip6_saved_properties);
for (i = 0; i < G_N_ELEMENTS (ip6_properties_to_save); i++) {
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
value = nm_platform_sysctl_get (NM_PLATFORM_GET, nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i]));
if (value) {
g_hash_table_insert (priv->ip6_saved_properties,
(char *) ip6_properties_to_save[i],
value);
}
}
}
static void
restore_ip6_properties (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, priv->ip6_saved_properties);
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
while (g_hash_table_iter_next (&iter, &key, &value)) {
/* Don't touch "disable_ipv6" if we're doing userland IPv6LL */
if (priv->nm_ipv6ll && strcmp (key, "disable_ipv6") == 0)
continue;
nm_device_ipv6_sysctl_set (self, key, value);
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
}
}
static inline void
set_disable_ipv6 (NMDevice *self, const char *value)
{
/* We only touch disable_ipv6 when NM is not managing the IPv6LL address */
if (NM_DEVICE_GET_PRIVATE (self)->nm_ipv6ll == FALSE)
nm_device_ipv6_sysctl_set (self, "disable_ipv6", value);
}
static inline void
set_nm_ipv6ll (NMDevice *self, gboolean enable)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ip_ifindex (self);
core: bounce disable_ipv6 when setting userspace IPv6 link-local (bgo #740096) The kernel does not terminate an ongoing IPv6LL address process when the IPv6LL address generation mode is set to 'none' (indicating that userspace wishes to handle IPv6LL). Next, NetworkManager does not expose IPv6 addresses internally until they have completed DAD. This means that the kernel may still be performing DAD for an IPv6LL address when NetworkManager turns userspace IPv6LL on, and when DAD is complete NetworkManager will finally pay attention to the address. If the device is in the DISCONNECTED state, NetworkManager will then generate and assume an IPv6LL-only connection on the device. Unfortunately, that behavior happens if the following is true: 1) IPv6LL addressing takes a while (eg, dad_transmits is high or the kernel takes a while for some reason) 2) the activated connection fails quickly (dhclient fails or some other fatal error terminates the activation attempt) 3) the activated connection has ipv6.method=ignore In this case, when the device was brought up and ipv6.method=ignore, NetworkManager re-enabled kernel IPv6LL and reset the IPv6 sysctl properties. The kernel then generated an IPv6LL address and began DAD. dhclient failed quickly, and NM deactivated the device. NM then turned off kernel IPv6LL when deactivating the device, but the kernel does not terminate the ongoing DAD. Some time after the device entered the DISCONNECTED state, the kernel finished DAD and that allowed NetworkManager to internally see the address, which caused NetworkManager to emit the 'recheck-assume' signal. This generated a new IPv6LL-only connection which was then assumed. Bouncing 'disable_ipv6' when re-enabling userspace IPv6LL during device deactivation flushes the tentative kernel IPv6LL address, thus preventing the address from being announced after userspace IPv6LL is re-enabled. The other alternative is to expose tentative addresses (eg those still doing DAD) in NMPlatform so they would be flushed when the device deactivates, but that is a larger & riskier set of changes. Reproducer: - ifconfig eth0 down - prepare a DHCPv4 connection with ipv6.method=ignore - set /proc/sys/net/ipv6/conf/all/dad_transmits to "15" - ensure that DHCPv4 will fail (replace dhclient with a script that exits after 2 seconds or something) - run NetworkManager - activate the DHCP connection and watch it immediately fail - wait for the kernel to announce the IPv6LL address after DAD finishes - watch NM "assume" the new IPv6LL connection https://bugzilla.gnome.org/show_bug.cgi?id=740096
2014-11-13 19:52:21 -06:00
char *value;
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET))
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
return;
priv->nm_ipv6ll = enable;
if (ifindex > 0) {
const char *detail = enable ? "enable" : "disable";
_LOGD (LOGD_IP6, "will %s userland IPv6LL", detail);
if (!nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, enable))
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
_LOGW (LOGD_IP6, "failed to %s userspace IPv6LL address handling", detail);
core: bounce disable_ipv6 when setting userspace IPv6 link-local (bgo #740096) The kernel does not terminate an ongoing IPv6LL address process when the IPv6LL address generation mode is set to 'none' (indicating that userspace wishes to handle IPv6LL). Next, NetworkManager does not expose IPv6 addresses internally until they have completed DAD. This means that the kernel may still be performing DAD for an IPv6LL address when NetworkManager turns userspace IPv6LL on, and when DAD is complete NetworkManager will finally pay attention to the address. If the device is in the DISCONNECTED state, NetworkManager will then generate and assume an IPv6LL-only connection on the device. Unfortunately, that behavior happens if the following is true: 1) IPv6LL addressing takes a while (eg, dad_transmits is high or the kernel takes a while for some reason) 2) the activated connection fails quickly (dhclient fails or some other fatal error terminates the activation attempt) 3) the activated connection has ipv6.method=ignore In this case, when the device was brought up and ipv6.method=ignore, NetworkManager re-enabled kernel IPv6LL and reset the IPv6 sysctl properties. The kernel then generated an IPv6LL address and began DAD. dhclient failed quickly, and NM deactivated the device. NM then turned off kernel IPv6LL when deactivating the device, but the kernel does not terminate the ongoing DAD. Some time after the device entered the DISCONNECTED state, the kernel finished DAD and that allowed NetworkManager to internally see the address, which caused NetworkManager to emit the 'recheck-assume' signal. This generated a new IPv6LL-only connection which was then assumed. Bouncing 'disable_ipv6' when re-enabling userspace IPv6LL during device deactivation flushes the tentative kernel IPv6LL address, thus preventing the address from being announced after userspace IPv6LL is re-enabled. The other alternative is to expose tentative addresses (eg those still doing DAD) in NMPlatform so they would be flushed when the device deactivates, but that is a larger & riskier set of changes. Reproducer: - ifconfig eth0 down - prepare a DHCPv4 connection with ipv6.method=ignore - set /proc/sys/net/ipv6/conf/all/dad_transmits to "15" - ensure that DHCPv4 will fail (replace dhclient with a script that exits after 2 seconds or something) - run NetworkManager - activate the DHCP connection and watch it immediately fail - wait for the kernel to announce the IPv6LL address after DAD finishes - watch NM "assume" the new IPv6LL connection https://bugzilla.gnome.org/show_bug.cgi?id=740096
2014-11-13 19:52:21 -06:00
if (enable) {
/* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */
value = nm_platform_sysctl_get (NM_PLATFORM_GET,
nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6"));
if (g_strcmp0 (value, "0") == 0)
core: bounce disable_ipv6 when setting userspace IPv6 link-local (bgo #740096) The kernel does not terminate an ongoing IPv6LL address process when the IPv6LL address generation mode is set to 'none' (indicating that userspace wishes to handle IPv6LL). Next, NetworkManager does not expose IPv6 addresses internally until they have completed DAD. This means that the kernel may still be performing DAD for an IPv6LL address when NetworkManager turns userspace IPv6LL on, and when DAD is complete NetworkManager will finally pay attention to the address. If the device is in the DISCONNECTED state, NetworkManager will then generate and assume an IPv6LL-only connection on the device. Unfortunately, that behavior happens if the following is true: 1) IPv6LL addressing takes a while (eg, dad_transmits is high or the kernel takes a while for some reason) 2) the activated connection fails quickly (dhclient fails or some other fatal error terminates the activation attempt) 3) the activated connection has ipv6.method=ignore In this case, when the device was brought up and ipv6.method=ignore, NetworkManager re-enabled kernel IPv6LL and reset the IPv6 sysctl properties. The kernel then generated an IPv6LL address and began DAD. dhclient failed quickly, and NM deactivated the device. NM then turned off kernel IPv6LL when deactivating the device, but the kernel does not terminate the ongoing DAD. Some time after the device entered the DISCONNECTED state, the kernel finished DAD and that allowed NetworkManager to internally see the address, which caused NetworkManager to emit the 'recheck-assume' signal. This generated a new IPv6LL-only connection which was then assumed. Bouncing 'disable_ipv6' when re-enabling userspace IPv6LL during device deactivation flushes the tentative kernel IPv6LL address, thus preventing the address from being announced after userspace IPv6LL is re-enabled. The other alternative is to expose tentative addresses (eg those still doing DAD) in NMPlatform so they would be flushed when the device deactivates, but that is a larger & riskier set of changes. Reproducer: - ifconfig eth0 down - prepare a DHCPv4 connection with ipv6.method=ignore - set /proc/sys/net/ipv6/conf/all/dad_transmits to "15" - ensure that DHCPv4 will fail (replace dhclient with a script that exits after 2 seconds or something) - run NetworkManager - activate the DHCP connection and watch it immediately fail - wait for the kernel to announce the IPv6LL address after DAD finishes - watch NM "assume" the new IPv6LL connection https://bugzilla.gnome.org/show_bug.cgi?id=740096
2014-11-13 19:52:21 -06:00
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
g_free (value);
/* Ensure IPv6 is enabled */
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "0");
core: bounce disable_ipv6 when setting userspace IPv6 link-local (bgo #740096) The kernel does not terminate an ongoing IPv6LL address process when the IPv6LL address generation mode is set to 'none' (indicating that userspace wishes to handle IPv6LL). Next, NetworkManager does not expose IPv6 addresses internally until they have completed DAD. This means that the kernel may still be performing DAD for an IPv6LL address when NetworkManager turns userspace IPv6LL on, and when DAD is complete NetworkManager will finally pay attention to the address. If the device is in the DISCONNECTED state, NetworkManager will then generate and assume an IPv6LL-only connection on the device. Unfortunately, that behavior happens if the following is true: 1) IPv6LL addressing takes a while (eg, dad_transmits is high or the kernel takes a while for some reason) 2) the activated connection fails quickly (dhclient fails or some other fatal error terminates the activation attempt) 3) the activated connection has ipv6.method=ignore In this case, when the device was brought up and ipv6.method=ignore, NetworkManager re-enabled kernel IPv6LL and reset the IPv6 sysctl properties. The kernel then generated an IPv6LL address and began DAD. dhclient failed quickly, and NM deactivated the device. NM then turned off kernel IPv6LL when deactivating the device, but the kernel does not terminate the ongoing DAD. Some time after the device entered the DISCONNECTED state, the kernel finished DAD and that allowed NetworkManager to internally see the address, which caused NetworkManager to emit the 'recheck-assume' signal. This generated a new IPv6LL-only connection which was then assumed. Bouncing 'disable_ipv6' when re-enabling userspace IPv6LL during device deactivation flushes the tentative kernel IPv6LL address, thus preventing the address from being announced after userspace IPv6LL is re-enabled. The other alternative is to expose tentative addresses (eg those still doing DAD) in NMPlatform so they would be flushed when the device deactivates, but that is a larger & riskier set of changes. Reproducer: - ifconfig eth0 down - prepare a DHCPv4 connection with ipv6.method=ignore - set /proc/sys/net/ipv6/conf/all/dad_transmits to "15" - ensure that DHCPv4 will fail (replace dhclient with a script that exits after 2 seconds or something) - run NetworkManager - activate the DHCP connection and watch it immediately fail - wait for the kernel to announce the IPv6LL address after DAD finishes - watch NM "assume" the new IPv6LL connection https://bugzilla.gnome.org/show_bug.cgi?id=740096
2014-11-13 19:52:21 -06:00
}
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
}
}
/************************************************************************/
static NMSettingIP6ConfigPrivacy
_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr)
{
switch (use_tempaddr) {
case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
return use_tempaddr;
default:
return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
}
}
static NMSettingIP6ConfigPrivacy
_ip6_privacy_get (NMDevice *self)
{
NMSettingIP6ConfigPrivacy ip6_privacy;
gs_free char *value = NULL;
NMConnection *connection;
g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
/* 1.) First look at the per-connection setting. If it is not -1 (unknown),
* use it. */
connection = nm_device_get_applied_connection (self);
if (connection) {
NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6) {
ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6));
ip6_privacy = _ip6_privacy_clamp (ip6_privacy);
if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
return ip6_privacy;
}
}
value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"ipv6.ip6-privacy", self);
/* 2.) use the default value from the configuration. */
ip6_privacy = _nm_utils_ascii_str_to_int64 (value, 10,
NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
return ip6_privacy;
/* 3.) No valid default-value configured. Fallback to reading sysctl.
*
* Instead of reading static config files in /etc, just read the current sysctl value.
* This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves
* the "default" entry untouched. */
ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/default/use_tempaddr", NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
return _ip6_privacy_clamp (ip6_privacy);
}
/****************************************************************/
static gboolean
ip6_requires_slaves (NMConnection *connection)
{
const char *method;
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
/* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves)
* to complete addressing. SLAAC and DHCP obviously need a peer to
* provide a prefix, while Link-Local must perform DAD on the local link.
*/
return strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
|| strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0
|| strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0;
}
static NMActStageReturn
act_stage3_ip6_config_start (NMDevice *self,
NMIP6Config **out_config,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2010-04-30 15:49:41 -07:00
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMConnection *connection;
const char *method;
NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
const char *ip6_privacy_str = "0\n";
GSList *slaves;
gboolean ready_slaves;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
if ( connection_ip6_method_requires_carrier (connection, NULL)
&& priv->is_master
&& !priv->carrier) {
_LOGI (LOGD_IP6 | LOGD_DEVICE,
"IPv6 config waiting until carrier is on");
return NM_ACT_STAGE_RETURN_WAIT;
}
if (priv->is_master && ip6_requires_slaves (connection)) {
/* If the master has no ready slaves, and depends on slaves for
* a successful IPv6 attempt, then postpone IPv6 addressing.
*/
slaves = nm_device_master_get_slaves (self);
ready_slaves = NM_DEVICE_GET_CLASS (self)->have_any_ready_slaves (self, slaves);
g_slist_free (slaves);
if (ready_slaves == FALSE) {
_LOGI (LOGD_DEVICE | LOGD_IP6,
"IPv6 config waiting until slaves are ready");
return NM_ACT_STAGE_RETURN_WAIT;
}
}
priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE;
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) {
if (!priv->master) {
gboolean old_nm_ipv6ll = priv->nm_ipv6ll;
/* When activating an IPv6 'ignore' connection we need to revert back
* to kernel IPv6LL, but the kernel won't actually assign an address
* to the interface until disable_ipv6 is bounced.
*/
set_nm_ipv6ll (self, FALSE);
if (old_nm_ipv6ll == TRUE)
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
restore_ip6_properties (self);
}
return NM_ACT_STAGE_RETURN_STOP;
}
/* Ensure the MTU makes sense. If it was below 1280 the kernel would not
* expose any ipv6 sysctls or allow presence of any addresses on the interface,
* including LL, which * would make it impossible to autoconfigure MTU to a
* correct value. */
if (!nm_device_uses_assumed_connection (self))
nm_device_ipv6_set_mtu (self, priv->ip6_mtu);
/* Any method past this point requires an IPv6LL address. Use NM-controlled
* IPv6LL if this is not an assumed connection, since assumed connections
* will already have IPv6 set up.
*/
if (!nm_device_uses_assumed_connection (self))
set_nm_ipv6ll (self, TRUE);
/* Re-enable IPv6 on the interface */
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
set_disable_ipv6 (self, "0");
ip6_privacy = _ip6_privacy_get (self);
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
if (!addrconf6_start (self, ip6_privacy)) {
/* IPv6 might be disabled; allow IPv4 to proceed */
ret = NM_ACT_STAGE_RETURN_STOP;
} else
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) {
ret = linklocal6_start (self);
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) {
priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_MANAGED;
if (!dhcp6_start (self, TRUE, reason)) {
/* IPv6 might be disabled; allow IPv4 to proceed */
ret = NM_ACT_STAGE_RETURN_STOP;
} else
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0) {
/* New blank config */
*out_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
g_assert (*out_config);
2010-04-30 15:49:41 -07:00
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else
_LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method);
2010-04-30 15:49:41 -07:00
/* Other methods (shared) aren't implemented yet */
switch (ip6_privacy) {
case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN:
case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
ip6_privacy_str = "0";
break;
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
ip6_privacy_str = "1";
break;
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
ip6_privacy_str = "2";
break;
}
nm_device_ipv6_sysctl_set (self, "use_tempaddr", ip6_privacy_str);
return ret;
}
/**
* nm_device_activate_stage3_ip4_start:
* @self: the device
*
* Try starting IPv4 configuration.
*/
gboolean
nm_device_activate_stage3_ip4_start (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
NMIP4Config *ip4_config = NULL;
g_assert (priv->ip4_state == IP_WAIT);
priv->ip4_state = IP_CONF;
ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
g_assert (ip4_config);
nm_device_activate_schedule_ip4_config_result (self, ip4_config);
g_object_unref (ip4_config);
} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return FALSE;
} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
/* Early finish */
priv->ip4_state = IP_FAIL;
} else if (ret == NM_ACT_STAGE_RETURN_WAIT) {
/* Wait for something to try IP config again */
priv->ip4_state = IP_WAIT;
} else
g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE);
return TRUE;
}
/**
* nm_device_activate_stage3_ip6_start:
* @self: the device
*
* Try starting IPv6 configuration.
*/
gboolean
nm_device_activate_stage3_ip6_start (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
NMIP6Config *ip6_config = NULL;
g_assert (priv->ip6_state == IP_WAIT);
priv->ip6_state = IP_CONF;
ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
g_assert (ip6_config);
/* Here we get a static IPv6 config, like for Shared where it's
* autogenerated or from modems where it comes from ModemManager.
*/
g_warn_if_fail (priv->ac_ip6_config == NULL);
priv->ac_ip6_config = ip6_config;
nm_device_activate_schedule_ip6_config_result (self);
} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return FALSE;
} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
/* Activation not wanted */
priv->ip6_state = IP_FAIL;
} else if (ret == NM_ACT_STAGE_RETURN_FINISH) {
/* Early finish, nothing more to do */
priv->ip6_state = IP_DONE;
if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
} else if (ret == NM_ACT_STAGE_RETURN_WAIT) {
/* Wait for something to try IP config again */
priv->ip6_state = IP_WAIT;
} else
g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE);
return TRUE;
}
/*
* activate_stage3_ip_config_start
*
* Begin automatic/manual IP configuration
*
*/
static void
activate_stage3_ip_config_start (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActiveConnection *master;
NMDevice *master_device;
priv->ip4_state = priv->ip6_state = IP_WAIT;
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
/* Device should be up before we can do anything with it */
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_is_up (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self)))
_LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self));
2012-11-14 14:05:30 -06:00
/* 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
* enslavement. If the master is already activating, it will have tried to
* enslave us when we changed state to IP_CONFIG, causing us to queue a
* transition to SECONDARIES (or FAILED if the enslavement failed), with
* our IP states set to IP_DONE either way. If the master isn't yet
* activating, then they'll still be in IP_WAIT. Either way, we bail out
* of IP config here.
2012-11-14 14:05:30 -06:00
*/
master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request));
2012-11-14 14:05:30 -06:00
if (master) {
master_device = nm_active_connection_get_device (master);
if (priv->ip4_state == IP_WAIT && priv->ip6_state == IP_WAIT) {
_LOGI (LOGD_DEVICE, "Activation: connection '%s' waiting on master '%s'",
nm_connection_get_id (nm_device_get_applied_connection (self)),
master_device ? nm_device_get_iface (master_device) : "(unknown)");
2012-11-14 14:05:30 -06:00
}
return;
2012-11-14 14:05:30 -06:00
}
/* IPv4 */
nm-device: only progress with ip-config if the device is still in IP_WAIT The device might be a slave and not need any L3 configuration in which case it will move to IP_DONE: Running test bridge_manipulation_with_1000_slaves ... <debug> [1446834482.545396] [nm-dispatcher.c:304] dispatcher_results_process(): (121) 12-dhcpd succeeded <debug> [1446834482.545404] [nm-dispatcher.c:304] dispatcher_results_process(): (121) 20-chrony succeeded <debug> [1446834482.545481] [devices/nm-device.c:5374] nm_device_activate_stage3_ip_config_start(): [0x7fc77e1c0fc0] (port120): Activation: Stage 3 of 5 (IP Configure Start) started... <info> (port120): device state change: config -> ip-config (reason 'none') [50 70 0] <debug> [1446834482.545578] [devices/nm-device.c:1683] slave_state_changed(): [0x7fc77df77020] (bridge0): slave port120 state change 50 (config) -> 70 (ip-config) <debug> [1446834482.545629] [devices/nm-device.c:7955] nm_device_add_pending_action(): [0x7fc77e1c0fc0] (port120): add_pending_action (2): 'queued state change to secondaries' <debug> [1446834482.545642] [devices/nm-device.c:8806] nm_device_queue_state(): [0x7fc77e1c0fc0] (port120): queued state change to secondaries due to none (id 11380) ** NetworkManager:ERROR:devices/nm-device.c:5250:nm_device_activate_stage3_ip4_start: assertion failed: (priv->ip4_state == IP_WAIT) 5250 g_assert (priv->ip4_state == IP_WAIT); (gdb) print priv->ip4_state $1 = IP_DONE (gdb) print priv->master $3 = { ... master = 0x7fc77df77020, enslaved = 1, master_ready_handled = 1, master_ready_id = 0, is_master = 0, slaves = 0x0, ...}
2015-11-09 11:44:09 +01:00
if ( nm_device_activate_ip4_state_in_wait (self)
&& !nm_device_activate_stage3_ip4_start (self))
return;
2012-11-14 14:05:30 -06:00
/* IPv6 */
nm-device: only progress with ip-config if the device is still in IP_WAIT The device might be a slave and not need any L3 configuration in which case it will move to IP_DONE: Running test bridge_manipulation_with_1000_slaves ... <debug> [1446834482.545396] [nm-dispatcher.c:304] dispatcher_results_process(): (121) 12-dhcpd succeeded <debug> [1446834482.545404] [nm-dispatcher.c:304] dispatcher_results_process(): (121) 20-chrony succeeded <debug> [1446834482.545481] [devices/nm-device.c:5374] nm_device_activate_stage3_ip_config_start(): [0x7fc77e1c0fc0] (port120): Activation: Stage 3 of 5 (IP Configure Start) started... <info> (port120): device state change: config -> ip-config (reason 'none') [50 70 0] <debug> [1446834482.545578] [devices/nm-device.c:1683] slave_state_changed(): [0x7fc77df77020] (bridge0): slave port120 state change 50 (config) -> 70 (ip-config) <debug> [1446834482.545629] [devices/nm-device.c:7955] nm_device_add_pending_action(): [0x7fc77e1c0fc0] (port120): add_pending_action (2): 'queued state change to secondaries' <debug> [1446834482.545642] [devices/nm-device.c:8806] nm_device_queue_state(): [0x7fc77e1c0fc0] (port120): queued state change to secondaries due to none (id 11380) ** NetworkManager:ERROR:devices/nm-device.c:5250:nm_device_activate_stage3_ip4_start: assertion failed: (priv->ip4_state == IP_WAIT) 5250 g_assert (priv->ip4_state == IP_WAIT); (gdb) print priv->ip4_state $1 = IP_DONE (gdb) print priv->master $3 = { ... master = 0x7fc77df77020, enslaved = 1, master_ready_handled = 1, master_ready_id = 0, is_master = 0, slaves = 0x0, ...}
2015-11-09 11:44:09 +01:00
if ( nm_device_activate_ip6_state_in_wait (self)
&& !nm_device_activate_stage3_ip6_start (self))
return;
nm_device_check_ip_failed (self, TRUE);
}
static gboolean
fw_change_zone_handle (NMDevice *self,
NMFirewallManagerCallId call_id,
GError *error)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_val_if_fail (priv->fw_call == call_id, FALSE);
priv->fw_call = NULL;
return !nm_utils_error_is_cancelled (error, FALSE);
}
static void
fw_change_zone_cb_stage2 (NMFirewallManager *firewall_manager,
NMFirewallManagerCallId call_id,
GError *error,
gpointer user_data)
{
NMDevice *self = user_data;
NMDevicePrivate *priv;
if (!fw_change_zone_handle (self, call_id, error))
return;
/* FIXME: fail the device on error? */
priv = NM_DEVICE_GET_PRIVATE (self);
priv->fw_ready = TRUE;
nm_device_activate_schedule_stage3_ip_config_start (self);
}
static void
fw_change_zone_cb_ip_check (NMFirewallManager *firewall_manager,
NMFirewallManagerCallId call_id,
GError *error,
gpointer user_data)
{
NMDevice *self = user_data;
if (!fw_change_zone_handle (self, call_id, error))
return;
/* FIXME: fail the device on error? */
nm_device_start_ip_check (self);
}
/*
* nm_device_activate_schedule_stage3_ip_config_start
*
* Schedule IP configuration start
*/
void
nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self)
{
NMDevicePrivate *priv;
NMConnection *connection;
NMSettingConnection *s_con = NULL;
const char *zone;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->act_request);
/* Add the interface to the specified firewall zone */
connection = nm_device_get_applied_connection (self);
g_assert (connection);
s_con = nm_connection_get_setting_connection (connection);
if (!priv->fw_ready) {
if (nm_device_uses_assumed_connection (self))
priv->fw_ready = TRUE;
else {
if (!priv->fw_call) {
zone = nm_setting_connection_get_zone (s_con);
_LOGD (LOGD_DEVICE, "Activation: setting firewall zone '%s'", zone ? zone : "default");
priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (),
nm_device_get_ip_iface (self),
zone,
FALSE,
fw_change_zone_cb_stage2,
self);
}
return;
}
}
activation_source_schedule (self, activate_stage3_ip_config_start, AF_INET);
}
static NMActStageReturn
act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *reason)
{
if (!get_ip_config_may_fail (self, AF_INET)) {
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
return NM_ACT_STAGE_RETURN_FAILURE;
}
return NM_ACT_STAGE_RETURN_SUCCESS;
}
/*
* nm_device_activate_stage4_ip4_config_timeout
*
* Time out on retrieving the IPv4 config.
*
*/
static void
activate_stage4_ip4_config_timeout (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &reason);
if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
return;
else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return;
}
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
priv->ip4_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
}
/*
* nm_device_activate_schedule_ip4_config_timeout
*
* Deal with a timeout of the IPv4 configuration
*
*/
void
nm_device_activate_schedule_ip4_config_timeout (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->act_request);
activation_source_schedule (self, activate_stage4_ip4_config_timeout, AF_INET);
}
static NMActStageReturn
act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *reason)
{
if (!get_ip_config_may_fail (self, AF_INET6)) {
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
return NM_ACT_STAGE_RETURN_FAILURE;
}
return NM_ACT_STAGE_RETURN_SUCCESS;
}
/*
* activate_stage4_ip6_config_timeout
*
* Time out on retrieving the IPv6 config.
*
*/
static void
activate_stage4_ip6_config_timeout (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &reason);
if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
return;
if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return;
}
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
priv->ip6_state = IP_FAIL;
nm_device_check_ip_failed (self, FALSE);
}
/*
* nm_device_activate_schedule_ip6_config_timeout
*
* Deal with a timeout of the IPv6 configuration
*
*/
void
nm_device_activate_schedule_ip6_config_timeout (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->act_request);
activation_source_schedule (self, activate_stage4_ip6_config_timeout, AF_INET6);
}
static gboolean
share_init (void)
{
char *modules[] = { "ip_tables", "iptable_nat", "nf_nat_ftp", "nf_nat_irc",
"nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323",
NULL };
char **iter;
int errsv;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_forward", "1")) {
errsv = errno;
nm_log_err (LOGD_SHARING, "share: error starting IP forwarding: (%d) %s",
errsv, strerror (errsv));
return FALSE;
}
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_dynaddr", "1")) {
errsv = errno;
nm_log_err (LOGD_SHARING, "share: error starting IP forwarding: (%d) %s",
errsv, strerror (errsv));
}
for (iter = modules; *iter; iter++)
nm_utils_modprobe (NULL, FALSE, *iter, NULL);
return TRUE;
}
static void
add_share_rule (NMActRequest *req, const char *table, const char *fmt, ...)
{
va_list args;
char *cmd;
va_start (args, fmt);
cmd = g_strdup_vprintf (fmt, args);
va_end (args);
nm_act_request_add_share_rule (req, table, cmd);
g_free (cmd);
}
static gboolean
start_sharing (NMDevice *self, NMIP4Config *config)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *req;
GError *error = NULL;
char str_addr[INET_ADDRSTRLEN + 1];
char str_mask[INET_ADDRSTRLEN + 1];
guint32 netmask, network;
const NMPlatformIP4Address *ip4_addr;
const char *ip_iface;
g_return_val_if_fail (config != NULL, FALSE);
ip_iface = nm_device_get_ip_iface (self);
ip4_addr = nm_ip4_config_get_address (config, 0);
if (!ip4_addr || !ip4_addr->address)
return FALSE;
netmask = nm_utils_ip4_prefix_to_netmask (ip4_addr->plen);
if (!inet_ntop (AF_INET, &netmask, str_mask, sizeof (str_mask)))
return FALSE;
network = ip4_addr->address & netmask;
if (!inet_ntop (AF_INET, &network, str_addr, sizeof (str_addr)))
return FALSE;
if (!share_init ())
return FALSE;
req = nm_device_get_act_request (self);
g_assert (req);
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", ip_iface);
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", ip_iface);
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", ip_iface);
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", ip_iface);
add_share_rule (req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface);
add_share_rule (req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface);
add_share_rule (req, "filter", "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", ip_iface, ip_iface);
add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, ip_iface);
add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, ip_iface);
add_share_rule (req, "nat", "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask);
nm_act_request_set_shared (req, TRUE);
if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, config, &error)) {
_LOGE (LOGD_SHARING, "share: (%s) failed to start dnsmasq: %s",
ip_iface, (error && error->message) ? error->message : "(unknown)");
g_error_free (error);
nm_act_request_set_shared (req, FALSE);
return FALSE;
}
priv->dnsmasq_state_id = g_signal_connect (priv->dnsmasq_manager, "state-changed",
G_CALLBACK (dnsmasq_state_changed_cb),
self);
return TRUE;
}
static void
send_arps (NMDevice *self, const char *mode_arg)
{
const char *argv[] = { NULL, mode_arg, "-q", "-I", nm_device_get_ip_iface (self), "-c", "1", NULL, NULL };
int ip_arg = G_N_ELEMENTS (argv) - 2;
NMConnection *connection;
NMSettingIPConfig *s_ip4;
int i, num;
NMIPAddress *addr;
GError *error = NULL;
connection = nm_device_get_applied_connection (self);
if (!connection)
return;
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (!s_ip4)
return;
num = nm_setting_ip_config_get_num_addresses (s_ip4);
if (num == 0)
return;
argv[0] = nm_utils_find_helper ("arping", NULL, NULL);
if (!argv[0]) {
_LOGW (LOGD_DEVICE | LOGD_IP4, "arping could not be found; no ARPs will be sent");
return;
}
for (i = 0; i < num; i++) {
gs_free char *tmp_str = NULL;
gboolean success;
addr = nm_setting_ip_config_get_address (s_ip4, i);
argv[ip_arg] = nm_ip_address_get_address (addr);
_LOGD (LOGD_DEVICE | LOGD_IP4,
"arping: run %s", (tmp_str = g_strjoinv (" ", (char **) argv)));
success = g_spawn_async (NULL, (char **) argv, NULL,
G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
NULL, NULL, NULL, &error);
if (!success) {
_LOGW (LOGD_DEVICE | LOGD_IP4,
"arping: could not send ARP for local address %s: %s",
argv[ip_arg], error->message);
g_clear_error (&error);
}
}
}
static gboolean
arp_announce_round2 (gpointer self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->arp_round2_id = 0;
if ( priv->state >= NM_DEVICE_STATE_IP_CONFIG
&& priv->state <= NM_DEVICE_STATE_ACTIVATED)
send_arps (self, "-U");
return G_SOURCE_REMOVE;
}
static void
arp_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->arp_round2_id) {
g_source_remove (priv->arp_round2_id);
priv->arp_round2_id = 0;
}
}
static void
arp_announce (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMSettingIPConfig *s_ip4;
int num;
arp_cleanup (self);
/* We only care about manually-configured addresses; DHCP- and autoip-configured
* ones should already have been seen on the network at this point.
*/
connection = nm_device_get_applied_connection (self);
if (!connection)
return;
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (!s_ip4)
return;
num = nm_setting_ip_config_get_num_addresses (s_ip4);
if (num == 0)
return;
send_arps (self, "-A");
priv->arp_round2_id = g_timeout_add_seconds (2, arp_announce_round2, self);
}
static void
activate_stage5_ip4_config_commit (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *req;
const char *method;
NMConnection *connection;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
int ip_ifindex;
req = nm_device_get_act_request (self);
g_assert (req);
connection = nm_act_request_get_applied_connection (req);
g_assert (connection);
/* Interface must be IFF_UP before IP config can be applied */
ip_ifindex = nm_device_get_ip_ifindex (self);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex) && !nm_device_uses_assumed_connection (self)) {
nm_platform_link_set_up (NM_PLATFORM_GET, ip_ifindex, NULL);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex))
_LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", 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)) {
_LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed");
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
return;
}
/* Start IPv4 sharing if we need it */
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) {
if (!start_sharing (self, priv->ip4_config)) {
_LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed.");
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
return;
}
}
/* If IPv4 wasn't the first to complete, and DHCP was used, then ensure
* dispatcher scripts get the DHCP lease information.
*/
if ( priv->dhcp4_client
&& nm_device_activate_ip4_state_in_conf (self)
&& (nm_device_get_state (self) > NM_DEVICE_STATE_IP_CONFIG)) {
/* Notify dispatcher scripts of new DHCP4 config */
nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE,
nm_device_get_settings_connection (self),
nm_device_get_applied_connection (self),
self,
NULL,
NULL,
NULL);
}
arp_announce (self);
/* Enter the IP_CHECK state if this is the first method to complete */
priv->ip4_state = IP_DONE;
nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE);
if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
}
static void
nm_device_queued_ip_config_change_clear (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->queued_ip4_config_id) {
_LOGD (LOGD_DEVICE, "clearing queued IP4 config change");
g_source_remove (priv->queued_ip4_config_id);
priv->queued_ip4_config_id = 0;
}
if (priv->queued_ip6_config_id) {
_LOGD (LOGD_DEVICE, "clearing queued IP6 config change");
g_source_remove (priv->queued_ip6_config_id);
priv->queued_ip6_config_id = 0;
}
}
void
nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *config)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
g_clear_object (&priv->dev_ip4_config);
if (config)
priv->dev_ip4_config = g_object_ref (config);
nm_device_queued_ip_config_change_clear (self);
activation_source_schedule (self, activate_stage5_ip4_config_commit, AF_INET);
}
gboolean
nm_device_activate_ip4_state_in_conf (NMDevice *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_CONF;
}
gboolean
nm_device_activate_ip4_state_in_wait (NMDevice *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_WAIT;
}
static void
activate_stage5_ip6_config_commit (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *req;
NMConnection *connection;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
int ip_ifindex;
req = nm_device_get_act_request (self);
g_assert (req);
connection = nm_act_request_get_applied_connection (req);
g_assert (connection);
/* Interface must be IFF_UP before IP config can be applied */
ip_ifindex = nm_device_get_ip_ifindex (self);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex) && !nm_device_uses_assumed_connection (self)) {
nm_platform_link_set_up (NM_PLATFORM_GET, ip_ifindex, NULL);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex))
_LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self));
}
if (ip6_config_merge_and_apply (self, TRUE, &reason)) {
/* If IPv6 wasn't the first IP to complete, and DHCP was used,
* then ensure dispatcher scripts get the DHCP lease information.
*/
if ( priv->dhcp6_client
&& nm_device_activate_ip6_state_in_conf (self)
&& (nm_device_get_state (self) > NM_DEVICE_STATE_IP_CONFIG)) {
/* Notify dispatcher scripts of new DHCP6 config */
nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE,
nm_device_get_settings_connection (self),
nm_device_get_applied_connection (self),
self,
NULL,
NULL,
NULL);
}
/* Enter the IP_CHECK state if this is the first method to complete */
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
priv->ip6_state = IP_DONE;
nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE);
nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
core: combine DHCP and RA IPv6 configs when either changes Since both RA and DHCP may be run at the same time, we want to make sure to merge both configs into a final config when either RA or DHCP changes. Previously this only happened when RA changed, but not when DHCP changed or completed. This caused the config applied when DHCP completed to not contain the RA-derived address, which was then removed from the device, which then regressed the IPv6 RA state, causing a device failure. Found by Tore Anderson Oct 18 18:35:00 wrath dhclient[13782]: RCV: Reply message on eth0 from fe80::ca6c:87ff:feab:da5f. Oct 18 18:35:00 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 state changed nbi -> renew6 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642273] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 7 Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642282] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'interface'=>'eth0' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642288] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_client_id'=>'0:3:0:1:0:30:1b:bc:7f:23' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642294] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'reason'=>'RENEW6' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642300] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_name_servers'=>'2001:840:100:: 2001:840:200::' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642305] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'new_dhcp6_server_id'=>'0:3:0:1:c8:6c:87:ab:da:5f' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.642311] [nm-dhcp-client.c:1211] ip6_options_to_config(): (eth0): option 'pid'=>'13782' Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) scheduled... Oct 18 18:35:00 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) started... Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643641] [nm-system.c:182] sync_addresses(): (eth0): syncing addresses (family 10) Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643655] [nm-system.c:235] sync_addresses(): (eth0): removing address '2001:840:3033:20:230:1bff:febc:7f23/64' Oct 18 18:35:00 wrath NetworkManager[12390]: <debug> [1318955700.643702] [nm-system.c:218] sync_addresses(): (eth0): ignoring IPv6 link-local address Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Policy set 'Wired connection 1' (eth0) as default for IPv4 routing and DNS. Oct 18 18:35:01 wrath NetworkManager[12390]: <info> Activation (eth0) Stage 5 of 5 (IPv6 Commit) complete. Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656335] [nm-ip6-manager.c:1041] netlink_notification(): netlink notificate type 21 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656345] [nm-ip6-manager.c:542] process_addr(): processing netlink new/del address message Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656359] [nm-ip6-manager.c:1069] netlink_notification(): (eth0): syncing device with netlink changes Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656367] [nm-ip6-manager.c:419] nm_ip6_device_sync_from_netlink(): (eth0): syncing with netlink (ra_flags 0x800000B0) (state/target 'got-address'/'got-address') Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656376] [nm-ip6-manager.c:438] nm_ip6_device_sync_from_netlink(): (eth0): netlink address: fe80::230:1bff:febc:7f23 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656382] [nm-ip6-manager.c:460] nm_ip6_device_sync_from_netlink(): (eth0): addresses synced (state got-address) Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656388] [nm-ip6-manager.c:474] nm_ip6_device_sync_from_netlink(): router advertisement requests parallel DHCPv6 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656393] [nm-ip6-manager.c:512] nm_ip6_device_sync_from_netlink(): (eth0): RA-provided address no longer valid Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): DHCPv6 client pid 13782 exited with status 0 Oct 18 18:35:01 wrath NetworkManager[12390]: <debug> [1318955701.656448] [nm-device.c:1582] dhcp6_state_changed(): (eth0): new DHCPv6 client state 23 Oct 18 18:35:01 wrath NetworkManager[12390]: <info> (eth0): device state change: activated -> failed (reason 'ip-config-unavailable') [100 120 5]
2011-10-21 14:25:35 -05:00
} else {
_LOGW (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed");
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
}
}
void
nm_device_activate_schedule_ip6_config_result (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (NM_IS_DEVICE (self));
/* If IP had previously failed, move it back to IP_CONF since we
* clearly now have configuration.
*/
if (priv->ip6_state == IP_FAIL)
priv->ip6_state = IP_CONF;
activation_source_schedule (self, activate_stage5_ip6_config_commit, AF_INET6);
}
gboolean
nm_device_activate_ip6_state_in_conf (NMDevice *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_CONF;
}
gboolean
nm_device_activate_ip6_state_in_wait (NMDevice *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_WAIT;
}
2007-09-11 Dan Williams <dcbw@redhat.com> * libnm-util/nm-setting.c libnm-util/nm-setting.h - (nm_setting_update_secrets): new function; add a virtual function that subclasses can implement to update their secrets - (setting_wireless_security_update_secrets): implement that function for the 802-11-wireless-security subclass * libnm-util/nm-connection.c libnm-util/nm-connection.h - (nm_connection_update_secrets): update secrets for a Setting and emit a signal on success * src/nm-manager.c src/nm-manager.h src/nm-marshal.list - (connection_get_settings_cb): enable system settings bits - (nm_manager_get_connection_secrets, get_secrets_cb): add function to request secrets from the settings dbus service and to push those secrets to the NMConnection itself * src/nm-activation-request.c src/nm-activation-request.h - Attach to the 'secrets-updated' signal of the NMConnection that's currently being activated, and proxy that signal to other listeners. Goes through the activation request because the activation request is the thing that manages the lifetime of the NMConnection that's being activated. * src/nm-device-802-11-wireless.c - (real_connection_secrets_updated): implement the connection secrets updated notification and restart activation when secrets are received - (real_act_stage2_config): request secrets from the settings dbus service if secrets are needed * src/nm-device.c src/nm-device.h - (clear_act_request, nm_device_activation_cancel, nm_device_deactivate_quickly, nm_device_dispose): consolidate places where the activation request is cleared - (nm_device_activate, connection_secrets_updated_cb): attach to the updated secrets signal of activation request and add a function that subclasses can override to handle it easily git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2782 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-09-11 18:02:27 +00:00
static void
clear_act_request (NMDevice *self)
{
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2007-09-11 Dan Williams <dcbw@redhat.com> * libnm-util/nm-setting.c libnm-util/nm-setting.h - (nm_setting_update_secrets): new function; add a virtual function that subclasses can implement to update their secrets - (setting_wireless_security_update_secrets): implement that function for the 802-11-wireless-security subclass * libnm-util/nm-connection.c libnm-util/nm-connection.h - (nm_connection_update_secrets): update secrets for a Setting and emit a signal on success * src/nm-manager.c src/nm-manager.h src/nm-marshal.list - (connection_get_settings_cb): enable system settings bits - (nm_manager_get_connection_secrets, get_secrets_cb): add function to request secrets from the settings dbus service and to push those secrets to the NMConnection itself * src/nm-activation-request.c src/nm-activation-request.h - Attach to the 'secrets-updated' signal of the NMConnection that's currently being activated, and proxy that signal to other listeners. Goes through the activation request because the activation request is the thing that manages the lifetime of the NMConnection that's being activated. * src/nm-device-802-11-wireless.c - (real_connection_secrets_updated): implement the connection secrets updated notification and restart activation when secrets are received - (real_act_stage2_config): request secrets from the settings dbus service if secrets are needed * src/nm-device.c src/nm-device.h - (clear_act_request, nm_device_activation_cancel, nm_device_deactivate_quickly, nm_device_dispose): consolidate places where the activation request is cleared - (nm_device_activate, connection_secrets_updated_cb): attach to the updated secrets signal of activation request and add a function that subclasses can override to handle it easily git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2782 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-09-11 18:02:27 +00:00
if (!priv->act_request)
2007-09-11 Dan Williams <dcbw@redhat.com> * libnm-util/nm-setting.c libnm-util/nm-setting.h - (nm_setting_update_secrets): new function; add a virtual function that subclasses can implement to update their secrets - (setting_wireless_security_update_secrets): implement that function for the 802-11-wireless-security subclass * libnm-util/nm-connection.c libnm-util/nm-connection.h - (nm_connection_update_secrets): update secrets for a Setting and emit a signal on success * src/nm-manager.c src/nm-manager.h src/nm-marshal.list - (connection_get_settings_cb): enable system settings bits - (nm_manager_get_connection_secrets, get_secrets_cb): add function to request secrets from the settings dbus service and to push those secrets to the NMConnection itself * src/nm-activation-request.c src/nm-activation-request.h - Attach to the 'secrets-updated' signal of the NMConnection that's currently being activated, and proxy that signal to other listeners. Goes through the activation request because the activation request is the thing that manages the lifetime of the NMConnection that's being activated. * src/nm-device-802-11-wireless.c - (real_connection_secrets_updated): implement the connection secrets updated notification and restart activation when secrets are received - (real_act_stage2_config): request secrets from the settings dbus service if secrets are needed * src/nm-device.c src/nm-device.h - (clear_act_request, nm_device_activation_cancel, nm_device_deactivate_quickly, nm_device_dispose): consolidate places where the activation request is cleared - (nm_device_activate, connection_secrets_updated_cb): attach to the updated secrets signal of activation request and add a function that subclasses can override to handle it easily git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2782 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-09-11 18:02:27 +00:00
return;
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE);
priv->master_ready_handled = FALSE;
nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id);
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
g_clear_object (&priv->act_request);
g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
2007-09-11 Dan Williams <dcbw@redhat.com> * libnm-util/nm-setting.c libnm-util/nm-setting.h - (nm_setting_update_secrets): new function; add a virtual function that subclasses can implement to update their secrets - (setting_wireless_security_update_secrets): implement that function for the 802-11-wireless-security subclass * libnm-util/nm-connection.c libnm-util/nm-connection.h - (nm_connection_update_secrets): update secrets for a Setting and emit a signal on success * src/nm-manager.c src/nm-manager.h src/nm-marshal.list - (connection_get_settings_cb): enable system settings bits - (nm_manager_get_connection_secrets, get_secrets_cb): add function to request secrets from the settings dbus service and to push those secrets to the NMConnection itself * src/nm-activation-request.c src/nm-activation-request.h - Attach to the 'secrets-updated' signal of the NMConnection that's currently being activated, and proxy that signal to other listeners. Goes through the activation request because the activation request is the thing that manages the lifetime of the NMConnection that's being activated. * src/nm-device-802-11-wireless.c - (real_connection_secrets_updated): implement the connection secrets updated notification and restart activation when secrets are received - (real_act_stage2_config): request secrets from the settings dbus service if secrets are needed * src/nm-device.c src/nm-device.h - (clear_act_request, nm_device_activation_cancel, nm_device_deactivate_quickly, nm_device_dispose): consolidate places where the activation request is cleared - (nm_device_activate, connection_secrets_updated_cb): attach to the updated secrets signal of activation request and add a function that subclasses can override to handle it easily git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2782 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-09-11 18:02:27 +00:00
}
static void
dnsmasq_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->dnsmasq_manager)
return;
if (priv->dnsmasq_state_id) {
g_signal_handler_disconnect (priv->dnsmasq_manager, priv->dnsmasq_state_id);
priv->dnsmasq_state_id = 0;
}
nm_dnsmasq_manager_stop (priv->dnsmasq_manager);
g_object_unref (priv->dnsmasq_manager);
priv->dnsmasq_manager = NULL;
}
static void
_update_ip4_address (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint32 addr;
g_return_if_fail (NM_IS_DEVICE (self));
device: avoid a crash during destruction The ipv4_config might be gone already, _cleanup_generic_post() sets it to NULL. NetworkManager[30564]: <info> caught SIGINT, shutting down normally. (NetworkManager:30564): GLib-GObject-CRITICAL **: g_type_instance_get_private: assertion 'instance != NULL && instance->g_class != NULL' failed Program received signal SIGTRAP, Trace/breakpoint trap. g_logv (log_domain=0x7ffff4d92f64 "GLib-GObject", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fffffffd5e0) at gmessages.c:1046 1046 g_private_set (&g_log_depth, GUINT_TO_POINTER (depth)); (gdb) bt #0 0x00007ffff4a738c3 in g_logv (log_domain=0x7ffff4d92f64 "GLib-GObject", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fffffffd5e0) at gmessages.c:1046 #1 0x00007ffff4a73a3f in g_log (log_domain=log_domain@entry=0x7ffff4d92f64 "GLib-GObject", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x7ffff4ae173d "%s: assertion '%s' failed") at gmessages.c:1079 #2 0x00007ffff4a73a79 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7ffff4d92f64 "GLib-GObject", pretty_function=pretty_function@entry=0x7ffff4d9aad0 <__FUNCTION__.13620> "g_type_instance_get_private", expression=expression@entry=0x7ffff4d99db8 "instance != NULL && instance->g_class != NULL") at gmessages.c:1088 #3 0x00007ffff4d8d2ba in g_type_instance_get_private (instance=instance@entry=0x0, private_type=<optimized out>) at gtype.c:4632 #4 0x00000000004bf774 in nm_ip4_config_get_num_addresses (config=0x0) at nm-ip4-config.c:1418 #5 0x0000000000458834 in _update_ip4_address (self=self@entry=0xa8a490 [NMDeviceBridge]) at devices/nm-device.c:6069 #6 0x000000000045e740 in nm_device_set_ip4_config (self=self@entry=0xa8a490 [NMDeviceBridge], new_config=new_config@entry=0x0, default_route_metric=default_route_metric@entry=0, commit=commit@entry=1, routes_full_sync=routes_full_sync@entry=1, reason=reason@entry=0x7fffffffd7cc) at devices/nm-device.c:6558 #7 0x0000000000466c56 in _cleanup_generic_post (self=self@entry=0xa8a490 [NMDeviceBridge], cleanup_type=cleanup_type@entry=CLEANUP_TYPE_KEEP) at devices/nm-device.c:8108 #8 0x00000000004671af in dispose (object=0xa8a490 [NMDeviceBridge]) at devices/nm-device.c:9128 #9 0x00007ffff4d6ea82 in g_object_unref (_object=0xa8a490) at gobject.c:3133 #10 0x00000000004d1a53 in remove_device (manager=manager@entry=0x8822b0 [NMManager], device=0xa8a490 [NMDeviceBridge], quitting=quitting@entry=1, allow_unmanage=allow_unmanage@entry=1) at nm-manager.c:780 #11 0x00000000004d7db1 in nm_manager_stop (self=self@entry=0x8822b0 [NMManager]) at nm-manager.c:4199 #12 0x0000000000445aa9 in main (argc=1, argv=0x7fffffffda88) at main.c:465 (gdb)
2015-08-12 16:03:12 +02:00
if ( priv->ip4_config
&& ip_config_valid (priv->state)
&& nm_ip4_config_get_num_addresses (priv->ip4_config)) {
addr = nm_ip4_config_get_address (priv->ip4_config, 0)->address;
if (addr != priv->ip4_address) {
priv->ip4_address = addr;
g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_ADDRESS);
}
}
}
gboolean
nm_device_get_is_nm_owned (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
}
/*
* delete_on_deactivate_link_delete
*
* Function will be queued with g_idle_add to call
* nm_platform_link_delete for the underlying resources
* of the device.
*/
static gboolean
delete_on_deactivate_link_delete (gpointer user_data)
{
DeleteOnDeactivateData *data = user_data;
NMDevice *self = data->device;
_LOGD (LOGD_DEVICE, "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)",
data->ifindex, data->idle_add_id);
if (data->device) {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (data->device);
gs_free_error GError *error = NULL;
g_object_remove_weak_pointer (G_OBJECT (data->device), (void **) &data->device);
priv->delete_on_deactivate_data = NULL;
if (!nm_device_unrealize (data->device, TRUE, &error))
_LOGD (LOGD_DEVICE, "delete_on_deactivate: unrealizing %d failed (%s)", data->ifindex, error->message);
} else
nm_platform_link_delete (NM_PLATFORM_GET, data->ifindex);
g_free (data);
return FALSE;
}
static void
delete_on_deactivate_unschedule (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->delete_on_deactivate_data) {
DeleteOnDeactivateData *data = priv->delete_on_deactivate_data;
priv->delete_on_deactivate_data = NULL;
g_source_remove (data->idle_add_id);
g_object_remove_weak_pointer (G_OBJECT (self), (void **) &data->device);
_LOGD (LOGD_DEVICE, "delete_on_deactivate: cancel cleanup and delete virtual link #%d (id=%u)",
data->ifindex, data->idle_add_id);
g_free (data);
}
}
static void
delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
DeleteOnDeactivateData *data;
if (ifindex <= 0)
return;
if (!priv->is_nm_owned)
return;
if (priv->queued_act_request)
return;
if (!nm_device_is_software (self) || !nm_device_is_real (self))
return;
if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
return;
if (nm_device_get_state (self) == NM_DEVICE_STATE_UNAVAILABLE)
return;
delete_on_deactivate_unschedule (self); /* always cancel and reschedule */
data = g_new (DeleteOnDeactivateData, 1);
g_object_add_weak_pointer (G_OBJECT (self), (void **) &data->device);
data->device = self;
data->ifindex = ifindex;
data->idle_add_id = g_idle_add (delete_on_deactivate_link_delete, data);
priv->delete_on_deactivate_data = data;
_LOGD (LOGD_DEVICE, "delete_on_deactivate: schedule cleanup and delete virtual link #%d (id=%u)",
ifindex, data->idle_add_id);
}
static void
disconnect_cb (NMDevice *self,
GDBusMethodInvocation *context,
2015-07-14 10:19:19 +02:00
NMAuthSubject *subject,
GError *error,
gpointer user_data)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GError *local = NULL;
if (error) {
g_dbus_method_invocation_return_gerror (context, error);
2015-07-14 10:19:19 +02:00
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, error->message);
return;
}
/* Authorized */
if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) {
local = g_error_new_literal (NM_DEVICE_ERROR,
NM_DEVICE_ERROR_NOT_ACTIVE,
"Device is not active");
2015-07-14 10:19:19 +02:00
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, local->message);
g_dbus_method_invocation_take_error (context, local);
} else {
nm_device_set_autoconnect (self, FALSE);
nm_device_state_changed (self,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
g_dbus_method_invocation_return_value (context, NULL);
2015-07-14 10:19:19 +02:00
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, subject, NULL);
}
}
static void
_clear_queued_act_request (NMDevicePrivate *priv)
{
if (priv->queued_act_request) {
nm_active_connection_set_state ((NMActiveConnection *) priv->queued_act_request, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
g_clear_object (&priv->queued_act_request);
}
}
static void
impl_device_disconnect (NMDevice *self, GDBusMethodInvocation *context)
{
NMConnection *connection;
GError *error = NULL;
if (NM_DEVICE_GET_PRIVATE (self)->act_request == NULL) {
error = g_error_new_literal (NM_DEVICE_ERROR,
NM_DEVICE_ERROR_NOT_ACTIVE,
"This device is not active");
g_dbus_method_invocation_take_error (context, error);
return;
}
connection = nm_device_get_applied_connection (self);
g_assert (connection);
/* Ask the manager to authenticate this request for us */
g_signal_emit (self, signals[AUTH_REQUEST], 0,
context,
connection,
NM_AUTH_PERMISSION_NETWORK_CONTROL,
TRUE,
disconnect_cb,
NULL);
}
static void
delete_cb (NMDevice *self,
GDBusMethodInvocation *context,
2015-07-14 10:19:19 +02:00
NMAuthSubject *subject,
GError *error,
gpointer user_data)
{
GError *local = NULL;
if (error) {
g_dbus_method_invocation_return_gerror (context, error);
2015-07-14 10:19:19 +02:00
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, FALSE, subject, error->message);
return;
}
/* Authorized */
2015-07-14 10:19:19 +02:00
nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, subject, NULL);
if (nm_device_unrealize (self, TRUE, &local))
g_dbus_method_invocation_return_value (context, NULL);
else
g_dbus_method_invocation_take_error (context, local);
}
static void
impl_device_delete (NMDevice *self, GDBusMethodInvocation *context)
{
GError *error = NULL;
if (!nm_device_is_software (self) || !nm_device_is_real (self)) {
error = g_error_new_literal (NM_DEVICE_ERROR,
NM_DEVICE_ERROR_NOT_SOFTWARE,
"This device is not a software device or is not realized");
g_dbus_method_invocation_take_error (context, error);
return;
}
/* Ask the manager to authenticate this request for us */
g_signal_emit (self, signals[AUTH_REQUEST], 0,
context,
NULL,
NM_AUTH_PERMISSION_NETWORK_CONTROL,
TRUE,
delete_cb,
NULL);
}
static gboolean
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
_device_activate (NMDevice *self, NMActRequest *req)
{
NMDevicePrivate *priv;
NMConnection *connection;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
/* Ensure the activation request is still valid; the master may have
* already failed in which case activation of this device should not proceed.
*/
if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING)
return FALSE;
priv = NM_DEVICE_GET_PRIVATE (self);
connection = nm_act_request_get_applied_connection (req);
g_assert (connection);
_LOGI (LOGD_DEVICE, "Activation: starting connection '%s' (%s)",
nm_connection_get_id (connection),
nm_connection_get_uuid (connection));
delete_on_deactivate_unschedule (self);
/* Move default unmanaged devices to DISCONNECTED state here */
if (nm_device_get_default_unmanaged (self) && priv->state == NM_DEVICE_STATE_UNMANAGED) {
nm_device_state_changed (self,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
/* note: don't notify D-Bus of the new AC here, but do it later when
* changing state to PREPARE so that the two properties change together.
*/
2007-09-28 Tambet Ingo <tambet@gmail.com> * src/nm-manager.c: * src/nm-manager.h: Implement device activation through NMManager. Implement "pending device activation" here - If the connection isn't found, we try to wait for up to 5 seconds for the connection to be provided. Add NMConnectionType argument to "connection-added" and "connection-removed" signals. (nm_manager_get): Remove. Finally. * src/nm-activation-request.c: * src/nm-activation-request.h: Remove all the deferred activation code. * src/nm-device.c: Remove all the deferred activation code. Once * the device activation is started, it's started. Update the activation virtual function signature. * src/nm-device-interface.c: * src/nm-device-interface.h: Device activation now takes only NMActRequest argument. Don't expose device activation directly on dbus, it's supposed to go through NMManager now. * src/NetworkManagerPolicy.c (nm_policy_device_change_check): * Make the code a bit more compact. Use the new device activation methods through NMManager. * introspection/nm-manager-client.xml: * introspection/nm-manager.xml: * libnm-glib/nm-client.c: * libnm-glib/nm-client.h: Add device activation method. * libnm-glib/nm-device.c: * libnm-glib/nm-device.h: * introspection/nm-device.xml: Remove device activation method. It's done through NMManager now. * src/vpn-manager/nm-vpn-manager.c (impl_vpn_manager_connect): * Use the shiny new (nm_manager_get_device_by_path) function, get rid of our own )find_device). git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2915 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-10-01 15:38:39 +00:00
priv->act_request = g_object_ref (req);
nm_device_activate_schedule_stage1_device_prepare (self);
return TRUE;
}
static void
_carrier_wait_check_queued_act_request (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *queued_req;
if ( !priv->queued_act_request
|| !priv->queued_act_request_is_waiting_for_carrier)
return;
priv->queued_act_request_is_waiting_for_carrier = FALSE;
if (!priv->carrier) {
_LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout");
_clear_queued_act_request (priv);
} else {
_LOGD (LOGD_DEVICE, "Activate queued activation request as we now have carrier");
queued_req = priv->queued_act_request;
priv->queued_act_request = NULL;
_device_activate (self, queued_req);
g_object_unref (queued_req);
}
}
static gboolean
_carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
/* If we have carrier or if we are not waiting for it, the activation
* request is not blocked waiting for carrier. */
if (priv->carrier)
return FALSE;
if (priv->carrier_wait_id == 0)
return FALSE;
connection = nm_act_request_get_applied_connection (req);
if (!connection_requires_carrier (connection))
return FALSE;
if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL)) {
/* We passed all @flags we have, and no @specific_object.
* This equals maximal availability, if a connection is not available
* in this case, it is not waiting for carrier.
*
* Actually, why are we even trying to activate it? Strange, but whatever
* the reason, don't wait for carrier.
*/
return FALSE;
}
if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, NULL)) {
/* The connection was available with flags ALL, and it is still available
* if we pretend not to wait for carrier. That means that the
* connection is available now, and does not wait for carrier.
*
* Since the flags increase the availability of a connection, when checking
* ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */
return FALSE;
}
/* The activation request must wait for carrier. */
return TRUE;
}
void
nm_device_steal_connection (NMDevice *self, NMSettingsConnection *connection)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
_LOGW (LOGD_DEVICE, "disconnecting connection '%s' for new activation request.",
nm_settings_connection_get_id (connection));
if ( priv->queued_act_request
&& connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request)))
_clear_queued_act_request (priv);
if ( priv->act_request
&& connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->act_request))
&& priv->state < NM_DEVICE_STATE_DEACTIVATING)
nm_device_state_changed (self,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION);
}
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
void
nm_device_queue_activation (NMDevice *self, NMActRequest *req)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean must_queue;
must_queue = _carrier_wait_check_act_request_must_queue (self, req);
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
if (!priv->act_request && !must_queue) {
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
/* Just activate immediately */
if (!_device_activate (self, req))
g_assert_not_reached ();
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
return;
}
/* supercede any already-queued request */
_clear_queued_act_request (priv);
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
priv->queued_act_request = g_object_ref (req);
priv->queued_act_request_is_waiting_for_carrier = must_queue;
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
_LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect");
/* Deactivate existing activation request first */
if (priv->act_request) {
_LOGI (LOGD_DEVICE, "disconnecting for new activation request.");
nm_device_state_changed (self,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION);
}
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
}
/*
* nm_device_is_activating
*
* Return whether or not the device is currently activating itself.
*
*/
gboolean
nm_device_is_activating (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceState state;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
state = nm_device_get_state (self);
if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES)
return TRUE;
/* There's a small race between the time when stage 1 is scheduled
* and when the device actually sets STATE_PREPARE when the activation
* handler is actually run. If there's an activation handler scheduled
* we're activating anyway.
*/
return priv->act_handle4.id ? TRUE : FALSE;
}
/* IP Configuration stuff */
NMDhcp4Config *
2008-09-18 Dan Williams <dcbw@redhat.com> Implement support for honoring configured and automatic hostnames, and for setting the configured hostname. * introspection/nm-ip4-config.xml src/nm-ip4-config.c src/nm-ip4-config.h src/dhcp-manager/nm-dhcp-manager.c - Remove useless hostname property; it's not really part of the IPv4 config * introspection/nm-settings-system.xml libnm-glib/nm-dbus-settings-system.c libnm-glib/nm-dbus-settings-system.h - Add SetHostname() call to system settings D-Bus interface - Add Hostname property to system settings D-Bus interface - (nm_dbus_settings_system_save_hostname, nm_dbus_settings_system_get_hostname): implement * src/nm-device.c src/nm-device.h - (nm_device_get_dhcp4_config): implement * src/nm-manager.c src/nm-manager.h - Fetch and track system settings service hostname changes, and proxy the changes via a GObject property of the manager * system-settings/src/nm-system-config-interface.c system-settings/src/nm-system-config-interface.h - Replace nm_system_config_interface_supports_add() with a capabilities bitfield * system-settings/src/nm-system-config-error.c system-settings/src/nm-system-config-error.h - Add additional errors * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (get_property, nm_sysconfig_settings_class_init): add hostname property; first plugin returning a hostname wins - (impl_settings_add_connection): use plugin capabilities instead of nm_system_config_interface_supports_add() - (impl_settings_save_hostname): implement hostname saving * src/NetworkManagerPolicy.c - (lookup_thread_run_cb, lookup_thread_worker, lookup_thread_new, lookup_thread_die): implement an asynchronous hostname lookup thread which given an IPv4 address tries to look up the hostname for that address with reverse DNS - (get_best_device): split out best device code from update_routing_and_dns() - (update_etc_hosts): update /etc/hosts with the machine's new hostname to preserve the 127.0.0.1 reverse mapping that so many things require - (set_system_hostname): set a given hostname - (update_system_hostname): implement hostname policy; a configured hostname (from the system settings service) is used if available, otherwise an automatically determined hostname from DHCP, VPN, etc. If there was no automatically determined hostname, reverse DNS of the best device's IP address will be used, and as a last resort the hostname 'localhost.localdomain' is set. - (update_routing_and_dns): use get_best_device(); update the system hostname when the network config changes - (hostname_changed): update system hostname if the system settings service signals a hostname change - (nm_policy_new): list for system settings service hostname changes - (nm_policy_destroy): ensure that an in-progress hostname lookup thread gets told to die * system-settings/plugins/keyfile/plugin.c system-settings/plugins/ifcfg-suse/plugin.c - (get_property, sc_plugin_ifcfg_class_init): implement hostname and capabilities properties * system-settings/plugins/ifcfg-fedora/shvar.c - (svOpenFile): re-enable R/W access of ifcfg files since the plugin writes out /etc/sysconfig/network now * system-settings/plugins/ifcfg-fedora/plugin.c - (plugin_get_hostname): get hostname from /etc/sysconfig/network - (plugin_set_hostname): save hostname to /etc/sysconfig/network - (sc_network_changed_cb): handle changes to /etc/sysconfig/network - (sc_plugin_ifcfg_init): monitor /etc/sysconfig/network for changes - (get_property, set_property, sc_plugin_ifcfg_class_init): implement hostname get/set and capabilities get git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4077 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-09-18 15:16:44 +00:00
nm_device_get_dhcp4_config (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
2008-09-18 Dan Williams <dcbw@redhat.com> Implement support for honoring configured and automatic hostnames, and for setting the configured hostname. * introspection/nm-ip4-config.xml src/nm-ip4-config.c src/nm-ip4-config.h src/dhcp-manager/nm-dhcp-manager.c - Remove useless hostname property; it's not really part of the IPv4 config * introspection/nm-settings-system.xml libnm-glib/nm-dbus-settings-system.c libnm-glib/nm-dbus-settings-system.h - Add SetHostname() call to system settings D-Bus interface - Add Hostname property to system settings D-Bus interface - (nm_dbus_settings_system_save_hostname, nm_dbus_settings_system_get_hostname): implement * src/nm-device.c src/nm-device.h - (nm_device_get_dhcp4_config): implement * src/nm-manager.c src/nm-manager.h - Fetch and track system settings service hostname changes, and proxy the changes via a GObject property of the manager * system-settings/src/nm-system-config-interface.c system-settings/src/nm-system-config-interface.h - Replace nm_system_config_interface_supports_add() with a capabilities bitfield * system-settings/src/nm-system-config-error.c system-settings/src/nm-system-config-error.h - Add additional errors * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (get_property, nm_sysconfig_settings_class_init): add hostname property; first plugin returning a hostname wins - (impl_settings_add_connection): use plugin capabilities instead of nm_system_config_interface_supports_add() - (impl_settings_save_hostname): implement hostname saving * src/NetworkManagerPolicy.c - (lookup_thread_run_cb, lookup_thread_worker, lookup_thread_new, lookup_thread_die): implement an asynchronous hostname lookup thread which given an IPv4 address tries to look up the hostname for that address with reverse DNS - (get_best_device): split out best device code from update_routing_and_dns() - (update_etc_hosts): update /etc/hosts with the machine's new hostname to preserve the 127.0.0.1 reverse mapping that so many things require - (set_system_hostname): set a given hostname - (update_system_hostname): implement hostname policy; a configured hostname (from the system settings service) is used if available, otherwise an automatically determined hostname from DHCP, VPN, etc. If there was no automatically determined hostname, reverse DNS of the best device's IP address will be used, and as a last resort the hostname 'localhost.localdomain' is set. - (update_routing_and_dns): use get_best_device(); update the system hostname when the network config changes - (hostname_changed): update system hostname if the system settings service signals a hostname change - (nm_policy_new): list for system settings service hostname changes - (nm_policy_destroy): ensure that an in-progress hostname lookup thread gets told to die * system-settings/plugins/keyfile/plugin.c system-settings/plugins/ifcfg-suse/plugin.c - (get_property, sc_plugin_ifcfg_class_init): implement hostname and capabilities properties * system-settings/plugins/ifcfg-fedora/shvar.c - (svOpenFile): re-enable R/W access of ifcfg files since the plugin writes out /etc/sysconfig/network now * system-settings/plugins/ifcfg-fedora/plugin.c - (plugin_get_hostname): get hostname from /etc/sysconfig/network - (plugin_set_hostname): save hostname to /etc/sysconfig/network - (sc_network_changed_cb): handle changes to /etc/sysconfig/network - (sc_plugin_ifcfg_init): monitor /etc/sysconfig/network for changes - (get_property, set_property, sc_plugin_ifcfg_class_init): implement hostname get/set and capabilities get git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4077 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-09-18 15:16:44 +00:00
return NM_DEVICE_GET_PRIVATE (self)->dhcp4_config;
2008-09-18 Dan Williams <dcbw@redhat.com> Implement support for honoring configured and automatic hostnames, and for setting the configured hostname. * introspection/nm-ip4-config.xml src/nm-ip4-config.c src/nm-ip4-config.h src/dhcp-manager/nm-dhcp-manager.c - Remove useless hostname property; it's not really part of the IPv4 config * introspection/nm-settings-system.xml libnm-glib/nm-dbus-settings-system.c libnm-glib/nm-dbus-settings-system.h - Add SetHostname() call to system settings D-Bus interface - Add Hostname property to system settings D-Bus interface - (nm_dbus_settings_system_save_hostname, nm_dbus_settings_system_get_hostname): implement * src/nm-device.c src/nm-device.h - (nm_device_get_dhcp4_config): implement * src/nm-manager.c src/nm-manager.h - Fetch and track system settings service hostname changes, and proxy the changes via a GObject property of the manager * system-settings/src/nm-system-config-interface.c system-settings/src/nm-system-config-interface.h - Replace nm_system_config_interface_supports_add() with a capabilities bitfield * system-settings/src/nm-system-config-error.c system-settings/src/nm-system-config-error.h - Add additional errors * system-settings/src/dbus-settings.c system-settings/src/dbus-settings.h - (get_property, nm_sysconfig_settings_class_init): add hostname property; first plugin returning a hostname wins - (impl_settings_add_connection): use plugin capabilities instead of nm_system_config_interface_supports_add() - (impl_settings_save_hostname): implement hostname saving * src/NetworkManagerPolicy.c - (lookup_thread_run_cb, lookup_thread_worker, lookup_thread_new, lookup_thread_die): implement an asynchronous hostname lookup thread which given an IPv4 address tries to look up the hostname for that address with reverse DNS - (get_best_device): split out best device code from update_routing_and_dns() - (update_etc_hosts): update /etc/hosts with the machine's new hostname to preserve the 127.0.0.1 reverse mapping that so many things require - (set_system_hostname): set a given hostname - (update_system_hostname): implement hostname policy; a configured hostname (from the system settings service) is used if available, otherwise an automatically determined hostname from DHCP, VPN, etc. If there was no automatically determined hostname, reverse DNS of the best device's IP address will be used, and as a last resort the hostname 'localhost.localdomain' is set. - (update_routing_and_dns): use get_best_device(); update the system hostname when the network config changes - (hostname_changed): update system hostname if the system settings service signals a hostname change - (nm_policy_new): list for system settings service hostname changes - (nm_policy_destroy): ensure that an in-progress hostname lookup thread gets told to die * system-settings/plugins/keyfile/plugin.c system-settings/plugins/ifcfg-suse/plugin.c - (get_property, sc_plugin_ifcfg_class_init): implement hostname and capabilities properties * system-settings/plugins/ifcfg-fedora/shvar.c - (svOpenFile): re-enable R/W access of ifcfg files since the plugin writes out /etc/sysconfig/network now * system-settings/plugins/ifcfg-fedora/plugin.c - (plugin_get_hostname): get hostname from /etc/sysconfig/network - (plugin_set_hostname): save hostname to /etc/sysconfig/network - (sc_network_changed_cb): handle changes to /etc/sysconfig/network - (sc_plugin_ifcfg_init): monitor /etc/sysconfig/network for changes - (get_property, set_property, sc_plugin_ifcfg_class_init): implement hostname get/set and capabilities get git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4077 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-09-18 15:16:44 +00:00
}
NMIP4Config *
nm_device_get_ip4_config (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->ip4_config;
}
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
static gboolean
nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *new_config,
guint32 default_route_metric,
gboolean commit,
gboolean routes_full_sync,
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
NMDeviceStateReason *reason)
{
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
NMDevicePrivate *priv;
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
NMIP4Config *old_config = NULL;
gboolean has_changes = FALSE;
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
gboolean success = TRUE;
NMDeviceStateReason reason_local = NM_DEVICE_STATE_REASON_NONE;
int ip_ifindex, config_ifindex;
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
ip_ifindex = nm_device_get_ip_ifindex (self);
if (new_config) {
config_ifindex = nm_ip4_config_get_ifindex (new_config);
if (config_ifindex > 0)
g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE);
}
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
old_config = priv->ip4_config;
/* Always commit to nm-platform to update lifetimes */
if (commit && new_config) {
gboolean assumed = nm_device_uses_assumed_connection (self);
nm_device_set_mtu (self, nm_ip4_config_get_mtu (new_config));
route-manager: manage IPv4 device-routes with NMRouteManager When adding an IPv4 address, kernel will also add a device-route. We don't want that route because it has the wrong metric. Instead, we add our own route (with a different metric) and remove the kernel-added one. This could be avoided if kernel would support an IPv4 address flag IFA_F_NOPREFIXROUTE like it does for IPv6 (see related bug rh#1221311). One important thing is, that we want don't want to manage the device-route on assumed devices. Note that this is correct behavior if "assumed" means "do-not-touch". If "assumed" means "seamlessly-takeover", then this is wrong. Imagine we get a new DHCP address. In this case, we would not manage the device-route on the assumed device. This cannot be fixed without splitting unmanaged/assumed with related bug bgo 746440. This is no regression as we would also not manage device-routes for assumed devices previously. We also don't want to remove the device-route if the user added it externally. Note that here we behave wrongly too, because we don't record externally added kernel routes in update_ip_config(). This still needs fixing. Let IPv4 device-routes also be managed by NMRouteManager. NMRouteManager has a list of all routes and can properly add, remove, and restore the device route as needed. One problem is, that the device-route does not get added immediately with the address. It only appears some time later. This is solved by NMRouteManager watching platform and if a matchin device-route shows up within a short time after configuring addresses, remove it. If the route appears after the short timeout, assume they were added for other reasons (e.g. by the user) and don't remove them. https://bugzilla.gnome.org/show_bug.cgi?id=751264 https://bugzilla.redhat.com/show_bug.cgi?id=1211287
2015-06-22 18:21:53 +02:00
/* For assumed devices we must not touch the kernel-routes, such as the device-route.
* FIXME: this is wrong in case where "assumed" means "take-over-seamlessly". In this
* case, we should manage the device route, for example on new DHCP lease. */
success = nm_ip4_config_commit (new_config, ip_ifindex,
routes_full_sync,
route-manager: manage IPv4 device-routes with NMRouteManager When adding an IPv4 address, kernel will also add a device-route. We don't want that route because it has the wrong metric. Instead, we add our own route (with a different metric) and remove the kernel-added one. This could be avoided if kernel would support an IPv4 address flag IFA_F_NOPREFIXROUTE like it does for IPv6 (see related bug rh#1221311). One important thing is, that we want don't want to manage the device-route on assumed devices. Note that this is correct behavior if "assumed" means "do-not-touch". If "assumed" means "seamlessly-takeover", then this is wrong. Imagine we get a new DHCP address. In this case, we would not manage the device-route on the assumed device. This cannot be fixed without splitting unmanaged/assumed with related bug bgo 746440. This is no regression as we would also not manage device-routes for assumed devices previously. We also don't want to remove the device-route if the user added it externally. Note that here we behave wrongly too, because we don't record externally added kernel routes in update_ip_config(). This still needs fixing. Let IPv4 device-routes also be managed by NMRouteManager. NMRouteManager has a list of all routes and can properly add, remove, and restore the device route as needed. One problem is, that the device-route does not get added immediately with the address. It only appears some time later. This is solved by NMRouteManager watching platform and if a matchin device-route shows up within a short time after configuring addresses, remove it. If the route appears after the short timeout, assume they were added for other reasons (e.g. by the user) and don't remove them. https://bugzilla.gnome.org/show_bug.cgi?id=751264 https://bugzilla.redhat.com/show_bug.cgi?id=1211287
2015-06-22 18:21:53 +02:00
assumed ? (gint64) -1 : (gint64) default_route_metric);
if (!success)
reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
}
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
if (new_config) {
if (old_config) {
/* has_changes is set only on relevant changes, because when the configuration changes,
* this causes a re-read and reset. This should only happen for relevant changes */
nm_ip4_config_replace (old_config, new_config, &has_changes);
if (has_changes) {
_LOGD (LOGD_IP4, "update IP4Config instance (%s)",
nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
}
} else {
has_changes = TRUE;
priv->ip4_config = g_object_ref (new_config);
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config)))
nm_exported_object_export (NM_EXPORTED_OBJECT (new_config));
_LOGD (LOGD_IP4, "set IP4Config instance (%s)",
nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config)));
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
}
} else if (old_config) {
has_changes = TRUE;
priv->ip4_config = NULL;
_LOGD (LOGD_IP4, "clear IP4Config instance (%s)",
nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
/* Device config is invalid if combined config is invalid */
g_clear_object (&priv->dev_ip4_config);
2008-11-07 Dan Williams <dcbw@redhat.com> Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-11-07 13:57:39 +00:00
}
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
if (has_changes) {
_update_ip4_address (self);
if (old_config != priv->ip4_config)
g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, old_config);
if (old_config != priv->ip4_config)
nm_exported_object_clear_and_unexport (&old_config);
if (nm_device_uses_generated_assumed_connection (self)) {
NMConnection *connection = nm_device_get_applied_connection (self);
NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self));
NMSetting *s_ip4;
g_object_freeze_notify (G_OBJECT (connection));
g_object_freeze_notify (G_OBJECT (settings_connection));
nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP4_CONFIG);
s_ip4 = nm_ip4_config_create_setting (priv->ip4_config);
nm_connection_add_setting (settings_connection, s_ip4);
nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
s_ip4 = nm_ip4_config_create_setting (priv->ip4_config);
nm_connection_add_setting (connection, s_ip4);
g_object_thaw_notify (G_OBJECT (settings_connection));
g_object_thaw_notify (G_OBJECT (connection));
}
nm_device_queue_recheck_assume (self);
}
if (reason)
*reason = reason_local;
2007-12-06 Tambet Ingo <tambet@gmail.com> * src/NetworkManagerSystem.c * (nm_system_device_set_from_ip4_config): Change the arguments: This whole file shouldn't really know anything about NMDevices, it should deal only with device interfaces. Devices might have different ifaces for different stuff and this place shouldn't know anything about it. * src/NetworkManagerPolicy.c: Get rid of leftover global * variable global_policy. (global_state_changed): Implement. In the current NM it's not really important, but will be required in the case of multiple active devices. (Or even better, if stuff like that gets moved out from NM). * src/vpn-manager/nm-vpn-connection.c * (connection_state_changed): Don't call nm_system_device_set_from_ip4_config() directly, use nm_device_set_ip4_config() instead. * src/nm-device.c: Add a ip_face protected member. It's used for * 'multi-interface' devices like serial devices (ttyS0 and ppp0 for example). (nm_device_get_ip_iface): Implement. Default to the device iface if ip_iface is not set. (nm_device_set_ip_iface): Implement. (nm_device_activate_stage5_ip_config_commit): Move all the extra actions that happen after setting ip4_config from here ... (nm_device_set_ip4_config): ... to here. The reason behind it is that no other code than this function should call nm_system_device_set_from_ip4_config() because no other code has enough information on which arguments to use. So instead, other code could just set the new ip4 config using this function and everyone is happy. * src/nm-umts-device.c: Store the pending ids so that we can * remove pending actions if we happen to get deactivated while something is pending. (automatic_registration): Handle the response that indicates pending network registration and wait until the pending registration is done. (real_deactivate_quickly): If there's a pending operation, cancel it. * src/nm-serial-device.c (ppp_ip4_config): Set the ip_iface when * the iface is up ... (real_deactivate_quickly): ... and remove it when it's down. (nm_serial_device_get_reply): Return the timeout id so that the callers can remove it if needed. (nm_serial_device_wait_for_reply): Ditto. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3141 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-12-06 14:51:43 +00:00
return success;
}
static gboolean
_replace_vpn_config_in_list (GSList **plist, GObject *old, GObject *new)
{
GSList *old_link;
/* Below, assert that we have an @old instance to replace and that
* @new is not yet tracked. But still, behave correctly in any
* case. */
if ( old
&& (old_link = g_slist_find (*plist, old))) {
if (old != new) {
if (new)
old_link->data = g_object_ref (new);
else
*plist = g_slist_remove_link (*plist, old_link);
g_object_unref (old);
}
return TRUE;
}
if (new) {
if (!g_slist_find (*plist, new))
*plist = g_slist_append (*plist, g_object_ref (new));
else
g_return_val_if_reached (TRUE);
g_return_val_if_fail (!old, TRUE);
return TRUE;
}
/* return FALSE if both @old and @new are unset. */
g_return_val_if_fail (!old, FALSE);
return FALSE;
}
void
nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *config)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!_replace_vpn_config_in_list (&priv->vpn4_configs, (GObject *) old, (GObject *) config))
return;
/* NULL to use existing configs */
if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL))
_LOGW (LOGD_IP4, "failed to set VPN routes for device");
}
void
nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->wwan_ip4_config == config)
return;
g_clear_object (&priv->wwan_ip4_config);
if (config)
priv->wwan_ip4_config = g_object_ref (config);
/* NULL to use existing configs */
if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL))
_LOGW (LOGD_IP4, "failed to set WWAN IPv4 configuration");
}
static gboolean
nm_device_set_ip6_config (NMDevice *self,
NMIP6Config *new_config,
gboolean commit,
gboolean routes_full_sync,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv;
NMIP6Config *old_config = NULL;
gboolean has_changes = FALSE;
gboolean success = TRUE;
NMDeviceStateReason reason_local = NM_DEVICE_STATE_REASON_NONE;
int ip_ifindex, config_ifindex;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
ip_ifindex = nm_device_get_ip_ifindex (self);
if (new_config) {
config_ifindex = nm_ip6_config_get_ifindex (new_config);
if (config_ifindex > 0)
g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE);
}
old_config = priv->ip6_config;
/* Always commit to nm-platform to update lifetimes */
if (commit && new_config) {
nm_device_ipv6_set_mtu (self, priv->ip6_mtu);
success = nm_ip6_config_commit (new_config,
ip_ifindex,
routes_full_sync);
if (!success)
reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
}
if (new_config) {
if (old_config) {
/* has_changes is set only on relevant changes, because when the configuration changes,
* this causes a re-read and reset. This should only happen for relevant changes */
nm_ip6_config_replace (old_config, new_config, &has_changes);
if (has_changes) {
_LOGD (LOGD_IP6, "update IP6Config instance (%s)",
nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
}
} else {
has_changes = TRUE;
priv->ip6_config = g_object_ref (new_config);
if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config)))
nm_exported_object_export (NM_EXPORTED_OBJECT (new_config));
_LOGD (LOGD_IP6, "set IP6Config instance (%s)",
nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config)));
}
} else if (old_config) {
has_changes = TRUE;
priv->ip6_config = NULL;
_LOGD (LOGD_IP6, "clear IP6Config instance (%s)",
nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
}
nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
if (has_changes) {
if (old_config != priv->ip6_config)
g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, old_config);
if (old_config != priv->ip6_config)
nm_exported_object_clear_and_unexport (&old_config);
if (nm_device_uses_generated_assumed_connection (self)) {
NMConnection *connection = nm_device_get_applied_connection (self);
NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self));
NMSetting *s_ip6;
g_object_freeze_notify (G_OBJECT (connection));
g_object_freeze_notify (G_OBJECT (settings_connection));
nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP6_CONFIG);
s_ip6 = nm_ip6_config_create_setting (priv->ip6_config);
nm_connection_add_setting (settings_connection, s_ip6);
nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
s_ip6 = nm_ip6_config_create_setting (priv->ip6_config);
nm_connection_add_setting (connection, s_ip6);
g_object_thaw_notify (G_OBJECT (settings_connection));
g_object_thaw_notify (G_OBJECT (connection));
}
nm_device_queue_recheck_assume (self);
}
if (reason)
*reason = reason_local;
return success;
}
void
nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *config)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!_replace_vpn_config_in_list (&priv->vpn6_configs, (GObject *) old, (GObject *) config))
return;
/* NULL to use existing configs */
if (!ip6_config_merge_and_apply (self, TRUE, NULL))
_LOGW (LOGD_IP6, "failed to set VPN routes for device");
}
void
nm_device_set_wwan_ip6_config (NMDevice *self, NMIP6Config *config)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->wwan_ip6_config == config)
return;
g_clear_object (&priv->wwan_ip6_config);
if (config)
priv->wwan_ip6_config = g_object_ref (config);
/* NULL to use existing configs */
if (!ip6_config_merge_and_apply (self, TRUE, NULL))
_LOGW (LOGD_IP6, "failed to set WWAN IPv6 configuration");
}
NMDhcp6Config *
nm_device_get_dhcp6_config (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->dhcp6_config;
}
NMIP6Config *
nm_device_get_ip6_config (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->ip6_config;
}
/****************************************************************/
static void
dispatcher_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->dispatcher.call_id) {
nm_dispatcher_call_cancel (priv->dispatcher.call_id);
priv->dispatcher.call_id = 0;
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
}
}
static void
dispatcher_complete_proceed_state (guint call_id, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (call_id == priv->dispatcher.call_id);
priv->dispatcher.call_id = 0;
nm_device_queue_state (self, priv->dispatcher.post_state,
priv->dispatcher.post_state_reason);
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
}
/****************************************************************/
static void
ip_check_pre_up (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->dispatcher.call_id != 0) {
g_warn_if_reached ();
dispatcher_cleanup (self);
}
priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_UP,
nm_device_get_settings_connection (self),
nm_device_get_applied_connection (self),
self,
dispatcher_complete_proceed_state,
self,
&priv->dispatcher.call_id)) {
/* Just proceed on errors */
dispatcher_complete_proceed_state (0, self);
}
}
static void
ip_check_gw_ping_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
nm_clear_g_source (&priv->gw_ping.watch);
nm_clear_g_source (&priv->gw_ping.timeout);
if (priv->gw_ping.pid) {
nm_utils_kill_child_async (priv->gw_ping.pid, SIGTERM, priv->gw_ping.log_domain, "ping", 1000, NULL, NULL);
priv->gw_ping.pid = 0;
}
g_clear_pointer (&priv->gw_ping.binary, g_free);
g_clear_pointer (&priv->gw_ping.address, g_free);
}
static gboolean
spawn_ping (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_free char *str_timeout = NULL;
gs_free char *tmp_str = NULL;
const char *args[] = { priv->gw_ping.binary, "-I", nm_device_get_ip_iface (self),
"-c", "1", "-w", NULL, priv->gw_ping.address, NULL };
gs_free_error GError *error = NULL;
gboolean ret;
args[6] = str_timeout = g_strdup_printf ("%u", priv->gw_ping.deadline);
tmp_str = g_strjoinv (" ", (gchar **) args);
_LOGD (priv->gw_ping.log_domain, "ping: running '%s'", tmp_str);
ret = g_spawn_async ("/",
(gchar **) args,
NULL,
G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
&priv->gw_ping.pid,
&error);
if (!ret) {
_LOGW (priv->gw_ping.log_domain, "ping: could not spawn %s: %s",
priv->gw_ping.binary, error->message);
}
return ret;
}
static gboolean
respawn_ping_cb (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->gw_ping.watch = 0;
if (spawn_ping (self)) {
priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid,
ip_check_ping_watch_cb, self);
} else {
ip_check_gw_ping_cleanup (self);
ip_check_pre_up (self);
}
return FALSE;
}
static void
ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMLogDomain log_domain = priv->gw_ping.log_domain;
gboolean success = FALSE;
if (!priv->gw_ping.watch)
return;
priv->gw_ping.watch = 0;
priv->gw_ping.pid = 0;
if (WIFEXITED (status)) {
if (WEXITSTATUS (status) == 0) {
_LOGD (log_domain, "ping: gateway ping succeeded");
success = TRUE;
} else {
_LOGW (log_domain, "ping: gateway ping failed with error code %d",
WEXITSTATUS (status));
}
} else
_LOGW (log_domain, "ping: stopped unexpectedly with status %d", status);
if (success) {
/* We've got connectivity, proceed to pre_up */
ip_check_gw_ping_cleanup (self);
ip_check_pre_up (self);
} else {
/* If ping exited with an error it may have returned early,
* wait 1 second and restart it */
priv->gw_ping.watch = g_timeout_add_seconds (1, respawn_ping_cb, self);
}
}
static gboolean
ip_check_ping_timeout_cb (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->gw_ping.timeout = 0;
_LOGW (priv->gw_ping.log_domain, "ping: gateway ping timed out");
ip_check_gw_ping_cleanup (self);
ip_check_pre_up (self);
return FALSE;
}
static gboolean
start_ping (NMDevice *self,
NMLogDomain log_domain,
const char *binary,
const char *address,
guint timeout)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_return_val_if_fail (priv->gw_ping.watch == 0, FALSE);
g_return_val_if_fail (priv->gw_ping.timeout == 0, FALSE);
priv->gw_ping.log_domain = log_domain;
priv->gw_ping.address = g_strdup (address);
priv->gw_ping.binary = g_strdup (binary);
priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */
if (spawn_ping (self)) {
priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid, ip_check_ping_watch_cb, self);
priv->gw_ping.timeout = g_timeout_add_seconds (timeout, ip_check_ping_timeout_cb, self);
return TRUE;
}
ip_check_gw_ping_cleanup (self);
return FALSE;
}
static void
nm_device_start_ip_check (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMSettingConnection *s_con;
guint timeout = 0;
const char *ping_binary = NULL;
char buf[INET6_ADDRSTRLEN] = { 0 };
NMLogDomain log_domain = LOGD_IP4;
/* Shouldn't be any active ping here, since IP_CHECK happens after the
* first IP method completes. Any subsequently completing IP method doesn't
* get checked.
*/
g_assert (!priv->gw_ping.watch);
g_assert (!priv->gw_ping.timeout);
g_assert (!priv->gw_ping.pid);
g_assert (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE);
connection = nm_device_get_applied_connection (self);
g_assert (connection);
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
timeout = nm_setting_connection_get_gateway_ping_timeout (s_con);
if (timeout) {
if (priv->ip4_config && priv->ip4_state == IP_DONE) {
guint gw = 0;
ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL);
log_domain = LOGD_IP4;
gw = nm_ip4_config_get_gateway (priv->ip4_config);
if (gw && !inet_ntop (AF_INET, &gw, buf, sizeof (buf)))
buf[0] = '\0';
} else if (priv->ip6_config && priv->ip6_state == IP_DONE) {
const struct in6_addr *gw = NULL;
ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL);
log_domain = LOGD_IP6;
gw = nm_ip6_config_get_gateway (priv->ip6_config);
if (gw && !inet_ntop (AF_INET6, gw, buf, sizeof (buf)))
buf[0] = '\0';
}
}
if (buf[0])
start_ping (self, log_domain, ping_binary, buf, timeout);
/* If no ping was started, just advance to pre_up */
if (!priv->gw_ping.pid)
ip_check_pre_up (self);
}
/****************************************************************/
static gboolean
carrier_wait_timeout (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0;
nm_device_remove_pending_action (self, "carrier wait", TRUE);
_carrier_wait_check_queued_act_request (self);
return G_SOURCE_REMOVE;
}
static gboolean
nm_device_is_up (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
if (NM_DEVICE_GET_CLASS (self)->is_up)
return NM_DEVICE_GET_CLASS (self)->is_up (self);
return TRUE;
}
static gboolean
is_up (NMDevice *self)
{
int ifindex = nm_device_get_ip_ifindex (self);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return ifindex > 0 ? nm_platform_link_is_up (NM_PLATFORM_GET, ifindex) : TRUE;
}
gboolean
nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean device_is_up = FALSE;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
_LOGD (LOGD_HW, "bringing up device.");
if (NM_DEVICE_GET_CLASS (self)->bring_up) {
if (!NM_DEVICE_GET_CLASS (self)->bring_up (self, no_firmware))
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
return FALSE;
}
device_is_up = nm_device_is_up (self);
if (block && !device_is_up) {
int ifindex = nm_device_get_ip_ifindex (self);
gint64 wait_until = nm_utils_get_monotonic_timestamp_us () + 10000 /* microseconds */;
do {
g_usleep (200);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_refresh (NM_PLATFORM_GET, ifindex))
return FALSE;
device_is_up = nm_device_is_up (self);
} while (!device_is_up && nm_utils_get_monotonic_timestamp_us () < wait_until);
}
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
if (!device_is_up) {
if (block)
_LOGW (LOGD_HW, "device not up after timeout!");
else
_LOGD (LOGD_HW, "device not up immediately");
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
return FALSE;
}
/* Devices that support carrier detect must be IFF_UP to report carrier
* changes; so after setting the device IFF_UP we must suppress startup
* complete (via a pending action) until either the carrier turns on, or
* a timeout is reached.
*/
if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
if (!nm_clear_g_source (&priv->carrier_wait_id))
nm_device_add_pending_action (self, "carrier wait", TRUE);
priv->carrier_wait_id = g_timeout_add_seconds (5, carrier_wait_timeout, self);
}
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
/* Can only get HW address of some devices when they are up */
nm_device_update_hw_address (self);
2007-03-02 Tambet Ingo <tambet@ximian.com> * libnm-glib/nm-device-802-11-wireless.c: Cache networks (bssids) list. We get signalled when it changes. * libnm-glib/nm-client.c: Cache NMState and device list, we get signalled when it changes. * libnm-glib/nm-device.c: Cache the device state property. * libnm-glib/nm-access-point.c: Cache the strength property. * src/nm-device-802-11-wireless.c: Fix wireless device scanning scheduler. The new algorithm is to start from SCAN_INTERVAL_MIN (currently defined as 0) and add a SCAN_INTERVAL_STEP (currently 20 seconds) with each successful scan until SCAN_INTERVAL_MAX (currently 120 seconds) is reached. Do not scan while the device is down, activating, or activated (in case of A/B/G cards). Remove some old dead ifdef'ed out code that used to configure wireless devices, it's all done through supplicant now. * src/supplicant-manager/nm-supplicant-interface.c: Fix the reference counting issues with pending calls which caused leaks and crashes when interface was removed (now that the interface actually gets removed). * src/nm-call-store.c: Make a copy of data before running a foreach with user callback on it - The most common usage pattern is to cancel (and thus remove) all pending calls with foreach which would modify the hash table we're iterating over. * src/nm-manager.c: When a device is added, make sure it is "up". When it's removed or disabled due to disabling wireless or networking, bring it down. * include/NetworkManager.h: Add new device state NM_DEVICE_STATE_DOWN. * src/nm-device-802-11-wireless.c: * src/nm-device-802-3-ethernet.c: * src/nm-device.c: - Remove "init" virtual function, all gobjects have a place for that already (constructor). - Replace "start" virtual function with "bring_up", devices can be brought up and down more than just on startup now. - Add "is_up" virtual function. - Implement one way to bring a device down instead of previous 4 different ways, each of witch did something different. * src/NetworkManagerUtils.c (nm_dev_sock_open): This doesn't need an NMDevice, all it needs is the device interface. Get rid of NMData.dev_list (3 members to go). Get rif of NMData in a lot of places. * gnome/libnm_glib/libnm_glib.c: Make it compile again. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2395 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-03-02 09:30:48 +00:00
_update_ip4_address (self);
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
return TRUE;
}
static gboolean
bring_up (NMDevice *self, gboolean *no_firmware)
{
int ifindex = nm_device_get_ip_ifindex (self);
gboolean result;
if (ifindex <= 0) {
if (no_firmware)
*no_firmware = FALSE;
return TRUE;
}
result = nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, no_firmware);
/* Store carrier immediately. */
if (result && nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT))
check_carrier (self);
return result;
}
void
nm_device_take_down (NMDevice *self, gboolean block)
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
{
gboolean device_is_up;
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
g_return_if_fail (NM_IS_DEVICE (self));
_LOGD (LOGD_HW, "taking down device.");
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
if (NM_DEVICE_GET_CLASS (self)->take_down) {
if (!NM_DEVICE_GET_CLASS (self)->take_down (self))
return;
}
device_is_up = nm_device_is_up (self);
if (block && device_is_up) {
int ifindex = nm_device_get_ip_ifindex (self);
gint64 wait_until = nm_utils_get_monotonic_timestamp_us () + 10000 /* microseconds */;
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
do {
g_usleep (200);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
if (!nm_platform_link_refresh (NM_PLATFORM_GET, ifindex))
return;
device_is_up = nm_device_is_up (self);
} while (device_is_up && nm_utils_get_monotonic_timestamp_us () < wait_until);
}
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
if (device_is_up) {
if (block)
_LOGW (LOGD_HW, "device not down after timeout!");
else
_LOGD (LOGD_HW, "device not down immediately");
}
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
}
static gboolean
take_down (NMDevice *self)
{
int ifindex = nm_device_get_ip_ifindex (self);
if (ifindex > 0)
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return nm_platform_link_set_down (NM_PLATFORM_GET, ifindex);
/* devices without ifindex are always up. */
_LOGD (LOGD_HW, "cannot take down device without ifindex");
return FALSE;
}
void
nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->firmware_missing != new_missing) {
priv->firmware_missing = new_missing;
g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_MISSING);
}
}
gboolean
nm_device_get_firmware_missing (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->firmware_missing;
}
void
nm_device_set_nm_plugin_missing (NMDevice *self, gboolean new_missing)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->nm_plugin_missing != new_missing) {
priv->nm_plugin_missing = new_missing;
g_object_notify (G_OBJECT (self), NM_DEVICE_NM_PLUGIN_MISSING);
}
}
gboolean
nm_device_get_nm_plugin_missing (NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE (self)->nm_plugin_missing;
}
static NMIP4Config *
find_ip4_lease_config (NMDevice *self,
NMConnection *connection,
NMIP4Config *ext_ip4_config)
{
const char *ip_iface = nm_device_get_ip_iface (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
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 (nm_dhcp_manager_get (),
ip_iface,
ip_ifindex,
nm_connection_get_uuid (connection),
FALSE,
nm_device_get_ip4_route_metric (self));
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);
2012-11-14 14:05:30 -06:00
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
capture_lease_config (NMDevice *self,
NMIP4Config *ext_ip4_config,
NMIP4Config **out_ip4_config,
NMIP6Config *ext_ip6_config,
NMIP6Config **out_ip6_config)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
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));
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
}
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 (self, candidate))
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 (self, 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
_ip4_config_intersect (gpointer value, gpointer user_data)
{
NMIP4Config *dst = (NMIP4Config *) value;
NMIP4Config *src = (NMIP4Config *) user_data;
nm_ip4_config_intersect (dst, src);
}
static void
_ip4_config_subtract (gpointer value, gpointer user_data)
{
NMIP4Config *dst = (NMIP4Config *) user_data;
NMIP4Config *src = (NMIP4Config *) value;
nm_ip4_config_subtract (dst, src);
}
static void
update_ip4_config (NMDevice *self, gboolean initial)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex;
gboolean capture_resolv_conf;
NMDnsManagerResolvConfMode resolv_conf_mode;
ifindex = nm_device_get_ip_ifindex (self);
if (!ifindex)
return;
resolv_conf_mode = nm_dns_manager_get_resolv_conf_mode (nm_dns_manager_get ());
capture_resolv_conf = initial && (resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT);
/* IPv4 */
g_clear_object (&priv->ext_ip4_config);
priv->ext_ip4_config = nm_ip4_config_capture (ifindex, capture_resolv_conf);
if (priv->ext_ip4_config) {
if (initial) {
g_clear_object (&priv->dev_ip4_config);
capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL);
}
route-manager: manage IPv4 device-routes with NMRouteManager When adding an IPv4 address, kernel will also add a device-route. We don't want that route because it has the wrong metric. Instead, we add our own route (with a different metric) and remove the kernel-added one. This could be avoided if kernel would support an IPv4 address flag IFA_F_NOPREFIXROUTE like it does for IPv6 (see related bug rh#1221311). One important thing is, that we want don't want to manage the device-route on assumed devices. Note that this is correct behavior if "assumed" means "do-not-touch". If "assumed" means "seamlessly-takeover", then this is wrong. Imagine we get a new DHCP address. In this case, we would not manage the device-route on the assumed device. This cannot be fixed without splitting unmanaged/assumed with related bug bgo 746440. This is no regression as we would also not manage device-routes for assumed devices previously. We also don't want to remove the device-route if the user added it externally. Note that here we behave wrongly too, because we don't record externally added kernel routes in update_ip_config(). This still needs fixing. Let IPv4 device-routes also be managed by NMRouteManager. NMRouteManager has a list of all routes and can properly add, remove, and restore the device route as needed. One problem is, that the device-route does not get added immediately with the address. It only appears some time later. This is solved by NMRouteManager watching platform and if a matchin device-route shows up within a short time after configuring addresses, remove it. If the route appears after the short timeout, assume they were added for other reasons (e.g. by the user) and don't remove them. https://bugzilla.gnome.org/show_bug.cgi?id=751264 https://bugzilla.redhat.com/show_bug.cgi?id=1211287
2015-06-22 18:21:53 +02:00
/* FIXME: ext_ip4_config does not contain routes with source==RTPROT_KERNEL.
* Hence, we will wrongly remove device-routes with metric=0 if they were added by
* the user on purpose. This should be fixed by also tracking and exposing
* kernel routes. */
/* This function was called upon external changes. Remove the configuration
* (addresses,routes) that is no longer present externally from the internal
2015-04-20 11:27:49 +02:00
* config. This way, we don't re-add addresses that were manually removed
* by the user. */
if (priv->con_ip4_config)
nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config);
if (priv->dev_ip4_config)
nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config);
g_slist_foreach (priv->vpn4_configs, _ip4_config_intersect, priv->ext_ip4_config);
if (priv->wwan_ip4_config)
nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config);
/* Remove parts from ext_ip4_config to only contain the information that
* was configured externally -- we already have the same configuration from
* internal origins. */
if (priv->con_ip4_config)
nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config);
if (priv->dev_ip4_config)
nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config);
g_slist_foreach (priv->vpn4_configs, _ip4_config_subtract, priv->ext_ip4_config);
if (priv->wwan_ip4_config)
nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config);
ip4_config_merge_and_apply (self, NULL, FALSE, NULL);
}
}
static void
_ip6_config_intersect (gpointer value, gpointer user_data)
{
NMIP6Config *dst = (NMIP6Config *) value;
NMIP6Config *src = (NMIP6Config *) user_data;
nm_ip6_config_intersect (dst, src);
}
static void
_ip6_config_subtract (gpointer value, gpointer user_data)
{
NMIP6Config *dst = (NMIP6Config *) user_data;
NMIP6Config *src = (NMIP6Config *) value;
nm_ip6_config_subtract (dst, src);
}
static void
update_ip6_config (NMDevice *self, gboolean initial)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex;
gboolean linklocal6_just_completed = FALSE;
gboolean capture_resolv_conf;
NMDnsManagerResolvConfMode resolv_conf_mode;
ifindex = nm_device_get_ip_ifindex (self);
if (!ifindex)
return;
resolv_conf_mode = nm_dns_manager_get_resolv_conf_mode (nm_dns_manager_get ());
capture_resolv_conf = initial && (resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT);
/* IPv6 */
g_clear_object (&priv->ext_ip6_config);
priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
if (priv->ext_ip6_config) {
/* Check this before modifying ext_ip6_config */
linklocal6_just_completed = priv->linklocal6_timeout_id &&
have_ip6_address (priv->ext_ip6_config, TRUE);
/* This function was called upon external changes. Remove the configuration
* (addresses,routes) that is no longer present externally from the internal
2015-04-20 11:27:49 +02:00
* config. This way, we don't re-add addresses that were manually removed
* by the user. */
if (priv->con_ip6_config)
nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config);
if (priv->ac_ip6_config)
nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config);
if (priv->dhcp6_ip6_config)
nm_ip6_config_intersect (priv->dhcp6_ip6_config, priv->ext_ip6_config);
if (priv->wwan_ip6_config)
nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config);
g_slist_foreach (priv->vpn6_configs, _ip6_config_intersect, priv->ext_ip6_config);
/* Remove parts from ext_ip6_config to only contain the information that
* was configured externally -- we already have the same configuration from
* internal origins. */
if (priv->con_ip6_config)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config);
if (priv->ac_ip6_config)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config);
if (priv->dhcp6_ip6_config)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6_ip6_config);
if (priv->wwan_ip6_config)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config);
g_slist_foreach (priv->vpn6_configs, _ip6_config_subtract, priv->ext_ip6_config);
ip6_config_merge_and_apply (self, FALSE, NULL);
}
if (linklocal6_just_completed) {
/* linklocal6 is ready now, do the state transition... we are also
* invoked as g_idle_add, so no problems with reentrance doing it now.
*/
linklocal6_complete (self);
}
}
void
nm_device_capture_initial_config (NMDevice *self)
{
update_ip4_config (self, TRUE);
update_ip6_config (self, TRUE);
}
static gboolean
queued_ip4_config_change (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* Wait for any queued state changes */
if (priv->queued_state.id)
return TRUE;
priv->queued_ip4_config_id = 0;
g_object_ref (self);
update_ip4_config (self, FALSE);
g_object_unref (self);
return FALSE;
}
static gboolean
queued_ip6_config_change (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
2009-07-07 14:34:01 -04:00
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GSList *iter;
gboolean need_ipv6ll = FALSE;
/* Wait for any queued state changes */
if (priv->queued_state.id)
return TRUE;
priv->queued_ip6_config_id = 0;
device: make sure NMDevice doesn't vanish halfway through applying configuration It could be that the device was removed and the default route manager holds the last reference: Breakpoint 1, dispose (object=0x90e710 [NMDeviceTun]) at devices/nm-device.c:8588 8588 NMDevice *self = NM_DEVICE (object); (gdb) bt #0 0x000000000045d24e in dispose (object=0x90e710 [NMDeviceTun]) at devices/nm-device.c:8588 #1 0x00007ffff4d29b7c in g_object_unref (_object=0x90e710) at gobject.c:3133 #2 0x00000000004b0a61 in _entry_at_idx_remove (entry=<optimized out>) at nm-default-route-manager.c:192 #3 0x00000000004b0a61 in _entry_at_idx_remove (vtable=<optimized out>, self=<optimized out>, entry_idx=<optimized out>) at nm-default-route-manager.c:638 #4 0x00000000004adb51 in _ipx_update_default_route (vtable=0x7b1850 <vtable_ip6>, self=0x7da610 [NMDefaultRouteManager], source=<optimized out>) at nm-default-route-manager.c:814 #5 0x0000000000459ccb in nm_device_set_ip6_config (self=0x90e710 [NMDeviceTun], new_config=<optimized out>, commit=<optimized out>, reason=<optimized out>) at devices/nm-device.c:6213 #6 0x0000000000450c92 in ip6_config_merge_and_apply (self=0x90e710 [NMDeviceTun], commit=0, out_reason=0x0) at devices/nm-device.c:3670 #7 0x0000000000452d06 in update_ip_config (self=0x90e710 [NMDeviceTun], initial=<optimized out>) at devices/nm-device.c:6915 #8 0x000000000046253e in queued_ip_config_change (user_data=<optimized out>) at devices/nm-device.c:6945 #9 0x00007ffff4a257fb in g_main_context_dispatch (context=0x7ca3e0) at gmain.c:3111 #10 0x00007ffff4a257fb in g_main_context_dispatch (context=context@entry=0x7ca3e0) at gmain.c:3710 #11 0x00007ffff4a25b98 in g_main_context_iterate (context=0x7ca3e0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3781 #12 0x00007ffff4a25ec2 in g_main_loop_run (loop=0x7ca4a0) at gmain.c:3975 #13 0x0000000000444bbe in main (argc=<optimized out>, argv=<optimized out>) at main.c:486 (gdb) Program received signal SIGTRAP, Trace/breakpoint trap. g_logv (log_domain=0x7ffff4d4f164 "GLib-GObject", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fffffffd5b0) at gmessages.c:1046 1046 g_private_set (&g_log_depth, GUINT_TO_POINTER (depth)); (gdb) bt #0 0x00007ffff4a2c970 in g_logv (log_domain=0x7ffff4d4f164 "GLib-GObject", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fffffffd5b0) at gmessages.c:1046 #1 0x00007ffff4a2cbaf in g_log (log_domain=log_domain@entry=0x7ffff4d4f164 "GLib-GObject", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x7ffff4d563b0 "invalid unclassed pointer in cast to '%s'") at gmessages.c:1079 #2 0x00007ffff4d481f9 in g_type_check_instance_cast (type_instance=0x90e710, iface_type=<optimized out>) at gtype.c:4030 #3 0x0000000000459ceb in nm_device_set_ip6_config (self=0x90e710, new_config=<optimized out>, commit=<optimized out>, reason=0x0) at devices/nm-device.c:6217 #4 0x0000000000450c92 in ip6_config_merge_and_apply (self=0x90e710, commit=0, out_reason=0x0) at devices/nm-device.c:3670 #5 0x0000000000452d06 in update_ip_config (self=0x90e710, initial=<optimized out>) at devices/nm-device.c:6915 #6 0x000000000046253e in queued_ip_config_change (user_data=<optimized out>) at devices/nm-device.c:6945 #7 0x00007ffff4a257fb in g_main_context_dispatch (context=0x7ca3e0) at gmain.c:3111 #8 0x00007ffff4a257fb in g_main_context_dispatch (context=context@entry=0x7ca3e0) at gmain.c:3710 #9 0x00007ffff4a25b98 in g_main_context_iterate (context=0x7ca3e0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3781 #10 0x00007ffff4a25ec2 in g_main_loop_run (loop=0x7ca4a0) at gmain.c:3975 #11 0x0000000000444bbe in main (argc=<optimized out>, argv=<optimized out>) at main.c:486 (gdb) https://bugzilla.gnome.org/show_bug.cgi?id=748193
2015-04-20 16:45:43 +02:00
g_object_ref (self);
update_ip6_config (self, FALSE);
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
if ( priv->state > NM_DEVICE_STATE_DISCONNECTED
&& priv->state < NM_DEVICE_STATE_DEACTIVATING) {
/* Handle DAD falures */
for (iter = priv->dad6_failed_addrs; iter; iter = g_slist_next (iter)) {
NMPlatformIP6Address *addr = iter->data;
if (addr->source >= NM_IP_CONFIG_SOURCE_USER)
continue;
_LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address",
nm_platform_ip6_address_to_string (addr, NULL, 0));
if (IN6_IS_ADDR_LINKLOCAL (&addr->address))
need_ipv6ll = TRUE;
else if (priv->rdisc)
nm_rdisc_dad_failed (priv->rdisc, &addr->address);
}
/* If no IPv6 link-local address exists but other addresses do then we
* must add the LL address to remain conformant with RFC 3513 chapter 2.1
* ("Addressing Model"): "All interfaces are required to have at least
* one link-local unicast address".
*/
if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config))
need_ipv6ll = TRUE;
if (need_ipv6ll)
check_and_add_ipv6ll_addr (self);
}
g_slist_free_full (priv->dad6_failed_addrs, g_free);
priv->dad6_failed_addrs = NULL;
device: make sure NMDevice doesn't vanish halfway through applying configuration It could be that the device was removed and the default route manager holds the last reference: Breakpoint 1, dispose (object=0x90e710 [NMDeviceTun]) at devices/nm-device.c:8588 8588 NMDevice *self = NM_DEVICE (object); (gdb) bt #0 0x000000000045d24e in dispose (object=0x90e710 [NMDeviceTun]) at devices/nm-device.c:8588 #1 0x00007ffff4d29b7c in g_object_unref (_object=0x90e710) at gobject.c:3133 #2 0x00000000004b0a61 in _entry_at_idx_remove (entry=<optimized out>) at nm-default-route-manager.c:192 #3 0x00000000004b0a61 in _entry_at_idx_remove (vtable=<optimized out>, self=<optimized out>, entry_idx=<optimized out>) at nm-default-route-manager.c:638 #4 0x00000000004adb51 in _ipx_update_default_route (vtable=0x7b1850 <vtable_ip6>, self=0x7da610 [NMDefaultRouteManager], source=<optimized out>) at nm-default-route-manager.c:814 #5 0x0000000000459ccb in nm_device_set_ip6_config (self=0x90e710 [NMDeviceTun], new_config=<optimized out>, commit=<optimized out>, reason=<optimized out>) at devices/nm-device.c:6213 #6 0x0000000000450c92 in ip6_config_merge_and_apply (self=0x90e710 [NMDeviceTun], commit=0, out_reason=0x0) at devices/nm-device.c:3670 #7 0x0000000000452d06 in update_ip_config (self=0x90e710 [NMDeviceTun], initial=<optimized out>) at devices/nm-device.c:6915 #8 0x000000000046253e in queued_ip_config_change (user_data=<optimized out>) at devices/nm-device.c:6945 #9 0x00007ffff4a257fb in g_main_context_dispatch (context=0x7ca3e0) at gmain.c:3111 #10 0x00007ffff4a257fb in g_main_context_dispatch (context=context@entry=0x7ca3e0) at gmain.c:3710 #11 0x00007ffff4a25b98 in g_main_context_iterate (context=0x7ca3e0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3781 #12 0x00007ffff4a25ec2 in g_main_loop_run (loop=0x7ca4a0) at gmain.c:3975 #13 0x0000000000444bbe in main (argc=<optimized out>, argv=<optimized out>) at main.c:486 (gdb) Program received signal SIGTRAP, Trace/breakpoint trap. g_logv (log_domain=0x7ffff4d4f164 "GLib-GObject", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fffffffd5b0) at gmessages.c:1046 1046 g_private_set (&g_log_depth, GUINT_TO_POINTER (depth)); (gdb) bt #0 0x00007ffff4a2c970 in g_logv (log_domain=0x7ffff4d4f164 "GLib-GObject", log_level=G_LOG_LEVEL_WARNING, format=<optimized out>, args=args@entry=0x7fffffffd5b0) at gmessages.c:1046 #1 0x00007ffff4a2cbaf in g_log (log_domain=log_domain@entry=0x7ffff4d4f164 "GLib-GObject", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x7ffff4d563b0 "invalid unclassed pointer in cast to '%s'") at gmessages.c:1079 #2 0x00007ffff4d481f9 in g_type_check_instance_cast (type_instance=0x90e710, iface_type=<optimized out>) at gtype.c:4030 #3 0x0000000000459ceb in nm_device_set_ip6_config (self=0x90e710, new_config=<optimized out>, commit=<optimized out>, reason=0x0) at devices/nm-device.c:6217 #4 0x0000000000450c92 in ip6_config_merge_and_apply (self=0x90e710, commit=0, out_reason=0x0) at devices/nm-device.c:3670 #5 0x0000000000452d06 in update_ip_config (self=0x90e710, initial=<optimized out>) at devices/nm-device.c:6915 #6 0x000000000046253e in queued_ip_config_change (user_data=<optimized out>) at devices/nm-device.c:6945 #7 0x00007ffff4a257fb in g_main_context_dispatch (context=0x7ca3e0) at gmain.c:3111 #8 0x00007ffff4a257fb in g_main_context_dispatch (context=context@entry=0x7ca3e0) at gmain.c:3710 #9 0x00007ffff4a25b98 in g_main_context_iterate (context=0x7ca3e0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3781 #10 0x00007ffff4a25ec2 in g_main_loop_run (loop=0x7ca4a0) at gmain.c:3975 #11 0x0000000000444bbe in main (argc=<optimized out>, argv=<optimized out>) at main.c:486 (gdb) https://bugzilla.gnome.org/show_bug.cgi?id=748193
2015-04-20 16:45:43 +02:00
g_object_unref (self);
return FALSE;
}
static void
device_ipx_changed (NMPlatform *platform,
NMPObjectType obj_type,
int ifindex,
gpointer platform_object,
NMPlatformSignalChangeType change_type,
NMDevice *self)
{
NMDevicePrivate *priv;
NMPlatformIP6Address *addr;
if (nm_device_get_ip_ifindex (self) != ifindex)
return;
priv = NM_DEVICE_GET_PRIVATE (self);
switch (obj_type) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
case NMP_OBJECT_TYPE_IP4_ROUTE:
if (!priv->queued_ip4_config_id) {
priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self);
_LOGD (LOGD_DEVICE, "queued IP4 config change");
}
break;
case NMP_OBJECT_TYPE_IP6_ADDRESS:
addr = platform_object;
if ( priv->state > NM_DEVICE_STATE_DISCONNECTED
&& priv->state < NM_DEVICE_STATE_DEACTIVATING
&& ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->flags & IFA_F_DADFAILED)
|| (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->flags & IFA_F_TENTATIVE))) {
priv->dad6_failed_addrs = g_slist_append (priv->dad6_failed_addrs,
g_memdup (addr, sizeof (NMPlatformIP6Address)));
}
/* fallthrough */
case NMP_OBJECT_TYPE_IP6_ROUTE:
if (!priv->queued_ip6_config_id) {
priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
_LOGD (LOGD_DEVICE, "queued IP6 config change");
}
break;
default:
g_return_if_reached ();
}
}
/**
* nm_device_get_managed():
* @self: the #NMDevice
*
* Returns: %TRUE if the device is managed
*/
gboolean
nm_device_get_managed (NMDevice *self)
{
NMDevicePrivate *priv;
gboolean managed;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
/* Return the composite of all managed flags. However, if the device
* is a default-unmanaged device, and would be managed except for the
* default-unmanaged flag (eg, only NM_UNMANAGED_DEFAULT is set) then
* the device is managed whenever it's not in the UNMANAGED state.
*/
managed = !NM_FLAGS_ANY (priv->unmanaged_flags, ~NM_UNMANAGED_DEFAULT);
if (managed && NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_DEFAULT))
managed = (priv->state > NM_DEVICE_STATE_UNMANAGED);
return managed;
}
/**
2015-11-05 02:32:53 +01:00
* nm_device_get_unmanaged_flags():
* @self: the #NMDevice
* @flag: return only the selected flags
*
* Returns: the unmanage flags of the device (filtered with @flag)
*/
NMUnmanagedFlags
2015-11-05 02:32:53 +01:00
nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag)
{
return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag;
}
/**
* nm_device_get_default_unmanaged():
* @self: the #NMDevice
*
* Returns: %TRUE if the device is by default unmanaged
*/
static gboolean
nm_device_get_default_unmanaged (NMDevice *self)
{
return !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_DEFAULT);
}
static void
_set_unmanaged_flags (NMDevice *self,
NMUnmanagedFlags flags,
gboolean unmanaged)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (unmanaged) {
if (!NM_FLAGS_ALL (priv->unmanaged_flags, flags)) {
_LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)",
(long long unsigned) (priv->unmanaged_flags | flags),
(long long unsigned) priv->unmanaged_flags,
"set",
(long long unsigned) flags);
priv->unmanaged_flags |= flags;
}
} else {
if (NM_FLAGS_ANY (priv->unmanaged_flags, flags)) {
_LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)",
(long long unsigned) (priv->unmanaged_flags & (~flags)),
(long long unsigned) priv->unmanaged_flags,
"clear",
(long long unsigned) flags);
priv->unmanaged_flags &= ~flags;
}
}
}
void
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (NMDevice *self,
NMUnmanagedFlags flag,
gboolean unmanaged,
NMDeviceStateReason reason)
{
NMDevicePrivate *priv;
gboolean was_managed, now_managed;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (flag <= NM_UNMANAGED_LAST);
priv = NM_DEVICE_GET_PRIVATE (self);
was_managed = nm_device_get_managed (self);
_set_unmanaged_flags (self, flag, unmanaged);
now_managed = nm_device_get_managed (self);
if (was_managed != now_managed) {
_LOGD (LOGD_DEVICE, "now %s", unmanaged ? "unmanaged" : "managed");
g_object_notify (G_OBJECT (self), NM_DEVICE_MANAGED);
if (unmanaged)
nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason);
else if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason);
}
}
void
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs)
{
NMDevicePrivate *priv;
gboolean unmanaged;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->managed_touched_by_user)
return;
unmanaged = nm_device_spec_match_list (self, unmanaged_specs);
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_USER,
unmanaged,
unmanaged
? NM_DEVICE_STATE_REASON_NOW_UNMANAGED
: NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
/**
2015-11-05 02:32:53 +01:00
* nm_device_set_unmanaged_flags_initial():
* @self: the #NMDevice
* @flag: an #NMUnmanagedFlag
* @unmanaged: %TRUE or %FALSE to set or clear @flag
*
2015-11-05 02:32:53 +01:00
* Like nm_device_set_unmanaged_flags(), but must be set before the device is
* initialized by nm_device_finish_init(), and does not trigger state changes.
* Should only be used when initializing a device.
*/
void
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags_initial (NMDevice *self,
NMUnmanagedFlags flag,
gboolean unmanaged)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (flag <= NM_UNMANAGED_LAST);
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->initialized == FALSE);
_set_unmanaged_flags (self, flag, unmanaged);
}
2015-11-05 02:28:34 +01:00
void
nm_device_set_unmanaged_quitting (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* It's OK to block here because we're quitting */
if (nm_device_is_activating (self) || priv->state == NM_DEVICE_STATE_ACTIVATED)
_set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE);
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_INTERNAL,
TRUE,
NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
2015-11-05 02:28:34 +01:00
}
/*****************************************************************************/
void
nm_device_set_dhcp_timeout (NMDevice *self, guint32 timeout)
{
g_return_if_fail (NM_IS_DEVICE (self));
NM_DEVICE_GET_PRIVATE (self)->dhcp_timeout = timeout;
}
void
nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (!addr || nm_utils_hwaddr_valid (addr, ETH_ALEN));
priv = NM_DEVICE_GET_PRIVATE (self);
g_free (priv->dhcp_anycast_address);
priv->dhcp_anycast_address = g_strdup (addr);
}
void
nm_device_reapply_settings_immediately (NMDevice *self)
{
NMConnection *applied_connection;
NMSettingsConnection *settings_connection;
NMDeviceState state;
NMSettingConnection *s_con_settings;
NMSettingConnection *s_con_applied;
const char *zone;
NMMetered metered;
g_return_if_fail (NM_IS_DEVICE (self));
state = nm_device_get_state (self);
if ( state <= NM_DEVICE_STATE_DISCONNECTED
|| state > NM_DEVICE_STATE_ACTIVATED)
return;
applied_connection = nm_device_get_applied_connection (self);
settings_connection = nm_device_get_settings_connection (self);
if (!nm_settings_connection_has_unmodified_applied_connection (settings_connection,
applied_connection,
NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY))
return;
s_con_settings = nm_connection_get_setting_connection ((NMConnection *) settings_connection);
s_con_applied = nm_connection_get_setting_connection (applied_connection);
if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)),
nm_setting_connection_get_zone (s_con_applied)) != 0) {
_LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s", NM_PRINT_FMT_QUOTE_STRING (zone));
g_object_set (G_OBJECT (s_con_applied),
NM_SETTING_CONNECTION_ZONE, zone,
NULL);
nm_device_update_firewall_zone (self);
}
if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) {
_LOGD (LOGD_DEVICE, "reapply setting: metered = %d", (int) metered);
g_object_set (G_OBJECT (s_con_applied),
NM_SETTING_CONNECTION_METERED, metered,
NULL);
nm_device_update_metered (self);
}
}
void
nm_device_update_firewall_zone (NMDevice *self)
{
NMConnection *applied_connection;
NMSettingConnection *s_con;
g_return_if_fail (NM_IS_DEVICE (self));
applied_connection = nm_device_get_applied_connection (self);
if (!applied_connection)
return;
s_con = nm_connection_get_setting_connection (applied_connection);
if ( nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED
&& !nm_device_uses_assumed_connection (self)) {
nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (),
nm_device_get_ip_iface (self),
nm_setting_connection_get_zone (s_con),
FALSE, /* change zone */
NULL,
NULL);
}
}
void
nm_device_update_metered (NMDevice *self)
{
#define NM_METERED_INVALID ((NMMetered) -1)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingConnection *setting;
NMMetered conn_value, value = NM_METERED_INVALID;
NMConnection *connection = NULL;
NMDeviceState state;
g_return_if_fail (NM_IS_DEVICE (self));
state = nm_device_get_state (self);
if ( state <= NM_DEVICE_STATE_DISCONNECTED
|| state > NM_DEVICE_STATE_ACTIVATED)
value = NM_METERED_UNKNOWN;
if (value == NM_METERED_INVALID) {
connection = nm_device_get_applied_connection (self);
if (connection) {
setting = nm_connection_get_setting_connection (connection);
if (setting) {
conn_value = nm_setting_connection_get_metered (setting);
if (conn_value != NM_METERED_UNKNOWN)
value = conn_value;
}
}
}
/* Try to guess a value using the metered flag in IP configuration */
if (value == NM_METERED_INVALID) {
if ( priv->ip4_config
&& priv->ip4_state == IP_DONE
&& nm_ip4_config_get_metered (priv->ip4_config))
value = NM_METERED_GUESS_YES;
}
/* Otherwise look at connection type */
if (value == NM_METERED_INVALID) {
if ( nm_connection_is_type (connection, NM_SETTING_GSM_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_CDMA_SETTING_NAME))
value = NM_METERED_GUESS_YES;
else
value = NM_METERED_GUESS_NO;
}
if (value != priv->metered) {
_LOGD (LOGD_DEVICE, "set metered value %d", value);
priv->metered = value;
g_object_notify (G_OBJECT (self), NM_DEVICE_METERED);
}
}
static gboolean
_nm_device_check_connection_available (NMDevice *self,
NMConnection *connection,
NMDeviceCheckConAvailableFlags flags,
const char *specific_object)
{
NMDeviceState state;
state = nm_device_get_state (self);
if (state < NM_DEVICE_STATE_UNMANAGED)
return FALSE;
if ( state < NM_DEVICE_STATE_UNAVAILABLE
2015-11-05 02:32:53 +01:00
&& nm_device_get_unmanaged_flags (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
return FALSE;
if ( state < NM_DEVICE_STATE_DISCONNECTED
&& !nm_device_is_software (self)
&& ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
|| ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER))))
return FALSE;
if (!nm_device_check_connection_compatible (self, connection))
return FALSE;
return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object);
}
/**
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
* nm_device_check_connection_available():
* @self: the #NMDevice
* @connection: the #NMConnection to check for availability
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
* @flags: flags to affect the decision making of whether a connection
* is available. Adding a flag can only make a connection more available,
* not less.
* @specific_object: a device type dependent argument to further
* filter the result. Passing a non %NULL specific object can only reduce
* the availability of a connection.
*
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
* Check if @connection is available to be activated on @self.
*
* Returns: %TRUE if @connection can be activated on @self
*/
gboolean
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
nm_device_check_connection_available (NMDevice *self,
NMConnection *connection,
NMDeviceCheckConAvailableFlags flags,
const char *specific_object)
{
gboolean available;
available = _nm_device_check_connection_available (self, connection, flags, specific_object);
#if NM_MORE_ASSERTS >= 2
{
/* The meaning of the flags is so that *adding* a flag relaxes a condition, thus making
* the device *more* available. Assert against that requirement by testing all the flags. */
NMDeviceCheckConAvailableFlags i, j, k;
gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = { FALSE };
for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++)
available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object);
for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) {
for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) {
if (NM_FLAGS_HAS (i, j)) {
k = i & ~j;
nm_assert ( available_all[i] == available_all[k]
|| available_all[i]);
}
}
}
}
#endif
return available;
}
static void
_signal_available_connections_changed (NMDevice *self)
{
g_object_notify (G_OBJECT (self), NM_DEVICE_AVAILABLE_CONNECTIONS);
}
static void
_clear_available_connections (NMDevice *self, gboolean do_signal)
{
g_hash_table_remove_all (NM_DEVICE_GET_PRIVATE (self)->available_connections);
if (do_signal == TRUE)
_signal_available_connections_changed (self);
}
static gboolean
_try_add_available_connection (NMDevice *self, NMConnection *connection)
{
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) {
g_hash_table_add (NM_DEVICE_GET_PRIVATE (self)->available_connections,
g_object_ref (connection));
return TRUE;
}
return FALSE;
}
static gboolean
_del_available_connection (NMDevice *self, NMConnection *connection)
{
return g_hash_table_remove (NM_DEVICE_GET_PRIVATE (self)->available_connections, connection);
}
static gboolean
check_connection_available (NMDevice *self,
NMConnection *connection,
NMDeviceCheckConAvailableFlags flags,
const char *specific_object)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
/* Connections which require a network connection are not available when
* the device has no carrier, even with ignore-carrer=TRUE.
*/
if ( priv->carrier
|| !connection_requires_carrier (connection))
return TRUE;
if ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& priv->carrier_wait_id != 0) {
/* The device has no carrier though the connection requires it.
*
* If we are still waiting for carrier, the connection is available
* for an explicit user-request. */
return TRUE;
}
return FALSE;
}
void
nm_device_recheck_available_connections (NMDevice *self)
{
NMDevicePrivate *priv;
const GSList *connections, *iter;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE(self);
if (priv->con_provider) {
_clear_available_connections (self, FALSE);
connections = nm_connection_provider_get_connections (priv->con_provider);
for (iter = connections; iter; iter = g_slist_next (iter))
_try_add_available_connection (self, NM_CONNECTION (iter->data));
_signal_available_connections_changed (self);
}
}
/**
* nm_device_get_available_connections:
* @self: the #NMDevice
* @specific_object: a specific object path if any
*
* Returns a list of connections available to activate on the device, taking
* into account any device-specific details given by @specific_object (like
* WiFi access point path).
*
* Returns: caller-owned #GPtrArray of #NMConnections
*/
GPtrArray *
nm_device_get_available_connections (NMDevice *self, const char *specific_object)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GHashTableIter iter;
guint num_available;
NMConnection *connection = NULL;
GPtrArray *array = NULL;
num_available = g_hash_table_size (priv->available_connections);
if (num_available > 0) {
array = g_ptr_array_sized_new (num_available);
g_hash_table_iter_init (&iter, priv->available_connections);
while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) {
/* If a specific object is given, only include connections that are
* compatible with it.
*/
device: eliminate direct calls to check_connection_available() in favor of nm_device_check_connection_available() It was confusing to understand the difference between calling nm_device_connection_is_available() and check_connection_available(), they behaved similar, but not really the same. Especially nm_device_connection_is_available() would look first into @available_connetions, and might call check_connection_available() itself. Whereas @available_connetions was also populated by testing check_connection_available(). This interrelation makes it hard to understand when nm_device_connection_is_available() returned true. Rename nm_device_connection_is_available() to nm_device_check_connection_available() and remove all direct calls of check_connection_available() in favor of the wrapper nm_device_check_connection_available(). Now we only call nm_device_check_connection_available() with different parameters (@flags and @specific_object). We also have the additional guarantee that specifying more @flags will widen the result and making a connection "more" available, while specifying a @specific_object will restrict it. This also changes behavior in several cases. For example before nm_device_connection_is_available() for user-requests would always declare matching connections available on Wi-Fi devices (only) regardless of the device state. Now the device state gets consistently considered. For default-unmanaged devices it also changes behavior in complicated ways, because before we would put connections into @available_connetions for every device-state, but nm_device_connection_is_available() had a special over-ride only for unmanaged-state. This also fixes a bug, that user can activate an unavailable Wi-Fi device: nmcli radio wifi off nmcli connection up wlan0
2015-01-16 16:43:48 +01:00
if ( !specific_object /* << Optimization: we know that the connection is available without @specific_object. */
|| nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, specific_object))
g_ptr_array_add (array, connection);
}
}
return array;
}
static void
cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
{
if (_try_add_available_connection (NM_DEVICE (user_data), connection))
_signal_available_connections_changed (NM_DEVICE (user_data));
}
static void
cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
{
if (_del_available_connection (NM_DEVICE (user_data), connection))
_signal_available_connections_changed (NM_DEVICE (user_data));
}
static void
cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
{
gboolean added, deleted;
/* FIXME: don't remove it from the hash if it's just going to get re-added */
deleted = _del_available_connection (NM_DEVICE (user_data), connection);
added = _try_add_available_connection (NM_DEVICE (user_data), connection);
/* Only signal if the connection was removed OR added, but not both */
if (added != deleted)
_signal_available_connections_changed (NM_DEVICE (user_data));
}
gboolean
nm_device_supports_vlans (NMDevice *self)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return nm_platform_link_supports_vlans (NM_PLATFORM_GET, nm_device_get_ifindex (self));
}
/**
* nm_device_add_pending_action():
* @self: the #NMDevice to add the pending action to
* @action: a static string that identifies the action
* @assert_not_yet_pending: if %TRUE, assert that the @action is currently not yet pending.
* Otherwise, ignore duplicate scheduling of the same action silently.
*
* Adds a pending action to the device.
*
* Returns: %TRUE if the action was added (and not already added before). %FALSE
* if the same action is already scheduled. In the latter case, the action was not scheduled
* a second time.
*/
gboolean
nm_device_add_pending_action (NMDevice *self, const char *action, gboolean assert_not_yet_pending)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GSList *iter;
guint count = 0;
g_return_val_if_fail (action, FALSE);
/* Check if the action is already pending. Cannot add duplicate actions */
for (iter = priv->pending_actions; iter; iter = iter->next) {
if (!strcmp (action, iter->data)) {
if (assert_not_yet_pending) {
_LOGW (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending",
count + g_slist_length (iter), action);
g_return_val_if_reached (FALSE);
} else {
_LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)",
count + g_slist_length (iter), action);
}
return FALSE;
}
count++;
}
priv->pending_actions = g_slist_append (priv->pending_actions, g_strdup (action));
count++;
_LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s'", count, action);
if (count == 1)
g_object_notify (G_OBJECT (self), NM_DEVICE_HAS_PENDING_ACTION);
return TRUE;
}
/**
* nm_device_remove_pending_action():
* @self: the #NMDevice to remove the pending action from
* @action: a static string that identifies the action
* @assert_is_pending: if %TRUE, assert that the @action is pending.
* If %FALSE, don't do anything if the current action is not pending and
* return %FALSE.
*
* Removes a pending action previously added by nm_device_add_pending_action().
*
* Returns: whether the @action was pending and is now removed.
*/
gboolean
nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean assert_is_pending)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GSList *iter, *next;
guint count = 0;
g_return_val_if_fail (action, FALSE);
for (iter = priv->pending_actions; iter; iter = next) {
next = iter->next;
if (!strcmp (action, iter->data)) {
_LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s'",
count + g_slist_length (iter->next), /* length excluding 'iter' */
action);
g_free (iter->data);
priv->pending_actions = g_slist_delete_link (priv->pending_actions, iter);
if (priv->pending_actions == NULL)
g_object_notify (G_OBJECT (self), NM_DEVICE_HAS_PENDING_ACTION);
return TRUE;
}
count++;
}
if (assert_is_pending) {
_LOGW (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action);
g_return_val_if_reached (FALSE);
} else
_LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action);
return FALSE;
}
gboolean
nm_device_has_pending_action (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
return !!priv->pending_actions;
}
/***********************************************************/
static void
_cleanup_ip_pre (NMDevice *self, CleanupType cleanup_type)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->ip4_state = priv->ip6_state = IP_NONE;
nm_device_queued_ip_config_change_clear (self);
dhcp4_cleanup (self, cleanup_type, FALSE);
arp_cleanup (self);
dhcp6_cleanup (self, cleanup_type, FALSE);
linklocal6_cleanup (self);
addrconf6_cleanup (self);
dnsmasq_cleanup (self);
ipv4ll_cleanup (self);
}
static void
_cancel_activation (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* Clean up when device was deactivated during call to firewall */
if (priv->fw_call) {
nm_firewall_manager_cancel_call (priv->fw_call);
g_warn_if_fail (!priv->fw_call);
priv->fw_call = NULL;
}
priv->fw_ready = FALSE;
ip_check_gw_ping_cleanup (self);
/* Break the activation chain */
activation_source_clear (self, AF_INET);
activation_source_clear (self, AF_INET6);
}
static void
_cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type)
{
NMConnection *connection;
_cancel_activation (self);
connection = nm_device_get_applied_connection (self);
if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE
&& connection
&& !nm_device_uses_assumed_connection (self)) {
nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (),
nm_device_get_ip_iface (self),
NULL,
NULL,
NULL);
}
/* Clear any queued transitions */
nm_device_queued_state_clear (self);
_cleanup_ip_pre (self, cleanup_type);
}
static void
_cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
priv->default_route.v4_has = FALSE;
priv->default_route.v6_has = FALSE;
if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
priv->default_route.v4_is_assumed = FALSE;
priv->default_route.v6_is_assumed = FALSE;
nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
}
priv->default_route.v4_is_assumed = TRUE;
priv->default_route.v6_is_assumed = TRUE;
nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
priv->linklocal6_dad_counter = 0;
/* Clean up IP configs; this does not actually deconfigure the
* interface; the caller must flush routes and addresses explicitly.
*/
nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE, &ignored);
nm_device_set_ip6_config (self, NULL, TRUE, TRUE, &ignored);
g_clear_object (&priv->con_ip4_config);
g_clear_object (&priv->dev_ip4_config);
g_clear_object (&priv->ext_ip4_config);
g_clear_object (&priv->wwan_ip4_config);
g_clear_object (&priv->ip4_config);
g_clear_object (&priv->con_ip6_config);
g_clear_object (&priv->ac_ip6_config);
g_clear_object (&priv->ext_ip6_config);
g_clear_object (&priv->wwan_ip6_config);
g_clear_object (&priv->ip6_config);
g_slist_free_full (priv->vpn4_configs, g_object_unref);
priv->vpn4_configs = NULL;
g_slist_free_full (priv->vpn6_configs, g_object_unref);
priv->vpn6_configs = NULL;
clear_act_request (self);
/* Clear legacy IPv4 address property */
if (priv->ip4_address) {
priv->ip4_address = 0;
g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_ADDRESS);
}
if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
/* Check if the device was deactivated, and if so, delete_link.
* Don't call delete_link synchronously because we are currently
* handling a state change -- which is not reentrant. */
delete_on_deactivate_check_and_schedule (self, nm_device_get_ip_ifindex (self));
}
/* ip_iface should be cleared after flushing all routes and addreses, since
* those are identified by ip_iface, not by iface (which might be a tty
* or ATM device).
*/
nm_device_set_ip_iface (self, NULL);
}
/*
* nm_device_cleanup
*
* Remove a device's routing table entries and IP addresses.
*
*/
static void
nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType cleanup_type)
{
NMDevicePrivate *priv;
int ifindex;
g_return_if_fail (NM_IS_DEVICE (self));
if (reason == NM_DEVICE_STATE_REASON_NOW_MANAGED)
_LOGD (LOGD_DEVICE, "preparing device");
else
_LOGD (LOGD_DEVICE, "deactivating device (reason '%s') [%d]", reason_to_string (reason), reason);
/* Save whether or not we tried IPv6 for later */
priv = NM_DEVICE_GET_PRIVATE (self);
_cleanup_generic_pre (self, cleanup_type);
/* Turn off kernel IPv6 */
if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
set_disable_ipv6 (self, "1");
nm_device_ipv6_sysctl_set (self, "accept_ra", "0");
nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0");
}
/* Call device type-specific deactivation */
if (NM_DEVICE_GET_CLASS (self)->deactivate)
NM_DEVICE_GET_CLASS (self)->deactivate (self);
/* master: release slaves */
nm_device_master_release_slaves (self);
/* slave: mark no longer enslaved */
if (nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) <= 0) {
g_clear_object (&priv->master);
priv->is_enslaved = FALSE;
g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER);
}
/* Take out any entries in the routing table and any IP address the device had. */
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex > 0) {
nm_route_manager_route_flush (nm_route_manager_get (), ifindex);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_address_flush (NM_PLATFORM_GET, ifindex);
}
if (priv->lldp_listener)
nm_lldp_listener_stop (priv->lldp_listener);
nm_device_update_metered (self);
_cleanup_generic_post (self, cleanup_type);
}
static char *
bin2hexstr (const char *bytes, gsize len)
{
GString *str;
int i;
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (len > 0, NULL);
str = g_string_sized_new (len * 2 + 1);
for (i = 0; i < len; i++) {
if (str->len)
g_string_append_c (str, ':');
g_string_append_printf (str, "%02x", (guint8) bytes[i]);
}
return g_string_free (str, FALSE);
}
static char *
find_dhcp4_address (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint i, n;
if (!priv->ip4_config)
return NULL;
n = nm_ip4_config_get_num_addresses (priv->ip4_config);
for (i = 0; i < n; i++) {
const NMPlatformIP4Address *a = nm_ip4_config_get_address (priv->ip4_config, i);
if (a->source == NM_IP_CONFIG_SOURCE_DHCP)
return g_strdup (nm_utils_inet4_ntop (a->address, NULL));
}
return NULL;
}
void
nm_device_spawn_iface_helper (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean configured = FALSE;
NMConnection *connection;
GError *error = NULL;
const char *method;
GPtrArray *argv;
gs_free char *dhcp4_address = NULL;
char *logging_backend;
if (priv->state != NM_DEVICE_STATE_ACTIVATED)
return;
if (!nm_device_can_assume_connections (self))
return;
connection = nm_device_get_applied_connection (self);
g_assert (connection);
argv = g_ptr_array_sized_new (10);
g_ptr_array_set_free_func (argv, g_free);
g_ptr_array_add (argv, g_strdup (LIBEXECDIR "/nm-iface-helper"));
g_ptr_array_add (argv, g_strdup ("--ifname"));
g_ptr_array_add (argv, g_strdup (nm_device_get_ip_iface (self)));
g_ptr_array_add (argv, g_strdup ("--uuid"));
g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection)));
logging_backend = nm_config_get_is_debug (nm_config_get ())
? g_strdup ("debug")
: nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
NM_CONFIG_KEYFILE_GROUP_LOGGING,
NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
if (logging_backend) {
g_ptr_array_add (argv, g_strdup ("--logging-backend"));
g_ptr_array_add (argv, logging_backend);
}
dhcp4_address = find_dhcp4_address (self);
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) {
NMSettingIPConfig *s_ip4;
char *hex_client_id;
s_ip4 = nm_connection_get_setting_ip4_config (connection);
g_assert (s_ip4);
g_ptr_array_add (argv, g_strdup ("--priority4"));
g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_ip4_route_metric (self)));
g_ptr_array_add (argv, g_strdup ("--dhcp4"));
g_ptr_array_add (argv, g_strdup (dhcp4_address));
if (nm_setting_ip_config_get_may_fail (s_ip4) == FALSE)
g_ptr_array_add (argv, g_strdup ("--dhcp4-required"));
if (priv->dhcp4_client) {
const char *hostname, *fqdn;
GBytes *client_id;
client_id = nm_dhcp_client_get_client_id (priv->dhcp4_client);
if (client_id) {
g_ptr_array_add (argv, g_strdup ("--dhcp4-clientid"));
hex_client_id = bin2hexstr (g_bytes_get_data (client_id, NULL),
g_bytes_get_size (client_id));
g_ptr_array_add (argv, hex_client_id);
}
hostname = nm_dhcp_client_get_hostname (priv->dhcp4_client);
if (hostname) {
g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname"));
g_ptr_array_add (argv, g_strdup (hostname));
}
fqdn = nm_dhcp_client_get_fqdn (priv->dhcp4_client);
if (fqdn) {
g_ptr_array_add (argv, g_strdup ("--dhcp4-fqdn"));
g_ptr_array_add (argv, g_strdup (fqdn));
}
}
configured = TRUE;
}
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
NMSettingIPConfig *s_ip6;
char *hex_iid;
NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT;
s_ip6 = nm_connection_get_setting_ip6_config (connection);
g_assert (s_ip6);
g_ptr_array_add (argv, g_strdup ("--priority6"));
g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_ip6_route_metric (self)));
g_ptr_array_add (argv, g_strdup ("--slaac"));
if (nm_setting_ip_config_get_may_fail (s_ip6) == FALSE)
g_ptr_array_add (argv, g_strdup ("--slaac-required"));
g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr"));
g_ptr_array_add (argv, g_strdup_printf ("%d", priv->rdisc_use_tempaddr));
if (nm_device_get_ip_iface_identifier (self, &iid)) {
g_ptr_array_add (argv, g_strdup ("--iid"));
hex_iid = bin2hexstr ((const char *) iid.id_u8, sizeof (NMUtilsIPv6IfaceId));
g_ptr_array_add (argv, hex_iid);
}
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
g_ptr_array_add (argv, g_strdup ("--addr-gen-mode"));
g_ptr_array_add (argv, g_strdup_printf ("%d", nm_setting_ip6_config_get_addr_gen_mode (NM_SETTING_IP6_CONFIG (s_ip6))));
configured = TRUE;
}
if (configured) {
GPid pid;
g_ptr_array_add (argv, NULL);
if (nm_logging_enabled (LOGL_DEBUG, LOGD_DEVICE)) {
char *tmp;
tmp = g_strjoinv (" ", (char **) argv->pdata);
_LOGD (LOGD_DEVICE, "running '%s'", tmp);
g_free (tmp);
}
if (g_spawn_async (NULL, (char **) argv->pdata, NULL,
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) {
_LOGI (LOGD_DEVICE, "spawned helper PID %u", (guint) pid);
} else {
_LOGW (LOGD_DEVICE, "failed to spawn helper: %s", error->message);
g_error_free (error);
}
}
g_ptr_array_unref (argv);
}
/***********************************************************/
static gboolean
ip_config_valid (NMDeviceState state)
{
return (state == NM_DEVICE_STATE_UNMANAGED) ||
(state >= NM_DEVICE_STATE_IP_CHECK &&
state <= NM_DEVICE_STATE_DEACTIVATING);
}
static void
notify_ip_properties (NMDevice *self)
{
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
}
static void
ip6_managed_setup (NMDevice *self)
{
set_nm_ipv6ll (self, TRUE);
set_disable_ipv6 (self, "1");
nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0");
nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0");
}
static void
deactivate_async_ready (NMDevice *self,
GAsyncResult *res,
gpointer user_data)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceStateReason reason = GPOINTER_TO_UINT (user_data);
GError *error = NULL;
NM_DEVICE_GET_CLASS (self)->deactivate_async_finish (self, res, &error);
/* If operation cancelled, just return */
if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
|| (priv->deactivating_cancellable && g_cancellable_is_cancelled (priv->deactivating_cancellable))) {
_LOGW (LOGD_DEVICE, "Deactivation cancelled");
}
/* In every other case, transition to the DISCONNECTED state */
else {
if (error) {
_LOGW (LOGD_DEVICE, "Deactivation failed: %s",
error->message);
}
nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason);
}
g_clear_object (&priv->deactivating_cancellable);
g_clear_error (&error);
}
static void
deactivate_dispatcher_complete (guint call_id, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceStateReason reason;
g_return_if_fail (call_id == priv->dispatcher.call_id);
g_return_if_fail (priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED);
reason = priv->dispatcher.post_state_reason;
priv->dispatcher.call_id = 0;
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
if (priv->deactivating_cancellable) {
g_warn_if_reached ();
g_cancellable_cancel (priv->deactivating_cancellable);
g_clear_object (&priv->deactivating_cancellable);
}
if ( NM_DEVICE_GET_CLASS (self)->deactivate_async
&& NM_DEVICE_GET_CLASS (self)->deactivate_async_finish) {
priv->deactivating_cancellable = g_cancellable_new ();
NM_DEVICE_GET_CLASS (self)->deactivate_async (self,
priv->deactivating_cancellable,
(GAsyncReadyCallback) deactivate_async_ready,
GUINT_TO_POINTER (reason));
} else
nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason);
}
static void
_set_state_full (NMDevice *self,
NMDeviceState state,
NMDeviceStateReason reason,
gboolean quitting)
{
NMDevicePrivate *priv;
2007-03-02 Tambet Ingo <tambet@ximian.com> * libnm-glib/nm-device-802-11-wireless.c: Cache networks (bssids) list. We get signalled when it changes. * libnm-glib/nm-client.c: Cache NMState and device list, we get signalled when it changes. * libnm-glib/nm-device.c: Cache the device state property. * libnm-glib/nm-access-point.c: Cache the strength property. * src/nm-device-802-11-wireless.c: Fix wireless device scanning scheduler. The new algorithm is to start from SCAN_INTERVAL_MIN (currently defined as 0) and add a SCAN_INTERVAL_STEP (currently 20 seconds) with each successful scan until SCAN_INTERVAL_MAX (currently 120 seconds) is reached. Do not scan while the device is down, activating, or activated (in case of A/B/G cards). Remove some old dead ifdef'ed out code that used to configure wireless devices, it's all done through supplicant now. * src/supplicant-manager/nm-supplicant-interface.c: Fix the reference counting issues with pending calls which caused leaks and crashes when interface was removed (now that the interface actually gets removed). * src/nm-call-store.c: Make a copy of data before running a foreach with user callback on it - The most common usage pattern is to cancel (and thus remove) all pending calls with foreach which would modify the hash table we're iterating over. * src/nm-manager.c: When a device is added, make sure it is "up". When it's removed or disabled due to disabling wireless or networking, bring it down. * include/NetworkManager.h: Add new device state NM_DEVICE_STATE_DOWN. * src/nm-device-802-11-wireless.c: * src/nm-device-802-3-ethernet.c: * src/nm-device.c: - Remove "init" virtual function, all gobjects have a place for that already (constructor). - Replace "start" virtual function with "bring_up", devices can be brought up and down more than just on startup now. - Add "is_up" virtual function. - Implement one way to bring a device down instead of previous 4 different ways, each of witch did something different. * src/NetworkManagerUtils.c (nm_dev_sock_open): This doesn't need an NMDevice, all it needs is the device interface. Get rid of NMData.dev_list (3 members to go). Get rif of NMData in a lot of places. * gnome/libnm_glib/libnm_glib.c: Make it compile again. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2395 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-03-02 09:30:48 +00:00
NMDeviceState old_state;
NMActRequest *req;
gboolean no_firmware = FALSE;
NMSettingsConnection *connection;
NMConnection *applied_connection;
2007-03-02 Tambet Ingo <tambet@ximian.com> * libnm-glib/nm-device-802-11-wireless.c: Cache networks (bssids) list. We get signalled when it changes. * libnm-glib/nm-client.c: Cache NMState and device list, we get signalled when it changes. * libnm-glib/nm-device.c: Cache the device state property. * libnm-glib/nm-access-point.c: Cache the strength property. * src/nm-device-802-11-wireless.c: Fix wireless device scanning scheduler. The new algorithm is to start from SCAN_INTERVAL_MIN (currently defined as 0) and add a SCAN_INTERVAL_STEP (currently 20 seconds) with each successful scan until SCAN_INTERVAL_MAX (currently 120 seconds) is reached. Do not scan while the device is down, activating, or activated (in case of A/B/G cards). Remove some old dead ifdef'ed out code that used to configure wireless devices, it's all done through supplicant now. * src/supplicant-manager/nm-supplicant-interface.c: Fix the reference counting issues with pending calls which caused leaks and crashes when interface was removed (now that the interface actually gets removed). * src/nm-call-store.c: Make a copy of data before running a foreach with user callback on it - The most common usage pattern is to cancel (and thus remove) all pending calls with foreach which would modify the hash table we're iterating over. * src/nm-manager.c: When a device is added, make sure it is "up". When it's removed or disabled due to disabling wireless or networking, bring it down. * include/NetworkManager.h: Add new device state NM_DEVICE_STATE_DOWN. * src/nm-device-802-11-wireless.c: * src/nm-device-802-3-ethernet.c: * src/nm-device.c: - Remove "init" virtual function, all gobjects have a place for that already (constructor). - Replace "start" virtual function with "bring_up", devices can be brought up and down more than just on startup now. - Add "is_up" virtual function. - Implement one way to bring a device down instead of previous 4 different ways, each of witch did something different. * src/NetworkManagerUtils.c (nm_dev_sock_open): This doesn't need an NMDevice, all it needs is the device interface. Get rid of NMData.dev_list (3 members to go). Get rif of NMData in a lot of places. * gnome/libnm_glib/libnm_glib.c: Make it compile again. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2395 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-03-02 09:30:48 +00:00
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
/* Track re-entry */
g_warn_if_fail (priv->in_state_changed == FALSE);
old_state = priv->state;
/* Do nothing if state isn't changing, but as a special case allow
* re-setting UNAVAILABLE if the device is missing firmware so that we
* can retry device initialization.
*/
if ( (priv->state == state)
&& !(state == NM_DEVICE_STATE_UNAVAILABLE && priv->firmware_missing)) {
_LOGD (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d] (skip due to missing firmware)",
state_to_string (old_state),
state_to_string (state),
reason_to_string (reason),
old_state,
state,
reason);
return;
}
_LOGI (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d]",
state_to_string (old_state),
state_to_string (state),
reason_to_string (reason),
old_state,
state,
reason);
priv->in_state_changed = TRUE;
priv->state = state;
priv->state_reason = reason;
/* Clear any queued transitions */
nm_device_queued_state_clear (self);
dispatcher_cleanup (self);
if (priv->deactivating_cancellable)
g_cancellable_cancel (priv->deactivating_cancellable);
/* Cache the activation request for the dispatcher */
req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
_clear_available_connections (self, TRUE);
_clear_queued_act_request (priv);
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
}
/* Update the available connections list when a device first becomes available */
if ( (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED)
|| nm_device_get_default_unmanaged (self))
nm_device_recheck_available_connections (self);
/* Handle the new state here; but anything that could trigger
* another state change should be done below.
*/
switch (state) {
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
case NM_DEVICE_STATE_UNMANAGED:
nm_device_set_firmware_missing (self, FALSE);
if (old_state > NM_DEVICE_STATE_UNMANAGED) {
if (reason == NM_DEVICE_STATE_REASON_REMOVED) {
nm_device_cleanup (self, reason, CLEANUP_TYPE_REMOVED);
} else {
/* Clean up if the device is now unmanaged but was activated */
if (nm_device_get_act_request (self))
nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE);
nm_device_take_down (self, TRUE);
set_nm_ipv6ll (self, FALSE);
restore_ip6_properties (self);
}
}
2008-04-28 Dan Williams <dcbw@redhat.com> Fix the device up/down ambiguities. Up/down state used to be a conglomeration of hardware state (IFF_UP) and any device-specific things (supplicant, periodic timers, etc) that the device used to indicate readiness. Unfortunately, if the hardware was already IFF_UP for some reason, then the device specific stuff wouldn't get run, and the device would be stuck. * src/nm-device.c src/nm-device.h - Create hw_is_up, hw_bring_up, and hw_take_down - Rename bring_down -> take_down - (real_hw_is_up): check interface flags for IFF_UP - (nm_device_hw_is_up): let subclasses figure out their own HW state - (nm_device_is_up): make static; only used locally - (nm_device_hw_bring_up): update the hardware and IPv4 addresses even if the device is already up; if the device isn't up, bring it up - (nm_device_hw_take_down): just take down hardware - (nm_device_bring_up): bring up HW first, then device specific stuff - (nm_device_take_down): always deactivate device when called; always try to take hardware down too - (nm_device_state_changed): take device down when entering unmanaged state from a higher state * src/nm-device-802-11-wireless.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really - (real_take_down, supplicant_iface_state_cb_handler, supplicant_iface_connection_state_cb_handler, supplicant_mgr_state_cb_handler): fix some messages * src/nm-device-802-3-ethernet.c - (real_hw_is_up, real_hw_bring_up, real_hw_take_down): implement; just check IFF_UP really git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3618 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-29 15:36:29 +00:00
break;
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
case NM_DEVICE_STATE_UNAVAILABLE:
if (old_state == NM_DEVICE_STATE_UNMANAGED) {
save_ip6_properties (self);
if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED)
ip6_managed_setup (self);
}
if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) {
if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) {
if (!nm_device_bring_up (self, TRUE, &no_firmware) && no_firmware)
_LOGW (LOGD_HW, "firmware may be missing.");
nm_device_set_firmware_missing (self, no_firmware ? TRUE : FALSE);
}
/* Ensure the device gets deactivated in response to stuff like
* carrier changes or rfkill. But don't deactivate devices that are
* about to assume a connection since that defeats the purpose of
* assuming the device's existing connection.
*
* Note that we "deactivate" the device even when coming from
* UNMANAGED, to ensure that it's in a clean state.
*/
nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE);
}
break;
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
case NM_DEVICE_STATE_DISCONNECTED:
core: bounce disable_ipv6 when setting userspace IPv6 link-local (bgo #740096) The kernel does not terminate an ongoing IPv6LL address process when the IPv6LL address generation mode is set to 'none' (indicating that userspace wishes to handle IPv6LL). Next, NetworkManager does not expose IPv6 addresses internally until they have completed DAD. This means that the kernel may still be performing DAD for an IPv6LL address when NetworkManager turns userspace IPv6LL on, and when DAD is complete NetworkManager will finally pay attention to the address. If the device is in the DISCONNECTED state, NetworkManager will then generate and assume an IPv6LL-only connection on the device. Unfortunately, that behavior happens if the following is true: 1) IPv6LL addressing takes a while (eg, dad_transmits is high or the kernel takes a while for some reason) 2) the activated connection fails quickly (dhclient fails or some other fatal error terminates the activation attempt) 3) the activated connection has ipv6.method=ignore In this case, when the device was brought up and ipv6.method=ignore, NetworkManager re-enabled kernel IPv6LL and reset the IPv6 sysctl properties. The kernel then generated an IPv6LL address and began DAD. dhclient failed quickly, and NM deactivated the device. NM then turned off kernel IPv6LL when deactivating the device, but the kernel does not terminate the ongoing DAD. Some time after the device entered the DISCONNECTED state, the kernel finished DAD and that allowed NetworkManager to internally see the address, which caused NetworkManager to emit the 'recheck-assume' signal. This generated a new IPv6LL-only connection which was then assumed. Bouncing 'disable_ipv6' when re-enabling userspace IPv6LL during device deactivation flushes the tentative kernel IPv6LL address, thus preventing the address from being announced after userspace IPv6LL is re-enabled. The other alternative is to expose tentative addresses (eg those still doing DAD) in NMPlatform so they would be flushed when the device deactivates, but that is a larger & riskier set of changes. Reproducer: - ifconfig eth0 down - prepare a DHCPv4 connection with ipv6.method=ignore - set /proc/sys/net/ipv6/conf/all/dad_transmits to "15" - ensure that DHCPv4 will fail (replace dhclient with a script that exits after 2 seconds or something) - run NetworkManager - activate the DHCP connection and watch it immediately fail - wait for the kernel to announce the IPv6LL address after DAD finishes - watch NM "assume" the new IPv6LL connection https://bugzilla.gnome.org/show_bug.cgi?id=740096
2014-11-13 19:52:21 -06:00
if (old_state > NM_DEVICE_STATE_DISCONNECTED) {
/* Ensure devices that previously assumed a connection now have
* userspace IPv6LL enabled.
*/
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
set_nm_ipv6ll (self, TRUE);
nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE);
} else if (old_state < NM_DEVICE_STATE_DISCONNECTED) {
if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) {
/* Ensure IPv6 is set up as it may not have been done when
* entering the UNAVAILABLE state depending on the reason.
*/
ip6_managed_setup (self);
}
core: bounce disable_ipv6 when setting userspace IPv6 link-local (bgo #740096) The kernel does not terminate an ongoing IPv6LL address process when the IPv6LL address generation mode is set to 'none' (indicating that userspace wishes to handle IPv6LL). Next, NetworkManager does not expose IPv6 addresses internally until they have completed DAD. This means that the kernel may still be performing DAD for an IPv6LL address when NetworkManager turns userspace IPv6LL on, and when DAD is complete NetworkManager will finally pay attention to the address. If the device is in the DISCONNECTED state, NetworkManager will then generate and assume an IPv6LL-only connection on the device. Unfortunately, that behavior happens if the following is true: 1) IPv6LL addressing takes a while (eg, dad_transmits is high or the kernel takes a while for some reason) 2) the activated connection fails quickly (dhclient fails or some other fatal error terminates the activation attempt) 3) the activated connection has ipv6.method=ignore In this case, when the device was brought up and ipv6.method=ignore, NetworkManager re-enabled kernel IPv6LL and reset the IPv6 sysctl properties. The kernel then generated an IPv6LL address and began DAD. dhclient failed quickly, and NM deactivated the device. NM then turned off kernel IPv6LL when deactivating the device, but the kernel does not terminate the ongoing DAD. Some time after the device entered the DISCONNECTED state, the kernel finished DAD and that allowed NetworkManager to internally see the address, which caused NetworkManager to emit the 'recheck-assume' signal. This generated a new IPv6LL-only connection which was then assumed. Bouncing 'disable_ipv6' when re-enabling userspace IPv6LL during device deactivation flushes the tentative kernel IPv6LL address, thus preventing the address from being announced after userspace IPv6LL is re-enabled. The other alternative is to expose tentative addresses (eg those still doing DAD) in NMPlatform so they would be flushed when the device deactivates, but that is a larger & riskier set of changes. Reproducer: - ifconfig eth0 down - prepare a DHCPv4 connection with ipv6.method=ignore - set /proc/sys/net/ipv6/conf/all/dad_transmits to "15" - ensure that DHCPv4 will fail (replace dhclient with a script that exits after 2 seconds or something) - run NetworkManager - activate the DHCP connection and watch it immediately fail - wait for the kernel to announce the IPv6LL address after DAD finishes - watch NM "assume" the new IPv6LL connection https://bugzilla.gnome.org/show_bug.cgi?id=740096
2014-11-13 19:52:21 -06:00
}
2007-03-02 Tambet Ingo <tambet@ximian.com> * libnm-glib/nm-device-802-11-wireless.c: Cache networks (bssids) list. We get signalled when it changes. * libnm-glib/nm-client.c: Cache NMState and device list, we get signalled when it changes. * libnm-glib/nm-device.c: Cache the device state property. * libnm-glib/nm-access-point.c: Cache the strength property. * src/nm-device-802-11-wireless.c: Fix wireless device scanning scheduler. The new algorithm is to start from SCAN_INTERVAL_MIN (currently defined as 0) and add a SCAN_INTERVAL_STEP (currently 20 seconds) with each successful scan until SCAN_INTERVAL_MAX (currently 120 seconds) is reached. Do not scan while the device is down, activating, or activated (in case of A/B/G cards). Remove some old dead ifdef'ed out code that used to configure wireless devices, it's all done through supplicant now. * src/supplicant-manager/nm-supplicant-interface.c: Fix the reference counting issues with pending calls which caused leaks and crashes when interface was removed (now that the interface actually gets removed). * src/nm-call-store.c: Make a copy of data before running a foreach with user callback on it - The most common usage pattern is to cancel (and thus remove) all pending calls with foreach which would modify the hash table we're iterating over. * src/nm-manager.c: When a device is added, make sure it is "up". When it's removed or disabled due to disabling wireless or networking, bring it down. * include/NetworkManager.h: Add new device state NM_DEVICE_STATE_DOWN. * src/nm-device-802-11-wireless.c: * src/nm-device-802-3-ethernet.c: * src/nm-device.c: - Remove "init" virtual function, all gobjects have a place for that already (constructor). - Replace "start" virtual function with "bring_up", devices can be brought up and down more than just on startup now. - Add "is_up" virtual function. - Implement one way to bring a device down instead of previous 4 different ways, each of witch did something different. * src/NetworkManagerUtils.c (nm_dev_sock_open): This doesn't need an NMDevice, all it needs is the device interface. Get rid of NMData.dev_list (3 members to go). Get rif of NMData in a lot of places. * gnome/libnm_glib/libnm_glib.c: Make it compile again. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2395 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2007-03-02 09:30:48 +00:00
break;
case NM_DEVICE_STATE_NEED_AUTH:
if (old_state > NM_DEVICE_STATE_NEED_AUTH) {
/* Clean up any half-done IP operations if the device's layer2
* finds out it needs authentication during IP config.
*/
_cleanup_ip_pre (self, CLEANUP_TYPE_DECONFIGURE);
}
break;
default:
break;
}
/* Reset autoconnect flag when the device is activating or connected. */
if ( state >= NM_DEVICE_STATE_PREPARE
&& state <= NM_DEVICE_STATE_ACTIVATED)
nm_device_set_autoconnect (self, TRUE);
g_object_notify (G_OBJECT (self), NM_DEVICE_STATE);
g_object_notify (G_OBJECT (self), NM_DEVICE_STATE_REASON);
g_signal_emit_by_name (self, "state-changed", state, old_state, reason);
/* Post-process the event after internal notification */
switch (state) {
case NM_DEVICE_STATE_UNAVAILABLE:
/* If the device can activate now (ie, it's got a carrier, the supplicant
* is active, or whatever) schedule a delayed transition to DISCONNECTED
* to get things rolling. The device can't transition immediately because
* we can't change states again from the state handler for a variety of
* reasons.
*/
if (nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
nm_device_queue_recheck_available (self,
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
} else {
if (old_state == NM_DEVICE_STATE_UNMANAGED)
_LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED");
else if ( old_state > NM_DEVICE_STATE_UNAVAILABLE
&& nm_device_get_default_unmanaged (self))
nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
}
break;
case NM_DEVICE_STATE_DEACTIVATING:
_cancel_activation (self);
if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
/* We cache the ignore_carrier state to not react on config-reloads while the connection
* is active. But on deactivating, reset the ignore-carrier flag to the current state. */
priv->ignore_carrier = nm_config_data_get_ignore_carrier (NM_CONFIG_GET_DATA, self);
}
if (quitting) {
nm_dispatcher_call_sync (DISPATCHER_ACTION_PRE_DOWN,
nm_act_request_get_settings_connection (req),
nm_act_request_get_applied_connection (req),
self);
} else {
priv->dispatcher.post_state = NM_DEVICE_STATE_DISCONNECTED;
priv->dispatcher.post_state_reason = reason;
if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_DOWN,
nm_act_request_get_settings_connection (req),
nm_act_request_get_applied_connection (req),
self,
deactivate_dispatcher_complete,
self,
&priv->dispatcher.call_id)) {
/* Just proceed on errors */
deactivate_dispatcher_complete (0, self);
}
}
break;
case NM_DEVICE_STATE_DISCONNECTED:
if ( priv->queued_act_request
&& !priv->queued_act_request_is_waiting_for_carrier) {
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
NMActRequest *queued_req;
gboolean success;
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
queued_req = priv->queued_act_request;
priv->queued_act_request = NULL;
success = _device_activate (self, queued_req);
core: queue re-activations to allow DEACTIVATING state If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
2014-02-17 17:16:08 -06:00
g_object_unref (queued_req);
if (success)
break;
/* fall through */
}
if ( old_state > NM_DEVICE_STATE_DISCONNECTED
&& nm_device_get_default_unmanaged (self))
nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
break;
case NM_DEVICE_STATE_ACTIVATED:
_LOGI (LOGD_DEVICE, "Activation: successful, device activated.");
nm_device_update_metered (self);
nm_dispatcher_call (DISPATCHER_ACTION_UP,
nm_act_request_get_settings_connection (req),
nm_act_request_get_applied_connection (req),
self, NULL, NULL, NULL);
break;
case NM_DEVICE_STATE_FAILED:
/* Usually upon failure the activation chain is interrupted in
* one of the stages; but in some cases the device fails for
* external events (as a failure of master connection) while
* the activation sequence is running and so we need to ensure
* that the chain is terminated here.
*/
_cancel_activation (self);
if (nm_device_uses_assumed_connection (self)) {
/* Avoid tearing down assumed connection, assume it's connected */
nm_device_queue_state (self,
NM_DEVICE_STATE_ACTIVATED,
NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
break;
}
connection = nm_device_get_settings_connection (self);
_LOGW (LOGD_DEVICE | LOGD_WIFI,
"Activation: failed for connection '%s'",
connection ? nm_settings_connection_get_id (connection) : "<unknown>");
2012-11-14 14:05:30 -06:00
/* Notify any slaves of the unexpected failure */
nm_device_master_release_slaves (self);
2012-11-14 14:05:30 -06:00
/* If the connection doesn't yet have a timestamp, set it to zero so that
* we can distinguish between connections we've tried to activate and have
* failed (zero timestamp), connections that succeeded (non-zero timestamp),
* and those we haven't tried yet (no timestamp).
*/
if (connection && !nm_settings_connection_get_timestamp (connection, NULL))
nm_settings_connection_update_timestamp (connection, (guint64) 0, TRUE);
/* Schedule the transition to DISCONNECTED. The device can't transition
* immediately because we can't change states again from the state
* handler for a variety of reasons.
*/
nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
break;
case NM_DEVICE_STATE_IP_CHECK:
/* Now that IP config has completed, check if the firewall
* zone must be set again for the IP interface.
*/
applied_connection = nm_device_get_applied_connection (self);
if ( applied_connection
&& priv->ifindex != priv->ip_ifindex
&& !nm_device_uses_assumed_connection (self)) {
NMSettingConnection *s_con;
const char *zone;
s_con = nm_connection_get_setting_connection (applied_connection);
zone = nm_setting_connection_get_zone (s_con);
g_assert (!priv->fw_call);
priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (),
nm_device_get_ip_iface (self),
zone,
FALSE,
fw_change_zone_cb_ip_check,
self);
} else
nm_device_start_ip_check (self);
/* IP-related properties are only valid when the device has IP configuration;
* now that it does, ensure their change notifications are emitted.
*/
notify_ip_properties (self);
break;
case NM_DEVICE_STATE_SECONDARIES:
ip_check_gw_ping_cleanup (self);
_LOGD (LOGD_DEVICE, "device entered SECONDARIES state");
break;
default:
break;
}
if (state > NM_DEVICE_STATE_DISCONNECTED)
delete_on_deactivate_unschedule (self);
if ( (old_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_DEACTIVATING)
&& (state != NM_DEVICE_STATE_DEACTIVATING)) {
if (quitting) {
nm_dispatcher_call_sync (DISPATCHER_ACTION_DOWN,
nm_act_request_get_settings_connection (req),
nm_act_request_get_applied_connection (req),
self);
} else {
nm_dispatcher_call (DISPATCHER_ACTION_DOWN,
nm_act_request_get_settings_connection (req),
nm_act_request_get_applied_connection (req),
self, NULL, NULL, NULL);
}
}
/* IP-related properties are only valid when the device has IP configuration.
* If it no longer does, ensure their change notifications are emitted.
*/
if (ip_config_valid (old_state) && !ip_config_valid (state))
notify_ip_properties (self);
/* Dispose of the cached activation request */
if (req)
g_object_unref (req);
priv->in_state_changed = FALSE;
}
void
nm_device_state_changed (NMDevice *self,
NMDeviceState state,
NMDeviceStateReason reason)
{
_set_state_full (self, state, reason, FALSE);
}
static gboolean
queued_set_state (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceState new_state;
NMDeviceStateReason new_reason;
if (priv->queued_state.id) {
_LOGD (LOGD_DEVICE, "running queued state change to %s (id %d)",
state_to_string (priv->queued_state.state),
priv->queued_state.id);
/* Clear queued state struct before triggering state change, since
* the state change may queue another state.
*/
priv->queued_state.id = 0;
new_state = priv->queued_state.state;
new_reason = priv->queued_state.reason;
nm_device_queued_state_clear (self);
nm_device_state_changed (self, new_state, new_reason);
nm_device_remove_pending_action (self, queued_state_to_string (new_state), TRUE);
} else {
g_warn_if_fail (priv->queued_state.state == NM_DEVICE_STATE_UNKNOWN);
g_warn_if_fail (priv->queued_state.reason == NM_DEVICE_STATE_REASON_NONE);
}
return FALSE;
}
void
nm_device_queue_state (NMDevice *self,
NMDeviceState state,
NMDeviceStateReason reason)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->queued_state.id && priv->queued_state.state == state)
return;
/* Add pending action for the new state before clearing the queued states, so
* that we don't accidently pop all pending states and reach 'startup complete' */
nm_device_add_pending_action (self, queued_state_to_string (state), TRUE);
/* We should only ever have one delayed state transition at a time */
if (priv->queued_state.id) {
_LOGW (LOGD_DEVICE, "overwriting previously queued state change to %s (%s)",
state_to_string (priv->queued_state.state),
reason_to_string (priv->queued_state.reason));
nm_device_queued_state_clear (self);
}
priv->queued_state.state = state;
priv->queued_state.reason = reason;
priv->queued_state.id = g_idle_add (queued_set_state, self);
_LOGD (LOGD_DEVICE, "queued state change to %s due to %s (id %d)",
state_to_string (state), reason_to_string (reason),
priv->queued_state.id);
}
NMDeviceState
nm_device_queued_state_peek (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_STATE_UNKNOWN);
priv = NM_DEVICE_GET_PRIVATE (self);
return priv->queued_state.id ? priv->queued_state.state : NM_DEVICE_STATE_UNKNOWN;
}
void
nm_device_queued_state_clear (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->queued_state.id) {
_LOGD (LOGD_DEVICE, "clearing queued state transition (id %d)",
priv->queued_state.id);
g_source_remove (priv->queued_state.id);
nm_device_remove_pending_action (self, queued_state_to_string (priv->queued_state.state), TRUE);
}
memset (&priv->queued_state, 0, sizeof (priv->queued_state));
}
NMDeviceState
nm_device_get_state (NMDevice *self)
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
{
g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_STATE_UNKNOWN);
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
return NM_DEVICE_GET_PRIVATE (self)->state;
}
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
/***********************************************************/
/* NMConfigDevice interface related stuff */
const char *
nm_device_get_hw_address (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
priv = NM_DEVICE_GET_PRIVATE (self);
return priv->hw_addr_len ? priv->hw_addr : NULL;
}
static void
nm_device_update_hw_address (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ifindex (self);
const guint8 *hwaddr;
gsize hwaddrlen = 0;
2008-04-07 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h - Remove the DOWN and CANCELLED device states - Add UNMANAGED and UNAVAILABLE device states - Document the device states * introspection/nm-device.xml src/nm-device-interface.c src/nm-device-interface.h - Add the 'managed' property * test/nm-tool.c - (detail_device): print out device state * src/NetworkManagerSystem.h src/backends/NetworkManagerArch.c src/backends/NetworkManagerDebian.c src/backends/NetworkManagerFrugalware.c src/backends/NetworkManagerGentoo.c src/backends/NetworkManagerMandriva.c src/backends/NetworkManagerPaldo.c src/backends/NetworkManagerRedHat.c src/backends/NetworkManagerSlackware.c src/backends/NetworkManagerSuSE.c - (nm_system_device_get_system_config, nm_system_device_get_disabled nm_system_device_free_system_config): remove; they were unused and their functionality should be re-implemented in each distro's system settings service plugin * src/nm-gsm-device.c src/nm-gsm-device.h src/nm-cdma-device.c src/nm-cdma-device.h - (*_new): take the 'managed' argument * src/nm-device.c - (nm_device_set_address): remove, fold into nm_device_bring_up() - (nm_device_init): start in unmanaged state, not disconnected - (constructor): don't start device until the system settings service has had a chance to figure out if the device is managed or not - (nm_device_deactivate, nm_device_bring_up, nm_device_bring_down): don't set device state here, let callers handle that as appropriate - (nm_device_dispose): don't touch the device if it's not managed - (set_property, get_property, nm_device_class_init): implement the 'managed' property - (nm_device_state_changed): bring the device up if its now managed, and deactivate it if it used to be active - (nm_device_get_managed, nm_device_set_managed): do the right thing with the managed state * src/nm-hal-manager.c - (wired_device_creator, wireless_device_creator, modem_device_creator): take initial managed state and pass it along to device constructors - (create_device_and_add_to_list): get managed state and pass to type creators * src/nm-device-802-11-wireless.c - (real_can_activate): fold in most of nm_device_802_11_wireless_can_activate() - (can_scan): can't scan in UNAVAILABLE or UNMANAGED - (link_timeout_cb): instead of deactivating, change device state and let the device state handler to it - (real_update_hw_address): clean up - (state_changed_cb): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device isn't rfkilled * src/nm-device-802-3-ethernet.c - (set_carrier): move above callers and get rid of prototype - (device_state_changed): when entering UNAVAILABLE state, schedule an idle handler to transition to DISCONNECTED if the device has a carrier - (real_update_hw_address): clean up - (link_timeout_cb, ppp_state_changed): change state instead of calling deactivation directly as deactivation doesn't change state anymore * src/NetworkManagerPolicy.c - (schedule_activate_check): yay, remove wireless_enabled hack since the NMManager and wireless devices work that out themselves now - (device_state_changed): change to a switch and update for new device states - (device_carrier_changed): remove; device handles this now through state changes - (device_added): don't care about carrier any more; the initial activation check will happen when the device transitions to DISCONNECTED * src/nm-manager.c - (dispose): clear unmanaged devices - (handle_unmanaged_devices): update unmanaged device list and toggle the managed property on each device when needed - (system_settings_properties_changed_cb): handle signals from the system settings service - (system_settings_get_unmanaged_devices_cb): handle callback from getting the unmanaged device list method call - (query_unmanaged_devices): ask the system settings service for its list of unmanaged devices - (nm_manager_name_owner_changed, initial_get_connections): get unmanaged devices - (manager_set_wireless_enabled): push rfkill state down to wireless devices directly and let them handle the necessary state transitions - (manager_device_state_changed): update for new device states - (nm_manager_add_device): set initial rfkill state on wireless devices - (nm_manager_remove_device): don't touch the device if it's unmanaged - (nm_manager_activate_connection): return error if the device is unmanaged - (nm_manager_sleep): handle new device states correctly; don't change the state of unavailable/unmanaged devices * libnm-glib/nm-device-802-11-wireless.c - (state_changed_cb): update for new device states git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3540 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-04-08 02:58:02 +00:00
if (ifindex <= 0)
return;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen);
if (hwaddrlen) {
priv->hw_addr_len = hwaddrlen;
if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
g_free (priv->hw_addr);
priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen);
_LOGD (LOGD_HW | LOGD_DEVICE, "hardware address now %s", priv->hw_addr);
g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS);
}
} else {
/* Invalid or no hardware address */
if (priv->hw_addr_len != 0) {
g_clear_pointer (&priv->hw_addr, g_free);
priv->hw_addr_len = 0;
_LOGD (LOGD_HW | LOGD_DEVICE,
"previous hardware address is no longer valid");
g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS);
}
}
}
gboolean
nm_device_set_hw_addr (NMDevice *self, const char *addr,
const char *detail, guint64 hw_log_domain)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean success = FALSE;
const char *cur_addr = nm_device_get_hw_address (self);
guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
g_return_val_if_fail (addr != NULL, FALSE);
/* Do nothing if current MAC is same */
if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
_LOGD (LOGD_DEVICE | hw_log_domain, "no MAC address change needed");
return TRUE;
}
if (!nm_utils_hwaddr_aton (addr, addr_bytes, priv->hw_addr_len)) {
_LOGW (LOGD_DEVICE | hw_log_domain, "invalid MAC address %s", addr);
return FALSE;
}
/* Can't change MAC address while device is up */
nm_device_take_down (self, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
success = nm_platform_link_set_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), addr_bytes, priv->hw_addr_len);
if (success) {
/* MAC address succesfully changed; update the current MAC to match */
nm_device_update_hw_address (self);
cur_addr = nm_device_get_hw_address (self);
if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
_LOGI (LOGD_DEVICE | hw_log_domain, "%s MAC address to %s",
detail, addr);
} else {
_LOGW (LOGD_DEVICE | hw_log_domain,
"new MAC address %s not successfully set", addr);
success = FALSE;
}
} else {
_LOGW (LOGD_DEVICE | hw_log_domain, "failed to %s MAC address to %s",
detail, addr);
}
nm_device_bring_up (self, TRUE, NULL);
return success;
}
const char *
nm_device_get_permanent_hw_address (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->perm_hw_addr;
}
const char *
nm_device_get_initial_hw_address (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->initial_hw_addr;
}
2013-03-13 13:52:55 -04:00
/**
* nm_device_spec_match_list:
* @self: an #NMDevice
2013-03-13 13:52:55 -04:00
* @specs: (element-type utf8): a list of device specs
*
* Checks if @self matches any of the specifications in @specs. The
2013-03-13 13:52:55 -04:00
* currently-supported spec types are:
*
* "mac:00:11:22:33:44:55" - matches a device with the given
* hardware address
*
* "interface-name:foo0" - matches a device with the given
* interface name
*
* "s390-subchannels:00.11.22" - matches a device with the given
* z/VM / s390 subchannels.
*
* "*" - matches any device
*
* Returns: #TRUE if @self matches one of the specs in @specs
2013-03-13 13:52:55 -04:00
*/
gboolean
nm_device_spec_match_list (NMDevice *self, const GSList *specs)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
if (!specs)
return FALSE;
return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs) == NM_MATCH_SPEC_MATCH;
}
static NMMatchSpecMatchType
spec_match_list (NMDevice *self, const GSList *specs)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
const GSList *iter;
for (iter = specs; iter; iter = g_slist_next (iter)) {
if (!strcmp ((const char *) iter->data, "*")) {
matched = NM_MATCH_SPEC_MATCH;
break;
}
}
if (priv->hw_addr_len) {
m = nm_match_spec_hwaddr (specs, priv->hw_addr);
matched = MAX (matched, m);
}
if (matched != NM_MATCH_SPEC_NEG_MATCH) {
m = nm_match_spec_interface_name (specs, nm_device_get_iface (self));
matched = MAX (matched, m);
}
if (matched != NM_MATCH_SPEC_NEG_MATCH) {
m = nm_match_spec_device_type (specs, nm_device_get_type_description (self));
matched = MAX (matched, m);
}
return matched;
}
/***********************************************************/
static const char *
_activation_func_to_string (ActivationHandleFunc func)
{
#define FUNC_TO_STRING_CHECK_AND_RETURN(func, f) \
G_STMT_START { \
if ((func) == (f)) \
return #f; \
} G_STMT_END
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage1_device_prepare);
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage2_device_config);
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage3_ip_config_start);
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip4_config_timeout);
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip6_config_timeout);
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip4_config_commit);
FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip6_config_commit);
g_return_val_if_reached ("unknown");
}
/***********************************************************/
#define DEFAULT_AUTOCONNECT TRUE
static void
nm_device_init (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->type = NM_DEVICE_TYPE_UNKNOWN;
priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
priv->state = NM_DEVICE_STATE_UNMANAGED;
priv->state_reason = NM_DEVICE_STATE_REASON_NONE;
priv->dhcp_timeout = 0;
priv->rfkill_type = RFKILL_TYPE_UNKNOWN;
priv->autoconnect = DEFAULT_AUTOCONNECT;
priv->unmanaged_flags = NM_UNMANAGED_INTERNAL;
priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
priv->default_route.v4_is_assumed = TRUE;
priv->default_route.v6_is_assumed = TRUE;
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
}
static void
constructed (GObject *object)
{
NMDevice *self = NM_DEVICE (object);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMPlatform *platform;
if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities)
priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self);
/* Watch for external IP config changes */
platform = nm_platform_get ();
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self);
priv->con_provider = nm_connection_provider_get ();
g_assert (priv->con_provider);
g_signal_connect (priv->con_provider,
NM_CP_SIGNAL_CONNECTION_ADDED,
G_CALLBACK (cp_connection_added),
self);
g_signal_connect (priv->con_provider,
NM_CP_SIGNAL_CONNECTION_REMOVED,
G_CALLBACK (cp_connection_removed),
self);
g_signal_connect (priv->con_provider,
NM_CP_SIGNAL_CONNECTION_UPDATED,
G_CALLBACK (cp_connection_updated),
self);
/* Update default-unmanaged device available connections immediately,
* since they don't transition from UNMANAGED (and thus the state handler
* doesn't run and update them) until something external happens.
*/
if (nm_device_get_default_unmanaged (self)) {
nm_device_set_autoconnect (self, FALSE);
nm_device_recheck_available_connections (self);
}
G_OBJECT_CLASS (nm_device_parent_class)->constructed (object);
_LOGD (LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME (self));
}
static void
dispose (GObject *object)
{
NMDevice *self = NM_DEVICE (object);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMPlatform *platform;
_LOGD (LOGD_DEVICE, "disposing");
g_signal_handlers_disconnect_by_func (nm_config_get (), config_changed_update_ignore_carrier, self);
dispatcher_cleanup (self);
_cleanup_generic_pre (self, CLEANUP_TYPE_KEEP);
g_warn_if_fail (priv->slaves == NULL);
g_assert (priv->master_ready_id == 0);
core: take over IPv6LL address management if kernel supports it (bgo #734149) NM keeps interfaces IFF_UP when possible to receive link layer events like carrier changes. Unfortunately, the kernel also uses IFF_UP as a flag to assign an IPv6LL address to the interface, which results in IPv6 connectivity on the link even if the interface is not supposed to be activated/connected. NM sets disable_ipv6=1 to ensure that the kernel does not set up IPv6LL connectivity on interfaces when they are not supposed to be active and connected. Unfortunately, that prevents users from manually adding IPv6 addresses to the interface, since they expect previous kernel behavior where IPv6 is enabled whenever the interface is IFF_UP. Furthermore, interfaces like PPP and some WWAN devices provide misleading information to the kernel which causes the kernel to create the wrong IPv6LL address for the interface. The IPv6LL address for these devices is obtained through control channels instead (IPV6CP for PPP, proprietary protocols for WWAN devices) and should be used instead of the kernel address. So we'd like to suppress kernel IPv6LL address generation on these interfaces anyway. This patch makes use of the netlink IFLA_INET6_ADDR_GEN_MODE attribute to take over assignment of IPv6LL addresses while keeping the interface IFF_UP, to ensure there is only IPv6 connectivity when the user requests it. To remain compliant with standards, if a user adds IPv6 addresses externally, NetworkManager must also immediately add an IPv6LL address for that interface too. https://bugzilla.gnome.org/show_bug.cgi?id=734149
2014-07-24 17:14:30 -05:00
/* Let the kernel manage IPv6LL again */
set_nm_ipv6ll (self, FALSE);
_cleanup_generic_post (self, CLEANUP_TYPE_KEEP);
g_hash_table_remove_all (priv->ip6_saved_properties);
if (priv->recheck_assume_id) {
g_source_remove (priv->recheck_assume_id);
priv->recheck_assume_id = 0;
}
if (priv->recheck_available.call_id) {
g_source_remove (priv->recheck_available.call_id);
priv->recheck_available.call_id = 0;
}
link_disconnect_action_cancel (self);
if (priv->con_provider) {
g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_added, self);
g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_removed, self);
g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_updated, self);
priv->con_provider = NULL;
}
g_hash_table_remove_all (priv->available_connections);
nm_clear_g_source (&priv->carrier_wait_id);
_clear_queued_act_request (priv);
platform = nm_platform_get ();
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self);
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
nm_clear_g_source (&priv->device_link_changed_id);
nm_clear_g_source (&priv->device_ip_link_changed_id);
if (priv->lldp_listener) {
g_signal_handlers_disconnect_by_func (priv->lldp_listener,
G_CALLBACK (lldp_neighbors_changed),
self);
nm_lldp_listener_stop (priv->lldp_listener);
g_clear_object (&priv->lldp_listener);
}
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
NMDevice *self = NM_DEVICE (object);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
_LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self));
g_free (priv->hw_addr);
g_free (priv->perm_hw_addr);
g_free (priv->initial_hw_addr);
g_slist_free_full (priv->pending_actions, g_free);
g_slist_free_full (priv->dad6_failed_addrs, g_free);
g_clear_pointer (&priv->physical_port_id, g_free);
g_free (priv->udi);
g_free (priv->iface);
g_free (priv->ip_iface);
g_free (priv->driver);
g_free (priv->driver_version);
g_free (priv->firmware_version);
g_free (priv->type_desc);
g_free (priv->type_description);
g_free (priv->dhcp_anycast_address);
g_hash_table_unref (priv->ip6_saved_properties);
g_hash_table_unref (priv->available_connections);
G_OBJECT_CLASS (nm_device_parent_class)->finalize (object);
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMDevice *self = NM_DEVICE (object);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *hw_addr, *p;
guint count;
gboolean val_bool;
const NMPlatformLink *pllink;
switch (prop_id) {
case PROP_UDI:
if (g_value_get_string (value)) {
g_free (priv->udi);
priv->udi = g_value_dup_string (value);
}
break;
case PROP_IFACE:
p = g_value_get_string (value);
if (p) {
g_free (priv->iface);
priv->iface = g_strdup (p);
pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface);
if (pllink) {
if (link_type_compatible (self, pllink->type, NULL, NULL)) {
priv->ifindex = pllink->ifindex;
priv->up = nm_platform_link_is_up (NM_PLATFORM_GET, priv->ifindex);
}
}
}
break;
case PROP_DRIVER:
if (g_value_get_string (value)) {
g_free (priv->driver);
priv->driver = g_value_dup_string (value);
}
break;
case PROP_DRIVER_VERSION:
g_free (priv->driver_version);
priv->driver_version = g_strdup (g_value_get_string (value));
break;
case PROP_FIRMWARE_VERSION:
g_free (priv->firmware_version);
priv->firmware_version = g_strdup (g_value_get_string (value));
break;
case PROP_MTU:
priv->mtu = g_value_get_uint (value);
break;
case PROP_IP4_ADDRESS:
priv->ip4_address = g_value_get_uint (value);
break;
case PROP_MANAGED:
val_bool = g_value_get_boolean (value);
priv->managed_touched_by_user = TRUE;
2015-11-05 02:32:53 +01:00
nm_device_set_unmanaged_flags (self,
NM_UNMANAGED_USER | (val_bool ? NM_UNMANAGED_DEFAULT : NM_UNMANAGED_NONE),
!val_bool,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
break;
case PROP_AUTOCONNECT:
nm_device_set_autoconnect (self, g_value_get_boolean (value));
break;
case PROP_FIRMWARE_MISSING:
priv->firmware_missing = g_value_get_boolean (value);
break;
case PROP_NM_PLUGIN_MISSING:
priv->nm_plugin_missing = g_value_get_boolean (value);
break;
case PROP_DEVICE_TYPE:
g_return_if_fail (priv->type == NM_DEVICE_TYPE_UNKNOWN);
priv->type = g_value_get_uint (value);
break;
case PROP_TYPE_DESC:
g_free (priv->type_desc);
priv->type_desc = g_value_dup_string (value);
break;
case PROP_RFKILL_TYPE:
priv->rfkill_type = g_value_get_uint (value);
break;
case PROP_IS_MASTER:
priv->is_master = g_value_get_boolean (value);
break;
case PROP_HW_ADDRESS:
/* construct only */
p = hw_addr = g_value_get_string (value);
/* Hardware address length is the number of ':' plus 1 */
count = 1;
while (p && *p) {
if (*p++ == ':')
count++;
}
if (count < ETH_ALEN || count > NM_UTILS_HWADDR_LEN_MAX) {
if (hw_addr && *hw_addr) {
_LOGW (LOGD_DEVICE, "ignoring hardware address '%s' with unexpected length %d",
hw_addr, count);
}
break;
}
priv->hw_addr_len = count;
g_free (priv->hw_addr);
if (nm_utils_hwaddr_valid (hw_addr, priv->hw_addr_len))
priv->hw_addr = g_strdup (hw_addr);
else {
_LOGW (LOGD_DEVICE, "could not parse hw-address '%s'", hw_addr);
priv->hw_addr = NULL;
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMDevice *self = NM_DEVICE (object);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GPtrArray *array;
GHashTableIter iter;
NMConnection *connection;
GVariantBuilder array_builder;
switch (prop_id) {
case PROP_UDI:
g_value_set_string (value, priv->udi);
break;
case PROP_IFACE:
g_value_set_string (value, priv->iface);
break;
case PROP_IP_IFACE:
if (ip_config_valid (priv->state))
g_value_set_string (value, nm_device_get_ip_iface (self));
else
g_value_set_string (value, NULL);
break;
case PROP_IFINDEX:
g_value_set_int (value, priv->ifindex);
break;
case PROP_DRIVER:
g_value_set_string (value, priv->driver);
break;
case PROP_DRIVER_VERSION:
g_value_set_string (value, priv->driver_version);
break;
case PROP_FIRMWARE_VERSION:
g_value_set_string (value, priv->firmware_version);
break;
case PROP_CAPABILITIES:
g_value_set_uint (value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK));
break;
case PROP_IP4_ADDRESS:
g_value_set_uint (value, priv->ip4_address);
break;
case PROP_CARRIER:
g_value_set_boolean (value, priv->carrier);
break;
case PROP_MTU:
g_value_set_uint (value, priv->mtu);
break;
case PROP_IP4_CONFIG:
nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip4_config : NULL);
break;
case PROP_DHCP4_CONFIG:
nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp4_config : NULL);
break;
case PROP_IP6_CONFIG:
nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip6_config : NULL);
break;
case PROP_DHCP6_CONFIG:
nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp6_config : NULL);
break;
case PROP_STATE:
g_value_set_uint (value, priv->state);
break;
case PROP_STATE_REASON:
g_value_take_variant (value,
g_variant_new ("(uu)", priv->state, priv->state_reason));
break;
case PROP_ACTIVE_CONNECTION:
nm_utils_g_value_set_object_path (value, priv->act_request);
break;
case PROP_DEVICE_TYPE:
g_value_set_uint (value, priv->type);
break;
case PROP_MANAGED:
g_value_set_boolean (value, nm_device_get_managed (self));
break;
case PROP_AUTOCONNECT:
g_value_set_boolean (value, priv->autoconnect);
break;
case PROP_FIRMWARE_MISSING:
g_value_set_boolean (value, priv->firmware_missing);
break;
case PROP_NM_PLUGIN_MISSING:
g_value_set_boolean (value, priv->nm_plugin_missing);
break;
case PROP_TYPE_DESC:
g_value_set_string (value, priv->type_desc);
break;
case PROP_RFKILL_TYPE:
g_value_set_uint (value, priv->rfkill_type);
break;
case PROP_AVAILABLE_CONNECTIONS:
array = g_ptr_array_sized_new (g_hash_table_size (priv->available_connections));
g_hash_table_iter_init (&iter, priv->available_connections);
while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL))
g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection)));
g_ptr_array_add (array, NULL);
g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
break;
case PROP_PHYSICAL_PORT_ID:
g_value_set_string (value, priv->physical_port_id);
break;
case PROP_IS_MASTER:
g_value_set_boolean (value, priv->is_master);
break;
case PROP_MASTER:
g_value_set_object (value, nm_device_get_master (self));
break;
case PROP_HW_ADDRESS:
g_value_set_string (value, priv->hw_addr);
break;
case PROP_HAS_PENDING_ACTION:
g_value_set_boolean (value, nm_device_has_pending_action (self));
break;
case PROP_METERED:
g_value_set_uint (value, priv->metered);
break;
case PROP_LLDP_NEIGHBORS:
if (priv->lldp_listener)
g_value_set_variant (value, nm_lldp_listener_get_neighbors (priv->lldp_listener));
else {
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
g_value_take_variant (value, g_variant_builder_end (&array_builder));
}
break;
case PROP_REAL:
g_value_set_boolean (value, priv->real);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_device_class_init (NMDeviceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (NMDevicePrivate));
exported_object_class->export_path = NM_DBUS_PATH "/Devices/%u";
/* Virtual methods */
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->constructed = constructed;
klass->link_changed = link_changed;
klass->is_available = is_available;
klass->act_stage1_prepare = act_stage1_prepare;
klass->act_stage2_config = act_stage2_config;
klass->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
klass->act_stage3_ip6_config_start = act_stage3_ip6_config_start;
klass->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout;
klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout;
klass->have_any_ready_slaves = have_any_ready_slaves;
klass->get_type_description = get_type_description;
klass->spec_match_list = spec_match_list;
klass->can_auto_connect = can_auto_connect;
klass->check_connection_compatible = check_connection_compatible;
klass->check_connection_available = check_connection_available;
klass->can_unmanaged_external_down = can_unmanaged_external_down;
klass->setup_start = setup_start;
klass->setup_finish = setup_finish;
klass->unrealize = unrealize;
klass->is_up = is_up;
klass->bring_up = bring_up;
klass->take_down = take_down;
klass->carrier_changed = carrier_changed;
klass->get_ip_iface_identifier = get_ip_iface_identifier;
/* Properties */
g_object_class_install_property
(object_class, PROP_UDI,
g_param_spec_string (NM_DEVICE_UDI, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IFACE,
g_param_spec_string (NM_DEVICE_IFACE, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IP_IFACE,
g_param_spec_string (NM_DEVICE_IP_IFACE, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_DRIVER,
g_param_spec_string (NM_DEVICE_DRIVER, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_DRIVER_VERSION,
g_param_spec_string (NM_DEVICE_DRIVER_VERSION, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_FIRMWARE_VERSION,
g_param_spec_string (NM_DEVICE_FIRMWARE_VERSION, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_CAPABILITIES,
g_param_spec_uint (NM_DEVICE_CAPABILITIES, "", "",
0, G_MAXUINT32, NM_DEVICE_CAP_NONE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_CARRIER,
g_param_spec_boolean (NM_DEVICE_CARRIER, "", "",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_MTU,
g_param_spec_uint (NM_DEVICE_MTU, "", "",
0, G_MAXUINT32, 1500,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IP4_ADDRESS,
g_param_spec_uint (NM_DEVICE_IP4_ADDRESS, "", "",
0, G_MAXUINT32, 0, /* FIXME */
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IP4_CONFIG,
g_param_spec_string (NM_DEVICE_IP4_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_DHCP4_CONFIG,
g_param_spec_string (NM_DEVICE_DHCP4_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IP6_CONFIG,
g_param_spec_string (NM_DEVICE_IP6_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_DHCP6_CONFIG,
g_param_spec_string (NM_DEVICE_DHCP6_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_STATE,
g_param_spec_uint (NM_DEVICE_STATE, "", "",
0, G_MAXUINT32, NM_DEVICE_STATE_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_STATE_REASON,
g_param_spec_variant (NM_DEVICE_STATE_REASON, "", "",
G_VARIANT_TYPE ("(uu)"),
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_ACTIVE_CONNECTION,
g_param_spec_string (NM_DEVICE_ACTIVE_CONNECTION, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_DEVICE_TYPE,
g_param_spec_uint (NM_DEVICE_DEVICE_TYPE, "", "",
0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_MANAGED,
g_param_spec_boolean (NM_DEVICE_MANAGED, "", "",
FALSE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_AUTOCONNECT,
g_param_spec_boolean (NM_DEVICE_AUTOCONNECT, "", "",
DEFAULT_AUTOCONNECT,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_FIRMWARE_MISSING,
g_param_spec_boolean (NM_DEVICE_FIRMWARE_MISSING, "", "",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_NM_PLUGIN_MISSING,
g_param_spec_boolean (NM_DEVICE_NM_PLUGIN_MISSING, "", "",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_TYPE_DESC,
g_param_spec_string (NM_DEVICE_TYPE_DESC, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_RFKILL_TYPE,
g_param_spec_uint (NM_DEVICE_RFKILL_TYPE, "", "",
RFKILL_TYPE_WLAN,
RFKILL_TYPE_MAX,
RFKILL_TYPE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IFINDEX,
g_param_spec_int (NM_DEVICE_IFINDEX, "", "",
0, G_MAXINT, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_AVAILABLE_CONNECTIONS,
g_param_spec_boxed (NM_DEVICE_AVAILABLE_CONNECTIONS, "", "",
G_TYPE_STRV,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_PHYSICAL_PORT_ID,
g_param_spec_string (NM_DEVICE_PHYSICAL_PORT_ID, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_IS_MASTER,
g_param_spec_boolean (NM_DEVICE_IS_MASTER, "", "",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_MASTER,
g_param_spec_object (NM_DEVICE_MASTER, "", "",
NM_TYPE_DEVICE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_HW_ADDRESS,
g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_HAS_PENDING_ACTION,
g_param_spec_boolean (NM_DEVICE_HAS_PENDING_ACTION, "", "",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDevice:metered:
*
* Whether the connection is metered.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_uint (NM_DEVICE_METERED, "", "",
0, G_MAXUINT32, NM_METERED_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_LLDP_NEIGHBORS,
g_param_spec_variant (NM_DEVICE_LLDP_NEIGHBORS, "", "",
G_VARIANT_TYPE ("aa{sv}"),
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_REAL,
g_param_spec_boolean (NM_DEVICE_REAL, "", "",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* Signals */
signals[STATE_CHANGED] =
g_signal_new ("state-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMDeviceClass, state_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 3,
G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
signals[AUTOCONNECT_ALLOWED] =
g_signal_new ("autoconnect-allowed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
autoconnect_allowed_accumulator, NULL, NULL,
G_TYPE_BOOLEAN, 0);
signals[AUTH_REQUEST] =
g_signal_new (NM_DEVICE_AUTH_REQUEST,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
/* context, connection, permission, allow_interaction, callback, user_data */
G_TYPE_NONE, 6, G_TYPE_DBUS_METHOD_INVOCATION, NM_TYPE_CONNECTION, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
signals[IP4_CONFIG_CHANGED] =
g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
signals[IP6_CONFIG_CHANGED] =
g_signal_new (NM_DEVICE_IP6_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
signals[REMOVED] =
g_signal_new (NM_DEVICE_REMOVED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[RECHECK_AUTO_ACTIVATE] =
g_signal_new (NM_DEVICE_RECHECK_AUTO_ACTIVATE,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[RECHECK_ASSUME] =
g_signal_new (NM_DEVICE_RECHECK_ASSUME,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[LINK_INITIALIZED] =
g_signal_new (NM_DEVICE_LINK_INITIALIZED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
NMDBUS_TYPE_DEVICE_SKELETON,
"Disconnect", impl_device_disconnect,
"Delete", impl_device_delete,
NULL);
2013-12-16 15:16:43 +01:00
}