diff options
| author | Michael Biebl <biebl@debian.org> | 2015-07-14 19:38:58 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2015-07-14 19:38:58 +0200 |
| commit | 50a58f0fabd8a34c1b6108a107e08abe3c1ccd24 (patch) | |
| tree | 6790165f39daee79e2b6c6617483320613493367 /src/devices | |
| parent | f408e27bccfacf347605a8d98649975a68f38a17 (diff) | |
Imported Upstream version 1.0.4 upstream/1.0.4
Diffstat (limited to 'src/devices')
40 files changed, 3126 insertions, 1786 deletions
diff --git a/src/devices/adsl/Makefile.in b/src/devices/adsl/Makefile.in index 02da85e7..6f7fe174 100644 --- a/src/devices/adsl/Makefile.in +++ b/src/devices/adsl/Makefile.in @@ -223,6 +223,7 @@ ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -336,6 +337,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index 6f34c02b..0830f85d 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -25,6 +25,7 @@ #include <gmodule.h> #include "nm-atm-manager.h" +#include "nm-setting-adsl.h" #include "nm-device-adsl.h" #include "nm-device-factory.h" #include "nm-logging.h" @@ -203,11 +204,9 @@ handle_uevent (GUdevClient *client, adsl_remove (self, device); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_ADSL; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_ADSL_SETTING_NAME) +) /*********************************************************************/ @@ -224,7 +223,7 @@ nm_atm_manager_init (NMAtmManager *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; factory_iface->start = start; } diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index e664ff48..4d2cac5b 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -73,7 +73,7 @@ typedef struct { /**************************************************************/ -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { return ( NM_DEVICE_CAP_CARRIER_DETECT @@ -144,7 +144,7 @@ set_nas_iface (NMDeviceAdsl *self, int idx, const char *name) g_return_if_fail (name != NULL); g_warn_if_fail (priv->nas_ifindex <= 0); - priv->nas_ifindex = idx > 0 ? idx : nm_platform_link_get_ifindex (name); + priv->nas_ifindex = idx > 0 ? idx : nm_platform_link_get_ifindex (NM_PLATFORM_GET, name); g_warn_if_fail (priv->nas_ifindex > 0); g_warn_if_fail (priv->nas_ifname == NULL); @@ -295,7 +295,7 @@ error: } static void -link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, NMPlatformReason reason, NMDeviceAdsl *self) +link_changed_cb (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, NMPlatformReason reason, NMDeviceAdsl *self) { if (change_type == NM_PLATFORM_SIGNAL_REMOVED) { NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); @@ -352,7 +352,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason) _LOGD (LOGD_ADSL, "ATM setup successful"); /* otherwise we're good for stage3 */ - nm_platform_link_set_up (priv->nas_ifindex); + nm_platform_link_set_up (NM_PLATFORM_GET, priv->nas_ifindex, NULL); ret = NM_ACT_STAGE_RETURN_SUCCESS; } else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) { @@ -492,7 +492,7 @@ carrier_update_cb (gpointer user_data) path = g_strdup_printf ("/sys/class/atm/%s/carrier", ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (NM_DEVICE (self)))); - carrier = (int) nm_platform_sysctl_get_int_checked (path, 10, 0, 1, -1); + carrier = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, path, 10, 0, 1, -1); g_free (path); if (carrier != -1) @@ -526,7 +526,7 @@ get_atm_index (const char *iface) path = g_strdup_printf ("/sys/class/atm/%s/atmindex", ASSERT_VALID_PATH_COMPONENT (iface)); - idx = (int) nm_platform_sysctl_get_int_checked (path, 10, 0, G_MAXINT, -1); + idx = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, path, 10, 0, G_MAXINT, -1); g_free (path); return idx; diff --git a/src/devices/bluetooth/Makefile.in b/src/devices/bluetooth/Makefile.in index b8e6dcda..6233a751 100644 --- a/src/devices/bluetooth/Makefile.in +++ b/src/devices/bluetooth/Makefile.in @@ -243,6 +243,7 @@ ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -356,6 +357,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index fe1a97bb..d5426052 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -28,6 +28,7 @@ #include "nm-core-internal.h" +#include "nm-bt-error.h" #include "nm-bluez-common.h" #include "nm-bluez-device.h" #include "nm-logging.h" @@ -436,8 +437,6 @@ nm_bluez_device_disconnect (NMBluezDevice *self) } else if (priv->bluez_version == 5) { #if WITH_BLUEZ5_DUN nm_bluez5_dun_cleanup (priv->b5_dun_context); -#else - g_assert_not_reached (); #endif priv->connected = FALSE; goto out; @@ -559,7 +558,11 @@ nm_bluez_device_connect_async (NMBluezDevice *self, priv->b5_dun_context = nm_bluez5_dun_new (priv->adapter_address, priv->address); nm_bluez5_dun_connect (priv->b5_dun_context, bluez5_dun_connect_cb, simple); #else - g_assert_not_reached (); + g_simple_async_result_set_error (simple, + NM_BT_ERROR, + NM_BT_ERROR_DUN_CONNECT_FAILED, + "NetworkManager built without support for Bluez 5"); + g_simple_async_result_complete (simple); #endif return; } diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index e176a4b4..df4eb46d 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -29,6 +29,7 @@ #include "nm-logging.h" #include "nm-bluez-manager.h" #include "nm-device-factory.h" +#include "nm-setting-bluetooth.h" #include "nm-bluez4-manager.h" #include "nm-bluez5-manager.h" #include "nm-bluez-device.h" @@ -37,6 +38,7 @@ #include "nm-device-bt.h" #include "nm-dbus-manager.h" +#include "nm-platform.h" typedef struct { int bluez_version; @@ -368,11 +370,10 @@ start (NMDeviceFactory *factory) check_bluez_and_try_setup (NM_BLUEZ_MANAGER (factory)); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_BT; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BNEP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BLUETOOTH_SETTING_NAME) +) /*********************************************************************/ @@ -405,10 +406,19 @@ nm_bluez_manager_init (NMBluezManager *self) g_assert (priv->provider); } +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +{ + g_warn_if_fail (plink->type == NM_LINK_TYPE_BNEP); + *out_ignore = TRUE; + return NULL; +} + static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; + factory_iface->new_link = new_link; factory_iface->start = start; } diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 61371ddd..88033e2e 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -124,7 +124,7 @@ get_connection_bt_type (NMConnection *connection) return NM_BT_CAPABILITY_NONE; } -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { return NM_DEVICE_CAP_IS_NON_KERNEL; @@ -479,6 +479,13 @@ device_state_changed (NMDevice *device, if (priv->modem) nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); + + /* Need to recheck available connections whenever MM appears or disappears, + * since the device could be both DUN and NAP capable and thus may not + * change state (which rechecks available connections) when MM comes and goes. + */ + if (priv->mm_running && (priv->capabilities & NM_BT_CAPABILITY_DUN)) + nm_device_recheck_available_connections (device); } static void @@ -944,60 +951,19 @@ is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) } static void -handle_availability_change (NMDeviceBt *self, - gboolean old_available, - NMDeviceStateReason unavailable_reason) -{ - NMDevice *device = NM_DEVICE (self); - NMDeviceState state; - gboolean available; - - state = nm_device_get_state (device); - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - _LOGD (LOGD_BT, "availability blocked by UNMANAGED state"); - return; - } - - available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - if (available == old_available) - return; - - if (available) { - if (state != NM_DEVICE_STATE_UNAVAILABLE) - _LOGW (LOGD_CORE | LOGD_BT, "not in expected unavailable state!"); - - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } else { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - unavailable_reason); - } -} - -static void set_mm_running (NMDeviceBt *self, gboolean running) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean old_available; - if (priv->mm_running == running) - return; - - _LOGD (LOGD_BT, "ModemManager now %s", - running ? "available" : "unavailable"); + if (priv->mm_running != running) { + _LOGD (LOGD_BT, "ModemManager now %s", + running ? "available" : "unavailable"); - old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - priv->mm_running = running; - handle_availability_change (self, old_available, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); - - /* Need to recheck available connections whenever MM appears or disappears, - * since the device could be both DUN and NAP capable and thus may not - * change state (which rechecks available connections) when MM comes and goes. - */ - if (priv->capabilities & NM_BT_CAPABILITY_DUN) - nm_device_recheck_available_connections (NM_DEVICE (self)); + priv->mm_running = running; + nm_device_queue_recheck_available (NM_DEVICE (self), + NM_DEVICE_STATE_REASON_NONE, + NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); + } } static void diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 0b2c97d1..7f139424 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -37,6 +37,7 @@ #include "nm-enum-types.h" #include "nm-device-factory.h" #include "nm-core-internal.h" +#include "nm-ip4-config.h" #include "nm-device-bond-glue.h" @@ -60,18 +61,16 @@ enum { /******************************************************************/ -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { - return NM_DEVICE_CAP_CARRIER_DETECT; + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } static gboolean is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) { - if (NM_DEVICE_GET_CLASS (dev)->is_up) - return NM_DEVICE_GET_CLASS (dev)->is_up (dev); - return FALSE; + return TRUE; } static gboolean @@ -144,7 +143,7 @@ set_bond_attr (NMDevice *device, const char *attr, const char *value) gboolean ret; int ifindex = nm_device_get_ifindex (device); - ret = nm_platform_master_set_option (ifindex, attr, value); + ret = nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, attr, value); if (!ret) _LOGW (LOGD_HW, "failed to set bonding attribute '%s' to '%s'", attr, value); return ret; @@ -178,7 +177,7 @@ update_connection (NMDevice *device, NMConnection *connection) /* Read bond options from sysfs and update the Bond setting to match */ options = nm_setting_bond_get_valid_options (s_bond); while (options && *options) { - gs_free char *value = nm_platform_master_get_option (ifindex, *options); + gs_free char *value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, *options); const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options); if (value && !ignore_if_zero (*options, value) && (g_strcmp0 (value, defvalue) != 0)) { @@ -334,7 +333,7 @@ apply_bonding_config (NMDevice *device) } /* Clear ARP targets */ - contents = nm_platform_master_get_option (ifindex, "arp_ip_target"); + contents = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "arp_ip_target"); set_arp_targets (device, contents, " \n", "-"); g_free (contents); @@ -377,6 +376,25 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) return ret; } +static void +ip4_config_pre_commit (NMDevice *self, NMIP4Config *config) +{ + NMConnection *connection; + NMSettingWired *s_wired; + guint32 mtu; + + connection = nm_device_get_connection (self); + g_assert (connection); + s_wired = nm_connection_get_setting_wired (connection); + + if (s_wired) { + /* MTU override */ + mtu = nm_setting_wired_get_mtu (s_wired); + if (mtu) + nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER); + } +} + static gboolean enslave_slave (NMDevice *device, NMDevice *slave, @@ -391,7 +409,8 @@ enslave_slave (NMDevice *device, if (configure) { nm_device_take_down (slave, TRUE); - success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device), + success = nm_platform_link_enslave (NM_PLATFORM_GET, + nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); nm_device_bring_up (slave, TRUE, &no_firmware); @@ -415,7 +434,8 @@ release_slave (NMDevice *device, gboolean success = TRUE, no_firmware = FALSE; if (configure) { - success = nm_platform_link_release (nm_device_get_ip_ifindex (device), + success = nm_platform_link_release (NM_PLATFORM_GET, + nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); if (success) { @@ -510,6 +530,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->master_update_slave_connection = master_update_slave_connection; parent_class->act_stage1_prepare = act_stage1_prepare; + parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; @@ -532,18 +553,15 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) #define NM_BOND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BOND_FACTORY, NMBondFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_BOND) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bonding", - NM_DEVICE_TYPE_DESC, "Bond", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, - NM_DEVICE_IS_MASTER, TRUE, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_DRIVER, "bonding", + NM_DEVICE_TYPE_DESC, "Bond", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, + NM_DEVICE_IS_MASTER, TRUE, + NULL); } static NMDevice * @@ -552,19 +570,18 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - const char *iface; - - if (!nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) - return NULL; - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); - - if ( !nm_platform_bond_add (iface) - && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_BOND, "(%s): failed to create bonding master interface for '%s': %s", - iface, nm_connection_get_id (connection), - nm_platform_get_error_msg ()); + const char *iface = nm_connection_get_interface_name (connection); + NMPlatformError plerr; + + g_assert (iface); + + plerr = nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bond interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); return NULL; } @@ -577,7 +594,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(BOND, Bond, bond, +NM_DEVICE_FACTORY_DEFINE_INTERNAL (BOND, Bond, bond, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BOND) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BOND_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index a2ed4b41..e1cafd60 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -59,18 +59,16 @@ enum { /******************************************************************/ -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { - return NM_DEVICE_CAP_CARRIER_DETECT; + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } static gboolean is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) { - if (NM_DEVICE_GET_CLASS (dev)->is_up) - return NM_DEVICE_GET_CLASS (dev)->is_up (dev); - return FALSE; + return TRUE; } static gboolean @@ -213,9 +211,9 @@ commit_option (NMDevice *device, NMSetting *setting, const Option *option, gbool value = g_strdup_printf ("%u", uval); if (slave) - nm_platform_slave_set_option (ifindex, option->sysname, value); + nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); else - nm_platform_master_set_option (ifindex, option->sysname, value); + nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); } static void @@ -259,7 +257,7 @@ update_connection (NMDevice *device, NMConnection *connection) } for (option = master_options; option->name; option++) { - gs_free char *str = nm_platform_master_get_option (ifindex, option->sysname); + gs_free char *str = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, option->sysname); int value; if (str) { @@ -298,7 +296,7 @@ master_update_slave_connection (NMDevice *device, } for (option = slave_options; option->name; option++) { - gs_free char *str = nm_platform_slave_get_option (ifindex_slave, option->sysname); + gs_free char *str = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex_slave, option->sysname); int value; if (str) { @@ -346,7 +344,7 @@ enslave_slave (NMDevice *device, NMDeviceBridge *self = NM_DEVICE_BRIDGE (device); if (configure) { - if (!nm_platform_link_enslave (nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave))) + if (!nm_platform_link_enslave (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave))) return FALSE; commit_slave_options (slave, nm_connection_get_setting_bridge_port (connection)); @@ -372,7 +370,8 @@ release_slave (NMDevice *device, gboolean success = TRUE; if (configure) { - success = nm_platform_link_release (nm_device_get_ip_ifindex (device), + success = nm_platform_link_release (NM_PLATFORM_GET, + nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); if (success) { @@ -477,18 +476,15 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) #define NM_BRIDGE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BRIDGE_FACTORY, NMBridgeFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_BRIDGE) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bridge", - NM_DEVICE_TYPE_DESC, "Bridge", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, - NM_DEVICE_IS_MASTER, TRUE, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_DRIVER, "bridge", + NM_DEVICE_TYPE_DESC, "Bridge", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, + NM_DEVICE_IS_MASTER, TRUE, + NULL); } static NMDevice * @@ -497,21 +493,16 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); NMSettingBridge *s_bridge; const char *mac_address_str; guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; + NMPlatformError plerr; - if (!nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) - return NULL; - - g_return_val_if_fail (connection != NULL, NULL); - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); s_bridge = nm_connection_get_setting_bridge (connection); - g_return_val_if_fail (s_bridge, NULL); + g_assert (s_bridge); mac_address_str = nm_setting_bridge_get_mac_address (s_bridge); if (mac_address_str) { @@ -519,13 +510,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, mac_address_str = NULL; } - if ( !nm_platform_bridge_add (iface, + plerr = nm_platform_bridge_add (NM_PLATFORM_GET, + iface, mac_address_str ? mac_address : NULL, - mac_address_str ? ETH_ALEN : 0) - && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_BRIDGE, "(%s): failed to create bridge master interface for '%s': %s", - iface, nm_connection_get_id (connection), - nm_platform_get_error_msg ()); + mac_address_str ? ETH_ALEN : 0, + NULL); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bridge interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); return NULL; } @@ -538,7 +533,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(BRIDGE, Bridge, bridge, +NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index ac408d3d..af2cb8f2 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -26,10 +26,6 @@ #include <netinet/in.h> #include <string.h> #include <stdlib.h> -#include <linux/sockios.h> -#include <linux/ethtool.h> -#include <linux/version.h> -#include <sys/ioctl.h> #include <unistd.h> #include <errno.h> @@ -48,6 +44,7 @@ #include "nm-enum-types.h" #include "nm-dbus-manager.h" #include "nm-platform.h" +#include "nm-platform-utils.h" #include "nm-dcb.h" #include "nm-settings-connection.h" #include "nm-config.h" @@ -55,6 +52,7 @@ #include "nm-connection-provider.h" #include "nm-device-factory.h" #include "nm-core-internal.h" +#include "NetworkManagerUtils.h" #include "nm-device-ethernet-glue.h" @@ -99,9 +97,6 @@ typedef enum { } DcbWait; typedef struct { - char * perm_hw_addr; /* Permanent MAC address */ - char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ - guint32 speed; Supplicant supplicant; @@ -156,26 +151,21 @@ static void _update_s390_subchannels (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - GUdevClient *client; GUdevDevice *dev; GUdevDevice *parent = NULL; const char *parent_path, *item, *driver; - const char *subsystems[] = { "net", NULL }; + int ifindex; GDir *dir; GError *error = NULL; - client = g_udev_client_new (subsystems); - if (!client) { - _LOGW (LOGD_DEVICE | LOGD_HW, "failed to initialize GUdev client"); - return; - } - - dev = g_udev_client_query_by_subsystem_and_name (client, "net", - nm_device_get_iface (NM_DEVICE (self))); + ifindex = nm_device_get_ifindex (NM_DEVICE (self)); + dev = (GUdevDevice *) nm_platform_link_get_udev_device (NM_PLATFORM_GET, ifindex); if (!dev) { - _LOGW (LOGD_DEVICE | LOGD_HW, "failed to find device with udev"); + _LOGW (LOGD_DEVICE | LOGD_HW, "failed to find device %d '%s' with udev", + ifindex, str_if_set (nm_device_get_iface (NM_DEVICE (self)), "(null)")); goto out; } + g_object_ref (dev); /* Try for the "ccwgroup" parent */ parent = g_udev_device_get_parent_with_subsystem (dev, "ccwgroup", NULL); @@ -210,7 +200,7 @@ _update_s390_subchannels (NMDeviceEthernet *self) || !strcmp (item, "portno")) { char *path, *value; path = g_strdup_printf ("%s/%s", parent_path, item); - value = nm_platform_sysctl_get (path); + value = nm_platform_sysctl_get (NM_PLATFORM_GET, path); if (value && *value) g_hash_table_insert (priv->s390_options, g_strdup (item), g_strdup (value)); else @@ -247,7 +237,6 @@ out: g_object_unref (parent); if (dev) g_object_unref (dev); - g_object_unref (client); } static GObject* @@ -263,7 +252,7 @@ constructor (GType type, if (object) { #ifndef G_DISABLE_ASSERT int ifindex = nm_device_get_ifindex (NM_DEVICE (object)); - NMLinkType link_type = nm_platform_link_get_type (ifindex); + NMLinkType link_type = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex); g_assert ( link_type == NM_LINK_TYPE_ETHERNET || link_type == NM_LINK_TYPE_VETH @@ -310,72 +299,12 @@ nm_device_ethernet_init (NMDeviceEthernet *self) priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } -static void -update_permanent_hw_address (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - struct ifreq req; - struct ethtool_perm_addr *epaddr = NULL; - int fd, ret, errsv; - const char *mac; - - g_return_if_fail (priv->perm_hw_addr == NULL); - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW, "couldn't open control socket."); - return; - } - - /* Get permanent MAC address */ - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); - - epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = ETH_ALEN; - req.ifr_data = (void *) epaddr; - - errno = 0; - ret = ioctl (fd, SIOCETHTOOL, &req); - errsv = errno; - if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) { - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", errsv); - /* Fall back to current address */ - mac = nm_device_get_hw_address (dev); - if (mac) - nm_utils_hwaddr_aton (mac, epaddr->data, ETH_ALEN); - else - memset (epaddr->data, 0, ETH_ALEN); - } - - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN); - - g_free (epaddr); - close (fd); -} - -static void -update_initial_hw_address (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - - /* This sets initial MAC address from current MAC address. It should only - * be called from NMDevice constructor() to really get the initial address. - */ - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev)); - - _LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr); -} - -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - if (nm_platform_link_supports_carrier_detect (nm_device_get_ifindex (device))) + if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, nm_device_get_ifindex (device))) return NM_DEVICE_CAP_CARRIER_DETECT; else { _LOGI (LOGD_HW, "driver '%s' does not support carrier detection.", @@ -421,7 +350,6 @@ static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingWired *s_wired; if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection)) @@ -438,7 +366,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (s_wired) { - const char *mac; + const char *mac, *perm_hw_addr; gboolean try_mac = TRUE; const char * const *mac_blacklist; int i; @@ -446,21 +374,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!match_subchans (self, s_wired, &try_mac)) return FALSE; + perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wired_get_mac_address (s_wired); - if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1)) - return FALSE; - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); + if (perm_hw_addr) { + if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) return FALSE; - } - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1)) - return FALSE; - } + /* Check for MAC address blacklist */ + mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); + for (i = 0; mac_blacklist[i]; i++) { + if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { + g_warn_if_reached (); + return FALSE; + } + + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + return FALSE; + } + } else if (mac) + return FALSE; } return TRUE; @@ -1160,7 +1092,7 @@ dcb_state (NMDevice *device, gboolean timeout) g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_CONFIG); - carrier = nm_platform_link_is_connected (nm_device_get_ifindex (device)); + carrier = nm_platform_link_is_connected (NM_PLATFORM_GET, nm_device_get_ifindex (device)); _LOGD (LOGD_DCB, "dcb_state() wait %d carrier %d timeout %d", priv->dcb_wait, carrier, timeout); switch (priv->dcb_wait) { @@ -1278,7 +1210,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB); if (s_dcb) { /* lldpad really really wants the carrier to be up */ - if (nm_platform_link_is_connected (nm_device_get_ifindex (device))) { + if (nm_platform_link_is_connected (NM_PLATFORM_GET, nm_device_get_ifindex (device))) { if (!dcb_enable (device)) { *reason = NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED; return NM_ACT_STAGE_RETURN_FAILURE; @@ -1391,8 +1323,8 @@ deactivate (NMDevice *device) NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s (); /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_ETHER); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_ETHER); } static gboolean @@ -1402,10 +1334,10 @@ complete_connection (NMDevice *device, const GSList *existing_connections, GError **error) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired; NMSettingPppoe *s_pppoe; const char *setting_mac; + const char *perm_hw_addr; s_pppoe = nm_connection_get_setting_pppoe (connection); @@ -1432,21 +1364,22 @@ complete_connection (NMDevice *device, nm_connection_add_setting (connection, NM_SETTING (s_wired)); } - setting_mac = nm_setting_wired_get_mac_address (s_wired); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); - return FALSE; - } - } else { - if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) { + perm_hw_addr = nm_device_get_permanent_hw_address (device); + if (perm_hw_addr) { + setting_mac = nm_setting_wired_get_mac_address (s_wired); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match device")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); + return FALSE; + } + } else { g_object_set (G_OBJECT (s_wired), - NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, + NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); } } @@ -1463,7 +1396,7 @@ new_default_connection (NMDevice *self) const char *hw_address; char *defname, *uuid; - if (!nm_config_get_ethernet_can_auto_default (nm_config_get (), self)) + if (nm_config_get_no_auto_default_for_device (nm_config_get (), self)) return NULL; hw_address = nm_device_get_hw_address (self); @@ -1495,15 +1428,19 @@ new_default_connection (NMDevice *self) return connection; } -static gboolean +static NMMatchSpecMatchType spec_match_list (NMDevice *device, const GSList *specs) { + NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m; NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); - if (priv->subchannels && nm_match_spec_s390_subchannels (specs, priv->subchannels)) - return TRUE; - - return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs); + if (priv->subchannels) + matched = nm_match_spec_s390_subchannels (specs, priv->subchannels); + if (matched != NM_MATCH_SPEC_NEG_MATCH) { + m = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs); + matched = MAX (matched, m); + } + return matched; } static void @@ -1511,6 +1448,7 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired = nm_connection_get_setting_wired (connection); + const char *perm_hw_addr = nm_device_get_permanent_hw_address (device); const char *mac = nm_device_get_hw_address (device); const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; GHashTableIter iter; @@ -1524,11 +1462,11 @@ update_connection (NMDevice *device, NMConnection *connection) /* If the device reports a permanent address, use that for the MAC address * and the current MAC, if different, is the cloned MAC. */ - if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) { - g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, NULL); + if (perm_hw_addr) { + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); mac_prop = NULL; - if (mac && !nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, mac, -1)) + if (mac && !nm_utils_hwaddr_matches (perm_hw_addr, -1, mac, -1)) mac_prop = NM_SETTING_WIRED_CLONED_MAC_ADDRESS; } @@ -1562,37 +1500,10 @@ get_link_speed (NMDevice *device) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - struct ifreq ifr; - struct ethtool_cmd edata = { - .cmd = ETHTOOL_GSET, - }; guint32 speed; - int fd; - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW | LOGD_ETHER, "couldn't open ethtool control socket."); + if (!nmp_utils_ethtool_get_link_speed (nm_device_get_iface (device), &speed)) return; - } - - memset (&ifr, 0, sizeof (struct ifreq)); - strncpy (ifr.ifr_name, nm_device_get_iface (device), IFNAMSIZ); - ifr.ifr_data = (char *) &edata; - - if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { - close (fd); - return; - } - close (fd); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - speed = edata.speed; -#else - speed = ethtool_cmd_speed (&edata); -#endif - if (speed == G_MAXUINT16 || speed == G_MAXUINT32) - speed = 0; - if (priv->speed == speed) return; @@ -1612,6 +1523,17 @@ carrier_changed (NMDevice *device, gboolean carrier) } static void +link_changed (NMDevice *device, NMPlatformLink *info) +{ + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + + NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info); + if (!priv->subchan1 && info->initialized) + _update_s390_subchannels (self); +} + +static void dispose (GObject *object) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); @@ -1634,8 +1556,6 @@ finalize (GObject *object) NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - g_free (priv->perm_hw_addr); - g_free (priv->initial_hw_addr); g_clear_object (&priv->supplicant.mgr); g_free (priv->subchan1); g_free (priv->subchan2); @@ -1656,7 +1576,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, priv->perm_hw_addr); + g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (object))); break; case PROP_SPEED: g_value_set_uint (value, priv->speed); @@ -1696,8 +1616,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->update_permanent_hw_address = update_permanent_hw_address; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; parent_class->new_default_connection = new_default_connection; @@ -1710,6 +1628,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->spec_match_list = spec_match_list; parent_class->update_connection = update_connection; parent_class->carrier_changed = carrier_changed; + parent_class->link_changed = link_changed; parent_class->state_changed = device_state_changed; @@ -1739,19 +1658,18 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) #define NM_ETHERNET_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_FACTORY, NMEthernetFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_ETHERNET) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Ethernet", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Ethernet", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(ETHERNET, Ethernet, ethernet, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (ETHERNET, Ethernet, ethernet, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_ETHERNET) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_PPPOE_SETTING_NAME), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index abfb8d4a..13034808 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -19,8 +19,19 @@ */ #include "config.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> + +#include <gmodule.h> #include "nm-device-factory.h" +#include "nm-logging.h" +#include "nm-platform.h" + +const NMLinkType _nm_device_factory_no_default_links[] = { NM_LINK_TYPE_NONE }; +const char *_nm_device_factory_no_default_settings[] = { NULL }; enum { DEVICE_ADDED, @@ -29,130 +40,509 @@ enum { }; static guint signals[LAST_SIGNAL] = { 0 }; -static GSList *internal_types = NULL; +gboolean +nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component) +{ + gboolean consumed = FALSE; + + g_signal_emit (factory, signals[COMPONENT_ADDED], 0, component, &consumed); + return consumed; +} void -_nm_device_factory_internal_register_type (GType factory_type) +nm_device_factory_get_supported_types (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types) { - g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL); - internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type)); + const NMLinkType *link_types_fallback; + const char **setting_types_fallback; + + g_return_if_fail (factory != NULL); + + if (!out_link_types) + out_link_types = &link_types_fallback; + if (!out_setting_types) + out_setting_types = &setting_types_fallback; + + NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_supported_types (factory, + out_link_types, + out_setting_types); } -const GSList * -nm_device_factory_get_internal_factory_types (void) +void +nm_device_factory_start (NMDeviceFactory *factory) { - return internal_types; + g_return_if_fail (factory != NULL); + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->start) + NM_DEVICE_FACTORY_GET_INTERFACE (factory)->start (factory); } -gboolean -nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component) +NMDevice * +nm_device_factory_new_link (NMDeviceFactory *factory, + NMPlatformLink *plink, + gboolean *out_ignore, + GError **error) { - gboolean consumed = FALSE; + NMDeviceFactory *interface; + const NMLinkType *link_types = NULL; + const char **setting_types = NULL; + int i; - g_signal_emit (factory, signals[COMPONENT_ADDED], 0, component, &consumed); - return consumed; + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (plink != NULL, NULL); + + /* Ensure the factory can create interfaces for this connection */ + nm_device_factory_get_supported_types (factory, &link_types, &setting_types); + for (i = 0; link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + if (plink->type == link_types[i]) + break; + } + + if (link_types[i] == NM_LINK_TYPE_UNKNOWN) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Device factory %s does not support link type %s (%d)", + G_OBJECT_TYPE_NAME (factory), + plink->kind, plink->type); + return NULL; + } + + interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); + if (!interface->new_link) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Device factory %s cannot manage new devices", + G_OBJECT_TYPE_NAME (factory)); + return NULL; + } + + return interface->new_link (factory, plink, out_ignore, error); } -static void -interface_init (gpointer g_iface) +NMDevice * +nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, + NMConnection *connection, + NMDevice *parent, + GError **error) { - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; + NMDeviceFactory *interface; + const char **setting_types = NULL; + gboolean found = FALSE; + int i; - if (G_LIKELY (initialized)) - return; + g_return_val_if_fail (factory, NULL); + g_return_val_if_fail (connection, NULL); + g_return_val_if_fail (!error || !*error, NULL); + + /* Ensure the factory can create interfaces for this connection */ + nm_device_factory_get_supported_types (factory, NULL, &setting_types); + for (i = 0; setting_types && setting_types[i]; i++) { + if (nm_connection_is_type (connection, setting_types[i])) { + found = TRUE; + break; + } + } + + if (!found) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Device factory %s does not support connection type %s", + G_OBJECT_TYPE_NAME (factory), + nm_connection_get_connection_type (connection)); + return NULL; + } + + interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); + if (!interface->create_virtual_device_for_connection) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Device factory %s cannot create virtual devices", + G_OBJECT_TYPE_NAME (factory)); + return NULL; + } + + return interface->create_virtual_device_for_connection (factory, connection, parent, error); +} + +const char * +nm_device_factory_get_connection_parent (NMDeviceFactory *factory, + NMConnection *connection) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + if (!nm_connection_is_virtual (connection)) + return NULL; + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent (factory, connection); + return NULL; +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *iface; + + /* For any other virtual connection, NMSettingConnection:interface-name is + * the virtual device name. + */ + iface = nm_connection_get_interface_name (connection); + g_return_val_if_fail (iface != NULL, NULL); + return g_strdup (iface); +} + +char * +nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + if (!nm_connection_is_virtual (connection)) + return NULL; + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name (factory, connection, parent_iface); + return NULL; +} + +/*******************************************************************/ + +static void +default_init (NMDeviceFactory *factory_iface) +{ + factory_iface->get_virtual_iface_name = get_virtual_iface_name; /* Signals */ signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, - iface_type, + NM_TYPE_DEVICE_FACTORY, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMDeviceFactory, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, NM_TYPE_DEVICE); signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, - iface_type, + NM_TYPE_DEVICE_FACTORY, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMDeviceFactory, component_added), g_signal_accumulator_true_handled, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); - - initialized = TRUE; } GType nm_device_factory_get_type (void) { - static GType device_factory_type = 0; + static volatile gsize g_define_type_id__volatile = 0; + if (g_once_init_enter (&g_define_type_id__volatile)) { + GType g_define_type_id = + g_type_register_static_simple (G_TYPE_INTERFACE, + g_intern_static_string ("NMDeviceFactory"), + sizeof (NMDeviceFactory), + (GClassInitFunc) default_init, + 0, + (GInstanceInitFunc) NULL, + (GTypeFlags) 0); + g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + return g_define_type_id__volatile; +} + +/*******************************************************************/ + +static GSList *internal_types = NULL; +static GHashTable *factories_by_link = NULL; +static GHashTable *factories_by_setting = NULL; + +void +_nm_device_factory_internal_register_type (GType factory_type) +{ + g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL); + internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type)); +} + +static void __attribute__((destructor)) +_cleanup (void) +{ + g_clear_pointer (&internal_types, g_slist_free); + g_clear_pointer (&factories_by_link, g_hash_table_unref); + g_clear_pointer (&factories_by_setting, g_hash_table_unref); +} - if (!device_factory_type) { - const GTypeInfo device_factory_info = { - sizeof (NMDeviceFactory), /* class_size */ - interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; +static NMDeviceFactory * +find_factory (const NMLinkType *needle_link_types, + const char **needle_setting_types) +{ + NMDeviceFactory *found; + guint i; - device_factory_type = g_type_register_static (G_TYPE_INTERFACE, - "NMDeviceFactory", - &device_factory_info, - 0); - g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); + g_return_val_if_fail (factories_by_link, NULL); + g_return_val_if_fail (factories_by_setting, NULL); + + /* NMLinkType search */ + for (i = 0; needle_link_types && needle_link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + found = g_hash_table_lookup (factories_by_link, GUINT_TO_POINTER (needle_link_types[i])); + if (found) + return found; + } + + /* NMSetting name search */ + for (i = 0; needle_setting_types && needle_setting_types[i]; i++) { + found = g_hash_table_lookup (factories_by_setting, needle_setting_types[i]); + if (found) + return found; } - return device_factory_type; + return NULL; } -NMDeviceType -nm_device_factory_get_device_type (NMDeviceFactory *factory) +NMDeviceFactory * +nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type) { - g_return_val_if_fail (factory != NULL, NM_DEVICE_TYPE_UNKNOWN); + const NMLinkType ltypes[2] = { link_type, NM_LINK_TYPE_NONE }; - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_device_type (factory); + if (link_type == NM_LINK_TYPE_UNKNOWN) + return NULL; + g_return_val_if_fail (link_type > NM_LINK_TYPE_UNKNOWN, NULL); + return find_factory (ltypes, NULL); +} + +NMDeviceFactory * +nm_device_factory_manager_find_factory_for_connection (NMConnection *connection) +{ + const char *stypes[2] = { nm_connection_get_connection_type (connection), NULL }; + + g_assert (stypes[0]); + return find_factory (NULL, stypes); } void -nm_device_factory_start (NMDeviceFactory *factory) +nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) { - g_return_if_fail (factory != NULL); + GHashTableIter iter; + NMDeviceFactory *factory; + GSList *list_iter, *list = NULL; - if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->start) - NM_DEVICE_FACTORY_GET_INTERFACE (factory)->start (factory); + g_return_if_fail (factories_by_link); + g_return_if_fail (factories_by_setting); + + g_hash_table_iter_init (&iter, factories_by_link); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } + + g_hash_table_iter_init (&iter, factories_by_setting); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } + + for (list_iter = list; list_iter; list_iter = list_iter->next) + callback (list_iter->data, user_data); + + g_slist_free (list); } -NMDevice * -nm_device_factory_new_link (NMDeviceFactory *factory, - NMPlatformLink *plink, - GError **error) +#define PLUGIN_PREFIX "libnm-device-plugin-" +#define PLUGIN_PATH_TAG "NMManager-plugin-path" + +struct read_device_factory_paths_data { + char *path; + struct stat st; +}; + +static gint +read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) { - g_return_val_if_fail (factory != NULL, NULL); - g_return_val_if_fail (plink != NULL, NULL); + const struct read_device_factory_paths_data *da = a; + const struct read_device_factory_paths_data *db = b; + time_t ta, tb; - if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link) - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link (factory, plink, error); - return NULL; + ta = MAX (da->st.st_mtime, da->st.st_ctime); + tb = MAX (db->st.st_mtime, db->st.st_ctime); + + if (ta < tb) + return 1; + if (ta > tb) + return -1; + return 0; } -NMDevice * -nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) +static char** +read_device_factory_paths (void) { - NMDeviceFactory *interface; + GDir *dir; + GError *error = NULL; + const char *item; + GArray *paths; + char **result; + guint i; - g_return_val_if_fail (factory, NULL); - g_return_val_if_fail (connection, NULL); - g_return_val_if_fail (!error || !*error, NULL); + dir = g_dir_open (NMPLUGINDIR, 0, &error); + if (!dir) { + nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s", + NMPLUGINDIR, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + return NULL; + } - interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); - if (interface->create_virtual_device_for_connection) - return interface->create_virtual_device_for_connection (factory, connection, parent, error); - return NULL; + paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data)); + + while ((item = g_dir_read_name (dir))) { + int errsv; + struct read_device_factory_paths_data data; + + if (!g_str_has_prefix (item, PLUGIN_PREFIX)) + continue; + if (g_str_has_suffix (item, ".la")) + continue; + + data.path = g_build_filename (NMPLUGINDIR, item, NULL); + + if (stat (data.path, &data.st) != 0) { + errsv = errno; + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv)); + goto NEXT; + } + if (!S_ISREG (data.st.st_mode)) + goto NEXT; + if (data.st.st_uid != 0) { + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path); + goto NEXT; + } + if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path); + goto NEXT; + } + + g_array_append_val (paths, data); + continue; +NEXT: + g_free (data.path); + } + g_dir_close (dir); + + /* sort filenames by modification time. */ + g_array_sort (paths, read_device_factory_paths_sort_fcn); + + result = g_new (char *, paths->len + 1); + for (i = 0; i < paths->len; i++) + result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path; + result[i] = NULL; + + g_array_free (paths, TRUE); + return result; +} + +static gboolean +_add_factory (NMDeviceFactory *factory, + gboolean check_duplicates, + const char *path, + NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + NMDeviceFactory *found = NULL; + const NMLinkType *link_types = NULL; + const char **setting_types = NULL; + int i; + + g_return_val_if_fail (factories_by_link, FALSE); + g_return_val_if_fail (factories_by_setting, FALSE); + + nm_device_factory_get_supported_types (factory, &link_types, &setting_types); + if (check_duplicates) { + found = find_factory (link_types, setting_types); + if (found) { + nm_log_warn (LOGD_HW, "Loading device plugin failed: multiple plugins " + "for same type (using '%s' instead of '%s')", + (char *) g_object_get_data (G_OBJECT (found), PLUGIN_PATH_TAG), + path); + return FALSE; + } + } + + g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, g_strdup (path), g_free); + for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) + g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory)); + for (i = 0; setting_types && setting_types[i]; i++) + g_hash_table_insert (factories_by_setting, (char *) setting_types[i], g_object_ref (factory)); + + callback (factory, user_data); + + nm_log_info (LOGD_HW, "Loaded device plugin: %s (%s)", G_OBJECT_TYPE_NAME (factory), path); + return TRUE; +} + +void +nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + NMDeviceFactory *factory; + const GSList *iter; + GError *error = NULL; + char **path, **paths; + + g_return_if_fail (factories_by_link == NULL); + g_return_if_fail (factories_by_setting == NULL); + + factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + /* Register internal factories first */ + for (iter = internal_types; iter; iter = iter->next) { + GType ftype = (GType) GPOINTER_TO_SIZE (iter->data); + + factory = (NMDeviceFactory *) g_object_new (ftype, NULL); + g_assert (factory); + _add_factory (factory, FALSE, "internal", callback, user_data); + } + + paths = read_device_factory_paths (); + if (!paths) + return; + + for (path = paths; *path; path++) { + GModule *plugin; + NMDeviceFactoryCreateFunc create_func; + const char *item; + + item = strrchr (*path, '/'); + g_assert (item); + + plugin = g_module_open (*path, G_MODULE_BIND_LOCAL); + + if (!plugin) { + nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ()); + continue; + } + + if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); + g_module_close (plugin); + continue; + } + + factory = create_func (&error); + if (!factory) { + nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", + item, error ? error->message : "unknown"); + g_clear_error (&error); + g_module_close (plugin); + continue; + } + g_clear_error (&error); + + if (_add_factory (factory, TRUE, g_module_name (plugin), callback, user_data)) + g_module_make_resident (plugin); + else + g_module_close (plugin); + + g_object_unref (factory); + } + g_strfreev (paths); } diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index ce672b8b..34c056d2 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -66,14 +66,19 @@ struct _NMDeviceFactory { GTypeInterface g_iface; /** - * get_device_type: + * get_supported_types: * @factory: the #NMDeviceFactory + * @out_link_types: on return, a %NM_LINK_TYPE_NONE terminated + * list of #NMLinkType that the plugin supports + * @out_setting_types: on return, a %NULL terminated list of + * base-type #NMSetting names that the plugin can create devices for * - * This function MUST be implemented. - * - * Returns: the #NMDeviceType that this plugin creates + * Returns the #NMLinkType and #NMSetting names that this plugin + * supports. This function MUST be implemented. */ - NMDeviceType (*get_device_type) (NMDeviceFactory *factory); + void (*get_supported_types) (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types); /** * start: @@ -87,20 +92,27 @@ struct _NMDeviceFactory { /** * new_link: * @factory: the #NMDeviceFactory - * @link: the new link + * @plink: the new link + * @out_ignore: on return, %TRUE if the link should be ignored * @error: error if the link could be claimed but an error occurred * * The NetworkManager core was notified of a new link which the plugin * may want to claim and create a #NMDevice subclass for. If the link - * represents a device the factory is capable of claiming, but the device - * could not be created, %NULL should be returned and @error should be set. - * %NULL should always be returned and @error should never be set if the - * factory cannot create devices for the type which @link represents. + * represents a device which the factory does not support, or the link + * is supported but the device could not be created, %NULL should be + * returned and @error should be set. + * + * If the plugin cannot create a #NMDevice for the link and wants the + * core to ignore it, set @out_ignore to %TRUE and return no error. + * + * @plink is guaranteed to be one of the types the factory returns in + * get_supported_types(). * * Returns: the #NMDevice if the link was claimed and created, %NULL if not */ NMDevice * (*new_link) (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error); /** @@ -121,6 +133,34 @@ struct _NMDeviceFactory { NMDevice *parent, GError **error); + /** + * get_connection_parent: + * @factory: the #NMDeviceFactory + * @connection: the #NMConnection to return the parent name for, if supported + * + * Given a connection, returns the a parent interface name, parent connection + * UUID, or parent device hardware address for @connection. + * + * Returns: the parent interface name, parent connection UUID, parent + * device hardware address, or %NULL + */ + const char * (*get_connection_parent) (NMDeviceFactory *factory, + NMConnection *connection); + + /** + * get_virtual_iface_name: + * @factory: the #NMDeviceFactory + * @connection: the #NMConnection to return the virtual interface name for + * @parent_iface: parent interface name + * + * Given a connection, returns the interface name that a device activating + * that connection would have. + * + * Returns: the interface name, or %NULL + */ + char * (*get_virtual_iface_name) (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface); /* Signals */ @@ -151,12 +191,22 @@ struct _NMDeviceFactory { GType nm_device_factory_get_type (void); -NMDeviceType nm_device_factory_get_device_type (NMDeviceFactory *factory); +void nm_device_factory_get_supported_types (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types); + +const char *nm_device_factory_get_connection_parent (NMDeviceFactory *factory, + NMConnection *connection); + +char * nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface); void nm_device_factory_start (NMDeviceFactory *factory); NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error); NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, @@ -168,15 +218,33 @@ NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFacto gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component); +#define NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(...) \ + { static const NMLinkType _df_links[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; *out_link_types = _df_links; } +#define NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(...) \ + { static const char *_df_settings[] = { __VA_ARGS__, NULL }; *out_setting_types = _df_settings; } + +extern const NMLinkType _nm_device_factory_no_default_links[]; +extern const char *_nm_device_factory_no_default_settings[]; + +#define NM_DEVICE_FACTORY_DECLARE_TYPES(...) \ + static void \ + get_supported_types (NMDeviceFactory *factory, \ + const NMLinkType **out_link_types, \ + const char ***out_setting_types) \ + { \ + *out_link_types = _nm_device_factory_no_default_links; \ + *out_setting_types = _nm_device_factory_no_default_settings; \ + \ + { __VA_ARGS__; } \ + } \ + \ + /************************************************************************** * INTERNAL DEVICE FACTORY FUNCTIONS - devices provided by plugins should * not use these functions. **************************************************************************/ -#define DEFINE_DEVICE_FACTORY_INTERNAL(upper, mixed, lower, dfi_code) \ - DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, upper, dfi_code) - -#define DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, devtype, dfi_code) \ +#define NM_DEVICE_FACTORY_DEFINE_INTERNAL(upper, mixed, lower, st_code, dfi_code) \ typedef GObject NM##mixed##Factory; \ typedef GObjectClass NM##mixed##FactoryClass; \ \ @@ -198,16 +266,12 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, g_type_ensure (NM_TYPE_##upper##_FACTORY); \ } \ \ - static NMDeviceType \ - get_device_type (NMDeviceFactory *factory) \ - { \ - return NM_DEVICE_TYPE_##devtype; \ - } \ + NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ \ static void \ device_factory_interface_init (NMDeviceFactory *factory_iface) \ { \ - factory_iface->get_device_type = get_device_type; \ + factory_iface->get_supported_types = get_supported_types; \ dfi_code \ } \ \ @@ -222,6 +286,22 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, } void _nm_device_factory_internal_register_type (GType factory_type); -const GSList *nm_device_factory_get_internal_factory_types (void); + +/************************************************************************** + * PRIVATE FACTORY FUNCTIONS - for factory consumers (eg, NMManager). + **************************************************************************/ + +typedef void (*NMDeviceFactoryManagerFactoryFunc) (NMDeviceFactory *factory, + gpointer user_data); + +void nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data); + +NMDeviceFactory * nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type); + +NMDeviceFactory * nm_device_factory_manager_find_factory_for_connection (NMConnection *connection); + +void nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data); #endif /* __NETWORKMANAGER_DEVICE_FACTORY_H__ */ diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index f103ef83..5841d834 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -45,15 +45,23 @@ enum { LAST_PROP }; -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { - if (nm_platform_link_supports_carrier_detect (nm_device_get_ifindex (dev))) + if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, nm_device_get_ifindex (dev))) return NM_DEVICE_CAP_CARRIER_DETECT; else return NM_DEVICE_CAP_NONE; } +static const char * +get_type_description (NMDevice *device) +{ + if (NM_DEVICE_GENERIC_GET_PRIVATE (device)->type_description) + return NM_DEVICE_GENERIC_GET_PRIVATE (device)->type_description; + return NM_DEVICE_CLASS (nm_device_generic_parent_class)->get_type_description (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -117,7 +125,7 @@ constructed (GObject *object) int ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); if (ifindex != 0) - priv->type_description = g_strdup (nm_platform_link_get_type_name (ifindex)); + priv->type_description = g_strdup (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex)); } G_OBJECT_CLASS (nm_device_generic_parent_class)->constructed (object); @@ -184,6 +192,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; + parent_class->get_type_description = get_type_description; parent_class->check_connection_compatible = check_connection_compatible; parent_class->update_connection = update_connection; diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c index 9c25b398..b3510d2e 100644 --- a/src/devices/nm-device-gre.c +++ b/src/devices/nm-device-gre.c @@ -71,7 +71,7 @@ update_properties (NMDevice *device) GObject *object = G_OBJECT (device); NMPlatformGreProperties props; - if (!nm_platform_gre_get_properties (nm_device_get_ifindex (device), &props)) { + if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { _LOGW (LOGD_HW, "could not read gre properties"); return; } @@ -267,19 +267,17 @@ nm_device_gre_class_init (NMDeviceGreClass *klass) #define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_GRE || plink->type == NM_LINK_TYPE_GRETAP) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Gre", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Gre", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(GRE, Gre, gre, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index e1af8995..2e2483c0 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -44,12 +44,15 @@ G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE) #define NM_DEVICE_INFINIBAND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandPrivate)) +#define NM_DEVICE_INFINIBAND_IS_PARTITION "is-partition" + typedef struct { - int dummy; + gboolean is_partition; } NMDeviceInfinibandPrivate; enum { PROP_0, + PROP_IS_PARTITION, LAST_PROP }; @@ -59,10 +62,15 @@ nm_device_infiniband_init (NMDeviceInfiniband * self) { } -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { - return NM_DEVICE_CAP_CARRIER_DETECT; + guint32 caps = NM_DEVICE_CAP_CARRIER_DETECT; + + if (NM_DEVICE_INFINIBAND_GET_PRIVATE (dev)->is_partition) + caps |= NM_DEVICE_CAP_IS_SOFTWARE; + + return caps; } static NMActStageReturn @@ -105,7 +113,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) } } - ok = nm_platform_sysctl_set (mode_path, transport_mode); + ok = nm_platform_sysctl_set (NM_PLATFORM_GET, mode_path, transport_mode); g_free (mode_path); if (!ok) { @@ -213,8 +221,8 @@ update_connection (NMDevice *device, NMConnection *connection) { NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection); const char *mac = nm_device_get_hw_address (device); - char *mode_path, *contents = NULL; const char *transport_mode = "datagram"; + int ifindex; if (!s_infiniband) { s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new (); @@ -224,16 +232,10 @@ update_connection (NMDevice *device, NMConnection *connection) if (mac && !nm_utils_hwaddr_matches (mac, -1, NULL, INFINIBAND_ALEN)) g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL); - mode_path = g_strdup_printf ("/sys/class/net/%s/mode", - ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (device))); - contents = nm_platform_sysctl_get (mode_path); - g_free (mode_path); - if (contents) { - if (strstr (contents, "datagram")) + ifindex = nm_device_get_ifindex (device); + if (ifindex > 0) { + if (!nm_platform_infiniband_get_info (NM_PLATFORM_GET, ifindex, NULL, NULL, &transport_mode)) transport_mode = "datagram"; - else if (strstr (contents, "connected")) - transport_mode = "connected"; - g_free (contents); } g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, transport_mode, NULL); } @@ -243,6 +245,9 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { + case PROP_IS_PARTITION: + g_value_set_boolean (value, NM_DEVICE_INFINIBAND_GET_PRIVATE (object)->is_partition); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -254,6 +259,9 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { + case PROP_IS_PARTITION: + NM_DEVICE_INFINIBAND_GET_PRIVATE (object)->is_partition = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -281,6 +289,12 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) parent_class->ip4_config_pre_commit = ip4_config_pre_commit; /* properties */ + g_object_class_install_property + (object_class, PROP_IS_PARTITION, + g_param_spec_boolean (NM_DEVICE_INFINIBAND_IS_PARTITION, "", "", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), @@ -293,16 +307,14 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) #define NM_INFINIBAND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_INFINIBAND_FACTORY, NMInfinibandFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_INFINIBAND) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "InfiniBand", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "InfiniBand", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, + NM_DEVICE_INFINIBAND_IS_PARTITION, (plink->parent > 0), + NULL); } static NMDevice * @@ -314,25 +326,30 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMSettingInfiniband *s_infiniband; int p_key, parent_ifindex; const char *iface; + NMPlatformError plerr; - if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) + if (!NM_IS_DEVICE_INFINIBAND (parent)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Parent interface %s must be an InfiniBand interface", + nm_device_get_iface (parent)); return NULL; - - g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (parent), NULL); + } s_infiniband = nm_connection_get_setting_infiniband (connection); iface = nm_setting_infiniband_get_virtual_interface_name (s_infiniband); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); parent_ifindex = nm_device_get_ifindex (parent); p_key = nm_setting_infiniband_get_p_key (s_infiniband); - if ( !nm_platform_infiniband_partition_add (parent_ifindex, p_key) - && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_INFINIBAND, "(%s): failed to add InfiniBand P_Key interface for '%s': %s", - iface, nm_connection_get_id (connection), - nm_platform_get_error_msg ()); + plerr = nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); return NULL; } @@ -341,11 +358,49 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NM_DEVICE_DRIVER, nm_device_get_driver (parent), NM_DEVICE_TYPE_DESC, "InfiniBand", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, + NM_DEVICE_INFINIBAND_IS_PARTITION, TRUE, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(INFINIBAND, Infiniband, infiniband, \ - factory_iface->new_link = new_link; \ +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingInfiniband *s_infiniband; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + return nm_setting_infiniband_get_parent (s_infiniband); +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + NMSettingInfiniband *s_infiniband; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + if (!parent_iface) + return NULL; + + g_return_val_if_fail (g_strcmp0 (parent_iface, nm_setting_infiniband_get_parent (s_infiniband)) == 0, NULL); + + return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband)); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME), + factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index bcd38617..0bfe3fe9 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -64,7 +64,7 @@ update_properties (NMDevice *device) GObject *object = G_OBJECT (device); NMPlatformMacvlanProperties props; - if (!nm_platform_macvlan_get_properties (nm_device_get_ifindex (device), &props)) { + if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { _LOGW (LOGD_HW, "could not read macvlan properties"); return; } @@ -175,19 +175,17 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) #define NM_MACVLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MACVLAN_FACTORY, NMMacvlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_MACVLAN || plink->type == NM_LINK_TYPE_MACVTAP) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Macvlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Macvlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(MACVLAN, Macvlan, macvlan, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 1f781bbc..f34969ac 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -97,6 +97,9 @@ void nm_device_set_carrier (NMDevice *self, gboolean carrier); void nm_device_emit_recheck_auto_activate (NMDevice *device); void nm_device_queue_recheck_assume (NMDevice *device); +void nm_device_queue_recheck_available (NMDevice *device, + NMDeviceStateReason available_reason, + NMDeviceStateReason unavailable_reason); void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config); void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config); diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 9a3fab5e..5aaff8b1 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -65,7 +65,7 @@ reload_tun_properties (NMDeviceTun *self) GObject *object = G_OBJECT (self); NMPlatformTunProperties props; - if (!nm_platform_tun_get_properties (nm_device_get_ifindex (NM_DEVICE (self)), &props)) { + if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &props)) { _LOGD (LOGD_HW, "could not read tun properties"); return; } @@ -123,7 +123,7 @@ constructed (GObject *object) gboolean properties_read; NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - properties_read = nm_platform_tun_get_properties (nm_device_get_ifindex (NM_DEVICE (self)), &priv->props); + properties_read = nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &priv->props); G_OBJECT_CLASS (nm_device_tun_parent_class)->constructed (object); @@ -270,7 +270,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) #define NM_TUN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_TUN_FACTORY, NMTunFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { const char *mode = NULL; @@ -278,8 +278,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) mode = "tun"; else if (plink->type == NM_LINK_TYPE_TAP) mode = "tap"; - else - return NULL; + else { + g_warn_if_reached (); + mode = "unknown"; + } return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN, NM_DEVICE_PLATFORM_DEVICE, plink, @@ -289,7 +291,8 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(TUN, Tun, tun, GENERIC, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index db29c00d..04f03fbb 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -82,7 +82,7 @@ get_peer (NMDeviceVeth *self) if (priv->ever_had_peer) return priv->peer; - if (!nm_platform_veth_get_properties (nm_device_get_ifindex (device), &props)) { + if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { _LOGW (LOGD_HW, "could not read veth properties"); return NULL; } @@ -96,13 +96,21 @@ get_peer (NMDeviceVeth *self) return priv->peer; } +static gboolean +can_unmanaged_external_down (NMDevice *self) +{ + /* Unless running in a container, an udev rule causes these to be + * unmanaged. If there's no udev then we're probably in a container + * and should IFF_UP and configure the veth ourselves even if we + * didn't create it. */ + return FALSE; +} /**************************************************************/ static void nm_device_veth_init (NMDeviceVeth *self) { - nm_device_set_initial_unmanaged_flag (NM_DEVICE (self), NM_UNMANAGED_DEFAULT, TRUE); } static void @@ -141,12 +149,15 @@ static void nm_device_veth_class_init (NMDeviceVethClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); g_type_class_add_private (klass, sizeof (NMDeviceVethPrivate)); object_class->get_property = get_property; object_class->dispose = dispose; + device_class->can_unmanaged_external_down = can_unmanaged_external_down; + /* properties */ g_object_class_install_property (object_class, PROP_PEER, @@ -166,19 +177,17 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) #define NM_VETH_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VETH_FACTORY, NMVethFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_VETH) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Veth", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Veth", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VETH, Veth, veth, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VETH, Veth, veth, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VETH), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index c69bcded..158e7de5 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -40,6 +40,7 @@ #include "nm-device-factory.h" #include "nm-manager.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" #include "nm-device-vlan-glue.h" @@ -51,14 +52,10 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) #define NM_DEVICE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VLAN, NMDeviceVlanPrivate)) typedef struct { - char *initial_hw_addr; - - gboolean disposed; gboolean invalid; NMDevice *parent; guint parent_state_id; - int vlan_id; } NMDeviceVlanPrivate; @@ -75,20 +72,68 @@ enum { /******************************************************************/ static void -update_initial_hw_address (NMDevice *dev) +parent_state_changed (NMDevice *parent, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); + + /* We'll react to our own carrier state notifications. Ignore the parent's. */ + if (reason == NM_DEVICE_STATE_REASON_CARRIER) + return; + + nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); +} + +static void +nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct) { - NMDeviceVlan *self = NM_DEVICE_VLAN (dev); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + + if (parent == priv->parent) + return; + + if (priv->parent_state_id) { + g_signal_handler_disconnect (priv->parent, priv->parent_state_id); + priv->parent_state_id = 0; + } + g_clear_object (&priv->parent); - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev)); - _LOGD (LOGD_DEVICE | LOGD_VLAN, "read initial MAC address %s", priv->initial_hw_addr); + if (parent) { + priv->parent = g_object_ref (parent); + priv->parent_state_id = g_signal_connect (priv->parent, + "state-changed", + G_CALLBACK (parent_state_changed), + device); + + /* Set parent-dependent unmanaged flag */ + if (construct) { + nm_device_set_initial_unmanaged_flag (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent)); + } else { + nm_device_set_unmanaged (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent), + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); + } + } + + /* Recheck availability now that the parent has changed */ + nm_device_queue_recheck_available (self, + NM_DEVICE_STATE_REASON_PARENT_CHANGED, + NM_DEVICE_STATE_REASON_PARENT_CHANGED); + g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); } -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { /* We assume VLAN interfaces always support carrier detect */ - return NM_DEVICE_CAP_CARRIER_DETECT; + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } static gboolean @@ -108,12 +153,55 @@ bring_up (NMDevice *dev, gboolean *no_firmware) /******************************************************************/ static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + if (!NM_DEVICE_VLAN_GET_PRIVATE (device)->parent) + return FALSE; + + return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags); +} + +static gboolean +component_added (NMDevice *device, GObject *component) +{ + NMDeviceVlan *self = NM_DEVICE_VLAN (device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); + NMDevice *added_device; + int parent_ifindex = -1; + + if (priv->parent) + return FALSE; + + if (!NM_IS_DEVICE (component)) + return FALSE; + added_device = NM_DEVICE (component); + + if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) { + _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component."); + return FALSE; + } + + if (nm_device_get_ifindex (added_device) != parent_ifindex) + return FALSE; + + nm_device_vlan_set_parent (self, added_device, FALSE); + + /* Don't claim parent exclusively */ + return FALSE; +} + +/******************************************************************/ + +static gboolean match_parent (NMDeviceVlan *self, const char *parent) { NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); g_return_val_if_fail (parent != NULL, FALSE); + if (!priv->parent) + return FALSE; + if (nm_utils_is_uuid (parent)) { NMActRequest *parent_req; NMConnection *parent_connection; @@ -239,32 +327,6 @@ complete_connection (NMDevice *device, return TRUE; } -static void parent_state_changed (NMDevice *parent, NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data); - -static void -nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); - - if (priv->parent_state_id) { - g_signal_handler_disconnect (priv->parent, priv->parent_state_id); - priv->parent_state_id = 0; - } - g_clear_object (&priv->parent); - - if (parent) { - priv->parent = g_object_ref (parent); - priv->parent_state_id = g_signal_connect (priv->parent, - "state-changed", - G_CALLBACK (parent_state_changed), - device); - } - g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); -} - static void update_connection (NMDevice *device, NMConnection *connection) { @@ -281,7 +343,7 @@ update_connection (NMDevice *device, NMConnection *connection) nm_connection_add_setting (connection, (NMSetting *) s_vlan); } - if (!nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id)) { + if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent_ifindex, &vlan_id)) { _LOGW (LOGD_VLAN, "failed to get VLAN interface info while updating connection."); return; } @@ -296,8 +358,7 @@ update_connection (NMDevice *device, NMConnection *connection) parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); g_assert (parent); - if (priv->parent != parent) - nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE); /* Update parent in the connection; default to parent's interface name */ new_parent = nm_device_get_iface (parent); @@ -353,12 +414,12 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP); for (i = 0; i < num; i++) { if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to)) - nm_platform_vlan_set_ingress_map (ifindex, from, to); + nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to); } num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP); for (i = 0; i < num; i++) { if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to)) - nm_platform_vlan_set_egress_map (ifindex, from, to); + nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to); } } @@ -386,30 +447,9 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) static void deactivate (NMDevice *device) { - NMDeviceVlan *self = NM_DEVICE_VLAN (device); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_VLAN); -} - -/******************************************************************/ - -static void -parent_state_changed (NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (reason == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_VLAN); } /******************************************************************/ @@ -431,37 +471,40 @@ constructed (GObject *object) if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed) G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object); - if (!priv->parent) { - _LOGE (LOGD_VLAN, "no parent specified."); - priv->invalid = TRUE; - return; - } - - itype = nm_platform_link_get_type (ifindex); + itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex); if (itype != NM_LINK_TYPE_VLAN) { _LOGE (LOGD_VLAN, "failed to get VLAN interface type."); priv->invalid = TRUE; return; } - if (!nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id)) { + if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent_ifindex, &vlan_id)) { _LOGW (LOGD_VLAN, "failed to get VLAN interface info."); priv->invalid = TRUE; return; } - if ( parent_ifindex < 0 - || parent_ifindex != nm_device_get_ip_ifindex (priv->parent) - || vlan_id < 0) { + if (parent_ifindex < 0 || vlan_id < 0) { _LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.", parent_ifindex, priv->vlan_id); priv->invalid = TRUE; return; } + if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) { + _LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.", + nm_device_get_iface (priv->parent), + nm_device_get_ifindex (priv->parent), + parent_ifindex); + priv->invalid = TRUE; + return; + } + priv->vlan_id = vlan_id; - _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s", - priv->vlan_id, nm_device_get_iface (priv->parent)); + _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)", + priv->vlan_id, + priv->parent ? nm_device_get_iface (priv->parent) : "unknown", + parent_ifindex); } static void @@ -494,7 +537,7 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_INT_PARENT_DEVICE: - nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value)); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE); break; case PROP_VLAN_ID: priv->vlan_id = g_value_get_uint (value); @@ -508,32 +551,12 @@ set_property (GObject *object, guint prop_id, static void dispose (GObject *object) { - NMDeviceVlan *self = NM_DEVICE_VLAN (object); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - if (priv->disposed) { - G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object); - return; - } - priv->disposed = TRUE; - - nm_device_vlan_set_parent (self, NULL); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), NULL, FALSE); G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object); } static void -finalize (GObject *object) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (object); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - g_free (priv->initial_hw_addr); - - G_OBJECT_CLASS (nm_device_vlan_parent_class)->finalize (object); -} - -static void nm_device_vlan_class_init (NMDeviceVlanClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); @@ -548,14 +571,14 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; - object_class->finalize = finalize; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->bring_up = bring_up; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->deactivate = deactivate; + parent_class->is_available = is_available; + parent_class->component_added = component_added; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -594,30 +617,18 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) #define NM_VLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VLAN_FACTORY, NMVlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { int parent_ifindex = -1; NMDevice *parent, *device; - if (plink->type != NM_LINK_TYPE_VLAN) - return NULL; - - /* Have to find the parent device */ - if (!nm_platform_vlan_get_info (plink->ifindex, &parent_ifindex, NULL)) { - nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", plink->name); + /* Find the parent device */ + if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, plink->ifindex, &parent_ifindex, NULL)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN parent ifindex unknown"); return NULL; } - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - if (!parent) { - /* If udev signaled the VLAN interface before it signaled - * the VLAN's parent at startup we may not know about the - * parent device yet. But we'll find it on the second pass - * from nm_manager_start(). - */ - nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name); - return NULL; - } device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, NM_DEVICE_PLATFORM_DEVICE, plink, @@ -627,14 +638,12 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, NULL); if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN initialization failed"); g_object_unref (device); device = NULL; } - /* Set initial parent-dependent unmanaged flag */ - if (device) - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent)); - return device; } @@ -646,15 +655,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, { NMDevice *device; NMSettingVlan *s_vlan; - char *iface; + gs_free char *iface = NULL; + NMPlatformError plerr; - if (!nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) + if (!NM_IS_DEVICE (parent)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN interfaces must have parents"); return NULL; - - g_return_val_if_fail (NM_IS_DEVICE (parent), NULL); + } s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); + g_assert (s_vlan); iface = g_strdup (nm_connection_get_interface_name (connection)); if (!iface) { @@ -662,14 +673,18 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, nm_setting_vlan_get_id (s_vlan)); } - if ( !nm_platform_vlan_add (iface, + plerr = nm_platform_vlan_add (NM_PLATFORM_GET, + iface, nm_device_get_ifindex (parent), nm_setting_vlan_get_id (s_vlan), - nm_setting_vlan_get_flags (s_vlan)) - && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_VLAN, "(%s) failed to add VLAN interface for '%s'", - iface, nm_connection_get_id (connection)); - g_free (iface); + nm_setting_vlan_get_flags (s_vlan), + NULL); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); return NULL; } @@ -680,21 +695,74 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NM_DEVICE_TYPE_DESC, "VLAN", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, NULL); - g_free (iface); if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': initialization failed", + iface, nm_connection_get_id (connection)); g_object_unref (device); device = NULL; } - /* Set initial parent-dependent unmanaged flag */ - if (device) - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent)); - return device; } -DEFINE_DEVICE_FACTORY_INTERNAL(VLAN, Vlan, vlan, \ - factory_iface->new_link = new_link; \ +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingVlan *s_vlan; + NMSettingWired *s_wired; + const char *parent = NULL; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + parent = nm_setting_vlan_get_parent (s_vlan); + if (parent) + return parent; + + /* Try the hardware address from the VLAN connection's hardware setting */ + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) + return nm_setting_wired_get_mac_address (s_wired); + + return NULL; +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *ifname; + NMSettingVlan *s_vlan; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + if (!parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + if (ifname) + return g_strdup (ifname); + + /* If the connection doesn't specify the interface name for the VLAN + * device, we create one for it using the VLAN ID and the parent + * interface's name. + */ + return nm_utils_new_vlan_name (parent_iface, nm_setting_vlan_get_id (s_vlan)); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME), + factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index ed6b8fa0..186e00de 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -76,7 +76,7 @@ update_properties (NMDevice *device) GObject *object = G_OBJECT (device); NMPlatformVxlanProperties props; - if (!nm_platform_vxlan_get_properties (nm_device_get_ifindex (device), &props)) { + if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { _LOGW (LOGD_HW, "could not read vxlan properties"); return; } @@ -199,7 +199,7 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->props.src_port_max); break; case PROP_PROXY: - g_value_set_uint (value, priv->props.proxy); + g_value_set_boolean (value, priv->props.proxy); break; case PROP_RSC: g_value_set_boolean (value, priv->props.rsc); @@ -353,19 +353,17 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) #define NM_VXLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VXLAN_FACTORY, NMVxlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_VXLAN) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Vxlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Vxlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VXLAN, Vxlan, vxlan, GENERIC, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VXLAN, Vxlan, vxlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VXLAN), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 47526281..c5d4c203 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -28,8 +28,6 @@ #include <string.h> #include <unistd.h> #include <errno.h> -#include <linux/sockios.h> -#include <linux/ethtool.h> #include <sys/ioctl.h> #include <signal.h> #include <sys/types.h> @@ -62,7 +60,6 @@ #include "nm-enum-types.h" #include "nm-settings-connection.h" #include "nm-connection-provider.h" -#include "nm-posix-signals.h" #include "nm-auth-utils.h" #include "nm-dbus-glib-types.h" #include "nm-dispatcher.h" @@ -70,12 +67,14 @@ #include "nm-dns-manager.h" #include "nm-core-internal.h" #include "nm-default-route-manager.h" +#include "nm-route-manager.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDevice); static void impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context); static void impl_device_delete (NMDevice *self, DBusGMethodInvocation *context); +static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data); #include "nm-device-glue.h" @@ -139,6 +138,12 @@ enum { #define PENDING_ACTION_AUTOCONF6 "autoconf6" typedef enum { + CLEANUP_TYPE_DECONFIGURE, + CLEANUP_TYPE_KEEP, + CLEANUP_TYPE_REMOVED, +} CleanupType; + +typedef enum { IP_NONE = 0, IP_WAIT, IP_CONF, @@ -164,6 +169,9 @@ typedef struct { guint timeout; guint watch; GPid pid; + const char *binary; + const char *address; + guint deadline; } PingInfo; typedef struct { @@ -175,23 +183,28 @@ typedef struct { 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_ip_config_id; + guint queued_ip4_config_id; + guint queued_ip6_config_id; GSList *pending_actions; char * udi; char * path; char * iface; /* may change, could be renamed by user */ int ifindex; - gboolean is_software; char * ip_iface; int ip_ifindex; NMDeviceType type; char * type_desc; - guint32 capabilities; + char * type_description; + NMDeviceCapabilities capabilities; char * driver; char * driver_version; char * firmware_version; @@ -200,6 +213,8 @@ typedef struct { 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; @@ -220,6 +235,11 @@ typedef struct { gpointer act_source6_func; 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; @@ -242,16 +262,18 @@ typedef struct { /* 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 */ - gboolean ext_ip4_config_had_any_addresses; NMIP4Config * wwan_ip4_config; /* WWAN configuration */ struct { gboolean v4_has; gboolean v4_is_assumed; + gboolean v4_configure_first_time; NMPlatformIP4Route v4; gboolean v6_has; gboolean v6_is_assumed; + gboolean v6_configure_first_time; NMPlatformIP6Route v6; } default_route; @@ -279,11 +301,12 @@ typedef struct { /* IP6 configuration info */ NMIP6Config * ip6_config; IpState ip6_state; + NMIP6Config * con_ip6_config; /* config from the setting */ NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */ NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ - gboolean ext_ip6_config_had_any_addresses; gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ + guint32 ip6_mtu; NMRDisc * rdisc; gulong rdisc_changed_id; @@ -322,6 +345,7 @@ 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, @@ -331,6 +355,7 @@ static gboolean ip4_config_merge_and_apply (NMDevice *self, static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *config, gboolean commit, + gboolean routes_full_sync, NMDeviceStateReason *reason); static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); @@ -448,6 +473,8 @@ static const char *reason_table[] = { [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 * @@ -463,13 +490,19 @@ reason_to_string (NMDeviceStateReason reason) gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value) { - return nm_platform_sysctl_set (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value); + return nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value); } -static gboolean -device_has_capability (NMDevice *self, NMDeviceCapabilities caps) +static guint32 +nm_device_ipv6_sysctl_get_int32 (NMDevice *self, const char *property, gint32 fallback) { - return !!(NM_DEVICE_GET_PRIVATE (self)->capabilities & caps); + 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); } /***********************************************************/ @@ -486,7 +519,7 @@ nm_device_dbus_export (NMDevice *self) g_return_if_fail (priv->path == NULL); priv->path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++); - _LOGI (LOGD_DEVICE, "exported as %s", priv->path); + _LOGD (LOGD_DEVICE, "exported as %s", priv->path); nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self); } @@ -509,7 +542,7 @@ nm_device_get_udi (NMDevice *self) const char * nm_device_get_iface (NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), 0); + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); return NM_DEVICE_GET_PRIVATE (self)->iface; } @@ -525,9 +558,7 @@ nm_device_get_ifindex (NMDevice *self) gboolean nm_device_is_software (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - return priv->is_software; + return NM_FLAGS_HAS (NM_DEVICE_GET_PRIVATE (self)->capabilities, NM_DEVICE_CAP_IS_SOFTWARE); } const char * @@ -550,7 +581,7 @@ nm_device_get_ip_ifindex (NMDevice *self) g_return_val_if_fail (self != NULL, 0); priv = NM_DEVICE_GET_PRIVATE (self); - /* If it's not set, default to iface */ + /* If it's not set, default to ifindex */ return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; } @@ -571,13 +602,13 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) priv->ip_iface = g_strdup (iface); if (priv->ip_iface) { - priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface); + priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); if (priv->ip_ifindex > 0) { - if (nm_platform_check_support_user_ipv6ll ()) - nm_platform_link_set_user_ipv6ll_enabled (priv->ip_ifindex, TRUE); + if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) + nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ip_ifindex, TRUE); - if (!nm_platform_link_is_up (priv->ip_ifindex)) - nm_platform_link_set_up (priv->ip_ifindex); + 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"); @@ -607,10 +638,10 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) ifindex = nm_device_get_ip_ifindex (self); g_assert (ifindex); - link_type = nm_platform_link_get_type (ifindex); + link_type = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex); g_return_val_if_fail (link_type > NM_LINK_TYPE_UNKNOWN, 0); - hwaddr = nm_platform_link_get_address (ifindex, &hwaddr_len); + hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddr_len); if (!hwaddr_len) return FALSE; @@ -724,50 +755,63 @@ nm_device_get_priority (NMDevice *self) return 11000; } -guint32 -nm_device_get_ip4_route_metric (NMDevice *self) +static guint32 +_get_ipx_route_metric (NMDevice *self, + gboolean is_v4) { + char *value; + gint64 route_metric; + NMSettingIPConfig *s_ip; NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - gint64 route_metric = -1; g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); connection = nm_device_get_connection (self); - if (connection) - s_ip = nm_connection_get_setting_ip4_config (connection); + 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); + /* 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; + } + } - return route_metric >= 0 ? route_metric : nm_device_get_priority (self); + /* 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_ip6_route_metric (NMDevice *self) +nm_device_get_ip4_route_metric (NMDevice *self) { - NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - gint64 route_metric = -1; - - g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); - - connection = nm_device_get_connection (self); - if (connection) - s_ip = 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); + return _get_ipx_route_metric (self, TRUE); +} - return route_metric >= 0 ? route_metric : nm_device_get_priority (self); +guint32 +nm_device_get_ip6_route_metric (NMDevice *self) +{ + return _get_ipx_route_metric (self, FALSE); } const NMPlatformIP4Route * @@ -808,6 +852,34 @@ nm_device_get_type_desc (NMDevice *self) 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) { @@ -1012,8 +1084,15 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure 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 -is_software_external (NMDevice *self) +can_unmanaged_external_down (NMDevice *self) { return nm_device_is_software (self) && !nm_device_get_is_nm_owned (self); @@ -1030,22 +1109,75 @@ void nm_device_finish_init (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean platform_unmanaged = FALSE; g_assert (priv->initialized == FALSE); /* Do not manage externally created software devices until they are IFF_UP */ - if ( is_software_external (self) - && !nm_platform_link_is_up (priv->ifindex) + if ( NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self) + && !nm_platform_link_is_up (NM_PLATFORM_GET, priv->ifindex) && priv->ifindex > 0) nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE); if (priv->master) nm_device_enslave_slave (priv->master, self, NULL); + if (priv->ifindex > 0) { + if (priv->ifindex == 1) { + /* keep 'lo' as default-unmanaged. */ + + /* FIXME: either find a better way to unmange 'lo' that cannot be changed + * by user configuration (NM_UNMANGED_LOOPBACK?) or fix managing 'lo'. + * Currently it can happen that NM deletes 127.0.0.1 address. */ + nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, TRUE); + } else if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) { + nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged); + nm_device_set_initial_unmanaged_flag (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. + */ + nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_PLATFORM_INIT, TRUE); + } + } + priv->initialized = TRUE; } static void +update_dynamic_ip_setup (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + 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 */ + } +} + +static void carrier_changed (NMDevice *self, gboolean carrier) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -1094,6 +1226,12 @@ carrier_changed (NMDevice *self, gboolean carrier) * 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); @@ -1176,37 +1314,6 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) } static void -update_for_ip_ifname_change (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - 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 */ - } -} - -static void device_set_master (NMDevice *self, int ifindex) { NMDevice *master; @@ -1223,35 +1330,58 @@ device_set_master (NMDevice *self, int ifindex) } else { _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", ifindex, - nm_platform_link_get_name (ifindex)); + nm_platform_link_get_name (NM_PLATFORM_GET, ifindex)); } } -static void -device_link_changed (NMDevice *self, NMPlatformLink *info) +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; + gboolean platform_unmanaged = FALSE; + const char *udi; + NMPlatformLink info; + const NMPlatformLink *pllink; + int ifindex; + + 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; - if (info->udi && g_strcmp0 (info->udi, priv->udi)) { + 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 (info->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; + if (priv->mtu != info.mtu) { + priv->mtu = info.mtu; g_object_notify (G_OBJECT (self), NM_DEVICE_MTU); } - if (info->name[0] && strcmp (priv->iface, info->name) != 0) { + 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); + priv->ifindex, priv->iface, info.name); g_free (priv->iface); - priv->iface = g_strdup (info->name); + 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; @@ -1270,30 +1400,36 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) } /* Update slave status for external changes */ - if (priv->enslaved && info->master != nm_device_get_ifindex (priv->master)) + if (priv->enslaved && info.master != nm_device_get_ifindex (priv->master)) nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE); - if (info->master && !priv->enslaved) { - device_set_master (self, info->master); + if (info.master && !priv->enslaved) { + device_set_master (self, info.master); if (priv->master) nm_device_enslave_slave (priv->master, self, NULL); } + 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); + klass->link_changed (self, &info); /* Update DHCP, etc, if needed */ if (ip_ifname_changed) - update_for_ip_ifname_change (self); + update_dynamic_ip_setup (self); - if (priv->up != info->up) { - priv->up = info->up; + if (priv->up != NM_FLAGS_HAS (info.flags, IFF_UP)) { + priv->up = NM_FLAGS_HAS (info.flags, IFF_UP); /* Manage externally-created software interfaces only when they are IFF_UP */ g_assert (priv->ifindex > 0); - if (is_software_external (self)) { + if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) { gboolean external_down = nm_device_get_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN); - if (external_down && info->up) { + if (external_down && NM_FLAGS_HAS (info.flags, IFF_UP)) { 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. @@ -1316,7 +1452,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) */ priv->unmanaged_flags &= ~NM_UNMANAGED_EXTERNAL_DOWN; } - } else if (!external_down && !info->up && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) { + } else if (!external_down && !NM_FLAGS_HAS (info.flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) { /* If the device is already disconnected and is set !IFF_UP, * unmanage it. */ @@ -1327,57 +1463,120 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) } } } + + if (priv->ifindex > 0 && !priv->platform_link_initialized && info.initialized) { + priv->platform_link_initialized = TRUE; + + if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) { + nm_device_set_unmanaged (self, + NM_UNMANAGED_DEFAULT, + platform_unmanaged, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + + nm_device_set_unmanaged (self, + NM_UNMANAGED_PLATFORM_INIT, + FALSE, + NM_DEVICE_STATE_REASON_NOW_MANAGED); + } + + return G_SOURCE_REMOVE; } -static void -device_ip_link_changed (NMDevice *self, NMPlatformLink *info) +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; - if (info->name[0] && g_strcmp0 (priv->ip_iface, info->name)) { + 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, info->name); + priv->ip_iface, pllink->name); g_free (priv->ip_iface); - priv->ip_iface = g_strdup (info->name); + priv->ip_iface = g_strdup (pllink->name); g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE); - update_for_ip_ifname_change (self); + update_dynamic_ip_setup (self); } + return G_SOURCE_REMOVE; } static void link_changed_cb (NMPlatform *platform, + NMPObjectType obj_type, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, NMPlatformReason reason, NMDevice *self) { + NMDevicePrivate *priv; + if (change_type != NM_PLATFORM_SIGNAL_CHANGED) return; + priv = NM_DEVICE_GET_PRIVATE (self); + /* We don't filter by 'reason' because we are interested in *all* link * changes. For example a call to nm_platform_link_set_up() may result * in an internal carrier change (i.e. we ask the kernel to set IFF_UP * and it results in also setting IFF_LOWER_UP. */ - if (ifindex == nm_device_get_ifindex (self)) - device_link_changed (self, info); - else if (ifindex == nm_device_get_ip_ifindex (self)) - device_ip_link_changed (self, info); + 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 ( device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT) - && !device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) + 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 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)); +} + /** * nm_device_notify_component_added(): * @self: the #NMDevice @@ -1965,7 +2164,7 @@ device_has_config (NMDevice *self) return TRUE; /* Slaves are also configured by definition */ - if (nm_platform_link_get_master (priv->ifindex) > 0) + if (nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) > 0) return TRUE; return FALSE; @@ -2103,6 +2302,20 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) 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; } @@ -2274,6 +2487,47 @@ nm_device_queue_recheck_assume (NMDevice *self) 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); + } + _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) { @@ -2432,7 +2686,7 @@ nm_device_activate_stage1_device_prepare (gpointer user_data) /* Notify the new ActiveConnection along with the state change */ g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION); - _LOGI (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) started..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) started..."); nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); /* Assumed connections were already set up outside NetworkManager */ @@ -2466,7 +2720,7 @@ nm_device_activate_stage1_device_prepare (gpointer user_data) nm_device_activate_schedule_stage2_device_config (self); out: - _LOGI (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) complete."); + _LOGD (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) complete."); return FALSE; } @@ -2489,7 +2743,7 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) activation_source_schedule (self, nm_device_activate_stage1_device_prepare, 0); - _LOGI (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) scheduled..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) scheduled..."); } static NMActStageReturn @@ -2520,7 +2774,7 @@ nm_device_activate_stage2_device_config (gpointer user_data) /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, 0); - _LOGI (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) starting..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) starting..."); nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); /* Assumed connections were already set up outside NetworkManager */ @@ -2555,12 +2809,12 @@ nm_device_activate_stage2_device_config (gpointer user_data) nm_device_queue_recheck_assume (info->slave); } - _LOGI (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) successful."); + _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) successful."); nm_device_activate_schedule_stage3_ip_config_start (self); out: - _LOGI (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) complete."); + _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) complete."); return FALSE; } @@ -2583,7 +2837,7 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) activation_source_schedule (self, nm_device_activate_stage2_device_config, 0); - _LOGI (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) scheduled..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) scheduled..."); } /*********************************************/ @@ -2759,23 +3013,6 @@ aipd_timeout_cb (gpointer user_data) return FALSE; } -static void -aipd_child_setup (gpointer user_data G_GNUC_UNUSED) -{ - /* We are in the child process at this point. - * Give child it's own program group for signal - * separation. - */ - pid_t pid = getpid (); - setpgid (pid, pid); - - /* - * We blocked signals in main(). We need to restore original signal - * mask for avahi-autoipd here so that it can receive signals. - */ - nm_unblock_posix_signals (NULL); -} - /* default to installed helper, but can be modified for testing */ const char *nm_device_autoipd_helper_path = LIBEXECDIR "/nm-avahi-autoipd.action"; @@ -2815,7 +3052,7 @@ aipd_start (NMDevice *self, NMDeviceStateReason *reason) g_free (cmdline); if (!g_spawn_async ("/", (char **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, - &aipd_child_setup, NULL, &(priv->aipd_pid), &error)) { + nm_utils_setpgid, NULL, &(priv->aipd_pid), &error)) { _LOGW (LOGD_DEVICE | LOGD_AUTOIP4, "Activation: Stage 3 of 5 (IP Configure Start) failed" " to start avahi-autoipd: %s", @@ -2825,7 +3062,7 @@ aipd_start (NMDevice *self, NMDeviceStateReason *reason) return NM_ACT_STAGE_RETURN_FAILURE; } - _LOGI (LOGD_DEVICE | LOGD_AUTOIP4, + _LOGD (LOGD_DEVICE | LOGD_AUTOIP4, "Activation: Stage 3 of 5 (IP Configure Start) started" " avahi-autoipd..."); @@ -2848,9 +3085,9 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat GArray *routes; if (addr_family == AF_INET) - routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + 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 (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + 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; @@ -2885,10 +3122,62 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat } /*********************************************/ + +static void +ensure_con_ip4_config (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + + if (priv->con_ip4_config) + return; + + connection = nm_device_get_connection (self); + if (!connection) + return; + + priv->con_ip4_config = nm_ip4_config_new (); + 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); + NMConnection *connection; + + if (priv->con_ip6_config) + return; + + connection = nm_device_get_connection (self); + if (!connection) + return; + + priv->con_ip6_config = nm_ip6_config_new (); + 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, gboolean stop, gboolean release) +dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -2901,7 +3190,8 @@ dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release) nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE); - if (stop) + 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); @@ -2923,7 +3213,11 @@ ip4_config_merge_and_apply (NMDevice *self, 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; /* Merge all the configs into the composite config */ if (config) { @@ -2932,6 +3226,10 @@ ip4_config_merge_and_apply (NMDevice *self, } composite = nm_ip4_config_new (); + + if (commit) + ensure_con_ip4_config (self); + if (priv->dev_ip4_config) nm_ip4_config_merge (composite, priv->dev_ip4_config); if (priv->vpn4_config) @@ -2945,73 +3243,120 @@ ip4_config_merge_and_apply (NMDevice *self, if (priv->wwan_ip4_config) nm_ip4_config_merge (composite, priv->wwan_ip4_config); - /* Merge user overrides into the composite config. Generated+assumed - * connections come from the system not the user and merging them would - * be redundant, so don't bother. - */ + /* Apply ignore-auto-routes and ignore-auto-dns settings */ connection = nm_device_get_connection (self); + if (connection) { + NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (connection); + + if (s_ip4) { + if (nm_setting_ip_config_get_ignore_auto_routes (s_ip4)) + nm_ip4_config_reset_routes (composite); + if (nm_setting_ip_config_get_ignore_auto_dns (s_ip4)) { + nm_ip4_config_reset_nameservers (composite); + nm_ip4_config_reset_domains (composite); + nm_ip4_config_reset_searches (composite); + } + } + } + + /* 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); + + + /* 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 (connection) { - gboolean assumed = nm_device_uses_assumed_connection (self); - NMPlatformIP4Route *route = &priv->default_route.v4; - if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { - nm_ip4_config_merge_setting (composite, - nm_connection_get_setting_ip4_config (connection), - default_route_metric); - } + routes_full_sync = commit + && priv->default_route.v4_configure_first_time + && !nm_device_uses_assumed_connection (self); - /* 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). + if (!commit) { + /* during a non-commit event, we always pickup whatever is configured. */ + goto END_ADD_DEFAULT_ROUTE; + } + + 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->default_route.v4_configure_first_time + && !nm_device_uses_assumed_connection (self) + && connection_is_never_default) { + /* If the connection is explicitly configured as never-default, we enforce the (absense 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; + } + + /* 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. + */ + + /* we are about to commit (for a non-assumed connection). Enforce whatever we have + * configured. */ + priv->default_route.v4_configure_first_time = FALSE; + 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 ( !gateway + && nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM) + goto END_ADD_DEFAULT_ROUTE; + + has_direct_route = ( gateway == 0 + || nm_ip4_config_get_subnet_for_host (composite, gateway) + || 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). */ - if ( !assumed - && nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection)) { - guint32 gateway = 0; - - priv->default_route.v4_is_assumed = FALSE; - if ( (!commit && priv->ext_ip4_config_had_any_addresses) - || ( commit && nm_ip4_config_get_num_addresses (composite))) { - /* For managed interfaces, we can only configure a gateway, if either the external config indicates - * that we already have addresses, or if we are about to commit any addresses. - * Otherwise adding a default route will fail, because NMDefaultRouteManager does not add any - * addresses for the route. */ - gateway = nm_ip4_config_get_gateway (composite); - if ( gateway - || nm_device_get_device_type (self) == NM_DEVICE_TYPE_MODEM) { - memset (route, 0, sizeof (*route)); - route->source = NM_IP_CONFIG_SOURCE_USER; - route->gateway = gateway; - route->metric = default_route_metric; - route->mss = nm_ip4_config_get_mss (composite); - priv->default_route.v4_has = TRUE; - - if ( gateway - && !nm_ip4_config_get_subnet_for_host (composite, gateway) - && !nm_ip4_config_get_direct_route_for_host (composite, gateway)) { - /* add a direct route to the gateway */ - NMPlatformIP4Route r = *route; - - r.network = gateway; - r.plen = 32; - r.gateway = 0; - nm_ip4_config_add_route (composite, &r); - } - } - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) route); - } + priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); } /* Allow setting MTU etc */ @@ -3020,7 +3365,7 @@ ip4_config_merge_and_apply (NMDevice *self, NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); } - success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, out_reason); + success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync, out_reason); g_object_unref (composite); return success; } @@ -3051,7 +3396,7 @@ dhcp4_fail (NMDevice *self, gboolean timeout) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - dhcp4_cleanup (self, TRUE, FALSE); + dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); if (timeout || (priv->ip4_state == IP_CONF)) nm_device_activate_schedule_ip4_config_timeout (self); else if (priv->ip4_state == IP_DONE) @@ -3143,7 +3488,7 @@ dhcp4_start (NMDevice *self, g_object_unref (priv->dhcp4_config); priv->dhcp4_config = nm_dhcp4_config_new (); - hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); + 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); @@ -3196,7 +3541,7 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release) _LOGI (LOGD_DHCP4, "DHCPv4 lease renewal requested"); /* Terminate old DHCP instance and release the old lease */ - dhcp4_cleanup (self, TRUE, release); + dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); connection = nm_device_get_connection (self); g_assert (connection); @@ -3451,7 +3796,7 @@ act_stage3_ip4_config_start (NMDevice *self, /* DHCPv6 stuff */ static void -dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release) +dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -3464,7 +3809,8 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release) priv->dhcp6_state_sigid = 0; } - if (stop) + 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); @@ -3487,10 +3833,16 @@ ip6_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; NMIP6Config *composite; + gboolean has_direct_route; + const struct in6_addr *gateway; + gboolean connection_has_default_route, connection_is_never_default; + gboolean routes_full_sync; /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); - g_assert (composite); + + if (commit) + ensure_con_ip6_config (self); /* Merge all the IP configs into the composite config */ if (priv->ac_ip6_config) @@ -3508,72 +3860,119 @@ ip6_config_merge_and_apply (NMDevice *self, if (priv->wwan_ip6_config) nm_ip6_config_merge (composite, priv->wwan_ip6_config); - /* Merge user overrides into the composite config. Generated+assumed - * connections come from the system not the user and merging them would - * be redundant, so don't bother. - */ + /* Apply ignore-auto-routes and ignore-auto-dns settings */ connection = nm_device_get_connection (self); - priv->default_route.v6_has = FALSE; - priv->default_route.v6_is_assumed = TRUE; if (connection) { - gboolean assumed = nm_device_uses_assumed_connection (self); - NMPlatformIP6Route *route = &priv->default_route.v6; + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { - nm_ip6_config_merge_setting (composite, - nm_connection_get_setting_ip6_config (connection), - nm_device_get_ip6_route_metric (self)); + if (s_ip6) { + if (nm_setting_ip_config_get_ignore_auto_routes (s_ip6)) + nm_ip6_config_reset_routes (composite); + if (nm_setting_ip_config_get_ignore_auto_dns (s_ip6)) { + nm_ip6_config_reset_nameservers (composite); + nm_ip6_config_reset_domains (composite); + nm_ip6_config_reset_searches (composite); + } } + } - /* 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). + /* 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); + + /* 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; + + routes_full_sync = commit + && priv->default_route.v6_configure_first_time + && !nm_device_uses_assumed_connection (self); + + if (!commit) { + /* during a non-commit event, we always pickup whatever is configured. */ + goto END_ADD_DEFAULT_ROUTE; + } + + 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->default_route.v6_configure_first_time + && !nm_device_uses_assumed_connection (self) + && 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; + } + + /* 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. + */ + + /* we are about to commit (for a non-assumed connection). Enforce whatever we have + * configured. */ + priv->default_route.v6_configure_first_time = FALSE; + 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); + } + +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). */ - if ( !assumed - && nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection)) { - const struct in6_addr *gateway = NULL; - - priv->default_route.v6_is_assumed = FALSE; - if ( (!commit && priv->ext_ip6_config_had_any_addresses) - || ( commit && nm_ip6_config_get_num_addresses (composite))) { - /* For managed interfaces, we can only configure a gateway, if either the external config indicates - * that we already have addresses, or if we are about to commit any addresses. - * Otherwise adding a default route will fail, because NMDefaultRouteManager does not add any - * addresses for the route. */ - gateway = nm_ip6_config_get_gateway (composite); - if (gateway) { - memset (route, 0, sizeof (*route)); - route->source = NM_IP_CONFIG_SOURCE_USER; - route->gateway = *gateway; - route->metric = nm_device_get_ip6_route_metric (self); - route->mss = nm_ip6_config_get_mss (composite); - priv->default_route.v6_has = TRUE; - - if ( gateway - && !nm_ip6_config_get_subnet_for_host (composite, gateway) - && !nm_ip6_config_get_direct_route_for_host (composite, gateway)) { - /* add a direct route to the gateway */ - NMPlatformIP6Route r = *route; - - r.network = *gateway; - r.plen = 128; - r.gateway = in6addr_any; - nm_ip6_config_add_route (composite, &r); - } - } - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) route); - } + 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, @@ -3585,7 +3984,7 @@ ip6_config_merge_and_apply (NMDevice *self, NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, composite); } - success = nm_device_set_ip6_config (self, composite, commit, out_reason); + success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync, out_reason); g_object_unref (composite); return success; } @@ -3623,7 +4022,7 @@ dhcp6_fail (NMDevice *self, gboolean timeout) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - dhcp6_cleanup (self, TRUE, FALSE); + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) { if (timeout || (priv->ip6_state == IP_CONF)) @@ -3648,7 +4047,7 @@ dhcp6_timeout (NMDevice *self, NMDhcpClient *client) dhcp6_fail (self, TRUE); else { /* not a hard failure; just live with the RA info */ - dhcp6_cleanup (self, TRUE, FALSE); + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); if (priv->ip6_state == IP_CONF) nm_device_activate_schedule_ip6_config_result (self); } @@ -3740,7 +4139,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); + 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); @@ -3823,7 +4222,7 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) _LOGI (LOGD_DHCP6, "DHCPv6 lease renewal requested"); /* Terminate old DHCP instance and release the old lease */ - dhcp6_cleanup (self, TRUE, release); + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); /* Start DHCP again on the interface */ return dhcp6_start (self, FALSE, NULL); @@ -3945,7 +4344,8 @@ check_and_add_ipv6ll_addr (NMDevice *self) lladdr.s6_addr16[0] = htons (0xfe80); nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid); _LOGD (LOGD_IP6, "adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL)); - if (!nm_platform_ip6_address_add (ip_ifindex, + if (!nm_platform_ip6_address_add (NM_PLATFORM_GET, + ip_ifindex, lladdr, in6addr_any, 64, @@ -3995,7 +4395,7 @@ print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) if (s_libnl == -1) { s_libnl = !!nm_platform_check_support_libnl_extended_ifa_flags (); - s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags (); + s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); if (s_libnl && s_kernel) { nm_log_dbg (LOGD_IP6, "kernel and libnl support extended IFA_FLAGS (needed by NM for IPv6 private addresses)"); @@ -4031,6 +4431,58 @@ print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) warn = 2; } +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_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 != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex)) + 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->ip6_mtu) { + _LOGW (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 < 1280) { + _LOGW (LOGD_DEVICE | LOGD_IP6, "IPv6 MTU (%d) smaller than 1280, adjusting", + priv->ip6_mtu); + priv->ip6_mtu = 1280; + } + + if (priv->mtu < priv->ip6_mtu) { + _LOGW (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) { @@ -4048,7 +4500,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) * from adding a prefix route for this address. **/ system_support = nm_platform_check_support_libnl_extended_ifa_flags () && - nm_platform_check_support_kernel_extended_ifa_flags (); + nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); } if (system_support) @@ -4151,13 +4603,13 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) } if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) { - dhcp6_cleanup (self, TRUE, TRUE); + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, TRUE); priv->dhcp6_mode = rdisc->dhcp_level; if (priv->dhcp6_mode != NM_RDISC_DHCP_LEVEL_NONE) { NMDeviceStateReason reason; - _LOGI (LOGD_DEVICE | LOGD_DHCP6, + _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)) { @@ -4169,14 +4621,10 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) } if (changed & NM_RDISC_CONFIG_HOP_LIMIT) - nm_platform_sysctl_set_ip6_hop_limit_safe (nm_device_get_ip_iface (self), rdisc->hop_limit); - - if (changed & NM_RDISC_CONFIG_MTU) { - char val[16]; + nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, nm_device_get_ip_iface (self), rdisc->hop_limit); - g_snprintf (val, sizeof (val), "%d", rdisc->mtu); - nm_device_ipv6_sysctl_set (self, "mtu", val); - } + if (changed & NM_RDISC_CONFIG_MTU) + priv->ip6_mtu = rdisc->mtu; nm_device_activate_schedule_ip6_config_result (self); } @@ -4213,11 +4661,12 @@ addrconf6_start_with_link_ready (NMDevice *self) g_assert (priv->rdisc); - if (!nm_device_get_ip_iface_identifier (self, &iid)) { + if (nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &iid)) { + _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); + } else if (!nm_device_get_ip_iface_identifier (self, &iid)) { _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 cannot continue"); return FALSE; } - nm_rdisc_set_iid (priv->rdisc, iid); /* Apply any manual configuration before starting RA */ if (!ip6_config_merge_and_apply (self, TRUE, NULL)) @@ -4236,6 +4685,8 @@ addrconf6_start_with_link_ready (NMDevice *self) NM_RDISC_RA_TIMEOUT, G_CALLBACK (rdisc_ra_timeout), self); + + nm_rdisc_set_iid (priv->rdisc, iid); nm_rdisc_start (priv->rdisc); return TRUE; } @@ -4325,7 +4776,7 @@ save_ip6_properties (NMDevice *self) g_hash_table_remove_all (priv->ip6_saved_properties); for (i = 0; i < G_N_ELEMENTS (ip6_properties_to_save); i++) { - value = nm_platform_sysctl_get (nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i])); + 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], @@ -4363,10 +4814,9 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ifindex = nm_device_get_ip_ifindex (self); - const char *iface = nm_device_get_ip_iface (self); char *value; - if (!nm_platform_check_support_user_ipv6ll ()) + if (!nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) return; priv->nm_ipv6ll = enable; @@ -4374,13 +4824,13 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) const char *detail = enable ? "enable" : "disable"; _LOGD (LOGD_IP6, "will %s userland IPv6LL", detail); - if ( !nm_platform_link_set_user_ipv6ll_enabled (ifindex, enable) - && nm_platform_get_error () != NM_PLATFORM_ERROR_NOT_FOUND) + if (!nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, enable)) _LOGW (LOGD_IP6, "failed to %s userspace IPv6LL address handling", detail); if (enable) { /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ - value = nm_platform_sysctl_get (nm_utils_ip6_property_path (iface, "disable_ipv6")); + 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) nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); g_free (value); @@ -4392,8 +4842,10 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) } } +/************************************************************************/ + static NMSettingIP6ConfigPrivacy -use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) +_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) { switch (use_tempaddr) { case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: @@ -4405,45 +4857,51 @@ use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) } } -/* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or - * /lib/sysctl.d/sysctl.conf - */ static NMSettingIP6ConfigPrivacy -ip6_use_tempaddr (void) +_ip6_privacy_get (NMDevice *self) { - char *contents = NULL; - const char *group_name = "[forged_group]\n"; - char *sysctl_data = NULL; - GKeyFile *keyfile; - GError *error = NULL; - gint tmp; - NMSettingIP6ConfigPrivacy ret = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + NMSettingIP6ConfigPrivacy ip6_privacy; + gs_free char *value = NULL; + NMConnection *connection; - /* Read file contents to a string. */ - if (!g_file_get_contents ("/etc/sysctl.conf", &contents, NULL, NULL)) - if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, NULL, NULL)) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - /* Prepend a group so that we can use GKeyFile parser. */ - sysctl_data = g_strdup_printf ("%s%s", group_name, contents); + /* 1.) First look at the per-connection setting. If it is not -1 (unknown), + * use it. */ + connection = nm_device_get_connection (self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - keyfile = g_key_file_new (); - if (!g_key_file_load_from_data (keyfile, sysctl_data, -1, G_KEY_FILE_NONE, NULL)) - goto done; + 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; + } + } - tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error); - if (error == NULL) - ret = use_tempaddr_clamp (tmp); + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ipv6.ip6-privacy", self); -done: - g_free (contents); - g_free (sysctl_data); - g_clear_error (&error); - g_key_file_free (keyfile); + /* 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; - return ret; + /* 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) { @@ -4525,6 +4983,13 @@ act_stage3_ip6_config_start (NMDevice *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. @@ -4535,18 +5000,7 @@ act_stage3_ip6_config_start (NMDevice *self, /* Re-enable IPv6 on the interface */ set_disable_ipv6 (self, "0"); - /* Enable/disable IPv6 Privacy Extensions. - * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf), - * use that value instead of per-connection value. - */ - ip6_privacy = ip6_use_tempaddr (); - if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) { - 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 = use_tempaddr_clamp (ip6_privacy); + ip6_privacy = _ip6_privacy_get (self); if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { if (!addrconf6_start (self, ip6_privacy)) { @@ -4734,11 +5188,11 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) priv->ip4_state = priv->ip6_state = IP_WAIT; - _LOGI (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) started..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) started..."); 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 */ - if (!nm_platform_link_is_up (nm_device_get_ip_ifindex (self))) + 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)); /* If the device is a slave, then we don't do any IP configuration but we @@ -4772,7 +5226,7 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) nm_device_check_ip_failed (self, TRUE); out: - _LOGI (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) complete."); + _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) complete."); return FALSE; } @@ -4796,7 +5250,7 @@ fw_change_zone_cb (GError *error, gpointer user_data) } activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0); - _LOGI (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) scheduled."); + _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) scheduled."); } /* @@ -4829,7 +5283,7 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) if (nm_device_uses_assumed_connection (self)) { _LOGD (LOGD_DEVICE, "Activation: skip setting firewall zone '%s' for assumed device", zone ? zone : "default"); activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0); - _LOGI (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) scheduled."); + _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) scheduled."); return; } @@ -4870,8 +5324,7 @@ nm_device_activate_ip4_config_timeout (gpointer user_data) /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, AF_INET); - _LOGI (LOGD_DEVICE | LOGD_IP4, - "Activation: Stage 4 of 5 (IPv4 Configure Timeout) started..."); + _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 4 of 5 (IPv4 Configure Timeout) started..."); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) @@ -4887,8 +5340,7 @@ nm_device_activate_ip4_config_timeout (gpointer user_data) nm_device_check_ip_failed (self, FALSE); out: - _LOGI (LOGD_DEVICE | LOGD_IP4, - "Activation: Stage 4 of 5 (IPv4 Configure Timeout) complete."); + _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 4 of 5 (IPv4 Configure Timeout) complete."); return FALSE; } @@ -4911,8 +5363,7 @@ nm_device_activate_schedule_ip4_config_timeout (NMDevice *self) activation_source_schedule (self, nm_device_activate_ip4_config_timeout, AF_INET); - _LOGI (LOGD_DEVICE | LOGD_IP4, - "Activation: Stage 4 of 5 (IPv4 Configure Timeout) scheduled..."); + _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 4 of 5 (IPv4 Configure Timeout) scheduled..."); } @@ -4945,8 +5396,7 @@ nm_device_activate_ip6_config_timeout (gpointer user_data) /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, AF_INET6); - _LOGI (LOGD_DEVICE | LOGD_IP6, - "Activation: Stage 4 of 5 (IPv6 Configure Timeout) started..."); + _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 4 of 5 (IPv6 Configure Timeout) started..."); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) @@ -4962,8 +5412,7 @@ nm_device_activate_ip6_config_timeout (gpointer user_data) nm_device_check_ip_failed (self, FALSE); out: - _LOGI (LOGD_DEVICE | LOGD_IP6, - "Activation: Stage 4 of 5 (IPv6 Configure Timeout) complete."); + _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 4 of 5 (IPv6 Configure Timeout) complete."); return FALSE; } @@ -4986,57 +5435,33 @@ nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) activation_source_schedule (self, nm_device_activate_ip6_config_timeout, AF_INET6); - _LOGI (LOGD_DEVICE | LOGD_IP6, - "Activation: Stage 4 of 5 (IPv6 Configure Timeout) scheduled..."); -} - -static void -share_child_setup (gpointer user_data G_GNUC_UNUSED) -{ - /* We are in the child process at this point */ - pid_t pid = getpid (); - setpgid (pid, pid); - - nm_unblock_posix_signals (NULL); + _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 4 of 5 (IPv6 Configure Timeout) scheduled..."); } static gboolean share_init (void) { - int status; 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; - if (!nm_platform_sysctl_set ("/proc/sys/net/ipv4/ip_forward", "1")) { + 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; } - if (!nm_platform_sysctl_set ("/proc/sys/net/ipv4/ip_dynaddr", "1")) { + 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++) { - char *argv[3] = { "/sbin/modprobe", *iter, NULL }; - char *envp[1] = { NULL }; - GError *error = NULL; - - if (!g_spawn_sync ("/", argv, envp, G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, - share_child_setup, NULL, NULL, NULL, &status, &error)) { - nm_log_err (LOGD_SHARING, "share: error loading NAT module %s: (%d) %s", - *iter, error ? error->code : 0, - (error && error->message) ? error->message : "unknown"); - if (error) - g_error_free (error); - } - } + for (iter = modules; *iter; iter++) + nm_utils_modprobe (NULL, FALSE, *iter, NULL); return TRUE; } @@ -5154,8 +5579,7 @@ send_arps (NMDevice *self, const char *mode_arg) "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, - nm_unblock_posix_signals, - NULL, NULL, &error); + NULL, NULL, NULL, &error); if (!success) { _LOGW (LOGD_DEVICE | LOGD_IP4, "arping: could not send ARP for local address %s: %s", @@ -5231,7 +5655,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data) /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, AF_INET); - _LOGI (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv4 Commit) started..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv4 Commit) started..."); req = nm_device_get_act_request (self); g_assert (req); @@ -5240,16 +5664,15 @@ nm_device_activate_ip4_config_commit (gpointer user_data) /* Interface must be IFF_UP before IP config can be applied */ ip_ifindex = nm_device_get_ip_ifindex (self); - if (!nm_platform_link_is_up (ip_ifindex) && !nm_device_uses_assumed_connection (self)) { - nm_platform_link_set_up (ip_ifindex); - if (!nm_platform_link_is_up (ip_ifindex)) + 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); + 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)) { - _LOGI (LOGD_DEVICE | LOGD_IP4, - "Activation: Stage 5 of 5 (IPv4 Commit) failed"); + _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } @@ -5291,11 +5714,28 @@ nm_device_activate_ip4_config_commit (gpointer user_data) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); out: - _LOGI (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv4 Commit) complete."); + _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv4 Commit) complete."); return FALSE; } +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) { @@ -5308,10 +5748,10 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf if (config) priv->dev_ip4_config = g_object_ref (config); + nm_device_queued_ip_config_change_clear (self); activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET); - _LOGI (LOGD_DEVICE | LOGD_IP4, - "Activation: Stage 5 of 5 (IPv4 Configure Commit) scheduled..."); + _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Configure Commit) scheduled..."); } gboolean @@ -5333,7 +5773,6 @@ nm_device_activate_ip6_config_commit (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint level = (priv->ip6_state == IP_DONE) ? LOGL_DEBUG : LOGL_INFO; NMActRequest *req; NMConnection *connection; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; @@ -5342,7 +5781,7 @@ nm_device_activate_ip6_config_commit (gpointer user_data) /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, AF_INET6); - _LOG (level, LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv6 Commit) started..."); + _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv6 Commit) started..."); req = nm_device_get_act_request (self); g_assert (req); @@ -5351,9 +5790,9 @@ nm_device_activate_ip6_config_commit (gpointer user_data) /* Interface must be IFF_UP before IP config can be applied */ ip_ifindex = nm_device_get_ip_ifindex (self); - if (!nm_platform_link_is_up (ip_ifindex) && !nm_device_uses_assumed_connection (self)) { - nm_platform_link_set_up (ip_ifindex); - if (!nm_platform_link_is_up (ip_ifindex)) + 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); + 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)); } @@ -5382,12 +5821,11 @@ nm_device_activate_ip6_config_commit (gpointer user_data) 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 { - _LOGW (LOGD_DEVICE | LOGD_IP6, - "Activation: Stage 5 of 5 (IPv6 Commit) failed"); + _LOGW (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); } - _LOG (level, LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv6 Commit) complete."); + _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv6 Commit) complete."); return FALSE; } @@ -5396,7 +5834,6 @@ void nm_device_activate_schedule_ip6_config_result (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint level = (priv->ip6_state == IP_DONE) ? LOGL_DEBUG : LOGL_INFO; g_return_if_fail (NM_IS_DEVICE (self)); @@ -5408,8 +5845,7 @@ nm_device_activate_schedule_ip6_config_result (NMDevice *self) activation_source_schedule (self, nm_device_activate_ip6_config_commit, AF_INET6); - _LOG (level, LOGD_DEVICE | LOGD_IP6, - "Activation: Stage 5 of 5 (IPv6 Commit) scheduled..."); + _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) scheduled..."); } gboolean @@ -5525,7 +5961,7 @@ delete_on_deactivate_link_delete (gpointer user_data) _LOGD (LOGD_DEVICE, "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", data->ifindex, data->idle_add_id); - nm_platform_link_delete (data->ifindex); + nm_platform_link_delete (NM_PLATFORM_GET, data->ifindex); g_free (data); return FALSE; } @@ -5659,7 +6095,7 @@ delete_cb (NMDevice *self, } /* Authorized */ - nm_platform_link_delete (nm_device_get_ifindex (self)); + nm_platform_link_delete (NM_PLATFORM_GET, nm_device_get_ifindex (self)); dbus_g_method_return (context); } @@ -5687,22 +6123,29 @@ impl_device_delete (NMDevice *self, DBusGMethodInvocation *context) NULL); } -static void +static gboolean _device_activate (NMDevice *self, NMActRequest *req) { NMDevicePrivate *priv; NMConnection *connection; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); + 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_connection (req); g_assert (connection); - _LOGI (LOGD_DEVICE, "Activation: starting connection '%s'", - nm_connection_get_id (connection)); + _LOGI (LOGD_DEVICE, "Activation: starting connection '%s' (%s)", + nm_connection_get_id (connection), + nm_connection_get_uuid (connection)); delete_on_deactivate_unschedule (self); @@ -5719,6 +6162,7 @@ _device_activate (NMDevice *self, NMActRequest *req) priv->act_request = g_object_ref (req); nm_device_activate_schedule_stage1_device_prepare (self); + return TRUE; } static void @@ -5785,6 +6229,26 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) } void +nm_device_steal_connection (NMDevice *self, NMConnection *connection) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + _LOGW (LOGD_DEVICE, "disconnecting connection '%s' for new activation request.", + nm_connection_get_id (connection)); + + if ( priv->queued_act_request + && connection == nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request))) + _clear_queued_act_request (priv); + + if ( priv->act_request + && connection == nm_active_connection_get_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); +} + +void nm_device_queue_activation (NMDevice *self, NMActRequest *req) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -5794,7 +6258,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) if (!priv->act_request && !must_queue) { /* Just activate immediately */ - _device_activate (self, req); + if (!_device_activate (self, req)) + g_assert_not_reached (); return; } @@ -5805,8 +6270,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) _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) { - /* Deactivate existing activation request first */ _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -5864,6 +6329,7 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *new_config, guint32 default_route_metric, gboolean commit, + gboolean routes_full_sync, NMDeviceStateReason *reason) { NMDevicePrivate *priv; @@ -5886,10 +6352,14 @@ nm_device_set_ip4_config (NMDevice *self, if (commit && new_config) { gboolean assumed = nm_device_uses_assumed_connection (self); - /* for assumed devices we set the device_route_metric to the default which will - * stop nm_platform_ip4_address_sync() to replace the device routes. */ + nm_device_set_mtu (self, nm_ip4_config_get_mtu (new_config)); + + /* 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, - assumed ? NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE : default_route_metric); + routes_full_sync, + assumed ? (gint64) -1 : (gint64) default_route_metric); if (!success) reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED; } @@ -5994,6 +6464,7 @@ static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *new_config, gboolean commit, + gboolean routes_full_sync, NMDeviceStateReason *reason) { NMDevicePrivate *priv; @@ -6014,7 +6485,10 @@ nm_device_set_ip6_config (NMDevice *self, /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { - success = nm_ip6_config_commit (new_config, ip_ifindex); + 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; } @@ -6187,19 +6661,67 @@ ip_check_gw_ping_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->gw_ping.watch) { - g_source_remove (priv->gw_ping.watch); - priv->gw_ping.watch = 0; - } - if (priv->gw_ping.timeout) { - g_source_remove (priv->gw_ping.timeout); - priv->gw_ping.timeout = 0; - } + 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 @@ -6208,6 +6730,7 @@ 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); guint log_domain = priv->gw_ping.log_domain; + gboolean success = FALSE; if (!priv->gw_ping.watch) return; @@ -6215,18 +6738,25 @@ ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data) priv->gw_ping.pid = 0; if (WIFEXITED (status)) { - if (WEXITSTATUS (status) == 0) + if (WEXITSTATUS (status) == 0) { _LOGD (log_domain, "ping: gateway ping succeeded"); - else { + 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); - /* We've got connectivity, proceed to pre_up */ - ip_check_gw_ping_cleanup (self); - ip_check_pre_up (self); + 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 @@ -6245,46 +6775,30 @@ ip_check_ping_timeout_cb (gpointer user_data) } static gboolean -spawn_ping (NMDevice *self, +start_ping (NMDevice *self, guint log_domain, const char *binary, const char *address, guint timeout) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *args[] = { binary, "-I", nm_device_get_ip_iface (self), "-c", "1", "-w", NULL, address, NULL }; - GError *error = NULL; - char *str_timeout; - gs_free char *tmp_str = NULL; - gboolean success; g_return_val_if_fail (priv->gw_ping.watch == 0, FALSE); g_return_val_if_fail (priv->gw_ping.timeout == 0, FALSE); - args[6] = str_timeout = g_strdup_printf ("%u", timeout); - - _LOGD (log_domain, "ping: running '%s'", - (tmp_str = g_strjoinv (" ", (gchar **) args))); + 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 */ - success = g_spawn_async ("/", - (gchar **) args, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD, - nm_unblock_posix_signals, - NULL, - &priv->gw_ping.pid, - &error); - if (success) { - priv->gw_ping.log_domain = log_domain; + 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 + 1, ip_check_ping_timeout_cb, self); - } else { - _LOGW (log_domain, "ping: could not spawn %s: %s", binary, error->message); - g_clear_error (&error); + priv->gw_ping.timeout = g_timeout_add_seconds (timeout, ip_check_ping_timeout_cb, self); + return TRUE; } - g_free (str_timeout); - return success; + ip_check_gw_ping_cleanup (self); + return FALSE; } static void @@ -6337,7 +6851,7 @@ nm_device_start_ip_check (NMDevice *self) } if (buf[0]) - spawn_ping (self, log_domain, ping_binary, buf, timeout); + start_ping (self, log_domain, ping_binary, buf, timeout); /* If no ping was started, just advance to pre_up */ if (!priv->gw_ping.pid) @@ -6375,7 +6889,7 @@ is_up (NMDevice *self) { int ifindex = nm_device_get_ip_ifindex (self); - return ifindex > 0 ? nm_platform_link_is_up (ifindex) : TRUE; + return ifindex > 0 ? nm_platform_link_is_up (NM_PLATFORM_GET, ifindex) : TRUE; } gboolean @@ -6400,7 +6914,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) do { g_usleep (200); - if (!nm_platform_link_refresh (ifindex)) + 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); @@ -6419,7 +6933,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) * complete (via a pending action) until either the carrier turns on, or * a timeout is reached. */ - if (device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { + if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { if (priv->carrier_wait_id) g_source_remove (priv->carrier_wait_id); else @@ -6434,15 +6948,6 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) return TRUE; } -static void -check_carrier (NMDevice *self) -{ - int ifindex = nm_device_get_ip_ifindex (self); - - if (!device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) - nm_device_set_carrier (self, nm_platform_link_is_connected (ifindex)); -} - static gboolean bring_up (NMDevice *self, gboolean *no_firmware) { @@ -6455,12 +6960,10 @@ bring_up (NMDevice *self, gboolean *no_firmware) return TRUE; } - result = nm_platform_link_set_up (ifindex); - if (no_firmware) - *no_firmware = nm_platform_get_error () == NM_PLATFORM_ERROR_NO_FIRMWARE; + result = nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, no_firmware); /* Store carrier immediately. */ - if (result && device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) + if (result && nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) check_carrier (self); return result; @@ -6487,7 +6990,7 @@ nm_device_take_down (NMDevice *self, gboolean block) do { g_usleep (200); - if (!nm_platform_link_refresh (ifindex)) + 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); @@ -6507,7 +7010,7 @@ take_down (NMDevice *self) int ifindex = nm_device_get_ip_ifindex (self); if (ifindex > 0) - return nm_platform_link_set_down (ifindex); + 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"); @@ -6634,11 +7137,10 @@ capture_lease_config (NMDevice *self, } static void -update_ip_config (NMDevice *self, gboolean initial) +update_ip4_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; @@ -6652,13 +7154,35 @@ update_ip_config (NMDevice *self, gboolean initial) /* IPv4 */ g_clear_object (&priv->ext_ip4_config); priv->ext_ip4_config = nm_ip4_config_capture (ifindex, capture_resolv_conf); - priv->ext_ip4_config_had_any_addresses = ( priv->ext_ip4_config - && nm_ip4_config_get_num_addresses (priv->ext_ip4_config) > 0); 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); } + + /* 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 + * (adresses,routes) that is no longer present externally from the interal + * config. This way, we don't readd 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); + if (priv->vpn4_config) + nm_ip4_config_intersect (priv->vpn4_config, 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); if (priv->vpn4_config) @@ -6668,18 +7192,53 @@ update_ip_config (NMDevice *self, gboolean initial) ip4_config_merge_and_apply (self, NULL, FALSE, NULL); } +} + +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); - priv->ext_ip6_config_had_any_addresses = ( priv->ext_ip6_config - && nm_ip6_config_get_num_addresses (priv->ext_ip6_config) > 0); 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 + * (adresses,routes) that is no longer present externally from the interal + * config. This way, we don't readd 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); + if (priv->vpn6_config) + nm_ip6_config_intersect (priv->vpn6_config, 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) @@ -6703,11 +7262,12 @@ update_ip_config (NMDevice *self, gboolean initial) void nm_device_capture_initial_config (NMDevice *self) { - update_ip_config (self, TRUE); + update_ip4_config (self, TRUE); + update_ip6_config (self, TRUE); } static gboolean -queued_ip_config_change (gpointer user_data) +queued_ip4_config_change (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -6716,8 +7276,27 @@ queued_ip_config_change (gpointer user_data) if (priv->queued_state.id) return TRUE; - priv->queued_ip_config_id = 0; - update_ip_config (self, FALSE); + 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); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* Wait for any queued state changes */ + if (priv->queued_state.id) + return TRUE; + + priv->queued_ip6_config_id = 0; + g_object_ref (self); + update_ip6_config (self, FALSE); /* 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 @@ -6727,36 +7306,43 @@ queued_ip_config_change (gpointer user_data) if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config)) check_and_add_ipv6ll_addr (self); + g_object_unref (self); + return FALSE; } static void -device_ip_changed (NMPlatform *platform, - int ifindex, - gpointer platform_object, - NMPlatformSignalChangeType change_type, - NMPlatformReason reason, - NMDevice *self) +device_ipx_changed (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + gpointer platform_object, + NMPlatformSignalChangeType change_type, + NMPlatformReason reason, + NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (nm_device_get_ip_ifindex (self) == ifindex) { - if (!priv->queued_ip_config_id) - priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self); - - _LOGD (LOGD_DEVICE, "queued IP config change"); - } -} + NMDevicePrivate *priv; -static void -nm_device_queued_ip_config_change_clear (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + if (nm_device_get_ip_ifindex (self) != ifindex) + return; - if (priv->queued_ip_config_id) { - _LOGD (LOGD_DEVICE, "clearing queued IP config change"); - g_source_remove (priv->queued_ip_config_id); - priv->queued_ip_config_id = 0; + 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: + 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 (); } } @@ -6840,7 +7426,7 @@ nm_device_set_unmanaged (NMDevice *self, if (unmanaged) nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason); - else + else if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED) nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason); } } @@ -7099,7 +7685,7 @@ cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gpoin gboolean nm_device_supports_vlans (NMDevice *self) { - return nm_platform_link_supports_vlans (nm_device_get_ifindex (self)); + return nm_platform_link_supports_vlans (NM_PLATFORM_GET, nm_device_get_ifindex (self)); } /** @@ -7206,16 +7792,16 @@ nm_device_has_pending_action (NMDevice *self) /***********************************************************/ static void -_cleanup_ip_pre (NMDevice *self, gboolean deconfigure) +_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, deconfigure, FALSE); + dhcp4_cleanup (self, cleanup_type, FALSE); arp_cleanup (self); - dhcp6_cleanup (self, deconfigure, FALSE); + dhcp6_cleanup (self, cleanup_type, FALSE); linklocal6_cleanup (self); addrconf6_cleanup (self); dnsmasq_cleanup (self); @@ -7223,10 +7809,9 @@ _cleanup_ip_pre (NMDevice *self, gboolean deconfigure) } static void -_cleanup_generic_pre (NMDevice *self, gboolean deconfigure) +_cancel_activation (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; /* Clean up when device was deactivated during call to firewall */ if (priv->fw_call) { @@ -7234,8 +7819,22 @@ _cleanup_generic_pre (NMDevice *self, gboolean deconfigure) priv->fw_call = NULL; } + ip_check_gw_ping_cleanup (self); + + /* Break the activation chain */ + activation_source_clear (self, TRUE, AF_INET); + activation_source_clear (self, TRUE, AF_INET6); +} + +static void +_cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type) +{ + NMConnection *connection; + + _cancel_activation (self); + connection = nm_device_get_connection (self); - if ( deconfigure + if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE && connection && !nm_device_uses_assumed_connection (self)) { nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (), @@ -7243,28 +7842,24 @@ _cleanup_generic_pre (NMDevice *self, gboolean deconfigure) NULL); } - ip_check_gw_ping_cleanup (self); - - /* Break the activation chain */ - activation_source_clear (self, TRUE, AF_INET); - activation_source_clear (self, TRUE, AF_INET6); - /* Clear any queued transitions */ nm_device_queued_state_clear (self); - _cleanup_ip_pre (self, deconfigure); + _cleanup_ip_pre (self, cleanup_type); } static void -_cleanup_generic_post (NMDevice *self, gboolean deconfigure) +_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.v4_is_assumed = TRUE; + priv->default_route.v4_configure_first_time = TRUE; priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; + priv->default_route.v6_configure_first_time = 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); @@ -7272,22 +7867,21 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure) /* 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, &ignored); - nm_device_set_ip6_config (self, NULL, TRUE, &ignored); + 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->vpn4_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->vpn6_config); g_clear_object (&priv->wwan_ip6_config); g_clear_object (&priv->ip6_config); - priv->ext_ip4_config_had_any_addresses = FALSE; - priv->ext_ip6_config_had_any_addresses = FALSE; - clear_act_request (self); /* Clear legacy IPv4 address property */ @@ -7296,7 +7890,7 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure) g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_ADDRESS); } - if (deconfigure) { + 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. */ @@ -7317,7 +7911,7 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure) * */ static void -nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, gboolean deconfigure) +nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType cleanup_type) { NMDevicePrivate *priv; int ifindex; @@ -7325,17 +7919,17 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, gboolean deconfig g_return_if_fail (NM_IS_DEVICE (self)); if (reason == NM_DEVICE_STATE_REASON_NOW_MANAGED) - _LOGI (LOGD_DEVICE, "preparing device"); + _LOGD (LOGD_DEVICE, "preparing device"); else - _LOGI (LOGD_DEVICE, "deactivating device (reason '%s') [%d]", reason_to_string (reason), reason); + _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, deconfigure); + _cleanup_generic_pre (self, cleanup_type); /* Turn off kernel IPv6 */ - if (deconfigure) { + 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"); @@ -7356,11 +7950,11 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, gboolean deconfig /* 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_platform_route_flush (ifindex); - nm_platform_address_flush (ifindex); + nm_route_manager_route_flush (nm_route_manager_get (), ifindex); + nm_platform_address_flush (NM_PLATFORM_GET, ifindex); } - _cleanup_generic_post (self, deconfigure); + _cleanup_generic_post (self, cleanup_type); } static char * @@ -7689,11 +8283,11 @@ _set_state_full (NMDevice *self, 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, FALSE); + 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, TRUE); + nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); nm_device_take_down (self, TRUE); set_nm_ipv6ll (self, FALSE); restore_ip6_properties (self); @@ -7722,7 +8316,7 @@ _set_state_full (NMDevice *self, * 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, TRUE); + nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); } break; case NM_DEVICE_STATE_DISCONNECTED: @@ -7732,7 +8326,7 @@ _set_state_full (NMDevice *self, */ set_nm_ipv6ll (self, TRUE); - nm_device_cleanup (self, reason, 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 @@ -7747,7 +8341,7 @@ _set_state_full (NMDevice *self, /* Clean up any half-done IP operations if the device's layer2 * finds out it needs authentication during IP config. */ - _cleanup_ip_pre (self, TRUE); + _cleanup_ip_pre (self, CLEANUP_TYPE_DECONFIGURE); } break; default: @@ -7774,8 +8368,9 @@ _set_state_full (NMDevice *self, * reasons. */ if (nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { - _LOGD (LOGD_DEVICE, "device is available, will transition to DISCONNECTED"); - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_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"); @@ -7785,6 +8380,14 @@ _set_state_full (NMDevice *self, } 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_connection (req), @@ -7807,13 +8410,18 @@ _set_state_full (NMDevice *self, if ( priv->queued_act_request && !priv->queued_act_request_is_waiting_for_carrier) { NMActRequest *queued_req; + gboolean success; queued_req = priv->queued_act_request; priv->queued_act_request = NULL; - _device_activate (self, queued_req); + success = _device_activate (self, queued_req); g_object_unref (queued_req); - } else if ( old_state > NM_DEVICE_STATE_DISCONNECTED - && nm_device_get_default_unmanaged (self)) + 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: @@ -8026,7 +8634,7 @@ nm_device_update_hw_address (NMDevice *self) if (ifindex <= 0) return; - hwaddr = nm_platform_link_get_address (ifindex, &hwaddrlen); + hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen); if (hwaddrlen) { if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) { @@ -8072,7 +8680,7 @@ nm_device_set_hw_addr (NMDevice *self, const char *addr, /* Can't change MAC address while device is up */ nm_device_take_down (self, FALSE); - success = nm_platform_link_set_address (nm_device_get_ip_ifindex (self), addr_bytes, priv->hw_addr_len); + 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); @@ -8094,6 +8702,22 @@ nm_device_set_hw_addr (NMDevice *self, const char *addr, 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; +} + /** * nm_device_spec_match_list: * @self: an #NMDevice @@ -8123,24 +8747,34 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs) if (!specs) return FALSE; - return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs); + return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs) == NM_MATCH_SPEC_MATCH; } -static gboolean +static NMMatchSpecMatchType spec_match_list (NMDevice *self, const GSList *specs) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean matched = FALSE; - - if (nm_match_spec_string (specs, "*")) - return TRUE; - - if (priv->hw_addr_len) - matched = nm_match_spec_hwaddr (specs, priv->hw_addr); - - if (!matched) - matched = nm_match_spec_interface_name (specs, nm_device_get_iface (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; } @@ -8165,47 +8799,9 @@ nm_device_init (NMDevice *self) 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.v4_configure_first_time = TRUE; priv->default_route.v6_is_assumed = TRUE; -} - -/* - * Get driver info from SIOCETHTOOL ioctl() for 'iface' - * Returns driver and firmware versions to 'driver_version and' 'firmware_version' - */ -static gboolean -device_get_driver_info (NMDevice *self, const char *iface, char **driver_version, char **firmware_version) -{ - struct ethtool_drvinfo drvinfo; - struct ifreq req; - int fd; - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW, "couldn't open control socket."); - return FALSE; - } - - /* Get driver and firmware version info */ - memset (&drvinfo, 0, sizeof (drvinfo)); - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, iface, IFNAMSIZ); - drvinfo.cmd = ETHTOOL_GDRVINFO; - req.ifr_data = &drvinfo; - - errno = 0; - if (ioctl (fd, SIOCETHTOOL, &req) < 0) { - _LOGD (LOGD_HW, "SIOCETHTOOL ioctl() failed: cmd=ETHTOOL_GDRVINFO, iface=%s, errno=%d", - iface, errno); - close (fd); - return FALSE; - } - if (driver_version) - *driver_version = g_strdup (drvinfo.version); - if (firmware_version) - *firmware_version = g_strdup (drvinfo.fw_version); - - close (fd); - return TRUE; + priv->default_route.v6_configure_first_time = TRUE; } static GObject* @@ -8243,27 +8839,40 @@ constructor (GType type, if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); - if (priv->ifindex <= 0 && !device_has_capability (self, NM_DEVICE_CAP_IS_NON_KERNEL)) - _LOGW (LOGD_HW, "failed to look up interface index"); + if (priv->ifindex > 0) { + priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex); + 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); + + nm_platform_link_get_driver_info (NM_PLATFORM_GET, + priv->ifindex, + NULL, + &priv->driver_version, + &priv->firmware_version); + } - device_get_driver_info (self, priv->iface, &priv->driver_version, &priv->firmware_version); + 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_ip_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (device_ip_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (device_ip_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ip_changed), self); + 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); /* trigger initial ip config change to initialize ip-config */ - priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self); + 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); - if (nm_platform_check_support_user_ipv6ll ()) { + if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) { int ip_ifindex = nm_device_get_ip_ifindex (self); if (ip_ifindex > 0) - priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (ip_ifindex); + priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, ip_ifindex); } return object; @@ -8282,18 +8891,39 @@ constructed (GObject *object) nm_device_update_hw_address (self); - if (NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address) - NM_DEVICE_GET_CLASS (self)->update_permanent_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 (NM_DEVICE_GET_CLASS (self)->update_initial_hw_address) - NM_DEVICE_GET_CLASS (self)->update_initial_hw_address (self); + 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); + } + } + } - /* Have to call update_initial_hw_address() before calling get_ignore_carrier() */ - if (device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - priv->ignore_carrier = nm_config_get_ignore_carrier (nm_config_get (), self); + /* 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); - _LOGI (LOGD_HW, + _LOGD (LOGD_HW, "carrier is %s%s", priv->carrier ? "ON" : "OFF", priv->ignore_carrier ? " (but ignored)" : ""); @@ -8302,18 +8932,8 @@ constructed (GObject *object) priv->carrier = TRUE; } - if (priv->ifindex > 0) { - priv->is_software = nm_platform_link_is_software (priv->ifindex); - priv->physical_port_id = nm_platform_link_get_physical_port_id (priv->ifindex); - priv->dev_id = nm_platform_link_get_dev_id (priv->ifindex); - priv->mtu = nm_platform_link_get_mtu (priv->ifindex); - } - /* Indicate software device in capabilities. */ - if (priv->is_software) - priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; - /* Enslave ourselves */ - master = nm_platform_link_get_master (priv->ifindex); + master = nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex); if (master) device_set_master (self, master); @@ -8355,9 +8975,11 @@ dispose (GObject *object) _LOGD (LOGD_DEVICE, "dispose(): %s", G_OBJECT_TYPE_NAME (self)); + g_signal_handlers_disconnect_by_func (nm_config_get (), config_changed_update_ignore_carrier, self); + dispatcher_cleanup (self); - _cleanup_generic_pre (self, FALSE); + _cleanup_generic_pre (self, CLEANUP_TYPE_KEEP); g_warn_if_fail (priv->slaves == NULL); g_assert (priv->master_ready_id == 0); @@ -8365,7 +8987,7 @@ dispose (GObject *object) /* Let the kernel manage IPv6LL again */ set_nm_ipv6ll (self, FALSE); - _cleanup_generic_post (self, FALSE); + _cleanup_generic_post (self, CLEANUP_TYPE_KEEP); g_hash_table_remove_all (priv->ip6_saved_properties); @@ -8374,6 +8996,11 @@ dispose (GObject *object) 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) { @@ -8393,9 +9020,12 @@ dispose (GObject *object) _clear_queued_act_request (priv); platform = nm_platform_get (); - g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self); + 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); + G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); } @@ -8408,6 +9038,8 @@ finalize (GObject *object) _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_clear_pointer (&priv->physical_port_id, g_free); g_free (priv->udi); @@ -8418,6 +9050,7 @@ finalize (GObject *object) 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); @@ -8435,19 +9068,20 @@ set_property (GObject *object, guint prop_id, NMPlatformLink *platform_device; const char *hw_addr, *p; guint count; - + switch (prop_id) { case PROP_PLATFORM_DEVICE: platform_device = g_value_get_pointer (value); if (platform_device) { g_free (priv->udi); - priv->udi = g_strdup (platform_device->udi); + priv->udi = g_strdup (nm_platform_link_get_udi (NM_PLATFORM_GET, platform_device->ifindex)); g_free (priv->iface); priv->iface = g_strdup (platform_device->name); priv->ifindex = platform_device->ifindex; - priv->up = platform_device->up; + priv->up = NM_FLAGS_HAS (platform_device->flags, IFF_UP); g_free (priv->driver); priv->driver = g_strdup (platform_device->driver); + priv->platform_link_initialized = platform_device->initialized; } break; case PROP_UDI: @@ -8460,9 +9094,9 @@ set_property (GObject *object, guint prop_id, if (g_value_get_string (value)) { g_free (priv->iface); priv->iface = g_value_dup_string (value); - priv->ifindex = nm_platform_link_get_ifindex (priv->iface); + priv->ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->iface); if (priv->ifindex > 0) - priv->up = nm_platform_link_is_up (priv->ifindex); + priv->up = nm_platform_link_is_up (NM_PLATFORM_GET, priv->ifindex); } break; case PROP_DRIVER: @@ -8696,10 +9330,12 @@ nm_device_class_init (NMDeviceClass *klass) 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->is_up = is_up; klass->bring_up = bring_up; klass->take_down = take_down; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index e204af84..f1dab9bf 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -130,19 +130,17 @@ typedef struct { void (* link_changed) (NMDevice *self, NMPlatformLink *info); /* Hardware state (IFF_UP) */ - gboolean (*is_up) (NMDevice *self); - gboolean (*bring_up) (NMDevice *self, gboolean *no_firmware); - gboolean (*take_down) (NMDevice *self); + gboolean (*can_unmanaged_external_down) (NMDevice *self); + gboolean (*is_up) (NMDevice *self); + gboolean (*bring_up) (NMDevice *self, gboolean *no_firmware); + gboolean (*take_down) (NMDevice *self); /* Carrier state (IFF_LOWER_UP) */ void (*carrier_changed) (NMDevice *, gboolean carrier); - void (* update_permanent_hw_address) (NMDevice *self); - void (* update_initial_hw_address) (NMDevice *self); - gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid); - guint32 (* get_generic_capabilities) (NMDevice *self); + NMDeviceCapabilities (* get_generic_capabilities) (NMDevice *self); gboolean (* is_available) (NMDevice *self, NMDeviceCheckDevAvailableFlags flags); @@ -213,7 +211,9 @@ typedef struct { /* Sync deactivating (in the DISCONNECTED phase) */ void (* deactivate) (NMDevice *self); - gboolean (* spec_match_list) (NMDevice *self, const GSList *specs); + const char *(*get_type_description) (NMDevice *self); + + NMMatchSpecMatchType (* spec_match_list) (NMDevice *self, const GSList *specs); /* Update the connection with currently configured L2 settings */ void (* update_connection) (NMDevice *device, NMConnection *connection); @@ -235,6 +235,21 @@ typedef struct { gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves); + /** + * component_added: + * @self: the #NMDevice + * @component: the component (device, modem, etc) which was added + * + * Notifies @self that a new component was added to the Manager. This + * may include any kind of %GObject subclass, and the device is expected + * to match only specific components they care about, like %NMModem objects + * or %NMDevice objects. + * + * Returns: %TRUE if the component was claimed exclusively and no further + * devices should be notified of the new component. %FALSE to indicate + * that the component was not exclusively claimed and other devices should + * be notified. + */ gboolean (* component_added) (NMDevice *self, GObject *component); gboolean (* owns_iface) (NMDevice *self, const char *iface); @@ -264,13 +279,16 @@ int nm_device_get_ip_ifindex(NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); +const char * nm_device_get_type_description (NMDevice *dev); NMDeviceType nm_device_get_device_type (NMDevice *dev); int nm_device_get_priority (NMDevice *dev); guint32 nm_device_get_ip4_route_metric (NMDevice *dev); guint32 nm_device_get_ip6_route_metric (NMDevice *dev); -const char * nm_device_get_hw_address (NMDevice *dev); +const char * nm_device_get_hw_address (NMDevice *dev); +const char * nm_device_get_permanent_hw_address (NMDevice *dev); +const char * nm_device_get_initial_hw_address (NMDevice *dev); NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev); @@ -342,6 +360,8 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device); * @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs) * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged * @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM + * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not + * yet initialized */ typedef enum { NM_UNMANAGED_NONE = 0x00, @@ -350,6 +370,7 @@ typedef enum { NM_UNMANAGED_USER = 0x04, NM_UNMANAGED_PARENT = 0x08, NM_UNMANAGED_EXTERNAL_DOWN = 0x10, + NM_UNMANAGED_PLATFORM_INIT = 0x20, /* Boundary value */ __NM_UNMANAGED_LAST, @@ -371,6 +392,8 @@ void nm_device_set_initial_unmanaged_flag (NMDevice *device, gboolean nm_device_get_is_nm_owned (NMDevice *device); void nm_device_set_nm_owned (NMDevice *device); +gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps); + gboolean nm_device_get_autoconnect (NMDevice *device); void nm_device_handle_autoip4_event (NMDevice *self, @@ -387,6 +410,8 @@ void nm_device_queue_state (NMDevice *self, gboolean nm_device_get_firmware_missing (NMDevice *self); +void nm_device_steal_connection (NMDevice *device, NMConnection *connection); + void nm_device_queue_activation (NMDevice *device, NMActRequest *req); gboolean nm_device_supports_vlans (NMDevice *device); diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in index 29ad0598..342c41ee 100644 --- a/src/devices/team/Makefile.in +++ b/src/devices/team/Makefile.in @@ -227,6 +227,7 @@ ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -340,6 +341,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 49202c36..23750f35 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -39,7 +39,6 @@ #include "nm-dbus-manager.h" #include "nm-enum-types.h" #include "nm-team-enum-types.h" -#include "nm-posix-signals.h" #include "nm-core-internal.h" #include "gsystem-local-alloc.h" @@ -71,18 +70,16 @@ static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); /******************************************************************/ -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { - return NM_DEVICE_CAP_CARRIER_DETECT; + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } static gboolean is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { - if (NM_DEVICE_GET_CLASS (device)->is_up) - return NM_DEVICE_GET_CLASS (device)->is_up (device); - return FALSE; + return TRUE; } static gboolean @@ -424,23 +421,6 @@ teamd_process_watch_cb (GPid pid, gint status, gpointer user_data) } } -static void -teamd_child_setup (gpointer user_data G_GNUC_UNUSED) -{ - /* We are in the child process at this point. - * Give child it's own program group for signal - * separation. - */ - pid_t pid = getpid (); - setpgid (pid, pid); - - /* - * We blocked signals in main(). We need to restore original signal - * mask for avahi-autoipd here so that it can receive signals. - */ - nm_unblock_posix_signals (NULL); -} - static gboolean teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) { @@ -448,7 +428,7 @@ teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) gs_free char *tmp_str = NULL; if (!teamd_binary) { - teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL); + teamd_binary = nm_utils_find_helper ("teamd", NULL, error); if (!teamd_binary) { _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: teamd binary not found"); return FALSE; @@ -463,7 +443,7 @@ teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) g_ptr_array_add (argv, NULL); _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); - return g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, NULL, error); + return g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, NULL, NULL, NULL, NULL, NULL, error); } static gboolean @@ -514,7 +494,7 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); if (!g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, - teamd_child_setup, NULL, &priv->teamd_pid, &error)) { + nm_utils_setpgid, NULL, &priv->teamd_pid, &error)) { _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: %s", error->message); teamd_cleanup (device, TRUE); return FALSE; @@ -638,7 +618,8 @@ enslave_slave (NMDevice *device, } } } - success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device), + success = nm_platform_link_enslave (NM_PLATFORM_GET, + nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); nm_device_bring_up (slave, TRUE, &no_firmware); @@ -663,7 +644,8 @@ release_slave (NMDevice *device, gboolean success = TRUE, no_firmware = FALSE; if (configure) { - success = nm_platform_link_release (nm_device_get_ip_ifindex (device), + success = nm_platform_link_release (NM_PLATFORM_GET, + nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); if (success) @@ -694,8 +676,6 @@ release_slave (NMDevice *device, NMDevice * nm_device_team_new (NMPlatformLink *platform_device) { - g_return_val_if_fail (platform_device != NULL, NULL); - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM, NM_DEVICE_PLATFORM_DEVICE, platform_device, NM_DEVICE_DRIVER, "team", @@ -708,21 +688,18 @@ nm_device_team_new (NMPlatformLink *platform_device) NMDevice * nm_device_team_new_for_connection (NMConnection *connection, GError **error) { - const char *iface; - - g_return_val_if_fail (connection != NULL, NULL); - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); - - if ( !nm_platform_team_add (iface) - && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "failed to create team master interface '%s' for connection '%s': %s", - iface, nm_connection_get_id (connection), - nm_platform_get_error_msg ()); + const char *iface = nm_connection_get_interface_name (connection); + NMPlatformError plerr; + + g_assert (iface); + + plerr = nm_platform_team_add (NM_PLATFORM_GET, iface, NULL); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create team master interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); return NULL; } diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index cb887cac..d87919b6 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -48,11 +48,9 @@ nm_device_factory_create (GError **error) /************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_TEAM) - return nm_device_team_new (plink); - return NULL; + return nm_device_team_new (plink); } static NMDevice * @@ -61,16 +59,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) - return nm_device_team_new_for_connection (connection, error); - return NULL; + return nm_device_team_new_for_connection (connection, error); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_TEAM; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TEAM) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TEAM_SETTING_NAME) +) /************************************************************************/ @@ -84,7 +79,7 @@ device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wifi/Makefile.in b/src/devices/wifi/Makefile.in index f5e88007..b679bfc2 100644 --- a/src/devices/wifi/Makefile.in +++ b/src/devices/wifi/Makefile.in @@ -267,6 +267,7 @@ ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -380,6 +381,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index dc3dfbc6..e67d1a20 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -197,8 +197,8 @@ _mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel) { int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - if (nm_platform_mesh_get_channel (ifindex) != channel) { - if (nm_platform_mesh_set_channel (ifindex, channel)) + if (nm_platform_mesh_get_channel (NM_PLATFORM_GET, ifindex) != channel) { + if (nm_platform_mesh_set_channel (NM_PLATFORM_GET, ifindex, channel)) g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL); } } @@ -224,7 +224,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) _mesh_set_channel (self, channel); ssid = nm_setting_olpc_mesh_get_ssid (s_mesh); - nm_platform_mesh_set_ssid (nm_device_get_ifindex (device), + nm_platform_mesh_set_ssid (NM_PLATFORM_GET, + nm_device_get_ifindex (device), g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); @@ -368,9 +369,9 @@ device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data) NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); if (!priv->companion && check_companion (self, other)) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); + nm_device_queue_recheck_available (NM_DEVICE (self), + NM_DEVICE_STATE_REASON_NONE, + NM_DEVICE_STATE_REASON_NONE); nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion", TRUE); } } @@ -398,9 +399,9 @@ find_companion (NMDeviceOlpcMesh *self) /* Try to find the companion if it's already known to the NMManager */ for (list = nm_manager_get_devices (nm_manager_get ()); list ; list = g_slist_next (list)) { if (check_companion (self, NM_DEVICE (list->data))) { - nm_device_queue_state (NM_DEVICE (self), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); + nm_device_queue_recheck_available (NM_DEVICE (self), + NM_DEVICE_STATE_REASON_NONE, + NM_DEVICE_STATE_REASON_NONE); nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion", TRUE); break; } @@ -453,7 +454,7 @@ constructor (GType type, self = NM_DEVICE_OLPC_MESH (object); - if (!nm_platform_wifi_get_capabilities (nm_device_get_ifindex (NM_DEVICE (self)), &caps)) { + if (!nm_platform_wifi_get_capabilities (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &caps)) { _LOGW (LOGD_HW | LOGD_OLPC, "failed to initialize WiFi driver"); g_object_unref (object); return NULL; @@ -482,7 +483,7 @@ get_property (GObject *object, guint prop_id, g_value_set_boxed (value, "/"); break; case PROP_ACTIVE_CHANNEL: - g_value_set_uint (value, nm_platform_mesh_get_channel (nm_device_get_ifindex (NM_DEVICE (device)))); + g_value_set_uint (value, nm_platform_mesh_get_channel (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (device)))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index ce9a3f75..2e116f87 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -26,13 +26,7 @@ #include <dbus/dbus.h> #include <netinet/in.h> #include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <signal.h> #include <unistd.h> -#include <linux/sockios.h> -#include <linux/ethtool.h> -#include <sys/ioctl.h> #include <errno.h> #include "nm-glib-compat.h" @@ -116,10 +110,7 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _NMDeviceWifiPrivate { - gboolean disposed; - - char * perm_hw_addr; /* Permanent MAC address */ - char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ + gboolean disposed; gint8 invalid_strength_counter; @@ -165,7 +156,7 @@ static void supplicant_iface_state_cb (NMSupplicantInterface *iface, static void supplicant_iface_new_bss_cb (NMSupplicantInterface * iface, const char *object_path, - GHashTable *properties, + GVariant *properties, NMDeviceWifi * self); static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, @@ -213,7 +204,8 @@ constructor (GType type, self = NM_DEVICE_WIFI (object); priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - if (!nm_platform_wifi_get_capabilities (nm_device_get_ifindex (NM_DEVICE (self)), + if (!nm_platform_wifi_get_capabilities (NM_PLATFORM_GET, + nm_device_get_ifindex (NM_DEVICE (self)), &priv->capabilities)) { _LOGW (LOGD_HW | LOGD_WIFI, "failed to initialize WiFi driver"); g_object_unref (object); @@ -362,21 +354,21 @@ find_active_ap (NMDeviceWifi *self, NM80211Mode devmode; guint32 devfreq; - nm_platform_wifi_get_bssid (ifindex, bssid); + nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid); _LOGD (LOGD_WIFI, "active BSSID: %02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); if (!nm_ethernet_address_is_valid (bssid, ETH_ALEN)) return NULL; - ssid = nm_platform_wifi_get_ssid (ifindex); + ssid = nm_platform_wifi_get_ssid (NM_PLATFORM_GET, ifindex); _LOGD (LOGD_WIFI, "active SSID: %s%s%s", ssid ? "'" : "", ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", ssid ? "'" : ""); - devmode = nm_platform_wifi_get_mode (ifindex); - devfreq = nm_platform_wifi_get_frequency (ifindex); + devmode = nm_platform_wifi_get_mode (NM_PLATFORM_GET, ifindex); + devfreq = nm_platform_wifi_get_frequency (NM_PLATFORM_GET, ifindex); /* When matching hidden APs, do a second pass that ignores the SSID check, * because NM might not yet know the SSID of the hidden AP in the scan list @@ -591,7 +583,7 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) if (priv->current_ap && (nm_ap_get_mode (priv->current_ap) == NM_802_11_MODE_ADHOC)) { guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; - nm_platform_wifi_get_bssid (ifindex, bssid); + nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid); /* 0x02 means "locally administered" and should be OR-ed into * the first byte of IBSS BSSIDs. */ @@ -607,7 +599,7 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) /* Try to smooth out the strength. Atmel cards, for example, will give no strength * one second and normal strength the next. */ - percent = nm_platform_wifi_get_quality (ifindex); + percent = nm_platform_wifi_get_quality (NM_PLATFORM_GET, ifindex); if (percent >= 0 || ++priv->invalid_strength_counter > 3) { nm_ap_set_strength (new_ap, (gint8) percent); priv->invalid_strength_counter = 0; @@ -639,7 +631,7 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) set_current_ap (self, new_ap, TRUE, FALSE); } - new_rate = nm_platform_wifi_get_rate (ifindex); + new_rate = nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex); if (new_rate != priv->rate) { priv->rate = new_rate; g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_BITRATE); @@ -738,18 +730,18 @@ deactivate (NMDevice *device) set_current_ap (self, NULL, TRUE, FALSE); /* Clear any critical protocol notification in the Wi-Fi stack */ - nm_platform_wifi_indicate_addressing_running (ifindex, FALSE); + nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_WIFI); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI); /* Ensure we're in infrastructure mode after deactivation; some devices * (usually older ones) don't scan well in adhoc mode. */ - if (nm_platform_wifi_get_mode (ifindex) != NM_802_11_MODE_INFRA) { + if (nm_platform_wifi_get_mode (NM_PLATFORM_GET, ifindex) != NM_802_11_MODE_INFRA) { nm_device_take_down (NM_DEVICE (self), TRUE); - nm_platform_wifi_set_mode (ifindex, NM_802_11_MODE_INFRA); + nm_platform_wifi_set_mode (NM_PLATFORM_GET, ifindex, NM_802_11_MODE_INFRA); nm_device_bring_up (NM_DEVICE (self), TRUE, NULL); } @@ -806,6 +798,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char * const *mac_blacklist; int i; const char *mode; + const char *perm_hw_addr; if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection)) return FALSE; @@ -820,21 +813,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_wireless) return FALSE; + perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); - if (mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1)) - return FALSE; - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); + if (perm_hw_addr) { + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) return FALSE; - } - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1)) - return FALSE; - } + /* Check for MAC address blacklist */ + mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); + for (i = 0; mac_blacklist[i]; i++) { + if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { + g_warn_if_reached (); + return FALSE; + } + + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + return FALSE; + } + } else if (mac) + return FALSE; if (is_adhoc_wpa (connection)) return FALSE; @@ -970,6 +967,7 @@ complete_connection (NMDevice *device, GBytes *setting_ssid = NULL; GSList *iter; gboolean hidden = FALSE; + const char *perm_hw_addr; s_wifi = nm_connection_get_setting_wireless (connection); s_wsec = nm_connection_get_setting_wireless_security (connection); @@ -1105,29 +1103,31 @@ complete_connection (NMDevice *device, if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - setting_mac = nm_setting_wireless_get_mac_address (s_wifi); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); - return FALSE; - } - } else { - guint8 perm_hw_addr[ETH_ALEN]; + perm_hw_addr = nm_device_get_permanent_hw_address (device); + if (perm_hw_addr) { + setting_mac = nm_setting_wireless_get_mac_address (s_wifi); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match device")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); + return FALSE; + } + } else { + guint8 tmp[ETH_ALEN]; - /* Lock the connection to this device by default if it uses a - * permanent MAC address (ie not a 'locally administered' one) - */ - nm_utils_hwaddr_aton (priv->perm_hw_addr, perm_hw_addr, ETH_ALEN); - if ( !(perm_hw_addr[0] & 0x02) - && !nm_utils_hwaddr_matches (perm_hw_addr, ETH_ALEN, NULL, ETH_ALEN)) { - g_object_set (G_OBJECT (s_wifi), - NM_SETTING_WIRELESS_MAC_ADDRESS, priv->perm_hw_addr, - NULL); + /* Lock the connection to this device by default if it uses a + * permanent MAC address (ie not a 'locally administered' one) + */ + nm_utils_hwaddr_aton (perm_hw_addr, tmp, ETH_ALEN); + if (!(tmp[0] & 0x02)) { + g_object_set (G_OBJECT (s_wifi), + NM_SETTING_WIRELESS_MAC_ADDRESS, perm_hw_addr, + NULL); + } } } @@ -1832,7 +1832,7 @@ schedule_scanlist_cull (NMDeviceWifi *self) static void supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, const char *object_path, - GHashTable *properties, + GVariant *properties, NMDeviceWifi *self) { NMDeviceState state; @@ -2148,6 +2148,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMDevice *device = NM_DEVICE (self); NMDeviceState devstate; gboolean scanning; + gboolean recheck_available = FALSE; if (new_state == old_state) return; @@ -2167,23 +2168,9 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, switch (new_state) { case NM_SUPPLICANT_INTERFACE_STATE_READY: + _LOGD (LOGD_WIFI_SCAN, "supplicant ready"); + recheck_available = TRUE; priv->scan_interval = SCAN_INTERVAL_MIN; - - /* If the interface can now be activated because the supplicant is now - * available, transition to DISCONNECTED. - */ - if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE); - } - - _LOGD (LOGD_WIFI_SCAN, "supplicant ready, requesting initial scan"); - - /* Request a scan to get latest results */ - cancel_pending_scan (self); - request_wireless_scan (self); - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) nm_device_remove_pending_action (device, "waiting for supplicant", TRUE); break; @@ -2243,6 +2230,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, } break; case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + recheck_available = TRUE; cleanup_association_attempt (self, FALSE); if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) @@ -2255,15 +2243,17 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, */ supplicant_interface_release (self); supplicant_interface_acquire (self); - - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); break; default: break; } + if (recheck_available) { + nm_device_queue_recheck_available (NM_DEVICE (device), + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + } + /* Signal scanning state changes */ if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) @@ -2507,62 +2497,6 @@ error: /****************************************************************************/ -static void -update_permanent_hw_address (NMDevice *device) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - struct ifreq req; - struct ethtool_perm_addr *epaddr = NULL; - int fd, ret, errsv; - - g_return_if_fail (priv->perm_hw_addr == NULL); - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGE (LOGD_HW, "could not open control socket."); - return; - } - - /* Get permanent MAC address */ - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (device), IFNAMSIZ); - - epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = ETH_ALEN; - req.ifr_data = (void *) epaddr; - - errno = 0; - ret = ioctl (fd, SIOCETHTOOL, &req); - errsv = errno; - if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) { - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", - errsv); - /* Fall back to current address */ - nm_utils_hwaddr_aton (nm_device_get_hw_address (device), epaddr->data, ETH_ALEN); - } - - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN); - - g_free (epaddr); - close (fd); -} - -static void -update_initial_hw_address (NMDevice *device) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - /* This sets initial MAC address from current MAC address. It should only - * be called from NMDevice constructor() to really get the initial address. - */ - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (device)); - - _LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { @@ -2687,9 +2621,9 @@ ensure_hotspot_frequency (NMDeviceWifi *self, return; if (g_strcmp0 (band, "a") == 0) - freq = nm_platform_wifi_find_frequency (nm_device_get_ifindex (NM_DEVICE (self)), a_freqs); + freq = nm_platform_wifi_find_frequency (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), a_freqs); else - freq = nm_platform_wifi_find_frequency (nm_device_get_ifindex (NM_DEVICE (self)), bg_freqs); + freq = nm_platform_wifi_find_frequency (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), bg_freqs); if (!freq) freq = (g_strcmp0 (band, "a") == 0) ? 5180 : 2462; @@ -2823,7 +2757,7 @@ act_stage3_ip4_config_start (NMDevice *device, /* Indicate that a critical protocol is about to start */ if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) - nm_platform_wifi_indicate_addressing_running (nm_device_get_ifindex (device), TRUE); + nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, nm_device_get_ifindex (device), TRUE); return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); } @@ -2846,7 +2780,7 @@ act_stage3_ip6_config_start (NMDevice *device, /* Indicate that a critical protocol is about to start */ if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) - nm_platform_wifi_indicate_addressing_running (nm_device_get_ifindex (device), TRUE); + nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, nm_device_get_ifindex (device), TRUE); return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip6_config_start (device, out_config, reason); } @@ -2998,7 +2932,7 @@ activation_success_handler (NMDevice *device) g_assert (connection); /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running (ifindex, FALSE); + nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); /* Clear wireless secrets tries on success */ g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, NULL); @@ -3017,16 +2951,16 @@ activation_success_handler (NMDevice *device) * But if activation was successful, the card will know the BSSID. Grab * the BSSID off the card and fill in the BSSID of the activation AP. */ - nm_platform_wifi_get_bssid (ifindex, bssid); + nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid); if (!nm_ap_get_address (ap)) { char *bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); nm_ap_set_address (ap, bssid_str); g_free (bssid_str); } if (!nm_ap_get_freq (ap)) - nm_ap_set_freq (ap, nm_platform_wifi_get_frequency (ifindex)); + nm_ap_set_freq (ap, nm_platform_wifi_get_frequency (NM_PLATFORM_GET, ifindex)); if (!nm_ap_get_max_bitrate (ap)) - nm_ap_set_max_bitrate (ap, nm_platform_wifi_get_rate (ifindex)); + nm_ap_set_max_bitrate (ap, nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex)); tmp_ap = find_active_ap (self, ap, TRUE); if (tmp_ap) { @@ -3076,7 +3010,7 @@ activation_failure_handler (NMDevice *device) g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, NULL); /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running (nm_device_get_ifindex (device), FALSE); + nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, nm_device_get_ifindex (device), FALSE); } static void @@ -3126,7 +3060,7 @@ device_state_changed (NMDevice *device, break; case NM_DEVICE_STATE_IP_CHECK: /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running (nm_device_get_ifindex (device), FALSE); + nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, nm_device_get_ifindex (device), FALSE); break; case NM_DEVICE_STATE_ACTIVATED: activation_success_handler (device); @@ -3253,12 +3187,6 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMDeviceWifi *self = NM_DEVICE_WIFI (object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - g_free (priv->perm_hw_addr); - g_free (priv->initial_hw_addr); - G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -3273,7 +3201,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, priv->perm_hw_addr); + g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (device))); break; case PROP_MODE: g_value_set_uint (value, priv->mode); @@ -3332,8 +3260,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) object_class->finalize = finalize; parent_class->bring_up = bring_up; - parent_class->update_permanent_hw_address = update_permanent_hw_address; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->can_auto_connect = can_auto_connect; parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 66d73563..d70dd9a6 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -30,6 +30,7 @@ #include "nm-utils.h" #include "nm-logging.h" #include "nm-dbus-manager.h" +#include "nm-core-internal.h" #include "nm-setting-wireless.h" #include "nm-glib-compat.h" @@ -330,163 +331,134 @@ nm_ap_new (void) } static NM80211ApSecurityFlags -pair_to_flags (const char *str) +security_from_vardict (GVariant *security) { - g_return_val_if_fail (str != NULL, NM_802_11_AP_SEC_NONE); + NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; + const char **array, *tmp; - if (strcmp (str, "tkip") == 0) - return NM_802_11_AP_SEC_PAIR_TKIP; - if (strcmp (str, "ccmp") == 0) - return NM_802_11_AP_SEC_PAIR_CCMP; - return NM_802_11_AP_SEC_NONE; -} + g_return_val_if_fail (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT), NM_802_11_AP_SEC_NONE); -static NM80211ApSecurityFlags -group_to_flags (const char *str) -{ - g_return_val_if_fail (str != NULL, NM_802_11_AP_SEC_NONE); - - if (strcmp (str, "wep40") == 0) - return NM_802_11_AP_SEC_GROUP_WEP40; - if (strcmp (str, "wep104") == 0) - return NM_802_11_AP_SEC_GROUP_WEP104; - if (strcmp (str, "tkip") == 0) - return NM_802_11_AP_SEC_GROUP_TKIP; - if (strcmp (str, "ccmp") == 0) - return NM_802_11_AP_SEC_GROUP_CCMP; - return NM_802_11_AP_SEC_NONE; -} - -static NM80211ApSecurityFlags -security_from_dict (GHashTable *security) -{ - GValue *value; - NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; - const char **items, **iter; - - value = g_hash_table_lookup (security, "KeyMgmt"); - if (value) { - items = g_value_get_boxed (value); - for (iter = items; iter && *iter; iter++) { - if (strcmp (*iter, "wpa-psk") == 0) - flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (strcmp (*iter, "wpa-eap") == 0) - flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; - } + if (g_variant_lookup (security, "KeyMgmt", "^a&s", &array)) { + if (_nm_utils_string_in_list ("wpa-psk", array)) + flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; + if (_nm_utils_string_in_list ("wpa-eap", array)) + flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; + g_free (array); } - value = g_hash_table_lookup (security, "Pairwise"); - if (value) { - items = g_value_get_boxed (value); - for (iter = items; iter && *iter; iter++) - flags |= pair_to_flags (*iter); + if (g_variant_lookup (security, "Pairwise", "^a&s", &array)) { + if (_nm_utils_string_in_list ("tkip", array)) + flags |= NM_802_11_AP_SEC_PAIR_TKIP; + if (_nm_utils_string_in_list ("ccmp", array)) + flags |= NM_802_11_AP_SEC_PAIR_CCMP; + g_free (array); } - value = g_hash_table_lookup (security, "Group"); - if (value) - flags |= group_to_flags (g_value_get_string (value)); + if (g_variant_lookup (security, "Group", "&s", &tmp)) { + if (strcmp (tmp, "wep40") == 0) + flags |= NM_802_11_AP_SEC_GROUP_WEP40; + if (strcmp (tmp, "wep104") == 0) + flags |= NM_802_11_AP_SEC_GROUP_WEP104; + if (strcmp (tmp, "tkip") == 0) + flags |= NM_802_11_AP_SEC_GROUP_TKIP; + if (strcmp (tmp, "ccmp") == 0) + flags |= NM_802_11_AP_SEC_GROUP_CCMP; + } return flags; } -static void -foreach_property_cb (gpointer key, gpointer value, gpointer user_data) -{ - GValue *variant = (GValue *) value; - NMAccessPoint *ap = (NMAccessPoint *) user_data; - - if (G_VALUE_HOLDS_BOXED (variant)) { - GArray *array = g_value_get_boxed (variant); - - if (!strcmp (key, "SSID")) { - guint32 len = MIN (32, array->len); - - /* Stupid ieee80211 layer uses <hidden> */ - if (((len == 8) || (len == 9)) - && (memcmp (array->data, "<hidden>", 8) == 0)) - return; - - if (nm_utils_is_empty_ssid ((const guint8 *) array->data, len)) - return; - - nm_ap_set_ssid (ap, (const guint8 *) array->data, len); - } else if (!strcmp (key, "BSSID")) { - char *addr; - - if (array->len != ETH_ALEN) - return; - addr = nm_utils_hwaddr_ntoa (array->data, array->len); - nm_ap_set_address (ap, addr); - g_free (addr); - } else if (!strcmp (key, "Rates")) { - guint32 maxrate = 0; - int i; - - /* Find the max AP rate */ - for (i = 0; i < array->len; i++) { - guint32 r = g_array_index (array, guint32, i); - - if (r > maxrate) { - maxrate = r; - nm_ap_set_max_bitrate (ap, r / 1000); - } - } - } else if (!strcmp (key, "WPA")) { - NM80211ApSecurityFlags flags = nm_ap_get_wpa_flags (ap); - - flags |= security_from_dict (g_value_get_boxed (variant)); - nm_ap_set_wpa_flags (ap, flags); - } else if (!strcmp (key, "RSN")) { - NM80211ApSecurityFlags flags = nm_ap_get_rsn_flags (ap); - - flags |= security_from_dict (g_value_get_boxed (variant)); - nm_ap_set_rsn_flags (ap, flags); - } - } else if (G_VALUE_HOLDS_UINT (variant)) { - guint32 val = g_value_get_uint (variant); - - if (!strcmp (key, "Frequency")) - nm_ap_set_freq (ap, val); - } else if (G_VALUE_HOLDS_INT (variant)) { - gint val = g_value_get_int (variant); - - if (!strcmp (key, "Signal")) - nm_ap_set_strength (ap, nm_ap_utils_level_to_quality (val)); - } else if (G_VALUE_HOLDS_STRING (variant)) { - const char *val = g_value_get_string (variant); - - if (val && !strcmp (key, "Mode")) { - if (strcmp (val, "infrastructure") == 0) - nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); - else if (strcmp (val, "ad-hoc") == 0) - nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); - } - } else if (G_VALUE_HOLDS_BOOLEAN (variant)) { - gboolean val = g_value_get_boolean (variant); - - if (strcmp (key, "Privacy") == 0) { - if (val) { - NM80211ApFlags flags = nm_ap_get_flags (ap); - nm_ap_set_flags (ap, flags | NM_802_11_AP_FLAGS_PRIVACY); - } - } - } -} - NMAccessPoint * -nm_ap_new_from_properties (const char *supplicant_path, GHashTable *properties) +nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) { - NMAccessPoint *ap; - const char *addr; const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + const char *addr; + const guint8 *bytes; + NMAccessPoint *ap; + GVariant *v; + gsize len; + gboolean b = FALSE; + const char *s; + gint16 i16; + guint16 u16; g_return_val_if_fail (properties != NULL, NULL); ap = nm_ap_new (); g_object_freeze_notify (G_OBJECT (ap)); - g_hash_table_foreach (properties, foreach_property_cb, ap); + + if (g_variant_lookup (properties, "Privacy", "b", &b) && b) + nm_ap_set_flags (ap, nm_ap_get_flags (ap) | NM_802_11_AP_FLAGS_PRIVACY); + + if (g_variant_lookup (properties, "Mode", "&s", &s)) { + if (!g_strcmp0 (s, "infrastructure")) + nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); + else if (!g_strcmp0 (s, "ad-hoc")) + nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); + } + + if (g_variant_lookup (properties, "Signal", "n", &i16)) + nm_ap_set_strength (ap, nm_ap_utils_level_to_quality (i16)); + + if (g_variant_lookup (properties, "Frequency", "q", &u16)) + nm_ap_set_freq (ap, u16); + + v = g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); + if (v) { + bytes = g_variant_get_fixed_array (v, &len, 1); + len = MIN (32, len); + + /* Stupid ieee80211 layer uses <hidden> */ + if ( bytes && len + && !(((len == 8) || (len == 9)) && !memcmp (bytes, "<hidden>", 8)) + && !nm_utils_is_empty_ssid (bytes, len)) + nm_ap_set_ssid (ap, bytes, len); + + g_variant_unref (v); + } + + v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); + if (v) { + bytes = g_variant_get_fixed_array (v, &len, 1); + if (len == ETH_ALEN) { + char *a; + + a = nm_utils_hwaddr_ntoa (bytes, len); + nm_ap_set_address (ap, a); + g_free (a); + } + g_variant_unref (v); + } + + v = g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au")); + if (v) { + const guint32 *rates = g_variant_get_fixed_array (v, &len, sizeof (guint32)); + guint32 maxrate = 0; + int i; + + /* Find the max AP rate */ + for (i = 0; i < len; i++) { + if (rates[i] > maxrate) { + maxrate = rates[i]; + nm_ap_set_max_bitrate (ap, rates[i] / 1000); + } + } + g_variant_unref (v); + } + + v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); + if (v) { + nm_ap_set_wpa_flags (ap, nm_ap_get_wpa_flags (ap) | security_from_vardict (v)); + g_variant_unref (v); + } + + v = g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT); + if (v) { + nm_ap_set_rsn_flags (ap, nm_ap_get_rsn_flags (ap) | security_from_vardict (v)); + g_variant_unref (v); + } nm_ap_set_supplicant_path (ap, supplicant_path); diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 0abb28fc..8ad9acb7 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -56,7 +56,7 @@ typedef struct { GType nm_ap_get_type (void); NMAccessPoint * nm_ap_new_from_properties (const char *supplicant_path, - GHashTable *properties); + GVariant *properties); NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection); void nm_ap_export_to_dbus (NMAccessPoint *ap); diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 4093c612..c4b4042e 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -23,6 +23,8 @@ #include <gmodule.h> #include "nm-device-factory.h" +#include "nm-setting-wireless.h" +#include "nm-setting-olpc-mesh.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" #include "nm-settings-connection.h" @@ -57,26 +59,25 @@ nm_device_factory_create (GError **error) /**************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { if (plink->type == NM_LINK_TYPE_WIFI) return nm_device_wifi_new (plink); else if (plink->type == NM_LINK_TYPE_OLPC_MESH) return nm_device_olpc_mesh_new (plink); - return NULL; + g_assert_not_reached (); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_WIFI; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_OLPC_MESH_SETTING_NAME) +) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wifi/tests/Makefile.in b/src/devices/wifi/tests/Makefile.in index e3b7c767..f807ee77 100644 --- a/src/devices/wifi/tests/Makefile.in +++ b/src/devices/wifi/tests/Makefile.in @@ -204,13 +204,196 @@ am__tty_colors = { \ std='[m'; \ fi; \ } +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/build-aux/depcomp + $(top_srcdir)/build-aux/depcomp \ + $(top_srcdir)/build-aux/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -324,6 +507,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ @@ -492,7 +676,7 @@ test_wifi_ap_utils_LDADD = $(top_builddir)/src/libNetworkManager.la all: all-am .SUFFIXES: -.SUFFIXES: .c .lo .o .obj +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -653,98 +837,168 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -check-TESTS: $(TESTS) - @failed=0; all=0; xfail=0; xpass=0; skip=0; \ - srcdir=$(srcdir); export srcdir; \ - list=' $(TESTS) '; \ - $(am__tty_colors); \ - if test -n "$$list"; then \ - for tst in $$list; do \ - if test -f ./$$tst; then dir=./; \ - elif test -f $$tst; then dir=; \ - else dir="$(srcdir)/"; fi; \ - if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ - all=`expr $$all + 1`; \ - case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$tst[\ \ ]*) \ - xpass=`expr $$xpass + 1`; \ - failed=`expr $$failed + 1`; \ - col=$$red; res=XPASS; \ - ;; \ - *) \ - col=$$grn; res=PASS; \ - ;; \ - esac; \ - elif test $$? -ne 77; then \ - all=`expr $$all + 1`; \ - case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$tst[\ \ ]*) \ - xfail=`expr $$xfail + 1`; \ - col=$$lgn; res=XFAIL; \ - ;; \ - *) \ - failed=`expr $$failed + 1`; \ - col=$$red; res=FAIL; \ - ;; \ - esac; \ - else \ - skip=`expr $$skip + 1`; \ - col=$$blu; res=SKIP; \ - fi; \ - echo "$${col}$$res$${std}: $$tst"; \ - done; \ - if test "$$all" -eq 1; then \ - tests="test"; \ - All=""; \ - else \ - tests="tests"; \ - All="All "; \ +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ - if test "$$failed" -eq 0; then \ - if test "$$xfail" -eq 0; then \ - banner="$$All$$all $$tests passed"; \ - else \ - if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ - banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ - fi; \ - else \ - if test "$$xpass" -eq 0; then \ - banner="$$failed of $$all $$tests failed"; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ else \ - if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ - banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ - fi; \ - dashes="$$banner"; \ - skipped=""; \ - if test "$$skip" -ne 0; then \ - if test "$$skip" -eq 1; then \ - skipped="($$skip test was not run)"; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ else \ - skipped="($$skip tests were not run)"; \ + color_start= color_end=; \ fi; \ - test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ - dashes="$$skipped"; \ - fi; \ - report=""; \ - if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ - report="Please report to $(PACKAGE_BUGREPORT)"; \ - test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ - dashes="$$report"; \ - fi; \ - dashes=`echo "$$dashes" | sed s/./=/g`; \ - if test "$$failed" -eq 0; then \ - col="$$grn"; \ - else \ - col="$$red"; \ - fi; \ - echo "$${col}$$dashes$${std}"; \ - echo "$${col}$$banner$${std}"; \ - test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ - test -z "$$report" || echo "$${col}$$report$${std}"; \ - echo "$${col}$$dashes$${std}"; \ - test "$$failed" -eq 0; \ - else :; fi + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +test-wifi-ap-utils.log: test-wifi-ap-utils$(EXEEXT) + @p='test-wifi-ap-utils$(EXEEXT)'; \ + b='test-wifi-ap-utils'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ @@ -801,6 +1055,9 @@ install-strip: "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: @@ -896,7 +1153,7 @@ uninstall-am: installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am + recheck tags tags-am uninstall uninstall-am .PRECIOUS: Makefile diff --git a/src/devices/wimax/Makefile.in b/src/devices/wimax/Makefile.in index 32800fb7..8ad4b4e2 100644 --- a/src/devices/wimax/Makefile.in +++ b/src/devices/wimax/Makefile.in @@ -221,6 +221,7 @@ ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -334,6 +335,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ diff --git a/src/devices/wimax/nm-wimax-factory.c b/src/devices/wimax/nm-wimax-factory.c index 39e9a287..7dc580fc 100644 --- a/src/devices/wimax/nm-wimax-factory.c +++ b/src/devices/wimax/nm-wimax-factory.c @@ -25,6 +25,7 @@ #include "nm-device-factory.h" #include "nm-device-wimax.h" #include "nm-platform.h" +#include "nm-setting-wimax.h" #define NM_TYPE_WIMAX_FACTORY (nm_wimax_factory_get_type ()) #define NM_WIMAX_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_WIMAX_FACTORY, NMWimaxFactory)) @@ -55,7 +56,7 @@ nm_device_factory_create (GError **error) /**************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { /* FIXME: check udev 'DEVTYPE' instead; but since we only support Intel * WiMAX devices for now this is appropriate. @@ -66,17 +67,16 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) return (NMDevice *) nm_device_wimax_new (plink); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_WIMAX; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIMAX) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIMAX_SETTING_NAME) +) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wimax/nm-wimax-util.h b/src/devices/wimax/nm-wimax-util.h index a1852d55..5fedc6e8 100644 --- a/src/devices/wimax/nm-wimax-util.h +++ b/src/devices/wimax/nm-wimax-util.h @@ -23,7 +23,7 @@ #include <glib.h> -#include "nm-utils-internal.h" +#include "nm-macros-internal.h" NM_PRAGMA_WARNING_DISABLE("-Wstrict-prototypes") #include <WiMaxType.h> diff --git a/src/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in index 1a8aef3b..227c622f 100644 --- a/src/devices/wwan/Makefile.in +++ b/src/devices/wwan/Makefile.in @@ -232,6 +232,7 @@ ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -345,6 +346,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOG_DRIVER = @LOG_DRIVER@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index f819d1d7..ca724c04 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -300,19 +300,9 @@ modem_state_cb (NMModem *modem, nm_device_recheck_available_connections (device); } - if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_MODEM_FAILED); - return; - } - - if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_MODEM_AVAILABLE); - return; - } + nm_device_queue_recheck_available (device, + NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, + NM_DEVICE_STATE_REASON_MODEM_FAILED); } static void @@ -376,12 +366,24 @@ device_state_changed (NMDevice *device, } } -static guint32 +static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { return NM_DEVICE_CAP_IS_NON_KERNEL; } +static const char * +get_type_description (NMDevice *device) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + if (NM_FLAGS_HAS (priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)) + return "gsm"; + if (NM_FLAGS_HAS (priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) + return "cdma"; + return NM_DEVICE_CLASS (nm_device_modem_parent_class)->get_type_description (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -751,6 +753,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) object_class->constructed = constructed; device_class->get_generic_capabilities = get_generic_capabilities; + device_class->get_type_description = get_type_description; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 69eaddf3..3385a6fd 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -32,6 +32,7 @@ #include "nm-device-private.h" #include "nm-dbus-glib-types.h" #include "nm-modem-enum-types.h" +#include "nm-route-manager.h" G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT) @@ -615,7 +616,7 @@ nm_modem_ip4_pre_commit (NMModem *modem, g_assert (address); if (address->plen == 32) - nm_platform_link_set_noarp (nm_device_get_ip_ifindex (device)); + nm_platform_link_set_noarp (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device)); } } @@ -912,9 +913,9 @@ deactivate_cleanup (NMModem *self, NMDevice *device) priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { ifindex = nm_device_get_ip_ifindex (device); if (ifindex > 0) { - nm_platform_route_flush (ifindex); - nm_platform_address_flush (ifindex); - nm_platform_link_set_down (ifindex); + nm_route_manager_route_flush (nm_route_manager_get (), ifindex); + nm_platform_address_flush (NM_PLATFORM_GET, ifindex); + nm_platform_link_set_down (NM_PLATFORM_GET, ifindex); } } } diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index 2b9c3d4d..49b0b0af 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -25,9 +25,12 @@ #include "nm-device-factory.h" #include "nm-wwan-factory.h" +#include "nm-setting-gsm.h" +#include "nm-setting-cdma.h" #include "nm-modem-manager.h" #include "nm-device-modem.h" #include "nm-logging.h" +#include "nm-platform.h" static GType nm_wwan_factory_get_type (void); @@ -87,10 +90,17 @@ modem_added_cb (NMModemManager *manager, } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WWAN_ETHERNET) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME) +) + +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - return NM_DEVICE_TYPE_MODEM; + g_warn_if_fail (plink->type == NM_LINK_TYPE_WWAN_ETHERNET); + *out_ignore = TRUE; + return NULL; } static void @@ -115,7 +125,8 @@ nm_wwan_factory_init (NMWwanFactory *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; + factory_iface->new_link = new_link; factory_iface->start = start; } |