diff options
Diffstat (limited to 'src')
248 files changed, 12863 insertions, 6948 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 55b660db..ecb1d8ae 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -217,7 +217,7 @@ nm_utils_complete_generic (NMPlatform *platform, gboolean default_enable_ipv6) { NMSettingConnection *s_con; - char *id, *uuid, *ifname; + char *id, *ifname; GHashTable *parameters; g_assert (fallback_id_prefix); @@ -230,9 +230,9 @@ nm_utils_complete_generic (NMPlatform *platform, g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_TYPE, ctype, NULL); if (!nm_setting_connection_get_uuid (s_con)) { - uuid = nm_utils_uuid_generate (); - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, uuid, NULL); - g_free (uuid); + char uuid[37]; + + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), NULL); } /* Add a connection ID if absent */ @@ -342,18 +342,19 @@ static int route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric) { gint64 r, metric1, metric2; + int family; + guint plen; + NMIPAddr a1 = { 0 }, a2 = { 0 }; - r = g_strcmp0 (nm_ip_route_get_dest (route1), nm_ip_route_get_dest (route2)); - if (r) - return r; - - r = nm_ip_route_get_prefix (route1) - nm_ip_route_get_prefix (route2); + family = nm_ip_route_get_family (route1); + r = family - nm_ip_route_get_family (route2); if (r) return r > 0 ? 1 : -1; - r = g_strcmp0 (nm_ip_route_get_next_hop (route1), nm_ip_route_get_next_hop (route2)); + plen = nm_ip_route_get_prefix (route1); + r = plen - nm_ip_route_get_prefix (route2); if (r) - return r; + return r > 0 ? 1 : -1; metric1 = nm_ip_route_get_metric (route1) == -1 ? default_metric : nm_ip_route_get_metric (route1); metric2 = nm_ip_route_get_metric (route2) == -1 ? default_metric : nm_ip_route_get_metric (route2); @@ -362,17 +363,26 @@ route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric) if (r) return r > 0 ? 1 : -1; - r = nm_ip_route_get_family (route1) - nm_ip_route_get_family (route2); + r = g_strcmp0 (nm_ip_route_get_next_hop (route1), nm_ip_route_get_next_hop (route2)); if (r) - return r > 0 ? 1 : -1; + return r; + + /* NMIPRoute validates family and dest. inet_pton() is not expected to fail. */ + inet_pton (family, nm_ip_route_get_dest (route1), &a1); + inet_pton (family, nm_ip_route_get_dest (route2), &a2); + nm_utils_ipx_address_clear_host_address (family, &a1, &a1, plen); + nm_utils_ipx_address_clear_host_address (family, &a2, &a2, plen); + r = memcmp (&a1, &a2, sizeof (a1)); + if (r) + return r; return 0; } static int -route_ptr_compare (const void *a, const void *b) +route_ptr_compare (const void *a, const void *b, gpointer metric) { - return route_compare (*(NMIPRoute **) a, *(NMIPRoute **) b, -1); + return route_compare (*(NMIPRoute **) a, *(NMIPRoute **) b, *((gint64 *) metric)); } static gboolean @@ -384,6 +394,7 @@ check_ip_routes (NMConnection *orig, { gs_free NMIPRoute **routes1 = NULL, **routes2 = NULL; NMSettingIPConfig *s_ip1, *s_ip2; + gint64 m; const char *s_name; GHashTable *props; guint i, num; @@ -415,8 +426,12 @@ check_ip_routes (NMConnection *orig, routes2[i] = nm_setting_ip_config_get_route (s_ip2, i); } - qsort (routes1, num, sizeof (NMIPRoute *), route_ptr_compare); - qsort (routes2, num, sizeof (NMIPRoute *), route_ptr_compare); + m = nm_setting_ip_config_get_route_metric (s_ip2); + if (m != -1) + default_metric = m; + + g_qsort_with_data (routes1, num, sizeof (NMIPRoute *), route_ptr_compare, &default_metric); + g_qsort_with_data (routes2, num, sizeof (NMIPRoute *), route_ptr_compare, &default_metric); for (i = 0; i < num; i++) { if (route_compare (routes1[i], routes2[i], default_metric)) @@ -584,7 +599,7 @@ check_connection_cloned_mac_address (NMConnection *orig, if (s_wired_cand) cand_mac = nm_setting_wired_get_cloned_mac_address (s_wired_cand); - /* special cloned mac address entires are accepted. */ + /* special cloned mac address entries are accepted. */ if (NM_CLONED_MAC_IS_SPECIAL (orig_mac)) orig_mac = NULL; if (NM_CLONED_MAC_IS_SPECIAL (cand_mac)) @@ -710,7 +725,7 @@ check_possible_match (NMConnection *orig, * matches well enough. */ NMConnection * -nm_utils_match_connection (GSList *connections, +nm_utils_match_connection (NMConnection *const*connections, NMConnection *original, gboolean device_has_carrier, gint64 default_v4_metric, @@ -719,10 +734,12 @@ nm_utils_match_connection (GSList *connections, gpointer match_filter_data) { NMConnection *best_match = NULL; - GSList *iter; - for (iter = connections; iter; iter = iter->next) { - NMConnection *candidate = NM_CONNECTION (iter->data); + if (!connections) + return NULL; + + for (; *connections; connections++) { + NMConnection *candidate = NM_CONNECTION (*connections); GHashTable *diffs = NULL; if (match_filter_func) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 9b5b9106..c20f2439 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -39,7 +39,7 @@ void nm_utils_complete_generic (NMPlatform *platform, typedef gboolean (NMUtilsMatchFilterFunc) (NMConnection *connection, gpointer user_data); -NMConnection *nm_utils_match_connection (GSList *connections, +NMConnection *nm_utils_match_connection (NMConnection *const*connections, NMConnection *original, gboolean device_has_carrier, gint64 default_v4_metric, diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index b04e9fe7..32c4c386 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -21,13 +21,14 @@ #include "nm-default.h" #include <string.h> -#include <gudev/gudev.h> #include <gmodule.h> +#include <libudev.h> #include "nm-setting-adsl.h" #include "nm-device-adsl.h" #include "devices/nm-device-factory.h" #include "platform/nm-platform.h" +#include "nm-utils/nm-udev-utils.h" /*****************************************************************************/ @@ -39,7 +40,7 @@ #define NM_ATM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) typedef struct { - GUdevClient *client; + NMUdevClient *udev_client; GSList *devices; } NMAtmManagerPrivate; @@ -73,35 +74,34 @@ nm_device_factory_create (GError **error) /*****************************************************************************/ static gboolean -dev_get_attrs (GUdevDevice *udev_device, +dev_get_attrs (struct udev_device *udev_device, const char **out_path, char **out_driver) { - GUdevDevice *parent = NULL; + struct udev_device *parent = NULL; const char *driver, *path; g_return_val_if_fail (udev_device != NULL, FALSE); g_return_val_if_fail (out_path != NULL, FALSE); g_return_val_if_fail (out_driver != NULL, FALSE); - path = g_udev_device_get_sysfs_path (udev_device); + path = udev_device_get_syspath (udev_device); if (!path) { nm_log_warn (LOGD_PLATFORM, "couldn't determine device path; ignoring..."); return FALSE; } - driver = g_udev_device_get_driver (udev_device); + driver = udev_device_get_driver (udev_device); if (!driver) { /* Try the parent */ - parent = g_udev_device_get_parent (udev_device); + parent = udev_device_get_parent (udev_device); if (parent) - driver = g_udev_device_get_driver (parent); + driver = udev_device_get_driver (parent); } *out_path = path; *out_driver = g_strdup (driver); - g_clear_object (&parent); return TRUE; } @@ -115,7 +115,7 @@ device_destroyed (gpointer user_data, GObject *dead) } static void -adsl_add (NMAtmManager *self, GUdevDevice *udev_device) +adsl_add (NMAtmManager *self, struct udev_device *udev_device) { NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); const char *ifname, *sysfs_path = NULL; @@ -126,7 +126,7 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device) g_return_if_fail (udev_device != NULL); - ifname = g_udev_device_get_name (udev_device); + ifname = udev_device_get_sysname (udev_device); if (!ifname) { nm_log_warn (LOGD_PLATFORM, "failed to get device's interface name"); return; @@ -165,10 +165,10 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device) } static void -adsl_remove (NMAtmManager *self, GUdevDevice *udev_device) +adsl_remove (NMAtmManager *self, struct udev_device *udev_device) { NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); - const char *iface = g_udev_device_get_name (udev_device); + const char *iface = udev_device_get_sysname (udev_device); GSList *iter; nm_log_dbg (LOGD_PLATFORM, "(%s): removing ATM device", iface); @@ -194,42 +194,49 @@ start (NMDeviceFactory *factory) { NMAtmManager *self = NM_ATM_MANAGER (factory); NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); - GUdevEnumerator *enumerator; - GList *devices, *iter; - - enumerator = g_udev_enumerator_new (priv->client); - g_udev_enumerator_add_match_subsystem (enumerator, "atm"); - g_udev_enumerator_add_match_is_initialized (enumerator); - devices = g_udev_enumerator_execute (enumerator); - for (iter = devices; iter; iter = g_list_next (iter)) { - adsl_add (self, G_UDEV_DEVICE (iter->data)); - g_object_unref (G_UDEV_DEVICE (iter->data)); + struct udev_enumerate *enumerate; + struct udev_list_entry *devices; + + enumerate = nm_udev_client_enumerate_new (priv->udev_client); + udev_enumerate_add_match_is_initialized (enumerate); + udev_enumerate_scan_devices (enumerate); + devices = udev_enumerate_get_list_entry (enumerate); + for (; devices; devices = udev_list_entry_get_next (devices)) { + struct udev_device *udevice; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), + udev_list_entry_get_name (devices)); + if (udevice) { + adsl_add (self, udevice); + udev_device_unref (udevice); + } } - g_list_free (devices); - g_object_unref (enumerator); + udev_enumerate_unref (enumerate); } static void -handle_uevent (GUdevClient *client, - const char *action, - GUdevDevice *device, +handle_uevent (NMUdevClient *client, + struct udev_device *device, gpointer user_data) { NMAtmManager *self = NM_ATM_MANAGER (user_data); const char *subsys; const char *ifindex; guint64 seqnum; + const char *action; + + action = udev_device_get_action (device); g_return_if_fail (action != NULL); /* A bit paranoid */ - subsys = g_udev_device_get_subsystem (device); + subsys = udev_device_get_subsystem (device); g_return_if_fail (!g_strcmp0 (subsys, "atm")); - ifindex = g_udev_device_get_property (device, "IFINDEX"); - seqnum = g_udev_device_get_seqnum (device); + ifindex = udev_device_get_property_value (device, "IFINDEX"); + seqnum = udev_device_get_seqnum (device); nm_log_dbg (LOGD_PLATFORM, "UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, - action, subsys, g_udev_device_get_name (device), ifindex ? ifindex : "unknown", seqnum); + action, subsys, udev_device_get_sysname (device), ifindex ? ifindex : "unknown", seqnum); if (!strcmp (action, "add")) adsl_add (self, device); @@ -243,10 +250,9 @@ static void nm_atm_manager_init (NMAtmManager *self) { NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); - const char *subsys[] = { "atm", NULL }; - priv->client = g_udev_client_new (subsys); - g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); + priv->udev_client = nm_udev_client_new ((const char *[]) {"atm", NULL }, + handle_uevent, self); } static void @@ -256,15 +262,12 @@ dispose (GObject *object) NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); GSList *iter; - if (priv->client) { - g_signal_handlers_disconnect_by_func (priv->client, handle_uevent, self); - g_clear_object (&priv->client); - } - for (iter = priv->devices; iter; iter = iter->next) g_object_weak_unref (G_OBJECT (iter->data), device_destroyed, self); g_clear_pointer (&priv->devices, g_slist_free); + priv->udev_client = nm_udev_client_unref (priv->udev_client); + G_OBJECT_CLASS (nm_atm_manager_parent_class)->dispose (object); } diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 53841a7f..fe622bdf 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -129,7 +129,7 @@ complete_connection (NMDevice *device, if (s_adsl && !nm_setting_verify (NM_SETTING (s_adsl), NULL, error)) return FALSE; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_ADSL_SETTING_NAME, existing_connections, @@ -273,14 +273,14 @@ pppoe_vcc_config (NMDeviceAdsl *self) return FALSE; /* Watch for the 'nas' interface going away */ - g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, + g_signal_connect (nm_device_get_platform (device), NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); _LOGD (LOGD_ADSL, "ATM setup successful"); /* otherwise we're good for stage3 */ - nm_platform_link_set_up (NM_PLATFORM_GET, priv->nas_ifindex, NULL); + nm_platform_link_set_up (nm_device_get_platform (device), priv->nas_ifindex, NULL); return TRUE; } @@ -306,7 +306,7 @@ nas_update_cb (gpointer user_data) } g_warn_if_fail (priv->nas_ifindex < 0); - priv->nas_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->nas_ifname); + priv->nas_ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (device), priv->nas_ifname); if (priv->nas_ifindex < 0) { /* Keep waiting for it to appear */ return G_SOURCE_CONTINUE; @@ -329,12 +329,12 @@ nas_update_cb (gpointer user_data) static NMActStageReturn br2684_create_iface (NMDeviceAdsl *self, NMSettingAdsl *s_adsl, - NMDeviceStateReason *out_reason) + NMDeviceStateReason *out_failure_reason) { NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); struct atm_newif_br2684 ni; - int err, fd, errsv; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + nm_auto_close int fd = -1; + int err, errsv; guint num = 0; g_return_val_if_fail (s_adsl != NULL, FALSE); @@ -348,7 +348,7 @@ br2684_create_iface (NMDeviceAdsl *self, if (fd < 0) { errsv = errno; _LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv); - *out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_BR2684_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -374,39 +374,36 @@ br2684_create_iface (NMDeviceAdsl *self, priv->nas_update_count = 0; priv->nas_update_id = g_timeout_add (100, nas_update_cb, self); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - break; - } else if (errno != EEXIST) { + return NM_ACT_STAGE_RETURN_POSTPONE; + } + if (errno != EEXIST) { errsv = errno; _LOGW (LOGD_ADSL, "failed to create br2684 interface (%d)", errsv); - *out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED; break; } } - close (fd); - return ret; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_BR2684_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceAdsl *self = NM_DEVICE_ADSL (device); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMSettingAdsl *s_adsl; const char *protocol; - g_assert (out_reason); - s_adsl = nm_connection_get_setting_adsl (nm_device_get_applied_connection (device)); - g_assert (s_adsl); + g_return_val_if_fail (s_adsl, NM_ACT_STAGE_RETURN_FAILURE); protocol = nm_setting_adsl_get_protocol (s_adsl); _LOGD (LOGD_ADSL, "using ADSL protocol '%s'", protocol); if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { /* PPPoE needs RFC2684 bridging before we can do PPP over it */ - ret = br2684_create_iface (self, s_adsl, out_reason); + ret = br2684_create_iface (self, s_adsl, out_failure_reason); } else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) { /* PPPoA doesn't need anything special */ ret = NM_ACT_STAGE_RETURN_SUCCESS; @@ -451,20 +448,19 @@ ppp_ip4_config (NMPPPManager *ppp_manager, static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMDeviceAdsl *self = NM_DEVICE_ADSL (device); NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); NMSettingAdsl *s_adsl; NMActRequest *req; GError *err = NULL; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; const char *ppp_iface; req = nm_device_get_act_request (device); - g_assert (req); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); s_adsl = (NMSettingAdsl *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_ADSL); - g_assert (s_adsl); + g_return_val_if_fail (s_adsl, NM_ACT_STAGE_RETURN_FAILURE); /* PPPoE uses the NAS interface, not the ATM interface */ if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { @@ -478,27 +474,26 @@ act_stage3_ip4_config_start (NMDevice *device, } priv->ppp_manager = nm_ppp_manager_create (ppp_iface, &err); - if ( priv->ppp_manager - && nm_ppp_manager_start (priv->ppp_manager, req, - nm_setting_adsl_get_username (s_adsl), - 30, 0, &err)) { - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK (ppp_state_changed), - self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK (ppp_ip4_config), - self); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { + if ( !priv->ppp_manager + || !nm_ppp_manager_start (priv->ppp_manager, req, + nm_setting_adsl_get_username (s_adsl), + 30, 0, &err)) { _LOGW (LOGD_ADSL, "PPP failed to start: %s", err->message); g_error_free (err); g_clear_object (&priv->ppp_manager); - *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; } - return ret; + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, + G_CALLBACK (ppp_state_changed), + self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, + G_CALLBACK (ppp_ip4_config), + self); + return NM_ACT_STAGE_RETURN_POSTPONE; } static void @@ -513,7 +508,7 @@ adsl_cleanup (NMDeviceAdsl *self) g_clear_object (&priv->ppp_manager); } - g_signal_handlers_disconnect_by_func (NM_PLATFORM_GET, G_CALLBACK (link_changed_cb), self); + g_signal_handlers_disconnect_by_func (nm_device_get_platform (NM_DEVICE (self)), G_CALLBACK (link_changed_cb), self); if (priv->brfd >= 0) { close (priv->brfd); @@ -547,7 +542,7 @@ carrier_update_cb (gpointer user_data) path = g_strdup_printf ("/sys/class/atm/%s/carrier", NM_ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (NM_DEVICE (self)))); - carrier = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (path), 10, 0, 1, -1); + carrier = (int) nm_platform_sysctl_get_int_checked (nm_device_get_platform (NM_DEVICE (self)), NMP_SYSCTL_PATHID_ABSOLUTE (path), 10, 0, 1, -1); g_free (path); if (carrier != -1) diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 92b2c918..ebfa0d64 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -183,7 +183,8 @@ pan_connection_check_create (NMBluezDevice *self) NMConnection *connection; NMConnection *added; NMSetting *setting; - char *uuid, *id; + char *id; + char uuid[37]; GError *error = NULL; NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); @@ -205,7 +206,7 @@ pan_connection_check_create (NMBluezDevice *self) connection = nm_simple_connection_new (); /* Setting: Connection */ - uuid = nm_utils_uuid_generate (); + nm_utils_uuid_generate_buf (uuid); id = g_strdup_printf (_("%s Network"), priv->name); setting = nm_setting_connection_new (); g_object_set (setting, @@ -266,7 +267,6 @@ pan_connection_check_create (NMBluezDevice *self) g_object_unref (connection); g_free (id); - g_free (uuid); } static gboolean diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 58fa9b01..2f0afa16 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -134,10 +134,7 @@ cleanup_checking (NMBluezManager *self, gboolean do_unwatch_name) { NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - if (priv->async_cancellable) { - g_cancellable_cancel (priv->async_cancellable); - g_clear_object (&priv->async_cancellable); - } + nm_clear_g_cancellable (&priv->async_cancellable); g_clear_object (&priv->introspect_proxy); diff --git a/src/devices/bluetooth/nm-bt-error.c b/src/devices/bluetooth/nm-bt-error.c index 18391187..66c65b6d 100644 --- a/src/devices/bluetooth/nm-bt-error.c +++ b/src/devices/bluetooth/nm-bt-error.c @@ -22,13 +22,5 @@ #include "nm-bt-error.h" -GQuark -nm_bt_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("nm-bt-error"); - return quark; -} - +NM_CACHED_QUARK_FCN ("nm-bt-error", nm_bt_error_quark) diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 31b9bbf9..4ee71489 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -99,7 +99,7 @@ G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) /*****************************************************************************/ -static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason); +static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *out_failure_reason); /*****************************************************************************/ @@ -328,7 +328,7 @@ complete_connection (NMDevice *device, return FALSE; } - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_BLUETOOTH_SETTING_NAME, existing_connections, @@ -362,18 +362,24 @@ complete_connection (NMDevice *device, static void ppp_stats (NMModem *modem, - guint32 in_bytes, - guint32 out_bytes, + guint i_in_bytes, + guint i_out_bytes, gpointer user_data) { - g_signal_emit (NM_DEVICE_BT (user_data), signals[PPP_STATS], 0, in_bytes, out_bytes); + guint32 in_bytes = i_in_bytes; + guint32 out_bytes = i_out_bytes; + + g_signal_emit (NM_DEVICE_BT (user_data), signals[PPP_STATS], 0, (guint) in_bytes, (guint) out_bytes); } static void -ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) +ppp_failed (NMModem *modem, + guint i_reason, + gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceStateReason reason = i_reason; switch (nm_device_get_state (device)) { case NM_DEVICE_STATE_PREPARE: @@ -430,28 +436,30 @@ modem_auth_result (NMModem *modem, GError *error, gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; if (error) { nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); } else { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + /* Otherwise, on success for GSM/CDMA secrets we need to schedule modem stage1 again */ g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - if (!modem_stage1 (NM_DEVICE_BT (device), priv->modem, &reason)) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + if (!modem_stage1 (NM_DEVICE_BT (device), priv->modem, &failure_reason)) + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, failure_reason); } } static void modem_prepare_result (NMModem *modem, gboolean success, - NMDeviceStateReason reason, + guint i_reason, gpointer user_data) { NMDeviceBt *self = NM_DEVICE_BT (user_data); NMDevice *device = NM_DEVICE (self); + NMDeviceStateReason reason = i_reason; NMDeviceState state; state = nm_device_get_state (device); @@ -460,12 +468,12 @@ modem_prepare_result (NMModem *modem, if (success) { NMActRequest *req; NMActStageReturn ret; - NMDeviceStateReason stage2_reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; req = nm_device_get_act_request (device); - g_assert (req); + g_return_if_fail (req); - ret = nm_modem_act_stage2_config (modem, req, &stage2_reason); + ret = nm_modem_act_stage2_config (modem, req, &failure_reason); switch (ret) { case NM_ACT_STAGE_RETURN_POSTPONE: break; @@ -474,17 +482,17 @@ modem_prepare_result (NMModem *modem, break; case NM_ACT_STAGE_RETURN_FAILURE: default: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, stage2_reason); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, failure_reason); break; } } else { - if (reason == NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT) { + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT) { /* If the connect failed because the SIM PIN was wrong don't allow * the device to be auto-activated anymore, which would risk locking * the SIM if the incorrect PIN continues to be used. */ - nm_device_set_autoconnect (device, FALSE); _LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN"); + nm_device_set_autoconnect_intern (device, FALSE); } nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); @@ -500,7 +508,7 @@ device_state_changed (NMDevice *device, NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); if (priv->modem) - nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); + nm_modem_device_state_changed (priv->modem, new_state, old_state); /* Need to recheck available connections whenever MM appears or disappears, * since the device could be both DUN and NAP capable and thus may not @@ -541,17 +549,15 @@ data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) } static gboolean -modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason) +modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *out_failure_reason) { NMActRequest *req; NMActStageReturn ret; - g_return_val_if_fail (reason != NULL, FALSE); - req = nm_device_get_act_request (NM_DEVICE (self)); - g_assert (req); + g_return_val_if_fail (req, FALSE); - ret = nm_modem_act_stage1_prepare (modem, req, reason); + ret = nm_modem_act_stage1_prepare (modem, req, out_failure_reason); switch (ret) { case NM_ACT_STAGE_RETURN_POSTPONE: case NM_ACT_STAGE_RETURN_SUCCESS: @@ -639,7 +645,7 @@ component_added (NMDevice *device, GObject *component) const gchar *modem_control_port; char *base; NMDeviceState state; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; if (!NM_IS_MODEM (component)) return FALSE; @@ -694,8 +700,8 @@ component_added (NMDevice *device, GObject *component) g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self); /* Kick off the modem connection */ - if (!modem_stage1 (self, modem, &reason)) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, reason); + if (!modem_stage1 (self, modem, &failure_reason)) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, failure_reason); return TRUE; } @@ -836,14 +842,15 @@ bt_connect_timeout (gpointer user_data) } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceBt *self = NM_DEVICE_BT (device); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); NMConnection *connection; connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + priv->bt_type = get_connection_bt_type (connection); if (priv->bt_type == NM_BT_CAPABILITY_NONE) { // FIXME: set a reason code @@ -851,7 +858,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } if (priv->bt_type == NM_BT_CAPABILITY_DUN && !priv->mm_running) { - *reason = NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -862,8 +869,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) priv->bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP), bluez_connect_cb, g_object_ref (device)); - if (priv->timeout_id) - g_source_remove (priv->timeout_id); + nm_clear_g_source (&priv->timeout_id); priv->timeout_id = g_timeout_add_seconds (30, bt_connect_timeout, device); return NM_ACT_STAGE_RETURN_POSTPONE; @@ -872,38 +878,34 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - NMActStageReturn ret; if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - ret = nm_modem_stage3_ip4_config_start (priv->modem, - device, - NM_DEVICE_CLASS (nm_device_bt_parent_class), - reason); - } else - ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); + return nm_modem_stage3_ip4_config_start (priv->modem, + device, + NM_DEVICE_CLASS (nm_device_bt_parent_class), + out_failure_reason); + } - return ret; + return NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); } static NMActStageReturn act_stage3_ip6_config_start (NMDevice *device, NMIP6Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - NMActStageReturn ret; if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - ret = nm_modem_stage3_ip6_config_start (priv->modem, - nm_device_get_act_request (device), - reason); - } else - ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip6_config_start (device, out_config, reason); + return nm_modem_stage3_ip6_config_start (priv->modem, + nm_device_get_act_request (device), + out_failure_reason); + } - return ret; + return NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason); } static void @@ -923,8 +925,7 @@ deactivate (NMDevice *device) */ nm_modem_device_state_changed (priv->modem, NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_ACTIVATED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); + NM_DEVICE_STATE_ACTIVATED); modem_cleanup (NM_DEVICE_BT (device)); } } @@ -1028,15 +1029,15 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_BT_NAME: - /* Construct only */ + /* construct-only */ priv->name = g_value_dup_string (value); break; case PROP_BT_CAPABILITIES: - /* Construct only */ + /* construct-only */ priv->capabilities = g_value_get_uint (value); break; case PROP_BT_DEVICE: - /* Construct only */ + /* construct-only */ priv->bt_device = g_value_dup_object (value); g_signal_connect (priv->bt_device, "removed", G_CALLBACK (bluez_device_removed), object); break; @@ -1174,6 +1175,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->complete_connection = complete_connection; device_class->is_available = is_available; device_class->component_added = component_added; + device_class->get_configured_mtu = nm_modem_get_configured_mtu; device_class->state_changed = device_state_changed; @@ -1198,12 +1200,13 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[PPP_STATS] = - g_signal_new ("ppp-stats", + g_signal_new (NM_DEVICE_BT_PPP_STATS, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); + G_TYPE_UINT /*guint32 in_bytes*/, + G_TYPE_UINT /*guint32 out_bytes*/); nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), NMDBUS_TYPE_DEVICE_BLUETOOTH_SKELETON, diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h index 43bd4257..9bcf6ca8 100644 --- a/src/devices/bluetooth/nm-device-bt.h +++ b/src/devices/bluetooth/nm-device-bt.h @@ -37,6 +37,8 @@ #define NM_DEVICE_BT_CAPABILITIES "bt-capabilities" #define NM_DEVICE_BT_DEVICE "bt-device" +#define NM_DEVICE_BT_PPP_STATS "ppp-stats" + typedef struct _NMDeviceBt NMDeviceBt; typedef struct _NMDeviceBtClass NMDeviceBtClass; diff --git a/src/devices/nm-arping-manager.c b/src/devices/nm-arping-manager.c index 7b765844..51f80e08 100644 --- a/src/devices/nm-arping-manager.c +++ b/src/devices/nm-arping-manager.c @@ -81,13 +81,14 @@ G_DEFINE_TYPE (NMArpingManager, nm_arping_manager, G_TYPE_OBJECT) #define _NMLOG(level, ...) \ G_STMT_START { \ char _sbuf[64]; \ + int _ifindex = (self) ? NM_ARPING_MANAGER_GET_PRIVATE (self)->ifindex : 0; \ \ nm_log ((level), _NMLOG_DOMAIN, \ + nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ + NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ - self ? nm_sprintf_buf (_sbuf, "[%p,%d]", \ - self, \ - NM_ARPING_MANAGER_GET_PRIVATE (self)->ifindex) : "" \ + self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, _ifindex) : "" \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } G_STMT_END diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 34d34eb4..3325c948 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -101,7 +101,7 @@ complete_connection (NMDevice *device, { NMSettingBond *s_bond; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_BOND_SETTING_NAME, existing_connections, @@ -131,7 +131,7 @@ set_bond_attr (NMDevice *device, NMBondMode mode, const char *attr, const char * if (!_nm_setting_bond_option_supported (attr, mode)) return FALSE; - ret = nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, attr, value); + ret = nm_platform_sysctl_master_set_option (nm_device_get_platform (device), ifindex, attr, value); if (!ret) _LOGW (LOGD_PLATFORM, "failed to set bonding attribute '%s' to '%s'", attr, value); return ret; @@ -165,7 +165,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_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, *options); + gs_free char *value = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, *options); const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options); char *p; @@ -328,7 +328,7 @@ apply_bonding_config (NMDevice *device) set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_PRIMARY, value ? value : ""); /* ARP targets: clear and initialize the list */ - contents = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, + contents = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); set_arp_targets (device, mode, contents, " \n", "-"); value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); @@ -363,21 +363,19 @@ apply_bonding_config (NMDevice *device) } static NMActStageReturn -act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; gboolean no_firmware = FALSE; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, reason); + ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; /* Interface must be down to set bond options */ nm_device_take_down (dev, TRUE); ret = apply_bonding_config (dev); - if (ret) + if (ret != NM_ACT_STAGE_RETURN_FAILURE) ret = nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE); nm_device_bring_up (dev, TRUE, &no_firmware); @@ -393,12 +391,13 @@ enslave_slave (NMDevice *device, NMDeviceBond *self = NM_DEVICE_BOND (device); gboolean success = TRUE, no_firmware = FALSE; const char *slave_iface = nm_device_get_ip_iface (slave); + NMConnection *master_con; nm_device_master_check_slave_physical_port (device, slave, LOGD_BOND); if (configure) { nm_device_take_down (slave, TRUE); - success = nm_platform_link_enslave (NM_PLATFORM_GET, + success = nm_platform_link_enslave (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); nm_device_bring_up (slave, TRUE, &no_firmware); @@ -407,6 +406,25 @@ enslave_slave (NMDevice *device, return FALSE; _LOGI (LOGD_BOND, "enslaved bond slave %s", slave_iface); + + /* The active_slave option can be set only after the interface is enslaved */ + master_con = nm_device_get_applied_connection (device); + if (master_con) { + NMSettingBond *s_bond = nm_connection_get_setting_bond (master_con); + const char *active; + + if (s_bond) { + active = nm_setting_bond_get_option_by_name (s_bond, "active_slave"); + if (active && nm_streq0 (active, nm_device_get_iface (slave))) { + nm_platform_sysctl_master_set_option (nm_device_get_platform (device), + nm_device_get_ifindex (device), + "active_slave", + active); + _LOGD (LOGD_BOND, "setting slave %s as active one for master %s", + active, nm_device_get_iface (device)); + } + } + } } else _LOGI (LOGD_BOND, "bond slave %s was enslaved", slave_iface); @@ -428,7 +446,7 @@ release_slave (NMDevice *device, */ address = g_strdup (nm_device_get_hw_address (device)); - success = nm_platform_link_release (NM_PLATFORM_GET, + success = nm_platform_link_release (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); @@ -440,7 +458,7 @@ release_slave (NMDevice *device, nm_device_get_ip_iface (slave)); } - nm_platform_process_events (NM_PLATFORM_GET); + nm_platform_process_events (nm_device_get_platform (device)); if (nm_device_update_hw_address (device)) nm_device_hw_addr_set (device, address, "restore", FALSE); @@ -468,7 +486,7 @@ create_and_realize (NMDevice *device, g_assert (iface); - plerr = nm_platform_link_bond_add (NM_PLATFORM_GET, iface, out_plink); + plerr = nm_platform_link_bond_add (nm_device_get_platform (device), iface, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create bond interface '%s' for '%s': %s", @@ -480,6 +498,116 @@ create_and_realize (NMDevice *device, return TRUE; } +static gboolean +check_changed_options (NMSettingBond *s_a, NMSettingBond *s_b, GError **error) +{ + guint i, num; + const char *name = NULL, *value_a = NULL, *value_b = NULL; + + /* Check that options in @s_a have compatible changes in @s_b */ + + num = nm_setting_bond_get_num_options (s_a); + for (i = 0; i < num; i++) { + nm_setting_bond_get_option (s_a, i, &name, &value_a); + + /* We support changes to these */ + if (NM_IN_STRSET (name, + NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, + NM_SETTING_BOND_OPTION_PRIMARY)) { + continue; + } + + /* Missing in @s_b, but has a default value in @s_a */ + value_b = nm_setting_bond_get_option_by_name (s_b, name); + if ( !value_b + && nm_streq0 (value_a, nm_setting_bond_get_option_default (s_a, name))) { + continue; + } + + /* Reject any other changes */ + if (!nm_streq0 (value_a, value_b)) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply '%s' bond option", + name); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +can_reapply_change (NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + NMDeviceClass *device_class; + NMSettingBond *s_bond_old, *s_bond_new; + + /* Only handle bond setting here, delegate other settings to parent class */ + if (nm_streq (setting_name, NM_SETTING_BOND_SETTING_NAME)) { + if (!nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_BOND_SETTING_NAME, + error, + NM_SETTING_BOND_OPTIONS)) + return FALSE; + + s_bond_old = NM_SETTING_BOND (s_old); + s_bond_new = NM_SETTING_BOND (s_new); + + if ( !check_changed_options (s_bond_old, s_bond_new, error) + || !check_changed_options (s_bond_new, s_bond_old, error)) { + return FALSE; + } + + return TRUE; + } + + device_class = NM_DEVICE_CLASS (nm_device_bond_parent_class); + return device_class->can_reapply_change (device, + setting_name, + s_old, + s_new, + diffs, + error); +} + +static void +reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new) +{ + NMDeviceBond *self = NM_DEVICE_BOND (device); + const char *value; + NMSettingBond *s_bond; + NMBondMode mode; + + NM_DEVICE_CLASS (nm_device_bond_parent_class)->reapply_connection (device, + con_old, + con_new); + + _LOGD (LOGD_BOND, "reapplying bond settings"); + s_bond = nm_connection_get_setting_bond (con_new); + g_return_if_fail (s_bond); + + value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE); + if (!value) + value = "balance-rr"; + + mode = _nm_setting_bond_mode_from_string (value); + g_return_if_fail (mode != NM_BOND_MODE_UNKNOWN); + + /* Primary */ + value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY); + set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_PRIMARY, value ? value : ""); + + /* Active slave */ + set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); +} + /*****************************************************************************/ static void @@ -508,6 +636,8 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; + parent_class->can_reapply_change = can_reapply_change; + parent_class->reapply_connection = reapply_connection; nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), NMDBUS_TYPE_DEVICE_BOND_SKELETON, diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 613d59cd..01c4eb22 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -107,7 +107,7 @@ complete_connection (NMDevice *device, { NMSettingBridge *s_bridge; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_BRIDGE_SETTING_NAME, existing_connections, @@ -197,9 +197,9 @@ commit_option (NMDevice *device, NMSetting *setting, const Option *option, gbool value = g_strdup_printf ("%u", uval); if (slave) - nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); + nm_platform_sysctl_slave_set_option (nm_device_get_platform (device), ifindex, option->sysname, value); else - nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); + nm_platform_sysctl_master_set_option (nm_device_get_platform (device), ifindex, option->sysname, value); } static void @@ -243,7 +243,7 @@ update_connection (NMDevice *device, NMConnection *connection) } for (option = master_options; option->name; option++) { - gs_free char *str = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, option->sysname); + gs_free char *str = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, option->sysname); int value; if (str) { @@ -282,7 +282,7 @@ master_update_slave_connection (NMDevice *device, } for (option = slave_options; option->name; option++) { - gs_free char *str = nm_platform_sysctl_slave_get_option (NM_PLATFORM_GET, ifindex_slave, option->sysname); + gs_free char *str = nm_platform_sysctl_slave_get_option (nm_device_get_platform (device), ifindex_slave, option->sysname); int value; if (str) { @@ -305,14 +305,14 @@ master_update_slave_connection (NMDevice *device, } static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret; NMConnection *connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; @@ -333,7 +333,7 @@ enslave_slave (NMDevice *device, NMDeviceBridge *self = NM_DEVICE_BRIDGE (device); if (configure) { - if (!nm_platform_link_enslave (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave))) + if (!nm_platform_link_enslave (nm_device_get_platform (device), 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)); @@ -357,7 +357,7 @@ release_slave (NMDevice *device, gboolean success; if (configure) { - success = nm_platform_link_release (NM_PLATFORM_GET, + success = nm_platform_link_release (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); @@ -401,7 +401,7 @@ create_and_realize (NMDevice *device, } } - plerr = nm_platform_link_bridge_add (NM_PLATFORM_GET, + plerr = nm_platform_link_bridge_add (nm_device_get_platform (device), iface, hwaddr ? mac_address : NULL, hwaddr ? ETH_ALEN : 0, diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c new file mode 100644 index 00000000..dce4f7bc --- /dev/null +++ b/src/devices/nm-device-dummy.c @@ -0,0 +1,205 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-dummy.h" + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "nm-act-request.h" +#include "nm-device-private.h" +#include "nm-ip4-config.h" +#include "platform/nm-platform.h" +#include "nm-device-factory.h" +#include "nm-setting-dummy.h" +#include "nm-core-internal.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.Dummy.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceDummy); + +/*****************************************************************************/ + +struct _NMDeviceDummy { + NMDevice parent; +}; + +struct _NMDeviceDummyClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceDummy, nm_device_dummy, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *dev) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingDummy *s_dummy; + + nm_utils_complete_generic (nm_device_get_platform (device), + connection, + NM_SETTING_DUMMY_SETTING_NAME, + existing_connections, + NULL, + _("Dummy connection"), + NULL, + TRUE); + + s_dummy = nm_connection_get_setting_dummy (connection); + if (!s_dummy) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'dummy' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMSettingDummy *s_dummy = nm_connection_get_setting_dummy (connection); + + if (!s_dummy) { + s_dummy = (NMSettingDummy *) nm_setting_dummy_new (); + nm_connection_add_setting (connection, (NMSetting *) s_dummy); + } +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMPlatformError plerr; + NMSettingDummy *s_dummy; + + s_dummy = nm_connection_get_setting_dummy (connection); + g_assert (s_dummy); + + plerr = nm_platform_link_dummy_add (nm_device_get_platform (device), iface, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create dummy interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMSettingDummy *s_dummy; + + if (!NM_DEVICE_CLASS (nm_device_dummy_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_dummy = nm_connection_get_setting_dummy (connection); + if (!s_dummy) + return FALSE; + + return TRUE; +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMActStageReturn ret; + + ret = NM_DEVICE_CLASS (nm_device_dummy_parent_class)->act_stage1_prepare (device, out_failure_reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) + return NM_ACT_STAGE_RETURN_FAILURE; + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +/*****************************************************************************/ + +static void +nm_device_dummy_init (NMDeviceDummy *self) +{ +} + +static void +nm_device_dummy_class_init (NMDeviceDummyClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_DUMMY) + + device_class->connection_type = NM_SETTING_DUMMY_SETTING_NAME; + device_class->complete_connection = complete_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->update_connection = update_connection; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_DUMMY_SKELETON, + NULL); +} + + +/*****************************************************************************/ + +#define NM_TYPE_DUMMY_DEVICE_FACTORY (nm_dummy_device_factory_get_type ()) +#define NM_DUMMY_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DUMMY_DEVICE_FACTORY, NMDummyDeviceFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_DUMMY, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "Dummy", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_DUMMY, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_DUMMY, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (DUMMY, Dummy, dummy, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_DUMMY) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_DUMMY_SETTING_NAME), + factory_class->create_device = create_device; +); diff --git a/src/devices/nm-device-dummy.h b/src/devices/nm-device-dummy.h new file mode 100644 index 00000000..cc89a847 --- /dev/null +++ b/src/devices/nm-device-dummy.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_DUMMY_H__ +#define __NETWORKMANAGER_DEVICE_DUMMY_H__ + +#include "nm-device-generic.h" + +#define NM_TYPE_DEVICE_DUMMY (nm_device_dummy_get_type ()) +#define NM_DEVICE_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummy)) +#define NM_DEVICE_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_DUMMY, NMDeviceDummyClass)) +#define NM_IS_DEVICE_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_DUMMY)) +#define NM_IS_DEVICE_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_DUMMY)) +#define NM_DEVICE_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummyClass)) + +typedef struct _NMDeviceDummy NMDeviceDummy; +typedef struct _NMDeviceDummyClass NMDeviceDummyClass; + +GType nm_device_dummy_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_DUMMY_H__ */ diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 5df16df0..4c5aeb5e 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -29,7 +29,7 @@ #include <unistd.h> #include <errno.h> -#include <gudev/gudev.h> +#include <libudev.h> #include "nm-device-private.h" #include "nm-act-request.h" @@ -59,8 +59,6 @@ _LOG_DECLARE_SELF(NMDeviceEthernet); /*****************************************************************************/ -#define WIRED_SECRETS_TRIES "wired-secrets-tries" - #define PPPOE_RECONNECT_DELAY 7 #define PPPOE_ENCAP_OVERHEAD 8 /* 2 bytes for PPP, 6 for PPPoE */ @@ -71,7 +69,6 @@ typedef struct Supplicant { NMSupplicantInterface *iface; /* signal handler ids */ - gulong iface_error_id; gulong iface_state_id; /* Timeouts and idles */ @@ -158,8 +155,8 @@ static void _update_s390_subchannels (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - gs_unref_object GUdevDevice *dev = NULL; - gs_unref_object GUdevDevice *parent = NULL; + struct udev_device *dev = NULL; + struct udev_device *parent = NULL; const char *parent_path, *item; int ifindex; GDir *dir; @@ -175,21 +172,20 @@ _update_s390_subchannels (NMDeviceEthernet *self) } ifindex = nm_device_get_ifindex ((NMDevice *) self); - dev = (GUdevDevice *) nm_g_object_ref (nm_platform_link_get_udev_device (NM_PLATFORM_GET, ifindex)); + dev = nm_platform_link_get_udev_device (nm_device_get_platform (NM_DEVICE (self)), ifindex); if (!dev) return; /* Try for the "ccwgroup" parent */ - parent = g_udev_device_get_parent_with_subsystem (dev, "ccwgroup", NULL); + parent = udev_device_get_parent_with_subsystem_devtype (dev, "ccwgroup", NULL); if (!parent) { /* FIXME: whatever 'lcs' devices' subsystem is here... */ - if (!parent) { - /* Not an s390 device */ - return; - } + + /* Not an s390 device */ + return; } - parent_path = g_udev_device_get_sysfs_path (parent); + parent_path = udev_device_get_syspath (parent); dir = g_dir_open (parent_path, 0, &error); if (!dir) { _LOGW (LOGD_DEVICE | LOGD_PLATFORM, "update-s390: failed to open directory '%s': %s", @@ -213,7 +209,7 @@ _update_s390_subchannels (NMDeviceEthernet *self) gs_free char *path = NULL, *value = NULL; path = g_strdup_printf ("%s/%s", parent_path, item); - value = nm_platform_sysctl_get (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (path)); + value = nm_platform_sysctl_get (nm_device_get_platform (NM_DEVICE (self)), NMP_SYSCTL_PATHID_ABSOLUTE (path)); if ( !strcmp (item, "portname") && !g_strcmp0 (value, "no portname required")) { @@ -259,16 +255,18 @@ _update_s390_subchannels (NMDeviceEthernet *self) } static void -clear_secrets_tries (NMDevice *device) +reset_8021x_autoconnect_retries (NMDevice *device) { NMActRequest *req; - NMConnection *connection; + NMSettingsConnection *connection; req = nm_device_get_act_request (device); - if (req) { - connection = nm_act_request_get_applied_connection (req); - /* Clear wired secrets tries on success, failure, or when deactivating */ - g_object_set_data (G_OBJECT (connection), WIRED_SECRETS_TRIES, NULL); + if ( req + && nm_device_get_applied_setting (device, NM_TYPE_SETTING_802_1X)) { + connection = nm_act_request_get_settings_connection (req); + g_return_if_fail (connection); + /* Reset autoconnect retries on success, failure, or when deactivating */ + nm_settings_connection_reset_autoconnect_retries (connection); } } @@ -281,10 +279,11 @@ device_state_changed (NMDevice *device, if (new_state > NM_DEVICE_STATE_ACTIVATED) wired_secrets_cancel (NM_DEVICE_ETHERNET (device)); - if ( new_state == NM_DEVICE_STATE_ACTIVATED - || new_state == NM_DEVICE_STATE_FAILED - || new_state == NM_DEVICE_STATE_DISCONNECTED) - clear_secrets_tries (device); + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_ACTIVATED, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_DISCONNECTED)) + reset_8021x_autoconnect_retries (device); } static void @@ -305,7 +304,7 @@ get_generic_capabilities (NMDevice *device) int ifindex = nm_device_get_ifindex (device); if (ifindex > 0) { - if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, ifindex)) + if (nm_platform_link_supports_carrier_detect (nm_device_get_platform (device), ifindex)) return NM_DEVICE_CAP_CARRIER_DETECT; else { _LOGI (LOGD_PLATFORM, "driver '%s' does not support carrier detection.", @@ -423,22 +422,12 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) /* 802.1X */ static void -supplicant_interface_clear_handlers (NMDeviceEthernet *self) +supplicant_interface_release (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); nm_clear_g_source (&priv->supplicant_timeout_id); nm_clear_g_source (&priv->supplicant.con_timeout_id); - nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_error_id); -} - -static void -supplicant_interface_release (NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - - supplicant_interface_clear_handlers (self); - nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id); if (priv->supplicant.iface) { @@ -580,7 +569,7 @@ build_supplicant_config (NMDeviceEthernet *self, connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_assert (connection); con_uuid = nm_connection_get_uuid (connection); - mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, + mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self))); config = nm_supplicant_config_new (); @@ -595,9 +584,24 @@ build_supplicant_config (NMDeviceEthernet *self, } static void +supplicant_iface_assoc_cb (NMSupplicantInterface *iface, + GError *error, + gpointer user_data) +{ + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); + + if (error && !nm_utils_error_is_cancelled (error, TRUE)) { + supplicant_interface_release (self); + nm_device_queue_state (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); + } +} + +static void supplicant_iface_state_cb (NMSupplicantInterface *iface, - guint32 new_state, - guint32 old_state, + int new_state_i, + int old_state_i, int disconnect_reason, gpointer user_data) { @@ -605,9 +609,10 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); NMSupplicantConfig *config; - gboolean success = FALSE; NMDeviceState devstate; GError *error = NULL; + NMSupplicantInterfaceState new_state = new_state_i; + NMSupplicantInterfaceState old_state = old_state_i; if (new_state == old_state) return; @@ -622,30 +627,23 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, case NM_SUPPLICANT_INTERFACE_STATE_READY: config = build_supplicant_config (self, &error); if (config) { - success = nm_supplicant_interface_set_config (priv->supplicant.iface, config, &error); + nm_supplicant_interface_assoc (priv->supplicant.iface, config, + supplicant_iface_assoc_cb, self); g_object_unref (config); - - if (!success) { - _LOGE (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) couldn't send security configuration to the supplicant: %s", - error->message); - g_clear_error (&error); - } } else { _LOGE (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) couldn't build security configuration: %s", error->message); g_clear_error (&error); - } - if (!success) { nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); } break; case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - supplicant_interface_clear_handlers (self); + nm_clear_g_source (&priv->supplicant_timeout_id); + nm_clear_g_source (&priv->supplicant.con_timeout_id); /* If this is the initial association during device activation, * schedule the next activation stage. @@ -677,39 +675,26 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, } } -static void -supplicant_iface_connection_error_cb (NMSupplicantInterface *iface, - const char *name, - const char *message, - gpointer user_data) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); - - _LOGW (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) association request to the supplicant failed: %s - %s", - name, message); - - supplicant_interface_release (self); - nm_device_queue_state (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); -} - static NMActStageReturn handle_auth_or_fail (NMDeviceEthernet *self, NMActRequest *req, gboolean new_secrets) { const char *setting_name; - guint32 tries; NMConnection *applied_connection; + NMSettingsConnection *settings_connection; + int tries_left; applied_connection = nm_act_request_get_applied_connection (req); + settings_connection = nm_act_request_get_settings_connection (req); - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), WIRED_SECRETS_TRIES)); - if (tries > 3) + tries_left = nm_settings_connection_get_autoconnect_retries (settings_connection); + if (tries_left == 0) return NM_ACT_STAGE_RETURN_FAILURE; + if (tries_left > 0) + nm_settings_connection_set_autoconnect_retries (settings_connection, tries_left - 1); + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (req)); @@ -719,7 +704,6 @@ handle_auth_or_fail (NMDeviceEthernet *self, wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); - g_object_set_data (G_OBJECT (applied_connection), WIRED_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); } else _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); @@ -771,6 +755,7 @@ static gboolean supplicant_interface_init (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + guint timeout; supplicant_interface_release (self); @@ -790,14 +775,11 @@ supplicant_interface_init (NMDeviceEthernet *self) G_CALLBACK (supplicant_iface_state_cb), self); - /* Hook up error signal handler to capture association errors */ - priv->supplicant.iface_error_id = g_signal_connect (priv->supplicant.iface, - NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR, - G_CALLBACK (supplicant_iface_connection_error_cb), - self); - - /* Set up a timeout on the connection attempt to fail it after 25 seconds */ - priv->supplicant.con_timeout_id = g_timeout_add_seconds (25, supplicant_connection_timeout_cb, self); + /* Set up a timeout on the connection attempt */ + timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); + priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout, + supplicant_connection_timeout_cb, + self); return TRUE; } @@ -846,7 +828,7 @@ link_negotiation_set (NMDevice *device) } } - if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_ifindex (device), + if (!nm_platform_ethtool_get_link_settings (nm_device_get_platform (device), nm_device_get_ifindex (device), &link_autoneg, &link_speed, &link_duplex)) { _LOGW (LOGD_DEVICE, "set-link: unable to retrieve link negotiation"); return; @@ -870,7 +852,7 @@ link_negotiation_set (NMDevice *device) duplex ? "" : "*"); } - if (!nm_platform_ethtool_set_link_settings (NM_PLATFORM_GET, + if (!nm_platform_ethtool_set_link_settings (nm_device_get_platform (device), nm_device_get_ifindex (device), autoneg, speed, @@ -893,15 +875,13 @@ pppoe_reconnect_delay (gpointer user_data) } static NMActStageReturn -act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMActStageReturn ret; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason); + ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; @@ -935,7 +915,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) } static NMActStageReturn -nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason) +nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMConnection *connection; @@ -944,11 +924,12 @@ nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason) NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; connection = nm_device_get_applied_connection (NM_DEVICE (self)); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + security = nm_connection_get_setting_802_1x (connection); if (!security) { _LOGE (LOGD_DEVICE, "Invalid or missing 802.1X security"); - *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return ret; } @@ -966,7 +947,7 @@ nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason) ret = handle_auth_or_fail (self, req, FALSE); if (ret != NM_ACT_STAGE_RETURN_POSTPONE) - *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); } else { _LOGI (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) connection '%s' requires no security. No secrets needed.", @@ -975,7 +956,7 @@ nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason) if (supplicant_interface_init (self)) ret = NM_ACT_STAGE_RETURN_POSTPONE; else - *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); } return ret; @@ -1017,43 +998,42 @@ ppp_ip4_config (NMPPPManager *ppp_manager, } static NMActStageReturn -pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reason) +pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingPppoe *s_pppoe; NMActRequest *req; GError *err = NULL; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; req = nm_device_get_act_request (NM_DEVICE (self)); - g_assert (req); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); s_pppoe = (NMSettingPppoe *) nm_device_get_applied_setting ((NMDevice *) self, NM_TYPE_SETTING_PPPOE); - g_assert (s_pppoe); + g_return_val_if_fail (s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); priv->ppp_manager = nm_ppp_manager_create (nm_device_get_iface (NM_DEVICE (self)), &err); - if ( priv->ppp_manager - && nm_ppp_manager_start (priv->ppp_manager, req, - nm_setting_pppoe_get_username (s_pppoe), - 30, 0, &err)) { - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK (ppp_state_changed), - self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK (ppp_ip4_config), - self); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { + + if ( !priv->ppp_manager + || !nm_ppp_manager_start (priv->ppp_manager, req, + nm_setting_pppoe_get_username (s_pppoe), + 30, 0, &err)) { _LOGW (LOGD_DEVICE, "PPPoE failed to start: %s", err->message); g_error_free (err); g_clear_object (&priv->ppp_manager); - *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; } - return ret; + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, + G_CALLBACK (ppp_state_changed), + self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, + G_CALLBACK (ppp_ip4_config), + self); + return NM_ACT_STAGE_RETURN_POSTPONE; } /*****************************************************************************/ @@ -1144,7 +1124,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_PLATFORM_GET, nm_device_get_ifindex (device)); + carrier = nm_platform_link_is_connected (nm_device_get_platform (device), 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) { @@ -1262,13 +1242,13 @@ wake_on_lan_enable (NMDevice *device) } wol = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; found: - return nm_platform_ethtool_set_wake_on_lan (NM_PLATFORM_GET, nm_device_get_ifindex (device), wol, password); + return nm_platform_ethtool_set_wake_on_lan (nm_device_get_platform (device), nm_device_get_ifindex (device), wol, password); } /*****************************************************************************/ static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceEthernet *self = (NMDeviceEthernet *) device; NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); @@ -1277,11 +1257,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; NMSettingDcb *s_dcb; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - s_con = NM_SETTING_CONNECTION (nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION)); - g_assert (s_con); + g_return_val_if_fail (s_con, NM_ACT_STAGE_RETURN_FAILURE); nm_clear_g_source (&priv->dcb_timeout_id); nm_clear_g_signal_handler (device, &priv->dcb_carrier_id); @@ -1297,7 +1275,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) NM_TYPE_SETTING_802_1X); if (security) { /* FIXME: for now 802.1x is mutually exclusive with DCB */ - return nm_8021x_stage2_config (self, reason); + return nm_8021x_stage2_config (self, out_failure_reason); } } @@ -1307,9 +1285,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) s_dcb = (NMSettingDcb *) nm_device_get_applied_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_PLATFORM_GET, nm_device_get_ifindex (device))) { + if (nm_platform_link_is_connected (nm_device_get_platform (device), nm_device_get_ifindex (device))) { if (!dcb_enable (device)) { - *reason = NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } } else { @@ -1343,7 +1321,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) if (mxu) { _LOGD (LOGD_PPP, "set MTU to %u (PPP interface MRU %u, MTU %u)", mxu + PPPOE_ENCAP_OVERHEAD, mru, mtu); - nm_platform_link_set_mtu (NM_PLATFORM_GET, + nm_platform_link_set_mtu (nm_device_get_platform (device), nm_device_get_ifindex (device), mxu + PPPOE_ENCAP_OVERHEAD); } @@ -1356,21 +1334,19 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMSettingConnection *s_con; const char *connection_type; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - s_con = NM_SETTING_CONNECTION (nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION)); - g_assert (s_con); + g_return_val_if_fail (s_con, NM_ACT_STAGE_RETURN_FAILURE); connection_type = nm_setting_connection_get_connection_type (s_con); if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) - return pppoe_stage3_ip4_config_start (NM_DEVICE_ETHERNET (device), reason); + return pppoe_stage3_ip4_config_start (NM_DEVICE_ETHERNET (device), out_failure_reason); - return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); + return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); } static guint32 @@ -1392,7 +1368,7 @@ deactivate (NMDevice *device) GError *error = NULL; /* Clear wired secrets tries when deactivating */ - clear_secrets_tries (device); + reset_8021x_autoconnect_retries (device); nm_clear_g_source (&priv->pppoe_wait_id); @@ -1451,7 +1427,7 @@ complete_connection (NMDevice *device, /* Default to an ethernet-only connection, but if a PPPoE setting was given * then PPPoE should be our connection type. */ - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, s_pppoe ? NM_SETTING_PPPOE_SETTING_NAME : NM_SETTING_WIRED_SETTING_NAME, existing_connections, @@ -1609,7 +1585,7 @@ get_link_speed (NMDevice *device) NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); guint32 speed; - if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL, &speed, NULL)) + if (!nm_platform_ethtool_get_link_settings (nm_device_get_platform (device), nm_device_get_ifindex (device), NULL, &speed, NULL)) return; if (priv->speed == speed) return; @@ -1647,6 +1623,53 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return !!nm_device_get_initial_hw_address (device); } +static gboolean +can_reapply_change (NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + NMDeviceClass *device_class; + + /* Only handle wired setting here, delegate other settings to parent class */ + if (nm_streq (setting_name, NM_SETTING_WIRED_SETTING_NAME)) { + return nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_WIRED_SETTING_NAME, + error, + NM_SETTING_WIRED_MTU, /* reapplied with IP config */ + NM_SETTING_WIRED_SPEED, + NM_SETTING_WIRED_DUPLEX, + NM_SETTING_WIRED_AUTO_NEGOTIATE, + NM_SETTING_WIRED_WAKE_ON_LAN, + NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD); + } + + device_class = NM_DEVICE_CLASS (nm_device_ethernet_parent_class); + return device_class->can_reapply_change (device, + setting_name, + s_old, + s_new, + diffs, + error); +} + +static void +reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new) +{ + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); + + NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->reapply_connection (device, + con_old, + con_new); + + _LOGD (LOGD_DEVICE, "reapplying wired settings"); + + link_negotiation_set (device); + wake_on_lan_enable (device); +} + static void dispose (GObject *object) { @@ -1744,6 +1767,8 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->carrier_changed = carrier_changed; parent_class->link_changed = link_changed; parent_class->is_available = is_available; + parent_class->can_reapply_change = can_reapply_change; + parent_class->reapply_connection = reapply_connection; parent_class->state_changed = device_state_changed; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 0ce2cb48..f512b8b2 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -32,7 +32,8 @@ #include "nm-utils.h" #define PLUGIN_PREFIX "libnm-device-plugin-" -#define PLUGIN_PATH_TAG "NMManager-plugin-path" + +static NM_CACHED_QUARK_FCN ("NMManager-plugin-path", plugin_path_quark) /*****************************************************************************/ @@ -350,13 +351,13 @@ _add_factory (NMDeviceFactory *factory, if (found) { nm_log_warn (LOGD_PLATFORM, "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), + (char *) g_object_get_qdata (G_OBJECT (found), plugin_path_quark ()), path); return FALSE; } } - g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, g_strdup (path), g_free); + g_object_set_qdata_full (G_OBJECT (factory), plugin_path_quark (), 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++) @@ -402,6 +403,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call _ADD_INTERNAL (nm_bond_device_factory_get_type); _ADD_INTERNAL (nm_bridge_device_factory_get_type); + _ADD_INTERNAL (nm_dummy_device_factory_get_type); _ADD_INTERNAL (nm_ethernet_device_factory_get_type); _ADD_INTERNAL (nm_infiniband_device_factory_get_type); _ADD_INTERNAL (nm_ip_tunnel_device_factory_get_type); diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 2f51c69d..f6a670b2 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -54,11 +54,11 @@ G_DEFINE_TYPE (NMDeviceGeneric, nm_device_generic, NM_TYPE_DEVICE) /*****************************************************************************/ static NMDeviceCapabilities -get_generic_capabilities (NMDevice *dev) +get_generic_capabilities (NMDevice *device) { - int ifindex = nm_device_get_ifindex (dev); + int ifindex = nm_device_get_ifindex (device); - if (ifindex > 0 && nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, ifindex)) + if (ifindex > 0 && nm_platform_link_supports_carrier_detect (nm_device_get_platform (device), ifindex)) return NM_DEVICE_CAP_CARRIER_DETECT; else return NM_DEVICE_CAP_NONE; @@ -84,7 +84,7 @@ realize_start_notify (NMDevice *device, const NMPlatformLink *plink) g_clear_pointer (&priv->type_description, g_free); ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); if (ifindex > 0) - priv->type_description = g_strdup (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex)); + priv->type_description = g_strdup (nm_platform_link_get_type_name (nm_device_get_platform (device), ifindex)); } static gboolean diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 60f1aefa..f7875d09 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -75,7 +75,7 @@ get_generic_capabilities (NMDevice *device) } static NMActStageReturn -act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { nm_auto_close int dirfd = -1; NMActStageReturn ret; @@ -84,34 +84,32 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) const char *transport_mode; gboolean ok, no_firmware = FALSE; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason); + ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; - s_infiniband = (NMSettingInfiniband *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_INFINIBAND); - g_assert (s_infiniband); + s_infiniband = (NMSettingInfiniband *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_INFINIBAND); + g_return_val_if_fail (s_infiniband, NM_ACT_STAGE_RETURN_FAILURE); transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband); - dirfd = nm_platform_sysctl_open_netdir (NM_PLATFORM_GET, nm_device_get_ifindex (dev), ifname_verified); + dirfd = nm_platform_sysctl_open_netdir (nm_device_get_platform (device), nm_device_get_ifindex (device), ifname_verified); if (dirfd < 0) { if (!strcmp (transport_mode, "datagram")) return NM_ACT_STAGE_RETURN_SUCCESS; else { - *reason = NM_DEVICE_STATE_REASON_INFINIBAND_MODE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_INFINIBAND_MODE); return NM_ACT_STAGE_RETURN_FAILURE; } } /* With some drivers the interface must be down to set transport mode */ - nm_device_take_down (dev, TRUE); - ok = nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "mode"), transport_mode); - nm_device_bring_up (dev, TRUE, &no_firmware); + nm_device_take_down (device, TRUE); + ok = nm_platform_sysctl_set (nm_device_get_platform (device), NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "mode"), transport_mode); + nm_device_bring_up (device, TRUE, &no_firmware); if (!ok) { - *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -186,7 +184,7 @@ complete_connection (NMDevice *device, const char *setting_mac; const char *hw_address; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_INFINIBAND_SETTING_NAME, existing_connections, @@ -242,7 +240,7 @@ update_connection (NMDevice *device, NMConnection *connection) ifindex = nm_device_get_ifindex (device); if (ifindex > 0) { - if (!nm_platform_link_infiniband_get_properties (NM_PLATFORM_GET, ifindex, NULL, NULL, &transport_mode)) + if (!nm_platform_link_infiniband_get_properties (nm_device_get_platform (device), ifindex, NULL, NULL, &transport_mode)) transport_mode = "datagram"; } g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, transport_mode, NULL); @@ -291,7 +289,7 @@ create_and_realize (NMDevice *device, return FALSE; } - plerr = nm_platform_link_infiniband_add (NM_PLATFORM_GET, priv->parent_ifindex, priv->p_key, out_plink); + plerr = nm_platform_link_infiniband_add (nm_device_get_platform (device), priv->parent_ifindex, priv->p_key, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", @@ -321,7 +319,7 @@ unrealize (NMDevice *device, GError **error) return FALSE; } - plerr = nm_platform_link_infiniband_delete (NM_PLATFORM_GET, priv->parent_ifindex, priv->p_key); + plerr = nm_platform_link_infiniband_delete (nm_device_get_platform (device), priv->parent_ifindex, priv->p_key); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to remove InfiniBand P_Key interface '%s': %s", diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 58544377..53b7cf4e 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -124,8 +124,8 @@ update_properties_from_ifindex (NMDevice *device, int ifindex) NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); int parent_ifindex = 0; - in_addr_t local4, remote4; - struct in6_addr local6, remote6; + in_addr_t local4 = 0, remote4 = 0; + struct in6_addr local6 = { 0 }, remote6 = { 0 }; guint8 ttl = 0, tos = 0, encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; @@ -157,7 +157,7 @@ clear: if (priv->mode == NM_IP_TUNNEL_MODE_GRE) { const NMPlatformLnkGre *lnk; - lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL); + lnk = nm_platform_link_get_lnk_gre (nm_device_get_platform (device), ifindex, NULL); if (!lnk) { _LOGW (LOGD_PLATFORM, "could not read %s properties", "gre"); goto clear; @@ -202,7 +202,7 @@ clear: } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { const NMPlatformLnkSit *lnk; - lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL); + lnk = nm_platform_link_get_lnk_sit (nm_device_get_platform (device), ifindex, NULL); if (!lnk) { _LOGW (LOGD_PLATFORM, "could not read %s properties", "sit"); goto clear; @@ -217,7 +217,7 @@ clear: } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) { const NMPlatformLnkIpIp *lnk; - lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL); + lnk = nm_platform_link_get_lnk_ipip (nm_device_get_platform (device), ifindex, NULL); if (!lnk) { _LOGW (LOGD_PLATFORM, "could not read %s properties", "ipip"); goto clear; @@ -233,7 +233,7 @@ clear: || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) { const NMPlatformLnkIp6Tnl *lnk; - lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL); + lnk = nm_platform_link_get_lnk_ip6tnl (nm_device_get_platform (device), ifindex, NULL); if (!lnk) { _LOGW (LOGD_PLATFORM, "could not read %s properties", "ip6tnl"); goto clear; @@ -332,7 +332,7 @@ complete_connection (NMDevice *device, { NMSettingIPTunnel *s_ip_tunnel; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_IP_TUNNEL_SETTING_NAME, existing_connections, @@ -641,7 +641,7 @@ create_and_realize (NMDevice *device, lnk_gre.output_flags = NM_GRE_KEY; } - plerr = nm_platform_link_gre_add (NM_PLATFORM_GET, iface, &lnk_gre, out_plink); + plerr = nm_platform_link_gre_add (nm_device_get_platform (device), iface, &lnk_gre, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create GRE interface '%s' for '%s': %s", @@ -667,7 +667,7 @@ create_and_realize (NMDevice *device, lnk_sit.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); - plerr = nm_platform_link_sit_add (NM_PLATFORM_GET, iface, &lnk_sit, out_plink); + plerr = nm_platform_link_sit_add (nm_device_get_platform (device), iface, &lnk_sit, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create SIT interface '%s' for '%s': %s", @@ -693,7 +693,7 @@ create_and_realize (NMDevice *device, lnk_ipip.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); - plerr = nm_platform_link_ipip_add (NM_PLATFORM_GET, iface, &lnk_ipip, out_plink); + plerr = nm_platform_link_ipip_add (nm_device_get_platform (device), iface, &lnk_ipip, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create IPIP interface '%s' for '%s': %s", @@ -722,7 +722,7 @@ create_and_realize (NMDevice *device, lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel); lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6; - plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink); + plerr = nm_platform_link_ip6tnl_add (nm_device_get_platform (device), iface, &lnk_ip6tnl, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create IPIP interface '%s' for '%s': %s", @@ -784,6 +784,33 @@ unrealize_notify (NMDevice *device) update_properties_from_ifindex (device, 0); } +static gboolean +can_reapply_change (NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + NMDeviceClass *device_class; + + /* Only handle ip-tunnel setting here, delegate other settings to parent class */ + if (nm_streq (setting_name, NM_SETTING_IP_TUNNEL_SETTING_NAME)) { + return nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_IP_TUNNEL_SETTING_NAME, + error, + NM_SETTING_IP_TUNNEL_MTU); /* reapplied with IP config */ + } + + device_class = NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class); + return device_class->can_reapply_change (device, + setting_name, + s_old, + s_new, + diffs, + error); +} + /*****************************************************************************/ static void @@ -866,16 +893,32 @@ constructed (GObject *object) } static void +dispose (GObject *object) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (object); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + + g_clear_pointer (&priv->local, g_free); + g_clear_pointer (&priv->remote, g_free); + g_clear_pointer (&priv->input_key, g_free); + g_clear_pointer (&priv->output_key, g_free); + + G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->dispose (object); +} + +static void nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; + object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; device_class->link_changed = link_changed; + device_class->can_reapply_change = can_reapply_change; device_class->complete_connection = complete_connection; device_class->update_connection = update_connection; device_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h index b7ec58fd..419a4a51 100644 --- a/src/devices/nm-device-logging.h +++ b/src/devices/nm-device-logging.h @@ -24,7 +24,8 @@ #include "nm-device.h" #define _LOG_DECLARE_SELF(t) \ -_nm_unused inline static NMDevice * \ +_nm_unused \ +static inline NMDevice * \ _nm_device_log_self_to_device (t *self) \ { \ return (NMDevice *) self; \ @@ -33,7 +34,9 @@ _nm_device_log_self_to_device (t *self) \ #undef _NMLOG_ENABLED #define _NMLOG_ENABLED(level, domain) ( nm_logging_enabled ((level), (domain)) ) #define _NMLOG(level, domain, ...) \ - nm_log_obj ((level), (domain), (self), "device", \ + nm_log_obj ((level), (domain), \ + (self) ? nm_device_get_iface (_nm_device_log_self_to_device (self)) : NULL, \ + NULL, (self), "device", \ "(%s): " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ (self) ? (nm_device_get_iface (_nm_device_log_self_to_device (self)) ?: "(null)") : "(none)" \ _NM_UTILS_MACRO_REST(__VA_ARGS__)) diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index c511a0e7..8add3f6f 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -45,7 +45,6 @@ typedef struct Supplicant { NMSupplicantInterface *iface; /* signal handler ids */ - gulong iface_error_id; gulong iface_state_id; /* Timeouts and idles */ @@ -90,8 +89,6 @@ G_DEFINE_TYPE (NMDeviceMacsec, nm_device_macsec, NM_TYPE_DEVICE) /******************************************************************/ -#define MACSEC_SECRETS_TRIES "macsec-secrets-tries" - static void macsec_secrets_cancel (NMDeviceMacsec *self); /******************************************************************/ @@ -113,7 +110,7 @@ parent_state_changed (NMDevice *parent, NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data); /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (reason == NM_DEVICE_STATE_REASON_CARRIER) + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER) return; nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason); @@ -176,7 +173,7 @@ update_properties (NMDevice *device) ifindex = nm_device_get_ifindex (device); g_return_if_fail (ifindex > 0); - props = nm_platform_link_get_lnk_macsec (NM_PLATFORM_GET, ifindex, &plink); + props = nm_platform_link_get_lnk_macsec (nm_device_get_platform (device), ifindex, &plink); if (!props) { _LOGW (LOGD_PLATFORM, "could not get macsec properties"); @@ -222,7 +219,7 @@ build_supplicant_config (NMDeviceMacsec *self, GError **error) connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_assert (connection); con_uuid = nm_connection_get_uuid (connection); - mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, + mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self))); config = nm_supplicant_config_new (); @@ -248,22 +245,12 @@ build_supplicant_config (NMDeviceMacsec *self, GError **error) } static void -supplicant_interface_clear_handlers (NMDeviceMacsec *self) +supplicant_interface_release (NMDeviceMacsec *self) { NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); nm_clear_g_source (&priv->supplicant_timeout_id); nm_clear_g_source (&priv->supplicant.con_timeout_id); - nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_error_id); -} - -static void -supplicant_interface_release (NMDeviceMacsec *self) -{ - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); - - supplicant_interface_clear_handlers (self); - nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id); if (priv->supplicant.iface) { @@ -273,21 +260,18 @@ supplicant_interface_release (NMDeviceMacsec *self) } static void -supplicant_iface_connection_error_cb (NMSupplicantInterface *iface, - const char *name, - const char *message, - gpointer user_data) +supplicant_iface_assoc_cb (NMSupplicantInterface *iface, + GError *error, + gpointer user_data) { NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data); - _LOGW (LOGD_DEVICE, - "Activation: association request to the supplicant failed: %s - %s", - name, message); - - supplicant_interface_release (self); - nm_device_queue_state (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); + if (error && !nm_utils_error_is_cancelled (error, TRUE)) { + supplicant_interface_release (self); + nm_device_queue_state (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); + } } static void @@ -412,8 +396,8 @@ time_out: static void supplicant_iface_state_cb (NMSupplicantInterface *iface, - guint32 new_state, - guint32 old_state, + int new_state_i, + int old_state_i, int disconnect_reason, gpointer user_data) { @@ -421,9 +405,10 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); NMSupplicantConfig *config; - gboolean success = FALSE; NMDeviceState devstate; GError *error = NULL; + NMSupplicantInterfaceState new_state = new_state_i; + NMSupplicantInterfaceState old_state = old_state_i; if (new_state == old_state) return; @@ -438,30 +423,23 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, case NM_SUPPLICANT_INTERFACE_STATE_READY: config = build_supplicant_config (self, &error); if (config) { - success = nm_supplicant_interface_set_config (priv->supplicant.iface, config, &error); + nm_supplicant_interface_assoc (priv->supplicant.iface, config, + supplicant_iface_assoc_cb, self); g_object_unref (config); - - if (!success) { - _LOGE (LOGD_DEVICE, - "Activation: couldn't send security configuration to the supplicant: %s", - error->message); - g_clear_error (&error); - } } else { _LOGE (LOGD_DEVICE, "Activation: couldn't build security configuration: %s", error->message); g_clear_error (&error); - } - if (!success) { nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); } break; case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - supplicant_interface_clear_handlers (self); + nm_clear_g_source (&priv->supplicant_timeout_id); + nm_clear_g_source (&priv->supplicant.con_timeout_id); nm_device_bring_up (device, TRUE, NULL); /* If this is the initial association during device activation, @@ -500,15 +478,20 @@ handle_auth_or_fail (NMDeviceMacsec *self, gboolean new_secrets) { const char *setting_name; - guint32 tries; + int tries_left; NMConnection *applied_connection; + NMSettingsConnection *settings_connection; applied_connection = nm_act_request_get_applied_connection (req); + settings_connection = nm_act_request_get_settings_connection (req); - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), MACSEC_SECRETS_TRIES)); - if (tries > 3) + tries_left = nm_settings_connection_get_autoconnect_retries (settings_connection); + if (tries_left == 0) return NM_ACT_STAGE_RETURN_FAILURE; + if (tries_left > 0) + nm_settings_connection_set_autoconnect_retries (settings_connection, tries_left - 1); + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (req)); @@ -518,7 +501,6 @@ handle_auth_or_fail (NMDeviceMacsec *self, macsec_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); - g_object_set_data (G_OBJECT (applied_connection), MACSEC_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); } else _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); @@ -571,6 +553,7 @@ supplicant_interface_init (NMDeviceMacsec *self) { NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); NMDevice *parent; + guint timeout; parent = nm_device_parent_get_device (NM_DEVICE (self)); g_return_val_if_fail (parent, FALSE); @@ -593,20 +576,16 @@ supplicant_interface_init (NMDeviceMacsec *self) G_CALLBACK (supplicant_iface_state_cb), self); - /* Hook up error signal handler to capture association errors */ - priv->supplicant.iface_error_id = g_signal_connect (priv->supplicant.iface, - NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR, - G_CALLBACK (supplicant_iface_connection_error_cb), - self); - - /* Set up a timeout on the connection attempt to fail it after 25 seconds */ - priv->supplicant.con_timeout_id = g_timeout_add_seconds (25, supplicant_connection_timeout_cb, self); - + /* Set up a timeout on the connection attempt */ + timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); + priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout, + supplicant_connection_timeout_cb, + self); return TRUE; } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceMacsec *self = NM_DEVICE_MACSEC (device); NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); @@ -615,7 +594,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) const char *setting_name; connection = nm_device_get_applied_connection (NM_DEVICE (self)); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); if (!priv->supplicant.mgr) priv->supplicant.mgr = g_object_ref (nm_supplicant_manager_get ()); @@ -631,7 +610,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) ret = handle_auth_or_fail (self, req, FALSE); if (ret != NM_ACT_STAGE_RETURN_POSTPONE) - *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); } else { _LOGI (LOGD_DEVICE | LOGD_ETHER, "Activation: connection '%s' requires no security. No secrets needed.", @@ -640,7 +619,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) if (supplicant_interface_init (self)) ret = NM_ACT_STAGE_RETURN_POSTPONE; else - *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); } return ret; @@ -735,7 +714,7 @@ create_and_realize (NMDevice *device, parent_ifindex = nm_device_get_ifindex (parent); g_warn_if_fail (parent_ifindex > 0); - plerr = nm_platform_link_macsec_add (NM_PLATFORM_GET, iface, parent_ifindex, &lnk, out_plink); + plerr = nm_platform_link_macsec_add (nm_device_get_platform (device), iface, parent_ifindex, &lnk, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create macsec interface '%s' for '%s': %s", @@ -758,17 +737,19 @@ link_changed (NMDevice *device, update_properties (device); } + static void -clear_secrets_tries (NMDevice *device) +reset_autoconnect_retries (NMDevice *device) { NMActRequest *req; - NMConnection *connection; + NMSettingsConnection *connection; req = nm_device_get_act_request (device); if (req) { - connection = nm_act_request_get_applied_connection (req); - /* Clear macsec secrets tries on success, failure, or when deactivating */ - g_object_set_data (G_OBJECT (connection), MACSEC_SECRETS_TRIES, NULL); + connection = nm_act_request_get_settings_connection (req); + g_return_if_fail (connection); + /* Reset autoconnect retries on success, failure, or when deactivating */ + nm_settings_connection_reset_autoconnect_retries (connection); } } @@ -784,7 +765,7 @@ device_state_changed (NMDevice *device, if ( new_state == NM_DEVICE_STATE_ACTIVATED || new_state == NM_DEVICE_STATE_FAILED || new_state == NM_DEVICE_STATE_DISCONNECTED) - clear_secrets_tries (device); + reset_autoconnect_retries (device); } /******************************************************************/ diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 94206716..cea2b984 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -131,7 +131,7 @@ parent_state_changed (NMDevice *parent, NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (user_data); /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (reason == NM_DEVICE_STATE_REASON_CARRIER) + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER) return; nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason); @@ -185,9 +185,9 @@ update_properties (NMDevice *device) const NMPlatformLink *plink; if (priv->props.tap) - props = nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); + props = nm_platform_link_get_lnk_macvtap (nm_device_get_platform (device), nm_device_get_ifindex (device), &plink); else - props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); + props = nm_platform_link_get_lnk_macvlan (nm_device_get_platform (device), nm_device_get_ifindex (device), &plink); if (!props) { _LOGW (LOGD_PLATFORM, "could not get %s properties", priv->props.tap ? "macvtap" : "macvlan"); @@ -251,7 +251,7 @@ create_and_realize (NMDevice *device, lnk.no_promisc = !nm_setting_macvlan_get_promiscuous (s_macvlan); lnk.tap = nm_setting_macvlan_get_tap (s_macvlan); - plerr = nm_platform_link_macvlan_add (NM_PLATFORM_GET, iface, parent_ifindex, &lnk, out_plink); + plerr = nm_platform_link_macvlan_add (nm_device_get_platform (device), iface, parent_ifindex, &lnk, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create %s interface '%s' for '%s': %s", @@ -399,7 +399,7 @@ complete_connection (NMDevice *device, { NMSettingMacvlan *s_macvlan; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_MACVLAN_SETTING_NAME, existing_connections, @@ -474,13 +474,11 @@ update_connection (NMDevice *device, NMConnection *connection) } static NMActStageReturn -act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->act_stage1_prepare (dev, reason); + ret = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->act_stage1_prepare (dev, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 2023feb5..a4067f9c 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -134,4 +134,9 @@ guint32 nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is NM_DEVICE_CLASS (klass)->link_types = link_types; \ } +gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, + GError **error, const char **argv); +#define nm_device_hash_check_invalid_keys(hash, setting_name, error, ...) \ + _nm_device_hash_check_invalid_keys (hash, setting_name, error, ((const char *[]) { __VA_ARGS__, NULL })) + #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index a937ae2d..b4af4416 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -80,7 +80,7 @@ update_properties (NMDeviceTun *self) ifindex = nm_device_get_ifindex (NM_DEVICE (self)); if (ifindex > 0) { - if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, ifindex, &props)) { + if (!nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)), ifindex, &props)) { _LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex); ifindex = 0; } else if (g_strcmp0 (priv->mode, props.mode) != 0) { @@ -138,7 +138,7 @@ complete_connection (NMDevice *device, { NMSettingTun *s_tun; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_TUN_SETTING_NAME, existing_connections, @@ -181,7 +181,7 @@ update_connection (NMDevice *device, NMConnection *connection) nm_connection_add_setting (connection, (NMSetting *) s_tun); } - if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { + if (!nm_platform_link_tun_get_properties (nm_device_get_platform (device), nm_device_get_ifindex (device), &props)) { _LOGW (LOGD_PLATFORM, "failed to get TUN interface info while updating connection."); return; } @@ -232,7 +232,7 @@ create_and_realize (NMDevice *device, user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); - plerr = nm_platform_link_tun_add (NM_PLATFORM_GET, iface, + plerr = nm_platform_link_tun_add (nm_device_get_platform (device), iface, nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP, user, group, nm_setting_tun_get_pi (s_tun), @@ -291,15 +291,13 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) } static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMActStageReturn ret; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_tun_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_tun_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 1971aeeb..11916c59 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -69,7 +69,7 @@ update_properties (NMDevice *device) ifindex = nm_device_get_ifindex (device); - if (!nm_platform_link_veth_get_properties (NM_PLATFORM_GET, ifindex, &peer_ifindex)) + if (!nm_platform_link_veth_get_properties (nm_device_get_platform (device), ifindex, &peer_ifindex)) peer_ifindex = 0; nm_device_parent_set_ifindex (device, peer_ifindex); diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 45d7cf67..06db6446 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -79,7 +79,7 @@ parent_state_changed (NMDevice *parent, 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) + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER) return; nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason); @@ -90,13 +90,14 @@ parent_hwaddr_maybe_changed (NMDevice *parent, GParamSpec *pspec, gpointer user_data) { - NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); + NMDevice *device = NM_DEVICE (user_data); + NMDeviceVlan *self = NM_DEVICE_VLAN (device); NMConnection *connection; const char *new_mac, *old_mac; NMSettingIPConfig *s_ip6; /* Never touch assumed devices */ - if (nm_device_uses_assumed_connection ((NMDevice *) self)) + if (nm_device_sys_iface_state_is_external_or_assume (device)) return; connection = nm_device_get_applied_connection ((NMDevice *) self); @@ -121,7 +122,7 @@ parent_hwaddr_maybe_changed (NMDevice *parent, */ s_ip6 = nm_connection_get_setting_ip6_config (connection); if (s_ip6) - nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6); + nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6, FALSE); } } @@ -185,7 +186,7 @@ update_properties (NMDevice *device) ifindex = nm_device_get_ifindex (device); if (ifindex > 0) - plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, &plink); + plnk = nm_platform_link_get_lnk_vlan (nm_device_get_platform (device), ifindex, &plink); if ( plnk && plink->parent > 0) @@ -248,7 +249,7 @@ create_and_realize (NMDevice *device, vlan_id = nm_setting_vlan_get_id (s_vlan); - plerr = nm_platform_link_vlan_add (NM_PLATFORM_GET, + plerr = nm_platform_link_vlan_add (nm_device_get_platform (device), iface, parent_ifindex, vlan_id, @@ -424,7 +425,7 @@ complete_connection (NMDevice *device, { NMSettingVlan *s_vlan; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_VLAN_SETTING_NAME, existing_connections, @@ -471,7 +472,7 @@ update_connection (NMDevice *device, NMConnection *connection) nm_connection_add_setting (connection, (NMSetting *) s_vlan); } - polnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink); + polnk = nm_platform_link_get_lnk (nm_device_get_platform (device), ifindex, NM_LINK_TYPE_VLAN, &plink); if (polnk) vlan_id = polnk->lnk_vlan.id; @@ -522,15 +523,13 @@ update_connection (NMDevice *device, NMConnection *connection) } static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDevice *parent_device; NMSettingVlan *s_vlan; NMActStageReturn ret; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_vlan_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_vlan_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; @@ -557,7 +556,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) &egress_map, &n_egress_map); - nm_platform_link_vlan_change (NM_PLATFORM_GET, + nm_platform_link_vlan_change (nm_device_get_platform (device), nm_device_get_ifindex (device), NM_VLAN_FLAGS_ALL, nm_setting_vlan_get_flags (s_vlan), @@ -585,7 +584,7 @@ get_configured_mtu (NMDevice *self, gboolean *out_is_user_config) /* Inherit the MTU from parent device, if any */ ifindex = nm_device_parent_get_ifindex (self); if (ifindex > 0) - mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex); + mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), ifindex); return mtu ?: NM_DEVICE_DEFAULT_MTU_WIRED; } diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index b4508133..d0b88874 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -87,7 +87,7 @@ update_properties (NMDevice *device) GObject *object = G_OBJECT (device); const NMPlatformLnkVxlan *props; - props = nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); + props = nm_platform_link_get_lnk_vxlan (nm_device_get_platform (device), nm_device_get_ifindex (device), NULL); if (!props) { _LOGW (LOGD_PLATFORM, "could not get vxlan properties"); return; @@ -217,7 +217,7 @@ create_and_realize (NMDevice *device, props.l2miss = nm_setting_vxlan_get_l2_miss (s_vxlan); props.l3miss = nm_setting_vxlan_get_l3_miss (s_vxlan); - plerr = nm_platform_link_vxlan_add (NM_PLATFORM_GET, iface, &props, out_plink); + plerr = nm_platform_link_vxlan_add (nm_device_get_platform (device), iface, &props, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create VXLAN interface '%s' for '%s': %s", @@ -361,7 +361,7 @@ complete_connection (NMDevice *device, { NMSettingVxlan *s_vxlan; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_VXLAN_SETTING_NAME, existing_connections, @@ -496,13 +496,11 @@ update_connection (NMDevice *device, NMConnection *connection) } static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 2a2d276d..da581a0d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2013 Red Hat, Inc. + * Copyright (C) 2005 - 2017 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -56,6 +56,7 @@ #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" #include "nm-auth-utils.h" +#include "nm-netns.h" #include "nm-dispatcher.h" #include "nm-config.h" #include "dns/nm-dns-manager.h" @@ -66,6 +67,8 @@ #include "nm-lldp-listener.h" #include "nm-audit-manager.h" #include "nm-arping-manager.h" +#include "nm-connectivity.h" +#include "nm-dbus-interface.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDevice); @@ -130,6 +133,13 @@ typedef enum { HW_ADDR_TYPE_GENERATED, } HwAddrType; +typedef enum { + FIREWALL_STATE_UNMANAGED = 0, + FIREWALL_STATE_INITIALIZED, + FIREWALL_STATE_WAIT_STAGE_3, + FIREWALL_STATE_WAIT_IP_CONFIG, +} FirewallState; + /*****************************************************************************/ enum { @@ -189,6 +199,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice, PROP_REFRESH_RATE_MS, PROP_TX_BYTES, PROP_RX_BYTES, + PROP_CONNECTIVITY, ); typedef struct _NMDevicePrivate { @@ -206,6 +217,7 @@ typedef struct _NMDevicePrivate { NMDeviceState state; NMDeviceStateReason reason; } queued_state; + guint queued_ip4_config_id; guint queued_ip6_config_id; GSList *pending_actions; @@ -250,6 +262,8 @@ typedef struct _NMDevicePrivate { NMUtilsStableType current_stable_id_type:3; + bool is_nm_owned:1; /* whether the device is a device owned and created by NM */ + GHashTable * available_connections; char * hw_addr; char * hw_addr_perm; @@ -259,7 +273,6 @@ typedef struct _NMDevicePrivate { NMUnmanagedFlags unmanaged_mask; NMUnmanagedFlags unmanaged_flags; - bool is_nm_owned; /* whether the device is a device owned and created by NM */ DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */ GCancellable *deactivating_cancellable; @@ -289,19 +302,25 @@ typedef struct _NMDevicePrivate { guint link_connected_id; guint link_disconnected_id; guint carrier_defer_id; - bool carrier; guint carrier_wait_id; - bool ignore_carrier; - gulong ignore_carrier_id; + gulong config_changed_id; guint32 mtu; guint32 ip6_mtu; guint32 mtu_initial; guint32 ip6_mtu_initial; + bool carrier:1; + bool ignore_carrier:1; + bool mtu_initialized:1; bool up:1; /* IFF_UP */ + bool v4_commit_first_time:1; + bool v6_commit_first_time:1; + + NMDeviceSysIfaceState sys_iface_state:2; + /* Generic DHCP stuff */ guint32 dhcp_timeout; char * dhcp_anycast_address; @@ -311,6 +330,7 @@ typedef struct _NMDevicePrivate { /* Proxy Configuration */ NMProxyConfig *proxy_config; NMPacrunnerManager *pacrunner_manager; + NMPacrunnerCallId *pacrunner_call_id; /* IP4 configuration info */ NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ @@ -331,9 +351,8 @@ typedef struct _NMDevicePrivate { NMPlatformIP4Route v4; NMPlatformIP6Route v6; } default_route; - - bool v4_commit_first_time; - bool v6_commit_first_time; + bool v4_has_shadowed_routes; + const char *ip4_rp_filter; /* DHCPv4 tracking */ struct { @@ -342,6 +361,8 @@ typedef struct _NMDevicePrivate { NMDhcp4Config * config; guint restart_id; guint num_tries_left; + char * pac_url; + bool was_active; } dhcp4; struct { @@ -359,7 +380,8 @@ typedef struct _NMDevicePrivate { gulong dnsmasq_state_id; /* Firewall */ - bool fw_ready; + FirewallState fw_state:4; + NMFirewallManager *fw_mgr; NMFirewallManagerCallId fw_call; /* IPv4LL stuff */ @@ -411,12 +433,14 @@ typedef struct _NMDevicePrivate { guint restart_id; guint num_tries_left; guint needed_prefixes; + bool was_active; } dhcp6; gboolean needs_ip6_subnet; /* allow autoconnect feature */ - bool autoconnect; + bool autoconnect_intern:1; + bool autoconnect_user:1; /* master interface for bridge/bond/team slave */ NMDevice * master; @@ -432,7 +456,12 @@ typedef struct _NMDevicePrivate { NMSettings *settings; + NMNetns *netns; + NMLldpListener *lldp_listener; + NMConnectivityState connectivity_state; + guint concheck_periodic_id; + guint64 concheck_seq; guint check_delete_unrealized_id; @@ -451,29 +480,25 @@ G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT) /*****************************************************************************/ -static void nm_device_set_proxy_config (NMDevice *self, GHashTable *options); +static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url); static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, guint32 default_route_metric, gboolean commit, - gboolean routes_full_sync, - NMDeviceStateReason *reason); + gboolean routes_full_sync); static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, - gboolean commit, - NMDeviceStateReason *out_reason); + gboolean commit); static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *config, gboolean commit, - gboolean routes_full_sync, - NMDeviceStateReason *reason); + gboolean routes_full_sync); static gboolean ip6_config_merge_and_apply (NMDevice *self, - gboolean commit, - NMDeviceStateReason *out_reason); + gboolean commit); -static void nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); +static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success); static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason); @@ -482,6 +507,9 @@ static NMActStageReturn linklocal6_start (NMDevice *self); static void _carrier_wait_check_queued_act_request (NMDevice *self); +static void nm_device_set_autoconnect_both (NMDevice *self, gboolean autoconnect); +static void nm_device_set_autoconnect_full (NMDevice *self, int autoconnect_intern, int autoconnect_user); + static const char *_activation_func_to_string (ActivationHandleFunc func); static void activation_source_handle_cb (NMDevice *self, int family); @@ -494,10 +522,12 @@ static gboolean queued_ip4_config_change (gpointer user_data); static gboolean queued_ip6_config_change (gpointer user_data); static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data); static gboolean ip_config_valid (NMDeviceState state); -static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, NMDeviceStateReason *reason); -static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason); +static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection); +static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll); static void nm_device_start_ip_check (NMDevice *self); -static void realize_start_setup (NMDevice *self, const NMPlatformLink *plink); +static void realize_start_setup (NMDevice *self, + const NMPlatformLink *plink, + NMUnmanFlagOp unmanaged_user_explicit); static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void dhcp_schedule_restart (NMDevice *self, int family, const char *reason); static void _cancel_activation (NMDevice *self); @@ -605,6 +635,81 @@ nm_device_get_settings (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->settings; } +NMNetns * +nm_device_get_netns (NMDevice *self) +{ + return NM_DEVICE_GET_PRIVATE (self)->netns; +} + +NMPlatform * +nm_device_get_platform (NMDevice *self) +{ + return nm_netns_get_platform (nm_device_get_netns (self)); +} + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_sys_iface_state_to_str, NMDeviceSysIfaceState, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, "external"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_ASSUME, "assume"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_MANAGED, "managed"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_REMOVED, "removed"), +); + +NMDeviceSysIfaceState +nm_device_sys_iface_state_get (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); + + return NM_DEVICE_GET_PRIVATE (self)->sys_iface_state; +} + +gboolean +nm_device_sys_iface_state_is_external (NMDevice *self) +{ + return NM_IN_SET (nm_device_sys_iface_state_get (self), + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); +} + +gboolean +nm_device_sys_iface_state_is_external_or_assume (NMDevice *self) +{ + return NM_IN_SET (nm_device_sys_iface_state_get (self), + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME); +} + +void +nm_device_sys_iface_state_set (NMDevice *self, + NMDeviceSysIfaceState sys_iface_state) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IN_SET (sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME, + NM_DEVICE_SYS_IFACE_STATE_MANAGED, + NM_DEVICE_SYS_IFACE_STATE_REMOVED)); + + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->sys_iface_state != sys_iface_state) { + _LOGT (LOGD_DEVICE, "sys-iface-state: %s -> %s", + _sys_iface_state_to_str (priv->sys_iface_state), + _sys_iface_state_to_str (sys_iface_state)); + priv->sys_iface_state = sys_iface_state; + } + + /* this function only sets a flag, no immediate actions are initiated. + * + * If you change this, make sure that all callers are fine with such actions. */ + + nm_assert (priv->sys_iface_state == sys_iface_state); +} + +/*****************************************************************************/ + static void init_ip4_config_dns_priority (NMDevice *self, NMIP4Config *config) { @@ -633,16 +738,48 @@ init_ip6_config_dns_priority (NMDevice *self, NMIP6Config *config) /*****************************************************************************/ +static gboolean +nm_device_ipv4_sysctl_set (NMDevice *self, const char *property, const char *value) +{ + NMPlatform *platform = nm_device_get_platform (self); + gs_free char *value_to_free = NULL; + const char *value_to_set; + + if (value) { + value_to_set = value; + } else { + /* Set to a default value when we've got a NULL @value. */ + value_to_free = nm_platform_sysctl_get (platform, + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path ("default", property))); + value_to_set = value_to_free; + } + + return nm_platform_sysctl_set (platform, + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (nm_device_get_ip_iface (self), property)), + value_to_set); +} + +static guint32 +nm_device_ipv4_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback) +{ + return nm_platform_sysctl_get_int_checked (nm_device_get_platform (self), + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (nm_device_get_ip_iface (self), property)), + 10, + 0, + G_MAXUINT32, + fallback); +} + gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value) { - return nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), value); + return nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), value); } static guint32 nm_device_ipv6_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback) { - return nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, + return nm_platform_sysctl_get_int_checked (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), 10, 0, @@ -872,7 +1009,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) if (nm_streq0 (iface, priv->ip_iface)) { if (!iface) return FALSE; - ifindex = nm_platform_if_nametoindex (NM_PLATFORM_GET, iface); + ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface); if ( ifindex <= 0 || priv->ip_ifindex == ifindex) return FALSE; @@ -890,7 +1027,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) * with this name still exists and we resolve the ifindex * anew. */ - priv->ip_ifindex = nm_platform_if_nametoindex (NM_PLATFORM_GET, iface); + priv->ip_ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface); if (priv->ip_ifindex > 0) _LOGD (LOGD_DEVICE, "ip-ifname: set ifname '%s', ifindex %d", iface, priv->ip_ifindex); else @@ -902,11 +1039,11 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) } if (priv->ip_ifindex > 0) { - 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_check_support_user_ipv6ll (nm_device_get_platform (self))) + nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ip_ifindex, TRUE); - if (!nm_platform_link_is_up (NM_PLATFORM_GET, priv->ip_ifindex)) - nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL); + if (!nm_platform_link_is_up (nm_device_get_platform (self), priv->ip_ifindex)) + nm_platform_link_set_up (nm_device_get_platform (self), priv->ip_ifindex, NULL); } /* We don't care about any saved values from the old iface */ @@ -1108,7 +1245,7 @@ _stats_timeout_cb (gpointer user_data) _LOGT (LOGD_DEVICE, "stats: refresh %d", ifindex); if (ifindex > 0) - nm_platform_link_refresh (NM_PLATFORM_GET, ifindex); + nm_platform_link_refresh (nm_device_get_platform (self), ifindex); return G_SOURCE_CONTINUE; } @@ -1165,7 +1302,7 @@ _stats_set_refresh_rate (NMDevice *self, guint refresh_rate_ms) * we don't get the result right away. */ ifindex = nm_device_get_ip_ifindex (self); if (ifindex > 0) - nm_platform_link_refresh (NM_PLATFORM_GET, ifindex); + nm_platform_link_refresh (nm_device_get_platform (self), ifindex); priv->stats.timeout_id = g_timeout_add (refresh_rate_ms, _stats_timeout_cb, self); } @@ -1184,7 +1321,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) ifindex = nm_device_get_ip_ifindex (self); g_return_val_if_fail (ifindex > 0, FALSE); - pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); + pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); if ( !pllink || NM_IN_SET (pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) return FALSE; @@ -1231,7 +1368,7 @@ nm_device_get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *iid, gboo if (!ignore_token) { s_ip6 = (NMSettingIP6Config *) - nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); + nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); g_return_val_if_fail (s_ip6, FALSE); token = nm_setting_ip6_config_get_token (s_ip6); } @@ -1345,6 +1482,8 @@ nm_device_get_priority (NMDevice *self) return 450; case NM_DEVICE_TYPE_VXLAN: return 500; + case NM_DEVICE_TYPE_DUMMY: + return 550; case NM_DEVICE_TYPE_WIFI: return 600; case NM_DEVICE_TYPE_OLPC_MESH: @@ -1368,6 +1507,26 @@ nm_device_get_priority (NMDevice *self) } static guint32 +route_metric_with_penalty (NMDevice *self, guint32 metric) +{ +#if WITH_CONCHECK + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + const guint32 PENALTY = 20000; + + /* Beware: for IPv6, a metric of 0 effectively means 1024. + * Only pass a normalized IPv6 metric (nm_utils_ip6_route_metric_normalize). */ + + if ( priv->connectivity_state != NM_CONNECTIVITY_FULL + && nm_connectivity_check_enabled (nm_connectivity_get ())) { + if (metric >= G_MAXUINT32 - PENALTY) + return G_MAXUINT32; + return metric + PENALTY; + } +#endif + return metric; +} + +static guint32 _get_ipx_route_metric (NMDevice *self, gboolean is_v4) { @@ -1449,9 +1608,9 @@ _update_default_route (NMDevice *self, int addr_family, gboolean has, gboolean i *p_is_assumed = is_assumed; if (addr_family == AF_INET) - nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self); + nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); else - nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self); + nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); } const NMPlatformIP4Route * @@ -1529,7 +1688,7 @@ nm_device_has_carrier (NMDevice *self) NMActRequest * nm_device_get_act_request (NMDevice *self) { - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); return NM_DEVICE_GET_PRIVATE (self)->act_request; } @@ -1590,33 +1749,174 @@ nm_device_get_physical_port_id (NMDevice *self) /*****************************************************************************/ +static void +update_connectivity_state (NMDevice *self, NMConnectivityState state) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* If the connectivity check is disabled, make an optimistic guess. */ + if (state == NM_CONNECTIVITY_UNKNOWN) { + if (priv->state == NM_DEVICE_STATE_ACTIVATED) { + if (priv->default_route.v4_has || priv->default_route.v6_has) + state = NM_CONNECTIVITY_FULL; + else + state = NM_CONNECTIVITY_LIMITED; + } else { + state = NM_CONNECTIVITY_NONE; + } + } + + if (priv->connectivity_state != state) { +#if WITH_CONCHECK + _LOGD (LOGD_CONCHECK, "state changed from %s to %s", + nm_connectivity_state_to_string (priv->connectivity_state), + nm_connectivity_state_to_string (state)); +#endif + priv->connectivity_state = state; + _notify (self, PROP_CONNECTIVITY); + + if (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED) { + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) + _LOGW (LOGD_IP4, "Failed to update IPv4 default route metric"); + if (!ip6_config_merge_and_apply (self, TRUE)) + _LOGW (LOGD_IP6, "Failed to update IPv6 default route metric"); + } + } +} + +typedef struct { + NMDevice *self; + NMDeviceConnectivityCallback callback; + gpointer user_data; + guint64 seq; +} ConnectivityCheckData; + +static void +concheck_done (ConnectivityCheckData *data) +{ + NMDevice *self = data->self; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* The unsolicited connectivity checks don't hook a callback. */ + if (data->callback) + data->callback (data->self, priv->connectivity_state, data->user_data); + g_object_unref (data->self); + g_slice_free (ConnectivityCheckData, data); +} + +#if WITH_CONCHECK +static void +concheck_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) +{ + ConnectivityCheckData *data = user_data; + NMDevice *self = data->self; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnectivity *connectivity = NM_CONNECTIVITY (source_object); + NMConnectivityState state; + GError *error = NULL; + + state = nm_connectivity_check_finish (connectivity, result, &error); + if (error) { + _LOGW (LOGD_DEVICE, "connectivity checking on '%s' failed: %s", + nm_device_get_iface (self), error->message); + g_error_free (error); + } + + if (data->seq == priv->concheck_seq) + update_connectivity_state (data->self, state); + concheck_done (data); +} +#endif /* WITH_CONCHECK */ + static gboolean -nm_device_uses_generated_assumed_connection (NMDevice *self) +no_concheck (gpointer user_data) { + ConnectivityCheckData *data = user_data; + + concheck_done (data); + return G_SOURCE_REMOVE; +} + +void +nm_device_check_connectivity (NMDevice *self, + NMDeviceConnectivityCallback callback, + gpointer user_data) +{ + ConnectivityCheckData *data; +#if WITH_CONCHECK NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingsConnection *connection; +#endif - if ( priv->act_request - && nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (priv->act_request))) { - connection = nm_act_request_get_settings_connection (priv->act_request); - if ( connection - && nm_settings_connection_get_nm_generated_assumed (connection)) - return TRUE; + data = g_slice_new0 (ConnectivityCheckData); + data->self = g_object_ref (self); + data->callback = callback; + data->user_data = user_data; + +#if WITH_CONCHECK + if (priv->concheck_periodic_id) { + data->seq = ++priv->concheck_seq; + + /* Kick off a real connectivity check. */ + nm_connectivity_check_async (nm_connectivity_get (), + nm_device_get_iface (self), + concheck_cb, + data); + return; } - return FALSE; +#endif + + /* Fake one. */ + g_idle_add (no_concheck, data); } -gboolean -nm_device_uses_assumed_connection (NMDevice *self) +NMConnectivityState +nm_device_get_connectivity_state (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NM_CONNECTIVITY_UNKNOWN); + + return NM_DEVICE_GET_PRIVATE (self)->connectivity_state; +} + +#if WITH_CONCHECK +static void +concheck_periodic (NMConnectivity *connectivity, NMDevice *self) +{ + nm_device_check_connectivity (self, NULL, NULL); +} +#endif + +static void +concheck_periodic_update (NMDevice *self) { +#if WITH_CONCHECK NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean check_enable; - if ( priv->act_request - && nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (priv->act_request))) - return TRUE; - return FALSE; + check_enable = (priv->state == NM_DEVICE_STATE_ACTIVATED) + && (priv->default_route.v4_has || priv->default_route.v6_has); + + if (check_enable && !priv->concheck_periodic_id) { + /* We just gained a default route. Enable periodic checking. */ + priv->concheck_periodic_id = g_signal_connect (nm_connectivity_get (), + NM_CONNECTIVITY_PERIODIC_CHECK, + G_CALLBACK (concheck_periodic), self); + /* Also kick off a check right away. */ + nm_device_check_connectivity (self, NULL, NULL); + } else if (!check_enable && priv->concheck_periodic_id) { + /* The default route has gone off, and so has connectivity. */ + g_signal_handler_disconnect (nm_connectivity_get (), priv->concheck_periodic_id); + priv->concheck_periodic_id = 0; + update_connectivity_state (self, NM_CONNECTIVITY_NONE); + } +#else + /* update_connectivity_state() figures out how to lie about + * connectivity state if the actual state is not really known. */ + update_connectivity_state (self, NM_CONNECTIVITY_UNKNOWN); +#endif } +/*****************************************************************************/ + static SlaveInfo * find_slave_info (NMDevice *self, NMDevice *slave) { @@ -1722,7 +2022,7 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co info = find_slave_info (self, slave); - _LOGt (LOGD_CORE, "master: release one slave %p/%s%s", slave, nm_device_get_iface (slave), + _LOGT (LOGD_CORE, "master: release one slave %p/%s%s", slave, nm_device_get_iface (slave), !info ? " (not registered)" : ""); if (!info) @@ -1785,7 +2085,7 @@ is_unmanaged_external_down (NMDevice *self, gboolean consider_can) /* Manage externally-created software interfaces only when they are IFF_UP */ if ( priv->ifindex <= 0 || !priv->up - || !(priv->slaves || nm_platform_link_can_assume (NM_PLATFORM_GET, priv->ifindex))) + || !(priv->slaves || nm_platform_link_can_assume (nm_device_get_platform (self), priv->ifindex))) return NM_UNMAN_FLAG_OP_SET_UNMANAGED; return NM_UNMAN_FLAG_OP_SET_MANAGED; @@ -1857,7 +2157,7 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) if (priv->lldp_listener && nm_lldp_listener_is_running (priv->lldp_listener)) { nm_lldp_listener_stop (priv->lldp_listener); - addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length); + addr = nm_platform_link_get_address (nm_device_get_platform (self), priv->ifindex, &addr_length); if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) { _LOGD (LOGD_DEVICE, "LLDP listener %p could not be restarted: %s", @@ -2029,7 +2329,7 @@ device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) } else { _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", plink->master, - nm_platform_link_get_name (NM_PLATFORM_GET, plink->master)); + nm_platform_link_get_name (nm_device_get_platform (self), plink->master)); } } } @@ -2120,13 +2420,13 @@ device_link_changed (NMDevice *self) priv->device_link_changed_id = 0; ifindex = nm_device_get_ifindex (self); - pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); + pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); if (!pllink) return G_SOURCE_REMOVE; info = *pllink; - udi = nm_platform_link_get_udi (NM_PLATFORM_GET, info.ifindex); + udi = nm_platform_link_get_udi (nm_device_get_platform (self), info.ifindex); if (udi && g_strcmp0 (udi, priv->udi)) { /* Update UDI to what udev gives us */ g_free (priv->udi); @@ -2234,11 +2534,11 @@ device_link_changed (NMDevice *self) /* the link was down and just came up. That happens for example, while changing MTU. * We must restore IP configuration. */ if (priv->ip4_state == IP_DONE) { - if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL)) + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again"); } if (priv->ip6_state == IP_DONE) { - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again"); } } @@ -2274,7 +2574,7 @@ device_ip_link_changed (NMDevice *self) if (!priv->ip_ifindex) return G_SOURCE_REMOVE; - pllink = nm_platform_link_get (NM_PLATFORM_GET, priv->ip_ifindex); + pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ip_ifindex); if (!pllink) return G_SOURCE_REMOVE; @@ -2316,6 +2616,45 @@ link_changed_cb (NMPlatform *platform, } static void +ip4_rp_filter_update (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + const char *ip4_rp_filter; + + if ( priv->v4_has_shadowed_routes + || priv->default_route.v4_has) { + if (nm_device_ipv4_sysctl_get_uint32 (self, "rp_filter", 0) != 1) { + /* Don't touch the rp_filter if it's not strict. */ + return; + } + /* Loose rp_filter */ + ip4_rp_filter = "2"; + } else { + /* Default rp_filter */ + ip4_rp_filter = NULL; + } + + if (ip4_rp_filter != priv->ip4_rp_filter) { + nm_device_ipv4_sysctl_set (self, "rp_filter", ip4_rp_filter); + priv->ip4_rp_filter = ip4_rp_filter; + } +} + +static void +ip4_routes_changed_changed_cb (NMRouteManager *route_manager, NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ifindex = nm_device_get_ip_ifindex (self); + + if (nm_device_sys_iface_state_is_external_or_assume (self)) + return; + + priv->v4_has_shadowed_routes = nm_route_manager_ip4_routes_shadowed (route_manager, + ifindex); + ip4_rp_filter_update (self); +} + +static void link_changed (NMDevice *self, const NMPlatformLink *pllink) { /* stub implementation of virtual function to allow subclasses to chain up. */ @@ -2368,6 +2707,8 @@ link_type_compatible (NMDevice *self, * nm_device_realize_start(): * @self: the #NMDevice * @plink: an existing platform link or %NULL + * @unmanaged_user_explicit: the user-explicit unmanaged flag to apply + * on the device initially. * @out_compatible: %TRUE on return if @self is compatible with @plink * @error: location to store error, or %NULL * @@ -2383,6 +2724,7 @@ link_type_compatible (NMDevice *self, gboolean nm_device_realize_start (NMDevice *self, const NMPlatformLink *plink, + NMUnmanFlagOp unmanaged_user_explicit, gboolean *out_compatible, GError **error) { @@ -2406,7 +2748,7 @@ nm_device_realize_start (NMDevice *self, plink_copy = *plink; plink = &plink_copy; } - realize_start_setup (self, plink); + realize_start_setup (self, plink, unmanaged_user_explicit); return TRUE; } @@ -2434,7 +2776,7 @@ nm_device_create_and_realize (NMDevice *self, const NMPlatformLink *plink = NULL; /* Must be set before device is realized */ - priv->is_nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface); + priv->is_nm_owned = !nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); _LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->is_nm_owned ? "" : "not "); @@ -2446,7 +2788,7 @@ nm_device_create_and_realize (NMDevice *self, plink = &plink_copy; } - realize_start_setup (self, plink); + realize_start_setup (self, plink, NM_UNMAN_FLAG_OP_FORGET); nm_device_realize_finish (self, plink); if (nm_device_get_managed (self, FALSE)) { @@ -2465,7 +2807,7 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) g_return_if_fail (plink != NULL); - udi = nm_platform_link_get_udi (NM_PLATFORM_GET, plink->ifindex); + udi = nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex); if (udi && !g_strcmp0 (udi, priv->udi)) { g_free (priv->udi); priv->udi = g_strdup (udi); @@ -2492,17 +2834,41 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) } static void -config_changed_update_ignore_carrier (NMConfig *config, - NMConfigData *config_data, - NMConfigChangeFlags changes, - NMConfigData *old_data, - NMDevice *self) +device_init_sriov_num_vfs (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gs_free char *value = NULL; + int num_vfs; + + if ( priv->ifindex > 0 + && nm_device_has_capability (self, NM_DEVICE_CAP_SRIOV)) { + value = nm_config_data_get_device_config (NM_CONFIG_GET_DATA, + "sriov-num-vfs", + self, + NULL); + num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1); + if (num_vfs >= 0) { + nm_platform_link_set_sriov_num_vfs (nm_device_get_platform (self), + priv->ifindex, num_vfs); + } + } +} + +static void +config_changed (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); + + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) + device_init_sriov_num_vfs (self); } static void @@ -2511,7 +2877,7 @@ 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_set_carrier (self, nm_platform_link_is_connected (nm_device_get_platform (self), ifindex)); } static void @@ -2527,6 +2893,7 @@ realize_start_notify (NMDevice *self, * realize_start_setup(): * @self: the #NMDevice * @plink: the #NMPlatformLink if backed by a kernel netdevice + * @unmanaged_user_explicit: the user-explict unmanaged flag to set. * * Update the device from backing resource properties (like hardware * addresses, carrier states, driver/firmware info, etc). This function @@ -2535,7 +2902,9 @@ realize_start_notify (NMDevice *self, * stuff). */ static void -realize_start_setup (NMDevice *self, const NMPlatformLink *plink) +realize_start_setup (NMDevice *self, + const NMPlatformLink *plink, + NMUnmanFlagOp unmanaged_user_explicit) { NMDevicePrivate *priv; NMDeviceClass *klass; @@ -2573,6 +2942,8 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) _notify (self, PROP_MTU); } + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); + if (plink) { g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL)); update_device_from_platform_link (self, plink); @@ -2580,21 +2951,21 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) } if (priv->ifindex > 0) { - priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex); + priv->physical_port_id = nm_platform_link_get_physical_port_id (nm_device_get_platform (self), priv->ifindex); _notify (self, PROP_PHYSICAL_PORT_ID); - priv->dev_id = nm_platform_link_get_dev_id (NM_PLATFORM_GET, priv->ifindex); + priv->dev_id = nm_platform_link_get_dev_id (nm_device_get_platform (self), priv->ifindex); - if (nm_platform_link_is_software (NM_PLATFORM_GET, priv->ifindex)) + if (nm_platform_link_is_software (nm_device_get_platform (self), priv->ifindex)) capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; - mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex); + mtu = nm_platform_link_get_mtu (nm_device_get_platform (self), priv->ifindex); if (priv->mtu != mtu) { priv->mtu = mtu; _notify (self, PROP_MTU); } - nm_platform_link_get_driver_info (NM_PLATFORM_GET, + nm_platform_link_get_driver_info (nm_device_get_platform (self), priv->ifindex, NULL, &priv->driver_version, @@ -2604,8 +2975,11 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) if (priv->firmware_version) _notify (self, PROP_FIRMWARE_VERSION); - if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) - priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ifindex); + if (nm_platform_check_support_user_ipv6ll (nm_device_get_platform (self))) + priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ifindex); + + if (nm_platform_link_supports_sriov (nm_device_get_platform (self), priv->ifindex)) + capabilities |= NM_DEVICE_CAP_SRIOV; } if (klass->get_generic_capabilities) @@ -2629,10 +3003,10 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) /* Note: initial hardware address must be read before calling get_ignore_carrier() */ config = nm_config_get (); priv->ignore_carrier = nm_config_data_get_ignore_carrier (nm_config_get_data (config), self); - if (!priv->ignore_carrier_id) { - priv->ignore_carrier_id = g_signal_connect (config, + if (!priv->config_changed_id) { + priv->config_changed_id = g_signal_connect (config, NM_CONFIG_SIGNAL_CONFIG_CHANGED, - G_CALLBACK (config_changed_update_ignore_carrier), + G_CALLBACK (config_changed), self); } @@ -2647,13 +3021,22 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) priv->carrier = TRUE; } + device_init_sriov_num_vfs (self); + nm_assert (!priv->stats.timeout_id); real_rate = _stats_refresh_rate_real (priv->stats.refresh_rate_ms); if (real_rate) priv->stats.timeout_id = g_timeout_add (real_rate, _stats_timeout_cb, self); + nm_device_set_autoconnect_full (self, !!DEFAULT_AUTOCONNECT, TRUE); + klass->realize_start_notify (self, plink); + nm_assert (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_USER_EXPLICIT)); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_USER_EXPLICIT, + unmanaged_user_explicit); + /* Do not manage externally created software devices until they are IFF_UP * or have IP addressing */ nm_device_set_unmanaged_flags (self, @@ -2787,7 +3170,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) if (!NM_DEVICE_GET_CLASS (self)->unrealize (self, error)) return FALSE; } else if (ifindex > 0) { - nm_platform_link_delete (NM_PLATFORM_GET, ifindex); + nm_platform_link_delete (nm_device_get_platform (self), ifindex); } } @@ -2841,12 +3224,12 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); _notify (self, PROP_CAPABILITIES); - nm_clear_g_signal_handler (nm_config_get (), &priv->ignore_carrier_id); + nm_clear_g_signal_handler (nm_config_get (), &priv->config_changed_id); priv->real = FALSE; _notify (self, PROP_REAL); - nm_device_set_autoconnect (self, DEFAULT_AUTOCONNECT); + nm_device_set_autoconnect_both (self, FALSE); g_object_thaw_notify (G_OBJECT (self)); @@ -2939,7 +3322,6 @@ slave_state_changed (NMDevice *slave, { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean release = FALSE; - gboolean configure = TRUE; _LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)", nm_device_get_iface (slave), @@ -2962,12 +3344,10 @@ slave_state_changed (NMDevice *slave, release = TRUE; } - /* Don't touch the device if its state changed externally. */ - if (reason == NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) - configure = FALSE; - if (release) { - nm_device_master_release_one_slave (self, slave, configure, reason); + nm_device_master_release_one_slave (self, slave, + priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED, + reason); /* Bridge/bond/team interfaces are left up until manually deactivated */ if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) _LOGD (LOGD_DEVICE, "last slave removed; remaining activated"); @@ -2983,32 +3363,36 @@ slave_state_changed (NMDevice *slave, * * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, * etc) then this function adds @slave to the slave list for later enslavement. + * + * Returns: %TRUE if the slave was enslaved. %FALSE means, the slave was already + * enslaved and nothing was done. */ -static void +static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) { NMDevicePrivate *priv; NMDevicePrivate *slave_priv; SlaveInfo *info; + gboolean changed = FALSE; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_DEVICE (slave)); - g_return_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE); + g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE); priv = NM_DEVICE_GET_PRIVATE (self); slave_priv = NM_DEVICE_GET_PRIVATE (slave); info = find_slave_info (self, slave); - _LOGt (LOGD_CORE, "master: add one slave %p/%s%s", slave, nm_device_get_iface (slave), + _LOGT (LOGD_CORE, "master: add one slave %p/%s%s", slave, nm_device_get_iface (slave), info ? " (already registered)" : ""); if (configure) - g_return_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED); + g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); if (!info) { - g_return_if_fail (!slave_priv->master); - g_return_if_fail (!slave_priv->is_enslaved); + g_return_val_if_fail (!slave_priv->master, FALSE); + g_return_val_if_fail (!slave_priv->is_enslaved, FALSE); info = g_slice_new0 (SlaveInfo); info->slave = g_object_ref (slave); @@ -3028,13 +3412,15 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) g_warn_if_fail (!NM_FLAGS_HAS (slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE)); nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + changed = TRUE; } else - g_return_if_fail (slave_priv->master == self); + g_return_val_if_fail (slave_priv->master == self, FALSE); nm_device_queue_recheck_assume (self); nm_device_queue_recheck_assume (slave); -} + return changed; +} /** * nm_device_master_get_slaves: @@ -3127,14 +3513,14 @@ nm_device_master_release_slaves (NMDevice *self) gboolean configure = TRUE; /* Don't release the slaves if this connection doesn't belong to NM. */ - if (nm_device_uses_generated_assumed_connection (self)) + if (nm_device_sys_iface_state_is_external (self)) return; reason = priv->state_reason; if (priv->state == NM_DEVICE_STATE_FAILED) reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - if (!nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex)) + if (!nm_platform_link_get (nm_device_get_platform (self), priv->ifindex)) configure = FALSE; while (priv->slaves) { @@ -3205,6 +3591,14 @@ nm_device_slave_notify_enslave (NMDevice *self, gboolean success) _LOGI (LOGD_DEVICE, "enslaved to %s", nm_device_get_iface (priv->master)); priv->is_enslaved = TRUE; + + if ( NM_IN_SET_TYPED (NMDeviceSysIfaceState, + priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME) + && nm_device_sys_iface_state_get (priv->master) == NM_DEVICE_SYS_IFACE_STATE_MANAGED) + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + _notify (self, PROP_MASTER); _notify (priv->master, PROP_SLAVES); } else if (activating) { @@ -3243,15 +3637,19 @@ nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) if ( priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { - if (reason == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) { + switch (nm_device_state_reason_check (reason)) { + case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: new_state = NM_DEVICE_STATE_FAILED; master_status = "failed"; - } else if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) { + break; + case NM_DEVICE_STATE_REASON_USER_REQUESTED: new_state = NM_DEVICE_STATE_DEACTIVATING; master_status = "deactivated by user request"; - } else { + break; + default: new_state = NM_DEVICE_STATE_DISCONNECTED; master_status = "deactivated"; + break; } _LOGD (LOGD_DEVICE, "Activation: connection '%s' master %s", @@ -3319,8 +3717,8 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config) _update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE); _update_default_route (self, AF_INET, FALSE, TRUE); _update_default_route (self, AF_INET6, FALSE, TRUE); - nm_device_set_ip4_config (self, NULL, 0, FALSE, FALSE, NULL); - nm_device_set_ip6_config (self, NULL, FALSE, FALSE, NULL); + nm_device_set_ip4_config (self, NULL, 0, FALSE, FALSE); + nm_device_set_ip6_config (self, NULL, FALSE, FALSE); } static gboolean @@ -3398,25 +3796,50 @@ nm_device_set_enabled (NMDevice *self, gboolean enabled) gboolean nm_device_get_autoconnect (NMDevice *self) { + NMDevicePrivate *priv; + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - return NM_DEVICE_GET_PRIVATE (self)->autoconnect; + priv = NM_DEVICE_GET_PRIVATE (self); + return priv->autoconnect_intern && priv->autoconnect_user; } -void -nm_device_set_autoconnect (NMDevice *self, gboolean autoconnect) +static void +nm_device_set_autoconnect_full (NMDevice *self, int autoconnect_intern, int autoconnect_user) { NMDevicePrivate *priv; + gboolean old_value; g_return_if_fail (NM_IS_DEVICE (self)); - autoconnect = !!autoconnect; - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->autoconnect != autoconnect) { - priv->autoconnect = autoconnect; + + old_value = nm_device_get_autoconnect (self); + if (autoconnect_intern != -1) + priv->autoconnect_intern = autoconnect_intern; + if (autoconnect_user != -1) + priv->autoconnect_user = autoconnect_user; + if (old_value != nm_device_get_autoconnect (self)) _notify (self, PROP_AUTOCONNECT); - } +} + +void +nm_device_set_autoconnect_intern (NMDevice *self, gboolean autoconnect) +{ + nm_device_set_autoconnect_full (self, !!autoconnect, -1); +} + +static void +nm_device_set_autoconnect_both (NMDevice *self, gboolean autoconnect) +{ + autoconnect = !!autoconnect; + nm_device_set_autoconnect_full (self, autoconnect, autoconnect); +} + +static gboolean +get_autoconnect_allowed (NMDevice *self) +{ + return TRUE; } static gboolean @@ -3441,10 +3864,12 @@ gboolean nm_device_autoconnect_allowed (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); GValue instance = G_VALUE_INIT; GValue retval = G_VALUE_INIT; - if (!priv->autoconnect) + if ( !nm_device_get_autoconnect (self) + || !klass->get_autoconnect_allowed (self)) return FALSE; /* Unrealized devices can always autoconnect. */ @@ -3535,7 +3960,7 @@ device_has_config (NMDevice *self) return TRUE; /* Master-slave relationship is also a configuration */ - if (priv->slaves || nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) > 0) + if (priv->slaves || nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) > 0) return TRUE; return FALSE; @@ -3598,7 +4023,7 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) NMSetting *s_con; NMSetting *s_ip4; NMSetting *s_ip6; - gs_free char *uuid = NULL; + char uuid[37]; const char *ip4_method, *ip6_method; GError *error = NULL; const NMPlatformLink *pllink; @@ -3615,10 +4040,9 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) connection = nm_simple_connection_new (); s_con = nm_setting_connection_new (); - uuid = nm_utils_uuid_generate (); g_object_set (s_con, - NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), NM_SETTING_CONNECTION_ID, ifname, NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, @@ -3649,7 +4073,7 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); nm_connection_add_setting (connection, s_ip6); - pllink = nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex); + pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ifindex); if (pllink && pllink->inet6_token.id) { _LOGD (LOGD_IP6, "IPv6 tokenized identifier present"); g_object_set (s_ip6, @@ -3889,12 +4313,14 @@ 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); + gboolean now_available; NMDeviceState state = nm_device_get_state (self); NMDeviceState new_state = NM_DEVICE_STATE_UNKNOWN; priv->recheck_available.call_id = 0; + now_available = nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); + 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); @@ -4101,7 +4527,7 @@ get_ip_config_may_fail (NMDevice *self, int family) g_assert_not_reached (); } - return nm_setting_ip_config_get_may_fail (s_ip); + return !s_ip || nm_setting_ip_config_get_may_fail (s_ip); } static void @@ -4133,7 +4559,7 @@ master_ready (NMDevice *self, /* If the master didn't change, add-slave only rechecks whether to assume a connection. */ nm_device_master_add_slave (master, self, - nm_active_connection_get_assumed (active) ? FALSE : TRUE); + !nm_device_sys_iface_state_is_external_or_assume (self)); } static void @@ -4185,7 +4611,7 @@ lldp_rx_enabled (NMDevice *self) } static NMActStageReturn -act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) { return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -4201,8 +4627,6 @@ activate_stage1_device_prepare (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); _set_ip_state (self, AF_INET, IP_NONE); _set_ip_state (self, AF_INET6, IP_NONE); @@ -4214,15 +4638,17 @@ activate_stage1_device_prepare (NMDevice *self) nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); /* Assumed connections were already set up outside NetworkManager */ - if (!nm_active_connection_get_assumed (active)) { - ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason); + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + + ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { return; } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return; } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + g_return_if_fail (ret == NM_ACT_STAGE_RETURN_SUCCESS); } nm_device_activate_schedule_stage2_device_config (self); @@ -4249,12 +4675,48 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) } static NMActStageReturn -act_stage2_config (NMDevice *self, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *self, NMDeviceStateReason *out_failure_reason) { - /* Nothing to do */ return NM_ACT_STAGE_RETURN_SUCCESS; } +static void +lldp_init (NMDevice *self, gboolean restart) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->ifindex > 0 && lldp_rx_enabled (self)) { + gs_free_error GError *error = NULL; + gconstpointer addr; + size_t addr_length; + + if (priv->lldp_listener) { + if (restart && nm_lldp_listener_is_running (priv->lldp_listener)) + nm_lldp_listener_stop (priv->lldp_listener); + } else { + priv->lldp_listener = nm_lldp_listener_new (); + g_signal_connect (priv->lldp_listener, + "notify::" NM_LLDP_LISTENER_NEIGHBORS, + G_CALLBACK (lldp_neighbors_changed), + self); + } + + if (!nm_lldp_listener_is_running (priv->lldp_listener)) { + addr = nm_platform_link_get_address (nm_device_get_platform (self), priv->ifindex, &addr_length); + + if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) + _LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); + else { + _LOGD (LOGD_DEVICE, "LLDP listener %p could not be started: %s", + priv->lldp_listener, error->message); + } + } + } else { + if (priv->lldp_listener) + nm_lldp_listener_stop (priv->lldp_listener); + } +} + /* * activate_stage2_device_config * @@ -4267,15 +4729,15 @@ activate_stage2_device_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; gboolean no_firmware = FALSE; - NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); GSList *iter; nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); /* Assumed connections were already set up outside NetworkManager */ - if (!nm_active_connection_get_assumed (active)) { + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + if (!nm_device_bring_up (self, FALSE, &no_firmware)) { if (no_firmware) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING); @@ -4284,11 +4746,11 @@ activate_stage2_device_config (NMDevice *self) return; } - ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); @@ -4301,36 +4763,13 @@ activate_stage2_device_config (NMDevice *self) if (slave_state == NM_DEVICE_STATE_IP_CONFIG) nm_device_master_enslave_slave (self, info->slave, nm_device_get_applied_connection (info->slave)); - else if ( nm_device_uses_generated_assumed_connection (self) + else if ( priv->act_request + && nm_device_sys_iface_state_is_external (self) && slave_state <= NM_DEVICE_STATE_DISCONNECTED) nm_device_queue_recheck_assume (info->slave); } - if (lldp_rx_enabled (self) && priv->ifindex > 0) { - gs_free_error GError *error = NULL; - gconstpointer addr; - size_t addr_length; - - if (priv->lldp_listener) - nm_lldp_listener_stop (priv->lldp_listener); - else { - priv->lldp_listener = nm_lldp_listener_new (); - g_signal_connect (priv->lldp_listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - G_CALLBACK (lldp_neighbors_changed), - self); - } - - addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length); - - if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) - _LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); - else { - _LOGD (LOGD_DEVICE, "LLDP listener %p could not be started: %s", - priv->lldp_listener, error->message); - } - } - + lldp_init (self, TRUE); nm_device_activate_schedule_stage3_ip_config_start (self); } @@ -4426,7 +4865,7 @@ check_ip_state (NMDevice *self, gboolean may_fail) && (priv->ip6_state == IP_FAIL || (ip6_ignore && priv->ip6_state == IP_DONE))) { /* Either both methods failed, or only one failed and the other is * disabled */ - if (nm_device_uses_assumed_connection (self)) { + if (nm_device_sys_iface_state_is_external_or_assume (self)) { /* We have assumed configuration, but couldn't redo it. No problem, * move to check state. */ _set_ip_state (self, AF_INET, IP_DONE); @@ -4610,7 +5049,7 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) } timeout = get_ipv4_dad_timeout (self); - hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET, + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &hw_addr_len); @@ -4618,7 +5057,7 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) || !hw_addr || !hw_addr_len || !addr_found - || nm_device_uses_assumed_connection (self)) { + || nm_device_sys_iface_state_is_external_or_assume (self)) { /* DAD not needed, signal success */ cb (self, configs, TRUE); @@ -4759,7 +5198,7 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) nm_clear_g_source (&priv->ipv4ll_timeout); nm_device_activate_schedule_ip4_config_result (self, config); } else if (priv->ip4_state == IP_DONE) { - if (!ip4_config_merge_and_apply (self, config, TRUE, NULL)) { + if (!ip4_config_merge_and_apply (self, config, TRUE)) { _LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); } @@ -4793,7 +5232,7 @@ ipv4ll_timeout_cb (gpointer user_data) } static NMActStageReturn -ipv4ll_start (NMDevice *self, NMDeviceStateReason *reason) +ipv4ll_start (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const struct ether_addr *addr; @@ -4805,55 +5244,51 @@ ipv4ll_start (NMDevice *self, NMDeviceStateReason *reason) r = sd_ipv4ll_new (&priv->ipv4ll); if (r < 0) { _LOGE (LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } r = sd_ipv4ll_attach_event (priv->ipv4ll, NULL, 0); if (r < 0) { _LOGE (LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } ifindex = nm_device_get_ip_ifindex (self); - addr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &addr_len); + addr = nm_platform_link_get_address (nm_device_get_platform (self), ifindex, &addr_len); if (!addr || addr_len != ETH_ALEN) { _LOGE (LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address"); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } r = sd_ipv4ll_set_mac (priv->ipv4ll, addr); if (r < 0) { _LOGE (LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } r = sd_ipv4ll_set_ifindex (priv->ipv4ll, ifindex); if (r < 0) { _LOGE (LOGD_AUTOIP4, "IPv4LL: set_ifindex() failed with error %d", r); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } r = sd_ipv4ll_set_callback (priv->ipv4ll, nm_device_handle_ipv4ll_event, self); if (r < 0) { _LOGE (LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } r = sd_ipv4ll_start (priv->ipv4ll); if (r < 0) { _LOGE (LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r); - goto fail; + return NM_ACT_STAGE_RETURN_FAILURE; } _LOGI (LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); /* Start a timeout to bound the address attempt */ priv->ipv4ll_timeout = g_timeout_add_seconds (20, ipv4ll_timeout_cb, self); - return NM_ACT_STAGE_RETURN_POSTPONE; -fail: - *reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; } /*****************************************************************************/ @@ -4866,9 +5301,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 (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); + routes = nm_platform_ip4_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); else - routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); + routes = nm_platform_ip6_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); if (routes) { guint route_metric = G_MAXUINT32, m; @@ -4923,7 +5358,7 @@ ensure_con_ip4_config (NMDevice *self) nm_connection_get_setting_ip4_config (connection), nm_device_get_ip4_route_metric (self)); - if (nm_device_uses_assumed_connection (self)) { + if (nm_device_sys_iface_state_is_external_or_assume (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); @@ -4949,7 +5384,7 @@ ensure_con_ip6_config (NMDevice *self) nm_connection_get_setting_ip6_config (connection), nm_device_get_ip6_route_metric (self)); - if (nm_device_uses_assumed_connection (self)) { + if (nm_device_sys_iface_state_is_external_or_assume (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); @@ -4965,6 +5400,7 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); nm_clear_g_source (&priv->dhcp4.restart_id); + g_clear_pointer (&priv->dhcp4.pac_url, g_free); if (priv->dhcp4.client) { /* Stop any ongoing DHCP transaction on this device */ @@ -4997,8 +5433,7 @@ _ip4_config_merge_default (gpointer value, gpointer user_data) static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, - gboolean commit, - NMDeviceStateReason *out_reason) + gboolean commit) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; @@ -5091,7 +5526,7 @@ ip4_config_merge_and_apply (NMDevice *self, * but if the IP method is automatic we need to update the default route to * maintain connectivity. */ - if (nm_device_uses_generated_assumed_connection (self) && !auto_method) + if (nm_device_sys_iface_state_is_external (self) && !auto_method) goto END_ADD_DEFAULT_ROUTE; /* At this point, we treat assumed and non-assumed connections alike. @@ -5100,7 +5535,7 @@ ip4_config_merge_and_apply (NMDevice *self, */ connection_has_default_route - = nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), + = nm_default_route_manager_ip4_connection_has_default_route (nm_netns_get_default_route_manager (priv->netns), connection, &connection_is_never_default); if ( !priv->v4_commit_first_time @@ -5136,7 +5571,7 @@ ip4_config_merge_and_apply (NMDevice *self, memset (&priv->default_route.v4, 0, sizeof (priv->default_route.v4)); priv->default_route.v4.rt_source = NM_IP_CONFIG_SOURCE_USER; priv->default_route.v4.gateway = gateway; - priv->default_route.v4.metric = default_route_metric; + priv->default_route.v4.metric = route_metric_with_penalty (self, default_route_metric); priv->default_route.v4.mss = nm_ip4_config_get_mss (composite); if (!has_direct_route) { @@ -5167,9 +5602,9 @@ END_ADD_DEFAULT_ROUTE: routes_full_sync = commit && priv->v4_commit_first_time - && !nm_device_uses_assumed_connection (self); + && !nm_device_sys_iface_state_is_external_or_assume (self); - success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync, out_reason); + success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync); g_object_unref (composite); if (commit) @@ -5180,23 +5615,17 @@ END_ADD_DEFAULT_ROUTE: static gboolean dhcp4_lease_change (NMDevice *self, NMIP4Config *config) { - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + g_return_val_if_fail (config, FALSE); - g_return_val_if_fail (config != NULL, FALSE); - - if (!ip4_config_merge_and_apply (self, config, TRUE, &reason)) { + if (!ip4_config_merge_and_apply (self, config, TRUE)) { _LOGW (LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); return FALSE; } - /* Notify dispatcher scripts of new DHCP4 config */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, - nm_device_get_settings_connection (self), - nm_device_get_applied_connection (self), - self, - NULL, - NULL, - NULL); + nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP4_CHANGE, + self, + NULL, + NULL, NULL, NULL); nm_device_remove_pending_action (self, NM_PENDING_ACTION_DHCP4, FALSE); @@ -5208,7 +5637,6 @@ dhcp4_restart_cb (gpointer user_data) { NMDevice *self = user_data; NMDevicePrivate *priv; - NMDeviceStateReason reason; NMConnection *connection; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); @@ -5217,7 +5645,7 @@ dhcp4_restart_cb (gpointer user_data) priv->dhcp4.restart_id = 0; connection = nm_device_get_applied_connection (self); - if (dhcp4_start (self, connection, &reason) == NM_ACT_STAGE_RETURN_FAILURE) + if (dhcp4_start (self, connection) == NM_ACT_STAGE_RETURN_FAILURE) dhcp_schedule_restart (self, AF_INET, NULL); return FALSE; @@ -5243,19 +5671,11 @@ dhcp4_fail (NMDevice *self, gboolean timeout) return; } - /* Instead of letting an assumed connection fail (which means that the - * device will transition to the ACTIVATED state without IP configuration), - * retry DHCP again. - */ - if (nm_device_uses_assumed_connection (self)) { - dhcp_schedule_restart (self, AF_INET, "connection is assumed"); - return; - } - if ( priv->dhcp4.num_tries_left == DHCP_NUM_TRIES_MAX - && (timeout || (priv->ip4_state == IP_CONF))) + && (timeout || (priv->ip4_state == IP_CONF)) + && !priv->dhcp4.was_active) nm_device_activate_schedule_ip4_config_timeout (self); - else if (priv->ip4_state == IP_DONE) { + else if (priv->ip4_state == IP_DONE || priv->dhcp4.was_active) { /* Don't fail immediately when the lease expires but try to * restart DHCP for a predefined number of times. */ @@ -5305,7 +5725,9 @@ dhcp4_state_changed (NMDhcpClient *client, break; } - nm_device_set_proxy_config (self, options); + g_free (priv->dhcp4.pac_url); + priv->dhcp4.pac_url = g_strdup (g_hash_table_lookup (options, "wpad")); + nm_device_set_proxy_config (self, priv->dhcp4.pac_url); nm_dhcp4_config_set_options (priv->dhcp4.config, options); _notify (self, PROP_DHCP4_CONFIG); @@ -5373,8 +5795,7 @@ dhcp4_get_timeout (NMDevice *self, NMSettingIP4Config *s_ip4) static NMActStageReturn dhcp4_start (NMDevice *self, - NMConnection *connection, - NMDeviceStateReason *reason) + NMConnection *connection) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip4; @@ -5388,7 +5809,7 @@ dhcp4_start (NMDevice *self, nm_exported_object_clear_and_unexport (&priv->dhcp4.config); priv->dhcp4.config = nm_dhcp4_config_new (); - hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), &hw_addr_len); + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), 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); @@ -5413,10 +5834,8 @@ dhcp4_start (NMDevice *self, if (tmp) g_byte_array_free (tmp, TRUE); - if (!priv->dhcp4.client) { - *reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED; + if (!priv->dhcp4.client) return NM_ACT_STAGE_RETURN_FAILURE; - } priv->dhcp4.state_sigid = g_signal_connect (priv->dhcp4.client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, @@ -5425,6 +5844,9 @@ dhcp4_start (NMDevice *self, nm_device_add_pending_action (self, NM_PENDING_ACTION_DHCP4, TRUE); + if (nm_device_sys_iface_state_is_external_or_assume (self)) + priv->dhcp4.was_active = TRUE; + /* DHCP devices will be notified by the DHCP manager when stuff happens */ return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -5433,8 +5855,6 @@ gboolean nm_device_dhcp4_renew (NMDevice *self, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret; - NMDeviceStateReason reason; NMConnection *connection; g_return_val_if_fail (priv->dhcp4.client != NULL, FALSE); @@ -5445,12 +5865,10 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release) dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); connection = nm_device_get_applied_connection (self); - g_assert (connection); + g_return_val_if_fail (connection, FALSE); /* Start DHCP again on the interface */ - ret = dhcp4_start (self, connection, &reason); - - return (ret != NM_ACT_STAGE_RETURN_FAILURE); + return dhcp4_start (self, connection) != NM_ACT_STAGE_RETURN_FAILURE; } /*****************************************************************************/ @@ -5499,24 +5917,22 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres } static NMIP4Config * -shared4_new_config (NMDevice *self, NMConnection *connection, NMDeviceStateReason *reason) +shared4_new_config (NMDevice *self, NMConnection *connection) { NMIP4Config *config = NULL; NMPlatformIP4Address address; g_return_val_if_fail (self != NULL, NULL); - if (!reserve_shared_ip (self, nm_connection_get_setting_ip4_config (connection), &address)) { - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + if (!reserve_shared_ip (self, nm_connection_get_setting_ip4_config (connection), &address)) return NULL; - } config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); address.addr_source = NM_IP_CONFIG_SOURCE_SHARED; nm_ip4_config_add_address (config, &address); /* Remove the address lock when the object gets disposed */ - g_object_set_data_full (G_OBJECT (config), "shared-ip", + g_object_set_qdata_full (G_OBJECT (config), NM_CACHED_QUARK ("shared-ip"), GUINT_TO_POINTER (address.address), release_shared_ip); @@ -5586,7 +6002,7 @@ connection_requires_carrier (NMConnection *connection) return TRUE; } - /* If an IP version wants a carrier and and the other IP version isn't + /* If an IP version wants a carrier and the other IP version isn't * used, the connection requires carrier since it will just fail without one. */ if (ip4_carrier_wanted && !ip6_used) @@ -5626,7 +6042,7 @@ ip4_requires_slaves (NMConnection *connection) static NMActStageReturn act_stage3_ip4_config_start (NMDevice *self, NMIP4Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; @@ -5635,10 +6051,8 @@ act_stage3_ip4_config_start (NMDevice *self, GSList *slaves; gboolean ready_slaves; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_device_get_applied_connection (self); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); if ( connection_ip4_method_requires_carrier (connection, NULL) && priv->is_master @@ -5667,11 +6081,15 @@ act_stage3_ip4_config_start (NMDevice *self, priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX; /* Start IPv4 addressing based on the method requested */ - if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) - ret = dhcp4_start (self, connection, reason); - else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0) - ret = ipv4ll_start (self, reason); - else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) { + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) { + ret = dhcp4_start (self, connection); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); + } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0) { + ret = ipv4ll_start (self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); + } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) { NMIP4Config **configs, *config; config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); @@ -5685,12 +6103,14 @@ act_stage3_ip4_config_start (NMDevice *self, ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { if (out_config) { - *out_config = shared4_new_config (self, connection, reason); + *out_config = shared4_new_config (self, connection); if (*out_config) { priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self)); ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else + } else { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); ret = NM_ACT_STAGE_RETURN_FAILURE; + } } else g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) @@ -5744,8 +6164,7 @@ _ip6_config_merge_default (gpointer value, gpointer user_data) static gboolean ip6_config_merge_and_apply (NMDevice *self, - gboolean commit, - NMDeviceStateReason *out_reason) + gboolean commit) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; @@ -5849,7 +6268,7 @@ ip6_config_merge_and_apply (NMDevice *self, * but if the IP method is automatic we need to update the default route to * maintain connectivity. */ - if (nm_device_uses_generated_assumed_connection (self) && !auto_method) + if (nm_device_sys_iface_state_is_external (self) && !auto_method) goto END_ADD_DEFAULT_ROUTE; /* At this point, we treat assumed and non-assumed connections alike. @@ -5858,7 +6277,7 @@ ip6_config_merge_and_apply (NMDevice *self, */ connection_has_default_route - = nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), + = nm_default_route_manager_ip6_connection_has_default_route (nm_netns_get_default_route_manager (priv->netns), connection, &connection_is_never_default); if ( !priv->v6_commit_first_time @@ -5894,7 +6313,8 @@ ip6_config_merge_and_apply (NMDevice *self, memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6)); priv->default_route.v6.rt_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.metric = route_metric_with_penalty (self, + nm_device_get_ip6_route_metric (self)); priv->default_route.v6.mss = nm_ip6_config_get_mss (composite); if (!has_direct_route) { @@ -5923,7 +6343,7 @@ END_ADD_DEFAULT_ROUTE: NMUtilsIPv6IfaceId iid; if (token && nm_utils_ipv6_interface_identifier_get_from_token (&iid, token)) { - nm_platform_link_set_ipv6_token (NM_PLATFORM_GET, + nm_platform_link_set_ipv6_token (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), iid); } @@ -5931,9 +6351,9 @@ END_ADD_DEFAULT_ROUTE: routes_full_sync = commit && priv->v6_commit_first_time - && !nm_device_uses_assumed_connection (self); + && !nm_device_sys_iface_state_is_external_or_assume (self); - success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync, out_reason); + success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync); g_object_unref (composite); if (commit) priv->v6_commit_first_time = FALSE; @@ -5945,7 +6365,6 @@ dhcp6_lease_change (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingsConnection *settings_connection; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; if (priv->dhcp6.ip6_config == NULL) { _LOGW (LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); @@ -5958,16 +6377,15 @@ dhcp6_lease_change (NMDevice *self) g_assert (settings_connection); /* Apply the updated config */ - if (!ip6_config_merge_and_apply (self, TRUE, &reason)) { + if (!ip6_config_merge_and_apply (self, TRUE)) { _LOGW (LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event"); return FALSE; } - /* Notify dispatcher scripts of new DHCPv6 config */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE, - settings_connection, - nm_device_get_applied_connection (self), - self, NULL, NULL, NULL); + nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP6_CHANGE, + self, + NULL, + NULL, NULL, NULL); nm_device_remove_pending_action (self, NM_PENDING_ACTION_DHCP6, FALSE); @@ -5979,14 +6397,13 @@ dhcp6_restart_cb (gpointer user_data) { NMDevice *self = user_data; NMDevicePrivate *priv; - NMDeviceStateReason reason; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); priv = NM_DEVICE_GET_PRIVATE (self); priv->dhcp6.restart_id = 0; - if (!dhcp6_start (self, FALSE, &reason)) + if (!dhcp6_start (self, FALSE)) dhcp_schedule_restart (self, AF_INET6, NULL); return FALSE; @@ -6044,19 +6461,11 @@ dhcp6_fail (NMDevice *self, gboolean timeout) return; } - /* Instead of letting an assumed connection fail (which means that the - * device will transition to the ACTIVATED state without IP configuration), - * retry DHCP again. - */ - if (nm_device_uses_assumed_connection (self)) { - dhcp_schedule_restart (self, AF_INET6, "connection is assumed"); - return; - } - if ( priv->dhcp6.num_tries_left == DHCP_NUM_TRIES_MAX - && (timeout || (priv->ip6_state == IP_CONF))) + && (timeout || (priv->ip6_state == IP_CONF)) + && !priv->dhcp6.was_active) nm_device_activate_schedule_ip6_config_timeout (self); - else if (priv->ip6_state == IP_DONE) { + else if (priv->ip6_state == IP_DONE || priv->dhcp6.was_active) { /* Don't fail immediately when the lease expires but try to * restart DHCP for a predefined number of times. */ @@ -6194,17 +6603,20 @@ 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_PLATFORM_GET, nm_device_get_ip_ifindex (self), &hw_addr_len); + if (priv->ext_ip6_config_captured) + ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE); + + if (!ll_addr) { + _LOGW (LOGD_DHCP6, "can't start DHCPv6: no link-local address"); + return FALSE; + } + + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), 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); } - if (priv->ext_ip6_config_captured) - ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE); - - g_return_val_if_fail (ll_addr, FALSE); - priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_ip_iface (self), nm_device_get_ip_ifindex (self), @@ -6233,11 +6645,14 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) self); } + if (nm_device_sys_iface_state_is_external_or_assume (self)) + priv->dhcp4.was_active = TRUE; + return !!priv->dhcp6.client; } static gboolean -dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) +dhcp6_start (NMDevice *self, gboolean wait_for_ll) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; @@ -6271,10 +6686,8 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } - if (!dhcp6_start_with_link_ready (self, connection)) { - NM_SET_OUT (reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); + if (!dhcp6_start_with_link_ready (self, connection)) return FALSE; - } return TRUE; } @@ -6292,7 +6705,7 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); /* Start DHCP again on the interface */ - return dhcp6_start (self, FALSE, NULL); + return dhcp6_start (self, FALSE); } /*****************************************************************************/ @@ -6344,7 +6757,7 @@ nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) subnet->preferred); /* This also updates the ndisc if there are actual changes. */ - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); } @@ -6380,7 +6793,7 @@ nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) nm_ip6_config_get_search (from_config, i)); } - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); } @@ -6419,7 +6832,8 @@ linklocal6_complete (NMDevice *self) const char *method; g_assert (priv->linklocal6_timeout_id); - g_assert (nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE)); + g_assert (priv->ext_ip6_config_captured); + g_assert (nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)); linklocal6_cleanup (self); @@ -6521,7 +6935,7 @@ check_and_add_ipv6ll_addr (NMDevice *self) } _LOGD (LOGD_IP6, "linklocal6: adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL)); - if (!nm_platform_ip6_address_add (NM_PLATFORM_GET, + if (!nm_platform_ip6_address_add (nm_device_get_platform (self), ip_ifindex, lladdr, 64, @@ -6543,8 +6957,8 @@ linklocal6_start (NMDevice *self) linklocal6_cleanup (self); - if ( priv->ip6_config - && nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE)) + if ( priv->ext_ip6_config_captured + && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) return NM_ACT_STAGE_RETURN_SUCCESS; connection = nm_device_get_applied_connection (self); @@ -6632,7 +7046,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) if (ifindex <= 0) return; - if (nm_device_uses_assumed_connection (self)) { + if (nm_device_sys_iface_state_is_external_or_assume (self)) { /* for assumed connections we don't tamper with the MTU. This is * a bug and supposed to be fixed by the unmanaged/assumed rework. */ return; @@ -6701,7 +7115,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) mtu_desired_orig = mtu_desired; ip6_mtu_orig = ip6_mtu; - mtu_plat = nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex); + mtu_plat = nm_platform_link_get_mtu (nm_device_get_platform (self), ifindex); if (ip6_mtu) { ip6_mtu = NM_MAX (1280, ip6_mtu); @@ -6743,7 +7157,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) } if (mtu_desired && mtu_desired != mtu_plat) - nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, mtu_desired); + nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, mtu_desired); if (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ()) { nm_device_ipv6_sysctl_set (self, "mtu", @@ -6768,7 +7182,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in * addresses as /128. The reason for the /128 is to prevent the kernel * from adding a prefix route for this address. **/ - system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); + system_support = nm_platform_check_support_kernel_extended_ifa_flags (nm_device_get_platform (self)); if (system_support) ifa_flags = IFA_F_NOPREFIXROUTE; @@ -6859,14 +7273,13 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in priv->dhcp6.mode = rdata->dhcp_level; if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { - NMDeviceStateReason reason; - _LOGD (LOGD_DEVICE | LOGD_DHCP6, "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" " as requested by IPv6 router..."); - if (!dhcp6_start (self, FALSE, &reason)) { + if (!dhcp6_start (self, FALSE)) { if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_DHCP_START_FAILED); return; } } @@ -6874,7 +7287,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in } if (changed & NM_NDISC_CONFIG_HOP_LIMIT) - nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, nm_device_get_ip_iface (self), rdata->hop_limit); + nm_platform_sysctl_set_ip6_hop_limit_safe (nm_device_get_platform (self), nm_device_get_ip_iface (self), rdata->hop_limit); if (changed & NM_NDISC_CONFIG_MTU) { if (priv->ip6_mtu != rdata->mtu) { @@ -6929,7 +7342,7 @@ addrconf6_start_with_link_ready (NMDevice *self) } /* Apply any manual configuration before starting RA */ - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration"); /* XXX: These sysctls would probably be better set by the lndp ndisc itself. */ @@ -7005,16 +7418,15 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) g_assert (s_ip6); stable_id = _get_stable_id (self, connection, &stable_type); - if (stable_id) { - priv->ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET, - nm_device_get_ip_ifindex (self), - nm_device_get_ip_iface (self), - stable_type, - stable_id, - nm_setting_ip6_config_get_addr_gen_mode (s_ip6), - ndisc_node_type (self), - &error); - } + g_assert (stable_id); + priv->ndisc = nm_lndp_ndisc_new (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self), + nm_device_get_ip_iface (self), + stable_type, + stable_id, + nm_setting_ip6_config_get_addr_gen_mode (s_ip6), + ndisc_node_type (self), + &error); if (!priv->ndisc) { _LOGE (LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); g_error_free (error); @@ -7024,7 +7436,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) priv->ndisc_use_tempaddr = use_tempaddr; if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) - && !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) { + && !nm_platform_check_support_kernel_extended_ifa_flags (nm_device_get_platform (self))) { _LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for " "IPv6 private addresses. This feature is not available"); } @@ -7082,7 +7494,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_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i]))); + value = nm_platform_sysctl_get (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (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], @@ -7122,7 +7534,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) int ifindex = nm_device_get_ip_ifindex (self); char *value; - if (!nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) + if (!nm_platform_check_support_user_ipv6ll (nm_device_get_platform (self))) return; priv->nm_ipv6ll = enable; @@ -7131,7 +7543,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) const char *detail = enable ? "enable" : "disable"; _LOGD (LOGD_IP6, "will %s userland IPv6LL", detail); - plerr = nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, enable); + plerr = nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), ifindex, enable); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { _NMLOG (plerr == NM_PLATFORM_ERROR_NOT_FOUND ? LOGL_DEBUG : LOGL_WARN, LOGD_IP6, @@ -7142,7 +7554,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) if (enable) { /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ - value = nm_platform_sysctl_get (NM_PLATFORM_GET, + value = nm_platform_sysctl_get (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (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"); @@ -7209,7 +7621,7 @@ _ip6_privacy_get (NMDevice *self) * 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, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + ip6_privacy = nm_platform_sysctl_get_int32 (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); return _ip6_privacy_clamp (ip6_privacy); } @@ -7232,7 +7644,7 @@ ip6_requires_slaves (NMConnection *connection) static NMActStageReturn act_stage3_ip6_config_start (NMDevice *self, NMIP6Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; @@ -7243,10 +7655,8 @@ act_stage3_ip6_config_start (NMDevice *self, GSList *slaves; gboolean ready_slaves; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_device_get_applied_connection (self); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); if ( connection_ip6_method_requires_carrier (connection, NULL) && priv->is_master @@ -7302,12 +7712,23 @@ act_stage3_ip6_config_start (NMDevice *self, * IPv6LL if this is not an assumed connection, since assumed connections * will already have IPv6 set up. */ - if (!nm_device_uses_assumed_connection (self)) + if (!nm_device_sys_iface_state_is_external_or_assume (self)) set_nm_ipv6ll (self, TRUE); /* Re-enable IPv6 on the interface */ set_disable_ipv6 (self, "0"); + /* Synchronize external IPv6 configuration with kernel, since + * linklocal6_start() uses the information there to determine if we can + * proceed with the selected method (SLAAC, DHCP, link-local). + */ + nm_platform_process_events (nm_device_get_platform (self)); + g_clear_object (&priv->ext_ip6_config_captured); + priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self), + nm_device_get_ifindex (self), + FALSE, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + ip6_privacy = _ip6_privacy_get (self); if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 @@ -7321,7 +7742,7 @@ act_stage3_ip6_config_start (NMDevice *self, ret = linklocal6_start (self); } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; - if (!dhcp6_start (self, TRUE, reason)) { + if (!dhcp6_start (self, TRUE)) { /* IPv6 might be disabled; allow IPv4 to proceed */ ret = NM_ACT_STAGE_RETURN_IP_FAIL; } else @@ -7332,7 +7753,7 @@ act_stage3_ip6_config_start (NMDevice *self, _LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); if ( ret != NM_ACT_STAGE_RETURN_FAILURE - && !nm_device_uses_assumed_connection (self)) { + && !nm_device_sys_iface_state_is_external_or_assume (self)) { switch (ip6_privacy) { case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: @@ -7362,13 +7783,19 @@ nm_device_activate_stage3_ip4_start (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; NMIP4Config *ip4_config = NULL; g_assert (priv->ip4_state == IP_WAIT); + /* Slaves stay in IP_CONFIG state until master is ready, and then + * they go directly to SECONDARIES without configuring IPv4. + */ + if (nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request))) + return TRUE; + _set_ip_state (self, AF_INET, IP_CONF); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { if (!ip4_config) ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); @@ -7378,7 +7805,7 @@ nm_device_activate_stage3_ip4_start (NMDevice *self) _set_ip_state (self, AF_INET, IP_DONE); check_ip_state (self, FALSE); } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return FALSE; } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { /* Activation not wanted */ @@ -7403,13 +7830,19 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; NMIP6Config *ip6_config = NULL; g_assert (priv->ip6_state == IP_WAIT); + /* Slaves stay in IP_CONFIG state until master is ready, and then + * they go directly to SECONDARIES without configuring IPv6. + */ + if (nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request))) + return TRUE; + _set_ip_state (self, AF_INET6, IP_CONF); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { if (!ip6_config) ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); @@ -7423,7 +7856,7 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) _set_ip_state (self, AF_INET6, IP_DONE); check_ip_state (self, FALSE); } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return FALSE; } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { /* Activation not wanted */ @@ -7456,7 +7889,7 @@ activate_stage3_ip_config_start (NMDevice *self) 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_PLATFORM_GET, nm_device_get_ip_ifindex (self))) + if (!nm_platform_link_is_up (nm_device_get_platform (self), 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 @@ -7495,60 +7928,72 @@ activate_stage3_ip_config_start (NMDevice *self) check_ip_state (self, TRUE); } -static gboolean -fw_change_zone_handle (NMDevice *self, - NMFirewallManagerCallId call_id, - GError *error) +static void +fw_change_zone_cb (NMFirewallManager *firewall_manager, + NMFirewallManagerCallId call_id, + GError *error, + gpointer user_data) { + NMDevice *self = user_data; NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_val_if_fail (priv->fw_call == call_id, FALSE); + if (priv->fw_call != call_id) + g_return_if_reached (); priv->fw_call = NULL; - return !nm_utils_error_is_cancelled (error, FALSE); + if (nm_utils_error_is_cancelled (error, FALSE)) + return; + + switch (priv->fw_state) { + case FIREWALL_STATE_WAIT_STAGE_3: + priv->fw_state = FIREWALL_STATE_INITIALIZED; + nm_device_activate_schedule_stage3_ip_config_start (self); + break; + case FIREWALL_STATE_WAIT_IP_CONFIG: + priv->fw_state = FIREWALL_STATE_INITIALIZED; + if (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE) + nm_device_start_ip_check (self); + break; + case FIREWALL_STATE_INITIALIZED: + break; + default: + g_return_if_reached (); + } } static void -fw_change_zone_cb_stage2 (NMFirewallManager *firewall_manager, - NMFirewallManagerCallId call_id, - GError *error, - gpointer user_data) +fw_change_zone (NMDevice *self) { - NMDevice *self = user_data; - NMDevicePrivate *priv; - - if (!fw_change_zone_handle (self, call_id, error)) - return; - - /* FIXME: fail the device on error? */ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *applied_connection; + NMSettingConnection *s_con; - priv = NM_DEVICE_GET_PRIVATE (self); - priv->fw_ready = TRUE; + nm_assert (priv->fw_state >= FIREWALL_STATE_INITIALIZED); - nm_device_activate_schedule_stage3_ip_config_start (self); -} + applied_connection = nm_device_get_applied_connection (self); + nm_assert (applied_connection); -static void -fw_change_zone_cb_ip_check (NMFirewallManager *firewall_manager, - NMFirewallManagerCallId call_id, - GError *error, - gpointer user_data) -{ - NMDevice *self = user_data; - NMDevicePrivate *priv; + s_con = nm_connection_get_setting_connection (applied_connection); + nm_assert (s_con); - if (!fw_change_zone_handle (self, call_id, error)) - return; + if (priv->fw_call) { + nm_firewall_manager_cancel_call (priv->fw_call); + nm_assert (!priv->fw_call); + } - /* FIXME: fail the device on error? */ + if (G_UNLIKELY (!priv->fw_mgr)) + priv->fw_mgr = g_object_ref (nm_firewall_manager_get ()); - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE) - nm_device_start_ip_check (self); + priv->fw_call = nm_firewall_manager_add_or_change_zone (priv->fw_mgr, + nm_device_get_ip_iface (self), + nm_setting_connection_get_zone (s_con), + FALSE, /* change zone */ + fw_change_zone_cb, + self); } /* @@ -7560,9 +8005,6 @@ void nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) { NMDevicePrivate *priv; - NMConnection *connection; - NMSettingConnection *s_con = NULL; - const char *zone; g_return_if_fail (NM_IS_DEVICE (self)); @@ -7570,37 +8012,30 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) g_return_if_fail (priv->act_request); /* Add the interface to the specified firewall zone */ - connection = nm_device_get_applied_connection (self); - g_assert (connection); - s_con = nm_connection_get_setting_connection (connection); - - if (!priv->fw_ready) { - if (nm_device_uses_generated_assumed_connection (self)) - priv->fw_ready = TRUE; - else { - if (!priv->fw_call) { - zone = nm_setting_connection_get_zone (s_con); - - _LOGD (LOGD_DEVICE, "Activation: setting firewall zone '%s'", zone ? zone : "default"); - priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - nm_device_get_ip_iface (self), - zone, - FALSE, - fw_change_zone_cb_stage2, - self); - } + if (priv->fw_state == FIREWALL_STATE_UNMANAGED) { + if (!nm_device_sys_iface_state_is_external (self)) { + priv->fw_state = FIREWALL_STATE_WAIT_STAGE_3; + fw_change_zone (self); return; } + + /* fake success. */ + priv->fw_state = FIREWALL_STATE_INITIALIZED; + } else if (priv->fw_state == FIREWALL_STATE_WAIT_STAGE_3) { + /* a firewall call for stage3 is pending. Return and wait. */ + return; } + nm_assert (priv->fw_state == FIREWALL_STATE_INITIALIZED); + activation_source_schedule (self, activate_stage3_ip_config_start, AF_INET); } static NMActStageReturn -act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *reason) +act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *out_failure_reason) { if (!get_ip_config_may_fail (self, AF_INET)) { - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } return NM_ACT_STAGE_RETURN_SUCCESS; @@ -7616,13 +8051,13 @@ static void activate_stage4_ip4_config_timeout (NMDevice *self) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); @@ -7652,10 +8087,10 @@ nm_device_activate_schedule_ip4_config_timeout (NMDevice *self) } static NMActStageReturn -act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *reason) +act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *out_failure_reason) { if (!get_ip_config_may_fail (self, AF_INET6)) { - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -7672,13 +8107,13 @@ static void activate_stage4_ip6_config_timeout (NMDevice *self) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); @@ -7708,7 +8143,7 @@ nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) } static gboolean -share_init (void) +share_init (NMDevice *self) { char *modules[] = { "ip_tables", "iptable_nat", "nf_nat_ftp", "nf_nat_irc", "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323", @@ -7716,14 +8151,14 @@ share_init (void) char **iter; int errsv; - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { + if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { errsv = errno; nm_log_err (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", errsv, strerror (errsv)); return FALSE; } - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { + if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { errsv = errno; nm_log_err (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", errsv, strerror (errsv)); @@ -7770,7 +8205,7 @@ start_sharing (NMDevice *self, NMIP4Config *config) if (!inet_ntop (AF_INET, &network, str_addr, sizeof (str_addr))) return FALSE; - if (!share_init ()) + if (!share_init (self)) return FALSE; req = nm_device_get_act_request (self); @@ -7826,7 +8261,7 @@ arp_announce (NMDevice *self) arp_cleanup (self); - hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET, + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &hw_addr_len); @@ -7868,7 +8303,6 @@ activate_stage5_ip4_config_commit (NMDevice *self) NMActRequest *req; const char *method; NMConnection *connection; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; int ip_ifindex; req = nm_device_get_act_request (self); @@ -7878,16 +8312,16 @@ activate_stage5_ip4_config_commit (NMDevice *self) /* 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 (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)) + if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex) && !nm_device_sys_iface_state_is_external_or_assume (self)) { + nm_platform_link_set_up (nm_device_get_platform (self), ip_ifindex, NULL); + if (!nm_platform_link_is_up (nm_device_get_platform (self), 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)) { + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) { _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); - nm_device_ip_method_failed (self, AF_INET, reason); + nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return; } @@ -7908,14 +8342,10 @@ activate_stage5_ip4_config_commit (NMDevice *self) if ( priv->dhcp4.client && nm_device_activate_ip4_state_in_conf (self) && (nm_device_get_state (self) > NM_DEVICE_STATE_IP_CONFIG)) { - /* Notify dispatcher scripts of new DHCP4 config */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, - nm_device_get_settings_connection (self), - nm_device_get_applied_connection (self), - self, - NULL, - NULL, - NULL); + nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP4_CHANGE, + self, + NULL, + NULL, NULL, NULL); } arp_announce (self); @@ -7991,7 +8421,7 @@ dad6_get_pending_addresses (NMDevice *self) num = nm_ip6_config_get_num_addresses (confs[i]); for (j = 0; j < num; j++) { addr = nm_ip6_config_get_address (confs[i], j); - pl_addr = nm_platform_ip6_address_get (NM_PLATFORM_GET, + pl_addr = nm_platform_ip6_address_get (nm_device_get_platform (self), ifindex, addr->address, addr->plen); @@ -8021,7 +8451,6 @@ activate_stage5_ip6_config_commit (NMDevice *self) NMActRequest *req; const char *method; NMConnection *connection; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; int ip_ifindex; int errsv; @@ -8032,26 +8461,23 @@ activate_stage5_ip6_config_commit (NMDevice *self) /* 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 (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)) + if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex) && !nm_device_sys_iface_state_is_external_or_assume (self)) { + nm_platform_link_set_up (nm_device_get_platform (self), ip_ifindex, NULL); + if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex)) _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); } - if (ip6_config_merge_and_apply (self, TRUE, &reason)) { + if (ip6_config_merge_and_apply (self, TRUE)) { if ( priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE && priv->ip6_state == IP_CONF) { if (priv->dhcp6.ip6_config) { /* If IPv6 wasn't the first IP to complete, and DHCP was used, * then ensure dispatcher scripts get the DHCP lease information. */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE, - nm_device_get_settings_connection (self), - nm_device_get_applied_connection (self), - self, - NULL, - NULL, - NULL); + nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP6_CHANGE, + self, + NULL, + NULL, NULL, NULL); } else { /* still waiting for first dhcp6 lease. */ return; @@ -8064,7 +8490,7 @@ activate_stage5_ip6_config_commit (NMDevice *self) method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/all/forwarding"), "1")) { + if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/all/forwarding"), "1")) { errsv = errno; _LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, strerror (errsv)); nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); @@ -8073,18 +8499,21 @@ activate_stage5_ip6_config_commit (NMDevice *self) /* Check if we have to wait for DAD */ if (priv->ip6_state == IP_CONF && !priv->dad6_ip6_config) { - priv->dad6_ip6_config = dad6_get_pending_addresses (self); + if (!priv->carrier && priv->ignore_carrier && get_ip_config_may_fail (self, AF_INET6)) + _LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: carrier missing and ignored, not delaying activation"); + else + priv->dad6_ip6_config = dad6_get_pending_addresses (self); + if (priv->dad6_ip6_config) { - _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: waiting termination"); + _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: awaiting termination"); } else { - /* No tentative addresses, proceed right away */ _set_ip_state (self, AF_INET6, IP_DONE); check_ip_state (self, FALSE); } } } else { _LOGW (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed"); - nm_device_ip_method_failed (self, AF_INET6, reason); + nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_CONFIG_FAILED); } } @@ -8164,7 +8593,24 @@ act_request_set (NMDevice *self, NMActRequest *act_request) "notify::"NM_EXPORTED_OBJECT_PATH, G_CALLBACK (act_request_set_cb), self); + + switch (nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (act_request))) { + case NM_ACTIVATION_TYPE_EXTERNAL: + break; + case NM_ACTIVATION_TYPE_ASSUME: + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_ASSUME); + break; + case NM_ACTIVATION_TYPE_MANAGED: + if (NM_IN_SET_TYPED (NMDeviceSysIfaceState, + priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME)) + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + break; + } } + _notify (self, PROP_ACTIVE_CONNECTION); } @@ -8234,7 +8680,7 @@ delete_on_deactivate_link_delete (gpointer user_data) if (!nm_device_unrealize (data->device, TRUE, &error)) _LOGD (LOGD_DEVICE, "delete_on_deactivate: unrealizing %d failed (%s)", data->ifindex, error->message); } else - nm_platform_link_delete (NM_PLATFORM_GET, data->ifindex); + nm_platform_link_delete (nm_device_get_platform (self), data->ifindex); g_free (data); return FALSE; @@ -8323,12 +8769,14 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type) addrconf6_cleanup (self); } -static gboolean -_hash_check_invalid_keys_impl (GHashTable *hash, const char *setting_name, GError **error, const char **argv) +gboolean +_nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, + GError **error, const char **argv) { guint found_keys = 0; guint i; + nm_assert (hash && g_hash_table_size (hash) > 0); nm_assert (argv && argv[0]); #if NM_MORE_ASSERTS > 10 @@ -8344,9 +8792,6 @@ _hash_check_invalid_keys_impl (GHashTable *hash, const char *setting_name, GErro } #endif - if (!hash || g_hash_table_size (hash) == 0) - return TRUE; - for (i = 0; argv[i]; i++) { if (g_hash_table_contains (hash, argv[i])) found_keys++; @@ -8362,7 +8807,7 @@ _hash_check_invalid_keys_impl (GHashTable *hash, const char *setting_name, GErro g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) { - if (_nm_utils_strv_find_first ((char **) argv, -1, k) < 0) { + if (nm_utils_strv_find_first ((char **) argv, -1, k) < 0) { first_invalid_key = k; break; } @@ -8387,12 +8832,12 @@ _hash_check_invalid_keys_impl (GHashTable *hash, const char *setting_name, GErro return TRUE; } -#define _hash_check_invalid_keys(hash, setting_name, error, ...) _hash_check_invalid_keys_impl (hash, setting_name, error, ((const char *[]) { __VA_ARGS__, NULL })) void nm_device_reactivate_ip4_config (NMDevice *self, NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new) + NMSettingIPConfig *s_ip4_new, + gboolean force_restart) { NMDevicePrivate *priv; const char *method_old, *method_new; @@ -8408,20 +8853,23 @@ nm_device_reactivate_ip4_config (NMDevice *self, s_ip4_new, nm_device_get_ip4_route_metric (self)); - method_old = s_ip4_old ? - nm_setting_ip_config_get_method (s_ip4_old) : - NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - method_new = s_ip4_new ? - nm_setting_ip_config_get_method (s_ip4_new) : - NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + if (!force_restart) { + method_old = s_ip4_old + ? nm_setting_ip_config_get_method (s_ip4_old) + : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + method_new = s_ip4_new + ? nm_setting_ip_config_get_method (s_ip4_new) + : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + force_restart = !nm_streq0 (method_old, method_new); + } - if (!nm_streq0 (method_old, method_new)) { + if (force_restart) { _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE); _set_ip_state (self, AF_INET, IP_WAIT); if (!nm_device_activate_stage3_ip4_start (self)) _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); } else { - if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL)) + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) _LOGW (LOGD_IP4, "Failed to reapply IPv4 configuration"); } } @@ -8430,7 +8878,8 @@ nm_device_reactivate_ip4_config (NMDevice *self, void nm_device_reactivate_ip6_config (NMDevice *self, NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new) + NMSettingIPConfig *s_ip6_new, + gboolean force_restart) { NMDevicePrivate *priv; const char *method_old, *method_new; @@ -8446,31 +8895,108 @@ nm_device_reactivate_ip6_config (NMDevice *self, s_ip6_new, nm_device_get_ip6_route_metric (self)); - method_old = s_ip6_old ? - nm_setting_ip_config_get_method (s_ip6_old) : - NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - method_new = s_ip6_new ? - nm_setting_ip_config_get_method (s_ip6_new) : - NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + if (!force_restart) { + method_old = s_ip6_old + ? nm_setting_ip_config_get_method (s_ip6_old) + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + method_new = s_ip6_new + ? nm_setting_ip_config_get_method (s_ip6_new) + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + force_restart = !nm_streq0 (method_old, method_new); + } - if (!nm_streq0 (method_old, method_new)) { + if (force_restart) { _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE); _set_ip_state (self, AF_INET6, IP_WAIT); if (!nm_device_activate_stage3_ip6_start (self)) _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); } else { - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "Failed to reapply IPv6 configuration"); } } } +static void +_pacrunner_manager_send (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, + &priv->pacrunner_call_id); + + if (!priv->pacrunner_manager) + priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ()); + + priv->pacrunner_call_id = nm_pacrunner_manager_send (priv->pacrunner_manager, + nm_device_get_ip_iface (self), + priv->proxy_config, + NULL, + NULL); +} + +static void +reactivate_proxy_config (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->pacrunner_call_id) + return; + nm_device_set_proxy_config (self, priv->dhcp4.pac_url); + _pacrunner_manager_send (self); +} + +static gboolean +can_reapply_change (NMDevice *self, const char *setting_name, + NMSetting *s_old, NMSetting *s_new, + GHashTable *diffs, GError **error) +{ + if (nm_streq (setting_name, NM_SETTING_CONNECTION_SETTING_NAME)) { + /* Whitelist allowed properties from "connection" setting which are + * allowed to differ. + * + * This includes UUID, there is no principal problem with reapplying a + * connection and changing it's UUID. In fact, disallowing it makes it + * cumbersome for the user to reapply any connection but the original + * settings-connection. */ + return nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_CONNECTION_SETTING_NAME, + error, + NM_SETTING_CONNECTION_ID, + NM_SETTING_CONNECTION_UUID, + NM_SETTING_CONNECTION_STABLE_ID, + NM_SETTING_CONNECTION_AUTOCONNECT, + NM_SETTING_CONNECTION_ZONE, + NM_SETTING_CONNECTION_METERED, + NM_SETTING_CONNECTION_LLDP); + } else if (NM_IN_STRSET (setting_name, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME)) { + /* accept all */ + return TRUE; + } else { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply any changes to '%s' setting", + setting_name); + return FALSE; + } +} + +static void +reapply_connection (NMDevice *self, NMConnection *con_old, NMConnection *con_new) +{ + +} -/* reapply_connection: +/* check_and_reapply_connection: * @connection: the new connection settings to be applied or %NULL to reapply * the current settings connection * @version_id: either zero, or the current version id for the applied * connection. + * @audit_args: on return, a string representing the changes * @error: the error if %FALSE is returned * * Change configuration of an already configured device if possible. @@ -8479,11 +9005,13 @@ nm_device_reactivate_ip6_config (NMDevice *self, * Return: %FALSE if the new configuration can not be reapplied. */ static gboolean -reapply_connection (NMDevice *self, - NMConnection *connection, - guint64 version_id, - GError **error) +check_and_reapply_connection (NMDevice *self, + NMConnection *connection, + guint64 version_id, + char **audit_args, + GError **error) { + NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *applied = nm_device_get_applied_connection (self); gs_unref_object NMConnection *applied_clone = NULL; @@ -8491,6 +9019,7 @@ reapply_connection (NMDevice *self, NMConnection *con_old, *con_new; NMSettingIPConfig *s_ip4_old, *s_ip4_new; NMSettingIPConfig *s_ip6_old, *s_ip6_new; + GHashTableIter iter; if (priv->state != NM_DEVICE_STATE_ACTIVATED) { g_set_error_literal (error, @@ -8506,30 +9035,29 @@ reapply_connection (NMDevice *self, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, &diffs); + if (diffs && nm_audit_manager_audit_enabled (nm_audit_manager_get ())) + *audit_args = nm_utils_format_con_diff_for_audit (diffs); + else + *audit_args = NULL; + /************************************************************************** * check for unsupported changes and reject to reapply *************************************************************************/ - if (!_hash_check_invalid_keys (diffs, NULL, error, - NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_SETTING_NAME, - NM_SETTING_CONNECTION_SETTING_NAME)) - return FALSE; - - /* whitelist allowed properties from "connection" setting which are allowed to differ. - * - * This includes UUID, there is no principal problem with reapplying a connection - * and changing it's UUID. In fact, disallowing it makes it cumbersome for the user - * to reapply any connection but the original settings-connection. */ - if (!_hash_check_invalid_keys (diffs ? g_hash_table_lookup (diffs, NM_SETTING_CONNECTION_SETTING_NAME) : NULL, - NM_SETTING_CONNECTION_SETTING_NAME, - error, - NM_SETTING_CONNECTION_ID, - NM_SETTING_CONNECTION_UUID, - NM_SETTING_CONNECTION_STABLE_ID, - NM_SETTING_CONNECTION_AUTOCONNECT, - NM_SETTING_CONNECTION_ZONE, - NM_SETTING_CONNECTION_METERED)) - return FALSE; + if (diffs) { + char *setting_name; + GHashTable *setting_diff; + + g_hash_table_iter_init (&iter, diffs); + while (g_hash_table_iter_next (&iter, (gpointer *) &setting_name, (gpointer *) &setting_diff)) { + if (!klass->can_reapply_change (self, + setting_name, + nm_connection_get_setting_by_name (applied, setting_name), + nm_connection_get_setting_by_name (connection, setting_name), + setting_diff, + error)) + return FALSE; + } + } if ( version_id != 0 && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request)) { @@ -8548,7 +9076,7 @@ reapply_connection (NMDevice *self, nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request); _LOGD (LOGD_DEVICE, "reapply (version-id %llu%s)", - (long long unsigned) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request)), + (unsigned long long) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request)), diffs ? "" : " (unmodified)"); if (diffs) { @@ -8559,7 +9087,7 @@ reapply_connection (NMDevice *self, NMSettingConnection *s_con_a, *s_con_n; /* we allow re-applying a connection with differing ID, UUID, STABLE_ID and AUTOCONNECT. - * This is for convenience but these values are not actually changable. So, check + * This is for convenience but these values are not actually changeable. So, check * if they changed, and if the did revert to the original values. */ s_con_a = nm_connection_get_setting_connection (applied); s_con_n = nm_connection_get_setting_connection (connection); @@ -8587,20 +9115,27 @@ reapply_connection (NMDevice *self, } else con_old = con_new = applied; - s_ip4_new = nm_connection_get_setting_ip4_config (con_new); - s_ip4_old = nm_connection_get_setting_ip4_config (con_old); - s_ip6_new = nm_connection_get_setting_ip6_config (con_new); - s_ip6_old = nm_connection_get_setting_ip6_config (con_old); + priv->v4_commit_first_time = TRUE; + priv->v6_commit_first_time = TRUE; /************************************************************************** * Reapply changes *************************************************************************/ + klass->reapply_connection (self, con_old, con_new); nm_device_update_firewall_zone (self); nm_device_update_metered (self); + lldp_init (self, FALSE); + + s_ip4_old = nm_connection_get_setting_ip4_config (con_old); + s_ip4_new = nm_connection_get_setting_ip4_config (con_new); + s_ip6_old = nm_connection_get_setting_ip6_config (con_old); + s_ip6_new = nm_connection_get_setting_ip6_config (con_new); - nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new); - nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new); + nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new, TRUE); + nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new, TRUE); + + reactivate_proxy_config (self); return TRUE; } @@ -8621,6 +9156,7 @@ reapply_cb (NMDevice *self, guint64 version_id = 0; gs_unref_object NMConnection *connection = NULL; GError *local = NULL; + gs_free char *audit_args = NULL; if (reapply_data) { connection = reapply_data->connection; @@ -8629,20 +9165,21 @@ reapply_cb (NMDevice *self, } if (error) { - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, error->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, subject, error->message); g_dbus_method_invocation_return_gerror (context, error); return; } - if (!reapply_connection (self, - connection ? : (NMConnection *) nm_device_get_settings_connection (self), - version_id, - &local)) { - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, local->message); + if (!check_and_reapply_connection (self, + connection ? : (NMConnection *) nm_device_get_settings_connection (self), + version_id, + &audit_args, + &local)) { + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, audit_args, subject, local->message); g_dbus_method_invocation_take_error (context, local); local = NULL; } else { - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, subject, NULL); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, audit_args, subject, NULL); g_dbus_method_invocation_return_value (context, NULL); } } @@ -8665,7 +9202,7 @@ impl_device_reapply (NMDevice *self, error = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, context, error->message); g_dbus_method_invocation_take_error (context, error); return; } @@ -8674,7 +9211,7 @@ impl_device_reapply (NMDevice *self, error = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, "Device is not activated"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, context, error->message); g_dbus_method_invocation_take_error (context, error); return; } @@ -8690,7 +9227,7 @@ impl_device_reapply (NMDevice *self, &error); if (!connection) { g_prefix_error (&error, "The settings specified are invalid: "); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, context, error->message); g_dbus_method_invocation_take_error (context, error); return; } @@ -8820,7 +9357,7 @@ disconnect_cb (NMDevice *self, if (error) { g_dbus_method_invocation_return_gerror (context, error); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, error->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, NULL, subject, error->message); return; } @@ -8829,16 +9366,16 @@ disconnect_cb (NMDevice *self, local = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, "Device is not active"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, local->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, NULL, subject, local->message); g_dbus_method_invocation_take_error (context, local); } else { - nm_device_set_autoconnect (self, FALSE); + nm_device_set_autoconnect_intern (self, FALSE); nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_USER_REQUESTED); g_dbus_method_invocation_return_value (context, NULL); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, subject, NULL); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, NULL, subject, NULL); } } @@ -8846,7 +9383,9 @@ static void _clear_queued_act_request (NMDevicePrivate *priv) { if (priv->queued_act_request) { - nm_active_connection_set_state ((NMActiveConnection *) priv->queued_act_request, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + nm_active_connection_set_state ((NMActiveConnection *) priv->queued_act_request, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); g_clear_object (&priv->queued_act_request); } } @@ -8889,12 +9428,12 @@ delete_cb (NMDevice *self, if (error) { g_dbus_method_invocation_return_gerror (context, error); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, FALSE, subject, error->message); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, FALSE, NULL, subject, error->message); return; } /* Authorized */ - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, subject, NULL); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, NULL, subject, NULL); if (nm_device_unrealize (self, TRUE, &local)) g_dbus_method_invocation_return_value (context, NULL); else @@ -9108,12 +9647,11 @@ nm_device_get_proxy_config (NMDevice *self) } static void -nm_device_set_proxy_config (NMDevice *self, GHashTable *options) +nm_device_set_proxy_config (NMDevice *self, const char *pac_url) { NMDevicePrivate *priv; NMConnection *connection; NMSettingProxy *s_proxy = NULL; - char *pac = NULL; g_return_if_fail (NM_IS_DEVICE (self)); @@ -9122,17 +9660,12 @@ nm_device_set_proxy_config (NMDevice *self, GHashTable *options) g_clear_object (&priv->proxy_config); priv->proxy_config = nm_proxy_config_new (); - if (options) { - pac = g_hash_table_lookup (options, "wpad"); - if (pac) { - nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); - nm_proxy_config_set_pac_url (priv->proxy_config, pac); - _LOGD (LOGD_PROXY, "proxy: PAC url \"%s\"", pac); - } else { - nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - _LOGD (LOGD_PROXY, "proxy: PAC url not obtained from DHCP server"); - } - } + if (pac_url) { + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + nm_proxy_config_set_pac_url (priv->proxy_config, pac_url); + _LOGD (LOGD_PROXY, "proxy: PAC url \"%s\"", pac_url); + } else + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); connection = nm_device_get_applied_connection (self); if (connection) @@ -9165,14 +9698,13 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *new_config, guint32 default_route_metric, gboolean commit, - gboolean routes_full_sync, - NMDeviceStateReason *reason) + gboolean routes_full_sync) { NMDevicePrivate *priv; NMIP4Config *old_config = NULL; gboolean has_changes = FALSE; gboolean success = TRUE; - NMDeviceStateReason reason_local = NM_DEVICE_STATE_REASON_NONE; + gboolean def_route_changed; int ip_ifindex, config_ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); @@ -9193,17 +9725,18 @@ nm_device_set_ip4_config (NMDevice *self, /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { - gboolean assumed = nm_device_uses_assumed_connection (self); + gboolean assumed = nm_device_sys_iface_state_is_external_or_assume (self); _commit_mtu (self, 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, + success = nm_ip4_config_commit (new_config, + nm_device_get_platform (self), + nm_netns_get_route_manager (priv->netns), + ip_ifindex, routes_full_sync, assumed ? (gint64) -1 : (gint64) default_route_metric); - if (!success) - reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED; } if (new_config) { @@ -9234,9 +9767,15 @@ nm_device_set_ip4_config (NMDevice *self, g_clear_object (&priv->dev_ip4_config); } - nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self); + def_route_changed = nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); + concheck_periodic_update (self); + + if (!nm_device_sys_iface_state_is_external_or_assume (self)) + ip4_rp_filter_update (self); if (has_changes) { + NMSettingsConnection *settings_connection; + _update_ip4_address (self); if (old_config != priv->ip4_config) @@ -9246,25 +9785,27 @@ nm_device_set_ip4_config (NMDevice *self, if (old_config != priv->ip4_config) nm_exported_object_clear_and_unexport (&old_config); - if (nm_device_uses_generated_assumed_connection (self)) { - NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self)); + if ( nm_device_sys_iface_state_is_external (self) + && (settings_connection = nm_device_get_settings_connection (self)) + && nm_settings_connection_get_nm_generated (settings_connection) + && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request)) == NM_ACTIVATION_TYPE_EXTERNAL) { NMSetting *s_ip4; g_object_freeze_notify (G_OBJECT (settings_connection)); - nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP4_CONFIG); + nm_connection_remove_setting (NM_CONNECTION (settings_connection), NM_TYPE_SETTING_IP4_CONFIG); s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); - nm_connection_add_setting (settings_connection, s_ip4); + nm_connection_add_setting (NM_CONNECTION (settings_connection), s_ip4); g_object_thaw_notify (G_OBJECT (settings_connection)); } nm_device_queue_recheck_assume (self); + } else if (def_route_changed) { + _LOGD (LOGD_IP4, "ip4-config: default route changed"); + g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, priv->ip4_config); } - if (reason) - *reason = reason_local; - return success; } @@ -9310,7 +9851,7 @@ nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *co return; /* NULL to use existing configs */ - if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL)) + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) _LOGW (LOGD_IP4, "failed to set VPN routes for device"); } @@ -9327,7 +9868,7 @@ nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config) priv->wwan_ip4_config = g_object_ref (config); /* NULL to use existing configs */ - if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL)) + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) _LOGW (LOGD_IP4, "failed to set WWAN IPv4 configuration"); } @@ -9335,14 +9876,13 @@ static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *new_config, gboolean commit, - gboolean routes_full_sync, - NMDeviceStateReason *reason) + gboolean routes_full_sync) { NMDevicePrivate *priv; NMIP6Config *old_config = NULL; gboolean has_changes = FALSE; gboolean success = TRUE; - NMDeviceStateReason reason_local = NM_DEVICE_STATE_REASON_NONE; + gboolean def_route_changed; int ip_ifindex, config_ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); @@ -9365,10 +9905,10 @@ nm_device_set_ip6_config (NMDevice *self, if (commit && new_config) { _commit_mtu (self, priv->ip4_config); success = nm_ip6_config_commit (new_config, + nm_device_get_platform (self), + nm_netns_get_route_manager (priv->netns), ip_ifindex, routes_full_sync); - if (!success) - reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED; } if (new_config) { @@ -9393,13 +9933,16 @@ nm_device_set_ip6_config (NMDevice *self, } else if (old_config) { has_changes = TRUE; priv->ip6_config = NULL; + priv->needs_ip6_subnet = FALSE; _LOGD (LOGD_IP6, "ip6-config: clear IP6Config instance (%s)", nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); } - nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self); + def_route_changed = nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); if (has_changes) { + NMSettingsConnection *settings_connection; + if (old_config != priv->ip6_config) _notify (self, PROP_IP6_CONFIG); g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, old_config); @@ -9407,15 +9950,17 @@ nm_device_set_ip6_config (NMDevice *self, if (old_config != priv->ip6_config) nm_exported_object_clear_and_unexport (&old_config); - if (nm_device_uses_generated_assumed_connection (self)) { - NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self)); + if ( nm_device_sys_iface_state_is_external (self) + && (settings_connection = nm_device_get_settings_connection (self)) + && nm_settings_connection_get_nm_generated (settings_connection) + && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request)) == NM_ACTIVATION_TYPE_EXTERNAL) { NMSetting *s_ip6; g_object_freeze_notify (G_OBJECT (settings_connection)); - nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP6_CONFIG); + nm_connection_remove_setting (NM_CONNECTION (settings_connection), NM_TYPE_SETTING_IP6_CONFIG); s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); - nm_connection_add_setting (settings_connection, s_ip6); + nm_connection_add_setting (NM_CONNECTION (settings_connection), s_ip6); g_object_thaw_notify (G_OBJECT (settings_connection)); } @@ -9424,11 +9969,11 @@ nm_device_set_ip6_config (NMDevice *self, if (priv->ndisc) ndisc_set_router_config (priv->ndisc, self); + } else if (def_route_changed) { + _LOGD (LOGD_IP6, "ip6-config: default route changed"); + g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, priv->ip6_config); } - if (reason) - *reason = reason_local; - return success; } @@ -9441,7 +9986,7 @@ nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *co return; /* NULL to use existing configs */ - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed to set VPN routes for device"); } @@ -9458,7 +10003,7 @@ nm_device_set_wwan_ip6_config (NMDevice *self, NMIP6Config *config) priv->wwan_ip6_config = g_object_ref (config); /* NULL to use existing configs */ - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed to set WWAN IPv6 configuration"); } @@ -9522,13 +10067,12 @@ ip_check_pre_up (NMDevice *self) priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_UP, - nm_device_get_settings_connection (self), - nm_device_get_applied_connection (self), - self, - dispatcher_complete_proceed_state, - self, - &priv->dispatcher.call_id)) { + if (!nm_dispatcher_call_device (NM_DISPATCHER_ACTION_PRE_UP, + self, + NULL, + dispatcher_complete_proceed_state, + self, + &priv->dispatcher.call_id)) { /* Just proceed on errors */ dispatcher_complete_proceed_state (0, self); } @@ -9759,7 +10303,7 @@ nm_device_is_up (NMDevice *self) g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); ifindex = nm_device_get_ip_ifindex (self); - return ifindex > 0 ? nm_platform_link_is_up (NM_PLATFORM_GET, ifindex) : TRUE; + return ifindex > 0 ? nm_platform_link_is_up (nm_device_get_platform (self), ifindex) : TRUE; } gboolean @@ -9784,7 +10328,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) if (ifindex <= 0) { /* assume success. */ } else { - if (!nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, no_firmware)) + if (!nm_platform_link_set_up (nm_device_get_platform (self), ifindex, no_firmware)) return FALSE; } @@ -9798,7 +10342,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) do { g_usleep (200); - if (!nm_platform_link_refresh (NM_PLATFORM_GET, ifindex)) + if (!nm_platform_link_refresh (nm_device_get_platform (self), ifindex)) return FALSE; device_is_up = nm_device_is_up (self); } while (!device_is_up && nm_utils_get_monotonic_timestamp_us () < wait_until); @@ -9837,11 +10381,11 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) /* when the link comes up, we must restore IP configuration if necessary. */ if (priv->ip4_state == IP_DONE) { - if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL)) + if (!ip4_config_merge_and_apply (self, NULL, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after bringing link up"); } if (priv->ip6_state == IP_DONE) { - if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after bringing link up"); } @@ -9863,7 +10407,7 @@ nm_device_take_down (NMDevice *self, gboolean block) return; } - if (!nm_platform_link_set_down (NM_PLATFORM_GET, ifindex)) + if (!nm_platform_link_set_down (nm_device_get_platform (self), ifindex)) return; device_is_up = nm_device_is_up (self); @@ -9872,7 +10416,7 @@ nm_device_take_down (NMDevice *self, gboolean block) do { g_usleep (200); - if (!nm_platform_link_refresh (NM_PLATFORM_GET, ifindex)) + if (!nm_platform_link_refresh (nm_device_get_platform (self), ifindex)) return; device_is_up = nm_device_is_up (self); } while (device_is_up && nm_utils_get_monotonic_timestamp_us () < wait_until); @@ -10055,7 +10599,9 @@ update_ip4_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 = nm_ip4_config_capture (nm_device_get_platform (self), + ifindex, + capture_resolv_conf); if (priv->ext_ip4_config) { if (initial) { g_clear_object (&priv->dev_ip4_config); @@ -10094,7 +10640,7 @@ update_ip4_config (NMDevice *self, gboolean initial) if (priv->wwan_ip4_config) nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config); - ip4_config_merge_and_apply (self, NULL, FALSE, NULL); + ip4_config_merge_and_apply (self, NULL, FALSE); } } @@ -10147,7 +10693,7 @@ update_ip6_config (NMDevice *self, gboolean initial) /* IPv6 */ g_clear_object (&priv->ext_ip6_config); g_clear_object (&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self), ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); if (priv->ext_ip6_config_captured) { priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); @@ -10179,7 +10725,7 @@ update_ip6_config (NMDevice *self, gboolean initial) nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config); g_slist_foreach (priv->vpn6_configs, _ip6_config_subtract, priv->ext_ip6_config); - ip6_config_merge_and_apply (self, FALSE, NULL); + ip6_config_merge_and_apply (self, FALSE); } if ( priv->linklocal6_timeout_id @@ -10245,7 +10791,7 @@ queued_ip6_config_change (gpointer user_data) update_ip6_config (self, FALSE); if (priv->state < NM_DEVICE_STATE_DEACTIVATING - && nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex)) { + && nm_platform_link_get (nm_device_get_platform (self), priv->ifindex)) { /* Handle DAD failures */ for (iter = priv->dad6_failed_addrs; iter; iter = g_slist_next (iter)) { NMPlatformIP6Address *addr = iter->data; @@ -10573,6 +11119,8 @@ _set_unmanaged_flags (NMDevice *self, const char *operation = NULL; char str1[512]; char str2[512]; + gboolean do_notify_has_pending_actions = FALSE; + gboolean had_pending_actions = FALSE; g_return_if_fail (NM_IS_DEVICE (self)); g_return_if_fail (flags); @@ -10608,6 +11156,11 @@ _set_unmanaged_flags (NMDevice *self, nm_assert_se (!nm_clear_g_source (&priv->queued_ip6_config_id)); priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); } + + if (!priv->pending_actions) { + do_notify_has_pending_actions = TRUE; + had_pending_actions = nm_device_has_pending_action (self); + } } old_flags = priv->unmanaged_flags; @@ -10643,19 +11196,16 @@ _set_unmanaged_flags (NMDevice *self, || ( !was_managed && nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)); -#define _FMTX "[%s%s0x%0x/0x%x/%s" -#define _FMT(flags, mask, str) \ - _unmanaged_flags2str ((flags), (mask), str, sizeof (str)), \ - ((flags) | (mask)) ? "=" : "", \ - (flags), \ - (mask), \ - (_get_managed_by_flags (flags, mask, FALSE) \ - ? "managed" \ - : (_get_managed_by_flags (flags, mask, TRUE) \ - ? "manageable" \ - : "unmanaged")) - _LOGD (LOGD_DEVICE, "unmanaged: flags set to "_FMTX"%s, %s [%s=0x%0x]%s%s%s)", - _FMT (priv->unmanaged_flags, priv->unmanaged_mask, str1), + _LOGD (LOGD_DEVICE, "unmanaged: flags set to [%s%s0x%0x/0x%x/%s%s], %s [%s=0x%0x]%s%s%s)", + _unmanaged_flags2str (priv->unmanaged_flags, priv->unmanaged_mask, str1, sizeof (str1)), \ + (priv->unmanaged_flags | priv->unmanaged_mask) ? "=" : "", \ + (guint) priv->unmanaged_flags, \ + (guint) priv->unmanaged_mask, \ + (_get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, FALSE) \ + ? "managed" \ + : (_get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, TRUE) \ + ? "manageable" \ + : "unmanaged")), priv->real ? "" : "/unrealized", operation, nm_unmanaged_flags2str (flags, str2, sizeof (str2)), @@ -10665,7 +11215,10 @@ _set_unmanaged_flags (NMDevice *self, reason_to_string (reason), transition_state ? ", transition-state" : "", "")); -#undef _FMT + + if ( do_notify_has_pending_actions + && had_pending_actions != nm_device_has_pending_action (self)) + _notify (self, PROP_HAS_PENDING_ACTION); if (transition_state) { new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE; @@ -10762,7 +11315,7 @@ nm_device_set_unmanaged_by_user_udev (NMDevice *self) ifindex = self->_priv->ifindex; if ( ifindex <= 0 - || !nm_platform_link_get_unmanaged (NM_PLATFORM_GET, ifindex, &platform_unmanaged)) + || !nm_platform_link_get_unmanaged (nm_device_get_platform (self), ifindex, &platform_unmanaged)) return; nm_device_set_unmanaged_by_flags (self, @@ -10847,7 +11400,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) nm_setting_connection_get_zone (s_con_applied)) != 0) { version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request); - _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (long long unsigned) version_id); + _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (unsigned long long) version_id); g_object_set (G_OBJECT (s_con_applied), NM_SETTING_CONNECTION_ZONE, zone, @@ -10859,7 +11412,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) { version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request); - _LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (long long unsigned) version_id); + _LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (unsigned long long) version_id); g_object_set (G_OBJECT (s_con_applied), NM_SETTING_CONNECTION_METERED, metered, @@ -10872,25 +11425,15 @@ nm_device_reapply_settings_immediately (NMDevice *self) void nm_device_update_firewall_zone (NMDevice *self) { - NMConnection *applied_connection; - NMSettingConnection *s_con; + NMDevicePrivate *priv; g_return_if_fail (NM_IS_DEVICE (self)); - applied_connection = nm_device_get_applied_connection (self); - if (!applied_connection) - return; + priv = NM_DEVICE_GET_PRIVATE (self); - s_con = nm_connection_get_setting_connection (applied_connection); - if ( nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED - && !nm_device_uses_generated_assumed_connection (self)) { - nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - nm_device_get_ip_iface (self), - nm_setting_connection_get_zone (s_con), - FALSE, /* change zone */ - NULL, - NULL); - } + if ( priv->fw_state >= FIREWALL_STATE_INITIALIZED + && !nm_device_sys_iface_state_is_external (self)) + fw_change_zone (self); } void @@ -11234,7 +11777,7 @@ cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpoin gboolean nm_device_supports_vlans (NMDevice *self) { - return nm_platform_link_supports_vlans (NM_PLATFORM_GET, nm_device_get_ifindex (self)); + return nm_platform_link_supports_vlans (nm_device_get_platform (self), nm_device_get_ifindex (self)); } /** @@ -11340,7 +11883,16 @@ nm_device_has_pending_action (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - return !!priv->pending_actions; + if (priv->pending_actions) + return TRUE; + + if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { + /* as long as the platform link is not yet initialized, we have a pending + * action. */ + return TRUE; + } + + return FALSE; } /*****************************************************************************/ @@ -11350,13 +11902,12 @@ _cancel_activation (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - /* Clean up when device was deactivated during call to firewall */ if (priv->fw_call) { nm_firewall_manager_cancel_call (priv->fw_call); - g_warn_if_fail (!priv->fw_call); + nm_assert (!priv->fw_call); priv->fw_call = NULL; + priv->fw_state = FIREWALL_STATE_INITIALIZED; } - priv->fw_ready = FALSE; ip_check_gw_ping_cleanup (self); @@ -11368,20 +11919,22 @@ _cancel_activation (NMDevice *self) static void _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type) { - NMConnection *connection; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); _cancel_activation (self); - connection = nm_device_get_applied_connection (self); if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE - && connection - && !nm_device_uses_generated_assumed_connection (self)) { - nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (), + && priv->fw_state >= FIREWALL_STATE_INITIALIZED + && priv->fw_mgr + && !nm_device_sys_iface_state_is_external (self)) { + nm_firewall_manager_remove_from_zone (priv->fw_mgr, nm_device_get_ip_iface (self), NULL, NULL, NULL); } + priv->fw_state = FIREWALL_STATE_UNMANAGED; + g_clear_object (&priv->fw_mgr); queued_state_clear (self); @@ -11412,8 +11965,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) /* Clean up IP configs; this does not actually deconfigure the * interface; the caller must flush routes and addresses explicitly. */ - nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE, NULL); - nm_device_set_ip6_config (self, NULL, TRUE, TRUE, NULL); + nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE); + nm_device_set_ip6_config (self, NULL, TRUE, TRUE); g_clear_object (&priv->proxy_config); g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->dev_ip4_config); @@ -11433,7 +11986,9 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) g_slist_free_full (priv->vpn6_configs, g_object_unref); priv->vpn6_configs = NULL; - priv->needs_ip6_subnet = FALSE; + /* We no longer accept the delegations. nm_device_set_ip6_config(NULL) + * above disables them. */ + nm_assert (priv->needs_ip6_subnet == FALSE); if (priv->act_request) { nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); @@ -11499,20 +12054,20 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean if (NM_DEVICE_GET_CLASS (self)->deactivate) NM_DEVICE_GET_CLASS (self)->deactivate (self); - if (cleanup_type != CLEANUP_TYPE_KEEP) { + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { /* master: release slaves */ nm_device_master_release_slaves (self); /* slave: mark no longer enslaved */ if ( priv->master - && nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) <= 0) + && nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0) nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); /* Take out any entries in the routing table and any IP address the device had. */ ifindex = nm_device_get_ip_ifindex (self); if (ifindex > 0) { - nm_route_manager_route_flush (nm_route_manager_get (), ifindex); - nm_platform_address_flush (NM_PLATFORM_GET, ifindex); + nm_route_manager_route_flush (nm_netns_get_route_manager (priv->netns), ifindex); + nm_platform_address_flush (nm_device_get_platform (self), ifindex); } } @@ -11543,7 +12098,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean _LOGT (LOGD_DEVICE, "mtu: reset device-mtu: %u, ipv6-mtu: %u, ifindex: %d", (guint) priv->mtu_initial, (guint) priv->ip6_mtu_initial, ifindex); if (priv->mtu_initial) - nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, priv->mtu_initial); + nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, priv->mtu_initial); if (priv->ip6_mtu_initial) { char sbuf[64]; @@ -11655,7 +12210,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--dhcp4-required")); if (priv->dhcp4.client) { - const char *hostname, *fqdn; + const char *hostname; GBytes *client_id; client_id = nm_dhcp_client_get_client_id (priv->dhcp4.client); @@ -11669,15 +12224,12 @@ nm_device_spawn_iface_helper (NMDevice *self) hostname = nm_dhcp_client_get_hostname (priv->dhcp4.client); if (hostname) { - g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname")); + if (nm_dhcp_client_get_use_fqdn (priv->dhcp4.client)) + g_ptr_array_add (argv, g_strdup ("--dhcp4-fqdn")); + else + g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname")); g_ptr_array_add (argv, g_strdup (hostname)); } - - fqdn = nm_dhcp_client_get_fqdn (priv->dhcp4.client); - if (fqdn) { - g_ptr_array_add (argv, g_strdup ("--dhcp4-fqdn")); - g_ptr_array_add (argv, g_strdup (fqdn)); - } } configured = TRUE; @@ -11788,9 +12340,8 @@ deactivate_async_ready (NMDevice *self, if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || (priv->deactivating_cancellable && g_cancellable_is_cancelled (priv->deactivating_cancellable))) { _LOGW (LOGD_DEVICE, "Deactivation cancelled"); - } - /* In every other case, transition to the DISCONNECTED state */ - else { + } else { + /* In every other case, transition to the DISCONNECTED state */ if (error) { _LOGW (LOGD_DEVICE, "Deactivation failed: %s", error->message); @@ -11818,11 +12369,8 @@ deactivate_dispatcher_complete (guint call_id, gpointer user_data) priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - if (priv->deactivating_cancellable) { + if (nm_clear_g_cancellable (&priv->deactivating_cancellable)) g_warn_if_reached (); - g_cancellable_cancel (priv->deactivating_cancellable); - g_clear_object (&priv->deactivating_cancellable); - } if ( NM_DEVICE_GET_CLASS (self)->deactivate_async && NM_DEVICE_GET_CLASS (self)->deactivate_async_finish) { @@ -11846,7 +12394,6 @@ _set_state_full (NMDevice *self, NMActRequest *req; gboolean no_firmware = FALSE; NMSettingsConnection *connection; - NMConnection *applied_connection; g_return_if_fail (NM_IS_DEVICE (self)); @@ -11897,6 +12444,15 @@ _set_state_full (NMDevice *self, /* Cache the activation request for the dispatcher */ req = nm_g_object_ref (priv->act_request); + if ( state > NM_DEVICE_STATE_UNMANAGED + && state <= NM_DEVICE_STATE_ACTIVATED + && nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NOW_MANAGED + && NM_IN_SET_TYPED (NMDeviceSysIfaceState, + priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME)) + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + if (state <= NM_DEVICE_STATE_UNAVAILABLE) { if (available_connections_del_all (self)) _notify (self, PROP_AVAILABLE_CONNECTIONS); @@ -11920,10 +12476,11 @@ _set_state_full (NMDevice *self, case NM_DEVICE_STATE_UNMANAGED: nm_device_set_firmware_missing (self, FALSE); if (old_state > NM_DEVICE_STATE_UNMANAGED) { - if (reason == NM_DEVICE_STATE_REASON_REMOVED) { - nm_device_cleanup (self, reason, CLEANUP_TYPE_REMOVED); - } else if (reason == NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { - nm_device_cleanup (self, reason, CLEANUP_TYPE_KEEP); + if (priv->sys_iface_state != NM_DEVICE_SYS_IFACE_STATE_MANAGED) { + nm_device_cleanup (self, reason, + priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_REMOVED + ? CLEANUP_TYPE_REMOVED + : CLEANUP_TYPE_KEEP); } else { /* Clean up if the device is now unmanaged but was activated */ if (nm_device_get_act_request (self)) @@ -11932,17 +12489,18 @@ _set_state_full (NMDevice *self, nm_device_hw_addr_reset (self, "unmanage"); set_nm_ipv6ll (self, FALSE); restore_ip6_properties (self); + break; } } break; case NM_DEVICE_STATE_UNAVAILABLE: if (old_state == NM_DEVICE_STATE_UNMANAGED) { save_ip6_properties (self); - if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) ip6_managed_setup (self); } - if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) { if (!nm_device_bring_up (self, TRUE, &no_firmware) && no_firmware) _LOGW (LOGD_PLATFORM, "firmware may be missing."); @@ -11969,7 +12527,7 @@ _set_state_full (NMDevice *self, nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); } else if (old_state < NM_DEVICE_STATE_DISCONNECTED) { - if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { /* Ensure IPv6 is set up as it may not have been done when * entering the UNAVAILABLE state depending on the reason. */ @@ -11996,11 +12554,11 @@ _set_state_full (NMDevice *self, /* Reset autoconnect flag when the device is activating or connected. */ if ( state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) - nm_device_set_autoconnect (self, TRUE); + nm_device_set_autoconnect_intern (self, TRUE); _notify (self, PROP_STATE); _notify (self, PROP_STATE_REASON); - g_signal_emit (self, signals[STATE_CHANGED], 0, state, old_state, reason); + g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) state, (guint) old_state, (guint) reason); /* Post-process the event after internal notification */ @@ -12028,27 +12586,24 @@ _set_state_full (NMDevice *self, priv->ignore_carrier = nm_config_data_get_ignore_carrier (NM_CONFIG_GET_DATA, self); if (quitting) { - nm_dispatcher_call_sync (DISPATCHER_ACTION_PRE_DOWN, - nm_act_request_get_settings_connection (req), - nm_act_request_get_applied_connection (req), - self); + nm_dispatcher_call_device_sync (NM_DISPATCHER_ACTION_PRE_DOWN, + self, req); } else { priv->dispatcher.post_state = NM_DEVICE_STATE_DISCONNECTED; priv->dispatcher.post_state_reason = reason; - if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_DOWN, - nm_act_request_get_settings_connection (req), - nm_act_request_get_applied_connection (req), - self, - deactivate_dispatcher_complete, - self, - &priv->dispatcher.call_id)) { + if (!nm_dispatcher_call_device (NM_DISPATCHER_ACTION_PRE_DOWN, + self, + req, + deactivate_dispatcher_complete, + self, + &priv->dispatcher.call_id)) { /* Just proceed on errors */ deactivate_dispatcher_complete (0, self); } } - /* Remove config from PacRunner */ - nm_pacrunner_manager_remove (priv->pacrunner_manager, nm_device_get_ip_iface (self)); + nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, + &priv->pacrunner_call_id); break; case NM_DEVICE_STATE_DISCONNECTED: if ( priv->queued_act_request @@ -12068,18 +12623,13 @@ _set_state_full (NMDevice *self, case NM_DEVICE_STATE_ACTIVATED: _LOGI (LOGD_DEVICE, "Activation: successful, device activated."); nm_device_update_metered (self); - nm_dispatcher_call (DISPATCHER_ACTION_UP, - nm_act_request_get_settings_connection (req), - nm_act_request_get_applied_connection (req), - self, NULL, NULL, NULL); - - if (priv->proxy_config) { - nm_pacrunner_manager_send (priv->pacrunner_manager, - nm_device_get_ip_iface (self), - priv->proxy_config, - priv->ip4_config, - priv->ip6_config); - } + nm_dispatcher_call_device (NM_DISPATCHER_ACTION_UP, + self, + req, + NULL, NULL, NULL); + + if (priv->proxy_config) + _pacrunner_manager_send (self); break; case NM_DEVICE_STATE_FAILED: /* Usually upon failure the activation chain is interrupted in @@ -12090,7 +12640,7 @@ _set_state_full (NMDevice *self, */ _cancel_activation (self); - if (nm_device_uses_assumed_connection (self)) { + if (nm_device_sys_iface_state_is_external_or_assume (self)) { /* Avoid tearing down assumed connection, assume it's connected */ nm_device_queue_state (self, NM_DEVICE_STATE_ACTIVATED, @@ -12121,26 +12671,11 @@ _set_state_full (NMDevice *self, nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); break; case NM_DEVICE_STATE_IP_CHECK: - /* Now that IP config has completed, check if the firewall - * zone must be set again for the IP interface. - */ - applied_connection = nm_device_get_applied_connection (self); - - if ( applied_connection - && priv->ifindex != priv->ip_ifindex - && !nm_device_uses_generated_assumed_connection (self)) { - NMSettingConnection *s_con; - const char *zone; - - s_con = nm_connection_get_setting_connection (applied_connection); - zone = nm_setting_connection_get_zone (s_con); - g_assert (!priv->fw_call); - priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - nm_device_get_ip_iface (self), - zone, - FALSE, - fw_change_zone_cb_ip_check, - self); + if ( priv->fw_state >= FIREWALL_STATE_INITIALIZED + && priv->ip_iface + && !nm_device_sys_iface_state_is_external (self)) { + priv->fw_state = FIREWALL_STATE_WAIT_IP_CONFIG; + fw_change_zone (self); } else nm_device_start_ip_check (self); @@ -12163,15 +12698,13 @@ _set_state_full (NMDevice *self, if ( (old_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_DEACTIVATING) && (state != NM_DEVICE_STATE_DEACTIVATING)) { if (quitting) { - nm_dispatcher_call_sync (DISPATCHER_ACTION_DOWN, - nm_act_request_get_settings_connection (req), - nm_act_request_get_applied_connection (req), - self); + nm_dispatcher_call_device_sync (NM_DISPATCHER_ACTION_DOWN, + self, req); } else { - nm_dispatcher_call (DISPATCHER_ACTION_DOWN, - nm_act_request_get_settings_connection (req), - nm_act_request_get_applied_connection (req), - self, NULL, NULL, NULL); + nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DOWN, + self, + req, + NULL, NULL, NULL); } } @@ -12181,6 +12714,8 @@ _set_state_full (NMDevice *self, if (ip_config_valid (old_state) && !ip_config_valid (state)) notify_ip_properties (self); + concheck_periodic_update (self); + /* Dispose of the cached activation request */ if (req) g_object_unref (req); @@ -12334,7 +12869,7 @@ nm_device_update_hw_address (NMDevice *self) if (priv->ifindex <= 0) return FALSE; - hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &hwaddrlen); + hwaddr = nm_platform_link_get_address (nm_device_get_platform (self), priv->ifindex, &hwaddrlen); if ( priv->type == NM_DEVICE_TYPE_ETHERNET && hwaddr @@ -12428,7 +12963,7 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze) /* the user is advised to configure stable MAC addresses for software devices via * UDEV. Thus, check whether the link is fully initialized. */ - pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); + pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); if ( !pllink || !pllink->initialized) { if (!force_freeze) { @@ -12437,7 +12972,7 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze) return; } /* try to refresh the link just to give UDEV a bit more time... */ - nm_platform_link_refresh (NM_PLATFORM_GET, ifindex); + nm_platform_link_refresh (nm_device_get_platform (self), ifindex); /* maybe the MAC address changed... */ nm_device_update_hw_address (self); } else if (!priv->hw_addr_len) @@ -12451,7 +12986,7 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze) return; } - success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, ifindex, buf, &len); + success_read = nm_platform_link_get_permanent_address (nm_device_get_platform (self), ifindex, buf, &len); if (success_read && priv->hw_addr_len == len) { priv->hw_addr_perm_fake = FALSE; priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, len); @@ -12474,7 +13009,7 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze) { gs_free NMConfigDeviceStateData *dev_state = NULL; - dev_state = nm_config_device_state_load (nm_config_get (), ifindex); + dev_state = nm_config_device_state_load (ifindex); if ( dev_state && dev_state->perm_hw_addr_fake && nm_utils_hwaddr_aton (dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len) @@ -12639,7 +13174,7 @@ _hw_addr_set (NMDevice *self, nm_device_take_down (self, FALSE); } - plerr = nm_platform_link_set_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), addr_bytes, addr_len); + plerr = nm_platform_link_set_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), addr_bytes, addr_len); success = (plerr == NM_PLATFORM_ERROR_SUCCESS); if (success) { /* MAC address succesfully changed; update the current MAC to match */ @@ -12670,7 +13205,7 @@ _hw_addr_set (NMDevice *self, poll_end = nm_utils_get_monotonic_timestamp_us () + (100 * 1000); for (;;) { - if (!nm_platform_link_refresh (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self))) + if (!nm_platform_link_refresh (nm_device_get_platform (self), nm_device_get_ip_ifindex (self))) goto handle_fail; if (!nm_device_update_hw_address (self)) goto handle_wait; @@ -12739,49 +13274,92 @@ nm_device_hw_addr_set (NMDevice *self, return _hw_addr_set (self, addr, "set", detail); } -gboolean -nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi) +/* + * _hw_addr_get_cloned: + * @self: a #NMDevice + * @connection: a #NMConnection + * @is_wifi: whether the device is Wi-Fi + * @preserve: (out): whether the address must be reset to initial one + * @hwaddr: (out): the cloned MAC address to set on interface + * @hwaddr_type: (out): the type of address to set + * @hwaddr_detail: (out): the detail (origin) of address to set + * @error: (out): on return, an error or %NULL + * + * Computes the MAC to be set on a interface. On success, one of the + * following exclusive conditions are verified: + * + * - @preserve is %TRUE: the address must be reset to the initial one + * - @hwaddr is not %NULL: the given address must be set on the device + * - @hwaddr is %NULL and @preserve is %FALSE: no action needed + * + * Returns: %FALSE in case of error in determining the cloned MAC address, + * %TRUE otherwise + */ +static gboolean +_hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, + gboolean *preserve, char **hwaddr, HwAddrType *hwaddr_type, + char **hwaddr_detail, GError **error) { NMDevicePrivate *priv; - gs_free char *hw_addr_tmp = NULL; + gs_free char *addr_setting_free = NULL; gs_free char *hw_addr_generated = NULL; gs_free char *generate_mac_address_mask_tmp = NULL; const char *addr, *addr_setting; + char *addr_out; + HwAddrType type_out; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (!error || !*error, FALSE); priv = NM_DEVICE_GET_PRIVATE (self); if (!connection) g_return_val_if_reached (FALSE); - addr = addr_setting = _get_cloned_mac_address_setting (self, connection, is_wifi, &hw_addr_tmp); + addr = addr_setting = _get_cloned_mac_address_setting (self, connection, is_wifi, &addr_setting_free); if (nm_streq (addr, NM_CLONED_MAC_PRESERVE)) { /* "preserve" means to reset the initial MAC address. */ - return nm_device_hw_addr_reset (self, addr_setting); + NM_SET_OUT (preserve, TRUE); + NM_SET_OUT (hwaddr, NULL); + NM_SET_OUT (hwaddr_type, HW_ADDR_TYPE_UNSET); + NM_SET_OUT (hwaddr_detail, g_steal_pointer (&addr_setting_free) ?: g_strdup (addr_setting)); + return TRUE; } if (nm_streq (addr, NM_CLONED_MAC_PERMANENT)) { addr = nm_device_get_permanent_hw_address (self); - if (!addr) + if (!addr) { + g_set_error_literal (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "failed to retrieve permanent address"); return FALSE; - priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT; + } + addr_out = g_strdup (addr); + type_out = HW_ADDR_TYPE_PERMANENT; } else if (NM_IN_STRSET (addr, NM_CLONED_MAC_RANDOM)) { if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { /* hm, we already use a generate MAC address. Most certainly, that is from the same * activation request, so we should not create a new random address, instead keep * the current. */ - return TRUE; + goto out_no_action; } hw_addr_generated = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (self), - _get_generate_mac_address_mask_setting (self, connection, is_wifi, &generate_mac_address_mask_tmp)); + _get_generate_mac_address_mask_setting (self, connection, + is_wifi, + &generate_mac_address_mask_tmp)); if (!hw_addr_generated) { - _LOGW (LOGD_DEVICE, "set-hw-addr: failed to generate %s MAC address", "random"); + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "failed to generate %s MAC address", "random"); return FALSE; } - priv->hw_addr_type = HW_ADDR_TYPE_GENERATED; - addr = hw_addr_generated; + + addr_out = g_steal_pointer (&hw_addr_generated); + type_out = HW_ADDR_TYPE_GENERATED; } else if (NM_IN_STRSET (addr, NM_CLONED_MAC_STABLE)) { NMUtilsStableType stable_type; const char *stable_id; @@ -12789,7 +13367,7 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { /* hm, we already use a generate MAC address. Most certainly, that is from the same * activation request, so let's skip creating the stable address anew. */ - return TRUE; + goto out_no_action; } stable_id = _get_stable_id (self, connection, &stable_type); @@ -12800,19 +13378,74 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean _get_generate_mac_address_mask_setting (self, connection, is_wifi, &generate_mac_address_mask_tmp)); } if (!hw_addr_generated) { - _LOGW (LOGD_DEVICE, "set-hw-addr: failed to generate %s MAC address", "stable"); + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "failed to generate %s MAC address", "stable"); return FALSE; } - priv->hw_addr_type = HW_ADDR_TYPE_GENERATED; - addr = hw_addr_generated; + + addr_out = g_steal_pointer (&hw_addr_generated); + type_out = HW_ADDR_TYPE_GENERATED; } else { /* this must be a valid address. Otherwise, we shouldn't come here. */ if (!nm_utils_hwaddr_valid (addr, -1)) g_return_val_if_reached (FALSE); - priv->hw_addr_type = HW_ADDR_TYPE_EXPLICIT; + + addr_out = g_strdup (addr); + type_out = HW_ADDR_TYPE_EXPLICIT; + } + + NM_SET_OUT (preserve, FALSE); + NM_SET_OUT (hwaddr, addr_out); + NM_SET_OUT (hwaddr_type, type_out); + NM_SET_OUT (hwaddr_detail, g_steal_pointer (&addr_setting_free) ?: g_strdup (addr_setting)); + return TRUE; +out_no_action: + NM_SET_OUT (preserve, FALSE); + NM_SET_OUT (hwaddr, NULL); + NM_SET_OUT (hwaddr_type, HW_ADDR_TYPE_UNSET); + NM_SET_OUT (hwaddr_detail, NULL); + return TRUE; +} + +gboolean +nm_device_hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, + char **hwaddr, gboolean *preserve, GError **error) +{ + if (!_hw_addr_get_cloned (self, connection, is_wifi, preserve, hwaddr, NULL, NULL, error)) + return FALSE; + + return TRUE; +} + +gboolean +nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi) +{ + NMDevicePrivate *priv; + gboolean preserve = FALSE; + gs_free char *hwaddr = NULL; + gs_free char *detail = NULL; + HwAddrType type = HW_ADDR_TYPE_UNSET; + gs_free_error GError *error = NULL; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + priv = NM_DEVICE_GET_PRIVATE (self); + + if (!_hw_addr_get_cloned (self, connection, is_wifi, &preserve, &hwaddr, &type, &detail, &error)) { + _LOGW (LOGD_DEVICE, "set-hw-addr: %s", error->message); + return FALSE; + } + + if (preserve) + return nm_device_hw_addr_reset (self, detail); + + if (hwaddr) { + priv->hw_addr_type = type; + return _hw_addr_set (self, hwaddr, "set-cloned", detail); } - return _hw_addr_set (self, addr, "set-cloned", addr_setting); + return TRUE; } gboolean @@ -12908,11 +13541,40 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs) m = nm_match_spec_device (specs, nm_device_get_iface (self), nm_device_get_type_description (self), + nm_device_get_driver (self), + nm_device_get_driver_version (self), nm_device_get_permanent_hw_address (self), klass->get_s390_subchannels ? klass->get_s390_subchannels (self) : NULL); return m == NM_MATCH_SPEC_MATCH; } +guint +nm_device_get_supplicant_timeout (NMDevice *self) +{ + NMConnection *connection; + NMSetting8021x *s_8021x; + gs_free char *value = NULL; + gint timeout; +#define SUPPLICANT_DEFAULT_TIMEOUT 25 + + g_return_val_if_fail (NM_IS_DEVICE (self), SUPPLICANT_DEFAULT_TIMEOUT); + + connection = nm_device_get_applied_connection (self); + g_return_val_if_fail (connection, SUPPLICANT_DEFAULT_TIMEOUT); + s_8021x = nm_connection_get_setting_802_1x (connection); + if (s_8021x) { + timeout = nm_setting_802_1x_get_auth_timeout (s_8021x); + if (timeout > 0) + return timeout; + } + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "802-1x.auth-timeout", + self); + return _nm_utils_ascii_str_to_int64 (value, 10, 1, G_MAXINT32, + SUPPLICANT_DEFAULT_TIMEOUT); +} + /*****************************************************************************/ static const char * @@ -12944,19 +13606,19 @@ nm_device_init (NMDevice *self) self->_priv = priv; + priv->netns = g_object_ref (NM_NETNS_GET); + priv->type = NM_DEVICE_TYPE_UNKNOWN; priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; priv->state = NM_DEVICE_STATE_UNMANAGED; priv->state_reason = NM_DEVICE_STATE_REASON_NONE; priv->dhcp_timeout = 0; priv->rfkill_type = RFKILL_TYPE_UNKNOWN; - priv->autoconnect = DEFAULT_AUTOCONNECT; priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT; priv->unmanaged_mask = priv->unmanaged_flags; priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); - - priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ()); + priv->sys_iface_state = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; priv->default_route.v4_is_assumed = TRUE; priv->default_route.v6_is_assumed = TRUE; @@ -12986,7 +13648,7 @@ constructor (GType type, if ( priv->iface && G_LIKELY (!nm_utils_get_testing ())) { - pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface); + pllink = nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) { priv->ifindex = pllink->ifindex; @@ -13022,13 +13684,16 @@ constructed (GObject *object) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); /* Watch for external IP config changes */ - platform = NM_PLATFORM_GET; + platform = nm_device_get_platform (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); + g_signal_connect (nm_netns_get_route_manager (priv->netns), NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED, + G_CALLBACK (ip4_routes_changed_changed_cb), self); + priv->settings = g_object_ref (NM_SETTINGS_GET); g_assert (priv->settings); @@ -13059,21 +13724,28 @@ dispose (GObject *object) _LOGD (LOGD_DEVICE, "disposing"); + nm_clear_g_cancellable (&priv->deactivating_cancellable); + _parent_set_ifindex (self, 0, FALSE); - platform = NM_PLATFORM_GET; + platform = nm_device_get_platform (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); + g_signal_handlers_disconnect_by_func (nm_netns_get_route_manager (priv->netns), + G_CALLBACK (ip4_routes_changed_changed_cb), self); + g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy); priv->arping.dad_list = NULL; arp_cleanup (self); - nm_clear_g_signal_handler (nm_config_get (), &priv->ignore_carrier_id); + nm_clear_g_signal_handler (nm_config_get (), &priv->config_changed_id); dispatcher_cleanup (self); + nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, + &priv->pacrunner_call_id); g_clear_object (&priv->pacrunner_manager); _cleanup_generic_pre (self, CLEANUP_TYPE_KEEP); @@ -13169,6 +13841,8 @@ finalize (GObject *object) * and thus @settings might be unset. */ if (priv->settings) g_object_unref (priv->settings); + + g_object_unref (priv->netns); } static void @@ -13213,8 +13887,10 @@ set_property (GObject *object, guint prop_id, managed = g_value_get_boolean (value); if (managed) reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - else + else { reason = NM_DEVICE_STATE_REASON_REMOVED; + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_REMOVED); + } nm_device_set_unmanaged_by_flags (self, NM_UNMANAGED_USER_EXPLICIT, !managed, @@ -13222,7 +13898,7 @@ set_property (GObject *object, guint prop_id, } break; case PROP_AUTOCONNECT: - nm_device_set_autoconnect (self, g_value_get_boolean (value)); + nm_device_set_autoconnect_both (self, g_value_get_boolean (value)); break; case PROP_FIRMWARE_MISSING: /* construct-only */ @@ -13348,7 +14024,7 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, nm_device_get_state (self) > NM_DEVICE_STATE_UNMANAGED); break; case PROP_AUTOCONNECT: - g_value_set_boolean (value, priv->autoconnect); + g_value_set_boolean (value, nm_device_get_autoconnect (self)); break; case PROP_FIRMWARE_MISSING: g_value_set_boolean (value, priv->firmware_missing); @@ -13440,6 +14116,9 @@ get_property (GObject *object, guint prop_id, case PROP_RX_BYTES: g_value_set_uint64 (value, priv->stats.rx_bytes); break; + case PROP_CONNECTIVITY: + g_value_set_uint (value, priv->connectivity_state); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -13475,6 +14154,7 @@ nm_device_class_init (NMDeviceClass *klass) klass->have_any_ready_slaves = have_any_ready_slaves; klass->get_type_description = get_type_description; + klass->get_autoconnect_allowed = get_autoconnect_allowed; klass->can_auto_connect = can_auto_connect; klass->check_connection_compatible = check_connection_compatible; klass->check_connection_available = check_connection_available; @@ -13486,6 +14166,8 @@ nm_device_class_init (NMDeviceClass *klass) klass->unmanaged_on_quit = unmanaged_on_quit; klass->deactivate_reset_hw_addr = deactivate_reset_hw_addr; klass->parent_changed_notify = parent_changed_notify; + klass->can_reapply_change = can_reapply_change; + klass->reapply_connection = reapply_connection; obj_properties[PROP_UDI] = g_param_spec_string (NM_DEVICE_UDI, "", "", @@ -13707,6 +14389,13 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /* Connectivity */ + obj_properties[PROP_CONNECTIVITY] = + g_param_spec_uint (NM_DEVICE_CONNECTIVITY, "", "", + NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[STATE_CHANGED] = diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index e512f2ca..be328eb6 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2013 Red Hat, Inc. + * Copyright (C) 2005 - 2017 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -30,6 +30,34 @@ #include "nm-rfkill-manager.h" #include "NetworkManagerUtils.h" +typedef enum { + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME, + NM_DEVICE_SYS_IFACE_STATE_MANAGED, + + /* the REMOVED state applies when the device is manually set to unmanaged + * or the link was externally removed. In both cases, we move the device + * to UNMANAGED state, without touching the link -- be it, because the link + * is already gone or because we want to release it (give it up). + */ + NM_DEVICE_SYS_IFACE_STATE_REMOVED, +} NMDeviceSysIfaceState; + +static inline NMDeviceStateReason +nm_device_state_reason_check (NMDeviceStateReason reason) +{ + /* the device-state-reason serves mostly informational purpse during a state + * change. In some cases however, decisions are made based on the reason. + * I tend to think that interpreting the state reason to derive some behaviors + * is confusing, because the cause and effect are so far apart. + * + * This function is here to mark source that inspects the reason to make + * a decision -- contrary to places that set the reason. Thus, by grepping + * for nm_device_state_reason_check() you can find the "effect" to a certain + * reason. + */ + return reason; +} #define NM_PENDING_ACTION_AUTOACTIVATE "autoactivate" #define NM_PENDING_ACTION_DHCP4 "dhcp4" @@ -113,6 +141,8 @@ #define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes" #define NM_DEVICE_STATISTICS_RX_BYTES "rx-bytes" +#define NM_DEVICE_CONNECTIVITY "connectivity" + #define NM_TYPE_DEVICE (nm_device_get_type ()) #define NM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE, NMDevice)) #define NM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE, NMDeviceClass)) @@ -243,6 +273,11 @@ typedef struct { void (* set_enabled) (NMDevice *self, gboolean enabled); + /* allow derived classes to override the result of nm_device_autoconnect_allowed(). + * If the value changes, the class should call nm_device_emit_recheck_auto_activate(), + * which emits NM_DEVICE_RECHECK_AUTO_ACTIVATE signal. */ + gboolean (* get_autoconnect_allowed) (NMDevice *self); + gboolean (* can_auto_connect) (NMDevice *self, NMConnection *connection, char **specific_object); @@ -278,19 +313,19 @@ typedef struct { GError **error); NMActStageReturn (* act_stage1_prepare) (NMDevice *self, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn (* act_stage2_config) (NMDevice *self, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn (* act_stage3_ip4_config_start) (NMDevice *self, NMIP4Config **out_config, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn (* act_stage3_ip6_config_start) (NMDevice *self, NMIP6Config **out_config, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn (* act_stage4_ip4_config_timeout) (NMDevice *self, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn (* act_stage4_ip6_config_timeout) (NMDevice *self, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); void (* ip4_config_pre_commit) (NMDevice *self, NMIP4Config *config); @@ -360,6 +395,17 @@ typedef struct { NMConnection * (* new_default_connection) (NMDevice *self); gboolean (* unmanaged_on_quit) (NMDevice *self); + + gboolean (* can_reapply_change) (NMDevice *self, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error); + + void (* reapply_connection) (NMDevice *self, + NMConnection *con_old, + NMConnection *con_new); } NMDeviceClass; typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device, @@ -370,6 +416,9 @@ typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device, GType nm_device_get_type (void); +NMNetns *nm_device_get_netns (NMDevice *self); +NMPlatform *nm_device_get_platform (NMDevice *self); + const char * nm_device_get_udi (NMDevice *dev); const char * nm_device_get_iface (NMDevice *dev); int nm_device_get_ifindex (NMDevice *dev); @@ -458,8 +507,6 @@ gboolean nm_device_complete_connection (NMDevice *device, gboolean nm_device_check_connection_compatible (NMDevice *device, NMConnection *connection); gboolean nm_device_check_slave_connection_compatible (NMDevice *device, NMConnection *connection); -gboolean nm_device_uses_assumed_connection (NMDevice *device); - gboolean nm_device_unmanage_on_quit (NMDevice *self); gboolean nm_device_spec_match_list (NMDevice *device, const GSList *specs); @@ -564,6 +611,7 @@ gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps); gboolean nm_device_realize_start (NMDevice *device, const NMPlatformLink *plink, + NMUnmanFlagOp unmanaged_user_explicit, gboolean *out_compatible, GError **error); void nm_device_realize_finish (NMDevice *self, @@ -577,9 +625,16 @@ gboolean nm_device_unrealize (NMDevice *device, GError **error); gboolean nm_device_get_autoconnect (NMDevice *device); -void nm_device_set_autoconnect (NMDevice *device, gboolean autoconnect); +void nm_device_set_autoconnect_intern (NMDevice *device, gboolean autoconnect); void nm_device_emit_recheck_auto_activate (NMDevice *device); +NMDeviceSysIfaceState nm_device_sys_iface_state_get (NMDevice *device); + +gboolean nm_device_sys_iface_state_is_external (NMDevice *self); +gboolean nm_device_sys_iface_state_is_external_or_assume (NMDevice *self); + +void nm_device_sys_iface_state_set (NMDevice *device, NMDeviceSysIfaceState sys_iface_state); + void nm_device_state_changed (NMDevice *device, NMDeviceState state, NMDeviceStateReason reason); @@ -626,14 +681,31 @@ void nm_device_update_firewall_zone (NMDevice *self); void nm_device_update_metered (NMDevice *self); void nm_device_reactivate_ip4_config (NMDevice *device, NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new); + NMSettingIPConfig *s_ip4_new, + gboolean force_restart); void nm_device_reactivate_ip6_config (NMDevice *device, NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new); + NMSettingIPConfig *s_ip6_new, + gboolean force_restart); gboolean nm_device_update_hw_address (NMDevice *self); void nm_device_update_initial_hw_address (NMDevice *self); void nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze); void nm_device_update_dynamic_ip_setup (NMDevice *self); +guint nm_device_get_supplicant_timeout (NMDevice *self); +gboolean nm_device_hw_addr_get_cloned (NMDevice *self, + NMConnection *connection, + gboolean is_wifi, + char **hwaddr, + gboolean *preserve, + GError **error); + +typedef void (*NMDeviceConnectivityCallback) (NMDevice *self, + NMConnectivityState state, + gpointer user_data); +void nm_device_check_connectivity (NMDevice *self, + NMDeviceConnectivityCallback callback, + gpointer user_data); +NMConnectivityState nm_device_get_connectivity_state (NMDevice *self); #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index ceec6063..bfd631f0 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -128,6 +128,8 @@ typedef struct { int _ifindex = (self) ? NM_LLDP_LISTENER_GET_PRIVATE (self)->ifindex : 0; \ \ _nm_log (_level, _NMLOG_DOMAIN, 0, \ + nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ + NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ ((_ifindex > 0) \ @@ -695,7 +697,7 @@ process_lldp_neighbor (NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboo return; } - /* ensure that we have at most MAX_NEIGHBORS entires */ + /* ensure that we have at most MAX_NEIGHBORS entries */ if ( !neigh_old /* only matters in the "add" case. */ && (g_hash_table_size (priv->lldp_neighbors) + 1 > MAX_NEIGHBORS)) { _LOGT ("process: ignore neighbor due to overall limit of %d", MAX_NEIGHBORS); diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 28d91ab3..1c4d2ef6 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -28,6 +28,7 @@ #include <sys/wait.h> #include <teamdctl.h> #include <stdlib.h> +#include <jansson.h> #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" @@ -72,7 +73,7 @@ G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) /*****************************************************************************/ -static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); +static gboolean teamd_start (NMDevice *device, NMConnection *connection); /*****************************************************************************/ @@ -126,7 +127,7 @@ complete_connection (NMDevice *device, { NMSettingTeam *s_team; - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_TEAM_SETTING_NAME, existing_connections, @@ -415,7 +416,7 @@ teamd_dbus_appeared (GDBusConnection *connection, success = teamd_read_config (device); if (success) nm_device_activate_schedule_stage2_device_config (device); - else if (!nm_device_uses_assumed_connection (device)) + else if (!nm_device_sys_iface_state_is_external_or_assume (device)) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); } } @@ -449,7 +450,7 @@ teamd_dbus_vanished (GDBusConnection *dbus_connection, NMConnection *connection = nm_device_get_applied_connection (device); g_assert (connection); - if (!teamd_start (device, nm_connection_get_setting_team (connection))) + if (!teamd_start (device, connection)) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); } } @@ -513,7 +514,7 @@ teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) } static gboolean -teamd_start (NMDevice *device, NMSettingTeam *s_team) +teamd_start (NMDevice *device, NMConnection *connection) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); @@ -523,6 +524,12 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) gs_free char *tmp_str = NULL; const char *teamd_binary; const char *config; + nm_auto_free const char *config_free = NULL; + NMSettingTeam *s_team; + gs_free char *cloned_mac = NULL; + + s_team = nm_connection_get_setting_team (connection); + g_return_val_if_fail (s_team, FALSE); teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL); if (!teamd_binary) { @@ -548,7 +555,39 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) g_ptr_array_add (argv, (gpointer) "-t"); g_ptr_array_add (argv, (gpointer) iface); - config = nm_setting_team_get_config(s_team); + config = nm_setting_team_get_config (s_team); + if (!nm_device_hw_addr_get_cloned (device, connection, FALSE, &cloned_mac, NULL, &error)) { + _LOGW (LOGD_DEVICE, "set-hw-addr: %s", error->message); + return FALSE; + } + + if (cloned_mac) { + json_t *json, *hwaddr; + json_error_t jerror; + + /* Inject the hwaddr property into the JSON configuration. + * While doing so, detect potential conflicts */ + + json = json_loads (config ?: "{}", 0, &jerror); + g_return_val_if_fail (json, FALSE); + + hwaddr = json_object_get (json, "hwaddr"); + if (hwaddr) { + if ( !json_is_string (hwaddr) + || !nm_streq0 (json_string_value (hwaddr), cloned_mac)) + _LOGW (LOGD_TEAM, "set-hw-addr: can't set team cloned-mac-address as the JSON configuration already contains \"hwaddr\""); + } else { + hwaddr = json_string (cloned_mac); + json_object_set (json, "hwaddr", hwaddr); + config = config_free = json_dumps (json, JSON_INDENT(0) | + JSON_ENSURE_ASCII | + JSON_SORT_KEYS); + _LOGD (LOGD_TEAM, "set-hw-addr: injected \"hwaddr\" \"%s\" into team configuration", cloned_mac); + json_decref (hwaddr); + } + json_decref (json); + } + if (config) { g_ptr_array_add (argv, (gpointer) "-c"); g_ptr_array_add (argv, (gpointer) config); @@ -580,23 +619,24 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) } static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; gs_free_error GError *error = NULL; NMSettingTeam *s_team; + NMConnection *connection; const char *cfg; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - ret = NM_DEVICE_CLASS (nm_device_team_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_team_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; - s_team = (NMSettingTeam *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_TEAM); - g_assert (s_team); + connection = nm_device_get_applied_connection (device); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + s_team = nm_connection_get_setting_team (connection); + g_return_val_if_fail (s_team, NM_ACT_STAGE_RETURN_FAILURE); if (priv->tdc) { /* If the existing teamd config is the same as we're about to use, @@ -614,7 +654,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) _LOGD (LOGD_TEAM, "existing teamd config mismatch; killing existing via teamdctl"); if (!teamd_kill (self, NULL, &error)) { _LOGW (LOGD_TEAM, "existing teamd config mismatch; failed to kill existing teamd: %s", error->message); - *reason = NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } } @@ -623,7 +663,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) teamd_cleanup (device, TRUE); } - return teamd_start (device, s_team) ? + return teamd_start (device, connection) ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; } @@ -681,7 +721,7 @@ enslave_slave (NMDevice *device, } } } - success = nm_platform_link_enslave (NM_PLATFORM_GET, + success = nm_platform_link_enslave (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); nm_device_bring_up (slave, TRUE, &no_firmware); @@ -711,7 +751,7 @@ release_slave (NMDevice *device, gboolean success, no_firmware = FALSE; if (configure) { - success = nm_platform_link_release (NM_PLATFORM_GET, + success = nm_platform_link_release (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); @@ -746,7 +786,7 @@ create_and_realize (NMDevice *device, const char *iface = nm_device_get_iface (device); NMPlatformError plerr; - plerr = nm_platform_link_team_add (NM_PLATFORM_GET, iface, out_plink); + plerr = nm_platform_link_team_add (nm_device_get_platform (device), iface, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create team master interface '%s' for '%s': %s", diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index 4d25f9a6..1e600cdf 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -351,7 +351,11 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data) int fd, s; fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); - g_assert (fd >= 0); + if (fd == -1) { + g_test_skip ("Unable to open /dev/net/tun"); + fixture->ifindex = 0; + return; + } ifr.ifr_flags = IFF_TAP | IFF_NO_PI; nm_utils_ifname_cpy (ifr.ifr_name, TEST_IFNAME); @@ -395,6 +399,11 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data) GError *error = NULL; guint sd_id; + if (fixture->ifindex == 0) { + g_test_skip ("Tun device not available"); + return; + } + listener = nm_lldp_listener_new (); g_assert (listener != NULL); g_assert (nm_lldp_listener_start (listener, fixture->ifindex, &error)); @@ -427,7 +436,8 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data) static void _test_recv_fixture_teardown (TestRecvFixture *fixture, gconstpointer user_data) { - nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex); + if (fixture->ifindex) + nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex); } /*****************************************************************************/ diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 0fdccb8a..24811931 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -148,7 +148,7 @@ complete_connection (NMDevice *device, } - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_OLPC_MESH_SETTING_NAME, existing_connections, @@ -163,14 +163,14 @@ complete_connection (NMDevice *device, /*****************************************************************************/ static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); NMActStageReturn ret; gboolean scanning; - ret = NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; @@ -200,16 +200,18 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) static void _mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel) { + NMPlatform *platform; int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - if (nm_platform_mesh_get_channel (NM_PLATFORM_GET, ifindex) != channel) { - if (nm_platform_mesh_set_channel (NM_PLATFORM_GET, ifindex, channel)) + platform = nm_device_get_platform (NM_DEVICE (self)); + if (nm_platform_mesh_get_channel (platform, ifindex) != channel) { + if (nm_platform_mesh_set_channel (platform, ifindex, channel)) _notify (self, PROP_ACTIVE_CHANNEL); } } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); NMConnection *connection; @@ -219,17 +221,17 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) const char *anycast_addr; connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); s_mesh = nm_connection_get_setting_olpc_mesh (connection); - g_assert (s_mesh); + g_return_val_if_fail (s_mesh, NM_ACT_STAGE_RETURN_FAILURE); channel = nm_setting_olpc_mesh_get_channel (s_mesh); if (channel != 0) _mesh_set_channel (self, channel); ssid = nm_setting_olpc_mesh_get_ssid (s_mesh); - nm_platform_mesh_set_ssid (NM_PLATFORM_GET, + nm_platform_mesh_set_ssid (nm_device_get_platform (device), nm_device_get_ifindex (device), g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); @@ -429,15 +431,16 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device); + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); + NMDevice *device = NM_DEVICE (self); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); switch (prop_id) { case PROP_COMPANION: nm_utils_g_value_set_object_path (value, priv->companion); break; case PROP_ACTIVE_CHANNEL: - g_value_set_uint (value, nm_platform_mesh_get_channel (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (device)))); + g_value_set_uint (value, nm_platform_mesh_get_channel (nm_device_get_platform (device), nm_device_get_ifindex (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 188ed54e..7359be96 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -63,7 +63,7 @@ _LOG_DECLARE_SELF(NMDeviceWifi); #define SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN 5 -#define WIRELESS_SECRETS_TRIES "wireless-secrets-tries" +static NM_CACHED_QUARK_FCN ("wireless-secrets-tries", wireless_secrets_tries_quark) /*****************************************************************************/ @@ -119,7 +119,6 @@ typedef struct { NMDeviceWifiCapabilities capabilities; gint32 hw_addr_scan_expire; - char *hw_addr_scan; } NMDeviceWifiPrivate; struct _NMDeviceWifi @@ -152,16 +151,11 @@ static void cleanup_association_attempt (NMDeviceWifi * self, gboolean disconnect); static void supplicant_iface_state_cb (NMSupplicantInterface *iface, - guint32 new_state, - guint32 old_state, + int new_state_i, + int old_state_i, int disconnect_reason, gpointer user_data); -static void supplicant_iface_new_bss_cb (NMSupplicantInterface * iface, - const char *object_path, - GVariant *properties, - NMDeviceWifi * self); - static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, const char *object_path, GVariant *properties, @@ -190,14 +184,13 @@ static void ap_add_remove (NMDeviceWifi *self, NMWifiAP *ap, gboolean recheck_available_connections); -static void remove_supplicant_interface_error_handler (NMDeviceWifi *self); - static void _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset); /*****************************************************************************/ static void _ap_dump (NMDeviceWifi *self, + NMLogLevel log_level, const NMWifiAP *ap, const char *prefix, gint32 now_s) @@ -205,9 +198,9 @@ _ap_dump (NMDeviceWifi *self, char buf[1024]; buf[0] = '\0'; - _LOGD (LOGD_WIFI_SCAN, "wifi-ap: %-7s %s", - prefix, - nm_wifi_ap_to_string (ap, buf, sizeof (buf), now_s)); + _NMLOG (log_level, LOGD_WIFI_SCAN, "wifi-ap: %-7s %s", + prefix, + nm_wifi_ap_to_string (ap, buf, sizeof (buf), now_s)); } static void @@ -263,10 +256,6 @@ supplicant_interface_acquire (NMDeviceWifi *self) G_CALLBACK (supplicant_iface_state_cb), self); g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_NEW_BSS, - G_CALLBACK (supplicant_iface_new_bss_cb), - self); - g_signal_connect (priv->sup_iface, NM_SUPPLICANT_INTERFACE_BSS_UPDATED, G_CALLBACK (supplicant_iface_bss_updated_cb), self); @@ -306,8 +295,10 @@ _requested_scan_set (NMDeviceWifi *self, gboolean value) priv->requested_scan = value; if (value) nm_device_add_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE); - else + else { + nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); nm_device_remove_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE); + } } static void @@ -428,7 +419,7 @@ periodic_update (NMDeviceWifi *self) guint32 new_rate; int percent; NMDeviceState state; - guint32 supplicant_state; + NMSupplicantInterfaceState supplicant_state; /* BSSID and signal strength have meaningful values only if the device * is activated and not scanning. @@ -453,14 +444,18 @@ periodic_update (NMDeviceWifi *self) if (priv->current_ap) { /* Smooth out the strength to work around crappy drivers */ - percent = nm_platform_wifi_get_quality (NM_PLATFORM_GET, ifindex); + percent = nm_platform_wifi_get_quality (nm_device_get_platform (NM_DEVICE (self)), ifindex); if (percent >= 0 || ++priv->invalid_strength_counter > 3) { - nm_wifi_ap_set_strength (priv->current_ap, (gint8) percent); + if (nm_wifi_ap_set_strength (priv->current_ap, (gint8) percent)) { +#ifdef NM_MORE_LOGGING + _ap_dump (self, LOGL_TRACE, priv->current_ap, "updated", 0); +#endif + } priv->invalid_strength_counter = 0; } } - new_rate = nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex); + new_rate = nm_platform_wifi_get_rate (nm_device_get_platform (NM_DEVICE (self)), ifindex); if (new_rate != priv->rate) { priv->rate = new_rate; _notify (self, PROP_BITRATE); @@ -488,7 +483,9 @@ ap_add_remove (NMDeviceWifi *self, g_hash_table_insert (priv->aps, (gpointer) nm_exported_object_export ((NMExportedObject *) ap), g_object_ref (ap)); - } + _ap_dump (self, LOGL_DEBUG, ap, "added", 0); + } else + _ap_dump (self, LOGL_DEBUG, ap, "removed", 0); g_signal_emit (self, signals[signum], 0, ap); @@ -544,14 +541,14 @@ deactivate (NMDevice *device) set_current_ap (self, NULL, TRUE); /* Clear any critical protocol notification in the Wi-Fi stack */ - nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE); /* 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 (NM_PLATFORM_GET, ifindex) != NM_802_11_MODE_INFRA) { + if (nm_platform_wifi_get_mode (nm_device_get_platform (device), ifindex) != NM_802_11_MODE_INFRA) { nm_device_take_down (NM_DEVICE (self), TRUE); - nm_platform_wifi_set_mode (NM_PLATFORM_GET, ifindex, NM_802_11_MODE_INFRA); + nm_platform_wifi_set_mode (nm_device_get_platform (device), ifindex, NM_802_11_MODE_INFRA); nm_device_bring_up (NM_DEVICE (self), TRUE, NULL); } @@ -904,7 +901,7 @@ complete_connection (NMDevice *device, str_ssid = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); - nm_utils_complete_generic (NM_PLATFORM_GET, + nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_WIRELESS_SETTING_NAME, existing_connections, @@ -955,7 +952,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - guint32 state; + NMSupplicantInterfaceState supplicant_state; if (!priv->enabled) return FALSE; @@ -963,15 +960,27 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) if (!priv->sup_iface) return FALSE; - state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( state < NM_SUPPLICANT_INTERFACE_STATE_READY - || state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) + supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); + if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY + || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) return FALSE; return TRUE; } static gboolean +get_autoconnect_allowed (NMDevice *device) +{ + NMDeviceWifiPrivate *priv; + + if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->get_autoconnect_allowed (device)) + return FALSE; + + priv = NM_DEVICE_WIFI_GET_PRIVATE (NM_DEVICE_WIFI (device)); + return !priv->requested_scan; +} + +static gboolean can_auto_connect (NMDevice *device, NMConnection *connection, char **specific_object) @@ -1128,7 +1137,9 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) TRUE, TRUE); if (!randomize) { - g_clear_pointer (&priv->hw_addr_scan, g_free); + /* expire the temporary MAC address used during scanning */ + priv->hw_addr_scan_expire = 0; + if (do_reset) nm_device_hw_addr_reset (device, "scanning"); return; @@ -1136,9 +1147,9 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) now = nm_utils_get_monotonic_timestamp_s (); - if ( !priv->hw_addr_scan - || now >= priv->hw_addr_scan_expire) { + if (now >= priv->hw_addr_scan_expire) { gs_free char *generate_mac_address_mask = NULL; + gs_free char *hw_addr_scan = NULL; /* the random MAC address for scanning expires after a while. * @@ -1152,12 +1163,10 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) device, NULL); - g_free (priv->hw_addr_scan); - priv->hw_addr_scan = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (device), - generate_mac_address_mask); + hw_addr_scan = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (device), + generate_mac_address_mask); + nm_device_hw_addr_set (device, hw_addr_scan, "scanning", TRUE); } - - nm_device_hw_addr_set (device, priv->hw_addr_scan, "scanning", TRUE); } static void @@ -1242,7 +1251,7 @@ static gboolean scanning_allowed (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - guint32 sup_state; + NMSupplicantInterfaceState supplicant_state; NMConnection *connection; g_return_val_if_fail (priv->sup_iface != NULL, FALSE); @@ -1274,11 +1283,11 @@ scanning_allowed (NMDeviceWifi *self) } /* Don't scan if the supplicant is busy */ - sup_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( sup_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING - || sup_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED - || sup_state == NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE - || sup_state == NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE + supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); + if ( supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING + || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED + || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE + || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE || nm_supplicant_interface_get_scanning (priv->sup_iface)) return FALSE; @@ -1338,12 +1347,14 @@ check_scanning_allowed (NMDeviceWifi *self) static gboolean hidden_filter_func (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *connection, gpointer user_data) { NMSettingWireless *s_wifi; - s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection); + if (!nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_WIRELESS_SETTING_NAME)) + return FALSE; + s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (NM_CONNECTION (connection)); return s_wifi ? nm_setting_wireless_get_hidden (s_wifi) : FALSE; } @@ -1352,7 +1363,8 @@ build_hidden_probe_list (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); guint max_scan_ssids = nm_supplicant_interface_get_max_scan_ssids (priv->sup_iface); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i, len; GPtrArray *ssids = NULL; static GByteArray *nullssid = NULL; @@ -1360,28 +1372,31 @@ build_hidden_probe_list (NMDeviceWifi *self) if (max_scan_ssids < 2) return NULL; - /* Static wildcard SSID used for every scan */ + connections = nm_settings_get_connections_clone (nm_device_get_settings ((NMDevice *) self), + &len, + hidden_filter_func, + NULL); + if (!connections[0]) + return NULL; + + g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_timestamp_p_with_data, NULL); + + ssids = g_ptr_array_new_full (max_scan_ssids, (GDestroyNotify) g_byte_array_unref); + + /* Add wildcard SSID using a static wildcard SSID used for every scan */ if (G_UNLIKELY (nullssid == NULL)) nullssid = g_byte_array_new (); + g_ptr_array_add (ssids, g_byte_array_ref (nullssid)); - connections = nm_settings_get_best_connections (nm_device_get_settings ((NMDevice *) self), - max_scan_ssids - 1, - NM_SETTING_WIRELESS_SETTING_NAME, - NULL, - hidden_filter_func, - NULL); - if (connections && connections->data) { - ssids = g_ptr_array_new_full (max_scan_ssids - 1, (GDestroyNotify) g_byte_array_unref); - g_ptr_array_add (ssids, g_byte_array_ref (nullssid)); /* Add wildcard SSID */ - } - - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *connection = iter->data; + for (i = 0; connections[i]; i++) { NMSettingWireless *s_wifi; GBytes *ssid; GByteArray *ssid_array; - s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection); + if (i >= max_scan_ssids - 1) + break; + + s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (NM_CONNECTION (connections[i])); g_assert (s_wifi); ssid = nm_setting_wireless_get_ssid (s_wifi); g_assert (ssid); @@ -1391,7 +1406,6 @@ build_hidden_probe_list (NMDeviceWifi *self) g_bytes_get_size (ssid)); g_ptr_array_add (ssids, ssid_array); } - g_slist_free (connections); return ssids; } @@ -1424,9 +1438,7 @@ static void request_wireless_scan (NMDeviceWifi *self, gboolean force_if_scanning, GVariant *scan_options) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - gboolean backoff = FALSE; - GPtrArray *ssids = NULL; - gboolean new_scan_requested = FALSE; + gboolean request_started = FALSE; nm_clear_g_source (&priv->pending_scan_id); @@ -1436,6 +1448,8 @@ request_wireless_scan (NMDeviceWifi *self, gboolean force_if_scanning, GVariant } if (check_scanning_allowed (self)) { + gs_unref_ptrarray GPtrArray *ssids = NULL; + _LOGD (LOGD_WIFI, "wifi-scan: scanning requested"); if (scan_options) { @@ -1473,22 +1487,14 @@ request_wireless_scan (NMDeviceWifi *self, gboolean force_if_scanning, GVariant _hw_addr_set_scanning (self, FALSE); - if (nm_supplicant_interface_request_scan (priv->sup_iface, ssids)) { - /* success */ - backoff = TRUE; - _requested_scan_set (self, TRUE); - new_scan_requested = TRUE; - } - - if (ssids) - g_ptr_array_unref (ssids); + nm_supplicant_interface_request_scan (priv->sup_iface, ssids); + request_started = TRUE; } else _LOGD (LOGD_WIFI, "wifi-scan: scanning requested but not allowed at this time"); - if (!new_scan_requested) - _requested_scan_set (self, FALSE); + _requested_scan_set (self, request_started); - schedule_scan (self, backoff); + schedule_scan (self, request_started); } static gboolean @@ -1589,7 +1595,7 @@ ap_list_dump (gpointer user_data) priv->scheduled_scan_time); list = ap_list_get_sorted (self, TRUE); for (i = 0; list[i]; i++) - _ap_dump (self, list[i], "dump", now_s); + _ap_dump (self, LOGL_DEBUG, list[i], "dump", now_s); } return G_SOURCE_REMOVE; } @@ -1639,14 +1645,13 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self, } static void -supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, - NMDeviceWifi *self) +supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, + const char *object_path, + GVariant *properties, + NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDeviceState state; - NMWifiAP *ap; NMWifiAP *found_ap = NULL; const GByteArray *ssid; @@ -1661,41 +1666,41 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) return; - ap = nm_wifi_ap_new_from_properties (object_path, properties); - if (!ap) { - _LOGD (LOGD_WIFI, "invalid AP properties received for %s", object_path); - return; - } + found_ap = get_ap_by_supplicant_path (self, object_path); + if (found_ap) { + if (!nm_wifi_ap_update_from_properties (found_ap, object_path, properties)) + return; + _ap_dump (self, LOGL_DEBUG, found_ap, "updated", 0); + } else { + gs_unref_object NMWifiAP *ap = NULL; - /* Let the manager try to fill in the SSID from seen-bssids lists */ - ssid = nm_wifi_ap_get_ssid (ap); - if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) { - /* Try to fill the SSID from the AP database */ - try_fill_ssid_for_hidden_ap (self, ap); + ap = nm_wifi_ap_new_from_properties (object_path, properties); + if (!ap) { + _LOGD (LOGD_WIFI, "invalid AP properties received for %s", object_path); + return; + } + /* Let the manager try to fill in the SSID from seen-bssids lists */ ssid = nm_wifi_ap_get_ssid (ap); - if (ssid && (nm_utils_is_empty_ssid (ssid->data, ssid->len) == FALSE)) { - /* Yay, matched it, no longer treat as hidden */ - _LOGD (LOGD_WIFI, "matched hidden AP %s => '%s'", - nm_wifi_ap_get_address (ap), nm_utils_escape_ssid (ssid->data, ssid->len)); - } else { - /* Didn't have an entry for this AP in the database */ - _LOGD (LOGD_WIFI, "failed to match hidden AP %s", - nm_wifi_ap_get_address (ap)); + if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) { + /* Try to fill the SSID from the AP database */ + try_fill_ssid_for_hidden_ap (self, ap); + + ssid = nm_wifi_ap_get_ssid (ap); + if (ssid && (nm_utils_is_empty_ssid (ssid->data, ssid->len) == FALSE)) { + /* Yay, matched it, no longer treat as hidden */ + _LOGD (LOGD_WIFI, "matched hidden AP %s => '%s'", + nm_wifi_ap_get_address (ap), nm_utils_escape_ssid (ssid->data, ssid->len)); + } else { + /* Didn't have an entry for this AP in the database */ + _LOGD (LOGD_WIFI, "failed to match hidden AP %s", + nm_wifi_ap_get_address (ap)); + } } - } - found_ap = get_ap_by_supplicant_path (self, object_path); - if (found_ap) { - _ap_dump (self, ap, "updated", 0); - nm_wifi_ap_update_from_properties (found_ap, object_path, properties); - } else { - _ap_dump (self, ap, "added", 0); ap_add_remove (self, ACCESS_POINT_ADDED, ap, TRUE); } - g_object_unref (ap); - /* Update the current AP if the supplicant notified a current BSS change * before it sent the current BSS's scan result. */ @@ -1706,32 +1711,6 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, } static void -supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, - NMDeviceWifi *self) -{ - NMDeviceState state; - NMWifiAP *ap; - - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); - g_return_if_fail (properties != NULL); - - /* Ignore new APs when unavailable or unmanaged */ - state = nm_device_get_state (NM_DEVICE (self)); - if (state <= NM_DEVICE_STATE_UNAVAILABLE) - return; - - ap = get_ap_by_supplicant_path (self, object_path); - if (ap) { - _ap_dump (self, ap, "updated", 0); - nm_wifi_ap_update_from_properties (ap, object_path, properties); - schedule_ap_list_dump (self); - } -} - -static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, const char *object_path, NMDeviceWifi *self) @@ -1744,38 +1723,30 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, priv = NM_DEVICE_WIFI_GET_PRIVATE (self); ap = get_ap_by_supplicant_path (self, object_path); - if (ap) { - if (ap == priv->current_ap) { - /* The current AP cannot be removed (to prevent NM indicating that - * it is connected, but to nothing), but it must be removed later - * when the current AP is changed or cleared. Set 'fake' to - * indicate that this AP is now unknown to the supplicant. - */ - nm_wifi_ap_set_fake (ap, TRUE); - } else { - _ap_dump (self, ap, "removed", 0); - ap_add_remove (self, ACCESS_POINT_REMOVED, ap, TRUE); - schedule_ap_list_dump (self); - } + if (!ap) + return; + + if (ap == priv->current_ap) { + /* The current AP cannot be removed (to prevent NM indicating that + * it is connected, but to nothing), but it must be removed later + * when the current AP is changed or cleared. Set 'fake' to + * indicate that this AP is now unknown to the supplicant. + */ + if (nm_wifi_ap_set_fake (ap, TRUE)) + _ap_dump (self, LOGL_DEBUG, ap, "updated", 0); + } else { + ap_add_remove (self, ACCESS_POINT_REMOVED, ap, TRUE); + schedule_ap_list_dump (self); } } static void -remove_supplicant_timeouts (NMDeviceWifi *self) +cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); nm_clear_g_source (&priv->sup_timeout_id); nm_clear_g_source (&priv->link_timeout_id); -} - -static void -cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - remove_supplicant_interface_error_handler (self); - remove_supplicant_timeouts (self); if (disconnect && priv->sup_iface) nm_supplicant_interface_disconnect (priv->sup_iface); } @@ -1893,7 +1864,7 @@ link_timeout_cb (gpointer user_data) static gboolean need_new_8021x_secrets (NMDeviceWifi *self, - guint32 old_state, + NMSupplicantInterfaceState old_state, const char **setting_name) { NMSetting8021x *s_8021x; @@ -1947,7 +1918,7 @@ need_new_8021x_secrets (NMDeviceWifi *self, static gboolean need_new_wpa_psk (NMDeviceWifi *self, - guint32 old_state, + NMSupplicantInterfaceState old_state, gint disconnect_reason, const char **setting_name) { @@ -1988,8 +1959,8 @@ need_new_wpa_psk (NMDeviceWifi *self, static gboolean handle_8021x_or_psk_auth_fail (NMDeviceWifi *self, - guint32 new_state, - guint32 old_state, + NMSupplicantInterfaceState new_state, + NMSupplicantInterfaceState old_state, int disconnect_reason) { NMDevice *device = NM_DEVICE (self); @@ -2042,8 +2013,8 @@ reacquire_interface_cb (gpointer user_data) static void supplicant_iface_state_cb (NMSupplicantInterface *iface, - guint32 new_state, - guint32 old_state, + int new_state_i, + int old_state_i, int disconnect_reason, gpointer user_data) { @@ -2052,6 +2023,8 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMDevice *device = NM_DEVICE (self); NMDeviceState devstate; gboolean scanning; + NMSupplicantInterfaceState new_state = new_state_i; + NMSupplicantInterfaceState old_state = old_state_i; if (new_state == old_state) return; @@ -2080,8 +2053,8 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); break; case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - remove_supplicant_interface_error_handler (self); - remove_supplicant_timeouts (self); + nm_clear_g_source (&priv->sup_timeout_id); + nm_clear_g_source (&priv->link_timeout_id); /* If this is the initial association during device activation, * schedule the next activation stage. @@ -2171,36 +2144,21 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, } static void -supplicant_iface_connection_error_cb (NMSupplicantInterface *iface, - const char *name, - const char *message, - NMDeviceWifi *self) +supplicant_iface_assoc_cb (NMSupplicantInterface *iface, + GError *error, + gpointer user_data) { + NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); NMDevice *device = NM_DEVICE (self); - if (nm_device_is_activating (device)) { - _LOGW (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) supplicant association failed: %s - %s", - name, message); - + if ( error && !nm_utils_error_is_cancelled (error, TRUE) + && nm_device_is_activating (device)) { cleanup_association_attempt (self, TRUE); nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); } } static void -remove_supplicant_interface_error_handler (NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - if (priv->sup_iface) { - g_signal_handlers_disconnect_by_func (priv->sup_iface, - supplicant_iface_connection_error_cb, - self); - } -} - -static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self) @@ -2259,7 +2217,7 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, } } -static NMActStageReturn +static gboolean handle_auth_or_fail (NMDeviceWifi *self, NMActRequest *req, gboolean new_secrets) @@ -2267,35 +2225,34 @@ handle_auth_or_fail (NMDeviceWifi *self, const char *setting_name; guint32 tries; NMConnection *applied_connection; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), FALSE); if (!req) { req = nm_device_get_act_request (NM_DEVICE (self)); - g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (req, FALSE); } applied_connection = nm_act_request_get_applied_connection (req); - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES)); + tries = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (applied_connection), wireless_secrets_tries_quark ())); if (tries > 3) - return NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); nm_act_request_clear_secrets (req); setting_name = nm_connection_need_secrets (applied_connection, NULL); - if (setting_name) { - wifi_secrets_get_secrets (self, setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); - g_object_set_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else + if (!setting_name) { _LOGW (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); + return FALSE; + } - return ret; + wifi_secrets_get_secrets (self, setting_name, + NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION + | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); + g_object_set_qdata (G_OBJECT (applied_connection), wireless_secrets_tries_quark (), GUINT_TO_POINTER (++tries)); + return TRUE; } /* @@ -2364,7 +2321,7 @@ supplicant_connection_timeout_cb (gpointer user_data) if (nm_settings_connection_get_timestamp (nm_act_request_get_settings_connection (req), ×tamp)) new_secrets = !timestamp; - if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_POSTPONE) + if (handle_auth_or_fail (self, req, new_secrets)) _LOGW (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets"); else { nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, @@ -2417,7 +2374,7 @@ build_supplicant_config (NMDeviceWifi *self, if (s_wireless_sec) { NMSetting8021x *s_8021x; const char *con_uuid = nm_connection_get_uuid (connection); - guint32 mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, + guint32 mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self))); g_assert (con_uuid); @@ -2448,7 +2405,7 @@ error: /*****************************************************************************/ static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -2460,18 +2417,18 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) const char *mode; const char *ap_path; - ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; req = nm_device_get_act_request (NM_DEVICE (self)); - g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_act_request_get_applied_connection (req); - g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); s_wireless = nm_connection_get_setting_wireless (connection); - g_assert (s_wireless); + g_return_val_if_fail (s_wireless, NM_ACT_STAGE_RETURN_FAILURE); mode = nm_setting_wireless_get_mode (s_wireless); if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) == 0) @@ -2492,12 +2449,12 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) */ if (is_adhoc_wpa (connection)) { _LOGW (LOGD_WIFI, "Ad-Hoc WPA disabled due to kernel bugs"); - *reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } - /* forget the temporary MAC address used during scanning */ - g_clear_pointer (&priv->hw_addr_scan, g_free); + /* expire the temporary MAC address used during scanning */ + priv->hw_addr_scan_expire = 0; /* Set spoof MAC to the interface */ if (!nm_device_hw_addr_set_cloned (device, connection, TRUE)) @@ -2549,6 +2506,7 @@ ensure_hotspot_frequency (NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP *ap) { + NMDevice *device = NM_DEVICE (self); const char *band = nm_setting_wireless_get_band (s_wifi); const guint32 a_freqs[] = { 5180, 5200, 5220, 5745, 5765, 5785, 5805, 0 }; const guint32 bg_freqs[] = { 2412, 2437, 2462, 2472, 0 }; @@ -2560,14 +2518,15 @@ ensure_hotspot_frequency (NMDeviceWifi *self, return; if (g_strcmp0 (band, "a") == 0) - freq = nm_platform_wifi_find_frequency (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), a_freqs); + freq = nm_platform_wifi_find_frequency (nm_device_get_platform (device), nm_device_get_ifindex (device), a_freqs); else - freq = nm_platform_wifi_find_frequency (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), bg_freqs); + freq = nm_platform_wifi_find_frequency (nm_device_get_platform (device), nm_device_get_ifindex (device), bg_freqs); if (!freq) freq = (g_strcmp0 (band, "a") == 0) ? 5180 : 2462; - nm_wifi_ap_set_freq (ap, freq); + if (nm_wifi_ap_set_freq (ap, freq)) + _ap_dump (self, LOGL_DEBUG, ap, "updated", 0); } static void @@ -2592,18 +2551,18 @@ set_powersave (NMDevice *device) NM_SETTING_WIRELESS_POWERSAVE_IGNORE); } - _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned int) powersave); + _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned) powersave); if (powersave == NM_SETTING_WIRELESS_POWERSAVE_IGNORE) return; - nm_platform_wifi_set_powersave (NM_PLATFORM_GET, + nm_platform_wifi_set_powersave (nm_device_get_platform (device), nm_device_get_ifindex (device), powersave == NM_SETTING_WIRELESS_POWERSAVE_ENABLE); } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -2615,17 +2574,17 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) const char *setting_name; NMSettingWireless *s_wireless; GError *error = NULL; + guint timeout; - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - remove_supplicant_timeouts (self); + nm_clear_g_source (&priv->sup_timeout_id); + nm_clear_g_source (&priv->link_timeout_id); req = nm_device_get_act_request (device); - g_assert (req); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); ap = priv->current_ap; if (!ap) { - *reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); goto out; } @@ -2642,9 +2601,12 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) "Activation: (wifi) access point '%s' has security, but secrets are required.", nm_connection_get_id (connection)); - ret = handle_auth_or_fail (self, req, FALSE); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + if (handle_auth_or_fail (self, req, FALSE)) + ret = NM_ACT_STAGE_RETURN_POSTPONE; + else { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + ret = NM_ACT_STAGE_RETURN_FAILURE; + } goto out; } @@ -2678,27 +2640,18 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) "Activation: (wifi) couldn't build wireless configuration: %s", error->message); g_clear_error (&error); - *reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); goto out; } - /* Hook up error signal handler to capture association errors */ - g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR, - G_CALLBACK (supplicant_iface_connection_error_cb), - self); - - if (!nm_supplicant_interface_set_config (priv->sup_iface, config, &error)) { - _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) couldn't send wireless configuration to the supplicant: %s", - error->message); - g_clear_error (&error); - *reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED; - goto out; - } + nm_supplicant_interface_assoc (priv->sup_iface, config, + supplicant_iface_assoc_cb, self); - /* Set up a timeout on the association attempt to fail after 25 seconds */ - priv->sup_timeout_id = g_timeout_add_seconds (25, supplicant_connection_timeout_cb, self); + /* Set up a timeout on the association attempt */ + timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); + priv->sup_timeout_id = g_timeout_add_seconds (timeout, + supplicant_connection_timeout_cb, + self); if (!priv->periodic_source_id) priv->periodic_source_id = g_timeout_add_seconds (6, periodic_update_cb, self); @@ -2722,36 +2675,38 @@ out: static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMConnection *connection; NMSettingIPConfig *s_ip4; const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + s_ip4 = nm_connection_get_setting_ip4_config (connection); if (s_ip4) method = nm_setting_ip_config_get_method (s_ip4); /* 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_PLATFORM_GET, nm_device_get_ifindex (device), TRUE); + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ifindex (device), TRUE); - return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); + return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); } static NMActStageReturn act_stage3_ip6_config_start (NMDevice *device, NMIP6Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMConnection *connection; NMSettingIPConfig *s_ip6; const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + s_ip6 = nm_connection_get_setting_ip6_config (connection); if (s_ip6) method = nm_setting_ip_config_get_method (s_ip6); @@ -2759,9 +2714,9 @@ 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_PLATFORM_GET, nm_device_get_ifindex (device), TRUE); + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ifindex (device), TRUE); - return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip6_config_start (device, out_config, reason); + return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason); } static guint32 @@ -2818,7 +2773,7 @@ handle_ip_config_timeout (NMDeviceWifi *self, NMConnection *connection, gboolean may_fail, gboolean *chain_up, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; @@ -2826,7 +2781,7 @@ handle_ip_config_timeout (NMDeviceWifi *self, if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) { *chain_up = TRUE; - return ret; + return NM_ACT_STAGE_RETURN_FAILURE; } /* If IP configuration times out and it's a static WEP connection, that @@ -2842,12 +2797,13 @@ handle_ip_config_timeout (NMDeviceWifi *self, "Activation: (wifi) could not get IP configuration for connection '%s'.", nm_connection_get_id (connection)); - ret = handle_auth_or_fail (self, NULL, TRUE); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + if (handle_auth_or_fail (self, NULL, TRUE)) { _LOGI (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets"); + ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { - *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + ret = NM_ACT_STAGE_RETURN_FAILURE; } } else { /* Not static WEP or failure allowed; let superclass handle it */ @@ -2859,7 +2815,7 @@ handle_ip_config_timeout (NMDeviceWifi *self, static NMActStageReturn -act_stage4_ip4_config_timeout (NMDevice *device, NMDeviceStateReason *reason) +act_stage4_ip4_config_timeout (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMConnection *connection; NMSettingIPConfig *s_ip4; @@ -2867,20 +2823,20 @@ act_stage4_ip4_config_timeout (NMDevice *device, NMDeviceStateReason *reason) NMActStageReturn ret; connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); s_ip4 = nm_connection_get_setting_ip4_config (connection); may_fail = nm_setting_ip_config_get_may_fail (s_ip4); - ret = handle_ip_config_timeout (NM_DEVICE_WIFI (device), connection, may_fail, &chain_up, reason); + ret = handle_ip_config_timeout (NM_DEVICE_WIFI (device), connection, may_fail, &chain_up, out_failure_reason); if (chain_up) - ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (device, reason); + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (device, out_failure_reason); return ret; } static NMActStageReturn -act_stage4_ip6_config_timeout (NMDevice *device, NMDeviceStateReason *reason) +act_stage4_ip6_config_timeout (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMConnection *connection; NMSettingIPConfig *s_ip6; @@ -2888,14 +2844,14 @@ act_stage4_ip6_config_timeout (NMDevice *device, NMDeviceStateReason *reason) NMActStageReturn ret; connection = nm_device_get_applied_connection (device); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); s_ip6 = nm_connection_get_setting_ip6_config (connection); may_fail = nm_setting_ip_config_get_may_fail (s_ip6); - ret = handle_ip_config_timeout (NM_DEVICE_WIFI (device), connection, may_fail, &chain_up, reason); + ret = handle_ip_config_timeout (NM_DEVICE_WIFI (device), connection, may_fail, &chain_up, out_failure_reason); if (chain_up) - ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (device, reason); + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (device, out_failure_reason); return ret; } @@ -2915,10 +2871,10 @@ activation_success_handler (NMDevice *device) applied_connection = nm_act_request_get_applied_connection (req); /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE); /* Clear wireless secrets tries on success */ - g_object_set_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES, NULL); + g_object_set_qdata (G_OBJECT (applied_connection), wireless_secrets_tries_quark (), NULL); /* There should always be a current AP, either a fake one because we haven't * seen a scan result for the activated AP yet, or a real one from the @@ -2927,6 +2883,8 @@ activation_success_handler (NMDevice *device) g_warn_if_fail (priv->current_ap); if (priv->current_ap) { if (nm_wifi_ap_get_fake (priv->current_ap)) { + gboolean ap_changed = FALSE; + /* If the activation AP hasn't been seen by the supplicant in a scan * yet, it will be "fake". This usually happens for Ad-Hoc and * AP-mode connections. Fill in the details from the device itself @@ -2936,16 +2894,19 @@ activation_success_handler (NMDevice *device) guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; gs_free char *bssid_str = NULL; - if ( nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid) + if ( nm_platform_wifi_get_bssid (nm_device_get_platform (device), ifindex, bssid) && nm_ethernet_address_is_valid (bssid, ETH_ALEN)) { bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); - nm_wifi_ap_set_address (priv->current_ap, bssid_str); + ap_changed |= nm_wifi_ap_set_address (priv->current_ap, bssid_str); } } if (!nm_wifi_ap_get_freq (priv->current_ap)) - nm_wifi_ap_set_freq (priv->current_ap, nm_platform_wifi_get_frequency (NM_PLATFORM_GET, ifindex)); + ap_changed |= nm_wifi_ap_set_freq (priv->current_ap, nm_platform_wifi_get_frequency (nm_device_get_platform (device), ifindex)); if (!nm_wifi_ap_get_max_bitrate (priv->current_ap)) - nm_wifi_ap_set_max_bitrate (priv->current_ap, nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex)); + ap_changed |= nm_wifi_ap_set_max_bitrate (priv->current_ap, nm_platform_wifi_get_rate (nm_device_get_platform (device), ifindex)); + + if (ap_changed) + _ap_dump (self, LOGL_DEBUG, priv->current_ap, "updated", 0); } nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), @@ -2969,10 +2930,10 @@ activation_failure_handler (NMDevice *device) g_assert (applied_connection); /* Clear wireless secrets tries on failure */ - g_object_set_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES, NULL); + g_object_set_qdata (G_OBJECT (applied_connection), wireless_secrets_tries_quark (), NULL); /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, nm_device_get_ifindex (device), FALSE); + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ifindex (device), FALSE); } static void @@ -3023,7 +2984,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_PLATFORM_GET, nm_device_get_ifindex (device), FALSE); + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ifindex (device), FALSE); break; case NM_DEVICE_STATE_ACTIVATED: activation_success_handler (device); @@ -3106,6 +3067,33 @@ set_enabled (NMDevice *device, gboolean enabled) } } +static gboolean +can_reapply_change (NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + NMDeviceClass *device_class; + + /* Only handle wireless setting here, delegate other settings to parent class */ + if (nm_streq (setting_name, NM_SETTING_WIRELESS_SETTING_NAME)) { + return nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_WIRELESS_SETTING_NAME, + error, + NM_SETTING_WIRELESS_MTU); /* reapplied with IP config */ + } + + device_class = NM_DEVICE_CLASS (nm_device_wifi_parent_class); + return device_class->can_reapply_change (device, + setting_name, + s_old, + s_new, + diffs, + error); +} + /*****************************************************************************/ static void @@ -3233,8 +3221,6 @@ finalize (GObject *object) g_hash_table_unref (priv->aps); - g_free (priv->hw_addr_scan); - G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -3253,6 +3239,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) object_class->finalize = finalize; parent_class->can_auto_connect = can_auto_connect; + parent_class->get_autoconnect_allowed = get_autoconnect_allowed; parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; parent_class->check_connection_available = check_connection_available; @@ -3270,6 +3257,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->deactivate = deactivate; parent_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; parent_class->unmanaged_on_quit = unmanaged_on_quit; + parent_class->can_reapply_change = can_reapply_change; parent_class->state_changed = device_state_changed; diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 96e9d19c..7de0838f 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -29,6 +29,7 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-core-internal.h" +#include "platform/nm-platform.h" #include "nm-setting-wireless.h" @@ -68,8 +69,8 @@ typedef struct { NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */ /* Non-scanned attributes */ - bool fake; /* Whether or not the AP is from a scan */ - bool hotspot; /* Whether the AP is a local device's hotspot network */ + bool fake:1; /* Whether or not the AP is from a scan */ + bool hotspot:1; /* Whether the AP is a local device's hotspot network */ gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ } NMWifiAPPrivate; @@ -122,20 +123,20 @@ const GByteArray * nm_wifi_ap_get_ssid (const NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->ssid; } -void +gboolean nm_wifi_ap_set_ssid (NMWifiAP *ap, const guint8 *ssid, gsize len) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); - g_return_if_fail (ssid == NULL || len > 0); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + g_return_val_if_fail (ssid == NULL || len > 0, FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); /* same SSID */ if ((ssid && priv->ssid) && (len == priv->ssid->len)) { if (!memcmp (ssid, priv->ssid->data, len)) - return; + return FALSE; } if (priv->ssid) { @@ -149,49 +150,56 @@ nm_wifi_ap_set_ssid (NMWifiAP *ap, const guint8 *ssid, gsize len) } _notify (ap, PROP_SSID); + return TRUE; } -static void +static gboolean nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->flags != flags) { priv->flags = flags; _notify (ap, PROP_FLAGS); + return TRUE; } + return FALSE; } -static void +static gboolean nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->wpa_flags != flags) { priv->wpa_flags = flags; _notify (ap, PROP_WPA_FLAGS); + return TRUE; } + return FALSE; } -static void +static gboolean nm_wifi_ap_set_rsn_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->rsn_flags != flags) { priv->rsn_flags = flags; _notify (ap, PROP_RSN_FLAGS); + return TRUE; } + return FALSE; } const char * @@ -202,25 +210,34 @@ nm_wifi_ap_get_address (const NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->address; } -void -nm_wifi_ap_set_address (NMWifiAP *ap, const char *addr) +static gboolean +nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 *addr /* ETH_ALEN bytes */) { NMWifiAPPrivate *priv; - guint8 addr_buf[ETH_ALEN]; - - g_return_if_fail (NM_IS_WIFI_AP (ap)); - if ( !addr - || !nm_utils_hwaddr_aton (addr, addr_buf, sizeof (addr_buf))) - g_return_if_reached (); priv = NM_WIFI_AP_GET_PRIVATE (ap); if ( !priv->address - || !nm_utils_hwaddr_matches (addr_buf, sizeof (addr_buf), priv->address, -1)) { + || !nm_utils_hwaddr_matches (addr, ETH_ALEN, priv->address, -1)) { g_free (priv->address); - priv->address = nm_utils_hwaddr_ntoa (addr_buf, sizeof (addr_buf)); + priv->address = nm_utils_hwaddr_ntoa (addr, ETH_ALEN); _notify (ap, PROP_HW_ADDRESS); + return TRUE; } + return FALSE; +} + +gboolean +nm_wifi_ap_set_address (NMWifiAP *ap, const char *addr) +{ + guint8 addr_buf[ETH_ALEN]; + + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + if ( !addr + || !nm_utils_hwaddr_aton (addr, addr_buf, sizeof (addr_buf))) + g_return_val_if_reached (FALSE); + + return nm_wifi_ap_set_address_bin (ap, addr_buf); } NM80211Mode @@ -231,21 +248,23 @@ nm_wifi_ap_get_mode (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->mode; } -static void +static gboolean nm_wifi_ap_set_mode (NMWifiAP *ap, const NM80211Mode mode) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); - g_return_if_fail ( mode == NM_802_11_MODE_ADHOC - || mode == NM_802_11_MODE_INFRA); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + g_return_val_if_fail ( mode == NM_802_11_MODE_ADHOC + || mode == NM_802_11_MODE_INFRA, FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->mode != mode) { priv->mode = mode; _notify (ap, PROP_MODE); + return TRUE; } + return FALSE; } gboolean @@ -264,19 +283,21 @@ nm_wifi_ap_get_strength (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->strength; } -void +gboolean nm_wifi_ap_set_strength (NMWifiAP *ap, const gint8 strength) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->strength != strength) { priv->strength = strength; _notify (ap, PROP_STRENGTH); + return TRUE; } + return FALSE; } guint32 @@ -287,20 +308,22 @@ nm_wifi_ap_get_freq (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->freq; } -void +gboolean nm_wifi_ap_set_freq (NMWifiAP *ap, const guint32 freq) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->freq != freq) { priv->freq = freq; _notify (ap, PROP_FREQUENCY); + return TRUE; } + return FALSE; } guint32 @@ -312,19 +335,21 @@ nm_wifi_ap_get_max_bitrate (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->max_bitrate; } -void +gboolean nm_wifi_ap_set_max_bitrate (NMWifiAP *ap, guint32 bitrate) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->max_bitrate != bitrate) { priv->max_bitrate = bitrate; _notify (ap, PROP_MAX_BITRATE); + return TRUE; } + return FALSE; } gboolean @@ -335,27 +360,37 @@ nm_wifi_ap_get_fake (const NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->fake; } -void +gboolean nm_wifi_ap_set_fake (NMWifiAP *ap, gboolean fake) { - g_return_if_fail (NM_IS_WIFI_AP (ap)); + NMWifiAPPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + + priv = NM_WIFI_AP_GET_PRIVATE (ap); - NM_WIFI_AP_GET_PRIVATE (ap)->fake = fake; + if (priv->fake != !!fake) { + priv->fake = fake; + return TRUE; + } + return FALSE; } -static void +static gboolean nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen) { NMWifiAPPrivate *priv; - g_return_if_fail (NM_IS_WIFI_AP (ap)); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->last_seen != last_seen) { priv->last_seen = last_seen; _notify (ap, PROP_LAST_SEEN); + return TRUE; } + return FALSE; } /*****************************************************************************/ @@ -400,13 +435,12 @@ security_from_vardict (GVariant *security) return flags; } -void +gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, const char *supplicant_path, GVariant *properties) { NMWifiAPPrivate *priv; - char *addr; const guint8 *bytes; GVariant *v; gsize len; @@ -414,28 +448,30 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, const char *s; gint16 i16; guint16 u16; + gboolean changed = FALSE; + + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + g_return_val_if_fail (properties, FALSE); - g_return_if_fail (ap != NULL); - g_return_if_fail (properties != NULL); priv = NM_WIFI_AP_GET_PRIVATE (ap); g_object_freeze_notify (G_OBJECT (ap)); if (g_variant_lookup (properties, "Privacy", "b", &b) && b) - nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); + changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); if (g_variant_lookup (properties, "Mode", "&s", &s)) { if (!g_strcmp0 (s, "infrastructure")) - nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); + changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); else if (!g_strcmp0 (s, "ad-hoc")) - nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC); + changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC); } if (g_variant_lookup (properties, "Signal", "n", &i16)) - nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (i16)); + changed |= nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (i16)); if (g_variant_lookup (properties, "Frequency", "q", &u16)) - nm_wifi_ap_set_freq (ap, u16); + changed |= nm_wifi_ap_set_freq (ap, u16); v = g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); if (v) { @@ -446,7 +482,7 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, if ( bytes && len && !(((len == 8) || (len == 9)) && !memcmp (bytes, "<hidden>", 8)) && !nm_utils_is_empty_ssid (bytes, len)) - nm_wifi_ap_set_ssid (ap, bytes, len); + changed |= nm_wifi_ap_set_ssid (ap, bytes, len); g_variant_unref (v); } @@ -454,11 +490,10 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, 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) { - addr = nm_utils_hwaddr_ntoa (bytes, len); - nm_wifi_ap_set_address (ap, addr); - g_free (addr); - } + if ( len == ETH_ALEN + && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 + && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) + changed |= nm_wifi_ap_set_address_bin (ap, bytes); g_variant_unref (v); } @@ -470,33 +505,37 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, /* Find the max AP rate */ for (i = 0; i < len; i++) { - if (rates[i] > maxrate) { + if (rates[i] > maxrate) maxrate = rates[i]; - nm_wifi_ap_set_max_bitrate (ap, rates[i] / 1000); - } } + if (maxrate) + changed |= nm_wifi_ap_set_max_bitrate (ap, maxrate / 1000); g_variant_unref (v); } v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); if (v) { - nm_wifi_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v)); + changed |= nm_wifi_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v)); g_variant_unref (v); } v = g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT); if (v) { - nm_wifi_ap_set_rsn_flags (ap, priv->rsn_flags | security_from_vardict (v)); + changed |= nm_wifi_ap_set_rsn_flags (ap, priv->rsn_flags | security_from_vardict (v)); g_variant_unref (v); } - if (!priv->supplicant_path) + if (!priv->supplicant_path) { priv->supplicant_path = g_strdup (supplicant_path); + changed = TRUE; + } - nm_wifi_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); - priv->fake = FALSE; + changed |= nm_wifi_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); + changed |= nm_wifi_ap_set_fake (ap, FALSE); g_object_thaw_notify (G_OBJECT (ap)); + + return changed; } static gboolean @@ -583,6 +622,7 @@ nm_wifi_ap_to_string (const NMWifiAP *self, { const NMWifiAPPrivate *priv; const char *supplicant_id = "-"; + const char *export_path; guint32 chan; char b1[200]; @@ -591,10 +631,16 @@ nm_wifi_ap_to_string (const NMWifiAP *self, priv = NM_WIFI_AP_GET_PRIVATE (self); chan = nm_utils_wifi_freq_to_channel (priv->freq); if (priv->supplicant_path) - supplicant_id = strrchr (priv->supplicant_path, '/'); + supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; + + export_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); + if (export_path) + export_path = strrchr (export_path, '/') ?: export_path; + else + export_path = "/"; g_snprintf (str_buf, buf_len, - "%17s %-32s [ %c %3u %3u%% %c W:%04X R:%04X ] %3us %s", + "%17s %-32s [ %c %3u %3u%% %c W:%04X R:%04X ] %3us sup:%s [nm:%s]", priv->address ?: "(none)", nm_sprintf_buf (b1, "%s%s%s", NM_PRINT_FMT_QUOTED (priv->ssid, "\"", nm_utils_escape_ssid (priv->ssid->data, priv->ssid->len), "\"", "(none)")), @@ -611,7 +657,8 @@ nm_wifi_ap_to_string (const NMWifiAP *self, priv->wpa_flags & 0xFFFF, priv->rsn_flags & 0xFFFF, priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1, - supplicant_id); + supplicant_id, + export_path); return str_buf; } @@ -793,10 +840,7 @@ nm_wifi_ap_init (NMWifiAP *ap) NMWifiAP * nm_wifi_ap_new_from_properties (const char *supplicant_path, GVariant *properties) { - const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; NMWifiAP *ap; - const char *addr; g_return_val_if_fail (supplicant_path != NULL, NULL); g_return_val_if_fail (properties != NULL, NULL); @@ -805,10 +849,7 @@ nm_wifi_ap_new_from_properties (const char *supplicant_path, GVariant *propertie nm_wifi_ap_update_from_properties (ap, supplicant_path, properties); /* ignore APs with invalid or missing BSSIDs */ - addr = nm_wifi_ap_get_address (ap); - if ( !addr - || nm_utils_hwaddr_matches (addr, -1, bad_bssid1, ETH_ALEN) - || nm_utils_hwaddr_matches (addr, -1, bad_bssid2, ETH_ALEN)) { + if (!nm_wifi_ap_get_address (ap)) { g_object_unref (ap); return NULL; } diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index a68aece8..5e64087c 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -53,7 +53,7 @@ NMWifiAP * nm_wifi_ap_new_from_properties (const char *supplicant_path, GVariant *properties); NMWifiAP * nm_wifi_ap_new_fake_from_connection (NMConnection *connection); -void nm_wifi_ap_update_from_properties (NMWifiAP *ap, +gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, const char *supplicant_path, GVariant *properties); @@ -68,25 +68,25 @@ gboolean nm_wifi_ap_complete_connection (NMWifiAP *self, const char * nm_wifi_ap_get_supplicant_path (NMWifiAP *ap); guint64 nm_wifi_ap_get_id (NMWifiAP *ap); const GByteArray *nm_wifi_ap_get_ssid (const NMWifiAP *ap); -void nm_wifi_ap_set_ssid (NMWifiAP *ap, +gboolean nm_wifi_ap_set_ssid (NMWifiAP *ap, const guint8 *ssid, gsize len); const char * nm_wifi_ap_get_address (const NMWifiAP *ap); -void nm_wifi_ap_set_address (NMWifiAP *ap, +gboolean nm_wifi_ap_set_address (NMWifiAP *ap, const char *addr); NM80211Mode nm_wifi_ap_get_mode (NMWifiAP *ap); gboolean nm_wifi_ap_is_hotspot (NMWifiAP *ap); gint8 nm_wifi_ap_get_strength (NMWifiAP *ap); -void nm_wifi_ap_set_strength (NMWifiAP *ap, +gboolean nm_wifi_ap_set_strength (NMWifiAP *ap, gint8 strength); guint32 nm_wifi_ap_get_freq (NMWifiAP *ap); -void nm_wifi_ap_set_freq (NMWifiAP *ap, +gboolean nm_wifi_ap_set_freq (NMWifiAP *ap, guint32 freq); guint32 nm_wifi_ap_get_max_bitrate (NMWifiAP *ap); -void nm_wifi_ap_set_max_bitrate (NMWifiAP *ap, +gboolean nm_wifi_ap_set_max_bitrate (NMWifiAP *ap, guint32 bitrate); gboolean nm_wifi_ap_get_fake (const NMWifiAP *ap); -void nm_wifi_ap_set_fake (NMWifiAP *ap, +gboolean nm_wifi_ap_set_fake (NMWifiAP *ap, gboolean fake); const char *nm_wifi_ap_to_string (const NMWifiAP *self, diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index 39c7fa17..1b6c2f4b 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -21,11 +21,11 @@ #ifndef __NM_WIFI_UTILS_H__ #define __NM_WIFI_UTILS_H__ -#include <nm-dbus-interface.h> -#include <nm-connection.h> -#include <nm-setting-wireless.h> -#include <nm-setting-wireless-security.h> -#include <nm-setting-8021x.h> +#include "nm-dbus-interface.h" +#include "nm-connection.h" +#include "nm-setting-wireless.h" +#include "nm-setting-wireless-security.h" +#include "nm-setting-8021x.h" gboolean nm_wifi_utils_complete_connection (const GByteArray *ssid, const char *bssid, diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index 23412de6..eb577aaf 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -9,6 +9,7 @@ global: nm_modem_deactivate_async_finish; nm_modem_device_state_changed; nm_modem_get_capabilities; + nm_modem_get_configured_mtu; nm_modem_get_control_port; nm_modem_get_data_port; nm_modem_get_driver; diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 7a70a0bf..4a4d2f2c 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -68,10 +68,13 @@ G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) /*****************************************************************************/ static void -ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) +ppp_failed (NMModem *modem, + guint i_reason, + gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDeviceStateReason reason = i_reason; switch (nm_device_get_state (device)) { case NM_DEVICE_STATE_PREPARE: @@ -110,12 +113,13 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) static void modem_prepare_result (NMModem *modem, gboolean success, - NMDeviceStateReason reason, + guint i_reason, gpointer user_data) { NMDeviceModem *self = NM_DEVICE_MODEM (user_data); NMDevice *device = NM_DEVICE (self); NMDeviceState state; + NMDeviceStateReason reason = i_reason; state = nm_device_get_state (device); g_return_if_fail (state == NM_DEVICE_STATE_PREPARE); @@ -123,12 +127,12 @@ modem_prepare_result (NMModem *modem, if (success) nm_device_activate_schedule_stage2_device_config (device); else { - if (reason == NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT) { + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT) { /* If the connect failed because the SIM PIN was wrong don't allow * the device to be auto-activated anymore, which would risk locking * the SIM if the incorrect PIN continues to be used. */ - nm_device_set_autoconnect (device, FALSE); + nm_device_set_autoconnect_intern (device, FALSE); _LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN"); } @@ -201,7 +205,7 @@ modem_ip6_config_result (NMModem *modem, NMDeviceModem *self = NM_DEVICE_MODEM (user_data); NMDevice *device = NM_DEVICE (self); NMActStageReturn ret; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; NMIP6Config *ignored = NULL; gboolean got_config = !!config; @@ -235,11 +239,11 @@ modem_ip6_config_result (NMModem *modem, } /* Start SLAAC now that we have a link-local address from the modem */ - ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage3_ip6_config_start (device, &ignored, &reason); + ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage3_ip6_config_start (device, &ignored, &failure_reason); g_assert (ignored == NULL); switch (ret) { case NM_ACT_STAGE_RETURN_FAILURE: - nm_device_ip_method_failed (device, AF_INET6, reason); + nm_device_ip_method_failed (device, AF_INET6, failure_reason); break; case NM_ACT_STAGE_RETURN_IP_FAIL: /* all done */ @@ -371,9 +375,9 @@ device_state_changed (NMDevice *device, nm_modem_state_to_string (nm_modem_get_state (priv->modem))); } - nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); + nm_modem_device_state_changed (priv->modem, new_state, old_state); - switch (reason) { + switch (nm_device_state_reason_check (reason)) { case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED: case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING: case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED: @@ -386,8 +390,10 @@ device_state_changed (NMDevice *device, /* Block autoconnect of the just-failed connection for situations * where a retry attempt would just fail again. */ - if (connection) - nm_settings_connection_set_autoconnect_blocked_reason (connection, reason); + if (connection) { + nm_settings_connection_set_autoconnect_blocked_reason (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_BLOCKED); + } break; default: break; @@ -509,41 +515,41 @@ deactivate_async (NMDevice *self, /*****************************************************************************/ static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret; NMActRequest *req; - ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, reason); + ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; req = nm_device_get_act_request (device); - g_assert (req); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); - return nm_modem_act_stage1_prepare (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, req, reason); + return nm_modem_act_stage1_prepare (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, req, out_failure_reason); } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMActRequest *req; req = nm_device_get_act_request (device); - g_assert (req); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); - return nm_modem_act_stage2_config (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, req, reason); + return nm_modem_act_stage2_config (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, req, out_failure_reason); } static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { return nm_modem_stage3_ip4_config_start (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, device, NM_DEVICE_CLASS (nm_device_modem_parent_class), - reason); + out_failure_reason); } static void @@ -555,11 +561,11 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) static NMActStageReturn act_stage3_ip6_config_start (NMDevice *device, NMIP6Config **out_config, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, nm_device_get_act_request (device), - reason); + out_failure_reason); } static gboolean @@ -800,6 +806,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->owns_iface = owns_iface; device_class->is_available = is_available; device_class->get_ip_iface_identifier = get_ip_iface_identifier; + device_class->get_configured_mtu = nm_modem_get_configured_mtu; device_class->state_changed = device_state_changed; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 7dfd38c5..4b16fb14 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -119,7 +119,10 @@ G_DEFINE_TYPE (NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM) char __prefix_name[128]; \ const char *__uid; \ \ - _nm_log (_level, (_NMLOG_DOMAIN), 0, \ + _nm_log (_level, (_NMLOG_DOMAIN), 0, NULL, \ + ((__self && __self->_priv.ctx) \ + ? nm_connection_get_uuid (__self->_priv.ctx->connection) \ + : NULL), \ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (__self \ @@ -407,7 +410,7 @@ connect_ready (MMModemSimple *simple_iface, if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { _LOGW ("failed to connect modem: invalid bearer IP configuration"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); connect_context_clear (self); return; } @@ -439,11 +442,10 @@ send_pin_ready (MMSim *sim, GAsyncResult *result, NMModemBroadband *self) if (error) { if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) && - mm_modem_get_unlock_required (self->_priv.modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { + mm_modem_get_unlock_required (self->_priv.modem_iface) == MM_MODEM_LOCK_SIM_PIN)) ask_for_pin (self); - } else { - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (self, error)); - } + else + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, translate_mm_error (self, error)); return; } @@ -506,7 +508,7 @@ connect_context_step (NMModemBroadband *self) _LOGW ("failed to connect '%s': not a mobile broadband modem", nm_connection_get_id (ctx->connection)); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); connect_context_clear (self); break; } @@ -520,7 +522,7 @@ connect_context_step (NMModemBroadband *self) error->message); g_clear_error (&error); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); connect_context_clear (self); break; } @@ -559,9 +561,9 @@ connect_context_step (NMModemBroadband *self) /* fall through */ case CONNECT_STEP_LAST: - if (self->_priv.ipv4_config || self->_priv.ipv6_config) { - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); - } else { + if (self->_priv.ipv4_config || self->_priv.ipv6_config) + nm_modem_emit_prepare_result (NM_MODEM (self), TRUE, NM_DEVICE_STATE_REASON_NONE); + else { /* If we have a saved error from a previous attempt, use it */ if (!ctx->first_error) ctx->first_error = g_error_new_literal (NM_DEVICE_ERROR, @@ -570,7 +572,7 @@ connect_context_step (NMModemBroadband *self) _LOGW ("failed to connect modem: %s", ctx->first_error->message); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (self, ctx->first_error)); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, translate_mm_error (self, ctx->first_error)); } connect_context_clear (self); @@ -581,7 +583,7 @@ connect_context_step (NMModemBroadband *self) static NMActStageReturn act_stage1_prepare (NMModem *_self, NMConnection *connection, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); @@ -590,7 +592,7 @@ act_stage1_prepare (NMModem *_self, self->_priv.simple_iface = mm_object_get_modem_simple (self->_priv.modem_object); if (!self->_priv.simple_iface) { _LOGW ("cannot access the Simple mobile broadband modem interface"); - *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } } @@ -944,7 +946,7 @@ out: static NMActStageReturn static_stage3_ip4_config_start (NMModem *_self, NMActRequest *req, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); @@ -1050,7 +1052,7 @@ out: } static NMActStageReturn -stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *reason) +stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *out_failure_reason) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 41d422aa..52b335c7 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -83,7 +83,7 @@ G_DEFINE_TYPE (NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) char __prefix_name[128]; \ const char *__uid; \ \ - _nm_log (_level, (_NMLOG_DOMAIN), 0, \ + _nm_log (_level, (_NMLOG_DOMAIN), 0, NULL, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (__self \ @@ -724,8 +724,8 @@ stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data if (error) { _LOGW ("connection failed: %s", error->message); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, - NM_DEVICE_STATE_REASON_MODEM_BUSY); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, + NM_DEVICE_STATE_REASON_MODEM_BUSY); /* * FIXME: add code to check for InProgress so that the * connection doesn't continue to try and activate, @@ -745,7 +745,6 @@ context_property_changed (GDBusProxy *proxy, { NMModemOfono *self = NM_MODEM_OFONO (user_data); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; NMPlatformIP4Address addr; gboolean ret = FALSE; GVariant *v_dict; @@ -910,39 +909,40 @@ context_property_changed (GDBusProxy *proxy, out: if (nm_modem_get_state (NM_MODEM (self)) != NM_MODEM_STATE_CONNECTED) { _LOGI ("emitting PREPARE_RESULT: %s", ret ? "TRUE" : "FALSE"); - if (!ret) - reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, ret, reason); + nm_modem_emit_prepare_result (NM_MODEM (self), ret, + ret + ? NM_DEVICE_STATE_REASON_NONE + : NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); } else { _LOGW ("MODEM_PPP_FAILED"); - g_signal_emit_by_name (self, NM_MODEM_PPP_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); + nm_modem_emit_ppp_failed (NM_MODEM (self), NM_DEVICE_STATE_REASON_PPP_FAILED); } } static NMActStageReturn static_stage3_ip4_config_start (NMModem *modem, NMActRequest *req, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemOfono *self = NM_MODEM_OFONO (modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; GError *error = NULL; - if (priv->ip4_config) { - _LOGD ("IP4 config is done; setting modem_state -> CONNECTED"); - g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, priv->ip4_config, error); + if (!priv->ip4_config) { + _LOGD ("IP4 config not ready(?)"); + return NM_ACT_STAGE_RETURN_FAILURE; + } - /* Signal listener takes ownership of the IP4Config */ - priv->ip4_config = NULL; + _LOGD ("IP4 config is done; setting modem_state -> CONNECTED"); + g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, priv->ip4_config, error); - nm_modem_set_state (NM_MODEM (self), - NM_MODEM_STATE_CONNECTED, - nm_modem_state_to_string (NM_MODEM_STATE_CONNECTED)); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } + /* Signal listener takes ownership of the IP4Config */ + priv->ip4_config = NULL; - return ret; + nm_modem_set_state (NM_MODEM (self), + NM_MODEM_STATE_CONNECTED, + nm_modem_state_to_string (NM_MODEM_STATE_CONNECTED)); + return NM_ACT_STAGE_RETURN_POSTPONE; } static void @@ -955,14 +955,14 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat priv->context_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); if (error) { _LOGE ("failed to create ofono ConnectionContext DBus proxy: %s", error->message); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, - NM_DEVICE_STATE_REASON_MODEM_BUSY); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, + NM_DEVICE_STATE_REASON_MODEM_BUSY); return; } if (!priv->gprs_attached) { - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, + NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); return; } @@ -1038,7 +1038,7 @@ create_connect_properties (NMConnection *connection) static NMActStageReturn act_stage1_prepare (NMModem *modem, NMConnection *connection, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemOfono *self = NM_MODEM_OFONO (modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); @@ -1047,7 +1047,7 @@ act_stage1_prepare (NMModem *modem, context_id = nm_connection_get_id (connection); id = g_strsplit (context_id, "/", 0); - g_assert (id[2]); + g_return_val_if_fail (id[2], NM_ACT_STAGE_RETURN_FAILURE); _LOGD ("trying %s %s", id[1], id[2]); @@ -1058,8 +1058,8 @@ act_stage1_prepare (NMModem *modem, g_strfreev (id); if (!priv->context_path) { - *reason = NM_DEVICE_STATE_REASON_GSM_APN_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; } if (priv->connect_properties) @@ -1073,7 +1073,7 @@ act_stage1_prepare (NMModem *modem, do_context_activate (self); } else { _LOGW ("could not activate context: modem is not registered."); - *reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); return NM_ACT_STAGE_RETURN_FAILURE; } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 1dec0dd1..6494b849 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -33,6 +33,7 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" #include "nm-route-manager.h" +#include "nm-netns.h" #include "nm-act-request.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -158,7 +159,7 @@ nm_modem_set_state (NMModem *self, priv->state = new_state; _notify (self, PROP_STATE); - g_signal_emit (self, signals[STATE_CHANGED], 0, (int) new_state, (int) old_state, reason); + g_signal_emit (self, signals[STATE_CHANGED], 0, (int) new_state, (int) old_state); } } @@ -201,7 +202,7 @@ nm_modem_set_mm_enabled (NMModem *self, /* Try to unlock the modem if it's being enabled */ if (enabled) - g_signal_emit_by_name (self, NM_MODEM_AUTH_REQUESTED, 0); + g_signal_emit (self, signals[AUTH_REQUESTED], 0); return; } @@ -222,6 +223,22 @@ nm_modem_emit_removed (NMModem *self) g_signal_emit (self, signals[REMOVED], 0); } +void +nm_modem_emit_prepare_result (NMModem *self, gboolean success, NMDeviceStateReason reason) +{ + nm_assert (NM_IS_MODEM (self)); + + g_signal_emit (self, signals[PREPARE_RESULT], 0, success, (guint) reason); +} + +void +nm_modem_emit_ppp_failed (NMModem *self, NMDeviceStateReason reason) +{ + nm_assert (NM_IS_MODEM (self)); + + g_signal_emit (self, signals[PPP_FAILED], 0, (guint) reason); +} + NMModemIPType nm_modem_get_supported_ip_types (NMModem *self) { @@ -382,10 +399,10 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_ { switch (status) { case NM_PPP_STATUS_DISCONNECT: - g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); + nm_modem_emit_ppp_failed (user_data, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); break; case NM_PPP_STATUS_DEAD: - g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_FAILED); + nm_modem_emit_ppp_failed (user_data, NM_DEVICE_STATE_REASON_PPP_FAILED); break; default: break; @@ -479,18 +496,19 @@ ppp_ip6_config (NMPPPManager *ppp_manager, static void ppp_stats (NMPPPManager *ppp_manager, - guint32 in_bytes, - guint32 out_bytes, + guint i_in_bytes, + guint i_out_bytes, gpointer user_data) { NMModem *self = NM_MODEM (user_data); NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + guint32 in_bytes = i_in_bytes; + guint32 out_bytes = i_out_bytes; if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) { priv->in_bytes = in_bytes; priv->out_bytes = out_bytes; - - g_signal_emit (self, signals[PPP_STATS], 0, in_bytes, out_bytes); + g_signal_emit (self, signals[PPP_STATS], 0, (guint) in_bytes, (guint) out_bytes); } } @@ -514,18 +532,16 @@ port_speed_is_zero (const char *port) static NMActStageReturn ppp_stage3_ip_config_start (NMModem *self, NMActRequest *req, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); const char *ppp_name = NULL; GError *error = NULL; - NMActStageReturn ret; guint ip_timeout = 30; guint baud_override = 0; g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); /* If we're already running PPP don't restart it; for example, if both * IPv4 and IPv6 are requested, IPv4 gets started first, but we use the @@ -560,24 +576,10 @@ ppp_stage3_ip_config_start (NMModem *self, baud_override = 57600; priv->ppp_manager = nm_ppp_manager_create (priv->data_port, &error); - if ( priv->ppp_manager - && nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, - ip_timeout, baud_override, &error)) { - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK (ppp_state_changed), - self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK (ppp_ip4_config), - self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, - G_CALLBACK (ppp_ip6_config), - self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATS, - G_CALLBACK (ppp_stats), - self); - - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { + + if ( !priv->ppp_manager + || !nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, + ip_timeout, baud_override, &error)) { nm_log_err (LOGD_PPP, "(%s): error starting PPP: %s", nm_modem_get_uid (self), error->message); @@ -585,11 +587,24 @@ ppp_stage3_ip_config_start (NMModem *self, g_clear_object (&priv->ppp_manager); - *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; - ret = NM_ACT_STAGE_RETURN_FAILURE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; } - return ret; + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, + G_CALLBACK (ppp_state_changed), + self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, + G_CALLBACK (ppp_ip4_config), + self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, + G_CALLBACK (ppp_ip6_config), + self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATS, + G_CALLBACK (ppp_stats), + self); + + return NM_ACT_STAGE_RETURN_POSTPONE; } /*****************************************************************************/ @@ -598,7 +613,7 @@ NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *self, NMDevice *device, NMDeviceClass *device_class, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemPrivate *priv; NMActRequest *req; @@ -611,12 +626,13 @@ nm_modem_stage3_ip4_config_start (NMModem *self, g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_DEVICE_CLASS (device_class), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); req = nm_device_get_act_request (device); - g_assert (req); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); + connection = nm_act_request_get_applied_connection (req); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); /* Only Disabled and Auto methods make sense for WWAN */ @@ -627,22 +643,22 @@ nm_modem_stage3_ip4_config_start (NMModem *self, nm_log_warn (LOGD_MB | LOGD_IP4, "(%s): unhandled WWAN IPv4 method '%s'; will fail", nm_modem_get_uid (self), method); - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } priv = NM_MODEM_GET_PRIVATE (self); switch (priv->ip4_method) { case NM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip_config_start (self, req, reason); + ret = ppp_stage3_ip_config_start (self, req, out_failure_reason); break; case NM_MODEM_IP_METHOD_STATIC: nm_log_dbg (LOGD_MB, "MODEM_IP_METHOD_STATIC"); - ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason); + ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, out_failure_reason); break; case NM_MODEM_IP_METHOD_AUTO: nm_log_dbg (LOGD_MB, "MODEM_IP_METHOD_AUTO"); - ret = device_class->act_stage3_ip4_config_start (device, NULL, reason); + ret = device_class->act_stage3_ip4_config_start (device, NULL, out_failure_reason); break; default: nm_log_info (LOGD_MB, "(%s): IPv4 configuration disabled", nm_modem_get_uid (self)); @@ -670,7 +686,7 @@ nm_modem_ip4_pre_commit (NMModem *modem, g_assert (address); if (address->plen == 32) - nm_platform_link_set_noarp (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device)); + nm_platform_link_set_noarp (nm_device_get_platform (device), nm_device_get_ip_ifindex (device)); } } @@ -712,30 +728,28 @@ nm_modem_emit_ip6_config_result (NMModem *self, } static NMActStageReturn -stage3_ip6_config_request (NMModem *self, NMDeviceStateReason *reason) +stage3_ip6_config_request (NMModem *self, NMDeviceStateReason *out_failure_reason) { - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *self, NMActRequest *req, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemPrivate *priv; NMActStageReturn ret; NMConnection *connection; const char *method; - g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_act_request_get_applied_connection (req); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); /* Only Ignore and Auto methods make sense for WWAN */ @@ -746,14 +760,14 @@ nm_modem_stage3_ip6_config_start (NMModem *self, nm_log_warn (LOGD_MB | LOGD_IP6, "(%s): unhandled WWAN IPv6 method '%s'; will fail", nm_modem_get_uid (self), method); - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } priv = NM_MODEM_GET_PRIVATE (self); switch (priv->ip6_method) { case NM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip_config_start (self, req, reason); + ret = ppp_stage3_ip_config_start (self, req, out_failure_reason); break; case NM_MODEM_IP_METHOD_STATIC: case NM_MODEM_IP_METHOD_AUTO: @@ -761,7 +775,7 @@ nm_modem_stage3_ip6_config_start (NMModem *self, * which in the static case is the full config, and the DHCP/Auto case * is just the IPv6LL address to use for SLAAC. */ - ret = NM_MODEM_GET_CLASS (self)->stage3_ip6_config_request (self, reason); + ret = NM_MODEM_GET_CLASS (self)->stage3_ip6_config_request (self, out_failure_reason); break; default: nm_log_info (LOGD_MB, "(%s): IPv6 configuration disabled", nm_modem_get_uid (self)); @@ -772,6 +786,45 @@ nm_modem_stage3_ip6_config_start (NMModem *self, return ret; } +guint32 +nm_modem_get_configured_mtu (NMDevice *self, gboolean *out_is_user_config) +{ + NMConnection *connection; + NMSetting *setting; + gint64 mtu_default; + guint mtu = 0; + const char *property_name; + + nm_assert (NM_IS_DEVICE (self)); + nm_assert (out_is_user_config); + + connection = nm_device_get_applied_connection (self); + if (!connection) + g_return_val_if_reached (0); + + setting = (NMSetting *) nm_connection_get_setting_gsm (connection); + if (!setting) + setting = (NMSetting *) nm_connection_get_setting_cdma (connection); + + if (setting) { + g_object_get (setting, "mtu", &mtu, NULL); + if (mtu) { + *out_is_user_config = TRUE; + return mtu; + } + + property_name = NM_IS_SETTING_GSM (setting) ? "gsm.mtu" : "cdma.mtu"; + mtu_default = nm_device_get_configured_mtu_from_connection_default (self, property_name); + if (mtu_default >= 0) { + *out_is_user_config = TRUE; + return (guint32) mtu_default; + } + } + + *out_is_user_config = FALSE; + return 0; +} + /*****************************************************************************/ static void @@ -835,16 +888,16 @@ nm_modem_get_secrets (NMModem *self, static NMActStageReturn act_stage1_prepare (NMModem *modem, NMConnection *connection, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { - *reason = NM_DEVICE_STATE_REASON_UNKNOWN; + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_UNKNOWN); return NM_ACT_STAGE_RETURN_FAILURE; } NMActStageReturn nm_modem_act_stage1_prepare (NMModem *self, NMActRequest *req, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); gs_unref_ptrarray GPtrArray *hints = NULL; @@ -857,13 +910,13 @@ nm_modem_act_stage1_prepare (NMModem *self, priv->act_request = g_object_ref (req); connection = nm_act_request_get_applied_connection (req); - g_assert (connection); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); setting_name = nm_connection_need_secrets (connection, &hints); if (!setting_name) { /* Ready to connect */ g_assert (!hints); - return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, reason); + return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, out_failure_reason); } /* Secrets required... */ @@ -887,7 +940,7 @@ nm_modem_act_stage1_prepare (NMModem *self, NMActStageReturn nm_modem_act_stage2_config (NMModem *self, NMActRequest *req, - NMDeviceStateReason *reason) + NMDeviceStateReason *out_failure_reason) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); @@ -1016,9 +1069,10 @@ 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_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); + nm_route_manager_route_flush (nm_netns_get_route_manager (nm_device_get_netns (device)), + ifindex); + nm_platform_address_flush (nm_device_get_platform (device), ifindex); + nm_platform_link_set_down (nm_device_get_platform (device), ifindex); } } } @@ -1205,8 +1259,7 @@ nm_modem_deactivate (NMModem *self, NMDevice *device) void nm_modem_device_state_changed (NMModem *self, NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) + NMDeviceState old_state) { gboolean was_connected = FALSE, warn = TRUE; NMModemPrivate *priv; @@ -1396,15 +1449,15 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PATH: - /* Construct only */ + /* construct-only */ priv->path = g_value_dup_string (value); break; case PROP_DRIVER: - /* Construct only */ + /* construct-only */ priv->driver = g_value_dup_string (value); break; case PROP_CONTROL_PORT: - /* Construct only */ + /* construct-only */ priv->control_port = g_value_dup_string (value); break; case PROP_DATA_PORT: @@ -1412,7 +1465,7 @@ set_property (GObject *object, guint prop_id, priv->data_port = g_value_dup_string (value); break; case PROP_UID: - /* Construct only */ + /* construct-only */ priv->uid = g_value_dup_string (value); break; case PROP_IP4_METHOD: @@ -1628,15 +1681,16 @@ nm_modem_class_init (NMModemClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[PPP_STATS] = - g_signal_new ("ppp-stats", + g_signal_new (NM_MODEM_PPP_STATS, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); + G_TYPE_UINT /*guint32 in_bytes*/, + G_TYPE_UINT /*guint32 out_bytes*/); signals[PPP_FAILED] = - g_signal_new ("ppp-failed", + g_signal_new (NM_MODEM_PPP_FAILED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index c590b9e4..a50727a9 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -132,17 +132,17 @@ typedef struct { NMActStageReturn (*act_stage1_prepare) (NMModem *modem, NMConnection *connection, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn (*static_stage3_ip4_config_start) (NMModem *self, NMActRequest *req, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); /* Request the IP6 config; when the config returns the modem * subclass should emit the ip6_config_result signal. */ NMActStageReturn (*stage3_ip6_config_request) (NMModem *self, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); void (*set_mm_enabled) (NMModem *self, gboolean enabled); @@ -187,20 +187,20 @@ gboolean nm_modem_complete_connection (NMModem *self, NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem, NMActRequest *req, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn nm_modem_act_stage2_config (NMModem *modem, NMActRequest *req, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *modem, NMDevice *device, NMDeviceClass *device_class, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem, NMActRequest *req, - NMDeviceStateReason *reason); + NMDeviceStateReason *out_failure_reason); void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config); @@ -222,8 +222,7 @@ gboolean nm_modem_deactivate_async_finish (NMModem *self, void nm_modem_device_state_changed (NMModem *modem, NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason); + NMDeviceState old_state); void nm_modem_set_mm_enabled (NMModem *self, gboolean enabled); @@ -239,6 +238,10 @@ NMModemIPType nm_modem_get_supported_ip_types (NMModem *self); /* For the modem-manager only */ void nm_modem_emit_removed (NMModem *self); +void nm_modem_emit_prepare_result (NMModem *self, gboolean success, NMDeviceStateReason reason); + +void nm_modem_emit_ppp_failed (NMModem *self, NMDeviceStateReason reason); + GArray *nm_modem_get_connection_ip_type (NMModem *self, NMConnection *connection, GError **error); @@ -250,4 +253,6 @@ void nm_modem_emit_ip6_config_result (NMModem *self, const gchar *nm_modem_ip_type_to_string (NMModemIPType ip_type); +guint32 nm_modem_get_configured_mtu (NMDevice *self, gboolean *out_is_user_config); + #endif /* __NETWORKMANAGER_MODEM_H__ */ diff --git a/src/dhcp/nm-dhcp-client-logging.h b/src/dhcp/nm-dhcp-client-logging.h index 8dd18bf2..1047a7d7 100644 --- a/src/dhcp/nm-dhcp-client-logging.h +++ b/src/dhcp/nm-dhcp-client-logging.h @@ -42,7 +42,7 @@ ? LOGD_DHCP \ : (nm_dhcp_client_get_ipv6 (_self) ? LOGD_DHCP6 : LOGD_DHCP4); \ \ - nm_log (_level, _domain, \ + nm_log (_level, _domain, __ifname, NULL, \ "%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (_domain == LOGD_DHCP4 ? "4" : (_domain == LOGD_DHCP6 ? "6" : "")), \ @@ -65,7 +65,7 @@ if (nm_logging_enabled (_level, _domain)) { \ const char *__ifname = (ifname); \ \ - nm_log (_level, _domain, \ + nm_log (_level, _domain, __ifname, NULL, \ "%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (_domain == LOGD_DHCP4 ? "4" : (_domain == LOGD_DHCP6 ? "6" : "")), \ diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index ba7c6dbf..0906f5be 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -68,7 +68,7 @@ typedef struct _NMDhcpClientPrivate { GByteArray * duid; GBytes * client_id; char * hostname; - char * fqdn; + gboolean use_fqdn; NMDhcpState state; pid_t pid; @@ -147,6 +147,14 @@ nm_dhcp_client_get_priority (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->priority; } +guint32 +nm_dhcp_client_get_timeout (NMDhcpClient *self) +{ + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), 0); + + return NM_DHCP_CLIENT_GET_PRIVATE (self)->timeout; +} + GBytes * nm_dhcp_client_get_client_id (NMDhcpClient *self) { @@ -178,12 +186,12 @@ nm_dhcp_client_get_hostname (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; } -const char * -nm_dhcp_client_get_fqdn (NMDhcpClient *self) +gboolean +nm_dhcp_client_get_use_fqdn (NMDhcpClient *self) { - g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->fqdn; + return NM_DHCP_CLIENT_GET_PRIVATE (self)->use_fqdn; } /*****************************************************************************/ @@ -298,7 +306,6 @@ nm_dhcp_client_set_state (NMDhcpClient *self, g_assert ( (priv->ipv6 && NM_IS_IP6_CONFIG (ip_config)) || (!priv->ipv6 && NM_IS_IP4_CONFIG (ip_config))); g_assert (options); - g_assert_cmpint (g_hash_table_size (options), >, 0); } else { g_assert (ip_config == NULL); g_assert (options == NULL); @@ -409,7 +416,7 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, - const char *fqdn, + gboolean use_fqdn, const char *last_ip4_address) { NMDhcpClientPrivate *priv; @@ -430,8 +437,7 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); - g_free (priv->fqdn); - priv->fqdn = g_strdup (fqdn); + priv->use_fqdn = use_fqdn; return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); } @@ -571,7 +577,7 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name) if (start_time == 0) goto out; - nm_sprintf_buf (proc_path, "/proc/%lu/cmdline", (long unsigned) pid); + nm_sprintf_buf (proc_path, "/proc/%lu/cmdline", (unsigned long) pid); if (!g_file_get_contents (proc_path, &proc_contents, NULL, NULL)) goto out; @@ -904,7 +910,6 @@ dispose (GObject *object) g_clear_pointer (&priv->iface, g_free); g_clear_pointer (&priv->hostname, g_free); - g_clear_pointer (&priv->fqdn, g_free); g_clear_pointer (&priv->uuid, g_free); g_clear_pointer (&priv->client_id, g_bytes_unref); diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 7a083ae7..e41a59a2 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -19,10 +19,10 @@ #ifndef __NETWORKMANAGER_DHCP_CLIENT_H__ #define __NETWORKMANAGER_DHCP_CLIENT_H__ -#include <nm-setting-ip4-config.h> -#include <nm-setting-ip6-config.h> -#include <nm-ip4-config.h> -#include <nm-ip6-config.h> +#include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" +#include "nm-ip4-config.h" +#include "nm-ip6-config.h" #define NM_TYPE_DHCP_CLIENT (nm_dhcp_client_get_type ()) #define NM_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClient)) @@ -117,17 +117,19 @@ const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); guint32 nm_dhcp_client_get_priority (NMDhcpClient *self); +guint32 nm_dhcp_client_get_timeout (NMDhcpClient *self); + GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self); const char *nm_dhcp_client_get_hostname (NMDhcpClient *self); -const char *nm_dhcp_client_get_fqdn (NMDhcpClient *self); +gboolean nm_dhcp_client_get_use_fqdn (NMDhcpClient *self); gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, - const char *fqdn, + gboolean use_fqdn, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index f36451b2..216319b3 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -93,29 +93,21 @@ grab_request_options (GPtrArray *store, const char* line) static void -add_hostname4 (GString *str, const char *hostname, const char *fqdn) +add_hostname4 (GString *str, const char *hostname, gboolean use_fqdn) { - char *plain_hostname, *dot; - - if (fqdn) { - g_string_append_printf (str, FQDN_FORMAT "\n", fqdn); - g_string_append (str, - "send fqdn.encoded on;\n" - "send fqdn.server-update on;\n"); - } else if (hostname) { - plain_hostname = g_strdup (hostname); - dot = strchr (plain_hostname, '.'); - /* get rid of the domain */ - if (dot) - *dot = '\0'; - - g_string_append_printf (str, HOSTNAME4_FORMAT "\n", plain_hostname); - g_free (plain_hostname); + if (hostname) { + if (use_fqdn) { + g_string_append_printf (str, FQDN_FORMAT "\n", hostname); + g_string_append (str, + "send fqdn.encoded on;\n" + "send fqdn.server-update on;\n"); + } else + g_string_append_printf (str, HOSTNAME4_FORMAT "\n", hostname); } } static void -add_ip4_config (GString *str, GBytes *client_id, const char *hostname, const char *fqdn) +add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean use_fqdn) { if (client_id) { const char *p; @@ -150,7 +142,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, const cha g_string_append (str, "; # added by NetworkManager\n"); } - add_hostname4 (str, hostname, fqdn); + add_hostname4 (str, hostname, use_fqdn); g_string_append_c (str, '\n'); @@ -232,13 +224,46 @@ nm_dhcp_dhclient_get_client_id_from_config_file (const char *path) return NULL; } +static gboolean +read_interface (const char *line, char *interface, guint size) +{ + gs_free char *dup = g_strdup (line + NM_STRLEN ("interface")); + char *ptr = dup, *end; + + while (g_ascii_isspace (*ptr)) + ptr++; + + if (*ptr == '"') { + ptr++; + end = strchr (ptr, '"'); + if (!end) + return FALSE; + *end = '\0'; + } else { + end = strchr (ptr, ' '); + if (!end) + end = strchr (ptr, '{'); + if (!end) + return FALSE; + *end = '\0'; + } + + if ( ptr[0] == '\0' + || strlen (ptr) + 1 > size) + return FALSE; + + snprintf (interface, size, "%s", ptr); + + return TRUE; +} + char * nm_dhcp_dhclient_create_config (const char *interface, gboolean is_ip6, GBytes *client_id, const char *anycast_addr, const char *hostname, - const char *fqdn, + gboolean use_fqdn, const char *orig_path, const char *orig_contents, GBytes **out_new_client_id) @@ -258,8 +283,10 @@ nm_dhcp_dhclient_create_config (const char *interface, char **lines, **line; gboolean in_alsoreq = FALSE; gboolean in_req = FALSE; + char intf[IFNAMSIZ]; g_string_append_printf (new_contents, _("# Merged from %s\n\n"), orig_path); + intf[0] = '\0'; lines = g_strsplit_set (orig_contents, "\n\r", 0); for (line = lines; lines && *line; line++) { @@ -268,6 +295,20 @@ nm_dhcp_dhclient_create_config (const char *interface, if (!strlen (g_strstrip (p))) continue; + if ( !intf[0] + && g_str_has_prefix (p, "interface")) { + if (read_interface (p, intf, sizeof (intf))) + continue; + } + + if (intf[0] && strchr (p, '}')) { + intf[0] = '\0'; + continue; + } + + if (intf[0] && !nm_streq (intf, interface)) + continue; + if (!strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG))) { /* Override config file "dhcp-client-id" and use one from the connection */ if (client_id) @@ -279,7 +320,7 @@ nm_dhcp_dhclient_create_config (const char *interface, } /* Override config file hostname and use one from the connection */ - if (hostname || fqdn) { + if (hostname) { if (strncmp (p, HOSTNAME4_TAG, strlen (HOSTNAME4_TAG)) == 0) continue; if (strncmp (p, FQDN_TAG, strlen (FQDN_TAG)) == 0) @@ -339,7 +380,7 @@ nm_dhcp_dhclient_create_config (const char *interface, add_request (reqs, "dhcp6.domain-search"); add_request (reqs, "dhcp6.client-id"); } else { - add_ip4_config (new_contents, client_id, hostname, fqdn); + add_ip4_config (new_contents, client_id, hostname, use_fqdn); add_request (reqs, "rfc3442-classless-static-routes"); add_request (reqs, "ms-classless-static-routes"); add_request (reqs, "static-routes"); diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h index 83d5a23d..994b1b9f 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/dhcp/nm-dhcp-dhclient-utils.h @@ -19,15 +19,15 @@ #ifndef __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ #define __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ -#include <nm-setting-ip4-config.h> -#include <nm-setting-ip6-config.h> +#include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" char *nm_dhcp_dhclient_create_config (const char *interface, gboolean is_ip6, GBytes *client_id, const char *anycast_addr, const char *hostname, - const char *fqdn, + gboolean use_fqdn, const char *orig_path, const char *orig_contents, GBytes **out_new_client_id); diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 64d93744..a56e5a3c 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -182,7 +182,7 @@ merge_dhclient_config (NMDhcpDhclient *self, GBytes *client_id, const char *anycast_addr, const char *hostname, - const char *fqdn, + gboolean use_fqdn, const char *orig_path, GBytes **out_new_client_id, GError **error) @@ -206,7 +206,7 @@ merge_dhclient_config (NMDhcpDhclient *self, if (is_ip6 && hostname && !strchr (hostname, '.')) _LOGW ("hostname is not a FQDN, it will be ignored"); - new = nm_dhcp_dhclient_create_config (iface, is_ip6, client_id, anycast_addr, hostname, fqdn, orig_path, orig, out_new_client_id); + new = nm_dhcp_dhclient_create_config (iface, is_ip6, client_id, anycast_addr, hostname, use_fqdn, orig_path, orig, out_new_client_id); g_assert (new); success = g_file_set_contents (conf_file, new, -1, error); g_free (new); @@ -294,7 +294,7 @@ create_dhclient_config (NMDhcpDhclient *self, GBytes *client_id, const char *dhcp_anycast_addr, const char *hostname, - const char *fqdn, + gboolean use_fqdn, GBytes **out_new_client_id) { char *orig = NULL, *new = NULL; @@ -314,7 +314,7 @@ create_dhclient_config (NMDhcpDhclient *self, error = NULL; success = merge_dhclient_config (self, iface, new, is_ip6, client_id, dhcp_anycast_addr, - hostname, fqdn, orig, out_new_client_id, &error); + hostname, use_fqdn, orig, out_new_client_id, &error); if (!success) { _LOGW ("error creating dhclient configuration: %s", error->message); g_error_free (error); @@ -342,6 +342,8 @@ dhclient_start (NMDhcpClient *client, char *binary_name, *cmd_str, *pid_file = NULL, *system_bus_address_env = NULL; gboolean ipv6, success; char *escaped, *preferred_leasefile_path = NULL; + guint32 timeout; + char timeout_str[64]; g_return_val_if_fail (priv->pid_file == NULL, FALSE); @@ -444,6 +446,17 @@ dhclient_start (NMDhcpClient *client, g_ptr_array_add (argv, (gpointer) priv->conf_file); } + /* Specify a timeout longer than configuration's one, + * so that dhclient doesn't send back a FAIL event before + * that time. + */ + timeout = nm_dhcp_client_get_timeout (client); + if (timeout >= 60) { + timeout = timeout < G_MAXINT32 ? timeout + 1 : G_MAXINT32; + g_ptr_array_add (argv, (gpointer) "-timeout"); + g_ptr_array_add (argv, (gpointer) nm_sprintf_buf (timeout_str, "%u", (unsigned) timeout)); + } + /* Usually the system bus address is well-known; but if it's supposed * to be something else, we need to push it to dhclient, since dhclient * sanitizes the environment it gives the action scripts. @@ -492,17 +505,18 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); GBytes *client_id; gs_unref_bytes GBytes *new_client_id = NULL; - const char *iface, *uuid, *hostname, *fqdn; + const char *iface, *uuid, *hostname; gboolean success = FALSE; + gboolean use_fqdn; iface = nm_dhcp_client_get_iface (client); uuid = nm_dhcp_client_get_uuid (client); client_id = nm_dhcp_client_get_client_id (client); hostname = nm_dhcp_client_get_hostname (client); - fqdn = nm_dhcp_client_get_fqdn (client); + use_fqdn = nm_dhcp_client_get_use_fqdn (client); priv->conf_file = create_dhclient_config (self, iface, FALSE, uuid, client_id, dhcp_anycast_addr, - hostname, fqdn, &new_client_id); + hostname, use_fqdn, &new_client_id); if (priv->conf_file) { if (new_client_id) nm_dhcp_client_set_client_id (client, new_client_id); @@ -530,7 +544,7 @@ ip6_start (NMDhcpClient *client, uuid = nm_dhcp_client_get_uuid (client); hostname = nm_dhcp_client_get_hostname (client); - priv->conf_file = create_dhclient_config (self, iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname, NULL, NULL); + priv->conf_file = create_dhclient_config (self, iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname, TRUE, NULL); if (!priv->conf_file) { _LOGW ("error creating dhclient configuration file"); return FALSE; diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index c8643881..66a31acf 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -88,9 +88,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last GPtrArray *argv = NULL; pid_t pid = -1; GError *error = NULL; - char *pid_contents = NULL, *binary_name, *cmd_str, *dot; - const char *iface, *dhcpcd_path, *hostname, *fqdn; - gs_free char *prefix = NULL; + char *pid_contents = NULL, *binary_name, *cmd_str; + const char *iface, *dhcpcd_path, *hostname; g_return_val_if_fail (priv->pid_file == NULL, FALSE); @@ -138,22 +137,17 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last #endif hostname = nm_dhcp_client_get_hostname (client); - fqdn = nm_dhcp_client_get_fqdn (client); - - if (fqdn) { - g_ptr_array_add (argv, (gpointer) "-h"); - g_ptr_array_add (argv, (gpointer) fqdn); - g_ptr_array_add (argv, (gpointer) "-F"); - g_ptr_array_add (argv, (gpointer) "both"); - } else if (hostname) { - prefix = strdup (hostname); - dot = strchr (prefix, '.'); - /* get rid of the domain */ - if (dot) - *dot = '\0'; - - g_ptr_array_add (argv, (gpointer) "-h"); /* Send hostname to DHCP server */ - g_ptr_array_add (argv, (gpointer) prefix); + + if (hostname) { + if (nm_dhcp_client_get_use_fqdn (client)) { + g_ptr_array_add (argv, (gpointer) "-h"); + g_ptr_array_add (argv, (gpointer) hostname); + g_ptr_array_add (argv, (gpointer) "-F"); + g_ptr_array_add (argv, (gpointer) "both"); + } else { + g_ptr_array_add (argv, (gpointer) "-h"); + g_ptr_array_add (argv, (gpointer) hostname); + } } g_ptr_array_add (argv, (gpointer) iface); diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index 56bd9d17..ca697ab3 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -92,7 +92,7 @@ NM_DEFINE_SINGLETON_GETTER (NMDhcpListener, nm_dhcp_listener_get, NM_TYPE_DHCP_L const NMDhcpListener *_self = (self); \ char _prefix[64]; \ \ - nm_log ((level), (_NMLOG_DOMAIN), \ + nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ (_self != singleton_instance \ ? nm_sprintf_buf (_prefix, "%s[%p]", _NMLOG_PREFIX_NAME, _self) \ diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index 9c1fbb38..fff9f9ec 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -163,7 +163,7 @@ client_start (NMDhcpManager *self, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, - const char *fqdn, + gboolean hostname_use_fqdn, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const char *last_ip4_address, @@ -209,7 +209,7 @@ client_start (NMDhcpManager *self, if (ipv6) success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); else - success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, fqdn, last_ip4_address); + success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, hostname_use_fqdn, last_ip4_address); if (!success) { remove_client (self, client); @@ -219,15 +219,6 @@ client_start (NMDhcpManager *self, return client; } -static const char * -get_send_hostname (NMDhcpManager *self, const char *setting_hostname) -{ - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self); - - /* Always prefer the explicit dhcp-send-hostname if given */ - return setting_hostname ? setting_hostname : priv->default_hostname; -} - /* Caller owns a reference to the NMDhcpClient on return */ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *self, @@ -244,18 +235,41 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, const char *dhcp_anycast_addr, const char *last_ip_address) { + NMDhcpManagerPrivate *priv; const char *hostname = NULL; - const char *fqdn = NULL; + gs_free char *hostname_tmp = NULL; + gboolean use_fqdn = FALSE; + char *dot; g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); + priv = NM_DHCP_MANAGER_GET_PRIVATE (self); if (send_hostname) { - hostname = get_send_hostname (self, dhcp_hostname); - fqdn = dhcp_fqdn; + /* Use, in order of preference: + * 1. FQDN from configuration + * 2. hostname from configuration + * 3. system hostname (only host part) + */ + if (dhcp_fqdn) { + hostname = dhcp_fqdn; + use_fqdn = TRUE; + } else if (dhcp_hostname) + hostname = dhcp_hostname; + else { + hostname = priv->default_hostname; + if (hostname) { + hostname_tmp = g_strdup (hostname); + dot = strchr (hostname_tmp, '.'); + if (dot) + *dot = '\0'; + hostname = hostname_tmp; + } + } } + return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL, dhcp_client_id, timeout, dhcp_anycast_addr, hostname, - fqdn, FALSE, 0, last_ip_address, 0); + use_fqdn, FALSE, 0, last_ip_address, 0); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -275,14 +289,18 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes) { + NMDhcpManagerPrivate *priv; const char *hostname = NULL; g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); + priv = NM_DHCP_MANAGER_GET_PRIVATE (self); - if (send_hostname) - hostname = get_send_hostname (self, dhcp_hostname); + if (send_hostname) { + /* Always prefer the explicit dhcp-hostname if given */ + hostname = dhcp_hostname ? dhcp_hostname : priv->default_hostname; + } return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE, - ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, NULL, info_only, + ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, TRUE, info_only, privacy, NULL, needed_prefixes); } diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 7067275b..aa902701 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -580,7 +580,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last const uint8_t *client_id = NULL; size_t client_id_len = 0; struct in_addr last_addr = { 0 }; - const char *hostname, *fqdn; + const char *hostname; int r, i; gboolean success = FALSE; guint16 arp_type; @@ -687,28 +687,13 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last hostname = nm_dhcp_client_get_hostname (client); if (hostname) { - char *prefix, *dot; - - prefix = strdup (hostname); - dot = strchr (prefix, '.'); - /* get rid of the domain */ - if (dot) - *dot = '\0'; - - r = sd_dhcp_client_set_hostname (priv->client4, prefix); - free (prefix); - - if (r < 0) { - _LOGW ("failed to set DHCP hostname (%d)", r); - goto error; - } - } - - fqdn = nm_dhcp_client_get_fqdn (client); - if (fqdn) { - r = sd_dhcp_client_set_hostname (priv->client4, fqdn); + /* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81) + * only based on whether the hostname has a domain part or not. At the + * moment there is no way to force one or another. + */ + r = sd_dhcp_client_set_hostname (priv->client4, hostname); if (r < 0) { - _LOGW ("failed to set DHCP FQDN (%d)", r); + _LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r); goto error; } } diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index b45c5e89..05982b16 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -21,8 +21,8 @@ #include <stdlib.h> -#include <nm-ip4-config.h> -#include <nm-ip6-config.h> +#include "nm-ip4-config.h" +#include "nm-ip6-config.h" NMIP4Config *nm_dhcp_utils_ip4_config_from_options (int ifindex, const char *iface, diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index f4cf9c9f..40a3e072 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -40,7 +40,7 @@ test_config (const char *orig, const char *expected, gboolean ipv6, const char *hostname, - const char *fqdn, + gboolean use_fqdn, const char *dhcp_client_id, GBytes *expected_new_client_id, const char *iface, @@ -60,7 +60,7 @@ test_config (const char *orig, client_id, anycast_addr, hostname, - fqdn, + use_fqdn, "/path/to/dhclient.conf", orig, &new_client_id); @@ -105,7 +105,7 @@ static const char *orig_missing_expected = \ static void test_orig_missing (void) { - test_config (NULL, orig_missing_expected, FALSE, NULL, NULL, NULL, NULL, "eth0", NULL); + test_config (NULL, orig_missing_expected, FALSE, NULL, FALSE, NULL, NULL, "eth0", NULL); } /*****************************************************************************/ @@ -134,7 +134,7 @@ static void test_override_client_id (void) { test_config (override_client_id_orig, override_client_id_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, "11:22:33:44:55:66", NULL, "eth0", @@ -163,7 +163,7 @@ static void test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, "1234", NULL, "eth0", @@ -192,7 +192,7 @@ static void test_ascii_client_id (void) { test_config (NULL, ascii_client_id_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, "qb:cd:ef:12:34:56", NULL, "eth0", @@ -221,7 +221,7 @@ static void test_hex_single_client_id (void) { test_config (NULL, hex_single_client_id_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, "ab:cd:e:12:34:56", NULL, "eth0", @@ -258,7 +258,7 @@ test_existing_hex_client_id (void) new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, NULL, new_client_id, "eth0", @@ -298,7 +298,7 @@ test_existing_ascii_client_id (void) memcpy (buf + 1, EACID, NM_STRLEN (EACID)); new_client_id = g_bytes_new (buf, sizeof (buf)); test_config (existing_ascii_client_id_orig, existing_ascii_client_id_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, NULL, new_client_id, "eth0", @@ -327,8 +327,8 @@ static void test_fqdn (void) { test_config (NULL, fqdn_expected, - FALSE, NULL, - "foo.bar.com", NULL, + FALSE, "foo.bar.com", + TRUE, NULL, NULL, "eth0", NULL); @@ -367,8 +367,8 @@ test_fqdn_options_override (void) { test_config (fqdn_options_override_orig, fqdn_options_override_expected, - FALSE, NULL, - "example2.com", NULL, + FALSE, "example2.com", + TRUE, NULL, NULL, "eth0", NULL); @@ -400,7 +400,7 @@ static void test_override_hostname (void) { test_config (override_hostname_orig, override_hostname_expected, - FALSE, "blahblah", NULL, + FALSE, "blahblah", FALSE, NULL, NULL, "eth0", @@ -429,7 +429,7 @@ static void test_override_hostname6 (void) { test_config (override_hostname6_orig, override_hostname6_expected, - TRUE, "blahblah.local", NULL, + TRUE, "blahblah.local", TRUE, NULL, NULL, "eth0", @@ -452,7 +452,7 @@ test_nonfqdn_hostname6 (void) /* Non-FQDN hostname can't be used with dhclient */ test_config (NULL, nonfqdn_hostname6_expected, TRUE, "blahblah", - NULL, NULL, + TRUE, NULL, NULL, "eth0", NULL); @@ -487,7 +487,7 @@ test_existing_alsoreq (void) { test_config (existing_alsoreq_orig, existing_alsoreq_expected, FALSE, NULL, - NULL, + FALSE, NULL, NULL, "eth0", @@ -526,7 +526,7 @@ test_existing_req (void) { test_config (existing_req_orig, existing_req_expected, FALSE, NULL, - NULL, + FALSE, NULL, NULL, "eth0", @@ -565,7 +565,7 @@ static void test_existing_multiline_alsoreq (void) { test_config (existing_multiline_alsoreq_orig, existing_multiline_alsoreq_expected, - FALSE, NULL, NULL, + FALSE, NULL, FALSE, NULL, NULL, "eth0", @@ -744,6 +744,95 @@ test_write_existing_commented_duid (void) /*****************************************************************************/ +static const char *interface1_orig = \ + "interface \"eth0\" {\n" + " also request my-option;\n" + " initial-delay 5;\n" + "}\n" + "interface \"eth1\" {\n" + " also request another-option;\n" + " initial-delay 0;\n" + "}\n" + "\n" + "also request yet-another-option;\n"; + +static const char *interface1_expected = \ + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "initial-delay 5;\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request my-option;\n" + "also request yet-another-option;\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "\n"; + +static void +test_interface1 (void) +{ + test_config (interface1_orig, interface1_expected, + FALSE, NULL, FALSE, + NULL, + NULL, + "eth0", + NULL); +} + +/*****************************************************************************/ + +static const char *interface2_orig = \ + "interface eth0 {\n" + " also request my-option;\n" + " initial-delay 5;\n" + " }\n" + "interface eth1 {\n" + " initial-delay 0;\n" + " request another-option;\n" + " } \n" + "\n" + "also request yet-another-option;\n"; + +static const char *interface2_expected = \ + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "initial-delay 0;\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "request; # override dhclient defaults\n" + "also request another-option;\n" + "also request yet-another-option;\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "\n"; + +static void +test_interface2 (void) +{ + test_config (interface2_orig, interface2_expected, + FALSE, NULL, FALSE, + NULL, + NULL, + "eth1", + NULL); +} + +/*****************************************************************************/ + static void test_read_lease_ip4_config_basic (void) { @@ -891,6 +980,8 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/existing_alsoreq", test_existing_alsoreq); g_test_add_func ("/dhcp/dhclient/existing_multiline_alsoreq", test_existing_multiline_alsoreq); g_test_add_func ("/dhcp/dhclient/duids", test_duids); + g_test_add_func ("/dhcp/dhclient/interface/1", test_interface1); + g_test_add_func ("/dhcp/dhclient/interface/2", test_interface2); g_test_add_func ("/dhcp/dhclient/read_duid_from_leasefile", test_read_duid_from_leasefile); g_test_add_func ("/dhcp/dhclient/read_commented_duid_from_leasefile", test_read_commented_duid_from_leasefile); diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 55e04180..1f7eb964 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2004 - 2005 Colin Walters <walters@redhat.com> - * Copyright (C) 2004 - 2013 Red Hat, Inc. + * Copyright (C) 2004 - 2017 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. * and others */ @@ -35,6 +35,10 @@ #include <linux/fs.h> +#if WITH_LIBPSL +#include <libpsl.h> +#endif + #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-dns-manager.h" @@ -52,20 +56,6 @@ #include "introspection/org.freedesktop.NetworkManager.DnsManager.h" -#if WITH_LIBSOUP -#include <libsoup/soup.h> - -#ifdef SOUP_CHECK_VERSION -#if SOUP_CHECK_VERSION (2, 40, 0) -#define DOMAIN_IS_VALID(domain) (*(domain) && !soup_tld_domain_is_public_suffix (domain)) -#endif -#endif -#endif - -#ifndef DOMAIN_IS_VALID -#define DOMAIN_IS_VALID(domain) (*(domain)) -#endif - #define HASH_LEN 20 #ifndef RESOLVCONF_PATH @@ -114,7 +104,7 @@ NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGE char __prefix[20]; \ const NMDnsManager *const __self = (self); \ \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ ((!__self || __self == singleton_instance) \ @@ -130,7 +120,10 @@ typedef struct { GPtrArray *configs; GVariant *config_variant; NMDnsIPConfigData *best_conf4, *best_conf6; - gboolean need_sort; + + bool need_sort:1; + bool dns_touched:1; + bool is_stopped:1; char *hostname; guint updates_queue; @@ -144,8 +137,6 @@ typedef struct { NMConfig *config; - gboolean dns_touched; - struct { guint64 ts; guint num_restarts; @@ -166,6 +157,18 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_DNS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsManager, NM_IS_DNS_MANAGER) +static gboolean +domain_is_valid (const gchar *domain) +{ + if (*domain == '\0') + return FALSE; +#if WITH_LIBPSL + if (psl_is_public_suffix (psl_builtin (), domain)) + return FALSE; +#endif + return TRUE; +} + /*****************************************************************************/ typedef struct { @@ -305,7 +308,7 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) const char *search; search = nm_ip4_config_get_search (src, i); - if (!DOMAIN_IS_VALID (search)) + if (!domain_is_valid (search)) continue; add_string_item (rc->searches, search); } @@ -315,7 +318,7 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) const char *domain; domain = nm_ip4_config_get_domain (src, i); - if (!DOMAIN_IS_VALID (domain)) + if (!domain_is_valid (domain)) continue; add_string_item (rc->searches, domain); } @@ -375,7 +378,7 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface) const char *search; search = nm_ip6_config_get_search (src, i); - if (!DOMAIN_IS_VALID (search)) + if (!domain_is_valid (search)) continue; add_string_item (rc->searches, search); } @@ -385,7 +388,7 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface) const char *domain; domain = nm_ip6_config_get_domain (src, i); - if (!DOMAIN_IS_VALID (domain)) + if (!domain_is_valid (domain)) continue; add_string_item (rc->searches, domain); } @@ -606,6 +609,8 @@ dispatch_resolvconf (NMDnsManager *self, FILE *f; gboolean success = FALSE; int errnosv, err; + char *argv[] = { RESOLVCONF_PATH, "-d", "NetworkManager", NULL }; + int status; if (!g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) { g_set_error_literal (error, @@ -618,9 +623,17 @@ dispatch_resolvconf (NMDnsManager *self, if (!searches && !nameservers) { _LOGI ("Removing DNS information from %s", RESOLVCONF_PATH); - cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); - if (nm_spawn_process (cmd, error) != 0) + if (!g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, error)) + return SR_ERROR; + + if (status != 0) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "%s returned error code", + RESOLVCONF_PATH); return SR_ERROR; + } return SR_SUCCESS; } @@ -657,6 +670,20 @@ dispatch_resolvconf (NMDnsManager *self, return success ? SR_SUCCESS : SR_ERROR; } +static const char * +_read_link_cached (const char *path, gboolean *is_cached, char **cached) +{ + nm_assert (is_cached); + nm_assert (cached); + + if (*is_cached) + return *cached; + + nm_assert (!*cached); + *is_cached = TRUE; + return (*cached = g_file_read_link (path, NULL)); +} + #define MY_RESOLV_CONF NMRUNDIR "/resolv.conf" #define MY_RESOLV_CONF_TMP MY_RESOLV_CONF ".tmp" #define RESOLV_CONF_TMP "/etc/.resolv.conf.NetworkManager" @@ -670,13 +697,14 @@ update_resolv_conf (NMDnsManager *self, NMDnsManagerResolvConfManager rc_manager) { FILE *f; - struct stat st; gboolean success; gs_free char *content = NULL; SpawnResult write_file_result = SR_SUCCESS; int errsv; const char *rc_path = _PATH_RESCONF; nm_auto_free char *rc_path_real = NULL; + gboolean resconf_link_cached = FALSE; + gs_free char *resconf_link = NULL; /* If we are not managing /etc/resolv.conf and it points to * MY_RESOLV_CONF, don't write the private DNS configuration to @@ -686,9 +714,8 @@ update_resolv_conf (NMDnsManager *self, * This is the only situation, where we don't try to update our * internal resolv.conf file. */ if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED) { - gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL); - - if (g_strcmp0 (path, MY_RESOLV_CONF) == 0) { + if (nm_streq0 (_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link), + MY_RESOLV_CONF)) { _LOGD ("update-resolv-conf: not updating " _PATH_RESCONF " since it points to " MY_RESOLV_CONF); return SR_SUCCESS; @@ -697,12 +724,16 @@ update_resolv_conf (NMDnsManager *self, content = create_resolv_conf (searches, nameservers, options); - if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) { + if ( rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE + || ( rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK + && !_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link))) { GError *local = NULL; - rc_path_real = realpath (rc_path, NULL); - if (rc_path_real) - rc_path = rc_path_real; + if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) { + rc_path_real = realpath (rc_path, NULL); + if (rc_path_real) + rc_path = rc_path_real; + } /* we first write to /etc/resolv.conf directly. If that fails, * we still continue to write to runstatedir but remember the @@ -777,60 +808,23 @@ update_resolv_conf (NMDnsManager *self, return write_file_result; } - if (rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK) { + if ( rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK + || !_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link)) { _LOGT ("update-resolv-conf: write internal file %s succeeded", MY_RESOLV_CONF); return SR_SUCCESS; } - /* A symlink pointing to NM's own resolv.conf (MY_RESOLV_CONF) is always - * overwritten to ensure that changes are indicated with inotify. Symlinks - * pointing to any other file are never overwritten. - */ - if (lstat (_PATH_RESCONF, &st) != 0) { - errsv = errno; - if (errsv != ENOENT) { - /* NM cannot read /etc/resolv.conf */ - _LOGT ("update-resolv-conf: write internal file %s succeeded but lstat(%s) failed (%s)", - MY_RESOLV_CONF, _PATH_RESCONF, g_strerror (errsv)); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not lstat %s: %s", - _PATH_RESCONF, - g_strerror (errsv)); - return SR_ERROR; - } - } else { - if (S_ISLNK (st.st_mode)) { - if (stat (_PATH_RESCONF, &st) != -1) { - gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL); - - if (!path || !nm_streq (path, MY_RESOLV_CONF)) { - /* It's not NM's symlink; do nothing */ - _LOGT ("update-resolv-conf: write internal file %s succeeded " - "but don't update %s as it points to %s", - MY_RESOLV_CONF, _PATH_RESCONF, path ?: ""); - return SR_SUCCESS; - } - - /* resolv.conf is a symlink owned by NM and the target is accessible - */ - } else { - /* resolv.conf is a symlink but the target is not accessible; - * some other program is probably managing resolv.conf and - * NM should not touch it. - */ - _LOGT ("update-resolv-conf: write internal file %s succeeded " - "but don't update %s as the symlinks points somewhere else", - MY_RESOLV_CONF, _PATH_RESCONF); - return SR_SUCCESS; - } - } + if (!nm_streq0 (_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link), + MY_RESOLV_CONF)) { + _LOGT ("update-resolv-conf: write internal file %s succeeded (don't touch symlink %s linking to %s)", + MY_RESOLV_CONF, _PATH_RESCONF, + _read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link)); + return SR_SUCCESS; } - /* By this point, either /etc/resolv.conf does not exist, is a regular - * file, or is a symlink already owned by NM. In all cases /etc/resolv.conf - * is replaced with a symlink pointing to NM's resolv.conf in /var/run/. + /* By this point, /etc/resolv.conf exists and is a symlink to our internal + * resolv.conf. We update the symlink so that applications get an inotify + * notification. */ if ( unlink (RESOLV_CONF_TMP) != 0 && ((errsv = errno) != ENOENT)) { @@ -925,7 +919,7 @@ merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) options = nm_global_dns_config_get_options (global_conf); for (i = 0; searches && searches[i]; i++) { - if (DOMAIN_IS_VALID (searches[i])) + if (domain_is_valid (searches[i])) add_string_item (rc->searches, searches[i]); } @@ -1066,9 +1060,9 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o if ( hostdomain && !nm_utils_ipaddr_valid (AF_UNSPEC, hostname)) { hostdomain++; - if (DOMAIN_IS_VALID (hostdomain)) + if (domain_is_valid (hostdomain)) add_string_item (rc.searches, hostdomain); - else if (DOMAIN_IS_VALID (hostname)) + else if (domain_is_valid (hostname)) add_string_item (rc.searches, hostname); } } @@ -1114,6 +1108,11 @@ update_dns (NMDnsManager *self, priv = NM_DNS_MANAGER_GET_PRIVATE (self); + if (priv->is_stopped) { + _LOGD ("update-dns: not updating resolv.conf (is stopped)"); + return TRUE; + } + nm_clear_g_source (&priv->plugin_ratelimit.timer); if (NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, @@ -1187,6 +1186,10 @@ update_dns (NMDnsManager *self, case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: result = update_resolv_conf (self, searches, nameservers, options, error, priv->rc_manager); resolv_conf_updated = TRUE; + /* If we have ended with no nameservers avoid updating again resolv.conf + * on stop, as some external changes may be applied to it in the meanwhile */ + if (!nameservers && !options) + priv->dns_touched = FALSE; break; case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: result = dispatch_resolvconf (self, searches, nameservers, options, error); @@ -1437,7 +1440,8 @@ nm_dns_manager_set_initial_hostname (NMDnsManager *self, void nm_dns_manager_set_hostname (NMDnsManager *self, - const char *hostname) + const char *hostname, + gboolean skip_update) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); GError *error = NULL; @@ -1458,6 +1462,8 @@ nm_dns_manager_set_hostname (NMDnsManager *self, g_free (priv->hostname); priv->hostname = g_strdup (filtered); + if (skip_update) + return; if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); @@ -1536,6 +1542,35 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func) memset (priv->prev_hash, 0, sizeof (priv->prev_hash)); } +void +nm_dns_manager_stop (NMDnsManager *self) +{ + NMDnsManagerPrivate *priv; + GError *error = NULL; + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + + if (priv->is_stopped) + g_return_if_reached (); + + _LOGT ("stopping..."); + + /* If we're quitting, leave a valid resolv.conf in place, not one + * pointing to 127.0.0.1 if any plugins were active. Thus update + * DNS after disposing of all plugins. But if we haven't done any + * DNS updates yet, there's no reason to touch resolv.conf on shutdown. + */ + if (priv->dns_touched) { + if (!update_dns (self, TRUE, &error)) { + _LOGW ("could not commit DNS changes on shutdown: %s", error->message); + g_clear_error (&error); + } + priv->dns_touched = FALSE; + } + + priv->is_stopped = TRUE; +} + /*****************************************************************************/ static gboolean @@ -1624,9 +1659,9 @@ _resolvconf_resolved_managed (void) NULL, NULL); if (info && g_file_info_get_is_symlink (info)) { - ret = _nm_utils_strv_find_first ((gchar **) resolved_paths, - G_N_ELEMENTS (resolved_paths), - g_file_info_get_symlink_target (info)) >= 0; + ret = nm_utils_strv_find_first ((gchar **) resolved_paths, + G_N_ELEMENTS (resolved_paths), + g_file_info_get_symlink_target (info)) >= 0; } g_clear_object(&info); @@ -2018,23 +2053,14 @@ dispose (GObject *object) NMDnsManager *self = NM_DNS_MANAGER (object); NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); NMDnsIPConfigData *data; - GError *error = NULL; guint i; _LOGT ("disposing"); - _clear_plugin (self); + if (!priv->is_stopped) + nm_dns_manager_stop (self); - /* If we're quitting, leave a valid resolv.conf in place, not one - * pointing to 127.0.0.1 if any plugins were active. Thus update - * DNS after disposing of all plugins. But if we haven't done any - * DNS updates yet, there's no reason to touch resolv.conf on shutdown. - */ - if (priv->dns_touched && !update_dns (self, TRUE, &error)) { - _LOGW ("could not commit DNS changes on shutdown: %s", error->message); - g_clear_error (&error); - priv->dns_touched = FALSE; - } + _clear_plugin (self); if (priv->config) { g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index 2fc2031b..899e4bb8 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -87,7 +87,8 @@ gboolean nm_dns_manager_remove_ip6_config (NMDnsManager *self, NMIP6Config *conf void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname); void nm_dns_manager_set_hostname (NMDnsManager *self, - const char *hostname); + const char *hostname, + gboolean skip_update); /** * NMDnsManagerResolvConfManager @@ -120,4 +121,6 @@ typedef enum { gboolean nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self); +void nm_dns_manager_stop (NMDnsManager *self); + #endif /* __NETWORKMANAGER_DNS_MANAGER_H__ */ diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c index 3a3bc646..00729c93 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -63,7 +63,7 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A char __prefix[20]; \ const NMDnsPlugin *const __self = (self); \ \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (!__self \ diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 325088e2..ed165618 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -118,9 +118,6 @@ add_interface_configuration (NMDnsSystemdResolved *self, device = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex); - if (!nm_device_get_managed (device, FALSE)) - return; - for (i = 0; i < interfaces->len; i++) { InterfaceConfig *tic = &g_array_index (interfaces, InterfaceConfig, i); if (ifindex == tic->ifindex) { diff --git a/src/dns/nm-dns-unbound.c b/src/dns/nm-dns-unbound.c index 3659beac..6af4bad8 100644 --- a/src/dns/nm-dns-unbound.c +++ b/src/dns/nm-dns-unbound.c @@ -43,6 +43,9 @@ update (NMDnsPlugin *plugin, const NMGlobalDnsConfig *global_config, const char *hostname) { + char *argv[] = { DNSSEC_TRIGGER_SCRIPT, "--async", "--update", NULL }; + int status; + /* TODO: We currently call a script installed with the dnssec-trigger * package that queries all information itself. Later, the dependency * on that package will be optional and the only hard dependency will @@ -52,7 +55,9 @@ update (NMDnsPlugin *plugin, * without calling custom scripts. The dnssec-trigger functionality * may be eventually merged into NetworkManager. */ - return nm_spawn_process (DNSSEC_TRIGGER_SCRIPT " --async --update", NULL) == 0; + if (!g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, NULL)) + return FALSE; + return (status == 0); } static gboolean diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index 9b24e69e..f76c983d 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -152,13 +152,15 @@ create_dm_cmd_line (const char *iface, GError **error) { NMCmdLine *cmd; - GString *s; + nm_auto_free_gstring GString *s = NULL; char first[INET_ADDRSTRLEN]; char last[INET_ADDRSTRLEN]; char localaddr[INET_ADDRSTRLEN]; + char tmpaddr[INET_ADDRSTRLEN]; char *error_desc = NULL; const char *dm_binary; const NMPlatformIP4Address *listen_address; + guint i, n; listen_address = nm_ip4_config_get_address (ip4_config, 0); g_return_val_if_fail (listen_address, NULL); @@ -167,6 +169,8 @@ create_dm_cmd_line (const char *iface, if (!dm_binary) return NULL; + s = g_string_sized_new (100); + /* Create dnsmasq command line */ cmd = nm_cmd_line_new (); nm_cmd_line_add_string (cmd, dm_binary); @@ -196,11 +200,11 @@ create_dm_cmd_line (const char *iface, */ nm_cmd_line_add_string (cmd, "--strict-order"); - s = g_string_new ("--listen-address="); nm_utils_inet4_ntop (listen_address->address, localaddr); + g_string_append (s, "--listen-address="); g_string_append (s, localaddr); nm_cmd_line_add_string (cmd, s->str); - g_string_free (s, TRUE); + g_string_truncate (s, 0); if (!nm_dnsmasq_utils_get_range (listen_address, first, last, &error_desc)) { g_set_error_literal (error, @@ -213,24 +217,41 @@ create_dm_cmd_line (const char *iface, return NULL; } - s = g_string_new ("--dhcp-range="); - g_string_append_printf (s, "%s,%s,60m", first, last); + g_string_append_printf (s, "--dhcp-range=%s,%s,60m", first, last); nm_cmd_line_add_string (cmd, s->str); - g_string_free (s, TRUE); + g_string_truncate (s, 0); if (!nm_ip4_config_get_never_default (ip4_config)) { - s = g_string_new ("--dhcp-option=option:router,"); + g_string_append (s, "--dhcp-option=option:router,"); g_string_append (s, localaddr); nm_cmd_line_add_string (cmd, s->str); - g_string_free (s, TRUE); + g_string_truncate (s, 0); + } + + if ((n = nm_ip4_config_get_num_nameservers (ip4_config))) { + g_string_append (s, "--dhcp-option=option:dns-server"); + for (i = 0; i < n; i++) { + g_string_append_c (s, ','); + g_string_append (s, nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (ip4_config, i), tmpaddr)); + } + g_string_truncate (s, 0); + } + + if ((n = nm_ip4_config_get_num_searches (ip4_config))) { + g_string_append (s, "--dhcp-option=option:domain-search"); + for (i = 0; i < n; i++) { + g_string_append_c (s, ','); + g_string_append (s, nm_ip4_config_get_search (ip4_config, i)); + } + g_string_truncate (s, 0); } nm_cmd_line_add_string (cmd, "--dhcp-lease-max=50"); - s = g_string_new ("--pid-file="); + g_string_append (s, "--pid-file="); g_string_append (s, pidfile); nm_cmd_line_add_string (cmd, s->str); - g_string_free (s, TRUE); + g_string_truncate (s, 0); /* dnsmasq exits if the conf dir is not present */ if (g_file_test (CONFDIR, G_FILE_TEST_IS_DIR)) diff --git a/src/main-utils.c b/src/main-utils.c index 9e3aa7bd..c84f1e4c 100644 --- a/src/main-utils.c +++ b/src/main-utils.c @@ -149,6 +149,9 @@ nm_main_utils_ensure_rundir () exit (1); } + /* NM_CONFIG_DEVICE_STATE_DIR is used to determine whether NM is restarted or not. + * It is important to set NMConfigCmdLineOptions.first_start before creating + * the directory. */ nm_assert (g_str_has_prefix (NM_CONFIG_DEVICE_STATE_DIR, NMRUNDIR"/")); if (g_mkdir (NM_CONFIG_DEVICE_STATE_DIR, 0755) != 0) { errsv = errno; diff --git a/src/main.c b/src/main.c index 20e6f30f..52f0b7c8 100644 --- a/src/main.c +++ b/src/main.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2004 - 2012 Red Hat, Inc. + * Copyright (C) 2004 - 2017 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. */ @@ -49,7 +49,10 @@ #include "nm-auth-manager.h" #include "nm-core-internal.h" #include "nm-exported-object.h" +#include "nm-connectivity.h" +#include "dns/nm-dns-manager.h" #include "systemd/nm-sd.h" +#include "nm-netns.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -58,6 +61,8 @@ #define NM_DEFAULT_PID_FILE NMRUNDIR "/NetworkManager.pid" #define NM_DEFAULT_SYSTEM_STATE_FILE NMSTATEDIR "/NetworkManager.state" +#define CONFIG_ATOMIC_SECTION_PREFIXES ((char **) NULL) + static GMainLoop *main_loop = NULL; static gboolean configure_and_quit = FALSE; @@ -166,7 +171,7 @@ print_config (NMConfigCmdLineOptions *config_cli) nm_logging_setup ("OFF", "ALL", NULL, NULL); - config = nm_config_new (config_cli, NULL, &error); + config = nm_config_new (config_cli, CONFIG_ATOMIC_SECTION_PREFIXES, &error); if (config == NULL) { fprintf (stderr, _("Failed to read configuration: %s\n"), error->message); return 7; @@ -234,7 +239,11 @@ main (int argc, char *argv[]) main_loop = g_main_loop_new (NULL, FALSE); - config_cli = nm_config_cmd_line_options_new (); + /* we determine a first-start (contrary to a restart during the same boot) + * based on the existence of NM_CONFIG_DEVICE_STATE_DIR directory. */ + config_cli = nm_config_cmd_line_options_new (!g_file_test (NM_CONFIG_DEVICE_STATE_DIR, + G_FILE_TEST_IS_DIR)); + do_early_setup (&argc, &argv, config_cli); if (global_opt.g_fatal_warnings) @@ -299,7 +308,7 @@ main (int argc, char *argv[]) } /* Read the config file and CLI overrides */ - config = nm_config_setup (config_cli, NULL, &error); + config = nm_config_setup (config_cli, CONFIG_ATOMIC_SECTION_PREFIXES, &error); nm_config_cmd_line_options_free (config_cli); config_cli = NULL; if (config == NULL) { @@ -345,14 +354,14 @@ main (int argc, char *argv[]) /* Set up unix signal handling - before creating threads, but after daemonizing! */ nm_main_utils_setup_signals (main_loop); - nm_logging_syslog_openlog (nm_config_get_is_debug (config) - ? "debug" - : nm_config_data_get_value_cached (NM_CONFIG_GET_DATA_ORIG, - NM_CONFIG_KEYFILE_GROUP_LOGGING, - NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, - NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY)); + nm_logging_syslog_openlog (nm_config_data_get_value_cached (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_LOGGING, + NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY), + nm_config_get_is_debug (config)); - nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting..."); + nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting... (%s)", + nm_config_get_first_start (config) ? "for the first time" : "after a restart"); nm_log_info (LOGD_CORE, "Read config: %s", nm_config_data_get_config_description (nm_config_get_data (config))); nm_config_data_log (nm_config_get_data (config), "CONFIG: ", " ", NULL); @@ -368,6 +377,11 @@ main (int argc, char *argv[]) #endif ); + /* Set up platform interaction layer */ + nm_linux_platform_setup (); + + NM_UTILS_KEEP_ALIVE (config, nm_netns_get (), "NMConfig-depends-on-NMNetns"); + nm_auth_manager_setup (nm_config_data_get_value_boolean (nm_config_get_data_orig (config), NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT, @@ -385,10 +399,9 @@ main (int argc, char *argv[]) } } - /* Set up platform interaction layer */ - nm_linux_platform_setup (); - - NM_UTILS_KEEP_ALIVE (config, NM_PLATFORM_GET, "NMConfig-depends-on-NMPlatform"); +#if WITH_CONCHECK + NM_UTILS_KEEP_ALIVE (nm_manager_get (), nm_connectivity_get (), "NMManager-depends-on-NMConnectivity"); +#endif nm_dispatcher_init (); @@ -399,6 +412,8 @@ main (int argc, char *argv[]) goto done; } + nm_platform_process_events (NM_PLATFORM_GET); + /* Make sure the loopback interface is up. If interface is down, we bring * it up and kernel will assign it link-local IPv4 and IPv6 addresses. If * it was already up, we assume is in clean state. @@ -434,6 +449,8 @@ done: nm_config_state_set (config, TRUE, TRUE); + nm_dns_manager_stop (nm_dns_manager_get ()); + if (global_opt.pidfile && wrote_pidfile) unlink (global_opt.pidfile); diff --git a/src/ndisc/nm-ndisc-private.h b/src/ndisc/nm-ndisc-private.h index 2308675a..10bcc64f 100644 --- a/src/ndisc/nm-ndisc-private.h +++ b/src/ndisc/nm-ndisc-private.h @@ -58,16 +58,14 @@ gboolean nm_ndisc_add_dns_domain (NMNDisc *ndisc, const NMNDiscDNSDoma if (nm_logging_enabled (__level, __domain)) { \ NMNDisc *const __self = (self); \ char __prefix[64]; \ + const char *__ifname = __self ? nm_ndisc_get_ifname (__self) : NULL; \ \ - _nm_log (__level, __domain, 0, \ + _nm_log (__level, __domain, 0, __ifname, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ (__self \ - ? ({ \ - const char *__ifname = nm_ndisc_get_ifname (__self); \ - nm_sprintf_buf (__prefix, "%s[%p,%s%s%s]", \ - _NMLOG_PREFIX_NAME, __self, \ - NM_PRINT_FMT_QUOTE_STRING (__ifname)); \ - }) \ + ? nm_sprintf_buf (__prefix, "%s[%p,%s%s%s]", \ + _NMLOG_PREFIX_NAME, __self, \ + NM_PRINT_FMT_QUOTE_STRING (__ifname)) \ : _NMLOG_PREFIX_NAME) \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ diff --git a/src/nm-act-request.c b/src/nm-act-request.c index 03964896..6d8bb065 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -397,6 +397,7 @@ device_state_changed (NMActiveConnection *active, { NMActiveConnectionState cur_ac_state = nm_active_connection_get_state (active); NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; + NMActiveConnectionStateReason ac_state_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; /* Decide which device state changes to handle when this active connection * is not the device's current request. Two cases here: (a) the AC is @@ -451,6 +452,7 @@ device_state_changed (NMActiveConnection *active, case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; + ac_state_reason = NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED; g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_notify), active); break; @@ -464,7 +466,7 @@ device_state_changed (NMActiveConnection *active, nm_active_connection_set_default6 (active, FALSE); } - nm_active_connection_set_state (active, ac_state); + nm_active_connection_set_state (active, ac_state, ac_state_reason); } static void @@ -486,7 +488,9 @@ master_failed (NMActiveConnection *self) } /* If no device, or the device wasn't active, just move to deactivated state */ - nm_active_connection_set_state (self, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + nm_active_connection_set_state (self, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEPENDENCY_FAILED); } /*****************************************************************************/ @@ -543,6 +547,7 @@ nm_act_request_init (NMActRequest *req) * @specific_object: the object path of the specific object (ie, WiFi access point, * etc) that will be used to activate @connection and @device * @subject: the #NMAuthSubject representing the requestor of the activation + * @activation_type: the #NMActivationType. * @device: the device/interface to configure according to @connection * * Creates a new device-based activation request. If an applied connection is @@ -555,6 +560,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection, NMConnection *applied_connection, const char *specific_object, NMAuthSubject *subject, + NMActivationType activation_type, NMDevice *device) { g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); @@ -567,6 +573,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection, NM_ACTIVE_CONNECTION_INT_DEVICE, device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, + NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, (int) activation_type, NULL); } diff --git a/src/nm-act-request.h b/src/nm-act-request.h index 47247f89..b8549404 100644 --- a/src/nm-act-request.h +++ b/src/nm-act-request.h @@ -40,6 +40,7 @@ NMActRequest *nm_act_request_new (NMSettingsConnection *settings_connec NMConnection *applied_connection, const char *specific_object, NMAuthSubject *subject, + NMActivationType activation_type, NMDevice *device); NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 068bc85e..19c0343f 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -44,20 +44,20 @@ typedef struct _NMActiveConnectionPrivate { char *pending_activation_id; - gboolean is_default; - gboolean is_default6; NMActiveConnectionState state; - gboolean state_set; - gboolean vpn; + bool is_default:1; + bool is_default6:1; + bool state_set:1; + bool vpn:1; + bool master_ready:1; + + NMActivationType activation_type:3; NMAuthSubject *subject; NMActiveConnection *master; - gboolean master_ready; NMActiveConnection *parent; - gboolean assumed; - NMAuthChain *chain; const char *wifi_shared_permission; NMActiveConnectionAuthResultFunc result_func; @@ -88,12 +88,14 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection, PROP_INT_SUBJECT, PROP_INT_MASTER, PROP_INT_MASTER_READY, + PROP_INT_ACTIVATION_TYPE, ); enum { DEVICE_CHANGED, DEVICE_METERED_CHANGED, PARENT_ACTIVE, + STATE_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -102,8 +104,15 @@ G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_EXPORT #define NM_ACTIVE_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMActiveConnection, NM_IS_ACTIVE_CONNECTION) +/*****************************************************************************/ + static void check_master_ready (NMActiveConnection *self); static void _device_cleanup (NMActiveConnection *self); +static void _settings_connection_notify_flags (NMSettingsConnection *settings_connection, + GParamSpec *param, + NMActiveConnection *self); +static void _set_activation_type (NMActiveConnection *self, + NMActivationType activation_type); /*****************************************************************************/ @@ -112,8 +121,12 @@ static void _device_cleanup (NMActiveConnection *self); #define _NMLOG(level, ...) \ G_STMT_START { \ char _sbuf[64]; \ + NMDevice *_device = (self) ? NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device : NULL; \ + NMConnection *_applied_connection = _device ? NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection : NULL; \ \ nm_log ((level), _NMLOG_DOMAIN, \ + (_device) ? nm_device_get_iface (_device) : NULL, \ + (_applied_connection) ? nm_connection_get_uuid (_applied_connection) : NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ self ? nm_sprintf_buf (_sbuf, "[%p]", self) : "" \ @@ -181,12 +194,15 @@ _set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connec if (priv->settings_connection) { g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_updated, self); g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_removed, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_notify_flags, self); g_clear_object (&priv->settings_connection); } if (connection) { priv->settings_connection = g_object_ref (connection); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, (GCallback) _settings_connection_removed, self); + if (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL) + g_signal_connect (connection, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self); } } @@ -198,7 +214,8 @@ nm_active_connection_get_state (NMActiveConnection *self) void nm_active_connection_set_state (NMActiveConnection *self, - NMActiveConnectionState new_state) + NMActiveConnectionState new_state, + NMActiveConnectionStateReason reason) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); NMActiveConnectionState old_state; @@ -214,9 +231,18 @@ nm_active_connection_set_state (NMActiveConnection *self, state_to_string (new_state), state_to_string (priv->state)); + if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED + && priv->activation_type == NM_ACTIVATION_TYPE_ASSUME) { + /* assuming connections mean to gracefully take over an externally + * configured device. Once activation is complete, an assumed + * activation *is* the same as a full activation. */ + _set_activation_type (self, NM_ACTIVATION_TYPE_MANAGED); + } + old_state = priv->state; priv->state = new_state; priv->state_set = TRUE; + g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) new_state, (guint) reason); _notify (self, PROP_STATE); check_master_ready (self); @@ -566,7 +592,7 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device) g_signal_connect (device, "notify::" NM_DEVICE_METERED, G_CALLBACK (device_metered_changed), self); - if (!priv->assumed) { + if (priv->activation_type != NM_ACTIVATION_TYPE_EXTERNAL) { priv->pending_activation_id = g_strdup_printf (NM_PENDING_ACTIONPREFIX_ACTIVATION"%p", (void *)self); nm_device_add_pending_action (device, priv->pending_activation_id, TRUE); } @@ -712,24 +738,55 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m check_master_ready (self); } -void -nm_active_connection_set_assumed (NMActiveConnection *self, gboolean assumed) +NMActivationType +nm_active_connection_get_activation_type (NMActiveConnection *self) +{ + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NM_ACTIVATION_TYPE_MANAGED); + + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->activation_type; +} + +static void +_set_activation_type (NMActiveConnection *self, + NMActivationType activation_type) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (priv->assumed == FALSE); - priv->assumed = assumed; + if (priv->activation_type == activation_type) + return; - if (priv->pending_activation_id) { - nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE); - g_clear_pointer (&priv->pending_activation_id, g_free); - } + _LOGD ("update activation type from %s to %s", + nm_activation_type_to_string (priv->activation_type), + nm_activation_type_to_string (activation_type)); + priv->activation_type = activation_type; + + if ( priv->activation_type == NM_ACTIVATION_TYPE_MANAGED + && priv->device + && self == NM_ACTIVE_CONNECTION (nm_device_get_act_request (priv->device)) + && NM_IN_SET (nm_device_sys_iface_state_get (priv->device), + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME)) + nm_device_sys_iface_state_set (priv->device, NM_DEVICE_SYS_IFACE_STATE_MANAGED); } -gboolean -nm_active_connection_get_assumed (NMActiveConnection *self) +/*****************************************************************************/ + +static void +_settings_connection_notify_flags (NMSettingsConnection *settings_connection, + GParamSpec *param, + NMActiveConnection *self) { - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->assumed; + nm_assert (NM_IS_ACTIVE_CONNECTION (self)); + nm_assert (NM_IS_SETTINGS_CONNECTION (settings_connection)); + nm_assert (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL); + nm_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection == settings_connection); + + if (nm_settings_connection_get_nm_generated (settings_connection)) + return; + + g_signal_handlers_disconnect_by_func (settings_connection, _settings_connection_notify_flags, self); + _set_activation_type (self, NM_ACTIVATION_TYPE_MANAGED); + nm_device_reapply_settings_immediately (nm_active_connection_get_device (self)); } /*****************************************************************************/ @@ -942,7 +999,7 @@ nm_active_connection_version_id_bump (NMActiveConnection *self) priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); priv->version_id = _version_id_new (); - _LOGT ("new version-id %llu", (long long unsigned) priv->version_id); + _LOGT ("new version-id %llu", (unsigned long long) priv->version_id); return priv->version_id; } @@ -1058,6 +1115,7 @@ set_property (GObject *object, guint prop_id, const char *tmp; NMSettingsConnection *con; NMConnection *acon; + int i; switch (prop_id) { case PROP_INT_SETTINGS_CONNECTION: @@ -1082,6 +1140,15 @@ set_property (GObject *object, guint prop_id, case PROP_INT_MASTER: nm_active_connection_set_master (self, g_value_get_object (value)); break; + case PROP_INT_ACTIVATION_TYPE: + /* construct-only */ + i = g_value_get_int (value); + if (!NM_IN_SET (i, NM_ACTIVATION_TYPE_MANAGED, + NM_ACTIVATION_TYPE_ASSUME, + NM_ACTIVATION_TYPE_EXTERNAL)) + g_return_if_reached (); + priv->activation_type = (NMActivationType) i; + break; case PROP_SPECIFIC_OBJECT: tmp = g_value_get_string (value); /* NM uses "/" to mean NULL */ @@ -1117,6 +1184,7 @@ nm_active_connection_init (NMActiveConnection *self) _LOGT ("creating"); + priv->activation_type = NM_ACTIVATION_TYPE_MANAGED; priv->version_id = _version_id_new (); } @@ -1128,15 +1196,16 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); - if (!priv->applied_connection && priv->settings_connection) { - priv->applied_connection = - nm_simple_connection_new_clone ((NMConnection *) priv->settings_connection); - } + if (!priv->applied_connection && priv->settings_connection) + priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection)); if (priv->applied_connection) nm_connection_clear_secrets (priv->applied_connection); - _LOGD ("constructed (%s, version-id %llu)", G_OBJECT_TYPE_NAME (self), (long long unsigned) priv->version_id); + _LOGD ("constructed (%s, version-id %llu, type %s)", + G_OBJECT_TYPE_NAME (self), + (unsigned long long) priv->version_id, + nm_activation_type_to_string (priv->activation_type)); g_return_if_fail (priv->subject); } @@ -1321,6 +1390,15 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_INT_ACTIVATION_TYPE] = + g_param_spec_int (NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, "", "", + NM_ACTIVATION_TYPE_MANAGED, + NM_ACTIVATION_TYPE_EXTERNAL, + NM_ACTIVATION_TYPE_MANAGED, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[DEVICE_CHANGED] = @@ -1347,6 +1425,13 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) NULL, NULL, NULL, G_TYPE_NONE, 1, NM_TYPE_ACTIVE_CONNECTION); + signals[STATE_CHANGED] = + g_signal_new (NM_ACTIVE_CONNECTION_STATE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ac_class), NMDBUS_TYPE_ACTIVE_CONNECTION_SKELETON, NULL); diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index d87a30b5..8d3478c7 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -55,6 +55,10 @@ #define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" #define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" #define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready" +#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE "int-activation-type" + +/* Signals */ +#define NM_ACTIVE_CONNECTION_STATE_CHANGED "state-changed" /* Internal signals*/ #define NM_ACTIVE_CONNECTION_DEVICE_CHANGED "device-changed" @@ -138,7 +142,8 @@ gboolean nm_active_connection_get_default6 (NMActiveConnection *self); NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self); void nm_active_connection_set_state (NMActiveConnection *self, - NMActiveConnectionState state); + NMActiveConnectionState state, + NMActiveConnectionStateReason reason); NMDevice * nm_active_connection_get_device (NMActiveConnection *self); @@ -158,10 +163,7 @@ void nm_active_connection_set_master (NMActiveConnection *self, void nm_active_connection_set_parent (NMActiveConnection *self, NMActiveConnection *parent); -void nm_active_connection_set_assumed (NMActiveConnection *self, - gboolean assumed); - -gboolean nm_active_connection_get_assumed (NMActiveConnection *self); +NMActivationType nm_active_connection_get_activation_type (NMActiveConnection *self); void nm_active_connection_clear_secrets (NMActiveConnection *self); diff --git a/src/nm-audit-manager.c b/src/nm-audit-manager.c index eeb9d2ba..2d75c0e7 100644 --- a/src/nm-audit-manager.c +++ b/src/nm-audit-manager.c @@ -77,7 +77,7 @@ G_DEFINE_TYPE (NMAuditManager, nm_audit_manager, G_TYPE_OBJECT) #define _NMLOG_PREFIX_NAME "audit" #define _NMLOG(level, domain, ...) \ G_STMT_START { \ - nm_log ((level), (domain), \ + nm_log ((level), (domain), NULL, NULL, \ "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME": " \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ @@ -302,11 +302,11 @@ _nm_audit_manager_log_generic_op (NMAuditManager *self, const char *file, guint void _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line, const char *func, const char *op, NMDevice *device, - gboolean result, gpointer subject_context, + gboolean result, const char *args, gpointer subject_context, const char *reason) { gs_unref_ptrarray GPtrArray *fields = NULL; - AuditField interface_field = { }, ifindex_field = { }; + AuditField interface_field = { }, ifindex_field = { }, args_field = { }; int ifindex; g_return_if_fail (op); @@ -324,6 +324,11 @@ _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint l g_ptr_array_add (fields, &ifindex_field); } + if (args) { + _audit_field_init_string (&args_field, "args", args, FALSE, BACKEND_ALL); + g_ptr_array_add (fields, &args_field); + } + _audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason); } diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h index 29bde1a5..56e26584 100644 --- a/src/nm-audit-manager.h +++ b/src/nm-audit-manager.h @@ -83,13 +83,13 @@ gboolean nm_audit_manager_audit_enabled (NMAuditManager *self); } \ } G_STMT_END -#define nm_audit_log_device_op(op, device, result, subject_context, reason) \ +#define nm_audit_log_device_op(op, device, result, args, subject_context, reason) \ G_STMT_START { \ NMAuditManager *_audit = nm_audit_manager_get (); \ \ if (nm_audit_manager_audit_enabled (_audit)) { \ _nm_audit_manager_log_device_op (_audit, __FILE__, __LINE__, G_STRFUNC, \ - (op), (device), (result), (subject_context), (reason)); \ + (op), (device), (result), (args), (subject_context), (reason)); \ } \ } G_STMT_END @@ -114,6 +114,7 @@ void _nm_audit_manager_log_generic_op (NMAuditManager *self, const char *file void _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line, const char *func, const char *op, NMDevice *device, - gboolean result, gpointer subject_context, const char *reason); + gboolean result, const char *args, gpointer subject_context, + const char *reason); #endif /* __NM_AUDIT_MANAGER_H__ */ diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 4359d8f1..003d9975 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -79,7 +79,7 @@ NM_DEFINE_SINGLETON_REGISTER (NMAuthManager); \ if ((self) != singleton_instance) \ g_snprintf (__prefix, sizeof (__prefix), ""_NMLOG_PREFIX_NAME"[%p]", (self)); \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ @@ -595,10 +595,7 @@ dispose (GObject *object) /* since we take a reference for each queued call, we don't expect to have any queued calls in dispose() */ g_assert (!priv->queued_calls); - if (priv->new_proxy_cancellable) { - g_cancellable_cancel (priv->new_proxy_cancellable); - g_clear_object (&priv->new_proxy_cancellable); - } + nm_clear_g_cancellable (&priv->new_proxy_cancellable); if (priv->proxy) { g_signal_handlers_disconnect_by_data (priv->proxy, self); diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index 9819ca70..0f40ff7c 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -88,9 +88,9 @@ nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len) switch (priv->subject_type) { case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS: g_snprintf (buf, buf_len, "unix-process[pid=%lu, uid=%lu, start=%llu]", - (long unsigned) priv->unix_process.pid, - (long unsigned) priv->unix_process.uid, - (long long unsigned) priv->unix_process.start_time); + (unsigned long) priv->unix_process.pid, + (unsigned long) priv->unix_process.uid, + (unsigned long long) priv->unix_process.start_time); break; case NM_AUTH_SUBJECT_TYPE_INTERNAL: g_strlcat (buf, "internal", buf_len); @@ -290,9 +290,9 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p const char *str; gulong id; - /* all properties are construct-only */ switch (prop_id) { case PROP_SUBJECT_TYPE: + /* construct-only */ i = g_value_get_int (value); g_return_if_fail (NM_IN_SET (i, (int) NM_AUTH_SUBJECT_TYPE_INTERNAL, (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS)); subject_type = i; @@ -300,6 +300,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p g_return_if_fail (priv->subject_type == subject_type); break; case PROP_UNIX_PROCESS_DBUS_SENDER: + /* construct-only */ if ((str = g_value_get_string (value))) { priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); @@ -307,6 +308,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p } break; case PROP_UNIX_PROCESS_PID: + /* construct-only */ if ((id = g_value_get_ulong (value)) != G_MAXULONG) { priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); @@ -314,6 +316,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p } break; case PROP_UNIX_PROCESS_UID: + /* construct-only */ if ((id = g_value_get_ulong (value)) != G_MAXULONG) { priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); @@ -407,7 +410,6 @@ nm_auth_subject_class_init (NMAuthSubjectClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); - /* virtual methods */ object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index 930f6d0f..b8e64ceb 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -301,12 +301,10 @@ auth_call_cancel (gpointer user_data) { AuthCall *call = user_data; - if (call->cancellable) { + if (nm_clear_g_cancellable (&call->cancellable)) { /* we don't free call immediately. Instead we cancel the async operation * and set cancellable to NULL. pk_call_cb() will check for this and * do the final cleanup. */ - g_cancellable_cancel (call->cancellable); - g_clear_object (&call->cancellable); } else { g_source_remove (call->call_idle_id); auth_call_free (call); @@ -319,7 +317,7 @@ pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data) { AuthCall *call = user_data; GError *error = NULL; - gboolean is_authorized, is_challenge; + gboolean is_authorized = FALSE, is_challenge = FALSE; guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN; nm_auth_manager_polkit_authority_check_authorization_finish (NM_AUTH_MANAGER (object), diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 7d89e61e..3f2f0eaa 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -24,6 +24,7 @@ #include <string.h> +#include "nm-active-connection.h" #include "nm-auth-subject.h" #include "nm-core-utils.h" #include "nm-dbus-interface.h" @@ -42,6 +43,7 @@ typedef struct { NMDevice *device; NMConnection *applied_connection; NMConnection *settings_connection; + guint64 ac_version_id; NMDeviceState state; bool realized:1; bool unmanaged_explicit:1; @@ -92,7 +94,7 @@ G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_EXPORTED_OBJECT) g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ else \ g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ @@ -116,6 +118,62 @@ nm_checkpoint_includes_device (NMCheckpoint *self, NMDevice *device) return g_hash_table_contains (priv->devices, device); } +static NMSettingsConnection * +find_settings_connection (NMCheckpoint *self, + DeviceCheckpoint *dev_checkpoint, + gboolean *need_update, + gboolean *need_activation) +{ + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); + const GSList *active_connections, *iter; + NMActiveConnection *active = NULL; + NMSettingsConnection *connection; + const char *uuid, *ac_uuid; + + *need_activation = FALSE; + *need_update = FALSE; + + uuid = nm_connection_get_uuid (dev_checkpoint->settings_connection); + connection = nm_settings_get_connection_by_uuid (nm_settings_get (), uuid); + + if (!connection) + return NULL; + + /* Now check if the connection changed, ... */ + if (!nm_connection_compare (dev_checkpoint->settings_connection, + NM_CONNECTION (connection), + NM_SETTING_COMPARE_FLAG_EXACT)) { + _LOGT ("rollback: settings connection %s changed", uuid); + *need_update = TRUE; + *need_activation = TRUE; + } + + /* ... is active, ... */ + active_connections = nm_manager_get_active_connections (priv->manager); + for (iter = active_connections; iter; iter = g_slist_next (iter)) { + active = iter->data; + ac_uuid = nm_settings_connection_get_uuid (nm_active_connection_get_settings_connection (active)); + if (nm_streq (uuid, ac_uuid)) { + _LOGT ("rollback: connection %s is active", uuid); + break; + } + } + + if (!iter) { + _LOGT ("rollback: connection %s is not active", uuid); + *need_activation = TRUE; + return connection; + } + + /* ... or if the connection was reactivated/reapplied */ + if (nm_active_connection_version_id_get (active) != dev_checkpoint->ac_version_id) { + _LOGT ("rollback: active connection version id of %s changed", uuid); + *need_activation = TRUE; + } + + return connection; +} + GVariant * nm_checkpoint_rollback (NMCheckpoint *self) { @@ -135,7 +193,6 @@ nm_checkpoint_rollback (NMCheckpoint *self) while (g_hash_table_iter_next (&iter, (gpointer *) &device, (gpointer *) &dev_checkpoint)) { gs_unref_object NMAuthSubject *subject = NULL; guint32 result = NM_ROLLBACK_RESULT_OK; - const char *con_uuid; _LOGD ("rollback: restoring device %s (state %d, realized %d, explicitly unmanaged %d)", nm_device_get_iface (device), @@ -180,27 +237,26 @@ activate: } if (dev_checkpoint->applied_connection) { - /* The device had an active connection, check if the - * connection still exists - * */ - con_uuid = nm_connection_get_uuid (dev_checkpoint->settings_connection); - connection = nm_settings_get_connection_by_uuid (nm_settings_get (), con_uuid); + gboolean need_update, need_activation; + /* The device had an active connection: check if the + * connection still exists, is active and was changed */ + connection = find_settings_connection (self, dev_checkpoint, &need_update, &need_activation); if (connection) { - /* If the connection is still there, restore its content - * and save it - * */ - _LOGD ("rollback: connection %s still exists", con_uuid); - - nm_connection_replace_settings_from_connection (NM_CONNECTION (connection), - dev_checkpoint->settings_connection); - nm_settings_connection_commit_changes (connection, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL, - NULL); + if (need_update) { + _LOGD ("rollback: updating connection %s", + nm_settings_connection_get_uuid (connection)); + nm_connection_replace_settings_from_connection (NM_CONNECTION (connection), + dev_checkpoint->settings_connection); + nm_settings_connection_commit_changes (connection, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + NULL); + } } else { /* The connection was deleted, recreate it */ - _LOGD ("rollback: adding connection %s again", con_uuid); + _LOGD ("rollback: adding connection %s again", + nm_connection_get_uuid (dev_checkpoint->settings_connection)); connection = nm_settings_add_connection (nm_settings_get (), dev_checkpoint->settings_connection, @@ -212,24 +268,29 @@ activate: result = NM_ROLLBACK_RESULT_ERR_FAILED; goto next_dev; } + need_activation = TRUE; } - /* Now re-activate the connection */ - subject = nm_auth_subject_new_internal (); - if (!nm_manager_activate_connection (priv->manager, - connection, - dev_checkpoint->applied_connection, - NULL, - device, - subject, - &local_error)) { - _LOGW ("rollback: reactivation of connection %s/%s failed: %s", - nm_connection_get_id ((NMConnection *) connection), - nm_connection_get_uuid ((NMConnection * ) connection), - local_error->message); - g_clear_error (&local_error); - result = NM_ROLLBACK_RESULT_ERR_FAILED; - goto next_dev; + if (need_activation) { + _LOGD ("rollback: reactivating connection %s", + nm_settings_connection_get_uuid (connection)); + subject = nm_auth_subject_new_internal (); + if (!nm_manager_activate_connection (priv->manager, + connection, + dev_checkpoint->applied_connection, + NULL, + device, + subject, + NM_ACTIVATION_TYPE_MANAGED, + &local_error)) { + _LOGW ("rollback: reactivation of connection %s/%s failed: %s", + nm_connection_get_id ((NMConnection *) connection), + nm_connection_get_uuid ((NMConnection * ) connection), + local_error->message); + g_clear_error (&local_error); + result = NM_ROLLBACK_RESULT_ERR_FAILED; + goto next_dev; + } } } else { /* The device was initially disconnected, deactivate any existing connection */ @@ -249,26 +310,25 @@ next_dev: if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) { NMSettingsConnection *con; - gs_free_slist GSList *list = NULL; - GSList *item; + gs_free NMSettingsConnection **list = NULL; + guint i; g_return_val_if_fail (priv->connection_uuids, NULL); - list = nm_settings_get_connections_sorted (nm_settings_get ()); + list = nm_settings_get_connections_sorted (nm_settings_get (), NULL); - for (item = list; item; item = g_slist_next (item)) { - con = item->data; + for (i = 0; list[i]; i++) { + con = list[i]; if (!g_hash_table_contains (priv->connection_uuids, nm_settings_connection_get_uuid (con))) { - _LOGD ("rollback: deleting new connection %s (%s)", - nm_settings_connection_get_uuid (con), - nm_settings_connection_get_id (con)); + _LOGD ("rollback: deleting new connection %s", + nm_settings_connection_get_uuid (con)); nm_settings_connection_delete (con, NULL, NULL); } } } if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { - const GSList *list = nm_manager_get_devices (priv->manager); + const GSList *list; NMDeviceState state; NMDevice *dev; @@ -300,6 +360,7 @@ device_checkpoint_create (NMDevice *device, NMSettingsConnection *settings_connection; const char *path; gboolean unmanaged_explicit; + NMActRequest *act_request; path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)); unmanaged_explicit = !!nm_device_get_unmanaged_flags (device, @@ -321,6 +382,11 @@ device_checkpoint_create (NMDevice *device, g_return_val_if_fail (settings_connection, NULL); dev_checkpoint->settings_connection = nm_simple_connection_new_clone (NM_CONNECTION (settings_connection)); + + act_request = nm_device_get_act_request (device); + g_return_val_if_fail (act_request, NULL); + dev_checkpoint->ac_version_id = + nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request)); } return dev_checkpoint; diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 68e66971..8f4d1121 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -561,7 +561,7 @@ _nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy) return g_strcmp0 (a, b); } -static struct { +static const struct { const char *group; const char *key; const char *value; @@ -601,7 +601,7 @@ nm_config_data_log (const NMConfigData *self, #define _LOG(stream, prefix, ...) \ G_STMT_START { \ if (!stream) \ - _nm_log (LOGL_DEBUG, LOGD_CORE, 0, "%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__)"%s", prefix _NM_UTILS_MACRO_REST (__VA_ARGS__), ""); \ + _nm_log (LOGL_DEBUG, LOGD_CORE, 0, NULL, NULL, "%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__)"%s", prefix _NM_UTILS_MACRO_REST (__VA_ARGS__), ""); \ else \ fprintf (stream, "%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__)"%s", prefix _NM_UTILS_MACRO_REST (__VA_ARGS__), "\n"); \ } G_STMT_END @@ -1437,15 +1437,17 @@ set_property (GObject *object, NMConfigData *self = NM_CONFIG_DATA (object); NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); - /* This type is immutable. All properties are construct only. */ switch (prop_id) { case PROP_CONFIG_MAIN_FILE: + /* construct-only */ priv->config_main_file = g_value_dup_string (value); break; case PROP_CONFIG_DESCRIPTION: + /* construct-only */ priv->config_description = g_value_dup_string (value); break; case PROP_KEYFILE_USER: + /* construct-only */ priv->keyfile_user = g_value_dup_boxed (value); if ( priv->keyfile_user && !_nm_keyfile_has_values (priv->keyfile_user)) { @@ -1454,6 +1456,7 @@ set_property (GObject *object, } break; case PROP_KEYFILE_INTERN: + /* construct-only */ priv->keyfile_intern = g_value_dup_boxed (value); if ( priv->keyfile_intern && !_nm_keyfile_has_values (priv->keyfile_intern)) { @@ -1462,6 +1465,7 @@ set_property (GObject *object, } break; case PROP_NO_AUTO_DEFAULT: + /* construct-only */ { char **value_arr = g_value_get_boxed (value); guint i, j = 0; @@ -1472,7 +1476,7 @@ set_property (GObject *object, for (i = 0; value_arr && value_arr[i]; i++) { if ( *value_arr[i] && nm_utils_hwaddr_valid (value_arr[i], -1) - && _nm_utils_strv_find_first (value_arr, i, value_arr[i]) < 0) { + && nm_utils_strv_find_first (value_arr, i, value_arr[i]) < 0) { priv->no_auto_default.arr[j++] = g_strdup (value_arr[i]); priv->no_auto_default.specs = g_slist_prepend (priv->no_auto_default.specs, g_strdup_printf ("mac:%s", value_arr[i])); } diff --git a/src/nm-config-data.h b/src/nm-config-data.h index d7d14a61..98c66751 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -171,6 +171,8 @@ const char *nm_config_data_get_rc_manager (const NMConfigData *self); gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device); gboolean nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *device); +int nm_config_data_get_sriov_num_vfs (const NMConfigData *self, NMDevice *device); + NMGlobalDnsConfig *nm_config_data_get_global_dns_config (const NMConfigData *self); char *nm_config_data_get_connection_default (const NMConfigData *self, diff --git a/src/nm-config.c b/src/nm-config.c index c68a8429..2cdf8556 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -60,6 +60,15 @@ struct NMConfigCmdLineOptions { */ int connectivity_interval; char *connectivity_response; + + /* @first_start is not provided by command line. It is a convenient hack + * to pass in an argument to NMConfig. This makes NMConfigCmdLineOptions a + * misnomer. + * + * It is true, if NM is started the first time -- contrary to a restart + * during the same boot up. That is determined by the content of the + * /var/run/NetworManager state directory. */ + bool first_start; }; typedef struct { @@ -291,6 +300,12 @@ nm_config_get_is_debug (NMConfig *config) return NM_CONFIG_GET_PRIVATE (config)->cli.is_debug; } +gboolean +nm_config_get_first_start (NMConfig *config) +{ + return NM_CONFIG_GET_PRIVATE (config)->cli.first_start; +} + /*****************************************************************************/ static char ** @@ -309,7 +324,7 @@ no_auto_default_from_file (const char *no_auto_default_file) for (i = 0; list[i]; i++) { if ( *list[i] && nm_utils_hwaddr_valid (list[i], -1) - && _nm_utils_strv_find_first (list, i, list[i]) < 0) + && nm_utils_strv_find_first (list, i, list[i]) < 0) g_ptr_array_add (no_auto_default_new, list[i]); else g_free (list[i]); @@ -369,7 +384,7 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device) no_auto_default_current = nm_config_data_get_no_auto_default (priv->config_data); - if (_nm_utils_strv_find_first ((char **) no_auto_default_current, -1, hw_address) >= 0) { + if (nm_utils_strv_find_first ((char **) no_auto_default_current, -1, hw_address) >= 0) { /* @hw_address is already blocked. We don't have to update our in-memory representation. * Maybe we should write to no_auto_default_file anew, but let's save that too. */ return; @@ -412,6 +427,7 @@ _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli) g_clear_pointer (&cli->connectivity_uri, g_free); g_clear_pointer (&cli->connectivity_response, g_free); cli->connectivity_interval = -1; + cli->first_start = FALSE; } static void @@ -434,14 +450,18 @@ _nm_config_cmd_line_options_copy (const NMConfigCmdLineOptions *cli, NMConfigCmd dst->connectivity_uri = g_strdup (cli->connectivity_uri); dst->connectivity_response = g_strdup (cli->connectivity_response); dst->connectivity_interval = cli->connectivity_interval; + dst->first_start = cli->first_start; } NMConfigCmdLineOptions * -nm_config_cmd_line_options_new () +nm_config_cmd_line_options_new (gboolean first_start) { NMConfigCmdLineOptions *cli = g_new0 (NMConfigCmdLineOptions, 1); _nm_config_cmd_line_options_clear (cli); + + cli->first_start = first_start; + return cli; } @@ -551,14 +571,14 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy) b_is_connection = g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); if (a_is_connection != b_is_connection) { - /* one is a [connection*] entry, the other not. We sort [connection*] entires + /* one is a [connection*] entry, the other not. We sort [connection*] entries * after. */ if (a_is_connection) return 1; return -1; } if (a_is_connection) { - /* both are [connection.\+] entires. Reverse their order. + /* both are [connection.\+] entries. Reverse their order. * One of the sections might be literally [connection]. That section * is special and it's order will be fixed later. It doesn't actually * matter here how it compares with [connection.\+] sections. */ @@ -569,14 +589,14 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy) b_is_device = g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE); if (a_is_device != b_is_device) { - /* one is a [device*] entry, the other not. We sort [device*] entires + /* one is a [device*] entry, the other not. We sort [device*] entries * after. */ if (a_is_device) return 1; return -1; } if (a_is_device) { - /* both are [device.\+] entires. Reverse their order. + /* both are [device.\+] entries. Reverse their order. * One of the sections might be literally [device]. That section * is special and it's order will be fixed later. It doesn't actually * matter here how it compares with [device.\+] sections. */ @@ -659,7 +679,7 @@ read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, co } /* the config-group is internal to every configuration snippets. It doesn't make sense - * to merge the into the global configuration, and it doesn't make sense to preserve the + * to merge it into the global configuration, and it doesn't make sense to preserve the * group beyond this point. */ g_key_file_remove_group (kf, NM_CONFIG_KEYFILE_GROUP_CONFIG, NULL); @@ -750,13 +770,13 @@ read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, co for (iter_val = old_val; iter_val && *iter_val; iter_val++) { if ( last_char != '-' - || _nm_utils_strv_find_first (new_val, -1, *iter_val) < 0) + || nm_utils_strv_find_first (new_val, -1, *iter_val) < 0) g_ptr_array_add (new, g_strdup (*iter_val)); } for (iter_val = new_val; iter_val && *iter_val; iter_val++) { /* don't add duplicates. That means an "option=a,b"; "option+=a,c" results in "option=a,b,c" */ if ( last_char == '+' - && _nm_utils_strv_find_first (old_val, -1, *iter_val) < 0) + && nm_utils_strv_find_first (old_val, -1, *iter_val) < 0) g_ptr_array_add (new, *iter_val); else g_free (*iter_val); @@ -953,8 +973,8 @@ read_entire_config (const NMConfigCmdLineOptions *cli, const char *filename = system_confs->pdata[i]; /* if a same named file exists in config_dir or run_config_dir, skip it. */ - if (_nm_utils_strv_find_first ((char **) confs->pdata, confs->len, filename) >= 0 || - _nm_utils_strv_find_first ((char **) run_confs->pdata, run_confs->len, filename) >= 0) { + if (nm_utils_strv_find_first ((char **) confs->pdata, confs->len, filename) >= 0 || + nm_utils_strv_find_first ((char **) run_confs->pdata, run_confs->len, filename) >= 0) { g_ptr_array_remove_index (system_confs, i); continue; } @@ -968,7 +988,7 @@ read_entire_config (const NMConfigCmdLineOptions *cli, const char *filename = run_confs->pdata[i]; /* if a same named file exists in config_dir, skip it. */ - if (_nm_utils_strv_find_first ((char **) confs->pdata, confs->len, filename) >= 0) { + if (nm_utils_strv_find_first ((char **) confs->pdata, confs->len, filename) >= 0) { g_ptr_array_remove_index (run_confs, i); continue; } @@ -1926,15 +1946,13 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf) /** * nm_config_device_state_load: - * @self: the NMConfig instance * @ifindex: the ifindex for which the state is to load * * Returns: (transfer full): a run state object. * Must be freed with g_free(). */ NMConfigDeviceStateData * -nm_config_device_state_load (NMConfig *self, - int ifindex) +nm_config_device_state_load (int ifindex) { NMConfigDeviceStateData *device_state; char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60]; @@ -1964,10 +1982,16 @@ nm_config_device_state_load (NMConfig *self, return device_state; } +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED, "unmanaged"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED, "managed"), +); + gboolean -nm_config_device_state_write (NMConfig *self, - int ifindex, - gboolean managed, +nm_config_device_state_write (int ifindex, + NMConfigDeviceStateManagedType managed, const char *perm_hw_addr_fake, const char *connection_uuid) { @@ -1975,20 +1999,23 @@ nm_config_device_state_write (NMConfig *self, GError *local = NULL; gs_unref_keyfile GKeyFile *kf = NULL; - g_return_val_if_fail (NM_IS_CONFIG (self), FALSE); g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (!connection_uuid || *connection_uuid, FALSE); - g_return_val_if_fail (managed || !connection_uuid, FALSE); + g_return_val_if_fail (managed == NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED || !connection_uuid, FALSE); nm_assert (!perm_hw_addr_fake || nm_utils_hwaddr_valid (perm_hw_addr_fake, -1)); nm_sprintf_buf (path, "%s/%d", NM_CONFIG_DEVICE_STATE_DIR, ifindex); kf = nm_config_create_keyfile (); - g_key_file_set_boolean (kf, - DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, - DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED, - !!managed); + if (NM_IN_SET (managed, + NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED, + NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED)) { + g_key_file_set_boolean (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED, + managed == NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED); + } if (perm_hw_addr_fake) { g_key_file_set_string (kf, DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, @@ -2007,17 +2034,16 @@ nm_config_device_state_write (NMConfig *self, g_error_free (local); return FALSE; } - _LOGT ("device-state: write #%d (%s); managed=%d%s%s%s%s%s%s", + _LOGT ("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s", ifindex, path, - (bool) managed, + _device_state_managed_type_to_str (managed), NM_PRINT_FMT_QUOTED (connection_uuid, ", connection-uuid=", connection_uuid, "", ""), NM_PRINT_FMT_QUOTED (perm_hw_addr_fake, ", perm-hw-addr-fake=", perm_hw_addr_fake, "", "")); return TRUE; } void -nm_config_device_state_prune_unseen (NMConfig *self, - GHashTable *seen_ifindexes) +nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes) { GDir *dir; const char *fn; @@ -2230,6 +2256,7 @@ set_property (GObject *object, guint prop_id, NMConfig *self = NM_CONFIG (object); NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self); NMConfigCmdLineOptions *cli; + char **strv; switch (prop_id) { case PROP_CMD_LINE_OPTIONS: @@ -2242,7 +2269,10 @@ set_property (GObject *object, guint prop_id, break; case PROP_ATOMIC_SECTION_PREFIXES: /* construct-only */ - priv->atomic_section_prefixes = g_strdupv (g_value_get_boxed (value)); + strv = g_value_get_boxed (value); + if (strv && !strv[0]) + strv = NULL; + priv->atomic_section_prefixes = g_strdupv (strv); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/src/nm-config.h b/src/nm-config.h index 9930df33..283d6a1b 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -62,6 +62,7 @@ #define NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT "auth-polkit" #define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp" #define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug" +#define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE "hostname-mode" #define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend" #define NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE "enable" #define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was" @@ -74,6 +75,7 @@ #define NM_CONFIG_KEYFILE_KEY_AUDIT "audit" #define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier" +#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs" #define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was." #define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set." @@ -123,13 +125,15 @@ const char *nm_config_get_log_domains (NMConfig *config); gboolean nm_config_get_configure_and_quit (NMConfig *config); gboolean nm_config_get_is_debug (NMConfig *config); +gboolean nm_config_get_first_start (NMConfig *config); + void nm_config_set_values (NMConfig *self, GKeyFile *keyfile_intern_new, gboolean allow_write, gboolean force_rewrite); /* for main.c only */ -NMConfigCmdLineOptions *nm_config_cmd_line_options_new (void); +NMConfigCmdLineOptions *nm_config_cmd_line_options_new (gboolean first_start); void nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli); void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli, GOptionContext *opt_ctx); @@ -202,14 +206,12 @@ struct _NMConfigDeviceStateData { const char *perm_hw_addr_fake; }; -NMConfigDeviceStateData *nm_config_device_state_load (NMConfig *self, - int ifindex); -gboolean nm_config_device_state_write (NMConfig *self, - int ifindex, - gboolean managed, +NMConfigDeviceStateData *nm_config_device_state_load (int ifindex); +gboolean nm_config_device_state_write (int ifindex, + NMConfigDeviceStateManagedType managed, const char *perm_hw_addr_fake, const char *connection_uuid); -void nm_config_device_state_prune_unseen (NMConfig *self, GHashTable *seen_ifindexes); +void nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes); /*****************************************************************************/ diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index a33ec680..75bb7b63 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -17,6 +17,7 @@ * * Copyright (C) 2011 Thomas Bechtold <thomasbechtold@jpberlin.de> * Copyright (C) 2011 Dan Williams <dcbw@redhat.com> + * Copyright (C) 2016,2017 Red Hat, Inc. */ #include "nm-default.h" @@ -24,36 +25,21 @@ #include "nm-connectivity.h" #include <string.h> -#if WITH_CONCHECK -#include <libsoup/soup.h> -#endif +#include <curl/curl.h> #include "nm-config.h" -#include "nm-dispatcher.h" #include "NetworkManagerUtils.h" /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE (NMConnectivity, - PROP_URI, - PROP_INTERVAL, - PROP_RESPONSE, - PROP_STATE, -); - typedef struct { char *uri; char *response; guint interval; - gboolean online; /* whether periodic connectivity checking is enabled. */ - -#if WITH_CONCHECK - SoupSession *soup_session; - gboolean initial_check_obsoleted; - guint check_id; -#endif - - NMConnectivityState state; + NMConfig *config; + guint periodic_check_id; + CURLM *curl_mhandle; + guint curl_timer; } NMConnectivityPrivate; struct _NMConnectivity { @@ -69,20 +55,37 @@ G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT) #define NM_CONNECTIVITY_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMConnectivity, NM_IS_CONNECTIVITY) +NM_DEFINE_SINGLETON_GETTER (NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECTIVITY); + +enum { + PERIODIC_CHECK, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_CONCHECK #define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "connectivity", __VA_ARGS__) -/*****************************************************************************/ - -NMConnectivityState -nm_connectivity_get_state (NMConnectivity *connectivity) -{ - g_return_val_if_fail (NM_IS_CONNECTIVITY (connectivity), NM_CONNECTIVITY_UNKNOWN); +#define _NMLOG2_DOMAIN LOGD_CONCHECK +#define _NMLOG2(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG2_DOMAIN)) { \ + _nm_log (__level, _NMLOG2_DOMAIN, 0, \ + &cb_data->ifspec[3], NULL, \ + "connectivity: (%s) " \ + _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + &cb_data->ifspec[3] \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END - return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->state; -} +/*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_state_to_string, NMConnectivityState, NM_UTILS_LOOKUP_DEFAULT_WARN ("???"), @@ -93,190 +96,245 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_state_to_string, NMConnectivityState NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FULL, "FULL"), ); -static void -update_state (NMConnectivity *self, NMConnectivityState state) -{ - NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - - if (priv->state != state) { - _LOGD ("state changed from %s to %s", - nm_connectivity_state_to_string (priv->state), - nm_connectivity_state_to_string (state)); - priv->state = state; - _notify (self, PROP_STATE); - - /* Notify dispatcher scripts of a connectivity state change */ - nm_dispatcher_call_connectivity (DISPATCHER_ACTION_CONNECTIVITY_CHANGE, state); - } -} +/*****************************************************************************/ -#if WITH_CONCHECK typedef struct { GSimpleAsyncResult *simple; - char *uri; char *response; - guint check_id_when_scheduled; + CURL *curl_ehandle; + size_t msg_size; + char *msg; + struct curl_slist *request_headers; + guint timeout_id; + char *ifspec; } ConCheckCbData; static void -nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_data) +finish_cb_data (ConCheckCbData *cb_data, NMConnectivityState new_state) { - NMConnectivity *self; - NMConnectivityPrivate *priv; - ConCheckCbData *cb_data = user_data; - GSimpleAsyncResult *simple = cb_data->simple; - NMConnectivityState new_state; - const char *nm_header; - const char *uri = cb_data->uri; - const char *response = cb_data->response ? cb_data->response : NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE; - - self = NM_CONNECTIVITY (g_async_result_get_source_object (G_ASYNC_RESULT (simple))); - /* it is safe to unref @self here, @simple holds yet another reference. */ - g_object_unref (self); - priv = NM_CONNECTIVITY_GET_PRIVATE (self); + /* Contrary to what cURL manual claim it is *not* safe to remove + * the easy handle "at any moment"; specifically not from the + * write function. Thus here we just dissociate the cb_data from + * the easy handle and the easy handle will be cleaned up when the + * message goes to CURLMSG_DONE in curl_check_connectivity(). */ + curl_easy_setopt (cb_data->curl_ehandle, CURLOPT_PRIVATE, NULL); + + g_simple_async_result_set_op_res_gssize (cb_data->simple, new_state); + g_simple_async_result_complete (cb_data->simple); + g_object_unref (cb_data->simple); + curl_slist_free_all (cb_data->request_headers); + g_free (cb_data->response); + g_source_remove (cb_data->timeout_id); + g_slice_free (ConCheckCbData, cb_data); +} - if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) { - _LOGI ("check for uri '%s' failed with '%s'", uri, msg->reason_phrase); - new_state = NM_CONNECTIVITY_LIMITED; - goto done; - } +static void +curl_check_connectivity (CURLM *mhandle, CURLMcode ret) +{ + ConCheckCbData *cb_data; + CURLMsg *msg; + CURLcode eret; + gint m_left; + + if (ret != CURLM_OK) + _LOGW ("connectivity check failed"); + + while ((msg = curl_multi_info_read (mhandle, &m_left))) { + if (msg->msg != CURLMSG_DONE) + continue; + + /* Here we have completed a session. Check easy session result. */ + eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, &cb_data); + if (eret != CURLE_OK) { + _LOG2E ("curl cannot extract cb_data for easy handle %p, skipping msg", msg->easy_handle); + continue; + } - if (msg->status_code == 511) { - _LOGD ("check for uri '%s' returned status '%d %s'; captive portal present.", - uri, msg->status_code, msg->reason_phrase); - new_state = NM_CONNECTIVITY_PORTAL; - } else { - /* Check headers; if we find the NM-specific one we're done */ - nm_header = soup_message_headers_get_one (msg->response_headers, "X-NetworkManager-Status"); - if (g_strcmp0 (nm_header, "online") == 0) { - _LOGD ("check for uri '%s' with Status header successful.", uri); - new_state = NM_CONNECTIVITY_FULL; - } else if (msg->status_code == SOUP_STATUS_OK) { - /* check response */ - if (msg->response_body->data && g_str_has_prefix (msg->response_body->data, response)) { - _LOGD ("check for uri '%s' successful.", uri); - new_state = NM_CONNECTIVITY_FULL; + if (cb_data) { + /* If cb_data is still there this message hasn't been + * taken care of. Do so now. */ + if (msg->data.result == CURLE_OK) { + /* If we get here, it means that easy_write_cb() didn't read enough + * bytes to be able to do a match. */ + _LOG2I ("response shorter than expected '%s'; assuming captive portal.", + cb_data->response); + finish_cb_data (cb_data, NM_CONNECTIVITY_PORTAL); } else { - _LOGI ("check for uri '%s' did not match expected response '%s'; assuming captive portal.", - uri, response); - new_state = NM_CONNECTIVITY_PORTAL; + _LOG2D ("check failed (%d)", msg->data.result); + finish_cb_data (cb_data, NM_CONNECTIVITY_LIMITED); } - } else { - _LOGI ("check for uri '%s' returned status '%d %s'; assuming captive portal.", - uri, msg->status_code, msg->reason_phrase); - new_state = NM_CONNECTIVITY_PORTAL; } - } - done: - /* Only update the state, if the call was done from external, or if the periodic check - * is still the one that called this async check. */ - if (!cb_data->check_id_when_scheduled || cb_data->check_id_when_scheduled == priv->check_id) { - /* Only update the state, if the URI and response parameters did not change - * since invocation. - * The interval does not matter for exernal calls, and for internal calls - * we don't reach this line if the interval changed. */ - if ( !g_strcmp0 (cb_data->uri, priv->uri) - && !g_strcmp0 (cb_data->response, priv->response)) - update_state (self, new_state); + curl_multi_remove_handle (mhandle, msg->easy_handle); + curl_easy_cleanup (msg->easy_handle); } +} - g_simple_async_result_set_op_res_gssize (simple, new_state); - g_simple_async_result_complete (simple); - g_object_unref (simple); +static gboolean +curl_timeout_cb (gpointer user_data) +{ + NMConnectivity *self = NM_CONNECTIVITY (user_data); + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURLMcode ret; + int pending_conn; - g_free (cb_data->uri); - g_free (cb_data->response); - g_slice_free (ConCheckCbData, cb_data); -} + priv->curl_timer = 0; -#define IS_PERIODIC_CHECK(callback) (callback == run_check_complete) + ret = curl_multi_socket_action (priv->curl_mhandle, CURL_SOCKET_TIMEOUT, 0, &pending_conn); + _LOGT ("timeout elapsed - multi_socket_action (%d conn remaining)", pending_conn); -static void -run_check_complete (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - NMConnectivity *self = NM_CONNECTIVITY (object); - GError *error = NULL; + curl_check_connectivity (priv->curl_mhandle, ret); - nm_connectivity_check_finish (self, result, &error); - if (error) { - _LOGE ("check failed: %s", error->message); - g_error_free (error); - } + return G_SOURCE_REMOVE; } -static gboolean -run_check (gpointer user_data) +static int +multi_timer_cb (CURLM *multi, long timeout_ms, void *userdata) { - NMConnectivity *self = NM_CONNECTIVITY (user_data); + NMConnectivity *self = NM_CONNECTIVITY (userdata); + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - nm_connectivity_check_async (self, run_check_complete, NULL); - return TRUE; + nm_clear_g_source (&priv->curl_timer); + if (timeout_ms != -1) + priv->curl_timer = g_timeout_add (timeout_ms * 1000, curl_timeout_cb, self); + + return 0; } static gboolean -idle_start_periodic_checks (gpointer user_data) +curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer data) { - NMConnectivity *self = user_data; + NMConnectivity *self = NM_CONNECTIVITY (data); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURLMcode ret; + int pending_conn = 0; + gboolean bret = TRUE; + int fd = g_io_channel_unix_get_fd (ch); + int action = 0; + + if (condition & G_IO_IN) + action |= CURL_CSELECT_IN; + if (condition & G_IO_OUT) + action |= CURL_CSELECT_OUT; - priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self); - if (!priv->initial_check_obsoleted) - run_check (self); + ret = curl_multi_socket_action (priv->curl_mhandle, fd, 0, &pending_conn); - return FALSE; + curl_check_connectivity (priv->curl_mhandle, ret); + + if (pending_conn == 0) { + nm_clear_g_source (&priv->curl_timer); + bret = FALSE; + } + return bret; } -#endif -static void -_reschedule_periodic_checks (NMConnectivity *self, gboolean force_reschedule) +typedef struct { + GIOChannel *ch; + guint ev; +} CurlSockData; + +static int +multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void *socketp) { + NMConnectivity *self = NM_CONNECTIVITY (userdata); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - -#if WITH_CONCHECK - if (priv->online && priv->uri && priv->interval) { - if (force_reschedule || !priv->check_id) { - if (priv->check_id) - g_source_remove (priv->check_id); - priv->check_id = g_timeout_add (0, idle_start_periodic_checks, self); - priv->initial_check_obsoleted = FALSE; + CurlSockData *fdp = (CurlSockData *) socketp; + GIOCondition condition = 0; + + if (what == CURL_POLL_REMOVE) { + if (fdp) { + nm_clear_g_source (&fdp->ev); + g_io_channel_unref (fdp->ch); + g_slice_free (CurlSockData, fdp); } } else { - nm_clear_g_source (&priv->check_id); + if (!fdp) { + fdp = g_slice_new0 (CurlSockData); + fdp->ch = g_io_channel_unix_new (s); + } else + nm_clear_g_source (&fdp->ev); + + if (what & CURL_POLL_IN) + condition |= G_IO_IN; + if (what & CURL_POLL_OUT) + condition |= G_IO_OUT; + + fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self); + curl_multi_assign (priv->curl_mhandle, s, fdp); } - if (priv->check_id) - return; -#endif - /* Either @online is %TRUE but we aren't checking connectivity, or - * @online is %FALSE. Either way we can update our status immediately. - */ - update_state (self, priv->online ? NM_CONNECTIVITY_FULL : NM_CONNECTIVITY_NONE); + return CURLM_OK; } -void -nm_connectivity_set_online (NMConnectivity *self, - gboolean online) +#define HEADER_STATUS_ONLINE "X-NetworkManager-Status: online\r\n" + +static size_t +easy_header_cb (char *buffer, size_t size, size_t nitems, void *userdata) { - NMConnectivityPrivate *priv= NM_CONNECTIVITY_GET_PRIVATE (self); + ConCheckCbData *cb_data = userdata; + size_t len = size * nitems; + + if ( len >= sizeof (HEADER_STATUS_ONLINE) - 1 + && !g_ascii_strncasecmp (buffer, HEADER_STATUS_ONLINE, sizeof (HEADER_STATUS_ONLINE) - 1)) { + _LOG2D ("status header found, check successful"); + finish_cb_data (cb_data, NM_CONNECTIVITY_FULL); + return 0; + } + + return len; +} - online = !!online; - if (priv->online != online) { - _LOGD ("set %s", online ? "online" : "offline"); - priv->online = online; - _reschedule_periodic_checks (self, FALSE); +static size_t +easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) +{ + ConCheckCbData *cb_data = userdata; + size_t len = size * nmemb; + + cb_data->msg = g_realloc (cb_data->msg, cb_data->msg_size + len); + memcpy (cb_data->msg + cb_data->msg_size, buffer, len); + cb_data->msg_size += len; + + if (cb_data->msg_size >= strlen (cb_data->response)) { + /* We already have enough data -- check response */ + if (g_str_has_prefix (cb_data->msg, cb_data->response)) { + _LOG2D ("check successful."); + finish_cb_data (cb_data, NM_CONNECTIVITY_FULL); + } else { + _LOG2I ("response did not match expected response '%s'; assuming captive portal.", + cb_data->response); + finish_cb_data (cb_data, NM_CONNECTIVITY_PORTAL); + } + return 0; } + + return len; +} + +static gboolean +timeout_cb (gpointer user_data) +{ + ConCheckCbData *cb_data = user_data; + NMConnectivity *self = NM_CONNECTIVITY (g_async_result_get_source_object (G_ASYNC_RESULT (cb_data->simple))); + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURL *ehandle = cb_data->curl_ehandle; + + _LOG2I ("timed out"); + finish_cb_data (cb_data, NM_CONNECTIVITY_LIMITED); + curl_multi_remove_handle (priv->curl_mhandle, ehandle); + curl_easy_cleanup (ehandle); + + return G_SOURCE_REMOVE; } void nm_connectivity_check_async (NMConnectivity *self, + const char *iface, GAsyncReadyCallback callback, gpointer user_data) { NMConnectivityPrivate *priv; GSimpleAsyncResult *simple; + CURL *ehandle = NULL; g_return_if_fail (NM_IS_CONNECTIVITY (self)); priv = NM_CONNECTIVITY_GET_PRIVATE (self); @@ -284,39 +342,40 @@ nm_connectivity_check_async (NMConnectivity *self, simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data, nm_connectivity_check_async); -#if WITH_CONCHECK - if (priv->uri && priv->interval) { - SoupMessage *msg; - ConCheckCbData *cb_data = g_slice_new (ConCheckCbData); + if (priv->uri && priv->interval && priv->curl_mhandle) + ehandle = curl_easy_init (); + + if (ehandle) { + ConCheckCbData *cb_data = g_slice_new0 (ConCheckCbData); - msg = soup_message_new ("GET", priv->uri); - soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT); - /* Disable HTTP/1.1 keepalive; the connection should not persist */ - soup_message_headers_append (msg->request_headers, "Connection", "close"); + cb_data->curl_ehandle = ehandle; + cb_data->request_headers = curl_slist_append (NULL, "Connection: close"); + cb_data->ifspec = g_strdup_printf ("if!%s", iface); cb_data->simple = simple; - cb_data->uri = g_strdup (priv->uri); - cb_data->response = g_strdup (priv->response); + if (priv->response) + cb_data->response = g_strdup (priv->response); + else + cb_data->response = g_strdup (NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE); - /* For internal calls (periodic), remember the check-id at time of scheduling. */ - cb_data->check_id_when_scheduled = IS_PERIODIC_CHECK (callback) ? priv->check_id : 0; + curl_easy_setopt (ehandle, CURLOPT_URL, priv->uri); + curl_easy_setopt (ehandle, CURLOPT_WRITEFUNCTION, easy_write_cb); + curl_easy_setopt (ehandle, CURLOPT_WRITEDATA, cb_data); + curl_easy_setopt (ehandle, CURLOPT_HEADERFUNCTION, easy_header_cb); + curl_easy_setopt (ehandle, CURLOPT_HEADERDATA, cb_data); + curl_easy_setopt (ehandle, CURLOPT_PRIVATE, cb_data); + curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->request_headers); + curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec); + curl_multi_add_handle (priv->curl_mhandle, ehandle); - soup_session_queue_message (priv->soup_session, - msg, - nm_connectivity_check_cb, - cb_data); - priv->initial_check_obsoleted = TRUE; + cb_data->timeout_id = g_timeout_add_seconds (30, timeout_cb, cb_data); - _LOGD ("check: send %srequest to '%s'", IS_PERIODIC_CHECK (callback) ? "periodic " : "", priv->uri); + _LOG2D ("sending request to '%s'", priv->uri); return; } else { - g_warn_if_fail (!IS_PERIODIC_CHECK (callback)); - _LOGD ("check: faking request. Connectivity check disabled"); + _LOGD ("(%s) faking request. Connectivity check disabled", iface); } -#else - _LOGD ("check: faking request. Compiled without connectivity-check support"); -#endif - g_simple_async_result_set_op_res_gssize (simple, priv->state); + g_simple_async_result_set_op_res_gssize (simple, NM_CONNECTIVITY_UNKNOWN); g_simple_async_result_complete_in_idle (simple); g_object_unref (simple); } @@ -336,120 +395,118 @@ nm_connectivity_check_finish (NMConnectivity *self, return (NMConnectivityState) g_simple_async_result_get_op_res_gssize (simple); } -/*****************************************************************************/ - -static void -get_property (GObject *object, guint property_id, - GValue *value, GParamSpec *pspec) +gboolean +nm_connectivity_check_enabled (NMConnectivity *self) { - NMConnectivity *self = NM_CONNECTIVITY (object); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - switch (property_id) { - case PROP_URI: - g_value_set_string (value, priv->uri); - break; - case PROP_INTERVAL: - g_value_set_uint (value, priv->interval); - break; - case PROP_RESPONSE: - if (priv->response) - g_value_set_string (value, priv->response); - else - g_value_set_static_string (value, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } + return (priv->uri && priv->interval && priv->curl_mhandle); +} + +/*****************************************************************************/ + +static gboolean +periodic_check (gpointer user_data) +{ + g_signal_emit (NM_CONNECTIVITY (user_data), signals[PERIODIC_CHECK], 0); + return G_SOURCE_CONTINUE; } static void -set_property (GObject *object, guint property_id, - const GValue *value, GParamSpec *pspec) +update_config (NMConnectivity *self, NMConfigData *config_data) { - NMConnectivity *self = NM_CONNECTIVITY (object); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); const char *uri, *response; guint interval; - gboolean changed; - - switch (property_id) { - case PROP_URI: - uri = g_value_get_string (value); - if (uri && !*uri) + gboolean changed = FALSE; + + /* Set the URI. */ + uri = nm_config_data_get_connectivity_uri (config_data); + if (uri && !*uri) + uri = NULL; + changed = g_strcmp0 (uri, priv->uri) != 0; + if (uri) { + char *scheme = g_uri_parse_scheme (uri); + + if (!scheme) { + _LOGE ("invalid URI '%s' for connectivity check.", uri); + uri = NULL; + } else if (strcasecmp (scheme, "https") == 0) { + _LOGW ("use of HTTPS for connectivity checking is not reliable and is discouraged (URI: %s)", uri); + } else if (strcasecmp (scheme, "http") != 0) { + _LOGE ("scheme of '%s' uri does't use a scheme that is allowed for connectivity check.", uri); uri = NULL; - changed = g_strcmp0 (uri, priv->uri) != 0; -#if WITH_CONCHECK - if (uri) { - SoupURI *soup_uri = soup_uri_new (uri); - - if (!soup_uri || !SOUP_URI_VALID_FOR_HTTP (soup_uri)) { - _LOGE ("invalid uri '%s' for connectivity check.", uri); - uri = NULL; - } - if (uri && soup_uri && changed && - soup_uri_get_scheme(soup_uri) == SOUP_URI_SCHEME_HTTPS) - _LOGW ("use of HTTPS for connectivity checking is not reliable and is discouraged (URI: %s)", uri); - if (soup_uri) - soup_uri_free (soup_uri); - } -#endif - if (changed) { - g_free (priv->uri); - priv->uri = g_strdup (uri); - _reschedule_periodic_checks (self, TRUE); - } - break; - case PROP_INTERVAL: - interval = g_value_get_uint (value); - if (priv->interval != interval) { - priv->interval = interval; - _reschedule_periodic_checks (self, TRUE); - } - break; - case PROP_RESPONSE: - response = g_value_get_string (value); - if (g_strcmp0 (response, priv->response) != 0) { - /* a response %NULL means, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE. Any other response - * (including "") is accepted. */ - g_free (priv->response); - priv->response = g_strdup (response); - _reschedule_periodic_checks (self, TRUE); } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; + + if (scheme) + g_free (scheme); + } + if (changed) { + g_free (priv->uri); + priv->uri = g_strdup (uri); + } + + /* Set the interval. */ + interval = nm_config_data_get_connectivity_interval (config_data); + if (priv->interval != interval) { + priv->interval = interval; + changed = TRUE; + } + + /* Set the response. */ + response = nm_config_data_get_connectivity_response (config_data); + if (g_strcmp0 (response, priv->response) != 0) { + /* a response %NULL means, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE. Any other response + * (including "") is accepted. */ + g_free (priv->response); + priv->response = g_strdup (response); + changed = TRUE; + } + + if (changed) { + nm_clear_g_source (&priv->periodic_check_id); + if (nm_connectivity_check_enabled (self)) + priv->periodic_check_id = g_timeout_add_seconds (priv->interval, periodic_check, self); } } -/*****************************************************************************/ +static void +config_changed_cb (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + NMConnectivity *self) +{ + update_config (self, config_data); +} static void nm_connectivity_init (NMConnectivity *self) { NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURLcode retv; -#if WITH_CONCHECK - priv->soup_session = soup_session_async_new_with_options (SOUP_SESSION_TIMEOUT, 15, NULL); -#endif - priv->state = NM_CONNECTIVITY_NONE; -} + priv->config = g_object_ref (nm_config_get ()); + update_config (self, nm_config_get_data (priv->config)); + g_signal_connect (G_OBJECT (priv->config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (config_changed_cb), + self); -NMConnectivity * -nm_connectivity_new (const char *uri, - guint interval, - const char *response) -{ - return g_object_new (NM_TYPE_CONNECTIVITY, - NM_CONNECTIVITY_URI, uri, - NM_CONNECTIVITY_INTERVAL, interval, - NM_CONNECTIVITY_RESPONSE, response, - NULL); + retv = curl_global_init (CURL_GLOBAL_ALL); + if (retv == CURLE_OK) + priv->curl_mhandle = curl_multi_init (); + + if (priv->curl_mhandle == NULL) { + _LOGE ("cnable to init cURL, connectivity check will not work"); + return; + } + + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb); + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETDATA, self); + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERDATA, self); + curl_multi_setopt (priv->curl_mhandle, CURLOPT_VERBOSE, 1); } static void @@ -461,14 +518,14 @@ dispose (GObject *object) g_clear_pointer (&priv->uri, g_free); g_clear_pointer (&priv->response, g_free); -#if WITH_CONCHECK - if (priv->soup_session) { - soup_session_abort (priv->soup_session); - g_clear_object (&priv->soup_session); + if (priv->config) { + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + g_clear_object (&priv->config); } - nm_clear_g_source (&priv->check_id); -#endif + curl_multi_cleanup (priv->curl_mhandle); + curl_global_cleanup (); + nm_clear_g_source (&priv->periodic_check_id); G_OBJECT_CLASS (nm_connectivity_parent_class)->dispose (object); } @@ -478,37 +535,12 @@ nm_connectivity_class_init (NMConnectivityClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->dispose = dispose; + signals[PERIODIC_CHECK] = + g_signal_new (NM_CONNECTIVITY_PERIODIC_CHECK, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); - obj_properties[PROP_URI] = - g_param_spec_string (NM_CONNECTIVITY_URI, "", "", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_INTERVAL] = - g_param_spec_uint (NM_CONNECTIVITY_INTERVAL, "", "", - 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_RESPONSE] = - g_param_spec_string (NM_CONNECTIVITY_RESPONSE, "", "", - NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STATE] = - g_param_spec_uint (NM_CONNECTIVITY_STATE, "", "", - NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + object_class->dispose = dispose; } - diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h index 6900bd0f..d9a9f233 100644 --- a/src/nm-connectivity.h +++ b/src/nm-connectivity.h @@ -16,6 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2011 Thomas Bechtold <thomasbechtold@jpberlin.de> + * Copyright (C) 2017 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_CONNECTIVITY_H__ @@ -30,31 +31,23 @@ #define NM_IS_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CONNECTIVITY)) #define NM_CONNECTIVITY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTIVITY, NMConnectivityClass)) -#define NM_CONNECTIVITY_URI "uri" -#define NM_CONNECTIVITY_INTERVAL "interval" -#define NM_CONNECTIVITY_RESPONSE "response" -#define NM_CONNECTIVITY_STATE "state" +#define NM_CONNECTIVITY_PERIODIC_CHECK "nm-connectivity-periodic-check" typedef struct _NMConnectivityClass NMConnectivityClass; GType nm_connectivity_get_type (void); -const char *nm_connectivity_state_to_string (NMConnectivityState state); - -NMConnectivity *nm_connectivity_new (const char *uri, - guint interval, - const char *response); +NMConnectivity *nm_connectivity_get (void); -void nm_connectivity_set_online (NMConnectivity *self, - gboolean online); - -NMConnectivityState nm_connectivity_get_state (NMConnectivity *self); +const char *nm_connectivity_state_to_string (NMConnectivityState state); void nm_connectivity_check_async (NMConnectivity *self, + const char *iface, GAsyncReadyCallback callback, gpointer user_data); NMConnectivityState nm_connectivity_check_finish (NMConnectivity *self, GAsyncResult *result, GError **error); +gboolean nm_connectivity_check_enabled (NMConnectivity *self); #endif /* __NETWORKMANAGER_CONNECTIVITY_H__ */ diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index c9bb220c..aaaf7b6c 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -110,6 +110,10 @@ _nm_utils_set_testing (NMUtilsTestFlags flags) /*****************************************************************************/ +const NMIPAddr nm_ip_addr_zero = NMIPAddrInit; + +/*****************************************************************************/ + static GSList *_singletons = NULL; static gboolean _singletons_shutdown = FALSE; @@ -155,6 +159,37 @@ _nm_singleton_instance_register_destruction (GObject *instance) /*****************************************************************************/ +static double +_exp10 (guint16 ex) +{ + double v; + + if (ex == 0) + return 1.0; + + v = _exp10 (ex / 2); + v = v * v; + if (ex % 2) + v *= 10; + return v; +} + +/* + * nm_utils_exp10: + * @ex: the exponent + * + * Returns: 10^ex, or pow(10, ex), or exp10(ex). + */ +double +nm_utils_exp10 (gint16 ex) +{ + if (ex >= 0) + return _exp10 (ex); + return 1.0 / _exp10 (- ((gint32) ex)); +} + +/*****************************************************************************/ + /* * nm_ethernet_address_is_valid: * @addr: pointer to a binary or ASCII Ethernet address @@ -367,30 +402,6 @@ nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, g_array_set_size (array, res_length); } -int -nm_spawn_process (const char *args, GError **error) -{ - GError *local = NULL; - gint num_args; - char **argv = NULL; - int status = -1; - - g_return_val_if_fail (args != NULL, -1); - g_return_val_if_fail (!error || !*error, -1); - - if (g_shell_parse_argv (args, &num_args, &argv, &local)) { - g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &local); - g_strfreev (argv); - } - - if (local) { - nm_log_warn (LOGD_CORE, "could not spawn process '%s': %s", args, local->message); - g_propagate_error (error, local); - } - - return status; -} - static const char * _trunk_first_line (char *str) { @@ -431,11 +442,11 @@ nm_utils_modprobe (GError **error, gboolean suppress_error_logging, const char * nm_log_dbg (LOGD_CORE, "modprobe: '%s'", ARGV_TO_STR (argv)); if (!g_spawn_sync (NULL, (char **) argv->pdata, NULL, 0, NULL, NULL, &std_out, &std_err, &exit_status, &local)) { - nm_log (llevel, LOGD_CORE, "modprobe: '%s' failed: %s", ARGV_TO_STR (argv), local->message); + nm_log (llevel, LOGD_CORE, NULL, NULL, "modprobe: '%s' failed: %s", ARGV_TO_STR (argv), local->message); g_propagate_error (error, local); return -1; } else if (exit_status != 0) { - nm_log (llevel, LOGD_CORE, "modprobe: '%s' exited with error %d%s%s%s%s%s%s", ARGV_TO_STR (argv), exit_status, + nm_log (llevel, LOGD_CORE, NULL, NULL, "modprobe: '%s' exited with error %d%s%s%s%s%s%s", ARGV_TO_STR (argv), exit_status, std_out&&*std_out ? " (" : "", std_out&&*std_out ? _trunk_first_line (std_out) : "", std_out&&*std_out ? ")" : "", std_err&&*std_err ? " (" : "", std_err&&*std_err ? _trunk_first_line (std_err) : "", std_err&&*std_err ? ")" : ""); } @@ -1000,7 +1011,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain } if (start_time != 0 && start_time != start_time0) { nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": don't kill process %ld because the start_time is unexpectedly %lu instead of %ld", - LOG_NAME_ARGS, (long int) pid, (long unsigned) start_time0, (long unsigned) start_time); + LOG_NAME_ARGS, (long int) pid, (unsigned long) start_time0, (unsigned long) start_time); return; } @@ -1206,6 +1217,7 @@ nm_utils_read_link_absolute (const char *link_file, GError **error) #define MAC_TAG "mac:" #define INTERFACE_NAME_TAG "interface-name:" #define DEVICE_TYPE_TAG "type:" +#define DRIVER_TAG "driver:" #define SUBCHAN_TAG "s390-subchannels:" #define EXCEPT_TAG "except:" #define MATCH_TAG_CONFIG_NM_VERSION "nm-version:" @@ -1216,6 +1228,8 @@ nm_utils_read_link_absolute (const char *link_file, GError **error) typedef struct { const char *interface_name; const char *device_type; + const char *driver; + const char *driver_version; struct { const char *value; gboolean is_parsed; @@ -1398,6 +1412,38 @@ match_device_eval (const char *spec_str, return FALSE; } + if (_MATCH_CHECK (spec_str, DRIVER_TAG)) { + const char *t; + + if (!match_data->driver) + return FALSE; + + /* support: + * 1) "${DRIVER}" + * In this case, DRIVER may not contain a '/' character. + * It matches any driver version. + * 2) "${DRIVER}/${DRIVER_VERSION}" + * In this case, DRIVER may contains '/' but DRIVER_VERSION + * may not. A '/' in DRIVER_VERSION may be replaced by '?'. + * + * It follows, that "${DRIVER}/""*" is like 1), but allows + * '/' inside DRIVER. + * + * The fields match to what `nmcli -f GENERAL.DRIVER,GENERAL.DRIVER-VERSION device show` + * gives. However, DRIVER matches literally, while DRIVER_VERSION is a glob + * supporting ? and *. + */ + + t = strrchr (spec_str, '/'); + + if (!t) + return nm_streq (spec_str, match_data->driver); + + return (strncmp (spec_str, match_data->driver, t - spec_str) == 0) + && g_pattern_match_simple (&t[1], + match_data->driver_version ?: ""); + } + if (_MATCH_CHECK (spec_str, SUBCHAN_TAG)) return match_data_s390_subchannels_eval (spec_str, match_data); @@ -1416,6 +1462,8 @@ NMMatchSpecMatchType nm_match_spec_device (const GSList *specs, const char *interface_name, const char *device_type, + const char *driver, + const char *driver_version, const char *hwaddr, const char *s390_subchannels) { @@ -1426,6 +1474,8 @@ nm_match_spec_device (const GSList *specs, MatchDeviceData match_data = { .interface_name = interface_name, .device_type = nm_str_not_empty (device_type), + .driver = nm_str_not_empty (driver), + .driver_version = nm_str_not_empty (driver_version), .hwaddr = { .value = hwaddr, }, @@ -1588,7 +1638,7 @@ nm_match_spec_config (const GSList *specs, guint cur_nm_version, const char *env * @value: the string of device specs * * Splits the specs from the string and returns them as individual - * entires in a #GSList. + * entries in a #GSList. * * It does not validate any specs, it basically just does a special * strsplit with ',' or ';' as separators and supporting '\\' as @@ -1999,27 +2049,57 @@ nm_utils_read_resolv_conf_dns_options (const char *rc_contents) return options; } +/*****************************************************************************/ + +/** + * nm_utils_cmp_connection_by_autoconnect_priority: + * @a: + * @b: + * + * compare connections @a and @b for their autoconnect property + * (with sorting the connection that has autoconnect enabled before + * the other) + * If they both have autoconnect enabled, sort them depending on their + * autoconnect-priority (with the higher priority first). + * + * If their autoconnect/autoconnect-priority is the same, 0 is returned. + * That is, they compare equal. + * + * Returns: -1, 0, or 1 + */ int -nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b) +nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b) { - NMSettingConnection *a_s_con, *b_s_con; - gboolean a_ac, b_ac; - gint a_ap, b_ap; - - a_s_con = nm_connection_get_setting_connection (*a); - b_s_con = nm_connection_get_setting_connection (*b); - - a_ac = !!nm_setting_connection_get_autoconnect (a_s_con); - b_ac = !!nm_setting_connection_get_autoconnect (b_s_con); - if (a_ac != b_ac) - return ((int) b_ac) - ((int) a_ac); - if (!a_ac) + NMSettingConnection *a_s_con; + NMSettingConnection *b_s_con; + int a_ap, b_ap; + gboolean can_autoconnect; + + if (a == b) return 0; + if (!a) + return 1; + if (!b) + return -1; + + a_s_con = nm_connection_get_setting_connection (a); + b_s_con = nm_connection_get_setting_connection (b); - a_ap = nm_setting_connection_get_autoconnect_priority (a_s_con); - b_ap = nm_setting_connection_get_autoconnect_priority (b_s_con); - if (a_ap != b_ap) - return (a_ap > b_ap) ? -1 : 1; + if (!a_s_con) + return !b_s_con ? 0 : 1; + if (!b_s_con) + return -1; + + can_autoconnect = !!nm_setting_connection_get_autoconnect (a_s_con); + if (can_autoconnect != (!!nm_setting_connection_get_autoconnect (b_s_con))) + return can_autoconnect ? -1 : 1; + + if (can_autoconnect) { + a_ap = nm_setting_connection_get_autoconnect_priority (a_s_con); + b_ap = nm_setting_connection_get_autoconnect_priority (b_s_con); + if (a_ap != b_ap) + return (a_ap > b_ap) ? -1 : 1; + } return 0; } @@ -2355,9 +2435,9 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, connection_diff_are_same = nm_connection_diff (connection, diff_base, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &connection_diff); if (connection_diff_are_same) { if (diff_base) - nm_log (level, domain, "%sconnection '%s' (%p/%s and %p/%s): no difference", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base)); + nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s and %p/%s): no difference", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base)); else - nm_log (level, domain, "%sconnection '%s' (%p/%s): no properties set", prefix, name, connection, G_OBJECT_TYPE_NAME (connection)); + nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s): no properties set", prefix, name, connection, G_OBJECT_TYPE_NAME (connection)); g_assert (!connection_diff); return; } @@ -2393,16 +2473,16 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, const char *path = nm_connection_get_path (connection); if (diff_base) { - nm_log (level, domain, "%sconnection '%s' (%p/%s < %p/%s)%s%s%s:", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base), + nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s < %p/%s)%s%s%s:", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base), NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); } else { - nm_log (level, domain, "%sconnection '%s' (%p/%s):%s%s%s", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), + nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s):%s%s%s", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); } print_header = FALSE; if (!nm_connection_verify (connection, &err_verify)) { - nm_log (level, domain, "%sconnection %p does not verify: %s", prefix, connection, err_verify->message); + nm_log (level, domain, NULL, NULL, "%sconnection %p does not verify: %s", prefix, connection, err_verify->message); g_clear_error (&err_verify); } } @@ -2415,21 +2495,21 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, g_string_printf (str1, "*missing* < %p", setting_data->diff_base_setting); else g_string_printf (str1, "%p < *missing*", setting_data->setting); - nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s [ %s ]", prefix, setting_data->name, str1->str); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s [ %s ]", prefix, setting_data->name, str1->str); } else - nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s [ %p ]", prefix, setting_data->name, setting_data->setting); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s [ %p ]", prefix, setting_data->name, setting_data->setting); print_setting_header = FALSE; } g_string_printf (str1, "%s.%s", setting_data->name, item->item_name); switch (item->diff_result & (NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B)) { case NM_SETTING_DIFF_RESULT_IN_B: - nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ? str_diff : "NULL"); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ? str_diff : "NULL"); break; case NM_SETTING_DIFF_RESULT_IN_A: - nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ? str_conn : "NULL"); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ? str_conn : "NULL"); break; default: - nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ? str_conn : "NULL", str_diff ? str_diff : "NULL"); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ? str_conn : "NULL", str_diff ? str_diff : "NULL"); break; #undef _NM_LOG_ALIGN } @@ -3249,7 +3329,7 @@ nm_utils_ipv6_interface_identifier_get_from_addr (NMUtilsIPv6IfaceId *iid, */ gboolean nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId *iid, - const char *token) + const char *token) { struct in6_addr i6_token; @@ -3469,11 +3549,36 @@ nm_utils_stable_id_parse (const char *stable_id, /*****************************************************************************/ static gboolean +_is_reserved_ipv6_iid (const guint8 *iid) +{ + /* https://tools.ietf.org/html/rfc5453 */ + /* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */ + + /* 0000:0000:0000:0000 (Subnet-Router Anycast [RFC4291]) */ + if (memcmp (iid, &nm_ip_addr_zero.addr6.s6_addr[8], 8) == 0) + return TRUE; + + /* 0200:5EFF:FE00:0000 - 0200:5EFF:FE00:5212 (Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block [RFC4291]) + * 0200:5EFF:FE00:5213 (Proxy Mobile IPv6 [RFC6543]) + * 0200:5EFF:FE00:5214 - 0200:5EFF:FEFF:FFFF (Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block [RFC4291]) */ + if (memcmp (iid, (const guint8[]) { 0x02, 0x00, 0x5E, 0xFF, 0xFE }, 5) == 0) + return TRUE; + + /* FDFF:FFFF:FFFF:FF80 - FDFF:FFFF:FFFF:FFFF (Reserved Subnet Anycast Addresses [RFC2526]) */ + if (memcmp (iid, (const guint8[]) { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 7) == 0) { + if (iid[7] & 0x80) + return TRUE; + } + + return FALSE; +} + +static gboolean _set_stable_privacy (NMUtilsStableType stable_type, struct in6_addr *addr, const char *ifname, const char *network_id, - guint dad_counter, + guint32 dad_counter, guint8 *secret_key, gsize key_len, GError **error) @@ -3524,9 +3629,19 @@ _set_stable_privacy (NMUtilsStableType stable_type, g_checksum_update (sum, (const guchar *) secret_key, key_len); g_checksum_get_digest (sum, digest, &len); - g_checksum_free (sum); - g_return_val_if_fail (len == 32, FALSE); + nm_assert (len == sizeof (digest)); + + while (_is_reserved_ipv6_iid (digest)) { + g_checksum_reset (sum); + tmp[0] = htonl (++dad_counter); + g_checksum_update (sum, digest, len); + g_checksum_update (sum, (const guchar *) &tmp[0], sizeof (tmp[0])); + g_checksum_get_digest (sum, digest, &len); + nm_assert (len == sizeof (digest)); + } + + g_checksum_free (sum); memcpy (addr->s6_addr + 8, &digest[0], 8); @@ -3538,7 +3653,7 @@ nm_utils_ipv6_addr_set_stable_privacy_impl (NMUtilsStableType stable_type, struct in6_addr *addr, const char *ifname, const char *network_id, - guint dad_counter, + guint32 dad_counter, guint8 *secret_key, gsize key_len, GError **error) @@ -3560,7 +3675,7 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type, struct in6_addr *addr, const char *ifname, const char *network_id, - guint dad_counter, + guint32 dad_counter, GError **error) { gs_free guint8 *secret_key = NULL; @@ -3795,7 +3910,7 @@ debug_key_matches (const gchar *key, * nm_utils_parse_debug_string: * @string: the string to parse * @keys: the debug keys - * @nkeys: number of entires in @keys + * @nkeys: number of entries in @keys * * Similar to g_parse_debug_string(), but does not special * case "help" or "all". @@ -4305,3 +4420,40 @@ skip: return result; } +char * +nm_utils_format_con_diff_for_audit (GHashTable *diff) +{ + GHashTable *setting_diff; + char *setting_name, *prop_name; + GHashTableIter iter, iter2; + GString *str; + + str = g_string_sized_new (32); + g_hash_table_iter_init (&iter, diff); + + while (g_hash_table_iter_next (&iter, + (gpointer *) &setting_name, + (gpointer *) &setting_diff)) { + if (!setting_diff) + continue; + + g_hash_table_iter_init (&iter2, setting_diff); + + while (g_hash_table_iter_next (&iter2, (gpointer *) &prop_name, NULL)) + g_string_append_printf (str, "%s.%s,", setting_name, prop_name); + } + + if (str->len) + str->str[str->len - 1] = '\0'; + + return g_string_free (str, FALSE); +} + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE (nm_activation_type_to_string, NMActivationType, + NM_UTILS_LOOKUP_DEFAULT_WARN ("(unknown)"), + NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVATION_TYPE_MANAGED, "managed"), + NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVATION_TYPE_ASSUME, "assume"), + NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVATION_TYPE_EXTERNAL, "external"), +) diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index ada3f8ef..0f37bd20 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -90,6 +90,25 @@ GETTER (void) \ /*****************************************************************************/ +typedef struct { + union { + guint8 addr_ptr[1]; + in_addr_t addr4; + struct in6_addr addr6; + + /* NMIPAddr is really a union for IP addresses. + * However, as ethernet addresses fit in here nicely, use + * it also for an ethernet MAC address. */ + guint8 addr_eth[6 /*ETH_ALEN*/]; + }; +} NMIPAddr; + +extern const NMIPAddr nm_ip_addr_zero; + +#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT } + +/*****************************************************************************/ + gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len); gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen); @@ -97,6 +116,8 @@ in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen); const struct in6_addr *nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen); gboolean nm_utils_ip6_address_same_prefix (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen); +double nm_utils_exp10 (gint16 e); + /** * nm_utils_ip6_route_metric_normalize: * @metric: the route metric @@ -112,8 +133,6 @@ nm_utils_ip6_route_metric_normalize (guint32 metric) return metric ? metric : 1024 /*NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6*/; } -int nm_spawn_process (const char *args, GError **error); - int nm_utils_modprobe (GError **error, gboolean suppress_error_loggin, const char *arg1, ...) G_GNUC_NULL_TERMINATED; guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid); @@ -144,6 +163,8 @@ typedef enum { NMMatchSpecMatchType nm_match_spec_device (const GSList *specs, const char *interface_name, + const char *driver, + const char *driver_version, const char *device_type, const char *hwaddr, const char *s390_subchannels); @@ -274,7 +295,7 @@ const char *nm_utils_new_infiniband_name (char *name, const char *parent_name, i GPtrArray *nm_utils_read_resolv_conf_nameservers (const char *rc_contents); GPtrArray *nm_utils_read_resolv_conf_dns_options (const char *rc_contents); -int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b); +int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b); void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix); @@ -390,7 +411,7 @@ gboolean nm_utils_ipv6_addr_set_stable_privacy_impl (NMUtilsStableType stable_ty struct in6_addr *addr, const char *ifname, const char *network_id, - guint dad_counter, + guint32 dad_counter, guint8 *secret_key, gsize key_len, GError **error); @@ -399,7 +420,7 @@ gboolean nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType id_type, struct in6_addr *addr, const char *ifname, const char *network_id, - guint dad_counter, + guint32 dad_counter, GError **error); char *nm_utils_hw_addr_gen_random_eth (const char *current_mac_address, @@ -471,5 +492,13 @@ struct stat; gboolean nm_utils_validate_plugin (const char *path, struct stat *stat, GError **error); char **nm_utils_read_plugin_paths (const char *dirname, const char *prefix); +char *nm_utils_format_con_diff_for_audit (GHashTable *diff); + + +/*****************************************************************************/ + +const char *nm_activation_type_to_string (NMActivationType activation_type); + +/*****************************************************************************/ #endif /* __NM_CORE_UTILS_H__ */ diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index 5944654c..9ac6d552 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -36,12 +36,16 @@ /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_LOG_WITH_PTR, PROP_PLATFORM, ); typedef struct { GPtrArray *entries_ip4; GPtrArray *entries_ip6; + + NMPlatform *platform; + struct { guint guard; guint backoff_wait_time_ms; @@ -56,9 +60,9 @@ typedef struct { * pointers. * Guard every publicly accessible function to return early if the instance * is already disposing. */ - gboolean disposed; + bool disposed; - NMPlatform *platform; + bool log_with_ptr; } NMDefaultRouteManagerPrivate; struct _NMDefaultRouteManager { @@ -74,8 +78,6 @@ G_DEFINE_TYPE (NMDefaultRouteManager, nm_default_route_manager, G_TYPE_OBJECT) #define NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDefaultRouteManager, NM_IS_DEFAULT_ROUTE_MANAGER) -NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get, NM_TYPE_DEFAULT_ROUTE_MANAGER); - /*****************************************************************************/ #define _NMLOG_PREFIX_NAME "default-route" @@ -97,9 +99,9 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get, if (nm_logging_enabled (__level, __domain)) { \ char __prefix_buf[100]; \ \ - _nm_log (__level, __domain, 0, \ + _nm_log (__level, __domain, 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - self != singleton_instance \ + NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr \ ? nm_sprintf_buf (__prefix_buf, "%s%c[%p]", \ _NMLOG2_PREFIX_NAME, \ __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'), \ @@ -123,9 +125,9 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get, guint __entry_idx = (entry_idx); \ const Entry *const __entry = (entry); \ \ - _nm_log (__level, __domain, 0, \ - "%s: entry[%u/%s:%p:%s:%c:%csync]: "_NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - self != singleton_instance \ + _nm_log (__level, __domain, 0, NULL, NULL, \ + "%s: entry[%u/%s:%p:%s:%chas:%csync]: "_NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr \ ? nm_sprintf_buf (__prefix_buf, "%s%c[%p]", \ _NMLOG2_PREFIX_NAME, \ __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'), \ @@ -135,7 +137,7 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get, NM_IS_DEVICE (__entry->source.pointer) ? "dev" : "vpn", \ __entry->source.pointer, \ NM_IS_DEVICE (__entry->source.pointer) ? nm_device_get_iface (__entry->source.device) : nm_active_connection_get_settings_connection_id (NM_ACTIVE_CONNECTION (__entry->source.vpn)), \ - (__entry->never_default ? '0' : '1'), \ + (__entry->never_default ? '-' : '+'), \ (__entry->synced ? '+' : '-') \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ @@ -301,24 +303,21 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g return FALSE; if (vtable->vt->is_ip4) { - success = nm_platform_ip4_route_add (priv->platform, - entry->route.rx.ifindex, - entry->route.rx.rt_source, - 0, - 0, - entry->route.r4.gateway, - 0, - entry->effective_metric, - entry->route.rx.mss); + NMPlatformIP4Route rt = entry->route.r4; + + rt.network = 0; + rt.plen = 0; + rt.metric = entry->effective_metric; + + success = nm_platform_ip4_route_add (priv->platform, &rt); } else { - success = nm_platform_ip6_route_add (priv->platform, - entry->route.rx.ifindex, - entry->route.rx.rt_source, - in6addr_any, - 0, - entry->route.r6.gateway, - entry->effective_metric, - entry->route.rx.mss); + NMPlatformIP6Route rt = entry->route.r6; + + rt.network = in6addr_any; + rt.plen = 0; + rt.metric = entry->effective_metric; + + success = nm_platform_ip6_route_add (priv->platform, &rt); } if (!success) { _LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u", @@ -483,17 +482,6 @@ _get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *s return result; } -static int -_sort_metrics_ascending_fcn (gconstpointer a, gconstpointer b) -{ - guint32 m_a = *((guint32 *) a); - guint32 m_b = *((guint32 *) b); - - if (m_a < m_b) - return -1; - return m_a == m_b ? 0 : 1; -} - static gboolean _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *changed_entry, const Entry *old_entry, gboolean external_change) { @@ -536,8 +524,6 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c for (i = 0; i < entries->len; i++) { entry = g_ptr_array_index (entries, i); - g_assert (entry != old_entry); - if (entry->never_default) continue; @@ -592,12 +578,15 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c /* for the changed entry, the previous metric was either old_entry->effective_metric, * or none. Hence, we only have to remember what is going to change. */ g_array_append_val (changed_metrics, expected_metric); - if (old_entry) { + if (!old_entry) { + _LOG2D (vtable, i, entry, "sync:add %s (%u)", + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric); + } else if (old_entry != changed_entry) { _LOG2D (vtable, i, entry, "sync:update %s (%u -> %u)", vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) old_entry->effective_metric, (guint) expected_metric); } else { - _LOG2D (vtable, i, entry, "sync:add %s (%u)", + _LOG2D (vtable, i, entry, "sync:resync %s (%u)", vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric); } } else if (entry->effective_metric != expected_metric) { @@ -624,7 +613,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c g_array_free (routes, TRUE); - g_array_sort (changed_metrics, _sort_metrics_ascending_fcn); + g_array_sort_with_data (changed_metrics, nm_cmp_uint32_p_with_data, NULL); last_metric = -1; for (j = 0; j < changed_metrics->len; j++) { expected_metric = g_array_index (changed_metrics, guint32, j); @@ -656,7 +645,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c return changed; } -static void +static gboolean _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry_idx, const Entry *old_entry) { NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); @@ -675,21 +664,26 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry->effective_metric = entry->route.rx.metric; _LOG2D (vtable, entry_idx, entry, "%s %s (%"G_GUINT32_FORMAT")", - old_entry ? "record:update" : "record:add ", + old_entry + ? (entry != old_entry + ? "record:update" + : "record:resync") + : "record:add ", vtable->vt->route_to_string (&entry->route, NULL, 0), entry->effective_metric); g_ptr_array_sort_with_data (entries, _sort_entries_cmp, NULL); - _resync_all (vtable, self, entry, old_entry, FALSE); + return _resync_all (vtable, self, entry, old_entry, FALSE); } -static void +static gboolean _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry_idx) { NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); Entry *entry; GPtrArray *entries; + gboolean ret; entries = vtable->get_entries (priv); @@ -704,15 +698,18 @@ _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint g_ptr_array_index (entries, entry_idx) = NULL; g_ptr_array_remove_index (entries, entry_idx); - _resync_all (vtable, self, NULL, entry, FALSE); - + ret = _resync_all (vtable, self, NULL, entry, FALSE); _entry_free (entry); + + return ret; } /*****************************************************************************/ -static void -_ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, gpointer source) +static gboolean +_ipx_update_default_route (const VTableIP *vtable, + NMDefaultRouteManager *self, + gpointer source) { NMDefaultRouteManagerPrivate *priv; Entry *entry; @@ -724,20 +721,20 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, NMDevice *device = NULL; NMVpnConnection *vpn = NULL; gboolean never_default = FALSE; - gboolean synced = FALSE; + gboolean synced = FALSE, ret; - g_return_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self)); + g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE); priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); if (priv->disposed) - return; + return FALSE; if (NM_IS_DEVICE (source)) device = source; else if (NM_IS_VPN_CONNECTION (source)) vpn = source; else - g_return_if_reached (); + g_return_val_if_reached (FALSE); if (device) ip_ifindex = nm_device_get_ip_ifindex (device); @@ -756,15 +753,15 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, g_object_freeze_notify (G_OBJECT (self)); _entry_at_idx_remove (vtable, self, entry_idx); g_assert (!_entry_find_by_source (entries, source, NULL)); - _ipx_update_default_route (vtable, self, source); + ret = _ipx_update_default_route (vtable, self, source); g_object_thaw_notify (G_OBJECT (self)); - return; + return ret; } /* get the @default_route from the device. */ if (ip_ifindex > 0) { if (device) { - gboolean is_assumed; + gboolean is_assumed = FALSE; if (vtable->vt->is_ip4) default_route = (const NMPlatformIPRoute *) nm_device_get_ip4_default_route (device, &is_assumed); @@ -784,9 +781,8 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, default_route = &rt.rx; never_default = TRUE; - synced = TRUE; - } else - synced = default_route && !is_assumed; + } + synced = !is_assumed; } else { NMConnection *connection = nm_active_connection_get_applied_connection ((NMActiveConnection *) vpn); @@ -842,9 +838,10 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, default_route = NULL; } - if (!entry && !default_route) - /* nothing to do */; - else if (!entry) { + if (!entry && !default_route) { + /* nothing to do */ + return FALSE; + } else if (!entry) { /* add */ entry = g_slice_new0 (Entry); entry->source.object = g_object_ref (source); @@ -862,7 +859,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, entry->synced = synced; g_ptr_array_add (entries, entry); - _entry_at_idx_update (vtable, self, entries->len - 1, NULL); + return _entry_at_idx_update (vtable, self, entries->len - 1, NULL); } else if (default_route) { /* update */ Entry old_entry, new_entry; @@ -878,28 +875,36 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, new_entry.never_default = never_default; new_entry.synced = synced; - if (memcmp (entry, &new_entry, sizeof (new_entry)) == 0) - return; - - old_entry = *entry; - *entry = new_entry; - _entry_at_idx_update (vtable, self, entry_idx, &old_entry); + if (memcmp (entry, &new_entry, sizeof (new_entry)) == 0) { + if (!synced) { + /* the internal book-keeping doesn't change, so don't do a full + * sync of the configured routes. */ + return FALSE; + } + return _entry_at_idx_update (vtable, self, entry_idx, entry); + } else { + old_entry = *entry; + *entry = new_entry; + return _entry_at_idx_update (vtable, self, entry_idx, &old_entry); + } } else { /* delete */ - _entry_at_idx_remove (vtable, self, entry_idx); + return _entry_at_idx_remove (vtable, self, entry_idx); } } -void -nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *self, gpointer source) +gboolean +nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *self, + gpointer source) { - _ipx_update_default_route (&vtable_ip4, self, source); + return _ipx_update_default_route (&vtable_ip4, self, source); } -void -nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *self, gpointer source) +gboolean +nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *self, + gpointer source) { - _ipx_update_default_route (&vtable_ip6, self, source); + return _ipx_update_default_route (&vtable_ip6, self, source); } /*****************************************************************************/ @@ -1259,7 +1264,7 @@ static const VTableIP vtable_ip6 = { /*****************************************************************************/ static gboolean -_resync_idle_now (NMDefaultRouteManager *self) +_resync_now (NMDefaultRouteManager *self) { gboolean has_v4_changes, has_v6_changes; gboolean changed = FALSE; @@ -1274,7 +1279,7 @@ _resync_idle_now (NMDefaultRouteManager *self) priv->resync.has_v4_changes = FALSE; priv->resync.has_v6_changes = FALSE; - priv->resync.idle_handle = 0; + nm_clear_g_source (&priv->resync.idle_handle); priv->resync.backoff_wait_time_ms = priv->resync.backoff_wait_time_ms == 0 ? 100 @@ -1291,6 +1296,64 @@ _resync_idle_now (NMDefaultRouteManager *self) _resync_idle_cancel (self); } + return changed; +} + +/** + * nm_default_route_manager_resync: + * @self: the #NMDefaultRouteManager instance + * @af_family: the address family to resync, can be + * AF_INET, AF_INET6 or AF_UNSPEC to sync both. + * + * #NMDefaultRouteManager keeps an internal list of configured + * routes. Usually, it configures routes in the system only + * - when that internal list changes due to + * nm_default_route_manager_ip4_update_default_route() or + * nm_default_route_manager_ip6_update_default_route(). + * - when platform notifies about changes, via _resync_idle_now(). + * This forces a resync to update the internal bookkeeping + * with what is currently configured in the system, but also + * reconfigure the system with all non-assumed default routes. + * + * Returns: %TRUE if anything changed during resync. + */ +gboolean +nm_default_route_manager_resync (NMDefaultRouteManager *self, + int af_family) +{ + NMDefaultRouteManagerPrivate *priv; + + g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE); + g_return_val_if_fail (NM_IN_SET (af_family, AF_INET, AF_INET6, AF_UNSPEC), FALSE); + + priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + + if (priv->disposed) + return FALSE; + + switch (af_family) { + case AF_INET: + priv->resync.has_v4_changes = TRUE; + break; + case AF_INET6: + priv->resync.has_v6_changes = TRUE; + break; + default: + priv->resync.has_v4_changes = TRUE; + priv->resync.has_v6_changes = TRUE; + break; + } + + return _resync_now (self); +} + +static gboolean +_resync_idle_now (NMDefaultRouteManager *self) +{ + NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + + priv->resync.idle_handle = 0; + _resync_now (self); return G_SOURCE_REMOVE; } @@ -1336,33 +1399,6 @@ _resync_idle_reschedule (NMDefaultRouteManager *self) } static void -_platform_ipx_route_changed_cb (const VTableIP *vtable, - NMDefaultRouteManager *self, - const NMPlatformIPRoute *route) -{ - NMDefaultRouteManagerPrivate *priv; - - if (route && !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { - /* we only care about address changes or changes of default route. */ - return; - } - - priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); - - if (priv->resync.guard) { - /* callbacks while executing _resync_all() are ignored. */ - return; - } - - if (vtable->vt->is_ip4) - priv->resync.has_v4_changes = TRUE; - else - priv->resync.has_v6_changes = TRUE; - - _resync_idle_reschedule (self); -} - -static void _platform_changed_cb (NMPlatform *platform, int obj_type_i, int ifindex, @@ -1370,24 +1406,44 @@ _platform_changed_cb (NMPlatform *platform, int change_type_i, NMDefaultRouteManager *self) { + NMDefaultRouteManagerPrivate *priv; const NMPObjectType obj_type = obj_type_i; + const VTableIP *vtable; switch (obj_type) { case NMP_OBJECT_TYPE_IP4_ADDRESS: - _platform_ipx_route_changed_cb (&vtable_ip4, self, NULL); + vtable = &vtable_ip4; break; case NMP_OBJECT_TYPE_IP6_ADDRESS: - _platform_ipx_route_changed_cb (&vtable_ip6, self, NULL); + vtable = &vtable_ip6; break; case NMP_OBJECT_TYPE_IP4_ROUTE: - _platform_ipx_route_changed_cb (&vtable_ip4, self, (const NMPlatformIPRoute *) platform_object); + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (platform_object)) + return; + vtable = &vtable_ip4; break; case NMP_OBJECT_TYPE_IP6_ROUTE: - _platform_ipx_route_changed_cb (&vtable_ip6, self, (const NMPlatformIPRoute *) platform_object); + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (platform_object)) + return; + vtable = &vtable_ip6; break; default: g_return_if_reached (); } + + priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + + if (priv->resync.guard) { + /* callbacks while executing _resync_all() are ignored. */ + return; + } + + if (vtable->vt->is_ip4) + priv->resync.has_v4_changes = TRUE; + else + priv->resync.has_v6_changes = TRUE; + + _resync_idle_reschedule (self); } /*****************************************************************************/ @@ -1400,6 +1456,10 @@ set_property (GObject *object, guint prop_id, NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); switch (prop_id) { + case PROP_LOG_WITH_PTR: + /* construct-only */ + priv->log_with_ptr = g_value_get_boolean (value); + break; case PROP_PLATFORM: /* construct-only */ priv->platform = g_value_get_object (value) ? : NM_PLATFORM_GET; @@ -1436,9 +1496,10 @@ constructed (GObject *object) } NMDefaultRouteManager * -nm_default_route_manager_new (NMPlatform *platform) +nm_default_route_manager_new (gboolean log_with_ptr, NMPlatform *platform) { return g_object_new (NM_TYPE_DEFAULT_ROUTE_MANAGER, + NM_DEFAULT_ROUTE_MANAGER_LOG_WITH_PTR, log_with_ptr, NM_DEFAULT_ROUTE_MANAGER_PLATFORM, platform, NULL); } @@ -1486,6 +1547,13 @@ nm_default_route_manager_class_init (NMDefaultRouteManagerClass *klass) object_class->dispose = dispose; object_class->set_property = set_property; + obj_properties[PROP_LOG_WITH_PTR] = + g_param_spec_boolean (NM_DEFAULT_ROUTE_MANAGER_LOG_WITH_PTR, "", "", + TRUE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PLATFORM] = g_param_spec_object (NM_DEFAULT_ROUTE_MANAGER_PLATFORM, "", "", NM_TYPE_PLATFORM, diff --git a/src/nm-default-route-manager.h b/src/nm-default-route-manager.h index bd5e8732..bac8a6eb 100644 --- a/src/nm-default-route-manager.h +++ b/src/nm-default-route-manager.h @@ -30,17 +30,17 @@ #define NM_IS_DEFAULT_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEFAULT_ROUTE_MANAGER)) #define NM_DEFAULT_ROUTE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEFAULT_ROUTE_MANAGER, NMDefaultRouteManagerClass)) -#define NM_DEFAULT_ROUTE_MANAGER_PLATFORM "platform" +#define NM_DEFAULT_ROUTE_MANAGER_LOG_WITH_PTR "log-with-ptr" +#define NM_DEFAULT_ROUTE_MANAGER_PLATFORM "platform" typedef struct _NMDefaultRouteManagerClass NMDefaultRouteManagerClass; GType nm_default_route_manager_get_type (void); -NMDefaultRouteManager *nm_default_route_manager_get (void); -NMDefaultRouteManager *nm_default_route_manager_new (NMPlatform *platform); +NMDefaultRouteManager *nm_default_route_manager_new (gboolean log_with_ptr, NMPlatform *platform); -void nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *manager, gpointer source); -void nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *manager, gpointer source); +gboolean nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *manager, gpointer source); +gboolean nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *manager, gpointer source); gboolean nm_default_route_manager_ip4_connection_has_default_route (NMDefaultRouteManager *manager, NMConnection *connection, gboolean *out_is_never_default); gboolean nm_default_route_manager_ip6_connection_has_default_route (NMDefaultRouteManager *manager, NMConnection *connection, gboolean *out_is_never_default); @@ -61,4 +61,7 @@ NMIP6Config *nm_default_route_manager_ip6_get_best_config (NMDefaultRouteManager NMDevice **out_device, NMVpnConnection **out_vpn); +gboolean nm_default_route_manager_resync (NMDefaultRouteManager *self, + int af_family); + #endif /* NM_DEFAULT_ROUTE_MANAGER_H */ diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 6c0c4bb4..0d482e0c 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -15,20 +15,22 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2004 - 2012 Red Hat, Inc. + * Copyright (C) 2004 - 2017 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. */ #include "nm-default.h" +#include "nm-dispatcher.h" + #include <string.h> #include <errno.h> -#include "nm-dispatcher.h" #include "nm-dispatcher-api.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-connectivity.h" +#include "nm-act-request.h" #include "devices/nm-device.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" @@ -70,14 +72,14 @@ static Monitor monitors[3] = { }; static const Monitor* -_get_monitor_by_action (DispatcherAction action) +_get_monitor_by_action (NMDispatcherAction action) { switch (action) { - case DISPATCHER_ACTION_PRE_UP: - case DISPATCHER_ACTION_VPN_PRE_UP: + case NM_DISPATCHER_ACTION_PRE_UP: + case NM_DISPATCHER_ACTION_VPN_PRE_UP: return &monitors[MONITOR_INDEX_PRE_UP]; - case DISPATCHER_ACTION_PRE_DOWN: - case DISPATCHER_ACTION_VPN_PRE_DOWN: + case NM_DISPATCHER_ACTION_PRE_DOWN: + case NM_DISPATCHER_ACTION_VPN_PRE_DOWN: return &monitors[MONITOR_INDEX_PRE_DOWN]; default: return &monitors[MONITOR_INDEX_DEFAULT]; @@ -311,9 +313,9 @@ fill_vpn_props (NMProxyConfig *proxy_config, } typedef struct { - DispatcherAction action; + NMDispatcherAction action; guint request_id; - DispatcherFunc callback; + NMDispatcherFunc callback; gpointer user_data; guint idle_id; } DispatchInfo; @@ -362,7 +364,7 @@ dispatch_result_to_string (DispatchResult result) } static void -dispatcher_results_process (guint request_id, DispatcherAction action, GVariantIter *results) +dispatcher_results_process (guint request_id, NMDispatcherAction action, GVariantIter *results) { const char *script, *err; guint32 result; @@ -440,22 +442,22 @@ dispatcher_done_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) } static const char *action_table[] = { - [DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME, - [DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP, - [DISPATCHER_ACTION_UP] = NMD_ACTION_UP, - [DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN, - [DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN, - [DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP, - [DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP, - [DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN, - [DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN, - [DISPATCHER_ACTION_DHCP4_CHANGE] = NMD_ACTION_DHCP4_CHANGE, - [DISPATCHER_ACTION_DHCP6_CHANGE] = NMD_ACTION_DHCP6_CHANGE, - [DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = NMD_ACTION_CONNECTIVITY_CHANGE + [NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME, + [NM_DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP, + [NM_DISPATCHER_ACTION_UP] = NMD_ACTION_UP, + [NM_DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN, + [NM_DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN, + [NM_DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP, + [NM_DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP, + [NM_DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN, + [NM_DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN, + [NM_DISPATCHER_ACTION_DHCP4_CHANGE] = NMD_ACTION_DHCP4_CHANGE, + [NM_DISPATCHER_ACTION_DHCP6_CHANGE] = NMD_ACTION_DHCP6_CHANGE, + [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = NMD_ACTION_CONNECTIVITY_CHANGE }; static const char * -action_to_string (DispatcherAction action) +action_to_string (NMDispatcherAction action) { g_assert ((gsize) action < G_N_ELEMENTS (action_table)); return action_table[action]; @@ -474,17 +476,18 @@ dispatcher_idle_cb (gpointer user_data) } static gboolean -_dispatcher_call (DispatcherAction action, +_dispatcher_call (NMDispatcherAction action, gboolean blocking, + NMDevice *device, NMSettingsConnection *settings_connection, NMConnection *applied_connection, - NMDevice *device, + gboolean activation_type_external, NMConnectivityState connectivity_state, const char *vpn_iface, NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config, - DispatcherFunc callback, + NMDispatcherFunc callback, gpointer user_data, guint *out_call_id) { @@ -504,6 +507,7 @@ _dispatcher_call (DispatcherAction action, GError *error = NULL; static guint request_counter = 0; guint reqid = ++request_counter; + const char *connectivity_state_string = "UNKNOWN"; if (!dispatcher_proxy) return FALSE; @@ -517,8 +521,8 @@ _dispatcher_call (DispatcherAction action, _ensure_requests (); /* All actions except 'hostname' and 'connectivity-change' require a device */ - if ( action == DISPATCHER_ACTION_HOSTNAME - || action == DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { + if ( action == NM_DISPATCHER_ACTION_HOSTNAME + || action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { _LOGD ("(%u) dispatching action '%s'%s", reqid, action_to_string (action), blocking @@ -573,7 +577,7 @@ _dispatcher_call (DispatcherAction action, NMD_CONNECTION_PROPS_FILENAME, g_variant_new_string (filename)); } - if (nm_settings_connection_get_nm_generated_assumed (settings_connection)) { + if (activation_type_external) { g_variant_builder_add (&connection_props, "{sv}", NMD_CONNECTION_PROPS_EXTERNAL, g_variant_new_boolean (TRUE)); @@ -589,8 +593,8 @@ _dispatcher_call (DispatcherAction action, g_variant_builder_init (&vpn_ip6_props, G_VARIANT_TYPE_VARDICT); /* hostname and connectivity-change actions don't send device data */ - if ( action != DISPATCHER_ACTION_HOSTNAME - && action != DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { + if ( action != NM_DISPATCHER_ACTION_HOSTNAME + && action != NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { fill_device_props (device, &device_props, &device_proxy_props, @@ -613,6 +617,10 @@ _dispatcher_call (DispatcherAction action, if (!device_dhcp6_props) device_dhcp6_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)); +#if WITH_CONCHECK + connectivity_state_string = nm_connectivity_state_to_string (connectivity_state); +#endif + /* Send the action to the dispatcher */ if (blocking) { GVariant *ret; @@ -629,7 +637,7 @@ _dispatcher_call (DispatcherAction action, &device_ip6_props, device_dhcp4_props, device_dhcp6_props, - nm_connectivity_state_to_string (connectivity_state), + connectivity_state_string, vpn_iface ? vpn_iface : "", &vpn_proxy_props, &vpn_ip4_props, @@ -667,7 +675,7 @@ _dispatcher_call (DispatcherAction action, &device_ip6_props, device_dhcp4_props, device_dhcp6_props, - nm_connectivity_state_to_string (connectivity_state), + connectivity_state_string, vpn_iface ? vpn_iface : "", &vpn_proxy_props, &vpn_ip4_props, @@ -694,41 +702,75 @@ done: } /** - * nm_dispatcher_call: - * @action: the %DispatcherAction - * @settings_connection: the #NMSettingsConnection the action applies to - * @applied_connection: the currently applied connection + * nm_dispatcher_call_hostname: + * @callback: a caller-supplied callback to execute when done + * @user_data: caller-supplied pointer passed to @callback + * @out_call_id: on success, a call identifier which can be passed to + * nm_dispatcher_call_cancel() + * + * This method always invokes the dispatcher action asynchronously. + * + * Returns: %TRUE if the action was dispatched, %FALSE on failure + */ +gboolean +nm_dispatcher_call_hostname (NMDispatcherFunc callback, + gpointer user_data, + guint *out_call_id) +{ + return _dispatcher_call (NM_DISPATCHER_ACTION_HOSTNAME, FALSE, + NULL, NULL, NULL, FALSE, + NM_CONNECTIVITY_UNKNOWN, + NULL, NULL, NULL, NULL, + callback, user_data, out_call_id); +} + +/** + * nm_dispatcher_call_device: + * @action: the %NMDispatcherAction * @device: the #NMDevice the action applies to + * @act_request: the #NMActRequest for the action. If %NULL, use the + * current request of the device. * @callback: a caller-supplied callback to execute when done * @user_data: caller-supplied pointer passed to @callback * @out_call_id: on success, a call identifier which can be passed to * nm_dispatcher_call_cancel() * - * This method always invokes the dispatcher action asynchronously. To ignore + * This method always invokes the device dispatcher action asynchronously. To ignore * the result, pass %NULL to @callback. * * Returns: %TRUE if the action was dispatched, %FALSE on failure */ gboolean -nm_dispatcher_call (DispatcherAction action, - NMSettingsConnection *settings_connection, - NMConnection *applied_connection, - NMDevice *device, - DispatcherFunc callback, - gpointer user_data, - guint *out_call_id) +nm_dispatcher_call_device (NMDispatcherAction action, + NMDevice *device, + NMActRequest *act_request, + NMDispatcherFunc callback, + gpointer user_data, + guint *out_call_id) { - return _dispatcher_call (action, FALSE, settings_connection, applied_connection, device, - NM_CONNECTIVITY_UNKNOWN, NULL, NULL, NULL, NULL, + nm_assert (NM_IS_DEVICE (device)); + if (!act_request) { + act_request = nm_device_get_act_request (device); + if (!act_request) + return FALSE; + } + nm_assert (NM_IN_SET (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (act_request)), NULL, device)); + return _dispatcher_call (action, FALSE, + device, + nm_act_request_get_settings_connection (act_request), + nm_act_request_get_applied_connection (act_request), + nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (act_request)) == NM_ACTIVATION_TYPE_EXTERNAL, + NM_CONNECTIVITY_UNKNOWN, + NULL, NULL, NULL, NULL, callback, user_data, out_call_id); } /** - * nm_dispatcher_call_sync(): - * @action: the %DispatcherAction - * @settings_connection: the #NMSettingsConnection the action applies to - * @applied_connection: the currently applied connection + * nm_dispatcher_call_device_sync(): + * @action: the %NMDispatcherAction * @device: the #NMDevice the action applies to + * @act_request: the #NMActRequest for the action. If %NULL, use the + * current request of the device. * * This method always invokes the dispatcher action synchronously and it may * take a long time to return. @@ -736,18 +778,30 @@ nm_dispatcher_call (DispatcherAction action, * Returns: %TRUE if the action was dispatched, %FALSE on failure */ gboolean -nm_dispatcher_call_sync (DispatcherAction action, - NMSettingsConnection *settings_connection, - NMConnection *applied_connection, - NMDevice *device) +nm_dispatcher_call_device_sync (NMDispatcherAction action, + NMDevice *device, + NMActRequest *act_request) { - return _dispatcher_call (action, TRUE, settings_connection, applied_connection, device, - NM_CONNECTIVITY_UNKNOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + nm_assert (NM_IS_DEVICE (device)); + if (!act_request) { + act_request = nm_device_get_act_request (device); + if (!act_request) + return FALSE; + } + nm_assert (NM_IN_SET (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (act_request)), NULL, device)); + return _dispatcher_call (action, TRUE, + device, + nm_act_request_get_settings_connection (act_request), + nm_act_request_get_applied_connection (act_request), + nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (act_request)) == NM_ACTIVATION_TYPE_EXTERNAL, + NM_CONNECTIVITY_UNKNOWN, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL); } /** * nm_dispatcher_call_vpn(): - * @action: the %DispatcherAction + * @action: the %NMDispatcherAction * @settings_connection: the #NMSettingsConnection the action applies to * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection @@ -766,7 +820,7 @@ nm_dispatcher_call_sync (DispatcherAction action, * Returns: %TRUE if the action was dispatched, %FALSE on failure */ gboolean -nm_dispatcher_call_vpn (DispatcherAction action, +nm_dispatcher_call_vpn (NMDispatcherAction action, NMSettingsConnection *settings_connection, NMConnection *applied_connection, NMDevice *parent_device, @@ -774,18 +828,23 @@ nm_dispatcher_call_vpn (DispatcherAction action, NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config, - DispatcherFunc callback, + NMDispatcherFunc callback, gpointer user_data, guint *out_call_id) { - return _dispatcher_call (action, FALSE, settings_connection, applied_connection, - parent_device, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_proxy_config, - vpn_ip4_config, vpn_ip6_config, callback, user_data, out_call_id); + return _dispatcher_call (action, FALSE, + parent_device, + settings_connection, + applied_connection, + FALSE, + NM_CONNECTIVITY_UNKNOWN, + vpn_iface, vpn_proxy_config, vpn_ip4_config, vpn_ip6_config, + callback, user_data, out_call_id); } /** * nm_dispatcher_call_vpn_sync(): - * @action: the %DispatcherAction + * @action: the %NMDispatcherAction * @settings_connection: the #NMSettingsConnection the action applies to * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection @@ -800,7 +859,7 @@ nm_dispatcher_call_vpn (DispatcherAction action, * Returns: %TRUE if the action was dispatched, %FALSE on failure */ gboolean -nm_dispatcher_call_vpn_sync (DispatcherAction action, +nm_dispatcher_call_vpn_sync (NMDispatcherAction action, NMSettingsConnection *settings_connection, NMConnection *applied_connection, NMDevice *parent_device, @@ -809,26 +868,39 @@ nm_dispatcher_call_vpn_sync (DispatcherAction action, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config) { - return _dispatcher_call (action, TRUE, settings_connection, applied_connection, - parent_device, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_proxy_config, - vpn_ip4_config, vpn_ip6_config, NULL, NULL, NULL); + return _dispatcher_call (action, TRUE, + parent_device, + settings_connection, + applied_connection, + FALSE, + NM_CONNECTIVITY_UNKNOWN, + vpn_iface, vpn_proxy_config, vpn_ip4_config, vpn_ip6_config, + NULL, NULL, NULL); } /** * nm_dispatcher_call_connectivity(): - * @action: the %DispatcherAction * @connectivity_state: the #NMConnectivityState value + * @callback: a caller-supplied callback to execute when done + * @user_data: caller-supplied pointer passed to @callback + * @out_call_id: on success, a call identifier which can be passed to + * nm_dispatcher_call_cancel() * * This method does not block the caller. * * Returns: %TRUE if the action was dispatched, %FALSE on failure */ gboolean -nm_dispatcher_call_connectivity (DispatcherAction action, - NMConnectivityState connectivity_state) +nm_dispatcher_call_connectivity (NMConnectivityState connectivity_state, + NMDispatcherFunc callback, + gpointer user_data, + guint *out_call_id) { - return _dispatcher_call (action, FALSE, NULL, NULL, NULL, connectivity_state, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); + return _dispatcher_call (NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, FALSE, + NULL, NULL, NULL, FALSE, + connectivity_state, + NULL, NULL, NULL, NULL, + callback, user_data, out_call_id); } void diff --git a/src/nm-dispatcher.h b/src/nm-dispatcher.h index 7ea1a6b8..4448e817 100644 --- a/src/nm-dispatcher.h +++ b/src/nm-dispatcher.h @@ -19,44 +19,44 @@ * Copyright (C) 2005 - 2008 Novell, Inc. */ -#ifndef __NETWORKMANAGER_DISPATCHER_H__ -#define __NETWORKMANAGER_DISPATCHER_H__ - -#include <stdio.h> +#ifndef __NM_DISPATCHER_H__ +#define __NM_DISPATCHER_H__ #include "nm-connection.h" typedef enum { - DISPATCHER_ACTION_HOSTNAME, - DISPATCHER_ACTION_PRE_UP, - DISPATCHER_ACTION_UP, - DISPATCHER_ACTION_PRE_DOWN, - DISPATCHER_ACTION_DOWN, - DISPATCHER_ACTION_VPN_PRE_UP, - DISPATCHER_ACTION_VPN_UP, - DISPATCHER_ACTION_VPN_PRE_DOWN, - DISPATCHER_ACTION_VPN_DOWN, - DISPATCHER_ACTION_DHCP4_CHANGE, - DISPATCHER_ACTION_DHCP6_CHANGE, - DISPATCHER_ACTION_CONNECTIVITY_CHANGE -} DispatcherAction; + NM_DISPATCHER_ACTION_HOSTNAME, + NM_DISPATCHER_ACTION_PRE_UP, + NM_DISPATCHER_ACTION_UP, + NM_DISPATCHER_ACTION_PRE_DOWN, + NM_DISPATCHER_ACTION_DOWN, + NM_DISPATCHER_ACTION_VPN_PRE_UP, + NM_DISPATCHER_ACTION_VPN_UP, + NM_DISPATCHER_ACTION_VPN_PRE_DOWN, + NM_DISPATCHER_ACTION_VPN_DOWN, + NM_DISPATCHER_ACTION_DHCP4_CHANGE, + NM_DISPATCHER_ACTION_DHCP6_CHANGE, + NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE +} NMDispatcherAction; + +typedef void (*NMDispatcherFunc) (guint call_id, gpointer user_data); -typedef void (*DispatcherFunc) (guint call_id, gpointer user_data); +gboolean nm_dispatcher_call_hostname (NMDispatcherFunc callback, + gpointer user_data, + guint *out_call_id); -gboolean nm_dispatcher_call (DispatcherAction action, - NMSettingsConnection *settings_connection, - NMConnection *applied_connection, - NMDevice *device, - DispatcherFunc callback, - gpointer user_data, - guint *out_call_id); +gboolean nm_dispatcher_call_device (NMDispatcherAction action, + NMDevice *device, + NMActRequest *act_request, + NMDispatcherFunc callback, + gpointer user_data, + guint *out_call_id); -gboolean nm_dispatcher_call_sync (DispatcherAction action, - NMSettingsConnection *settings_connection, - NMConnection *applied_connection, - NMDevice *device); +gboolean nm_dispatcher_call_device_sync (NMDispatcherAction action, + NMDevice *device, + NMActRequest *act_request); -gboolean nm_dispatcher_call_vpn (DispatcherAction action, +gboolean nm_dispatcher_call_vpn (NMDispatcherAction action, NMSettingsConnection *settings_connection, NMConnection *applied_connection, NMDevice *parent_device, @@ -64,11 +64,11 @@ gboolean nm_dispatcher_call_vpn (DispatcherAction action, NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config, - DispatcherFunc callback, + NMDispatcherFunc callback, gpointer user_data, guint *out_call_id); -gboolean nm_dispatcher_call_vpn_sync (DispatcherAction action, +gboolean nm_dispatcher_call_vpn_sync (NMDispatcherAction action, NMSettingsConnection *settings_connection, NMConnection *applied_connection, NMDevice *parent_device, @@ -77,11 +77,14 @@ gboolean nm_dispatcher_call_vpn_sync (DispatcherAction action, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config); -gboolean nm_dispatcher_call_connectivity (DispatcherAction action, - NMConnectivityState state); +gboolean nm_dispatcher_call_connectivity (NMConnectivityState state, + NMDispatcherFunc callback, + gpointer user_data, + guint *out_call_id); + void nm_dispatcher_call_cancel (guint call_id); void nm_dispatcher_init (void); -#endif /* __NETWORKMANAGER_DISPATCHER_H__ */ +#endif /* __NM_DISPATCHER_H__ */ diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c index cd0789ee..0e903b89 100644 --- a/src/nm-exported-object.c +++ b/src/nm-exported-object.c @@ -77,8 +77,7 @@ typedef struct { GArray *methods; } NMExportedObjectClassInfo; -GQuark nm_exported_object_class_info_quark (void); -G_DEFINE_QUARK (NMExportedObjectClassInfo, nm_exported_object_class_info) +static NM_CACHED_QUARK_FCN ("NMExportedObjectClassInfo", nm_exported_object_class_info_quark) /*****************************************************************************/ @@ -388,8 +387,7 @@ nm_exported_object_meta_marshal (GClosure *closure, GValue *return_value, g_free (local_param_values); } -GQuark _skeleton_data_quark (void); -G_DEFINE_QUARK (skeleton-data, _skeleton_data); +static NM_CACHED_QUARK_FCN ("skeleton-data", _skeleton_data_quark) typedef struct { GBinding **prop_bindings; @@ -595,7 +593,7 @@ _create_export_path (NMExportedObjectClass *klass) } NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral") - return g_strdup_printf (class_export_path, (long long unsigned) (++(*counter))); + return g_strdup_printf (class_export_path, (unsigned long long) (++(*counter))); NM_PRAGMA_WARNING_REENABLE } diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index 5ba3d23e..4a887b79 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -28,22 +28,19 @@ /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE (NMFirewallManager, - PROP_AVAILABLE, -); - enum { - STARTED, + STATE_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - GDBusProxy * proxy; - gboolean running; + GDBusProxy *proxy; + GCancellable *proxy_cancellable; GHashTable *pending_calls; + bool running; } NMFirewallManagerPrivate; struct _NMFirewallManager { @@ -73,6 +70,7 @@ typedef enum { typedef enum { CB_INFO_MODE_IDLE = 1, + CB_INFO_MODE_DBUS_WAITING, CB_INFO_MODE_DBUS, CB_INFO_MODE_DBUS_COMPLETED, } CBInfoMode; @@ -80,7 +78,10 @@ typedef enum { struct _NMFirewallManagerCallId { NMFirewallManager *self; CBInfoOpsType ops_type; - CBInfoMode mode; + union { + const CBInfoMode mode; + CBInfoMode mode_mutable; + }; char *iface; NMFirewallManagerAddRemoveCallback callback; gpointer user_data; @@ -88,6 +89,7 @@ struct _NMFirewallManagerCallId { union { struct { GCancellable *cancellable; + GVariant *arg; } dbus; struct { guint id; @@ -118,7 +120,7 @@ _ops_type_to_string (CBInfoOpsType ops_type) char __prefix_name[30]; \ char __prefix_info[64]; \ \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ "%s: %s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ (self) != singleton_instance \ ? ({ \ @@ -129,7 +131,7 @@ _ops_type_to_string (CBInfoOpsType ops_type) __info \ ? ({ \ g_snprintf (__prefix_info, sizeof (__prefix_info), "[%p,%s%s:%s%s%s]: ", __info, \ - _ops_type_to_string (__info->ops_type), _cb_info_is_idle (__info) ? "*" : "", \ + _ops_type_to_string (__info->ops_type), __info->mode == CB_INFO_MODE_IDLE ? "*" : "", \ NM_PRINT_FMT_QUOTE_STRING (__info->iface)); \ __prefix_info; \ }) \ @@ -140,16 +142,21 @@ _ops_type_to_string (CBInfoOpsType ops_type) /*****************************************************************************/ -static gboolean -_cb_info_is_idle (CBInfo *info) +gboolean +nm_firewall_manager_get_running (NMFirewallManager *self) { - return info->mode == CB_INFO_MODE_IDLE; + g_return_val_if_fail (NM_IS_FIREWALL_MANAGER (self), FALSE); + + return NM_FIREWALL_MANAGER_GET_PRIVATE (self)->running; } +/*****************************************************************************/ + static CBInfo * _cb_info_create (NMFirewallManager *self, CBInfoOpsType ops_type, const char *iface, + const char *zone, NMFirewallManagerAddRemoveCallback callback, gpointer user_data) { @@ -163,14 +170,14 @@ _cb_info_create (NMFirewallManager *self, info->callback = callback; info->user_data = user_data; - if (priv->running) { - info->mode = CB_INFO_MODE_DBUS; - info->dbus.cancellable = g_cancellable_new (); + if (priv->running || priv->proxy_cancellable) { + info->mode_mutable = CB_INFO_MODE_DBUS_WAITING; + info->dbus.arg = g_variant_new ("(ss)", zone ? zone : "", iface); } else - info->mode = CB_INFO_MODE_IDLE; + info->mode_mutable = CB_INFO_MODE_IDLE; if (!nm_g_hash_table_add (priv->pending_calls, info)) - g_return_val_if_reached (NULL); + nm_assert_not_reached (); return info; } @@ -178,8 +185,11 @@ _cb_info_create (NMFirewallManager *self, static void _cb_info_free (CBInfo *info) { - if (!_cb_info_is_idle (info)) - g_object_unref (info->dbus.cancellable); + if (info->mode != CB_INFO_MODE_IDLE) { + if (info->dbus.arg) + g_variant_unref (info->dbus.arg); + g_clear_object (&info->dbus.cancellable); + } g_free (info->iface); if (info->self) g_object_unref (info->self); @@ -253,14 +263,16 @@ _handle_dbus (GObject *proxy, GAsyncResult *result, gpointer user_data) non_error = "UNKNOWN_INTERFACE"; break; } - if (!g_strcmp0 (error->message, non_error)) { + if ( error->message + && non_error + && g_str_has_prefix (error->message, non_error) + && NM_IN_SET (error->message[strlen (non_error)], '\0', ':')) { _LOGD (info, "complete: request failed with a non-error (%s)", error->message); /* The operation failed with an error reason that we don't want * to propagate. Instead, signal success. */ g_clear_error (&error); - } - else + } else _LOGW (info, "complete: request failed (%s)", error->message); } else _LOGD (info, "complete: success"); @@ -268,6 +280,48 @@ _handle_dbus (GObject *proxy, GAsyncResult *result, gpointer user_data) _cb_info_complete_normal (info, error); } +static void +_handle_dbus_start (NMFirewallManager *self, + CBInfo *info) +{ + NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); + const char *dbus_method = NULL; + GVariant *arg; + + nm_assert (info); + nm_assert (priv->running); + nm_assert (info->mode == CB_INFO_MODE_DBUS_WAITING); + + switch (info->ops_type) { + case CB_INFO_OPS_ADD: + dbus_method = "addInterface"; + break; + case CB_INFO_OPS_CHANGE: + dbus_method = "changeZone"; + break; + case CB_INFO_OPS_REMOVE: + dbus_method = "removeInterface"; + break; + } + nm_assert (dbus_method); + + arg = info->dbus.arg; + info->dbus.arg = NULL; + + nm_assert (arg && g_variant_is_floating (arg)); + + info->mode_mutable = CB_INFO_MODE_DBUS; + info->dbus.cancellable = g_cancellable_new (); + + g_dbus_proxy_call (priv->proxy, + dbus_method, + arg, + G_DBUS_CALL_FLAGS_NONE, 10000, + info->dbus.cancellable, + _handle_dbus, + info); +} + static NMFirewallManagerCallId _start_request (NMFirewallManager *self, CBInfoOpsType ops_type, @@ -278,45 +332,27 @@ _start_request (NMFirewallManager *self, { NMFirewallManagerPrivate *priv; CBInfo *info; - const char *dbus_method; g_return_val_if_fail (NM_IS_FIREWALL_MANAGER (self), NULL); g_return_val_if_fail (iface && *iface, NULL); priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - info = _cb_info_create (self, ops_type, iface, callback, user_data); + info = _cb_info_create (self, ops_type, iface, zone, callback, user_data); _LOGD (info, "firewall zone %s %s:%s%s%s%s", _ops_type_to_string (info->ops_type), iface, NM_PRINT_FMT_QUOTED (zone, "\"", zone, "\"", "default"), - _cb_info_is_idle (info) ? " (not running, simulate success)" : ""); - - if (!_cb_info_is_idle (info)) { - - switch (ops_type) { - case CB_INFO_OPS_ADD: - dbus_method = "addInterface"; - break; - case CB_INFO_OPS_CHANGE: - dbus_method = "changeZone"; - break; - case CB_INFO_OPS_REMOVE: - dbus_method = "removeInterface"; - break; - default: - g_assert_not_reached (); - } - - g_dbus_proxy_call (priv->proxy, - dbus_method, - g_variant_new ("(ss)", zone ? zone : "", iface), - G_DBUS_CALL_FLAGS_NONE, 10000, - info->dbus.cancellable, - _handle_dbus, - info); - + info->mode == CB_INFO_MODE_IDLE + ? " (not running, simulate success)" + : (!priv->running + ? " (waiting to initialize)" + : "")); + + if (info->mode == CB_INFO_MODE_DBUS_WAITING) { + if (priv->running) + _handle_dbus_start (self, info); if (!info->callback) { /* if the user did not provide a callback, the call_id is useless. * Especially, the user cannot use the call-id to cancel the request, @@ -326,15 +362,18 @@ _start_request (NMFirewallManager *self, * (the request will always be started). */ return NULL; } - } else if (!info->callback) { - /* if the user did not provide a callback and firewalld is not running, - * there is no point in scheduling an idle-request to fake success. Just - * return right away. */ - _LOGD (info, "complete: drop request simulating success"); - _cb_info_complete_normal (info, NULL); - return NULL; + } else if (info->mode == CB_INFO_MODE_IDLE) { + if (!info->callback) { + /* if the user did not provide a callback and firewalld is not running, + * there is no point in scheduling an idle-request to fake success. Just + * return right away. */ + _LOGD (info, "complete: drop request simulating success"); + _cb_info_complete_normal (info, NULL); + return NULL; + } else + info->idle.id = g_idle_add (_handle_idle, info); } else - info->idle.id = g_idle_add (_handle_idle, info); + nm_assert_not_reached (); return info; } @@ -393,11 +432,13 @@ nm_firewall_manager_cancel_call (NMFirewallManagerCallId call) _cb_info_callback (info, error); - if (_cb_info_is_idle (info)) { + if (info->mode == CB_INFO_MODE_DBUS_WAITING) + _cb_info_free (info); + else if (info->mode == CB_INFO_MODE_IDLE) { g_source_remove (info->idle.id); _cb_info_free (info); } else { - info->mode = CB_INFO_MODE_DBUS_COMPLETED; + info->mode_mutable = CB_INFO_MODE_DBUS_COMPLETED; g_cancellable_cancel (info->dbus.cancellable); g_clear_object (&info->self); } @@ -405,49 +446,92 @@ nm_firewall_manager_cancel_call (NMFirewallManagerCallId call) /*****************************************************************************/ -static void -set_running (NMFirewallManager *self, gboolean now_running) +static gboolean +name_owner_changed (NMFirewallManager *self) { NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - gboolean old_running = priv->running; + gs_free char *owner = NULL; + gboolean now_running; + + owner = g_dbus_proxy_get_name_owner (priv->proxy); + now_running = !!owner; + + if (now_running == priv->running) + return FALSE; priv->running = now_running; - if (old_running != priv->running) - _notify (self, PROP_AVAILABLE); + _LOGD (NULL, "firewall %s", now_running ? "started" : "stopped"); + return TRUE; } static void -name_owner_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) +name_owner_changed_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) { - NMFirewallManager *self = NM_FIREWALL_MANAGER (user_data); - gs_free char *owner = NULL; + NMFirewallManager *self = user_data; - owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); - if (owner) { - _LOGD (NULL, "firewall started"); - set_running (self, TRUE); - g_signal_emit (self, signals[STARTED], 0); - } else { - _LOGD (NULL, "firewall stopped"); - set_running (self, FALSE); - } -} + nm_assert (NM_IS_FIREWALL_MANAGER (self)); + nm_assert (G_IS_DBUS_PROXY (object)); + nm_assert (NM_FIREWALL_MANAGER_GET_PRIVATE (self)->proxy == G_DBUS_PROXY (object)); -/*****************************************************************************/ + if (name_owner_changed (self)) + g_signal_emit (self, signals[STATE_CHANGED], 0, FALSE); +} static void -get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +_proxy_new_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - switch (prop_id) { - case PROP_AVAILABLE: - g_value_set_boolean (value, NM_FIREWALL_MANAGER_GET_PRIVATE ((NMFirewallManager *) object)->running); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + NMFirewallManager *self; + NMFirewallManagerPrivate *priv; + GDBusProxy *proxy; + gs_free_error GError *error = NULL; + GHashTableIter iter; + CBInfo *info; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); + g_clear_object (&priv->proxy_cancellable); + + if (!proxy) { + _LOGW (NULL, "could not connect to system D-Bus (%s)", error->message); + return; + } + + priv->proxy = proxy; + g_signal_connect (priv->proxy, "notify::g-name-owner", + G_CALLBACK (name_owner_changed_cb), self); + + if (!name_owner_changed (self)) + _LOGD (NULL, "firewall %s", "initialized (not running)"); + +again: + g_hash_table_iter_init (&iter, priv->pending_calls); + while (g_hash_table_iter_next (&iter, (gpointer *) &info, NULL)) { + if (info->mode != CB_INFO_MODE_DBUS_WAITING) + continue; + if (priv->running) { + _LOGD (info, "make D-Bus call"); + _handle_dbus_start (self, info); + } else { + _LOGD (info, "complete: fake success"); + g_hash_table_iter_remove (&iter); + _cb_info_callback (info, NULL); + _cb_info_free (info); + goto again; + } } + + /* we always emit a state-changed signal, even if the + * "running" property is still false. */ + g_signal_emit (self, signals[STATE_CHANGED], 0, TRUE); } /*****************************************************************************/ @@ -465,28 +549,21 @@ constructed (GObject *object) { NMFirewallManager *self = (NMFirewallManager *) object; NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - gs_free char *owner = NULL; - gs_free_error GError *error = NULL; - G_OBJECT_CLASS (nm_firewall_manager_parent_class)->constructed (object); + priv->proxy_cancellable = g_cancellable_new (); - priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - FIREWALL_DBUS_SERVICE, - FIREWALL_DBUS_PATH, - FIREWALL_DBUS_INTERFACE_ZONE, - NULL, &error); - if (priv->proxy) { - g_signal_connect (priv->proxy, "notify::g-name-owner", - G_CALLBACK (name_owner_changed), self); - owner = g_dbus_proxy_get_name_owner (priv->proxy); - priv->running = (owner != NULL); - } else - _LOGW (NULL, "could not connect to system D-Bus (%s)", error->message); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + FIREWALL_DBUS_SERVICE, + FIREWALL_DBUS_PATH, + FIREWALL_DBUS_INTERFACE_ZONE, + priv->proxy_cancellable, + _proxy_new_cb, + self); - _LOGD (NULL, "firewall constructed (%srunning)", priv->running ? "" : "not"); + G_OBJECT_CLASS (nm_firewall_manager_parent_class)->constructed (object); } static void @@ -503,6 +580,7 @@ dispose (GObject *object) priv->pending_calls = NULL; } + nm_clear_g_cancellable (&priv->proxy_cancellable); g_clear_object (&priv->proxy); G_OBJECT_CLASS (nm_firewall_manager_parent_class)->dispose (object); @@ -514,23 +592,15 @@ nm_firewall_manager_class_init (NMFirewallManagerClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = constructed; - object_class->get_property = get_property; object_class->dispose = dispose; - obj_properties[PROP_AVAILABLE] = - g_param_spec_boolean (NM_FIREWALL_MANAGER_AVAILABLE, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[STARTED] = - g_signal_new (NM_FIREWALL_MANAGER_STARTED, + signals[STATE_CHANGED] = + g_signal_new (NM_FIREWALL_MANAGER_STATE_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, + G_TYPE_BOOLEAN /* initialized_now */); } diff --git a/src/nm-firewall-manager.h b/src/nm-firewall-manager.h index a00ee451..8bbf82a7 100644 --- a/src/nm-firewall-manager.h +++ b/src/nm-firewall-manager.h @@ -33,9 +33,7 @@ #define NM_IS_FIREWALL_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FIREWALL_MANAGER)) #define NM_FIREWALL_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FIREWALL_MANAGER, NMFirewallManagerClass)) -#define NM_FIREWALL_MANAGER_AVAILABLE "available" - -#define NM_FIREWALL_MANAGER_STARTED "started" +#define NM_FIREWALL_MANAGER_STATE_CHANGED "state-changed" typedef struct _NMFirewallManagerCallId *NMFirewallManagerCallId; @@ -46,6 +44,8 @@ GType nm_firewall_manager_get_type (void); NMFirewallManager *nm_firewall_manager_get (void); +gboolean nm_firewall_manager_get_running (NMFirewallManager *self); + typedef void (*NMFirewallManagerAddRemoveCallback) (NMFirewallManager *self, NMFirewallManagerCallId call_id, GError *error, diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 4405c325..f8df2b9a 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -42,6 +42,7 @@ #include "nm-utils.h" #include "nm-setting-ip6-config.h" #include "systemd/nm-sd.h" +#include "nm-route-manager.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -91,12 +92,18 @@ static struct { #define _NMLOG_PREFIX_NAME "nm-iface-helper" #define _NMLOG(level, domain, ...) \ - nm_log ((level), (domain), \ + nm_log ((level), (domain), global_opt.ifname, NULL, \ "iface-helper: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) \ _NM_UTILS_MACRO_REST (__VA_ARGS__)) /*****************************************************************************/ +NMRouteManager *route_manager_get (void); + +NM_DEFINE_SINGLETON_GETTER (NMRouteManager, route_manager_get, NM_TYPE_ROUTE_MANAGER); + +/*****************************************************************************/ + static void dhcp4_state_changed (NMDhcpClient *client, NMDhcpState state, @@ -115,12 +122,12 @@ dhcp4_state_changed (NMDhcpClient *client, switch (state) { case NM_DHCP_STATE_BOUND: g_assert (ip4_config); - existing = nm_ip4_config_capture (gl.ifindex, FALSE); + existing = nm_ip4_config_capture (NM_PLATFORM_GET, gl.ifindex, FALSE); if (last_config) nm_ip4_config_subtract (existing, last_config); nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); - if (!nm_ip4_config_commit (existing, gl.ifindex, TRUE, global_opt.priority_v4)) + if (!nm_ip4_config_commit (existing, NM_PLATFORM_GET, route_manager_get (), gl.ifindex, TRUE, global_opt.priority_v4)) _LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config"); if (last_config) @@ -170,7 +177,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in ifa_flags |= IFA_F_MANAGETEMPADDR; } - existing = nm_ip6_config_capture (gl.ifindex, FALSE, global_opt.tempaddr); + existing = nm_ip6_config_capture (NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr); if (ndisc_config) nm_ip6_config_subtract (existing, ndisc_config); else @@ -245,7 +252,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in } nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT); - if (!nm_ip6_config_commit (existing, gl.ifindex, TRUE)) + if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, route_manager_get (), gl.ifindex, TRUE)) _LOGW (LOGD_IP6, "failed to apply IPv6 config"); } @@ -432,9 +439,8 @@ main (int argc, char *argv[]) gl.main_loop = g_main_loop_new (NULL, FALSE); setup_signals (); - nm_logging_syslog_openlog (global_opt.logging_backend - ? global_opt.logging_backend - : (global_opt.debug ? "debug" : NULL)); + nm_logging_syslog_openlog (global_opt.logging_backend, + global_opt.debug); _LOGI (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting..."); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 1486edcc..20532e86 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -249,7 +249,7 @@ notify_addresses (NMIP4Config *self) } NMIP4Config * -nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) +nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf) { NMIP4Config *config; NMIP4ConfigPrivate *priv; @@ -259,7 +259,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) gboolean old_has_gateway = FALSE; /* Slaves have no IP configuration */ - if (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex) > 0) + if (nm_platform_link_get_master (platform, ifindex) > 0) return NULL; config = nm_ip4_config_new (ifindex); @@ -268,8 +268,8 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) g_array_unref (priv->addresses); g_array_unref (priv->routes); - priv->addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); - priv->routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex); + priv->routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); /* Extract gateway from default route */ old_gateway = priv->gateway; @@ -331,7 +331,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) } gboolean -nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_full_sync, gint64 default_route_metric) +nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric) { const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); gs_unref_ptrarray GPtrArray *added_addresses = NULL; @@ -340,7 +340,7 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu g_return_val_if_fail (config != NULL, FALSE); /* Addresses */ - nm_platform_ip4_address_sync (NM_PLATFORM_GET, ifindex, priv->addresses, + nm_platform_ip4_address_sync (platform, ifindex, priv->addresses, default_route_metric >= 0 ? &added_addresses : NULL); /* Routes */ @@ -401,9 +401,9 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu g_array_append_vals (routes, route, 1); } - nm_route_manager_ip4_route_register_device_route_purge_list (nm_route_manager_get (), device_route_purge_list); + nm_route_manager_ip4_route_register_device_route_purge_list (route_manager, device_route_purge_list); - success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, default_route_metric < 0, routes_full_sync); + success = nm_route_manager_ip4_route_sync (route_manager, ifindex, routes, default_route_metric < 0, routes_full_sync); g_array_unref (routes); if (!success) return FALSE; @@ -412,6 +412,38 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu return TRUE; } +static void +merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r) +{ + GVariant *variant; + in_addr_t addr; + +#define GET_ATTR(name, field, variant_type, type) \ + variant = nm_ip_route_get_attribute (s_route, name); \ + if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ + r->field = g_variant_get_ ## type (variant); + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + if (inet_pton (AF_INET, g_variant_get_string (variant, NULL), &addr) == 1) + r->pref_src = addr; + } + +#undef GET_ATTR +} + void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) { @@ -492,6 +524,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu route.metric = nm_ip_route_get_metric (s_route); route.rt_source = NM_IP_CONFIG_SOURCE_USER; + merge_route_attributes (s_route, &route); nm_ip4_config_add_route (config, &route); } @@ -1822,7 +1855,7 @@ nm_ip4_config_add_search (NMIP4Config *config, const char *new) return; } - if (_nm_utils_strv_find_first ((char **) priv->searches->pdata, + if (nm_utils_strv_find_first ((char **) priv->searches->pdata, priv->searches->len, search) >= 0) { g_free (search); return; diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 58ee4a7d..ceb52ac5 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -59,8 +59,8 @@ NMIP4Config * nm_ip4_config_new (int ifindex); int nm_ip4_config_get_ifindex (const NMIP4Config *config); -NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf); -gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_full_sync, gint64 default_route_metric); +NMIP4Config *nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf); +gboolean nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric); void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index c90d04aa..af88b21c 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -301,7 +301,7 @@ nm_ip6_config_addresses_sort (NMIP6Config *self) } NMIP6Config * -nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary) +nm_ip6_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary) { NMIP6Config *config; NMIP6ConfigPrivate *priv; @@ -312,7 +312,7 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co gboolean notify_nameservers = FALSE; /* Slaves have no IP configuration */ - if (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex) > 0) + if (nm_platform_link_get_master (platform, ifindex) > 0) return NULL; config = nm_ip6_config_new (ifindex); @@ -321,8 +321,8 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co g_array_unref (priv->addresses); g_array_unref (priv->routes); - priv->addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); - priv->routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + priv->addresses = nm_platform_ip6_address_get_all (platform, ifindex); + priv->routes = nm_platform_ip6_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); /* Extract gateway from default route */ old_gateway = priv->gateway; @@ -386,7 +386,11 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co } gboolean -nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_full_sync) +nm_ip6_config_commit (const NMIP6Config *config, + NMPlatform *platform, + NMRouteManager *route_manager, + int ifindex, + gboolean routes_full_sync) { const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); gboolean success; @@ -395,7 +399,7 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_fu g_return_val_if_fail (config != NULL, FALSE); /* Addresses */ - nm_platform_ip6_address_sync (NM_PLATFORM_GET, ifindex, priv->addresses, TRUE); + nm_platform_ip6_address_sync (platform, ifindex, priv->addresses, TRUE); /* Routes */ { @@ -409,13 +413,64 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_fu g_array_append_vals (routes, route, 1); } - success = nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, routes_full_sync); + success = nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync); g_array_unref (routes); } return success; } +static void +merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r) +{ + GVariant *variant; + struct in6_addr addr; + +#define GET_ATTR(name, field, variant_type, type) \ + variant = nm_ip_route_get_attribute (s_route, name); \ + if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ + r->field = g_variant_get_ ## type (variant); + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); + + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + if (inet_pton (AF_INET6, g_variant_get_string (variant, NULL), &addr) == 1) + r->pref_src = addr; + } + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + gs_free char *string = NULL; + guint8 plen = 128; + char *sep; + + string = g_variant_dup_string (variant, NULL); + sep = strchr (string, '/'); + if (sep) { + *sep = 0; + plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); + } + if ( plen <= 128 + && inet_pton (AF_INET6, string, &addr) == 1) { + r->src = addr; + r->src_plen = plen; + } + } +#undef GET_ATTR +} + void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) { @@ -492,6 +547,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu route.metric = nm_ip_route_get_metric (s_route); route.rt_source = NM_IP_CONFIG_SOURCE_USER; + merge_route_attributes (s_route, &route); nm_ip6_config_add_route (config, &route); } @@ -1742,7 +1798,7 @@ nm_ip6_config_add_search (NMIP6Config *config, const char *new) return; } - if (_nm_utils_strv_find_first ((char **) priv->searches->pdata, + if (nm_utils_strv_find_first ((char **) priv->searches->pdata, priv->searches->len, search) >= 0) { g_free (search); return; diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index c196421b..557041c9 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -61,8 +61,12 @@ NMIP6Config * nm_ip6_config_new_cloned (const NMIP6Config *src); int nm_ip6_config_get_ifindex (const NMIP6Config *config); -NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); -gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_full_sync); +NMIP6Config *nm_ip6_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); +gboolean nm_ip6_config_commit (const NMIP6Config *config, + NMPlatform *platform, + NMRouteManager *route_manager, + int ifindex, + gboolean routes_full_sync); void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric); NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config); diff --git a/src/nm-logging.c b/src/nm-logging.c index c242d903..f19f0de1 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -94,6 +94,7 @@ static struct Global { NMLogLevel log_level; bool uses_syslog:1; bool syslog_identifier_initialized:1; + bool debug_stderr:1; const char *prefix; const char *syslog_identifier; enum { @@ -593,6 +594,8 @@ _nm_log_impl (const char *file, NMLogLevel level, NMLogDomain domain, int error, + const char *ifname, + const char *conn_uuid, const char *fmt, ...) { @@ -630,6 +633,9 @@ _nm_log_impl (const char *file, g_get_current_time (&tv); + if (global.debug_stderr) + g_printerr (MESSAGE_FMT"\n", MESSAGE_ARG (global, tv, msg)); + switch (global.log_backend) { #if SYSTEMD_JOURNAL case LOG_BACKEND_JOURNAL: @@ -638,7 +644,7 @@ _nm_log_impl (const char *file, #define _NUM_MAX_FIELDS_SYSLOG_FACILITY 10 struct iovec iov_data[12 + _NUM_MAX_FIELDS_SYSLOG_FACILITY]; struct iovec *iov = iov_data; - gpointer iov_free_data[3]; + gpointer iov_free_data[5]; gpointer *iov_free = iov_free_data; nm_auto_free_gstring GString *s_domain_all = NULL; @@ -700,6 +706,10 @@ _nm_log_impl (const char *file, _iovec_set_format_a (iov++, 60, "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000)); if (error != 0) _iovec_set_format_a (iov++, 30, "ERRNO=%d", error); + if (ifname) + _iovec_set_format (iov++, iov_free++, "NM_DEVICE=%s", ifname); + if (conn_uuid) + _iovec_set_format (iov++, iov_free++, "NM_CONNECTION=%s", conn_uuid); nm_assert (iov <= &iov_data[G_N_ELEMENTS (iov_data)]); nm_assert (iov_free <= &iov_free_data[G_N_ELEMENTS (iov_free_data)]); @@ -817,7 +827,7 @@ nm_logging_set_prefix (const char *format, ...) } void -nm_logging_syslog_openlog (const char *logging_backend) +nm_logging_syslog_openlog (const char *logging_backend, gboolean debug) { if (global.log_backend != LOG_BACKEND_GLIB) g_return_if_reached (); @@ -825,21 +835,21 @@ nm_logging_syslog_openlog (const char *logging_backend) if (!logging_backend) logging_backend = ""NM_CONFIG_DEFAULT_LOGGING_BACKEND; - if (strcmp (logging_backend, "debug") == 0) { - global.log_backend = LOG_BACKEND_SYSLOG; - openlog (syslog_identifier_domain (&global), LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER); #if SYSTEMD_JOURNAL - } else if (strcmp (logging_backend, "syslog") != 0) { + if (strcmp (logging_backend, "syslog") != 0) { global.log_backend = LOG_BACKEND_JOURNAL; global.uses_syslog = TRUE; + global.debug_stderr = debug; /* ensure we read a monotonic timestamp. Reading the timestamp the first * time causes a logging message. We don't want to do that during _nm_log_impl. */ nm_utils_get_monotonic_timestamp_ns (); + } else #endif - } else { + { global.log_backend = LOG_BACKEND_SYSLOG; global.uses_syslog = TRUE; + global.debug_stderr = debug; openlog (syslog_identifier_domain (&global), LOG_PID, LOG_DAEMON); } diff --git a/src/nm-logging.h b/src/nm-logging.h index 2c1a1059..ff1fac79 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -22,6 +22,8 @@ #ifndef __NETWORKMANAGER_LOGGING_H__ #define __NETWORKMANAGER_LOGGING_H__ +#include "nm-core-types.h" + #ifdef __NM_TEST_UTILS_H__ #error nm-test-utils.h must be included as last header #endif @@ -97,11 +99,11 @@ typedef enum { /*< skip >*/ _LOGL_N, /* the number of logging levels including "OFF" */ } NMLogLevel; -#define nm_log_err(domain, ...) nm_log (LOGL_ERR, (domain), __VA_ARGS__) -#define nm_log_warn(domain, ...) nm_log (LOGL_WARN, (domain), __VA_ARGS__) -#define nm_log_info(domain, ...) nm_log (LOGL_INFO, (domain), __VA_ARGS__) -#define nm_log_dbg(domain, ...) nm_log (LOGL_DEBUG, (domain), __VA_ARGS__) -#define nm_log_trace(domain, ...) nm_log (LOGL_TRACE, (domain), __VA_ARGS__) +#define nm_log_err(domain, ...) nm_log (LOGL_ERR, (domain), NULL, NULL, __VA_ARGS__) +#define nm_log_warn(domain, ...) nm_log (LOGL_WARN, (domain), NULL, NULL, __VA_ARGS__) +#define nm_log_info(domain, ...) nm_log (LOGL_INFO, (domain), NULL, NULL, __VA_ARGS__) +#define nm_log_dbg(domain, ...) nm_log (LOGL_DEBUG, (domain), NULL, NULL, __VA_ARGS__) +#define nm_log_trace(domain, ...) nm_log (LOGL_TRACE, (domain), NULL, NULL, __VA_ARGS__) //#define _NM_LOG_FUNC G_STRFUNC #define _NM_LOG_FUNC NULL @@ -109,53 +111,84 @@ typedef enum { /*< skip >*/ /* A wrapper for the _nm_log_impl() function that adds call site information. * Contrary to nm_log(), it unconditionally calls the function without * checking whether logging for the given level and domain is enabled. */ -#define _nm_log(level, domain, error, ...) \ +#define _nm_log(level, domain, error, ifname, con_uuid, ...) \ G_STMT_START { \ _nm_log_impl (__FILE__, __LINE__, \ _NM_LOG_FUNC, \ (level), \ (domain), \ (error), \ + (ifname), \ + (con_uuid), \ ""__VA_ARGS__); \ } G_STMT_END /* nm_log() only evaluates it's argument list after checking * whether logging for the given level/domain is enabled. */ -#define nm_log(level, domain, ...) \ +#define nm_log(level, domain, ifname, con_uuid, ...) \ G_STMT_START { \ if (nm_logging_enabled ((level), (domain))) { \ - _nm_log (level, domain, 0, __VA_ARGS__); \ + _nm_log (level, domain, 0, ifname, con_uuid, __VA_ARGS__); \ } \ } G_STMT_END -#define _nm_log_ptr(level, domain, self, prefix, ...) \ - nm_log ((level), (domain), "%s[%p] " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), (prefix) ?: "", self _NM_UTILS_MACRO_REST(__VA_ARGS__)) +#define _nm_log_ptr(level, domain, ifname, con_uuid, self, prefix, ...) \ + nm_log ((level), \ + (domain), \ + (ifname), \ + (con_uuid), \ + "%s[%p] " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + (prefix) ?: "", \ + self _NM_UTILS_MACRO_REST(__VA_ARGS__)) /* log a message for an object (with providing a generic @self pointer) */ -#define nm_log_ptr(level, domain, self, prefix, ...) \ +#define nm_log_ptr(level, domain, ifname, con_uuid, self, prefix, ...) \ G_STMT_START { \ NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare") \ if ((level) <= LOGL_DEBUG) { \ - _nm_log_ptr ((level), (domain), (self), (prefix), __VA_ARGS__); \ + _nm_log_ptr ((level), \ + (domain), \ + (ifname), \ + (con_uuid), \ + (self), \ + (prefix), \ + __VA_ARGS__); \ } else { \ const char *__prefix = (prefix); \ \ - nm_log ((level), (domain), "%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), __prefix ?: "", __prefix ? " " : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + nm_log ((level), \ + (domain), \ + (ifname), \ + (con_uuid), \ + "%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix ?: "", \ + __prefix ? " " : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ NM_PRAGMA_WARNING_REENABLE \ } G_STMT_END -#define _nm_log_obj(level, domain, self, prefix, ...) \ - _nm_log_ptr ((level), (domain), (self), prefix, __VA_ARGS__) +#define _nm_log_obj(level, domain, ifname, con_uuid, self, prefix, ...) \ + _nm_log_ptr ((level), \ + (domain), \ + (ifname), \ + (con_uuid), \ + (self), \ + prefix, \ + __VA_ARGS__) /* log a message for an object (with providing a @self pointer to a GObject). * Contrary to nm_log_ptr(), @self must be a GObject type (or %NULL). * As of now, nm_log_obj() is identical to nm_log_ptr(), but we might change that */ -#define nm_log_obj(level, domain, self, prefix, ...) \ - nm_log_ptr ((level), (domain), (self), prefix, __VA_ARGS__) - +#define nm_log_obj(level, domain, ifname, con_uuid, self, prefix, ...) \ + nm_log_ptr ((level), \ + (domain), \ + (ifname), \ + (con_uuid), \ + (self), \ + prefix, \ + __VA_ARGS__) void _nm_log_impl (const char *file, guint line, @@ -163,8 +196,10 @@ void _nm_log_impl (const char *file, NMLogLevel level, NMLogDomain domain, int error, + const char *ifname, + const char *con_uuid, const char *fmt, - ...) _nm_printf (7, 8); + ...) _nm_printf (9, 10); const char *nm_logging_level_to_string (void); const char *nm_logging_domains_to_string (void); @@ -191,7 +226,7 @@ gboolean nm_logging_setup (const char *level, void nm_logging_set_syslog_identifier (const char *domain); void nm_logging_set_prefix (const char *format, ...) _nm_printf (1, 2); -void nm_logging_syslog_openlog (const char *logging_backend); +void nm_logging_syslog_openlog (const char *logging_backend, gboolean debug); gboolean nm_logging_syslog_enabled (void); /*****************************************************************************/ @@ -277,7 +312,7 @@ extern void (*_nm_logging_clear_platform_logging_cache) (void); #define __NMLOG_DEFAULT(level, domain, prefix, ...) \ G_STMT_START { \ - nm_log ((level), (domain), \ + nm_log ((level), (domain), NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ (prefix) \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ @@ -285,7 +320,7 @@ extern void (*_nm_logging_clear_platform_logging_cache) (void); #define __NMLOG_DEFAULT_WITH_ADDR(level, domain, prefix, ...) \ G_STMT_START { \ - nm_log ((level), (domain), \ + nm_log ((level), (domain), NULL, NULL, \ "%s[%p]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ (prefix), \ (self) \ diff --git a/src/nm-manager.c b/src/nm-manager.c index 7dfaa5ab..a7402195 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2009 Novell, Inc. - * Copyright (C) 2007 - 2012 Red Hat, Inc. + * Copyright (C) 2007 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -54,6 +54,7 @@ #include "nm-dbus-compat.h" #include "nm-checkpoint.h" #include "nm-checkpoint-manager.h" +#include "nm-dispatcher.h" #include "NetworkManagerUtils.h" #include "introspection/org.freedesktop.NetworkManager.h" @@ -67,6 +68,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error); static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); @@ -86,7 +88,11 @@ static void device_sleep_cb (NMDevice *device, GParamSpec *pspec, NMManager *self); -#define TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE "act-con-add-and-activate" +static void settings_startup_complete_changed (NMSettings *settings, + GParamSpec *pspec, + NMManager *self); + +static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark) typedef struct { gboolean user_enabled; @@ -112,7 +118,7 @@ typedef struct { GSList *devices; NMState state; NMConfig *config; - NMConnectivity *connectivity; + NMConnectivityState connectivity_state; NMPolicy *policy; @@ -129,9 +135,6 @@ typedef struct { char *hostname; RadioState radio_states[RFKILL_TYPE_MAX]; - gboolean sleeping; - gboolean net_enabled; - NMVpnManager *vpn_manager; NMSleepMonitor *sleep_monitor; @@ -147,8 +150,13 @@ typedef struct { guint timestamp_update_id; - gboolean startup; - gboolean devices_inited; + guint devices_inited_id; + + bool startup:1; + bool devices_inited:1; + + bool sleeping:1; + bool net_enabled:1; } NMManagerPrivate; struct _NMManager { @@ -221,7 +229,7 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager); const NMManager *const __self = (self); \ char __sbuf[32]; \ \ - _nm_log (__level, __domain, 0, \ + _nm_log (__level, __domain, 0, NULL, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (__self && __self != singleton_instance) \ @@ -233,8 +241,7 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager); /*****************************************************************************/ -GQuark autoconnect_root_quark (void); -G_DEFINE_QUARK (autoconnect-root, autoconnect_root); +static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) static void active_connection_state_changed (NMActiveConnection *active, GParamSpec *pspec, @@ -265,20 +272,20 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self); - if ( nm_active_connection_get_assumed (active) - && (connection = nm_active_connection_get_settings_connection (active)) - && nm_settings_connection_get_nm_generated_assumed (connection)) + if ( (connection = nm_active_connection_get_settings_connection (active)) + && nm_settings_connection_get_volatile (connection)) g_object_ref (connection); else connection = NULL; nm_exported_object_clear_and_unexport (&active); - if ( connection - && nm_settings_has_connection (priv->settings, connection)) { - _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", - nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (connection), NULL, NULL); + if (connection) { + if (nm_settings_has_connection (priv->settings, connection)) { + _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", + nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); + nm_settings_connection_delete (connection, NULL, NULL); + } g_object_unref (connection); } } @@ -390,63 +397,84 @@ nm_manager_get_active_connections (NMManager *manager) } static NMActiveConnection * -find_ac_for_connection (NMManager *manager, NMConnection *connection) +active_connection_find_first (NMManager *self, + NMSettingsConnection *settings_connection, + const char *uuid, + NMActiveConnectionState max_state) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMManagerPrivate *priv; GSList *iter; - const char *uuid = NULL; - gboolean is_settings_connection; - is_settings_connection = NM_IS_SETTINGS_CONNECTION (connection); + g_return_val_if_fail (NM_IS_MANAGER (self), NULL); + g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); - if (!is_settings_connection) - uuid = nm_connection_get_uuid (connection); + priv = NM_MANAGER_GET_PRIVATE (self); for (iter = priv->active_connections; iter; iter = iter->next) { NMActiveConnection *ac = iter->data; NMSettingsConnection *con; con = nm_active_connection_get_settings_connection (ac); - - /* depending on whether we have a NMSettingsConnection or a NMConnection, - * we lookup by UUID or by reference. */ - if (is_settings_connection) { - if (con != (NMSettingsConnection *) connection) - continue; - } else { - if (strcmp (uuid, nm_connection_get_uuid (NM_CONNECTION (con))) != 0) - continue; - } - if (nm_active_connection_get_state (ac) < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) - return ac; + if (settings_connection && con != settings_connection) + continue; + if (uuid && !nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (con)))) + continue; + if (nm_active_connection_get_state (ac) > max_state) + continue; + return ac; } return NULL; } +static NMActiveConnection * +active_connection_find_first_by_connection (NMManager *self, + NMConnection *connection) +{ + gboolean is_settings_connection; + + nm_assert (NM_IS_MANAGER (self)); + nm_assert (NM_IS_CONNECTION (connection)); + + is_settings_connection = NM_IS_SETTINGS_CONNECTION (connection); + /* Depending on whether connection is a settings connection, + * either lookup by object-identity of @connection, or compare the UUID */ + return active_connection_find_first (self, + is_settings_connection ? NM_SETTINGS_CONNECTION (connection) : NULL, + is_settings_connection ? NULL : nm_connection_get_uuid (connection), + NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); +} + +static gboolean +_get_activatable_connections_filter (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) +{ + if (nm_settings_connection_get_volatile (connection)) + return FALSE; + return !active_connection_find_first (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); +} + /* Filter out connections that are already active. * nm_settings_get_connections_sorted() returns sorted list. We need to preserve the * order so that we didn't change auto-activation order (recent timestamps * are first). * Caller is responsible for freeing the returned list with g_slist_free(). */ -GSList * -nm_manager_get_activatable_connections (NMManager *manager) +NMSettingsConnection ** +nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *all_connections = nm_settings_get_connections_sorted (priv->settings); - GSList *connections = NULL, *iter; - NMSettingsConnection *connection; - - for (iter = all_connections; iter; iter = iter->next) { - connection = iter->data; - - if (!find_ac_for_connection (manager, NM_CONNECTION (connection))) - connections = g_slist_prepend (connections, connection); - } + NMSettingsConnection **connections; + guint len; - g_slist_free (all_connections); - return g_slist_reverse (connections); + connections = nm_settings_get_connections_clone (priv->settings, &len, + _get_activatable_connections_filter, + manager); + if (sort && len > 1) + g_qsort_with_data (connections, len, sizeof (connections[0]), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); + NM_SET_OUT (out_len, len); + return connections; } static NMActiveConnection * @@ -472,12 +500,6 @@ active_connection_get_by_path (NMManager *manager, const char *path) static void _config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMManager *self) { - g_object_set (NM_MANAGER_GET_PRIVATE (self)->connectivity, - NM_CONNECTIVITY_URI, nm_config_data_get_connectivity_uri (config_data), - NM_CONNECTIVITY_INTERVAL, nm_config_data_get_connectivity_interval (config_data), - NM_CONNECTIVITY_RESPONSE, nm_config_data_get_connectivity_response (config_data), - NULL); - if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) _notify (self, PROP_GLOBAL_DNS_CONFIGURATION); } @@ -745,27 +767,8 @@ set_state (NMManager *self, NMState state) g_signal_emit (self, signals[STATE_CHANGED], 0, priv->state); } -static void -checked_connectivity (GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMManager *manager = user_data; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - NMConnectivityState connectivity; - - if (priv->state == NM_STATE_CONNECTING || priv->state == NM_STATE_CONNECTED_SITE) { - connectivity = nm_connectivity_check_finish (priv->connectivity, result, NULL); - - if (connectivity == NM_CONNECTIVITY_FULL) - set_state (manager, NM_STATE_CONNECTED_GLOBAL); - - _notify (manager, PROP_CONNECTIVITY); - } - - g_object_unref (manager); -} - static NMState -find_best_device_state (NMManager *manager, gboolean *force_connectivity_check) +find_best_device_state (NMManager *manager) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMState best_state = NM_STATE_DISCONNECTED; @@ -779,24 +782,27 @@ find_best_device_state (NMManager *manager, gboolean *force_connectivity_check) case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: if ( nm_active_connection_get_default (ac) || nm_active_connection_get_default6 (ac)) { - if (nm_connectivity_get_state (priv->connectivity) == NM_CONNECTIVITY_FULL) + if (priv->connectivity_state) return NM_STATE_CONNECTED_GLOBAL; best_state = NM_STATE_CONNECTED_SITE; - NM_SET_OUT (force_connectivity_check, TRUE); } else { if (best_state < NM_STATE_CONNECTING) best_state = NM_STATE_CONNECTED_LOCAL; } break; case NM_ACTIVE_CONNECTION_STATE_ACTIVATING: - if (!nm_active_connection_get_assumed (ac)) { + if (!NM_IN_SET (nm_active_connection_get_activation_type (ac), + NM_ACTIVATION_TYPE_EXTERNAL, + NM_ACTIVATION_TYPE_ASSUME)) { if (best_state != NM_STATE_CONNECTED_GLOBAL) best_state = NM_STATE_CONNECTING; } break; case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING: - if (!nm_active_connection_get_assumed (ac)) { + if (!NM_IN_SET (nm_active_connection_get_activation_type (ac), + NM_ACTIVATION_TYPE_EXTERNAL, + NM_ACTIVATION_TYPE_ASSUME)) { if (best_state < NM_STATE_DISCONNECTING) best_state = NM_STATE_DISCONNECTING; } @@ -837,7 +843,6 @@ nm_manager_update_state (NMManager *manager) { NMManagerPrivate *priv; NMState new_state = NM_STATE_DISCONNECTED; - gboolean force_connectivity_check = FALSE; g_return_if_fail (NM_IS_MANAGER (manager)); @@ -846,14 +851,11 @@ nm_manager_update_state (NMManager *manager) if (manager_sleeping (manager)) new_state = NM_STATE_ASLEEP; else - new_state = find_best_device_state (manager, &force_connectivity_check); - - nm_connectivity_set_online (priv->connectivity, new_state >= NM_STATE_CONNECTED_LOCAL); + new_state = find_best_device_state (manager); - if (new_state == NM_STATE_CONNECTED_SITE || force_connectivity_check) { - nm_connectivity_check_async (priv->connectivity, - checked_connectivity, - g_object_ref (manager)); + if ( new_state >= NM_STATE_CONNECTED_LOCAL + && priv->connectivity_state == NM_CONNECTIVITY_FULL) { + new_state = NM_STATE_CONNECTED_GLOBAL; } set_state (manager, new_state); @@ -920,15 +922,18 @@ check_if_startup_complete (NMManager *self) _LOGI (LOGD_CORE, "startup complete"); priv->startup = FALSE; - _notify (self, PROP_STARTUP); - /* We don't have to watch notify::has-pending-action any more. */ + /* we no longer care about these signals. Startup-complete only + * happens once. */ + g_signal_handlers_disconnect_by_func (priv->settings, G_CALLBACK (settings_startup_complete_changed), self); for (iter = priv->devices; iter; iter = iter->next) { - NMDevice *dev = iter->data; - - g_signal_handlers_disconnect_by_func (dev, G_CALLBACK (device_has_pending_action_changed), self); + g_signal_handlers_disconnect_by_func (iter->data, + G_CALLBACK (device_has_pending_action_changed), + self); } + _notify (self, PROP_STARTUP); + if (nm_config_get_configure_and_quit (priv->config)) g_signal_emit (self, signals[CONFIGURE_QUIT], 0); } @@ -993,8 +998,10 @@ remove_device (NMManager *self, if (unmanage) { if (quitting) nm_device_set_unmanaged_by_quitting (device); - else + else { + nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_REMOVED); nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_PLATFORM_INIT, TRUE, NM_DEVICE_STATE_REASON_REMOVED); + } } else if (quitting && nm_config_get_configure_and_quit (priv->config)) { nm_device_spawn_iface_helper (device); } @@ -1023,7 +1030,12 @@ remove_device (NMManager *self, g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); _notify (self, PROP_DEVICES); + } else { + /* unrealize() does not release a slave device from master and + * clear IP configurations, do it here */ + nm_device_removed (device, TRUE); } + g_signal_emit (self, signals[INTERNAL_DEVICE_REMOVED], 0, device); _notify (self, PROP_ALL_DEVICES); @@ -1132,6 +1144,11 @@ nm_manager_get_connection_iface (NMManager *self, factory = nm_device_factory_manager_find_factory_for_connection (connection); if (!factory) { + if (nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_GENERIC_SETTING_NAME)) { + /* the generic type doesn't have a factory. */ + goto return_ifname_fom_connection; + } + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, @@ -1143,15 +1160,7 @@ nm_manager_get_connection_iface (NMManager *self, if ( !out_parent && !NM_DEVICE_FACTORY_GET_CLASS (factory)->get_connection_iface) { /* optimization. Shortcut lookup of the partent device. */ - iface = g_strdup (nm_connection_get_interface_name (connection)); - if (!iface) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "failed to determine interface name: error determine name for %s", - nm_connection_get_connection_type (connection)); - } - return iface; + goto return_ifname_fom_connection; } parent = find_parent_device_for_connection (self, connection, factory); @@ -1165,6 +1174,17 @@ nm_manager_get_connection_iface (NMManager *self, if (out_parent) *out_parent = parent; return iface; + +return_ifname_fom_connection: + iface = g_strdup (nm_connection_get_interface_name (connection)); + if (!iface) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "failed to determine interface name: error determine name for %s", + nm_connection_get_connection_type (connection)); + } + return iface; } /** @@ -1206,7 +1226,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; - gs_free_slist GSList *connections = NULL; + gs_free NMSettingsConnection **connections = NULL; + guint i; GSList *iter; gs_free char *iface = NULL; NMDevice *device = NULL, *parent = NULL; @@ -1277,9 +1298,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) } /* Create backing resources if the device has any autoconnect connections */ - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = iter->data; + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMConnection *candidate = NM_CONNECTION (connections[i]); NMSettingConnection *s_con; if (!nm_device_check_connection_compatible (device, candidate)) @@ -1308,13 +1329,14 @@ static void retry_connections_for_parent_device (NMManager *self, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; g_return_if_fail (device); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = iter->data; + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMConnection *candidate = NM_CONNECTION (connections[i]); gs_free_error GError *error = NULL; gs_free char *ifname = NULL; NMDevice *parent; @@ -1329,8 +1351,6 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) } } } - - g_slist_free (connections); } static void @@ -1667,35 +1687,35 @@ done: g_clear_error (&error); } -static gboolean -match_connection_filter (NMConnection *connection, gpointer user_data) -{ - if (nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) - return FALSE; - - return nm_device_check_connection_compatible (NM_DEVICE (user_data), connection); -} - /** * get_existing_connection: * @manager: #NMManager instance * @device: #NMDevice instance + * @guess_assume: whether to employ a heuristic to search for a matching + * connection to assume. + * @assume_connection_uuid: if present, try to assume a connection with this + * UUID. If no uuid is given or no matching connection is found, we + * only do external activation. * @out_generated: (allow-none): return TRUE, if the connection was generated. * * Returns: a #NMSettingsConnection to be assumed by the device, or %NULL if * the device does not support assuming existing connections. */ static NMSettingsConnection * -get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_generated) +get_existing_connection (NMManager *self, + NMDevice *device, + gboolean guess_assume, + const char *assume_connection_uuid, + gboolean *out_generated) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gs_free_slist GSList *connections = nm_manager_get_activatable_connections (self); NMConnection *connection = NULL; - NMSettingsConnection *matched; NMSettingsConnection *added = NULL; GError *error = NULL; NMDevice *master = NULL; int ifindex = nm_device_get_ifindex (device); + NMSettingsConnection *matched; + NMSettingsConnection *connection_checked = NULL; if (out_generated) *out_generated = FALSE; @@ -1739,18 +1759,61 @@ get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_genera * When no configured connection matches the generated connection, we keep * the generated connection instead. */ - connections = g_slist_reverse (g_slist_sort (connections, nm_settings_sort_connections)); - matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, - connection, - nm_device_has_carrier (device), - nm_device_get_ip4_route_metric (device), - nm_device_get_ip6_route_metric (device), - match_connection_filter, - device)); + if ( assume_connection_uuid + && (connection_checked = nm_settings_get_connection_by_uuid (priv->settings, assume_connection_uuid)) + && !active_connection_find_first (self, connection_checked, NULL, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) + && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) { + NMConnection *const connections[] = { + NM_CONNECTION (connection_checked), + NULL, + }; + + matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, + connection, + nm_device_has_carrier (device), + nm_device_get_ip4_route_metric (device), + nm_device_get_ip6_route_metric (device), + NULL, NULL)); + } else + matched = NULL; + + if (!matched && guess_assume) { + gs_free NMSettingsConnection **connections = NULL; + guint len, i, j; + + /* the state file doesn't indicate a connection UUID to assume. Search the + * persistent connections for a matching candidate. */ + connections = nm_manager_get_activatable_connections (self, &len, FALSE); + if (len > 0) { + for (i = 0, j = 0; i < len; i++) { + NMConnection *con = NM_CONNECTION (connections[i]); + + if ( con != NM_CONNECTION (connection_checked) + && nm_device_check_connection_compatible (device, con)) + connections[j++] = connections[i]; + } + connections[j] = NULL; + len = j; + g_qsort_with_data (connections, len, sizeof (connections[0]), + nm_settings_connection_cmp_timestamp_p_with_data, NULL); + + matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection ((NMConnection *const*) connections, + connection, + nm_device_has_carrier (device), + nm_device_get_ip4_route_metric (device), + nm_device_get_ip6_route_metric (device), + NULL, NULL)); + } + } + if (matched) { - _LOGI (LOGD_DEVICE, "(%s): found matching connection '%s'", + _LOGI (LOGD_DEVICE, "(%s): found matching connection '%s' (%s)%s", nm_device_get_iface (device), - nm_settings_connection_get_id (matched)); + nm_settings_connection_get_id (matched), + nm_settings_connection_get_uuid (matched), + assume_connection_uuid && nm_streq (assume_connection_uuid, nm_settings_connection_get_uuid (matched)) + ? " (indicated)" : " (guessed)"); g_object_unref (connection); return matched; } @@ -1763,7 +1826,7 @@ get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_genera if (added) { nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED, + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, TRUE); if (out_generated) *out_generated = TRUE; @@ -1780,55 +1843,17 @@ get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_genera } static gboolean -assume_connection (NMManager *self, NMDevice *device, NMSettingsConnection *connection) -{ - NMActiveConnection *active, *master_ac; - NMAuthSubject *subject; - GError *error = NULL; - - _LOGD (LOGD_DEVICE, "(%s): will attempt to assume connection", - nm_device_get_iface (device)); - - /* Move device to DISCONNECTED to activate the connection */ - if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) { - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - g_return_val_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); - - subject = nm_auth_subject_new_internal (); - active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL, device, subject, &error); - g_object_unref (subject); - - if (!active) { - _LOGW (LOGD_DEVICE, "assumed connection %s failed to activate: %s", - nm_connection_get_path (NM_CONNECTION (connection)), - error->message); - g_error_free (error); - return FALSE; - } - - /* If the device is a slave or VLAN, find the master ActiveConnection */ - master_ac = NULL; - if (find_master (self, NM_CONNECTION (connection), device, NULL, NULL, &master_ac, NULL) && master_ac) - nm_active_connection_set_master (active, master_ac); - - nm_active_connection_set_assumed (active, TRUE); - nm_exported_object_export (NM_EXPORTED_OBJECT (active)); - active_connection_add (self, active); - nm_device_queue_activation (device, NM_ACT_REQUEST (active)); - g_object_unref (active); - - return TRUE; -} - -static gboolean -recheck_assume_connection (NMManager *self, NMDevice *device) +recheck_assume_connection (NMManager *self, + NMDevice *device, + gboolean guess_assume, + const char *assume_connection_uuid) { NMSettingsConnection *connection; - gboolean was_unmanaged = FALSE, success, generated = FALSE; + gboolean was_unmanaged = FALSE; + gboolean generated = FALSE; NMDeviceState state; + NMDeviceSysIfaceState if_state; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_DEVICE (device), FALSE); @@ -1843,43 +1868,93 @@ recheck_assume_connection (NMManager *self, NMDevice *device) if (state > NM_DEVICE_STATE_DISCONNECTED) return FALSE; - connection = get_existing_connection (self, device, &generated); + if_state = nm_device_sys_iface_state_get (device); + if (!priv->startup && (if_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED)) + nm_assert (!guess_assume && (assume_connection_uuid == NULL)); + else if (if_state != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) + return FALSE; + + connection = get_existing_connection (self, device, guess_assume, assume_connection_uuid, &generated); if (!connection) { _LOGD (LOGD_DEVICE, "(%s): can't assume; no connection", nm_device_get_iface (device)); return FALSE; } + _LOGD (LOGD_DEVICE, "(%s): will attempt to assume connection", + nm_device_get_iface (device)); + + if (!generated) + nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_ASSUME); + + /* Move device to DISCONNECTED to activate the connection */ if (state == NM_DEVICE_STATE_UNMANAGED) { was_unmanaged = TRUE; nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } - success = assume_connection (self, device, connection); - if (!success) { - if (was_unmanaged) { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - } + g_return_val_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + + { + gs_unref_object NMActiveConnection *active = NULL; + gs_unref_object NMAuthSubject *subject = NULL; + NMActiveConnection *master_ac; + GError *error = NULL; + + subject = nm_auth_subject_new_internal (); + active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL, + device, subject, + generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME, + &error); + + if (!active) { + _LOGW (LOGD_DEVICE, "assumed connection %s failed to activate: %s", + nm_connection_get_path (NM_CONNECTION (connection)), + error->message); + g_error_free (error); + + if (was_unmanaged) { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } - if (generated) { - _LOGD (LOGD_DEVICE, "(%s): connection assumption failed. Deleting generated connection", - nm_device_get_iface (device)); + if (generated) { + _LOGD (LOGD_DEVICE, "(%s): connection assumption failed. Deleting generated connection", + nm_device_get_iface (device)); - nm_settings_connection_delete (connection, NULL, NULL); + nm_settings_connection_delete (connection, NULL, NULL); + } else { + if (nm_device_sys_iface_state_get (device) == NM_DEVICE_SYS_IFACE_STATE_ASSUME) + nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); + } + return FALSE; } + + /* If the device is a slave or VLAN, find the master ActiveConnection */ + master_ac = NULL; + if (find_master (self, NM_CONNECTION (connection), device, NULL, NULL, &master_ac, NULL) && master_ac) + nm_active_connection_set_master (active, master_ac); + + nm_exported_object_export (NM_EXPORTED_OBJECT (active)); + active_connection_add (self, active); + nm_device_queue_activation (device, NM_ACT_REQUEST (active)); } - return success; + return TRUE; } static void recheck_assume_connection_cb (NMDevice *device, gpointer user_data) { - recheck_assume_connection (user_data, device); + recheck_assume_connection (user_data, device, FALSE, NULL); } static void @@ -1939,8 +2014,42 @@ device_realized (NMDevice *device, _notify (self, PROP_DEVICES); } +#if WITH_CONCHECK static void -_device_realize_finish (NMManager *self, NMDevice *device, const NMPlatformLink *plink) +device_connectivity_changed (NMDevice *device, + GParamSpec *pspec, + NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMConnectivityState best_state = NM_CONNECTIVITY_UNKNOWN; + NMConnectivityState state; + const GSList *devices; + + for (devices = priv->devices; devices; devices = devices->next) { + state = nm_device_get_connectivity_state (NM_DEVICE (devices->data)); + if (state > best_state) + best_state = state; + } + + if (best_state != priv->connectivity_state) { + priv->connectivity_state = best_state; + + _LOGD (LOGD_CORE, "connectivity checking indicates %s", + nm_connectivity_state_to_string (priv->connectivity_state)); + + nm_manager_update_state (self); + _notify (self, PROP_CONNECTIVITY); + nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL); + } +} +#endif + +static void +_device_realize_finish (NMManager *self, + NMDevice *device, + const NMPlatformLink *plink, + gboolean guess_assume, + const char *connection_uuid_to_assume) { g_return_if_fail (NM_IS_MANAGER (self)); g_return_if_fail (NM_IS_DEVICE (device)); @@ -1950,7 +2059,7 @@ _device_realize_finish (NMManager *self, NMDevice *device, const NMPlatformLink if (!nm_device_get_managed (device, FALSE)) return; - if (recheck_assume_connection (self, device)) + if (recheck_assume_connection (self, device, guess_assume, connection_uuid_to_assume)) return; /* if we failed to assume a connection for the managed device, but the device @@ -2040,6 +2149,12 @@ add_device (NMManager *self, NMDevice *device, GError **error) G_CALLBACK (device_realized), self); +#if WITH_CONCHECK + g_signal_connect (device, "notify::" NM_DEVICE_CONNECTIVITY, + G_CALLBACK (device_connectivity_changed), + self); +#endif + if (priv->startup) { g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, G_CALLBACK (device_has_pending_action_changed), @@ -2096,9 +2211,13 @@ factory_device_added_cb (NMDeviceFactory *factory, g_return_if_fail (NM_IS_MANAGER (self)); - if (nm_device_realize_start (device, NULL, NULL, &error)) { + if (nm_device_realize_start (device, + NULL, + NM_UNMAN_FLAG_OP_FORGET, + NULL, + &error)) { add_device (self, device, NULL); - _device_realize_finish (self, device, NULL); + _device_realize_finish (self, device, NULL, FALSE, NULL); } else { _LOGW (LOGD_DEVICE, "(%s): failed to realize device: %s", nm_device_get_iface (device), error->message); @@ -2144,6 +2263,7 @@ static void platform_link_added (NMManager *self, int ifindex, const NMPlatformLink *plink, + gboolean guess_assume, const NMConfigDeviceStateData *dev_state) { NMDeviceFactory *factory; @@ -2169,9 +2289,13 @@ platform_link_added (NMManager *self, * device with the link's name. */ return; - } else if (nm_device_realize_start (candidate, plink, &compatible, &error)) { + } else if (nm_device_realize_start (candidate, + plink, + NM_UNMAN_FLAG_OP_FORGET, + &compatible, + &error)) { /* Success */ - _device_realize_finish (self, candidate, plink); + _device_realize_finish (self, candidate, plink, FALSE, NULL); return; } @@ -2221,10 +2345,30 @@ platform_link_added (NMManager *self, if (device) { gs_free_error GError *error = NULL; + NMUnmanFlagOp unmanaged_user_explicit = NM_UNMAN_FLAG_OP_FORGET; + + if (dev_state) { + switch (dev_state->managed) { + case NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED: + unmanaged_user_explicit = NM_UNMAN_FLAG_OP_SET_MANAGED; + break; + case NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED: + unmanaged_user_explicit = NM_UNMAN_FLAG_OP_SET_UNMANAGED; + break; + case NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN: + break; + } + } - if (nm_device_realize_start (device, plink, NULL, &error)) { + if (nm_device_realize_start (device, + plink, + unmanaged_user_explicit, + NULL, + &error)) { add_device (self, device, NULL); - _device_realize_finish (self, device, plink); + _device_realize_finish (self, device, plink, + guess_assume, + dev_state ? dev_state->connection_uuid : NULL); } else { _LOGW (LOGD_DEVICE, "%s: failed to realize device: %s", plink->name, error->message); @@ -2254,7 +2398,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data) NMPlatformLink pllink; pllink = *l; /* make a copy of the link instance */ - platform_link_added (self, data->ifindex, &pllink, NULL); + platform_link_added (self, data->ifindex, &pllink, FALSE, NULL); } else { NMDevice *device; GError *error = NULL; @@ -2262,6 +2406,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data) device = nm_manager_get_device_by_ifindex (self, data->ifindex); if (device) { if (nm_device_is_software (device)) { + nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_REMOVED); /* Our software devices stick around until their connection is removed */ if (!nm_device_unrealize (device, FALSE, &error)) { _LOGW (LOGD_DEVICE, "(%s): failed to unrealize: %s", @@ -2310,22 +2455,24 @@ platform_link_cb (NMPlatform *platform, static void platform_query_devices (NMManager *self) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GArray *links_array; NMPlatformLink *links; int i; + gboolean guess_assume; + + guess_assume = nm_config_get_first_start (nm_config_get ()); links_array = nm_platform_link_get_all (NM_PLATFORM_GET); links = (NMPlatformLink *) links_array->data; for (i = 0; i < links_array->len; i++) { gs_free NMConfigDeviceStateData *dev_state = NULL; - dev_state = nm_config_device_state_load (priv->config, - links[i].ifindex); + dev_state = nm_config_device_state_load (links[i].ifindex); platform_link_added (self, links[i].ifindex, &links[i], + guess_assume && (!dev_state || !dev_state->connection_uuid), dev_state); } @@ -2372,27 +2519,22 @@ nm_manager_get_device_paths (NMManager *self) } static NMDevice * -nm_manager_get_connection_device (NMManager *self, - NMConnection *connection) -{ - NMActiveConnection *ac = find_ac_for_connection (self, connection); - if (ac == NULL) - return NULL; - - return nm_active_connection_get_device (ac); -} - -static NMDevice * nm_manager_get_best_device_for_connection (NMManager *self, NMConnection *connection, - gboolean for_user_request) + gboolean for_user_request, + GHashTable *unavailable_devices) { const GSList *devices, *iter; - NMDevice *act_device = nm_manager_get_connection_device (self, connection); + NMActiveConnection *ac; + NMDevice *act_device; NMDeviceCheckConAvailableFlags flags; - if (act_device) - return act_device; + ac = active_connection_find_first_by_connection (self, connection); + if (ac) { + act_device = nm_active_connection_get_device (ac); + if (act_device) + return act_device; + } flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE; @@ -2401,6 +2543,9 @@ nm_manager_get_best_device_for_connection (NMManager *self, for (iter = devices; iter; iter = g_slist_next (iter)) { NMDevice *device = NM_DEVICE (iter->data); + if (unavailable_devices && g_hash_table_contains (unavailable_devices, device)) + continue; + if (nm_device_check_connection_available (device, connection, flags, NULL)) return device; } @@ -2590,8 +2735,10 @@ find_master (NMManager *self, *out_master_connection = master_connection; if (out_master_device) *out_master_device = master_device; - if (out_master_ac && master_connection) - *out_master_ac = find_ac_for_connection (self, NM_CONNECTION (master_connection)); + if (out_master_ac && master_connection) { + *out_master_ac = active_connection_find_first (self, master_connection, NULL, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); + } if (master_device || master_connection) return TRUE; @@ -2676,14 +2823,15 @@ ensure_master_active_connection (NMManager *self, * activate it on the device. */ if (master_state == NM_DEVICE_STATE_DISCONNECTED || !nm_device_is_real (master_device)) { - GSList *connections; + gs_free NMSettingsConnection **connections = NULL; + guint i; g_assert (master_connection == NULL); /* Find a compatible connection and activate this device using it */ - connections = nm_manager_get_activatable_connections (self); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data); + connections = nm_manager_get_activatable_connections (self, NULL, TRUE); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *candidate = connections[i]; /* Ensure eg bond/team slave and the candidate master is a * bond/team master @@ -2698,12 +2846,11 @@ ensure_master_active_connection (NMManager *self, NULL, master_device, subject, + NM_ACTIVATION_TYPE_MANAGED, error); - g_slist_free (connections); return master_ac; } } - g_slist_free (connections); g_set_error (error, NM_MANAGER_ERROR, @@ -2745,6 +2892,7 @@ ensure_master_active_connection (NMManager *self, NULL, candidate, subject, + NM_ACTIVATION_TYPE_MANAGED, error); return master_ac; } @@ -2759,49 +2907,83 @@ ensure_master_active_connection (NMManager *self, return NULL; } +typedef struct { + NMSettingsConnection *connection; + NMDevice *device; +} SlaveConnectionInfo; + /** * find_slaves: * @manager: #NMManager object * @connection: the master #NMSettingsConnection to find slave connections for * @device: the master #NMDevice for the @connection + * @out_n_slaves: on return, the number of slaves found * * Given an #NMSettingsConnection, attempts to find its slaves. If @connection is not * master, or has not any slaves, this will return %NULL. * - * Returns: list of slave connections for given master @connection, or %NULL + * Returns: an array of #SlaveConnectionInfo for given master @connection, or %NULL **/ -static GSList * +static SlaveConnectionInfo * find_slaves (NMManager *manager, NMSettingsConnection *connection, - NMDevice *device) + NMDevice *device, + guint *out_n_slaves) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *all_connections, *iter; - GSList *slaves = NULL; + gs_free NMSettingsConnection **all_connections = NULL; + guint n_all_connections; + guint i; + SlaveConnectionInfo *slaves = NULL; + guint n_slaves = 0; NMSettingConnection *s_con; + gs_unref_hashtable GHashTable *devices = NULL; + + nm_assert (out_n_slaves); s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); - g_assert (s_con); + g_return_val_if_fail (s_con, NULL); + + devices = g_hash_table_new (g_direct_hash, g_direct_equal); /* Search through all connections, not only inactive ones, because * even if a slave was already active, it might be deactivated during * master reactivation. */ - all_connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = all_connections; iter; iter = iter->next) { + all_connections = nm_settings_get_connections_sorted (priv->settings, &n_all_connections); + for (i = 0; i < n_all_connections; i++) { NMSettingsConnection *master_connection = NULL; - NMDevice *master_device = NULL; - NMConnection *candidate = iter->data; + NMDevice *master_device = NULL, *slave_device; + NMConnection *candidate = NM_CONNECTION (all_connections[i]); find_master (manager, candidate, NULL, &master_connection, &master_device, NULL, NULL); if ( (master_connection && master_connection == connection) || (master_device && master_device == device)) { - slaves = g_slist_prepend (slaves, candidate); + slave_device = nm_manager_get_best_device_for_connection (manager, + candidate, + FALSE, + devices); + + if (!slaves) { + /* what we allocate is quite likely much too large. Don't bother, it is only + * a temporary buffer. */ + slaves = g_new (SlaveConnectionInfo, n_all_connections); + } + + nm_assert (n_slaves < n_all_connections); + slaves[n_slaves].connection = NM_SETTINGS_CONNECTION (candidate), + slaves[n_slaves].device = slave_device, + n_slaves++; + + if (slave_device) + g_hash_table_add (devices, slave_device); } } - g_slist_free (all_connections); - return g_slist_reverse (slaves); + *out_n_slaves = n_slaves; + + /* Warning: returns NULL if n_slaves is zero. */ + return slaves; } static gboolean @@ -2833,39 +3015,56 @@ out: return FALSE; } -static gboolean +static gint +compare_slaves (gconstpointer a, gconstpointer b, gpointer _unused) +{ + const SlaveConnectionInfo *a_info = a; + const SlaveConnectionInfo *b_info = b; + + /* Slaves without a device at the end */ + if (!a_info->device) + return 1; + if (!b_info->device) + return -1; + + return g_strcmp0 (nm_device_get_iface (a_info->device), + nm_device_get_iface (b_info->device)); +} + +static void autoconnect_slaves (NMManager *self, NMSettingsConnection *master_connection, NMDevice *master_device, NMAuthSubject *subject) { GError *local_err = NULL; - gboolean ret = FALSE; if (should_connect_slaves (NM_CONNECTION (master_connection), master_device)) { - GSList *slaves, *iter; + gs_free SlaveConnectionInfo *slaves = NULL; + guint i, n_slaves = 0; - iter = slaves = find_slaves (self, master_connection, master_device); - ret = slaves != NULL; + slaves = find_slaves (self, master_connection, master_device, &n_slaves); + if (n_slaves > 1) { + g_qsort_with_data (slaves, n_slaves, sizeof (slaves[0]), + compare_slaves, NULL); + } - while (iter) { - NMSettingsConnection *slave_connection = iter->data; + for (i = 0; i < n_slaves; i++) { + SlaveConnectionInfo *slave = &slaves[i]; const char *uuid; - iter = iter->next; - /* To avoid loops when autoconnecting slaves, we propagate * the UUID of the initial connection down to slaves until * the same connection is found. */ uuid = g_object_get_qdata (G_OBJECT (master_connection), autoconnect_root_quark ()); - if (nm_streq0 (nm_settings_connection_get_uuid (slave_connection), uuid)) { + if (nm_streq0 (nm_settings_connection_get_uuid (slave->connection), uuid)) { _LOGI (LOGD_CORE, "will NOT activate slave connection '%s' (%s) as a dependency for master '%s' (%s): " "circular dependency detected", - nm_settings_connection_get_id (slave_connection), - nm_settings_connection_get_uuid (slave_connection), + nm_settings_connection_get_id (slave->connection), + nm_settings_connection_get_uuid (slave->connection), nm_settings_connection_get_id (master_connection), nm_settings_connection_get_uuid (master_connection)); continue; @@ -2873,44 +3072,60 @@ autoconnect_slaves (NMManager *self, if (!uuid) uuid = nm_settings_connection_get_uuid (master_connection); - g_object_set_qdata_full (G_OBJECT (slave_connection), + g_object_set_qdata_full (G_OBJECT (slave->connection), autoconnect_root_quark (), g_strdup (uuid), g_free); + if (!slave->device) { + _LOGD (LOGD_CORE, + "will NOT activate slave connection '%s' (%s) as a dependency for master '%s' (%s): " + "no compatible device found", + nm_settings_connection_get_id (slave->connection), + nm_settings_connection_get_uuid (slave->connection), + nm_settings_connection_get_id (master_connection), + nm_settings_connection_get_uuid (master_connection)); + continue; + } + _LOGD (LOGD_CORE, "will activate slave connection '%s' (%s) as a dependency for master '%s' (%s)", - nm_settings_connection_get_id (slave_connection), - nm_settings_connection_get_uuid (slave_connection), + nm_settings_connection_get_id (slave->connection), + nm_settings_connection_get_uuid (slave->connection), nm_settings_connection_get_id (master_connection), nm_settings_connection_get_uuid (master_connection)); /* Schedule slave activation */ nm_manager_activate_connection (self, - slave_connection, + slave->connection, NULL, NULL, - nm_manager_get_best_device_for_connection (self, NM_CONNECTION (slave_connection), FALSE), + slave->device, subject, + NM_ACTIVATION_TYPE_MANAGED, &local_err); if (local_err) { _LOGW (LOGD_CORE, "Slave connection activation failed: %s", local_err->message); - g_error_free (local_err); + g_clear_error (&local_err); } } - g_slist_free (slaves); } - return ret; } static gboolean _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **error) { + gboolean success; + g_assert (NM_IS_VPN_CONNECTION (active)); nm_exported_object_export (NM_EXPORTED_OBJECT (active)); - return nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager, - NM_VPN_CONNECTION (active), - error); + success = nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager, + NM_VPN_CONNECTION (active), + error); + if (!success) + nm_exported_object_unexport (NM_EXPORTED_OBJECT (active)); + + return success; } /* Traverse the device to disconnected state. This means that the device is ready @@ -2969,12 +3184,16 @@ active_connection_parent_active (NMActiveConnection *active, } else { _LOGW (LOGD_CORE, "Could not realize device '%s': %s", nm_device_get_iface (device), error->message); - nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + nm_active_connection_set_state (active, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REALIZE_FAILED); } } else { _LOGW (LOGD_CORE, "The parent connection device '%s' depended on disappeared.", nm_device_get_iface (device)); - nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + nm_active_connection_set_state (active, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REMOVED); } } @@ -2982,6 +3201,7 @@ static gboolean _internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error) { NMDevice *device, *existing, *master_device = NULL; + NMActiveConnection *existing_ac; NMConnection *applied; NMSettingsConnection *connection; NMSettingsConnection *master_connection = NULL; @@ -3048,7 +3268,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } - parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, subject, error); + parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, + subject, NM_ACTIVATION_TYPE_MANAGED, error); if (!parent_ac) { g_prefix_error (error, "%s failed to activate parent: ", nm_device_get_iface (device)); return FALSE; @@ -3142,9 +3363,12 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * autoconnect_slaves (self, connection, device, nm_active_connection_get_subject (active)); /* Disconnect the connection if connected or queued on another device */ - existing = nm_manager_get_connection_device (self, NM_CONNECTION (connection)); - if (existing) - nm_device_steal_connection (existing, connection); + existing_ac = active_connection_find_first (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); + if (existing_ac) { + existing = nm_active_connection_get_device (existing_ac); + if (existing) + nm_device_steal_connection (existing, connection); + } /* If the device is there, we can ready it for the activation. */ if (nm_device_is_real (device)) @@ -3243,6 +3467,7 @@ _new_active_connection (NMManager *self, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error) { NMSettingsConnection *settings_connection = NULL; @@ -3253,7 +3478,7 @@ _new_active_connection (NMManager *self, g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); /* Can't create new AC for already-active connection */ - existing_ac = find_ac_for_connection (self, connection); + existing_ac = active_connection_find_first_by_connection (self, connection); if (NM_IS_VPN_CONNECTION (existing_ac)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, "Connection '%s' is already active", @@ -3271,6 +3496,8 @@ _new_active_connection (NMManager *self, settings_connection = (NMSettingsConnection *) connection; if (is_vpn) { + if (activation_type != NM_ACTIVATION_TYPE_MANAGED) + g_return_val_if_reached (NULL); return _new_vpn_active_connection (self, settings_connection, specific_object, @@ -3282,6 +3509,7 @@ _new_active_connection (NMManager *self, applied, specific_object, subject, + activation_type, device); } @@ -3295,8 +3523,12 @@ _internal_activation_failed (NMManager *self, error_desc); if (nm_active_connection_get_state (active) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); - nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + nm_active_connection_set_state (active, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, + NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN); + nm_active_connection_set_state (active, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN); } } @@ -3334,6 +3566,8 @@ _internal_activation_auth_done (NMActiveConnection *active, * @specific_object: the specific object path, if any, for the activation * @device: the #NMDevice to activate @connection on * @subject: the subject which requested activation + * @activation_type: whether to assume the connection. That is, take over gracefully, + * non-destructible. * @error: return location for an error * * Begins a new internally-initiated activation of @connection on @device. @@ -3353,6 +3587,7 @@ nm_manager_activate_connection (NMManager *self, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -3399,6 +3634,7 @@ nm_manager_activate_connection (NMManager *self, specific_object, device, subject, + activation_type, error); if (active) { priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); @@ -3484,7 +3720,7 @@ validate_activation_request (NMManager *self, goto error; } } else - device = nm_manager_get_best_device_for_connection (self, connection, TRUE); + device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL); if (!device && !vpn) { gboolean is_software = nm_connection_is_virtual (connection); @@ -3642,6 +3878,7 @@ impl_manager_activate_connection (NMManager *self, specific_object_path, device, subject, + NM_ACTIVATION_TYPE_MANAGED, &error); if (!active) goto error; @@ -3739,8 +3976,8 @@ _add_and_activate_auth_done (NMActiveConnection *active, if (success) { NMConnection *connection; - connection = g_object_steal_data (G_OBJECT (active), - TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE); + connection = g_object_steal_qdata (G_OBJECT (active), + active_connection_add_and_activate_quark ()); info = g_slice_new (AddAndActivateInfo); info->manager = self; @@ -3814,7 +4051,17 @@ impl_manager_add_and_activate_connection (NMManager *self, if (!subject) goto error; - all_connections = nm_settings_get_connections_sorted (priv->settings); + { + gs_free NMSettingsConnection **connections = NULL; + guint i, len; + + connections = nm_settings_get_connections_sorted (priv->settings, &len); + all_connections = NULL; + for (i = len; i > 0; ) { + i--; + all_connections = g_slist_prepend (all_connections, connections[i]); + } + } if (vpn) { /* Try to fill the VPN's connection setting and name at least */ if (!nm_connection_get_setting_vpn (connection)) { @@ -3851,14 +4098,15 @@ impl_manager_add_and_activate_connection (NMManager *self, specific_object_path, device, subject, + NM_ACTIVATION_TYPE_MANAGED, &error); if (!active) goto error; - g_object_set_data_full (G_OBJECT (active), - TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE, - connection, - g_object_unref); + g_object_set_qdata_full (G_OBJECT (active), + active_connection_add_and_activate_quark (), + connection, + g_object_unref); nm_active_connection_authorize (active, connection, _add_and_activate_auth_done, self, context); g_object_unref (subject); @@ -3886,10 +4134,11 @@ nm_manager_deactivate_connection (NMManager *manager, gboolean success = FALSE; if (NM_IS_VPN_CONNECTION (active)) { - NMVpnConnectionStateReason vpn_reason = NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED; + NMActiveConnectionStateReason vpn_reason = NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED; + + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED) + vpn_reason = NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED; - if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED) - vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED; if (nm_vpn_connection_deactivate (NM_VPN_CONNECTION (active), vpn_reason, FALSE)) success = TRUE; else @@ -4240,7 +4489,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) nm_device_set_enabled (device, enabled); } - nm_device_set_autoconnect (device, TRUE); + nm_device_set_autoconnect_intern (device, TRUE); nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED); } @@ -4631,24 +4880,36 @@ impl_manager_get_logging (NMManager *manager, nm_logging_domains_to_string ())); } +typedef struct { + guint remaining; + GDBusMethodInvocation *context; + NMConnectivityState state; +} ConnectivityCheckData; + static void -connectivity_check_done (GObject *object, - GAsyncResult *result, - gpointer user_data) +device_connectivity_done (NMDevice *device, NMConnectivityState state, gpointer user_data) { - GDBusMethodInvocation *context = user_data; - NMConnectivityState state; - GError *error = NULL; + ConnectivityCheckData *data = user_data; - state = nm_connectivity_check_finish (NM_CONNECTIVITY (object), result, &error); - if (error) - g_dbus_method_invocation_take_error (context, error); - else { - g_dbus_method_invocation_return_value (context, - g_variant_new ("(u)", state)); + data->remaining--; + + /* We check if the state is already FULL so that we can provide the + * response without waiting for slower devices that are not going to + * affect the overall state anyway. */ + + if (data->state != NM_CONNECTIVITY_FULL) { + if (state > data->state) + data->state = state; + + if (data->state == NM_CONNECTIVITY_FULL || !data->remaining) { + g_dbus_method_invocation_return_value (data->context, + g_variant_new ("(u)", data->state)); + } } -} + if (!data->remaining) + g_slice_free (ConnectivityCheckData, data); +} static void check_connectivity_auth_done_cb (NMAuthChain *chain, @@ -4660,6 +4921,8 @@ check_connectivity_auth_done_cb (NMAuthChain *chain, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *error = NULL; NMAuthCallResult result; + ConnectivityCheckData *data; + const GSList *devices; priv->auth_chains = g_slist_remove (priv->auth_chains, chain); @@ -4677,9 +4940,15 @@ check_connectivity_auth_done_cb (NMAuthChain *chain, "Not authorized to recheck connectivity"); } else { /* it's allowed */ - nm_connectivity_check_async (priv->connectivity, - connectivity_check_done, - context); + data = g_slice_new0 (ConnectivityCheckData); + data->context = context; + + for (devices = priv->devices; devices; devices = devices->next) { + data->remaining++; + nm_device_check_connectivity (NM_DEVICE (devices->data), + device_connectivity_done, + data); + } } if (error) @@ -4728,6 +4997,7 @@ nm_manager_write_device_state (NMManager *self) NMDevice *device = NM_DEVICE (devices->data); int ifindex; gboolean managed; + NMConfigDeviceStateManagedType managed_type; NMConnection *settings_connection; const char *uuid = NULL; const char *perm_hw_addr_fake = NULL; @@ -4749,39 +5019,48 @@ nm_manager_write_device_state (NMManager *self) settings_connection = NM_CONNECTION (nm_device_get_settings_connection (device)); if (settings_connection) uuid = nm_connection_get_uuid (settings_connection); - } + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED; + } else if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_USER_EXPLICIT)) + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; + else + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN; perm_hw_addr_fake = nm_device_get_permanent_hw_address_full (device, FALSE, &perm_hw_addr_is_fake); if (perm_hw_addr_fake && !perm_hw_addr_is_fake) perm_hw_addr_fake = NULL; - if (nm_config_device_state_write (priv->config, - ifindex, - managed, + if (nm_config_device_state_write (ifindex, + managed_type, perm_hw_addr_fake, uuid)) g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex)); } - nm_config_device_state_prune_unseen (priv->config, - seen_ifindexes); + nm_config_device_state_prune_unseen (seen_ifindexes); +} + +static gboolean +devices_inited_cb (gpointer user_data) +{ + NMManager *self = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + priv->devices_inited_id = 0; + priv->devices_inited = TRUE; + check_if_startup_complete (self); + return G_SOURCE_REMOVE; } gboolean nm_manager_start (NMManager *self, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter, *connections; + gs_free NMSettingsConnection **connections = NULL; guint i; if (!nm_settings_start (priv->settings, error)) return FALSE; - g_signal_connect (NM_PLATFORM_GET, - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK (platform_link_cb), - self); - /* Set initial radio enabled/disabled state */ for (i = 0; i < RFKILL_TYPE_MAX; i++) { RadioState *rstate = &priv->radio_states[i]; @@ -4814,6 +5093,13 @@ nm_manager_start (NMManager *self, GError **error) nm_device_factory_manager_load_factories (_register_device_factory, self); nm_device_factory_manager_for_each_factory (start_factory, NULL); + nm_platform_process_events (NM_PLATFORM_GET); + + g_signal_connect (NM_PLATFORM_GET, + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK (platform_link_cb), + self); + platform_query_devices (self); /* Load VPN plugins */ @@ -4823,14 +5109,12 @@ nm_manager_start (NMManager *self, GError **error) * connection-added signals thus devices have to be created manually. */ _LOGD (LOGD_CORE, "creating virtual devices..."); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = iter->next) - connection_changed (self, NM_CONNECTION (iter->data)); - g_slist_free (connections); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) + connection_changed (self, NM_CONNECTION (connections[i])); - priv->devices_inited = TRUE; - - check_if_startup_complete (self); + nm_clear_g_source (&priv->devices_inited_id); + priv->devices_inited_id = g_idle_add_full (G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL); return TRUE; } @@ -4845,6 +5129,8 @@ nm_manager_stop (NMManager *self) remove_device (self, NM_DEVICE (priv->devices->data), TRUE, TRUE); _active_connection_cleanup (self); + + nm_clear_g_source (&priv->devices_inited_id); } static gboolean @@ -4877,20 +5163,6 @@ handle_firmware_changed (gpointer user_data) } static void -connectivity_changed (NMConnectivity *connectivity, - GParamSpec *pspec, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - - _LOGD (LOGD_CORE, "connectivity checking indicates %s", - nm_connectivity_state_to_string (nm_connectivity_get_state (connectivity))); - - nm_manager_update_state (self); - _notify (self, PROP_CONNECTIVITY); -} - -static void firmware_dir_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, @@ -5044,9 +5316,9 @@ prop_set_auth_done_cb (NMAuthChain *chain, priv->auth_chains = g_slist_remove (priv->auth_chains, chain); result = nm_auth_chain_get_result (chain, pfd->permission); if (error || (result != NM_AUTH_CALL_RESULT_YES)) { - reply = g_dbus_message_new_method_error (pfd->message, - NM_PERM_DENIED_ERROR, - (error_message = "Not authorized to perform this operation")); + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Not authorized to perform this operation")); if (error) error_message = error->message; goto done; @@ -5055,17 +5327,17 @@ prop_set_auth_done_cb (NMAuthChain *chain, object = NM_EXPORTED_OBJECT (nm_bus_manager_get_registered_object (priv->dbus_mgr, g_dbus_message_get_path (pfd->message))); if (!object) { - reply = g_dbus_message_new_method_error (pfd->message, - "org.freedesktop.DBus.Error.UnknownObject", - (error_message = "Object doesn't exist.")); + reply = g_dbus_message_new_method_error_literal (pfd->message, + "org.freedesktop.DBus.Error.UnknownObject", + (error_message = "Object doesn't exist.")); goto done; } /* do some extra type checking... */ if (!nm_exported_object_get_interface_by_type (object, pfd->interface_type)) { - reply = g_dbus_message_new_method_error (pfd->message, - "org.freedesktop.DBus.Error.InvalidArgs", - (error_message = "Object is of unexpected type.")); + reply = g_dbus_message_new_method_error_literal (pfd->message, + "org.freedesktop.DBus.Error.InvalidArgs", + (error_message = "Object is of unexpected type.")); goto done; } @@ -5078,9 +5350,9 @@ prop_set_auth_done_cb (NMAuthChain *chain, global_dns = nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)); if (global_dns && !nm_global_dns_config_is_internal (global_dns)) { - reply = g_dbus_message_new_method_error (pfd->message, - NM_PERM_DENIED_ERROR, - (error_message = "Global DNS configuration already set via configuration file")); + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Global DNS configuration already set via configuration file")); goto done; } /* ... but set the property on the @object itself. It would be correct to set the property @@ -5122,18 +5394,18 @@ do_set_property_check (gpointer user_data) pfd->subject = nm_auth_subject_new_unix_process_from_message (pfd->connection, pfd->message); if (!pfd->subject) { - reply = g_dbus_message_new_method_error (pfd->message, - NM_PERM_DENIED_ERROR, - (error_message = "Could not determine request UID.")); + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Could not determine request UID.")); goto out; } /* Validate the user request */ chain = nm_auth_chain_new_subject (pfd->subject, NULL, prop_set_auth_done_cb, pfd); if (!chain) { - reply = g_dbus_message_new_method_error (pfd->message, - NM_PERM_DENIED_ERROR, - (error_message = "Could not authenticate request.")); + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Could not authenticate request.")); goto out; } @@ -5697,7 +5969,6 @@ constructed (GObject *object) { NMManager *self = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMConfigData *config_data; const NMConfigState *state; G_OBJECT_CLASS (nm_manager_parent_class)->constructed (object); @@ -5740,13 +6011,6 @@ constructed (GObject *object) G_CALLBACK (_config_changed_cb), self); - config_data = nm_config_get_data (priv->config); - priv->connectivity = nm_connectivity_new (nm_config_data_get_connectivity_uri (config_data), - nm_config_data_get_connectivity_interval (config_data), - nm_config_data_get_connectivity_response (config_data)); - g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE, - G_CALLBACK (connectivity_changed), self); - state = nm_config_state_get (priv->config); priv->net_enabled = state->net_enabled; @@ -5902,7 +6166,7 @@ get_property (GObject *object, guint prop_id, nm_utils_g_value_set_object_path_array (value, priv->active_connections, NULL, NULL); break; case PROP_CONNECTIVITY: - g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity)); + g_value_set_uint (value, priv->connectivity_state); break; case PROP_PRIMARY_CONNECTION: nm_utils_g_value_set_object_path (value, priv->primary_connection); @@ -6003,6 +6267,8 @@ dispose (GObject *object) g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; + nm_clear_g_source (&priv->devices_inited_id); + if (priv->checkpoint_mgr) { nm_checkpoint_manager_destroy_all (priv->checkpoint_mgr, NULL); g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_unref); @@ -6029,10 +6295,6 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (priv->config, _config_changed_cb, manager); g_clear_object (&priv->config); } - if (priv->connectivity) { - g_signal_handlers_disconnect_by_func (priv->connectivity, connectivity_changed, manager); - g_clear_object (&priv->connectivity); - } g_free (priv->hostname); diff --git a/src/nm-manager.h b/src/nm-manager.h index c69fc9e1..676fa995 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -84,7 +84,10 @@ gboolean nm_manager_start (NMManager *manager, void nm_manager_stop (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); const GSList *nm_manager_get_active_connections (NMManager *manager); -GSList * nm_manager_get_activatable_connections (NMManager *manager); + +NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager, + guint *out_len, + gboolean sort); void nm_manager_write_device_state (NMManager *manager); @@ -112,6 +115,7 @@ NMActiveConnection *nm_manager_activate_connection (NMManager *manager, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error); gboolean nm_manager_deactivate_connection (NMManager *manager, diff --git a/src/nm-netns.c b/src/nm-netns.c new file mode 100644 index 00000000..a81aa696 --- /dev/null +++ b/src/nm-netns.c @@ -0,0 +1,176 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-netns.h" + +#include "platform/nm-platform.h" +#include "platform/nmp-netns.h" +#include "nm-route-manager.h" +#include "nm-default-route-manager.h" +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_PLATFORM, +); + +typedef struct { + NMPlatform *platform; + NMPNetns *platform_netns; + NMRouteManager *route_manager; + NMDefaultRouteManager *default_route_manager; + bool log_with_ptr; +} NMNetnsPrivate; + +struct _NMNetns { + GObject parent; + NMNetnsPrivate _priv; +}; + +struct _NMNetnsClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMNetns, nm_netns, G_TYPE_OBJECT); + +#define NM_NETNS_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMNetns, NM_IS_NETNS) + +/*****************************************************************************/ + +NM_DEFINE_SINGLETON_GETTER (NMNetns, nm_netns_get, NM_TYPE_NETNS); + +/*****************************************************************************/ + +NMPNetns * +nm_netns_get_platform_netns (NMNetns *self) +{ + return NM_NETNS_GET_PRIVATE (self)->platform_netns; +} + +NMPlatform * +nm_netns_get_platform (NMNetns *self) +{ + return NM_NETNS_GET_PRIVATE (self)->platform; +} + +NMDefaultRouteManager * +nm_netns_get_default_route_manager (NMNetns *self) +{ + return NM_NETNS_GET_PRIVATE (self)->default_route_manager; +} + +NMRouteManager * +nm_netns_get_route_manager (NMNetns *self) +{ + return NM_NETNS_GET_PRIVATE (self)->route_manager; +} + +/*****************************************************************************/ + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMNetns *self = NM_NETNS (object); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_PLATFORM: + /* construct-only */ + priv->platform = g_value_get_object (value) ?: NM_PLATFORM_GET; + if (!priv->platform) + g_return_if_reached (); + g_object_ref (priv->platform); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_netns_init (NMNetns *self) +{ +} + +static void +constructed (GObject *object) +{ + NMNetns *self = NM_NETNS (object); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + gboolean log_with_ptr; + + if (!priv->platform) + g_return_if_reached (); + + log_with_ptr = nm_platform_get_log_with_ptr (priv->platform); + + priv->platform_netns = nm_platform_netns_get (priv->platform); + priv->route_manager = nm_route_manager_new (log_with_ptr, priv->platform); + priv->default_route_manager = nm_default_route_manager_new (log_with_ptr, priv->platform); + + G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object); +} + +NMNetns * +nm_netns_new (NMPlatform *platform) +{ + return g_object_new (NM_TYPE_NETNS, + NM_NETNS_PLATFORM, platform, + NULL); +} + +static void +dispose (GObject *object) +{ + NMNetns *self = NM_NETNS (object); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + + g_clear_object (&priv->route_manager); + g_clear_object (&priv->default_route_manager); + g_clear_object (&priv->platform); + + G_OBJECT_CLASS (nm_netns_parent_class)->dispose (object); +} + +static void +nm_netns_class_init (NMNetnsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = constructed; + object_class->set_property = set_property; + object_class->dispose = dispose; + + obj_properties[PROP_PLATFORM] = + g_param_spec_object (NM_NETNS_PLATFORM, "", "", + NM_TYPE_PLATFORM, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} diff --git a/src/nm-netns.h b/src/nm-netns.h new file mode 100644 index 00000000..fd5daf47 --- /dev/null +++ b/src/nm-netns.h @@ -0,0 +1,47 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#ifndef __NM_NETNS_H__ +#define __NM_NETNS_H__ + +#define NM_TYPE_NETNS (nm_netns_get_type ()) +#define NM_NETNS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETNS, NMNetns)) +#define NM_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETNS, NMNetnsClass)) +#define NM_IS_NETNS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETNS)) +#define NM_IS_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETNS)) +#define NM_NETNS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_NETNS, NMNetnsClass)) + +#define NM_NETNS_PLATFORM "platform" + +typedef struct _NMNetnsClass NMNetnsClass; + +GType nm_netns_get_type (void); + +NMNetns *nm_netns_get (void); +NMNetns *nm_netns_new (NMPlatform *platform); + +NMPlatform *nm_netns_get_platform (NMNetns *self); +NMPNetns *nm_netns_get_platform_netns (NMNetns *self); +NMRouteManager *nm_netns_get_route_manager (NMNetns *self); +NMDefaultRouteManager *nm_netns_get_default_route_manager (NMNetns *self); + +#define NM_NETNS_GET (nm_netns_get ()) + +#endif /* __NM_NETNS_H__ */ diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index 450cf0e3..cfc028c2 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -28,24 +28,29 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" +static void pacrunner_remove_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data); + #define PACRUNNER_DBUS_SERVICE "org.pacrunner" #define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" #define PACRUNNER_DBUS_PATH "/org/pacrunner/manager" /*****************************************************************************/ -struct remove_data { - char *iface; +struct _NMPacrunnerCallId { + NMPacrunnerManager *manager; + GVariant *args; char *path; + guint refcount; + bool removed; }; +typedef struct _NMPacrunnerCallId Config; + typedef struct { char *iface; - GPtrArray *domains; GDBusProxy *pacrunner; GCancellable *pacrunner_cancellable; - GList *args; - GList *remove; + GList *configs; } NMPacrunnerManagerPrivate; struct _NMPacrunnerManager { @@ -68,23 +73,58 @@ NM_DEFINE_SINGLETON_GETTER (NMPacrunnerManager, nm_pacrunner_manager_get, NM_TYP /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_PROXY -#define _NMLOG(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG_DOMAIN, "pacrunner", __VA_ARGS__) +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "pacrunner", __VA_ARGS__) + +#define _NMLOG2_PREFIX_NAME "pacrunner" +#define _NMLOG2(level, config, ...) \ + G_STMT_START { \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ + "%s%p]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + "pacrunner: call[", \ + (config) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END /*****************************************************************************/ +static Config * +config_new (NMPacrunnerManager *manager, GVariant *args) +{ + Config *config; + + config = g_slice_new0 (Config); + config->manager = manager; + config->args = g_variant_ref_sink (args); + config->refcount = 1; + + return config; +} + static void -remove_data_destroy (struct remove_data *data) +config_ref (Config *config) { - g_return_if_fail (data != NULL); + g_assert (config); + g_assert (config->refcount > 0); - g_free (data->iface); - g_free (data->path); - memset (data, 0, sizeof (struct remove_data)); - g_free (data); + config->refcount++; } static void -add_proxy_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, const NMProxyConfig *proxy_config) +config_unref (Config *config) +{ + g_assert (config); + g_assert (config->refcount > 0); + + if (config->refcount == 1) { + g_variant_unref (config->args); + g_free (config->path); + g_slice_free (Config, config); + } else + config->refcount--; +} + +static void +add_proxy_config (GVariantBuilder *proxy_data, const NMProxyConfig *proxy_config) { const char *pac_url, *pac_script; NMProxyConfigMethod method; @@ -113,19 +153,18 @@ add_proxy_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, const N } static void -add_ip4_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP4Config *ip4) +get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4) { - NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + char *cidr; int i; - char *cidr = NULL; /* Extract searches */ for (i = 0; i < nm_ip4_config_get_num_searches (ip4); i++) - g_ptr_array_add (priv->domains, g_strdup (nm_ip4_config_get_search (ip4, i))); + g_ptr_array_add (domains, g_strdup (nm_ip4_config_get_search (ip4, i))); /* Extract domains */ for (i = 0; i < nm_ip4_config_get_num_domains (ip4); i++) - g_ptr_array_add (priv->domains, g_strdup (nm_ip4_config_get_domain (ip4, i))); + g_ptr_array_add (domains, g_strdup (nm_ip4_config_get_domain (ip4, i))); /* Add addresses and routes in CIDR form */ for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) { @@ -134,8 +173,7 @@ add_ip4_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP4Conf cidr = g_strdup_printf ("%s/%u", nm_utils_inet4_ntop (address->address, NULL), address->plen); - g_ptr_array_add (priv->domains, g_strdup (cidr)); - g_free (cidr); + g_ptr_array_add (domains, cidr); } for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) { @@ -144,25 +182,23 @@ add_ip4_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP4Conf cidr = g_strdup_printf ("%s/%u", nm_utils_inet4_ntop (routes->network, NULL), routes->plen); - g_ptr_array_add (priv->domains, g_strdup (cidr)); - g_free (cidr); + g_ptr_array_add (domains, cidr); } } static void -add_ip6_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP6Config *ip6) +get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) { - NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + char *cidr; int i; - char *cidr = NULL; /* Extract searches */ for (i = 0; i < nm_ip6_config_get_num_searches (ip6); i++) - g_ptr_array_add (priv->domains, g_strdup (nm_ip6_config_get_search (ip6, i))); + g_ptr_array_add (domains, g_strdup (nm_ip6_config_get_search (ip6, i))); /* Extract domains */ for (i = 0; i < nm_ip6_config_get_num_domains (ip6); i++) - g_ptr_array_add (priv->domains, g_strdup (nm_ip6_config_get_domain (ip6, i))); + g_ptr_array_add (domains, g_strdup (nm_ip6_config_get_domain (ip6, i))); /* Add addresses and routes in CIDR form */ for (i = 0; i < nm_ip6_config_get_num_addresses (ip6); i++) { @@ -171,8 +207,7 @@ add_ip6_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP6Conf cidr = g_strdup_printf ("%s/%u", nm_utils_inet6_ntop (&address->address, NULL), address->plen); - g_ptr_array_add (priv->domains, g_strdup (cidr)); - g_free (cidr); + g_ptr_array_add (domains, cidr); } for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) { @@ -181,93 +216,101 @@ add_ip6_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP6Conf cidr = g_strdup_printf ("%s/%u", nm_utils_inet6_ntop (&routes->network, NULL), routes->plen); - g_ptr_array_add (priv->domains, g_strdup (cidr)); - g_free (cidr); + g_ptr_array_add (domains, cidr); } } static void -pacrunner_send_done (GObject *source, GAsyncResult *res, gpointer user_data) +pacrunner_send_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { - NMPacrunnerManager *self = NM_PACRUNNER_MANAGER (user_data); - NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + Config *config = user_data; + NMPacrunnerManager *self; + NMPacrunnerManagerPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *variant = NULL; const char *path = NULL; - GList *iter = NULL; - gboolean found = FALSE; - variant = g_dbus_proxy_call_finish (priv->pacrunner, res, &error); - if (!variant) { - _LOGD ("sending proxy config to pacrunner failed: %s", error->message); - } else { - struct remove_data *data; - g_variant_get (variant, "(&o)", &path); + g_return_if_fail (!config->path); - /* Replace the old path (if any) of proxy config with the new one returned - * from CreateProxyConfiguration() DBus method on pacrunner. - */ - for (iter = g_list_first (priv->remove); iter; iter = g_list_next (iter)) { - struct remove_data *r = iter->data; - if (g_strcmp0 (priv->iface, r->iface) == 0) { - g_free (r->path); - r->path = g_strdup (path); - found = TRUE; - break; - } - } + variant = g_dbus_proxy_call_finish (proxy, res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + config_unref (config); + return; + } + + self = NM_PACRUNNER_MANAGER (config->manager); + priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - if (!found) { - data = g_malloc0 (sizeof (struct remove_data)); - data->iface = g_strdup (priv->iface); - data->path = g_strdup (path); - priv->remove = g_list_append (priv->remove, data); - _LOGD ("proxy config sent to pacrunner"); + if (!variant) + _LOG2D (config, "sending failed: %s", error->message); + else { + g_variant_get (variant, "(&o)", &path); + + config->path = g_strdup (path); + _LOG2D (config, "sent"); + + if (config->removed) { + g_dbus_proxy_call (priv->pacrunner, + "DestroyProxyConfiguration", + g_variant_new ("(o)", config->path), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + priv->pacrunner_cancellable, + (GAsyncReadyCallback) pacrunner_remove_done, + config); } } + config_unref (config); } static void -send_pacrunner_proxy_data (NMPacrunnerManager *self, GVariant *pacrunner_manager_args) +pacrunner_send_config (NMPacrunnerManager *self, Config *config) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - if (!pacrunner_manager_args) - return; + if (priv->pacrunner) { + _LOG2T (config, "sending..."); + + config_ref (config); + g_clear_pointer (&config->path, g_free); - if (priv->pacrunner) g_dbus_proxy_call (priv->pacrunner, "CreateProxyConfiguration", - pacrunner_manager_args, - G_DBUS_CALL_FLAGS_NONE, + config->args, + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, - NULL, - (GAsyncReadyCallback) pacrunner_send_done, - self); + priv->pacrunner_cancellable, + (GAsyncReadyCallback) pacrunner_send_done, + config); + } } static void -name_owner_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) +name_owner_changed (NMPacrunnerManager *self) { - NMPacrunnerManager *self = NM_PACRUNNER_MANAGER (user_data); NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); gs_free char *owner = NULL; GList *iter = NULL; - owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); + owner = g_dbus_proxy_get_name_owner (priv->pacrunner); if (owner) { - _LOGD ("pacrunner appeared as %s", owner); - for (iter = g_list_first(priv->args); iter; iter = g_list_next(iter)) { - send_pacrunner_proxy_data (self, iter->data); - } + _LOGD ("name owner appeared (%s)", owner); + for (iter = g_list_first (priv->configs); iter; iter = g_list_next (iter)) + pacrunner_send_config (self, iter->data); } else { - _LOGD ("pacrunner disappeared"); + _LOGD ("name owner disappeared"); } } static void +name_owner_changed_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + name_owner_changed (user_data); +} + +static void pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NMPacrunnerManager *self = user_data; @@ -289,7 +332,8 @@ pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) nm_clear_g_cancellable (&priv->pacrunner_cancellable); g_signal_connect (priv->pacrunner, "notify::g-name-owner", - G_CALLBACK (name_owner_changed), self); + G_CALLBACK (name_owner_changed_cb), self); + name_owner_changed (self); } /** @@ -297,10 +341,18 @@ pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) * @self: the #NMPacrunnerManager * @iface: the iface for the connection or %NULL * @proxy_config: proxy config of the connection - * @ip4_config: IP4 config of the connection - * @ip6_config: IP6 config of the connection + * @ip4_config: IP4 config of the connection to extract domain info from + * @ip6_config: IP6 config of the connection to extract domain info from + * + * Returns: a #NMPacrunnerCallId call id. The function cannot + * fail and always returns a non NULL pointer. The call-id may + * be used to remove the configuration later via nm_pacrunner_manager_remove(). + * Note that the call-id does not keep the @self instance alive. + * If you plan to remove the configuration later, you must keep + * the instance alive long enough. You can remove the configuration + * at most once using this call call-id. */ -void +NMPacrunnerCallId * nm_pacrunner_manager_send (NMPacrunnerManager *self, const char *iface, NMProxyConfig *proxy_config, @@ -311,10 +363,11 @@ nm_pacrunner_manager_send (NMPacrunnerManager *self, NMProxyConfigMethod method; NMPacrunnerManagerPrivate *priv; GVariantBuilder proxy_data; - GVariant *pacrunner_manager_args; + GPtrArray *domains; + Config *config; - g_return_if_fail (NM_IS_PACRUNNER_MANAGER (self)); - g_return_if_fail (proxy_config); + g_return_val_if_fail (NM_IS_PACRUNNER_MANAGER (self), NULL); + g_return_val_if_fail (proxy_config, NULL); priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); @@ -343,80 +396,133 @@ nm_pacrunner_manager_send (NMPacrunnerManager *self, g_variant_new_string ("direct")); } - priv->domains = g_ptr_array_new_with_free_func (g_free); /* Extract stuff from configs */ - add_proxy_config (self, &proxy_data, proxy_config); + add_proxy_config (&proxy_data, proxy_config); - if (ip4_config) - add_ip4_config (self, &proxy_data, ip4_config); - if (ip6_config) - add_ip6_config (self, &proxy_data, ip6_config); + if (ip4_config || ip6_config) { + domains = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (priv->domains, NULL); - strv = (char **) g_ptr_array_free (priv->domains, (priv->domains->len == 1)); + if (ip4_config) + get_ip4_domains (domains, ip4_config); + if (ip6_config) + get_ip6_domains (domains, ip6_config); - if (strv) { - g_variant_builder_add (&proxy_data, "{sv}", - "Domains", - g_variant_new_strv ((const char *const *) strv, -1)); - g_strfreev (strv); + g_ptr_array_add (domains, NULL); + strv = (char **) g_ptr_array_free (domains, (domains->len == 1)); + + if (strv) { + g_variant_builder_add (&proxy_data, "{sv}", + "Domains", + g_variant_new_strv ((const char *const *) strv, -1)); + g_strfreev (strv); + } } - pacrunner_manager_args = g_variant_ref_sink (g_variant_new ("(a{sv})", &proxy_data)); - priv->args = g_list_append (priv->args, pacrunner_manager_args); + config = config_new (self, g_variant_new ("(a{sv})", &proxy_data)); + priv->configs = g_list_append (priv->configs, config); - /* Send if pacrunner is available on Bus, otherwise - * argument has already been appended above to be + { + gs_free char *args_str = NULL; + + _LOG2D (config, "send: new config %s", + (args_str = g_variant_print (config->args, FALSE))); + } + + /* Send if pacrunner is available on bus, otherwise + * config has already been appended above to be * sent when pacrunner appears. */ - send_pacrunner_proxy_data (self, pacrunner_manager_args); + pacrunner_send_config (self, config); + + return config; } static void -pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data) +pacrunner_remove_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { - /* @self may be a dangling pointer. However, we don't use it as the - * logging macro below does not dereference @self. */ - NMPacrunnerManager *self = user_data; + Config *config = user_data; + NMPacrunnerManager *self; gs_free_error GError *error = NULL; gs_unref_variant GVariant *ret = NULL; - ret = g_dbus_proxy_call_finish ((GDBusProxy *) source, res, &error); + ret = g_dbus_proxy_call_finish (proxy, res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + config_unref (config); + return; + } + + self = NM_PACRUNNER_MANAGER (config->manager); if (!ret) - _LOGD ("Couldn't remove proxy config from pacrunner: %s", error->message); + _LOG2D (config, "remove failed: %s", error->message); else - _LOGD ("Successfully removed proxy config from pacrunner"); + _LOG2D (config, "removed"); + + config_unref (config); } /** * nm_pacrunner_manager_remove: * @self: the #NMPacrunnerManager - * @iface: the iface for the connection to be removed - * from pacrunner + * @call_id: the call-id obtained from nm_pacrunner_manager_send() */ void -nm_pacrunner_manager_remove (NMPacrunnerManager *self, const char *iface) +nm_pacrunner_manager_remove (NMPacrunnerManager *self, NMPacrunnerCallId *call_id) { - NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + NMPacrunnerManagerPrivate *priv; + Config *config; GList *list; - for (list = g_list_first(priv->remove); list; list = g_list_next(list)) { - struct remove_data *data = list->data; - if (g_strcmp0 (data->iface, iface) == 0) { - if (priv->pacrunner && data->path) - g_dbus_proxy_call (priv->pacrunner, - "DestroyProxyConfiguration", - g_variant_new ("(o)", data->path), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback) pacrunner_remove_done, - self); - break; + g_return_if_fail (NM_IS_PACRUNNER_MANAGER (self)); + g_return_if_fail (call_id); + + config = call_id; + priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + + _LOG2T (config, "removing..."); + + list = g_list_find (priv->configs, config); + if (!list) + g_return_if_reached (); + + if (priv->pacrunner) { + if (!config->path) { + /* send() failed or is still pending. Mark the item as + * removed, so that we ask pacrunner to drop it when the + * send() completes. + */ + config->removed = TRUE; + config_unref (config); + } else { + g_dbus_proxy_call (priv->pacrunner, + "DestroyProxyConfiguration", + g_variant_new ("(o)", config->path), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + priv->pacrunner_cancellable, + (GAsyncReadyCallback) pacrunner_remove_done, + config); } - } + } else + config_unref (config); + priv->configs = g_list_delete_link (priv->configs, list); +} + +gboolean +nm_pacrunner_manager_remove_clear (NMPacrunnerManager *self, + NMPacrunnerCallId **p_call_id) +{ + g_return_val_if_fail (p_call_id, FALSE); + + /* if we have no call-id, allow for %NULL */ + g_return_val_if_fail ((!self && !*p_call_id) || NM_IS_PACRUNNER_MANAGER (self), FALSE); + + if (!*p_call_id) + return FALSE; + nm_pacrunner_manager_remove (self, + g_steal_pointer (p_call_id)); + return TRUE; } /*****************************************************************************/ @@ -445,16 +551,11 @@ dispose (GObject *object) NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE ((NMPacrunnerManager *) object); g_clear_pointer (&priv->iface, g_free); - nm_clear_g_cancellable (&priv->pacrunner_cancellable); - g_clear_object (&priv->pacrunner); - g_list_free_full (priv->args, (GDestroyNotify) g_variant_unref); - priv->args = NULL; - - g_list_free_full (priv->remove, (GDestroyNotify) remove_data_destroy); - priv->remove = NULL; + g_list_free_full (priv->configs, (GDestroyNotify) config_unref); + priv->configs = NULL; G_OBJECT_CLASS (nm_pacrunner_manager_parent_class)->dispose (object); } diff --git a/src/nm-pacrunner-manager.h b/src/nm-pacrunner-manager.h index 99e85115..3080c4f5 100644 --- a/src/nm-pacrunner-manager.h +++ b/src/nm-pacrunner-manager.h @@ -15,7 +15,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + * Copyright 2016 Atul Anand <atulhjp@gmail.com>. + * Copyright 2016 - 2017 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_PACRUNNER_MANAGER_H__ @@ -30,16 +31,22 @@ typedef struct _NMPacrunnerManagerClass NMPacrunnerManagerClass; +typedef struct _NMPacrunnerCallId NMPacrunnerCallId; + GType nm_pacrunner_manager_get_type (void); NMPacrunnerManager *nm_pacrunner_manager_get (void); -void nm_pacrunner_manager_send (NMPacrunnerManager *self, - const char *iface, - NMProxyConfig *proxy_config, - NMIP4Config *ip4_config, - NMIP6Config *ip6_config); +NMPacrunnerCallId *nm_pacrunner_manager_send (NMPacrunnerManager *self, + const char *iface, + NMProxyConfig *proxy_config, + NMIP4Config *ip4_config, + NMIP6Config *ip6_config); + +void nm_pacrunner_manager_remove (NMPacrunnerManager *self, + NMPacrunnerCallId *call_id); -void nm_pacrunner_manager_remove (NMPacrunnerManager *self, const char *iface); +gboolean nm_pacrunner_manager_remove_clear (NMPacrunnerManager *self, + NMPacrunnerCallId **p_call_id); #endif /* __NETWORKMANAGER_PACRUNNER_MANAGER_H__ */ diff --git a/src/nm-policy.c b/src/nm-policy.c index a2ff2945..7c74a6b4 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -47,6 +47,8 @@ #include "settings/nm-settings-connection.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" +#include "nm-config.h" +#include "nm-netns.h" /*****************************************************************************/ @@ -61,6 +63,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMPolicy, typedef struct { NMManager *manager; + NMNetns *netns; NMFirewallManager *firewall_manager; GSList *pending_activation_checks; @@ -68,8 +71,6 @@ typedef struct { GSList *pending_secondaries; - gulong fw_started_id; - NMSettings *settings; NMDevice *default_device4, *activating_device4; @@ -85,9 +86,12 @@ typedef struct { guint schedule_activate_all_id; /* idle handler for schedule_activate_all(). */ + NMPolicyHostnameMode hostname_mode; char *orig_hostname; /* hostname at NM start time */ char *cur_hostname; /* hostname we want to assign */ - gboolean hostname_changed; /* TRUE if NM ever set the hostname */ + char *last_hostname; /* last hostname NM set (to detect if someone else changed it in the meanwhile) */ + gboolean changing_hostname; /* hostname set operation still in progress */ + gboolean dhcp_hostname; /* current hostname was set from dhcp */ GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */ } NMPolicyPrivate; @@ -123,7 +127,7 @@ _PRIV_TO_SELF (NMPolicyPrivate *priv) #define _NMLOG_PREFIX_NAME "policy" #define _NMLOG(level, domain, ...) \ G_STMT_START { \ - nm_log ((level), (domain), \ + nm_log ((level), (domain), NULL, NULL, \ "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME": " \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ @@ -369,7 +373,7 @@ get_best_ip4_device (NMPolicy *self, gboolean fully_activated) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - return nm_default_route_manager_ip4_get_best_device (nm_default_route_manager_get (), + return nm_default_route_manager_ip4_get_best_device (nm_netns_get_default_route_manager (priv->netns), nm_manager_get_devices (priv->manager), fully_activated, priv->default_device4); @@ -380,12 +384,32 @@ get_best_ip6_device (NMPolicy *self, gboolean fully_activated) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - return nm_default_route_manager_ip6_get_best_device (nm_default_route_manager_get (), + return nm_default_route_manager_ip6_get_best_device (nm_netns_get_default_route_manager (priv->netns), nm_manager_get_devices (priv->manager), fully_activated, priv->default_device6); } +static gboolean +all_devices_not_active (NMPolicy *self) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + const GSList *iter = nm_manager_get_devices (priv->manager); + + while (iter != NULL) { + NMDeviceState state; + + state = nm_device_get_state (NM_DEVICE (iter->data)); + if ( state <= NM_DEVICE_STATE_DISCONNECTED + || state >= NM_DEVICE_STATE_DEACTIVATING) { + iter = g_slist_next (iter); + continue; + } + return FALSE; + } + return TRUE; +} + #define FALLBACK_HOSTNAME4 "localhost.localdomain" static void @@ -393,22 +417,76 @@ settings_set_hostname_cb (const char *hostname, gboolean result, gpointer user_data) { + NMPolicy *self = NM_POLICY (user_data); + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); int ret = 0; if (!result) { + _LOGT (LOGD_DNS, "set-hostname: hostname set via dbus failed, fallback to \"sethostname\""); ret = sethostname (hostname, strlen (hostname)); if (ret != 0) { int errsv = errno; - _LOGW (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", + _LOGW (LOGD_DNS, "set-hostname: couldn't set the system hostname to '%s': (%d) %s", hostname, errsv, strerror (errsv)); if (errsv == EPERM) - _LOGW (LOGD_DNS, "you should use hostnamed when systemd hardening is in effect!"); + _LOGW (LOGD_DNS, "set-hostname: you should use hostnamed when systemd hardening is in effect!"); } } + priv->changing_hostname = FALSE; if (!ret) - nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); + nm_dispatcher_call_hostname (NULL, NULL, NULL); + g_object_unref (self); +} + +#define HOST_NAME_BUFSIZE (HOST_NAME_MAX + 2) + +static char * +_get_hostname (NMPolicy *self, char **hostname) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + char *buf; + + g_assert (hostname && *hostname == NULL); + + /* If there is an in-progress hostname change, return + * the last hostname set as would be set soon... + */ + if (priv->changing_hostname) { + _LOGT (LOGD_DNS, "get-hostname: \"%s\" (last on set)", priv->last_hostname); + *hostname = g_strdup (priv->last_hostname); + return *hostname; + } + + /* try to get the hostname via dbus... */ + if (nm_settings_get_transient_hostname (priv->settings, hostname)) { + _LOGT (LOGD_DNS, "get-hostname: \"%s\" (from dbus)", *hostname); + return *hostname; + } + + /* ...or retrieve it by yourself */ + buf = g_malloc (HOST_NAME_BUFSIZE); + if (gethostname (buf, HOST_NAME_BUFSIZE -1) != 0) { + int errsv = errno; + + _LOGT (LOGD_DNS, "get-hostname: couldn't get the system hostname: (%d) %s", + errsv, g_strerror (errsv)); + g_free (buf); + return NULL; + } + + /* the name may be truncated... */ + buf[HOST_NAME_BUFSIZE - 1] = '\0'; + if (strlen (buf) >= HOST_NAME_BUFSIZE -1) { + _LOGT (LOGD_DNS, "get-hostname: system hostname too long: \"%s\"", buf); + g_free (buf); + return NULL; + } + + _LOGT (LOGD_DNS, "get-hostname: \"%s\"", buf); + *hostname = buf; + return *hostname; } static void @@ -417,9 +495,8 @@ _set_hostname (NMPolicy *self, const char *msg) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - char old_hostname[HOST_NAME_MAX + 1]; + gs_free char *old_hostname = NULL; const char *name; - int ret; /* The incoming hostname *can* be NULL, which will get translated to * 'localhost.localdomain' or such in the hostname policy code, but we @@ -433,25 +510,18 @@ _set_hostname (NMPolicy *self, if (new_hostname) g_clear_object (&priv->lookup_addr); - if ( priv->orig_hostname - && (priv->hostname_changed == FALSE) - && g_strcmp0 (priv->orig_hostname, new_hostname) == 0) { - /* Don't change the hostname or update DNS this is the first time we're - * trying to change the hostname, and it's not actually changing. - */ - } else if (g_strcmp0 (priv->cur_hostname, new_hostname) == 0) { - /* Don't change the hostname or update DNS if the hostname isn't actually - * going to change. - */ - } else { + /* Update the DNS only if the hostname is actually + * going to change. + */ + if (!nm_streq0 (priv->cur_hostname, new_hostname)) { g_free (priv->cur_hostname); priv->cur_hostname = g_strdup (new_hostname); - priv->hostname_changed = TRUE; /* Notify the DNS manager of the hostname change so that the domain part, if * present, can be added to the search list. */ - nm_dns_manager_set_hostname (priv->dns_manager, priv->cur_hostname); + nm_dns_manager_set_hostname (priv->dns_manager, priv->cur_hostname, + all_devices_not_active (self)); } /* Finally, set kernel hostname */ @@ -463,26 +533,26 @@ _set_hostname (NMPolicy *self, } else name = new_hostname; - old_hostname[HOST_NAME_MAX] = '\0'; - errno = 0; - ret = gethostname (old_hostname, HOST_NAME_MAX); - if (ret != 0) { - _LOGW (LOGD_DNS, "couldn't get the system hostname: (%d) %s", - errno, strerror (errno)); - } else { - /* Don't set the hostname if it isn't actually changing */ - if (nm_streq (name, old_hostname)) - return; + /* Don't set the hostname if it isn't actually changing */ + if ( _get_hostname (self, &old_hostname) + && (nm_streq (name, old_hostname))) { + _LOGT (LOGD_DNS, "set-hostname: hostname already set to '%s' (%s)", name, msg); + return; } - _LOGI (LOGD_DNS, "setting system hostname to '%s' (%s)", name, msg); + /* Keep track of the last set hostname */ + g_free (priv->last_hostname); + priv->last_hostname = g_strdup (name); + priv->changing_hostname = TRUE; + + _LOGI (LOGD_DNS, "set-hostname: set hostname to '%s' (%s)", name, msg); /* Ask NMSettings to update the transient hostname using its * systemd-hostnamed proxy */ nm_settings_set_transient_hostname (priv->settings, name, settings_set_hostname_cb, - NULL); + g_object_ref (self)); } static void @@ -490,49 +560,76 @@ lookup_callback (GObject *source, GAsyncResult *result, gpointer user_data) { - NMPolicy *self = (NMPolicy *) user_data; - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const char *hostname; - GError *error = NULL; + NMPolicy *self; + NMPolicyPrivate *priv; + gs_free char *hostname = NULL; + gs_free_error GError *error = NULL; hostname = g_resolver_lookup_by_address_finish (G_RESOLVER (source), result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - /* Don't touch policy; it may have been freed already */ - g_error_free (error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } + + self = user_data; + priv = NM_POLICY_GET_PRIVATE (self); + + g_clear_object (&priv->lookup_cancellable); if (hostname) _set_hostname (self, hostname, "from address lookup"); - else { + else _set_hostname (self, NULL, error->message); - g_error_free (error); - } - - g_clear_object (&priv->lookup_cancellable); } static void -update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) +update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const char *msg) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); char *configured_hostname = NULL; + gs_free char *temp_hostname = NULL; const char *dhcp_hostname, *p; NMIP4Config *ip4_config; NMIP6Config *ip6_config; + gboolean external_hostname = FALSE; g_return_if_fail (self != NULL); - if (priv->lookup_cancellable) { - g_cancellable_cancel (priv->lookup_cancellable); - g_clear_object (&priv->lookup_cancellable); + if (priv->hostname_mode == NM_POLICY_HOSTNAME_MODE_NONE) { + _LOGT (LOGD_DNS, "set-hostname: hostname is unmanaged"); + return; + } + + _LOGT (LOGD_DNS, "set-hostname: updating hostname (%s)", msg); + + nm_clear_g_cancellable (&priv->lookup_cancellable); + + /* Check if the hostname was set externally to NM, so that in that case + * we can avoid to fallback to the one we got when we started. + * Consider "not specific" hostnames as equal. */ + if ( _get_hostname (self, &temp_hostname) + && !nm_streq0 (temp_hostname, priv->last_hostname) + && ( nm_utils_is_specific_hostname (temp_hostname) + || nm_utils_is_specific_hostname (priv->last_hostname))) { + external_hostname = TRUE; + _LOGI (LOGD_DNS, "set-hostname: current hostname was changed outside NetworkManager: '%s'", + temp_hostname); + priv->dhcp_hostname = FALSE; + + if (!nm_streq0 (temp_hostname, priv->orig_hostname)) { + /* Update original (fallback) hostname */ + g_free (priv->orig_hostname); + if (nm_utils_is_specific_hostname (temp_hostname)) { + priv->orig_hostname = temp_hostname; + temp_hostname = NULL; + } else + priv->orig_hostname = NULL; + } } /* Hostname precedence order: * * 1) a configured hostname (from settings) * 2) automatic hostname from the default device's config (DHCP, VPN, etc) - * 3) the original hostname when NM started + * 3) the last hostname set outside NM * 4) reverse-DNS of the best device's IPv4 address * */ @@ -541,6 +638,7 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) g_object_get (G_OBJECT (priv->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL); if (configured_hostname && nm_utils_is_specific_hostname (configured_hostname)) { _set_hostname (self, configured_hostname, "from system configuration"); + priv->dhcp_hostname = FALSE; g_free (configured_hostname); return; } @@ -552,14 +650,6 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) if (!best6) best6 = get_best_ip6_device (self, TRUE); - if (!best4 && !best6) { - /* No best device; fall back to original hostname or if there wasn't - * one, 'localhost.localdomain' - */ - _set_hostname (self, priv->orig_hostname, "no default device"); - return; - } - if (best4) { NMDhcp4Config *dhcp4_config; @@ -572,10 +662,11 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) while (*p) { if (!g_ascii_isspace (*p++)) { _set_hostname (self, p-1, "from DHCPv4"); + priv->dhcp_hostname = TRUE; return; } } - _LOGW (LOGD_DNS, "DHCPv4-provided hostname '%s' looks invalid; ignoring it", + _LOGW (LOGD_DNS, "set-hostname: DHCPv4-provided hostname '%s' looks invalid; ignoring it", dhcp_hostname); } } @@ -591,17 +682,45 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) while (*p) { if (!g_ascii_isspace (*p++)) { _set_hostname (self, p-1, "from DHCPv6"); + priv->dhcp_hostname = TRUE; return; } } - _LOGW (LOGD_DNS, "DHCPv6-provided hostname '%s' looks invalid; ignoring it", + _LOGW (LOGD_DNS, "set-hostname: DHCPv6-provided hostname '%s' looks invalid; ignoring it", dhcp_hostname); } } } - /* If no automatically-configured hostname, try using the hostname from - * when NM started up. + /* If an hostname was set outside NetworkManager keep it */ + if (external_hostname) + return; + + if (priv->hostname_mode == NM_POLICY_HOSTNAME_MODE_DHCP) { + /* In dhcp hostname-mode, the hostname is updated only if it comes from + * a DHCP host-name option: if last set was from a host-name option and + * we are here than that connection is gone (with its host-name option), + * so reset the hostname to the previous value + */ + if (priv->dhcp_hostname) { + _set_hostname (self, priv->orig_hostname, "reset dhcp hostname"); + priv->dhcp_hostname = FALSE; + } + return; + } + + priv->dhcp_hostname = FALSE; + + if (!best4 && !best6) { + /* No best device; fall back to the last hostname set externally + * to NM or if there wasn't one, 'localhost.localdomain' + */ + _set_hostname (self, priv->orig_hostname, "no default device"); + return; + } + + /* If no automatically-configured hostname, try using the last hostname + * set externally to NM */ if (priv->orig_hostname) { _set_hostname (self, priv->orig_hostname, "from system startup"); @@ -672,7 +791,7 @@ get_best_ip4_config (NMPolicy *self, NMDevice **out_device, NMVpnConnection **out_vpn) { - return nm_default_route_manager_ip4_get_best_config (nm_default_route_manager_get (), + return nm_default_route_manager_ip4_get_best_config (nm_netns_get_default_route_manager (NM_POLICY_GET_PRIVATE (self)->netns), ignore_never_default, out_ip_iface, out_ac, @@ -767,7 +886,7 @@ get_best_ip6_config (NMPolicy *self, NMDevice **out_device, NMVpnConnection **out_vpn) { - return nm_default_route_manager_ip6_get_best_config (nm_default_route_manager_get (), + return nm_default_route_manager_ip6_get_best_config (nm_netns_get_default_route_manager (NM_POLICY_GET_PRIVATE (self)->netns), ignore_never_default, out_ip_iface, out_ac, @@ -903,7 +1022,7 @@ update_routing_and_dns (NMPolicy *self, gboolean force_update) update_ip6_routing (self, force_update); /* Update the system hostname */ - update_system_hostname (self, priv->default_device4, priv->default_device6); + update_system_hostname (self, priv->default_device4, priv->default_device6, "routing and dns"); nm_dns_manager_end_updates (priv->dns_manager, __func__); } @@ -960,9 +1079,8 @@ auto_activate_device (NMPolicy *self, NMPolicyPrivate *priv; NMSettingsConnection *best_connection; gs_free char *specific_object = NULL; - GPtrArray *connections; - GSList *connection_list; - guint i; + gs_free NMSettingsConnection **connections = NULL; + guint i, len; nm_assert (NM_IS_POLICY (self)); nm_assert (NM_IS_DEVICE (device)); @@ -976,21 +1094,14 @@ auto_activate_device (NMPolicy *self, if (nm_device_get_act_request (device)) return; - connection_list = nm_manager_get_activatable_connections (priv->manager); - if (!connection_list) + connections = nm_manager_get_activatable_connections (priv->manager, &len, TRUE); + if (!connections[0]) return; - connections = _nm_utils_copy_slist_to_array (connection_list, NULL, NULL); - g_slist_free (connection_list); - - /* sort is stable (which is important at this point) so that connections - * with same priority are still sorted by last-connected-timestamp. */ - g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority); - /* Find the first connection that should be auto-activated */ best_connection = NULL; - for (i = 0; i < connections->len; i++) { - NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections->pdata[i]); + for (i = 0; i < len; i++) { + NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections[i]); if (!nm_settings_connection_can_autoconnect (candidate)) continue; @@ -999,7 +1110,6 @@ auto_activate_device (NMPolicy *self, break; } } - g_ptr_array_free (connections, TRUE); if (best_connection) { GError *error = NULL; @@ -1014,6 +1124,7 @@ auto_activate_device (NMPolicy *self, specific_object, device, subject, + NM_ACTIVATION_TYPE_MANAGED, &error)) { _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: (%d) %s", nm_settings_connection_get_id (best_connection), @@ -1142,14 +1253,15 @@ hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - update_system_hostname (self, NULL, NULL); + update_system_hostname (self, NULL, NULL, "hostname changed"); } static void reset_autoconnect_all (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; if (device) { _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections on %s", @@ -1157,41 +1269,43 @@ reset_autoconnect_all (NMPolicy *self, NMDevice *device) } else _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections"); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - if (!device || nm_device_check_connection_compatible (device, iter->data)) { - nm_settings_connection_reset_autoconnect_retries (iter->data); - nm_settings_connection_set_autoconnect_blocked_reason (iter->data, NM_DEVICE_STATE_REASON_NONE); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; + + if (!device || nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) { + nm_settings_connection_reset_autoconnect_retries (connection); + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_UNBLOCKED); } } - g_slist_free (connections); } static void reset_autoconnect_for_failed_secrets (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections with failed secrets"); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; - if (nm_settings_connection_get_autoconnect_blocked_reason (connection) == NM_DEVICE_STATE_REASON_NO_SECRETS) { + if (nm_settings_connection_get_autoconnect_blocked_reason (connection) == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS) { nm_settings_connection_reset_autoconnect_retries (connection); - nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE); + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_UNBLOCKED); } } - g_slist_free (connections); } static void block_autoconnect_for_device (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; _LOGD (LOGD_DEVICE, "blocking autoconnect for all connections on %s", nm_device_get_iface (device)); @@ -1203,14 +1317,15 @@ block_autoconnect_for_device (NMPolicy *self, NMDevice *device) if (!nm_device_is_software (device)) return; - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - if (nm_device_check_connection_compatible (device, iter->data)) { - nm_settings_connection_set_autoconnect_blocked_reason (NM_SETTINGS_CONNECTION (iter->data), - NM_DEVICE_STATE_REASON_USER_REQUESTED); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; + + if (nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) { + nm_settings_connection_set_autoconnect_blocked_reason (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_BLOCKED); } } - g_slist_free (connections); } static void @@ -1278,7 +1393,8 @@ reset_connections_retries (gpointer user_data) { NMPolicy *self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; gint32 con_stamp, min_stamp, now; gboolean changed = FALSE; @@ -1286,9 +1402,9 @@ reset_connections_retries (gpointer user_data) min_stamp = 0; now = nm_utils_get_monotonic_timestamp_s (); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; con_stamp = nm_settings_connection_get_autoconnect_retry_time (connection); if (con_stamp == 0) @@ -1300,7 +1416,6 @@ reset_connections_retries (gpointer user_data) } else if (min_stamp == 0 || min_stamp > con_stamp) min_stamp = con_stamp; } - g_slist_free (connections); /* Schedule the handler again if there are some stamps left */ if (min_stamp != 0) @@ -1318,8 +1433,7 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); const char *master_device, *master_uuid_settings = NULL, *master_uuid_applied = NULL; - gs_free_slist GSList *connections = NULL; - GSList *iter; + guint i; NMActRequest *req; gboolean internal_activation = FALSE; @@ -1345,27 +1459,29 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) internal_activation = subject && nm_auth_subject_is_internal (subject); } - if (!internal_activation) - connections = nm_settings_get_connections_sorted (priv->settings); + if (!internal_activation) { + gs_free NMSettingsConnection **connections = NULL; - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *slave; - NMSettingConnection *s_slave_con; - const char *slave_master; + connections = nm_settings_get_connections_sorted (priv->settings, NULL); - slave = NM_CONNECTION (iter->data); - g_assert (slave); + for (i = 0; connections[i]; i++) { + NMConnection *slave; + NMSettingConnection *s_slave_con; + const char *slave_master; - s_slave_con = nm_connection_get_setting_connection (slave); - g_assert (s_slave_con); - slave_master = nm_setting_connection_get_master (s_slave_con); - if (!slave_master) - continue; + slave = NM_CONNECTION (connections[i]); + + s_slave_con = nm_connection_get_setting_connection (slave); + g_assert (s_slave_con); + slave_master = nm_setting_connection_get_master (s_slave_con); + if (!slave_master) + continue; - if ( !g_strcmp0 (slave_master, master_device) - || !g_strcmp0 (slave_master, master_uuid_applied) - || !g_strcmp0 (slave_master, master_uuid_settings)) - nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave)); + if ( !g_strcmp0 (slave_master, master_device) + || !g_strcmp0 (slave_master, master_uuid_applied) + || !g_strcmp0 (slave_master, master_uuid_settings)) + nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave)); + } } schedule_activate_all (self); @@ -1419,6 +1535,7 @@ activate_secondary_connections (NMPolicy *self, nm_exported_object_get_path (NM_EXPORTED_OBJECT (req)), device, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), + NM_ACTIVATION_TYPE_MANAGED, &error); if (ac) secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); @@ -1469,11 +1586,11 @@ device_state_changed (NMDevice *device, && old_state <= NM_DEVICE_STATE_ACTIVATED) { int tries = nm_settings_connection_get_autoconnect_retries (connection); - if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) { + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NO_SECRETS) { _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets", nm_settings_connection_get_id (connection)); - nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NO_SECRETS); + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS); } else if (tries != 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", nm_settings_connection_get_id (connection), tries); @@ -1528,7 +1645,7 @@ device_state_changed (NMDevice *device, update_routing_and_dns (self, FALSE); break; case NM_DEVICE_STATE_DEACTIVATING: - if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) { + if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_USER_REQUESTED) { if (!nm_device_get_autoconnect (device)) { /* The device was disconnected; block all connections on it */ block_autoconnect_for_device (self, device); @@ -1538,7 +1655,7 @@ device_state_changed (NMDevice *device, _LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s' by user request", nm_settings_connection_get_id (connection)); nm_settings_connection_set_autoconnect_blocked_reason (connection, - NM_DEVICE_STATE_REASON_USER_REQUESTED); + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_BLOCKED); } } } @@ -1548,7 +1665,8 @@ device_state_changed (NMDevice *device, /* Reset retry counts for a device's connections when carrier on; if cable * was unplugged and plugged in again, we should try to reconnect. */ - if (reason == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE) + if ( nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER + && old_state == NM_DEVICE_STATE_UNAVAILABLE) reset_autoconnect_all (self, device); if (old_state > NM_DEVICE_STATE_DISCONNECTED) @@ -1566,7 +1684,7 @@ device_state_changed (NMDevice *device, case NM_DEVICE_STATE_IP_CONFIG: /* We must have secrets if we got here. */ if (connection) - nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE); + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_UNBLOCKED); break; case NM_DEVICE_STATE_SECONDARIES: if (connection) @@ -1603,8 +1721,9 @@ device_ip4_config_changed (NMDevice *device, nm_dns_manager_begin_updates (priv->dns_manager, __func__); - /* Ignore IP config changes while the device is activating, because we'll - * catch all the changes when the device moves to ACTIVATED state. + /* We catch already all the IP events registering on the device state changes but + * the ones where the IP changes but the device state keep stable (i.e., activated): + * ignore IP config changes but when the device is in activated state. * Prevents unecessary changes to DNS information. */ if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { @@ -1616,7 +1735,7 @@ device_ip4_config_changed (NMDevice *device, } update_ip4_dns (self, priv->dns_manager); update_ip4_routing (self, TRUE); - update_system_hostname (self, priv->default_device4, priv->default_device6); + update_system_hostname (self, priv->default_device4, priv->default_device6, "ip4 conf"); } else { /* Old configs get removed immediately */ if (old_config) @@ -1638,11 +1757,12 @@ device_ip6_config_changed (NMDevice *device, nm_dns_manager_begin_updates (priv->dns_manager, __func__); - /* Ignore IP config changes while the device is activating, because we'll - * catch all the changes when the device moves to ACTIVATED state. + /* We catch already all the IP events registering on the device state changes but + * the ones where the IP changes but the device state keep stable (i.e., activated): + * ignore IP config changes but when the device is in activated state. * Prevents unecessary changes to DNS information. */ - if (!nm_device_is_activating (device)) { + if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (old_config) nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); @@ -1651,7 +1771,7 @@ device_ip6_config_changed (NMDevice *device, } update_ip6_dns (self, priv->dns_manager); update_ip6_routing (self, TRUE); - update_system_hostname (self, priv->default_device4, priv->default_device6); + update_system_hostname (self, priv->default_device4, priv->default_device6, "ip6 conf"); } else { /* Old configs get removed immediately */ if (old_config) @@ -1803,7 +1923,7 @@ static void vpn_connection_state_changed (NMVpnConnection *vpn, NMVpnConnectionState new_state, NMVpnConnectionState old_state, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, NMPolicy *self) { if (new_state == NM_VPN_CONNECTION_STATE_ACTIVATED) @@ -1831,6 +1951,7 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *self) NULL, NULL, nm_active_connection_get_subject (ac), + NM_ACTIVATION_TYPE_MANAGED, &error)) { _LOGW (LOGD_DEVICE, "VPN '%s' reconnect failed: %s", nm_settings_connection_get_id (connection), @@ -1933,13 +2054,24 @@ connection_added (NMSettings *settings, } static void -firewall_started (NMFirewallManager *manager, - gpointer user_data) +firewall_state_changed (NMFirewallManager *manager, + gboolean initialized_now, + gpointer user_data) { NMPolicy *self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); const GSList *iter; + if (initialized_now) { + /* the firewall manager was initializing, but all requests + * so fare were queued and are already sent. No need to + * re-update the firewall zone of the devices. */ + return; + } + + if (!nm_firewall_manager_get_running (manager)) + return; + /* add interface of each device to correct zone */ for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) nm_device_update_firewall_zone (iter->data); @@ -1956,15 +2088,20 @@ dns_config_changed (NMDnsManager *dns_manager, gpointer user_data) * (race in updating DNS and doing the reverse lookup). */ - /* Stop a lookup thread if any. */ - if (priv->lookup_cancellable) { - g_cancellable_cancel (priv->lookup_cancellable); - g_clear_object (&priv->lookup_cancellable); - } + nm_clear_g_cancellable (&priv->lookup_cancellable); /* Re-start the hostname lookup thread if we don't have hostname yet. */ if (priv->lookup_addr) { char *str = NULL; + gs_free char *hostname = NULL; + + /* Check if the hostname was externally set */ + if ( _get_hostname (self, &hostname) + && nm_utils_is_specific_hostname (hostname) + && !nm_streq0 (hostname, priv->last_hostname)) { + g_clear_object (&priv->lookup_addr); + return; + } _LOGD (LOGD_DNS, "restarting reverse-lookup thread for address %s", (str = g_inet_address_to_string (priv->lookup_addr))); @@ -2159,7 +2296,22 @@ static void nm_policy_init (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - + const char *hostname_mode; + + priv->netns = g_object_ref (nm_netns_get ()); + + hostname_mode = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_MAIN, + NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); + if (nm_streq0 (hostname_mode, "none")) + priv->hostname_mode = NM_POLICY_HOSTNAME_MODE_NONE; + else if (nm_streq0 (hostname_mode, "dhcp")) + priv->hostname_mode = NM_POLICY_HOSTNAME_MODE_DHCP; + else /* default - full mode */ + priv->hostname_mode = NM_POLICY_HOSTNAME_MODE_FULL; + + _LOGI (LOGD_DNS, "hostname management mode: %s", hostname_mode ? hostname_mode : "default"); priv->devices = g_hash_table_new (NULL, NULL); priv->ip6_prefix_delegations = g_array_new (FALSE, FALSE, sizeof (IP6PrefixDelegation)); g_array_set_clear_func (priv->ip6_prefix_delegations, clear_ip6_prefix_delegation); @@ -2170,20 +2322,21 @@ constructed (GObject *object) { NMPolicy *self = NM_POLICY (object); NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - char hostname[HOST_NAME_MAX + 2]; + char *hostname = NULL; /* Grab hostname on startup and use that if nothing provides one */ - memset (hostname, 0, sizeof (hostname)); - if (gethostname (&hostname[0], HOST_NAME_MAX) == 0) { + if (_get_hostname (self, &hostname)) { + /* init last_hostname */ + priv->last_hostname = hostname; + /* only cache it if it's a valid hostname */ - if (*hostname && nm_utils_is_specific_hostname (hostname)) + if (nm_utils_is_specific_hostname (hostname)) priv->orig_hostname = g_strdup (hostname); } priv->firewall_manager = g_object_ref (nm_firewall_manager_get ()); - - priv->fw_started_id = g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STARTED, - G_CALLBACK (firewall_started), self); + g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED, + G_CALLBACK (firewall_state_changed), self); priv->dns_manager = g_object_ref (nm_dns_manager_get ()); nm_dns_manager_set_initial_hostname (priv->dns_manager, priv->orig_hostname); @@ -2242,8 +2395,7 @@ dispose (GObject *object) priv->pending_secondaries = NULL; if (priv->firewall_manager) { - g_assert (priv->fw_started_id); - nm_clear_g_signal_handler (priv->firewall_manager, &priv->fw_started_id); + g_signal_handlers_disconnect_by_func (priv->firewall_manager, firewall_state_changed, self); g_clear_object (&priv->firewall_manager); } @@ -2270,6 +2422,7 @@ dispose (GObject *object) g_clear_pointer (&priv->orig_hostname, g_free); g_clear_pointer (&priv->cur_hostname, g_free); + g_clear_pointer (&priv->last_hostname, g_free); if (priv->settings) { g_signal_handlers_disconnect_by_data (priv->settings, priv); @@ -2302,6 +2455,8 @@ finalize (GObject *object) g_hash_table_unref (priv->devices); G_OBJECT_CLASS (nm_policy_parent_class)->finalize (object); + + g_object_unref (priv->netns); } static void diff --git a/src/nm-policy.h b/src/nm-policy.h index 64cac4fe..2c96e6d0 100644 --- a/src/nm-policy.h +++ b/src/nm-policy.h @@ -47,4 +47,21 @@ NMDevice *nm_policy_get_default_ip6_device (NMPolicy *policy); NMDevice *nm_policy_get_activating_ip4_device (NMPolicy *policy); NMDevice *nm_policy_get_activating_ip6_device (NMPolicy *policy); +/** + * NMPolicyHostnameMode + * @NM_POLICY_HOSTNAME_MODE_NONE: never update the transient hostname. + * @NM_POLICY_HOSTNAME_MODE_DHCP: only hostname from DHCP hostname + * options are eligible to be set as transient hostname. + * @NM_POLICY_HOSTNAME_MODE_FULL: NM will try to update the hostname looking + * to current static hostname, DHCP options, reverse IP lookup and externally + * set hostnames. + * + * NMPolicy's hostname update policy + */ +typedef enum { + NM_POLICY_HOSTNAME_MODE_NONE, + NM_POLICY_HOSTNAME_MODE_DHCP, + NM_POLICY_HOSTNAME_MODE_FULL, +} NMPolicyHostnameMode; + #endif /* __NETWORKMANAGER_POLICY_H__ */ diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c index 09a32965..e655e67c 100644 --- a/src/nm-rfkill-manager.c +++ b/src/nm-rfkill-manager.c @@ -23,7 +23,9 @@ #include "nm-rfkill-manager.h" #include <string.h> -#include <gudev/gudev.h> +#include <libudev.h> + +#include "nm-utils/nm-udev-utils.h" /*****************************************************************************/ @@ -35,7 +37,7 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - GUdevClient *client; + NMUdevClient *udev_client; /* Authoritative rfkill state (RFKILL_* enum) */ RfKillState rfkill_states[RFKILL_TYPE_MAX]; @@ -101,32 +103,32 @@ rfkill_state_to_desc (RfKillState rstate) } static Killswitch * -killswitch_new (GUdevDevice *device, RfKillType rtype) +killswitch_new (struct udev_device *device, RfKillType rtype) { Killswitch *ks; - GUdevDevice *parent = NULL, *grandparent = NULL; + struct udev_device *parent = NULL, *grandparent = NULL; const char *driver, *subsys, *parent_subsys = NULL; ks = g_malloc0 (sizeof (Killswitch)); - ks->name = g_strdup (g_udev_device_get_name (device)); - ks->seqnum = g_udev_device_get_seqnum (device); - ks->path = g_strdup (g_udev_device_get_sysfs_path (device)); + ks->name = g_strdup (udev_device_get_sysname (device)); + ks->seqnum = udev_device_get_seqnum (device); + ks->path = g_strdup (udev_device_get_syspath (device)); ks->rtype = rtype; - driver = g_udev_device_get_property (device, "DRIVER"); - subsys = g_udev_device_get_subsystem (device); + driver = udev_device_get_property_value (device, "DRIVER"); + subsys = udev_device_get_subsystem (device); /* Check parent for various attributes */ - parent = g_udev_device_get_parent (device); + parent = udev_device_get_parent (device); if (parent) { - parent_subsys = g_udev_device_get_subsystem (parent); + parent_subsys = udev_device_get_subsystem (parent); if (!driver) - driver = g_udev_device_get_property (parent, "DRIVER"); + driver = udev_device_get_property_value (parent, "DRIVER"); if (!driver) { /* Sigh; try the grandparent */ - grandparent = g_udev_device_get_parent (parent); + grandparent = udev_device_get_parent (parent); if (grandparent) - driver = g_udev_device_get_property (grandparent, "DRIVER"); + driver = udev_device_get_property_value (grandparent, "DRIVER"); } } @@ -140,10 +142,6 @@ killswitch_new (GUdevDevice *device, RfKillType rtype) || g_strcmp0 (parent_subsys, "acpi") == 0) ks->platform = TRUE; - if (grandparent) - g_object_unref (grandparent); - if (parent) - g_object_unref (parent); return ks; } @@ -196,32 +194,34 @@ recheck_killswitches (NMRfkillManager *self) /* Poll the states of all killswitches */ for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { Killswitch *ks = iter->data; - GUdevDevice *device; + struct udev_device *device; RfKillState dev_state; int sysfs_state; - device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name); - if (device) { - sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE"); - dev_state = sysfs_state_to_nm_state (sysfs_state); - - nm_log_dbg (LOGD_RFKILL, "%s rfkill%s switch %s state now %d/%u", - rfkill_type_to_desc (ks->rtype), - ks->platform ? " platform" : "", - ks->name, - sysfs_state, - dev_state); - - if (ks->platform == FALSE) { - if (dev_state > poll_states[ks->rtype]) - poll_states[ks->rtype] = dev_state; - } else { - platform_checked[ks->rtype] = TRUE; - if (dev_state > platform_states[ks->rtype]) - platform_states[ks->rtype] = dev_state; - } - g_object_unref (device); + device = udev_device_new_from_subsystem_sysname (nm_udev_client_get_udev (priv->udev_client), + "rfkill", ks->name); + if (!device) + continue; + sysfs_state = _nm_utils_ascii_str_to_int64 (udev_device_get_property_value (device, "RFKILL_STATE"), + 10, G_MININT, G_MAXINT, -1); + dev_state = sysfs_state_to_nm_state (sysfs_state); + + nm_log_dbg (LOGD_RFKILL, "%s rfkill%s switch %s state now %d/%u", + rfkill_type_to_desc (ks->rtype), + ks->platform ? " platform" : "", + ks->name, + sysfs_state, + dev_state); + + if (ks->platform == FALSE) { + if (dev_state > poll_states[ks->rtype]) + poll_states[ks->rtype] = dev_state; + } else { + platform_checked[ks->rtype] = TRUE; + if (dev_state > platform_states[ks->rtype]) + platform_states[ks->rtype] = dev_state; } + udev_device_unref (device); } /* Log and emit change signal for final rfkill states */ @@ -276,14 +276,14 @@ rfkill_type_to_enum (const char *str) } static void -add_one_killswitch (NMRfkillManager *self, GUdevDevice *device) +add_one_killswitch (NMRfkillManager *self, struct udev_device *device) { NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); const char *str_type; RfKillType rtype; Killswitch *ks; - str_type = g_udev_device_get_property (device, "RFKILL_TYPE"); + str_type = udev_device_get_property_value (device, "RFKILL_TYPE"); rtype = rfkill_type_to_enum (str_type); if (rtype == RFKILL_TYPE_UNKNOWN) return; @@ -300,12 +300,12 @@ add_one_killswitch (NMRfkillManager *self, GUdevDevice *device) } static void -rfkill_add (NMRfkillManager *self, GUdevDevice *device) +rfkill_add (NMRfkillManager *self, struct udev_device *device) { const char *name; g_return_if_fail (device != NULL); - name = g_udev_device_get_name (device); + name = udev_device_get_sysname (device); g_return_if_fail (name != NULL); if (!killswitch_find_by_name (self, name)) @@ -314,14 +314,14 @@ rfkill_add (NMRfkillManager *self, GUdevDevice *device) static void rfkill_remove (NMRfkillManager *self, - GUdevDevice *device) + struct udev_device *device) { NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); GSList *iter; const char *name; g_return_if_fail (device != NULL); - name = g_udev_device_get_name (device); + name = udev_device_get_sysname (device); g_return_if_fail (name != NULL); for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { @@ -337,22 +337,24 @@ rfkill_remove (NMRfkillManager *self, } static void -handle_uevent (GUdevClient *client, - const char *action, - GUdevDevice *device, +handle_uevent (NMUdevClient *client, + struct udev_device *device, gpointer user_data) { NMRfkillManager *self = NM_RFKILL_MANAGER (user_data); const char *subsys; + const char *action; + + action = udev_device_get_action (device); g_return_if_fail (action != NULL); /* A bit paranoid */ - subsys = g_udev_device_get_subsystem (device); + subsys = udev_device_get_subsystem (device); g_return_if_fail (!g_strcmp0 (subsys, "rfkill")); nm_log_dbg (LOGD_PLATFORM, "udev rfkill event: action '%s' device '%s'", - action, g_udev_device_get_name (device)); + action, udev_device_get_sysname (device)); if (!strcmp (action, "add")) rfkill_add (self, device); @@ -368,22 +370,31 @@ static void nm_rfkill_manager_init (NMRfkillManager *self) { NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); - const char *subsys[] = { "rfkill", NULL }; - GList *switches, *iter; - guint32 i; + struct udev_enumerate *enumerate; + struct udev_list_entry *iter; + guint i; for (i = 0; i < RFKILL_TYPE_MAX; i++) priv->rfkill_states[i] = RFKILL_UNBLOCKED; - priv->client = g_udev_client_new (subsys); - g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); + priv->udev_client = nm_udev_client_new ((const char *[]) { "rfkill", NULL }, + handle_uevent, self); + + enumerate = nm_udev_client_enumerate_new (priv->udev_client); + udev_enumerate_scan_devices (enumerate); + iter = udev_enumerate_get_list_entry (enumerate); + for (; iter; iter = udev_list_entry_get_next (iter)) { + struct udev_device *udevice; - switches = g_udev_client_query_by_subsystem (priv->client, "rfkill"); - for (iter = switches; iter; iter = g_list_next (iter)) { - add_one_killswitch (self, G_UDEV_DEVICE (iter->data)); - g_object_unref (G_UDEV_DEVICE (iter->data)); + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), + udev_list_entry_get_name (iter)); + if (!udevice) + continue; + + add_one_killswitch (self, udevice); + udev_device_unref (udevice); } - g_list_free (switches); + udev_enumerate_unref (enumerate); recheck_killswitches (self); } @@ -400,13 +411,13 @@ dispose (GObject *object) NMRfkillManager *self = NM_RFKILL_MANAGER (object); NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); - g_clear_object (&priv->client); - if (priv->killswitches) { g_slist_free_full (priv->killswitches, (GDestroyNotify) killswitch_destroy); priv->killswitches = NULL; } + priv->udev_client = nm_udev_client_unref (priv->udev_client); + G_OBJECT_CLASS (nm_rfkill_manager_parent_class)->dispose (object); } diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 344ebc46..b58cdeb0 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -63,7 +63,14 @@ typedef struct { /*****************************************************************************/ +enum { + IP4_ROUTES_CHANGED, + LAST_SIGNAL, +}; +static guint signals[LAST_SIGNAL] = { 0 }; + NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_LOG_WITH_PTR, PROP_PLATFORM, ); @@ -76,6 +83,8 @@ typedef struct { GHashTable *entries; guint gc_id; } ip4_device_routes; + + bool log_with_ptr; } NMRouteManagerPrivate; struct _NMRouteManager { @@ -93,10 +102,6 @@ G_DEFINE_TYPE (NMRouteManager, nm_route_manager, G_TYPE_OBJECT); /*****************************************************************************/ -NM_DEFINE_SINGLETON_GETTER (NMRouteManager, nm_route_manager_get, NM_TYPE_ROUTE_MANAGER); - -/*****************************************************************************/ - typedef struct { const NMPlatformVTableRoute *vt; @@ -150,11 +155,11 @@ static const VTableIP vtable_v4, vtable_v6; char __ch = __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'); \ char __prefix[30] = _NMLOG_PREFIX_NAME; \ \ - if ((self) != singleton_instance) \ + if (NM_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr) \ g_snprintf (__prefix, sizeof (__prefix), "%s%c[%p]", _NMLOG_PREFIX_NAME, __ch, (self)); \ else \ __prefix[NM_STRLEN (_NMLOG_PREFIX_NAME)] = __ch; \ - _nm_log ((level), (__domain), 0, \ + _nm_log ((level), (__domain), 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ @@ -167,7 +172,7 @@ static gboolean _ip4_device_routes_cancel (NMRouteManager *self); /*****************************************************************************/ #if NM_MORE_ASSERTS && !defined (G_DISABLE_ASSERT) -inline static void +static inline void ASSERT_route_index_valid (const VTableIP *vtable, const GArray *entries, const RouteIndex *index, gboolean unique_ifindexes) { guint i, j; @@ -371,7 +376,7 @@ _route_equals_ignoring_ifindex (const VTableIP *vtable, const NMPlatformIPXRoute r2_backup.rx.metric = (guint32) r2_metric; r2 = &r2_backup; } - return vtable->vt->route_cmp (r1, r2) == 0; + return vtable->vt->route_cmp (r1, r2, FALSE) == 0; } static NMPlatformIPXRoute * @@ -530,6 +535,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const memcpy (cur_ipx_route, cur_known_route, vtable->vt->sizeof_route); cur_ipx_route->rx.ifindex = ifindex; cur_ipx_route->rx.metric = vtable->vt->metric_normalize (cur_ipx_route->rx.metric); + nm_utils_ipx_address_clear_host_address (vtable->vt->addr_family, cur_ipx_route->rx.network_ptr, + cur_ipx_route->rx.network_ptr, cur_ipx_route->rx.plen); ipx_routes_changed = TRUE; _LOGt (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes, vtable->vt->route_to_string (cur_ipx_route, NULL, 0)); @@ -625,6 +632,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const ipx_route = VTABLE_ROUTE_INDEX (vtable, ipx_routes->entries, ipx_routes->entries->len - 1); ipx_route->rx.ifindex = ifindex; ipx_route->rx.metric = vtable->vt->metric_normalize (ipx_route->rx.metric); + nm_utils_ipx_address_clear_host_address (vtable->vt->addr_family, ipx_route->rx.network_ptr, + ipx_route->rx.network_ptr, ipx_route->rx.plen); g_array_index (ipx_routes->effective_metrics_reverse, gint64, j++) = -1; @@ -904,6 +913,9 @@ next: } } + if (vtable->vt->is_ip4 && ipx_routes_changed) + g_signal_emit (self, signals[IP4_ROUTES_CHANGED], 0); + g_free (known_routes_idx); g_free (plat_routes_idx); g_array_unref (plat_routes); @@ -967,6 +979,33 @@ nm_route_manager_route_flush (NMRouteManager *self, int ifindex) return success; } +/** + * nm_route_manager_ip4_routes_shadowed: + * @ifindex: Interface index + * + * Returns: %TRUE if some other link has a route to the same destination + * with a lower metric. + */ +gboolean +nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex) +{ + NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + RouteIndex *index = priv->ip4_routes.index; + const NMPlatformIP4Route *route; + guint i; + + for (i = 1; i < index->len; i++) { + route = (const NMPlatformIP4Route *) index->entries[i]; + + if (route->ifindex != ifindex) + continue; + if (_v4_route_dest_cmp (route, (const NMPlatformIP4Route *) index->entries[i - 1]) == 0) + return TRUE; + } + + return FALSE; +} + /*****************************************************************************/ static gboolean @@ -1167,6 +1206,10 @@ set_property (GObject *object, guint prop_id, NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); switch (prop_id) { + case PROP_LOG_WITH_PTR: + /* construct-only */ + priv->log_with_ptr = g_value_get_boolean (value); + break; case PROP_PLATFORM: /* construct-only */ priv->platform = g_value_get_object (value) ? : NM_PLATFORM_GET; @@ -1202,9 +1245,10 @@ nm_route_manager_init (NMRouteManager *self) } NMRouteManager * -nm_route_manager_new (NMPlatform *platform) +nm_route_manager_new (gboolean log_with_ptr, NMPlatform *platform) { return g_object_new (NM_TYPE_ROUTE_MANAGER, + NM_ROUTE_MANAGER_LOG_WITH_PTR, log_with_ptr, NM_ROUTE_MANAGER_PLATFORM, platform, NULL); } @@ -1251,6 +1295,13 @@ nm_route_manager_class_init (NMRouteManagerClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; + obj_properties[PROP_LOG_WITH_PTR] = + g_param_spec_boolean (NM_ROUTE_MANAGER_LOG_WITH_PTR, "", "", + TRUE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PLATFORM] = g_param_spec_object (NM_ROUTE_MANAGER_PLATFORM, "", "", NM_TYPE_PLATFORM, @@ -1258,4 +1309,11 @@ nm_route_manager_class_init (NMRouteManagerClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + signals[IP4_ROUTES_CHANGED] = + g_signal_new (NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); } diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h index d12f0256..bdf79a09 100644 --- a/src/nm-route-manager.h +++ b/src/nm-route-manager.h @@ -28,7 +28,10 @@ #define NM_IS_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ROUTE_MANAGER)) #define NM_ROUTE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass)) -#define NM_ROUTE_MANAGER_PLATFORM "platform" +#define NM_ROUTE_MANAGER_LOG_WITH_PTR "log-with-ptr" +#define NM_ROUTE_MANAGER_PLATFORM "platform" + +#define NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED "ip4-routes-changed" typedef struct _NMRouteManagerClass NMRouteManagerClass; @@ -38,9 +41,9 @@ gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, con gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync); gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex); +gboolean nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex); void nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list); -NMRouteManager *nm_route_manager_get (void); -NMRouteManager *nm_route_manager_new (NMPlatform *platform); +NMRouteManager *nm_route_manager_new (gboolean log_with_ptr, NMPlatform *platform); #endif /* __NM_ROUTE_MANAGER_H__ */ diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c index b37db362..151deec8 100644 --- a/src/nm-session-monitor.c +++ b/src/nm-session-monitor.c @@ -28,8 +28,20 @@ #include <string.h> #include <sys/stat.h> +#if defined (SESSION_TRACKING_SYSTEMD) && defined (SESSION_TRACKING_ELOGIND) +#error Cannot build both systemd-logind and elogind support +#endif + #ifdef SESSION_TRACKING_SYSTEMD #include <systemd/sd-login.h> +#define LOGIND_NAME "systemd-logind" +#endif + +#ifdef SESSION_TRACKING_ELOGIND +#include <elogind/sd-login.h> +#define LOGIND_NAME "elogind" +/* Re-Use SESSION_TRACKING_SYSTEMD as elogind substitutes systemd-login */ +#define SESSION_TRACKING_SYSTEMD 1 #endif #include "NetworkManagerUtils.h" @@ -85,7 +97,7 @@ st_sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active) status = sd_uid_get_sessions (uid, active, NULL); if (status < 0) - _LOGE ("failed to get systemd sessions for uid %d: %d", uid, status); + _LOGE ("failed to get "LOGIND_NAME" sessions for uid %d: %d", uid, status); return status > 0; } @@ -112,7 +124,7 @@ st_sd_init (NMSessionMonitor *monitor) return; if ((status = sd_login_monitor_new (NULL, &monitor->sd.monitor)) < 0) { - _LOGE ("failed to create systemd login monitor: %d", status); + _LOGE ("failed to create "LOGIND_NAME" monitor: %d", status); return; } @@ -357,7 +369,7 @@ nm_session_monitor_init (NMSessionMonitor *monitor) { #ifdef SESSION_TRACKING_SYSTEMD st_sd_init (monitor); - _LOGD ("using systemd-logind session tracking"); + _LOGD ("using "LOGIND_NAME" session tracking"); #endif #ifdef SESSION_TRACKING_CONSOLEKIT diff --git a/src/nm-sleep-monitor.c b/src/nm-sleep-monitor.c index 3be542c7..037db11b 100644 --- a/src/nm-sleep-monitor.c +++ b/src/nm-sleep-monitor.c @@ -38,13 +38,17 @@ #define USE_UPOWER 1 #define _NMLOG_PREFIX_NAME "sleep-monitor-up" -#elif defined (SUSPEND_RESUME_SYSTEMD) +#elif defined (SUSPEND_RESUME_SYSTEMD) || defined (SUSPEND_RESUME_ELOGIND) #define SUSPEND_DBUS_NAME "org.freedesktop.login1" #define SUSPEND_DBUS_PATH "/org/freedesktop/login1" #define SUSPEND_DBUS_INTERFACE "org.freedesktop.login1.Manager" #define USE_UPOWER 0 +#if defined (SUSPEND_RESUME_SYSTEMD) #define _NMLOG_PREFIX_NAME "sleep-monitor-sd" +#else +#define _NMLOG_PREFIX_NAME "sleep-monitor-el" +#endif #elif defined(SUSPEND_RESUME_CONSOLEKIT) @@ -60,7 +64,7 @@ #else -#error define one of SUSPEND_RESUME_SYSTEMD, SUSPEND_RESUME_CONSOLEKIT, or SUSPEND_RESUME_UPOWER +#error define one of SUSPEND_RESUME_SYSTEMD, SUSPEND_RESUME_ELOGIND, SUSPEND_RESUME_CONSOLEKIT, or SUSPEND_RESUME_UPOWER #endif diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index f5118398..4e8e2f98 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -30,12 +30,12 @@ /*****************************************************************************/ -inline static void +static inline void nmtst_init_with_logging (int *argc, char ***argv, const char *log_level, const char *log_domains) { __nmtst_init (argc, argv, FALSE, log_level, log_domains, NULL); } -inline static void +static inline void nmtst_init_assert_logging (int *argc, char ***argv, const char *log_level, const char *log_domains) { gboolean set_logging; @@ -54,7 +54,7 @@ nmtst_init_assert_logging (int *argc, char ***argv, const char *log_level, const #ifdef __NETWORKMANAGER_PLATFORM_H__ -inline static NMPlatformIP4Address * +static inline NMPlatformIP4Address * nmtst_platform_ip4_address (const char *address, const char *peer_address, guint plen) { static NMPlatformIP4Address addr; @@ -72,7 +72,7 @@ nmtst_platform_ip4_address (const char *address, const char *peer_address, guint return &addr; } -inline static NMPlatformIP4Address * +static inline NMPlatformIP4Address * nmtst_platform_ip4_address_full (const char *address, const char *peer_address, guint plen, int ifindex, NMIPConfigSource source, guint32 timestamp, guint32 lifetime, guint32 preferred, guint32 flags, @@ -95,7 +95,7 @@ nmtst_platform_ip4_address_full (const char *address, const char *peer_address, return addr; } -inline static NMPlatformIP6Address * +static inline NMPlatformIP6Address * nmtst_platform_ip6_address (const char *address, const char *peer_address, guint plen) { static NMPlatformIP6Address addr; @@ -110,7 +110,7 @@ nmtst_platform_ip6_address (const char *address, const char *peer_address, guint return &addr; } -inline static NMPlatformIP6Address * +static inline NMPlatformIP6Address * nmtst_platform_ip6_address_full (const char *address, const char *peer_address, guint plen, int ifindex, NMIPConfigSource source, guint32 timestamp, guint32 lifetime, guint32 preferred, guint32 flags) @@ -127,7 +127,7 @@ nmtst_platform_ip6_address_full (const char *address, const char *peer_address, return addr; } -inline static NMPlatformIP4Route * +static inline NMPlatformIP4Route * nmtst_platform_ip4_route (const char *network, guint plen, const char *gateway) { static NMPlatformIP4Route route; @@ -142,7 +142,7 @@ nmtst_platform_ip4_route (const char *network, guint plen, const char *gateway) return &route; } -inline static NMPlatformIP4Route * +static inline NMPlatformIP4Route * nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gateway, int ifindex, NMIPConfigSource source, guint metric, guint mss, @@ -161,8 +161,8 @@ nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gate return route; } -inline static NMPlatformIP6Route * -nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) +static inline NMPlatformIP6Route * +nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway, const char *pref_src) { static NMPlatformIP6Route route; @@ -172,16 +172,17 @@ nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) route.network = *nmtst_inet6_from_string (network); route.plen = plen; route.gateway = *nmtst_inet6_from_string (gateway); + route.pref_src = *nmtst_inet6_from_string (pref_src); return &route; } -inline static NMPlatformIP6Route * +static inline NMPlatformIP6Route * nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gateway, int ifindex, NMIPConfigSource source, guint metric, guint mss) { - NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway); + NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway, NULL); route->ifindex = ifindex; route->rt_source = source; @@ -191,13 +192,13 @@ nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gate return route; } -inline static int +static inline int _nmtst_platform_ip4_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data) { return nm_platform_ip4_route_cmp ((const NMPlatformIP4Route *) a, (const NMPlatformIP4Route *) b); } -inline static void +static inline void nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gsize len, gboolean ignore_order) { gsize i; @@ -217,7 +218,7 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP if (nm_platform_ip4_route_cmp (&a[i], &b[i]) != 0) { char buf[sizeof (_nm_utils_to_string_buffer)]; - g_error ("Error comparing IPv4 route[%lu]: %s vs %s", (long unsigned) i, + g_error ("Error comparing IPv4 route[%lu]: %s vs %s", (unsigned long) i, nm_platform_ip4_route_to_string (&a[i], NULL, 0), nm_platform_ip4_route_to_string (&b[i], buf, sizeof (buf))); g_assert_not_reached (); @@ -225,13 +226,13 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP } } -inline static int +static inline int _nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data) { return nm_platform_ip6_route_cmp ((const NMPlatformIP6Route *) a, (const NMPlatformIP6Route *) b); } -inline static void +static inline void nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gsize len, gboolean ignore_order) { gsize i; @@ -251,7 +252,7 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP if (nm_platform_ip6_route_cmp (&a[i], &b[i]) != 0) { char buf[sizeof (_nm_utils_to_string_buffer)]; - g_error ("Error comparing IPv6 route[%lu]: %s vs %s", (long unsigned) i, + g_error ("Error comparing IPv6 route[%lu]: %s vs %s", (unsigned long) i, nm_platform_ip6_route_to_string (&a[i], NULL, 0), nm_platform_ip6_route_to_string (&b[i], buf, sizeof (buf))); g_assert_not_reached (); @@ -264,7 +265,7 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP #ifdef __NETWORKMANAGER_IP4_CONFIG_H__ -inline static NMIP4Config * +static inline NMIP4Config * nmtst_ip4_config_clone (NMIP4Config *config) { NMIP4Config *copy = nm_ip4_config_new (-1); @@ -280,7 +281,7 @@ nmtst_ip4_config_clone (NMIP4Config *config) #ifdef __NETWORKMANAGER_IP6_CONFIG_H__ -inline static NMIP6Config * +static inline NMIP6Config * nmtst_ip6_config_clone (NMIP6Config *config) { NMIP6Config *copy = nm_ip6_config_new (-1); diff --git a/src/nm-types.h b/src/nm-types.h index c323c9a7..44b4fecb 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -46,6 +46,7 @@ typedef struct _NMProxyConfig NMProxyConfig; typedef struct _NMIP4Config NMIP4Config; typedef struct _NMIP6Config NMIP6Config; typedef struct _NMManager NMManager; +typedef struct _NMNetns NMNetns; typedef struct _NMPolicy NMPolicy; typedef struct _NMRfkillManager NMRfkillManager; typedef struct _NMPacrunnerManager NMPacrunnerManager; @@ -55,6 +56,22 @@ typedef struct _NMSleepMonitor NMSleepMonitor; typedef struct _NMLldpListener NMLldpListener; typedef struct _NMConfigDeviceStateData NMConfigDeviceStateData; +/*****************************************************************************/ + +typedef enum { + /* Do a full activation. */ + NM_ACTIVATION_TYPE_MANAGED = 0, + + /* gracefully/seamlessly take over the device. This leaves additional + * IP addresses and does not restore missing manual addresses. */ + NM_ACTIVATION_TYPE_ASSUME = 1, + + /* external activation. This device is not managed by NM, instead + * a in-memory connection is generated and NM pretends the device + * to be active, but it doesn't do anything really. */ + NM_ACTIVATION_TYPE_EXTERNAL = 2, +} NMActivationType; + typedef enum { /* In priority order; higher number == higher priority */ @@ -83,7 +100,7 @@ typedef enum { NM_IP_CONFIG_SOURCE_USER, } NMIPConfigSource; -inline static gboolean +static inline gboolean NM_IS_IP_CONFIG_SOURCE_RTPROT (NMIPConfigSource source) { return source > NM_IP_CONFIG_SOURCE_UNKNOWN && source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST; diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf index d130f7e2..6be1feb6 100644 --- a/src/org.freedesktop.NetworkManager.conf +++ b/src/org.freedesktop.NetworkManager.conf @@ -11,8 +11,8 @@ <allow send_interface="org.freedesktop.NetworkManager.SecretAgent"/> <!-- These are there because some broken policies do - <deny send_interface="..." /> (see dbus-daemon(8) for details). - This seems to override that for the known VPN plugins. + <deny send_interface="..." /> (see dbus-daemon(8) for details). + This seems to override that for the known VPN plugins. --> <allow send_destination="org.freedesktop.NetworkManager.openconnect"/> <allow send_destination="org.freedesktop.NetworkManager.openswan"/> @@ -27,6 +27,8 @@ <allow send_destination="org.freedesktop.NetworkManager.strongswan"/> <allow send_interface="org.freedesktop.NetworkManager.VPN.Plugin"/> + <allow send_destination="org.fedoraproject.FirewallD1"/> + <!-- Allow the custom name for the dnsmasq instance spawned by NM from the dns dnsmasq plugin to own it's dbus name, and for messages to be sent to it. @@ -39,7 +41,7 @@ <deny send_destination="org.freedesktop.NetworkManager"/> - <!-- Basic D-Bus API stuff --> + <!-- Basic D-Bus API stuff --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.DBus.Introspectable"/> <allow send_destination="org.freedesktop.NetworkManager" @@ -47,7 +49,7 @@ <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.DBus.ObjectManager"/> - <!-- Devices (read-only properties, no methods) --> + <!-- Devices (read-only properties, no methods) --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Device.Adsl"/> <allow send_destination="org.freedesktop.NetworkManager" @@ -83,17 +85,17 @@ <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.AccessPoint"/> - <!-- Devices (read-only, no security required) --> + <!-- Devices (read-only, no security required) --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Device.WiMax"/> - <!-- Devices (read/write, secured with PolicyKit) --> + <!-- Devices (read/write, secured with PolicyKit) --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Device.Wireless"/> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Device"/> - <!-- Core stuff (read-only properties, no methods) --> + <!-- Core stuff (read-only properties, no methods) --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Connection.Active"/> <allow send_destination="org.freedesktop.NetworkManager" @@ -107,7 +109,7 @@ <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.VPN.Connection"/> - <!-- Core stuff (read/write, secured with PolicyKit) --> + <!-- Core stuff (read/write, secured with PolicyKit) --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager"/> <allow send_destination="org.freedesktop.NetworkManager" @@ -115,13 +117,13 @@ <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Settings.Connection"/> - <!-- Agents; secured with PolicyKit. Any process can talk to - the AgentManager API, but only NetworkManager can talk - to the agents themselves. --> + <!-- Agents; secured with PolicyKit. Any process can talk to + the AgentManager API, but only NetworkManager can talk + to the agents themselves. --> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.AgentManager"/> - <!-- Root-only functions --> + <!-- Root-only functions --> <deny send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager" send_member="SetLogging"/> @@ -139,7 +141,7 @@ <deny send_destination="org.freedesktop.NetworkManager.dnsmasq"/> </policy> - <limit name="max_replies_per_connection">1024</limit> - <limit name="max_match_rules_per_connection">2048</limit> + <limit name="max_replies_per_connection">1024</limit> + <limit name="max_match_rules_per_connection">2048</limit> </busconfig> diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index b92f56ce..38706f37 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -82,13 +82,13 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) if (nm_logging_enabled (__level, __domain)) { \ char __prefix[32]; \ const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const void *const __self = (self); \ + NMPlatform *const __self = (self); \ \ - if (__self && __self != nm_platform_try_get ()) { \ + if (__self && nm_platform_get_log_with_ptr (self)) { \ g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ __p_prefix = __prefix; \ } \ - _nm_log (__level, __domain, 0, \ + _nm_log (__level, __domain, 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ @@ -573,6 +573,12 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) return !!device; } +static gboolean +link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) +{ + return TRUE; +} + static const char * link_get_udi (NMPlatform *platform, int ifindex) { @@ -633,6 +639,22 @@ link_supports_vlans (NMPlatform *platform, int ifindex) } static gboolean +link_supports_sriov (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + switch (device->link.type) { + case NM_LINK_TYPE_LOOPBACK: + return FALSE; + default: + return TRUE; + } +} + +static gboolean link_enslave (NMPlatform *platform, int master, int slave) { NMFakePlatformLink *device = link_get (platform, slave); @@ -1225,42 +1247,29 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu } static gboolean -ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss) +ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); - NMPlatformIP4Route route; + NMPlatformIP4Route rt = *route; guint i; - guint8 scope; - - g_assert (plen <= 32); - scope = gateway == 0 ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source); + rt.network = nm_utils_ip4_address_clear_host_address (rt.network, rt.plen); + rt.scope_inv = nm_platform_route_scope_inv (rt.gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK); - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source); - route.network = nm_utils_ip4_address_clear_host_address (network, plen); - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.scope_inv = nm_platform_route_scope_inv (scope); - - if (gateway) { + if (rt.gateway) { for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); guint32 gate = ntohl (item->network) >> (32 - item->plen); - guint32 host = ntohl (gateway) >> (32 - item->plen); + guint32 host = ntohl (rt.gateway) >> (32 - item->plen); - if (ifindex == item->ifindex && gate == host) + if (rt.ifindex == item->ifindex && gate == host) break; } if (i == priv->ip4_routes->len) { nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable", - route.ifindex, nm_utils_inet4_ntop (route.network, NULL), route.plen, route.metric); + rt.ifindex, nm_utils_inet4_ntop (rt.network, NULL), rt.plen, rt.metric); return FALSE; } } @@ -1268,65 +1277,58 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); - if (item->network != route.network) + if (item->network != rt.network) continue; - if (item->plen != route.plen) + if (item->plen != rt.plen) continue; - if (item->metric != metric) + if (item->metric != rt.metric) continue; - if (item->ifindex != route.ifindex) { + if (item->ifindex != rt.ifindex) { ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric); i--; continue; } - memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED); + memcpy (item, &rt, sizeof (rt)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } - g_array_append_val (priv->ip4_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED); + g_array_append_val (priv->ip4_routes, rt); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED); return TRUE; } static gboolean -ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) +ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); - NMPlatformIP6Route route; + NMPlatformIP6Route rt = *route; guint i; - metric = nm_utils_ip6_route_metric_normalize (metric); - - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source); - nm_utils_ip6_address_clear_host_address (&route.network, &network, plen); - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; + rt.metric = nm_utils_ip6_route_metric_normalize (rt.metric); + rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source); + nm_utils_ip6_address_clear_host_address (&rt.network, &rt.network, rt.plen); - if (!IN6_IS_ADDR_UNSPECIFIED(&gateway)) { + if (!IN6_IS_ADDR_UNSPECIFIED (&rt.gateway)) { for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - guint8 gate_bits = gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8); + guint8 gate_bits = rt.gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8); guint8 host_bits = item->network.s6_addr[item->plen / 8] >> (8 - item->plen % 8); - if ( ifindex == item->ifindex - && memcmp (&gateway, &item->network, item->plen / 8) == 0 + if ( rt.ifindex == item->ifindex + && memcmp (&rt.gateway, &item->network, item->plen / 8) == 0 && gate_bits == host_bits) break; } if (i == priv->ip6_routes->len) { nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable", - route.ifindex, nm_utils_inet6_ntop (&route.network, NULL), route.plen, route.metric); + rt.ifindex, nm_utils_inet6_ntop (&rt.network, NULL), rt.plen, rt.metric); return FALSE; } } @@ -1334,26 +1336,28 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network)) + if (!IN6_ARE_ADDR_EQUAL (&item->network, &rt.network)) continue; - if (item->plen != route.plen) + if (item->plen != rt.plen) continue; - if (item->metric != metric) + if (item->metric != rt.metric) continue; - if (item->ifindex != route.ifindex) { + if (item->ifindex != rt.ifindex) { ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric); i--; continue; } - memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED); + memcpy (item, &rt, sizeof (rt)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } - g_array_append_val (priv->ip6_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED); + g_array_append_val (priv->ip6_routes, rt); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED); return TRUE; } @@ -1418,7 +1422,9 @@ nm_fake_platform_setup (void) { NMPlatform *platform; - platform = g_object_new (NM_TYPE_FAKE_PLATFORM, NULL); + platform = g_object_new (NM_TYPE_FAKE_PLATFORM, + NM_PLATFORM_LOG_WITH_PTR, FALSE, + NULL); nm_platform_setup (platform); @@ -1486,11 +1492,13 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_set_mtu = link_set_mtu; + platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; + platform_class->link_supports_sriov = link_supports_sriov; platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 2c5f0897..252f054d 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -38,7 +38,7 @@ #include <linux/if_tunnel.h> #include <netlink/netlink.h> #include <netlink/msg.h> -#include <gudev/gudev.h> +#include <libudev.h> #include "nm-utils.h" #include "nm-core-internal.h" @@ -51,6 +51,7 @@ #include "wifi/wifi-utils.h" #include "wifi/wifi-utils-wext.h" #include "nm-utils/unaligned.h" +#include "nm-utils/nm-udev-utils.h" #define VLAN_FLAG_MVRP 0x8 @@ -144,13 +145,13 @@ G_STMT_START { \ char __prefix[32]; \ const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const void *const __self = (self); \ + NMPlatform *const __self = (self); \ \ - if (__self && __self != nm_platform_try_get ()) { \ + if (__self && nm_platform_get_log_with_ptr (__self)) { \ g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ __p_prefix = __prefix; \ } \ - _nm_log (__level, __domain, __errsv, \ + _nm_log (__level, __domain, __errsv, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } G_STMT_END @@ -298,7 +299,7 @@ _support_user_ipv6ll_get (void) { if (_support_user_ipv6ll_still_undecided ()) { _support_user_ipv6ll = -1; - _LOG2W ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support"); + _LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume no support"); return FALSE; } return _support_user_ipv6ll > 0; @@ -309,13 +310,11 @@ static void _support_user_ipv6ll_detect (struct nlattr **tb) { if (_support_user_ipv6ll_still_undecided ()) { - if (tb[IFLA_INET6_ADDR_GEN_MODE]) { - _support_user_ipv6ll = 1; - _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected"); - } else { - _support_user_ipv6ll = -1; - _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected"); - } + gboolean supported = !!tb[IFLA_INET6_ADDR_GEN_MODE]; + + _support_user_ipv6ll = supported ? 1 : -1; + _LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", + supported ? "detected" : "not detected"); } } @@ -1835,6 +1834,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) NMIPAddr gateway; } nh; guint32 mss; + guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0; guint32 table; if (!nlmsg_valid_hdr (nlh, sizeof (*rtm))) @@ -1848,8 +1848,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6)) goto errout; - if ( rtm->rtm_type != RTN_UNICAST - || rtm->rtm_tos != 0) + if (rtm->rtm_type != RTN_UNICAST) goto errout; err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); @@ -1943,21 +1942,34 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) mss = 0; if (tb[RTA_METRICS]) { struct nlattr *mtb[RTAX_MAX + 1]; - int i; + static struct nla_policy rtax_policy[RTAX_MAX + 1] = { + [RTAX_LOCK] = { .type = NLA_U32 }, + [RTAX_ADVMSS] = { .type = NLA_U32 }, + [RTAX_WINDOW] = { .type = NLA_U32 }, + [RTAX_CWND] = { .type = NLA_U32 }, + [RTAX_INITCWND] = { .type = NLA_U32 }, + [RTAX_INITRWND] = { .type = NLA_U32 }, + [RTAX_MTU] = { .type = NLA_U32 }, + }; - err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); + err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy); if (err < 0) goto errout; - for (i = 1; i <= RTAX_MAX; i++) { - if (mtb[i]) { - if (i == RTAX_ADVMSS) { - if (nla_len (mtb[i]) >= sizeof (uint32_t)) - mss = nla_get_u32(mtb[i]); - break; - } - } - } + if (mtb[RTAX_LOCK]) + lock = nla_get_u32 (mtb[RTAX_LOCK]); + if (mtb[RTAX_ADVMSS]) + mss = nla_get_u32 (mtb[RTAX_ADVMSS]); + if (mtb[RTAX_WINDOW]) + window = nla_get_u32 (mtb[RTAX_WINDOW]); + if (mtb[RTAX_CWND]) + cwnd = nla_get_u32 (mtb[RTAX_CWND]); + if (mtb[RTAX_INITCWND]) + initcwnd = nla_get_u32 (mtb[RTAX_INITCWND]); + if (mtb[RTAX_INITRWND]) + initrwnd = nla_get_u32 (mtb[RTAX_INITRWND]); + if (mtb[RTAX_MTU]) + mtu = nla_get_u32 (mtb[RTAX_MTU]); } /*****************************************************************/ @@ -1982,12 +1994,31 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (is_v4) obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope); - if (is_v4) { - if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) + if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) { + if (is_v4) memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); + else + memcpy (&obj->ip6_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); + } + + if (!is_v4 && tb[RTA_SRC]) { + _check_addr_or_errout (tb, RTA_SRC, addr_len); + memcpy (&obj->ip6_route.src, nla_data (tb[RTA_SRC]), addr_len); + obj->ip6_route.src_plen = rtm->rtm_src_len; } obj->ip_route.mss = mss; + obj->ip_route.window = window; + obj->ip_route.cwnd = cwnd; + obj->ip_route.initcwnd = initcwnd; + obj->ip_route.initrwnd = initrwnd; + obj->ip_route.mtu = mtu; + obj->ip_route.tos = rtm->rtm_tos; + obj->ip_route.lock_window = NM_FLAGS_HAS (lock, 1 << RTAX_WINDOW); + obj->ip_route.lock_cwnd = NM_FLAGS_HAS (lock, 1 << RTAX_CWND); + obj->ip_route.lock_initcwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITCWND); + obj->ip_route.lock_initrwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITRWND); + obj->ip_route.lock_mtu = NM_FLAGS_HAS (lock, 1 << RTAX_MTU); if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) { /* we must not straight way reject cloned routes, because we might have cached @@ -2362,21 +2393,29 @@ _nl_msg_new_route (int nlmsg_type, gconstpointer gateway, guint32 metric, guint32 mss, - gconstpointer pref_src) + gconstpointer pref_src, + gconstpointer src, + guint8 src_plen, + guint8 tos, + guint32 window, + guint32 cwnd, + guint32 initcwnd, + guint32 initrwnd, + guint32 mtu, + guint32 lock) { struct nl_msg *msg; struct rtmsg rtmsg = { .rtm_family = family, - .rtm_tos = 0, + .rtm_tos = tos, .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */ .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (source), .rtm_scope = scope, .rtm_type = RTN_UNICAST, .rtm_flags = 0, .rtm_dst_len = plen, - .rtm_src_len = 0, + .rtm_src_len = src ? src_plen : 0, }; - NMIPAddr network_clean; gsize addr_len; @@ -2393,22 +2432,37 @@ _nl_msg_new_route (int nlmsg_type, addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); - nm_utils_ipx_address_clear_host_address (family, &network_clean, network, plen); - NLA_PUT (msg, RTA_DST, addr_len, &network_clean); + NLA_PUT (msg, RTA_DST, addr_len, network); + + if (src) + NLA_PUT (msg, RTA_SRC, addr_len, src); NLA_PUT_U32 (msg, RTA_PRIORITY, metric); if (pref_src) NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src); - if (mss > 0) { + if (mss || window || cwnd || initcwnd || initrwnd || mtu || lock) { struct nlattr *metrics; metrics = nla_nest_start (msg, RTA_METRICS); if (!metrics) goto nla_put_failure; - NLA_PUT_U32 (msg, RTAX_ADVMSS, mss); + if (mss) + NLA_PUT_U32 (msg, RTAX_ADVMSS, mss); + if (window) + NLA_PUT_U32 (msg, RTAX_WINDOW, window); + if (cwnd) + NLA_PUT_U32 (msg, RTAX_CWND, cwnd); + if (initcwnd) + NLA_PUT_U32 (msg, RTAX_INITCWND, initcwnd); + if (initrwnd) + NLA_PUT_U32 (msg, RTAX_INITRWND, initrwnd); + if (mtu) + NLA_PUT_U32 (msg, RTAX_MTU, mtu); + if (lock) + NLA_PUT_U32 (msg, RTAX_LOCK, lock); nla_nest_end(msg, metrics); } @@ -2452,15 +2506,15 @@ _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR * and IFA_F_NOPREFIXROUTE (they were added together). **/ - _support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */); - _LOG2D ("support: kernel-extended-ifa-flags: %ssupported", _support_kernel_extended_ifa_flags ? "" : "not "); + _support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS); + _LOG2D ("kernel-support: extended-ifa-flags: %s", _support_kernel_extended_ifa_flags ? "detected" : "not detected"); } static gboolean _support_kernel_extended_ifa_flags_get (void) { if (_support_kernel_extended_ifa_flags_still_undecided ()) { - _LOG2W ("support: kernel-extended-ifa-flags: unable to detect kernel support for handling IPv6 temporary addresses. Assume support"); + _LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support"); _support_kernel_extended_ifa_flags = 1; } return _support_kernel_extended_ifa_flags; @@ -2492,7 +2546,7 @@ typedef struct { gboolean sysctl_get_warned; GHashTable *sysctl_get_prev_values; - GUdevClient *udev_client; + NMUdevClient *udev_client; struct { /* which delayed actions are scheduled, as marked in @flags. @@ -2526,19 +2580,13 @@ struct _NMLinuxPlatformClass { G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) -static inline NMLinuxPlatformPrivate * -NM_LINUX_PLATFORM_GET_PRIVATE (const void *self) -{ - nm_assert (NM_IS_LINUX_PLATFORM (self)); - - return &(((NMLinuxPlatform *) self)->_priv); -} +#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_VOID(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM) NMPlatform * -nm_linux_platform_new (gboolean netns_support) +nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support) { return g_object_new (NM_TYPE_LINUX_PLATFORM, - NM_PLATFORM_REGISTER_SINGLETON, FALSE, + NM_PLATFORM_LOG_WITH_PTR, log_with_ptr, NM_PLATFORM_NETNS_SUPPORT, netns_support, NULL); } @@ -2546,10 +2594,7 @@ nm_linux_platform_new (gboolean netns_support) void nm_linux_platform_setup (void) { - g_object_new (NM_TYPE_LINUX_PLATFORM, - NM_PLATFORM_REGISTER_SINGLETON, TRUE, - NM_PLATFORM_NETNS_SUPPORT, FALSE, - NULL); + nm_platform_setup (nm_linux_platform_new (FALSE, FALSE)); } static void @@ -2584,23 +2629,24 @@ static void _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value) { GError *error = NULL; - char *contents, *contents_escaped; - char *value_escaped = g_strescape (value, NULL); + char *contents; + gs_free char *value_escaped = g_strescape (value, NULL); if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) { _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message); g_clear_error (&error); - } else { - g_strstrip (contents); - contents_escaped = g_strescape (contents, NULL); - if (strcmp (contents, value) == 0) - _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped); - else - _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped); - g_free (contents); - g_free (contents_escaped); + return; } - g_free (value_escaped); + + g_strstrip (contents); + if (nm_streq (contents, value)) + _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped); + else { + gs_free char *contents_escaped = g_strescape (contents, NULL); + + _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped); + } + g_free (contents); } #define _log_dbg_sysctl_set(platform, pathid, dirfd, path, value) \ @@ -2750,26 +2796,23 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char * if (prev_value) { if (strcmp (prev_value, contents) != 0) { - char *contents_escaped = g_strescape (contents, NULL); - char *prev_value_escaped = g_strescape (prev_value, NULL); + gs_free char *contents_escaped = g_strescape (contents, NULL); + gs_free char *prev_value_escaped = g_strescape (prev_value, NULL); _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped); - g_free (contents_escaped); - g_free (prev_value_escaped); g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); } } else { - char *contents_escaped = g_strescape (contents, NULL); + gs_free char *contents_escaped = g_strescape (contents, NULL); _LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped); - g_free (contents_escaped); g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); - } - if ( !priv->sysctl_get_warned - && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) { - _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`."); - priv->sysctl_get_warned = TRUE; + if ( !priv->sysctl_get_warned + && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) { + _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`."); + priv->sysctl_get_warned = TRUE; + } } } @@ -4352,18 +4395,23 @@ link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *unmanaged) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); const NMPObject *link; - GUdevDevice *udev_device = NULL; + struct udev_device *udevice = NULL; + const char *uproperty; link = nmp_cache_lookup_link (priv->cache, ifindex); - if (link) - udev_device = link->_link.udev.device; + if (!link) + return FALSE; - if (udev_device && g_udev_device_get_property (udev_device, "NM_UNMANAGED")) { - *unmanaged = g_udev_device_get_property_as_boolean (udev_device, "NM_UNMANAGED"); - return TRUE; - } + udevice = link->_link.udev.device; + if (!udevice) + return FALSE; - return FALSE; + uproperty = udev_device_get_property_value (udevice, "NM_UNMANAGED"); + if (!uproperty) + return FALSE; + + *unmanaged = nm_udev_utils_property_as_boolean (uproperty); + return TRUE; } static gboolean @@ -4463,10 +4511,10 @@ link_get_udi (NMPlatform *platform, int ifindex) || !obj->_link.netlink.is_in_netlink || !obj->_link.udev.device) return NULL; - return g_udev_device_get_sysfs_path (obj->_link.udev.device); + return udev_device_get_syspath (obj->_link.udev.device); } -static GObject * +static struct udev_device * link_get_udev_device (NMPlatform *platform, int ifindex) { const NMPObject *obj_cache; @@ -4477,7 +4525,7 @@ link_get_udev_device (NMPlatform *platform, int ifindex) * appears invisible via other platform functions. */ obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex); - return obj_cache ? (GObject *) obj_cache->_link.udev.device : NULL; + return obj_cache ? obj_cache->_link.udev.device : NULL; } static NMPlatformError @@ -4556,6 +4604,30 @@ link_supports_vlans (NMPlatform *platform, int ifindex) return nmp_utils_ethtool_supports_vlans (ifindex); } +static gboolean +link_supports_sriov (NMPlatform *platform, int ifindex) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + nm_auto_close int dirfd = -1; + char ifname[IFNAMSIZ]; + int total = -1; + + if (!nm_platform_netns_push (platform, &netns)) + return FALSE; + + dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname); + if (dirfd < 0) + return FALSE; + + total = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_totalvfs"), + -1); + + return total > 0; +} + static NMPlatformError link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) { @@ -4647,6 +4719,71 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static gboolean +link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + nm_auto_close int dirfd = -1; + int total, current; + char ifname[IFNAMSIZ]; + char buf[64]; + + _LOGD ("link: change %d: num VFs: %u", ifindex, num_vfs); + + if (!nm_platform_netns_push (platform, &netns)) + return FALSE; + + dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname); + if (!dirfd) + return FALSE; + + total = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_totalvfs"), + -1); + if (total < 1) + return FALSE; + if (num_vfs > total) { + _LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs); + num_vfs = total; + } + + current = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + -1); + if (current == num_vfs) + return TRUE; + + if (current != 0) { + /* We need to destroy all other VFs before changing the value */ + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + "0")) { + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", 0, strerror (errno)); + return FALSE; + } + if (num_vfs == 0) + return TRUE; + } + + /* Finally, set the desired value */ + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + nm_sprintf_buf (buf, "%d", num_vfs))) { + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno)); + return FALSE; + } + + return TRUE; +} + static char * link_get_physical_port_id (NMPlatform *platform, int ifindex) { @@ -4691,7 +4828,7 @@ vlan_add (NMPlatform *platform, vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL; _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X", - name, parent, vlan_id, (unsigned int) vlan_flags); + name, parent, vlan_id, (unsigned) vlan_flags); nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, @@ -5153,7 +5290,7 @@ _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map, if (current_n_map) { if (is_ingress_map) { /* For the ingress-map, there are only 8 entries (0 to 7). - * When the user requests to reset all entires, we don't actually + * When the user requests to reset all entries, we don't actually * need the cached entries, we can just explicitly clear all possible * ones. * @@ -5456,34 +5593,17 @@ wifi_get_wifi_data (NMPlatform *platform, int ifindex) wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex)); pllink = nm_platform_link_get (platform, ifindex); - /* @wifi_data contains an interface name which is used for WEXT queries. If - * the interface name changes we should at least replace the name in the - * existing structure; but probably a complete reinitialization is better - * because during the initial creation there can be race conditions while - * the interface is renamed by udev. - */ - if (wifi_data && pllink) { - if (!nm_streq (wifi_utils_get_iface (wifi_data), pllink->name)) { - _LOGD ("wifi: interface %s renamed to %s, dropping old data for ifindex %d", - wifi_utils_get_iface (wifi_data), - pllink->name, - ifindex); - g_hash_table_remove (priv->wifi_data, GINT_TO_POINTER (ifindex)); - wifi_data = NULL; - } - } - if (!wifi_data) { if (pllink) { if (pllink->type == NM_LINK_TYPE_WIFI) - wifi_data = wifi_utils_init (pllink->name, ifindex, TRUE); + wifi_data = wifi_utils_init (ifindex, TRUE); else if (pllink->type == NM_LINK_TYPE_OLPC_MESH) { /* The kernel driver now uses nl80211, but we force use of WEXT because * the cfg80211 interactions are not quite ready to support access to * mesh control through nl80211 just yet. */ #if HAVE_WEXT - wifi_data = wifi_wext_init (pllink->name, ifindex, FALSE); + wifi_data = wifi_wext_init (ifindex, FALSE); #endif } @@ -5905,53 +6025,85 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags); } +static guint32 +ip_route_get_lock_flag (NMPlatformIPRoute *route) +{ + return (((guint32) route->lock_window) << RTAX_WINDOW) + | (((guint32) route->lock_cwnd) << RTAX_CWND) + | (((guint32) route->lock_initcwnd) << RTAX_INITCWND) + | (((guint32) route->lock_initrwnd) << RTAX_INITRWND) + | (((guint32) route->lock_mtu) << RTAX_MTU); +} + static gboolean -ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss) +ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + in_addr_t network; + + network = nm_utils_ip4_address_clear_host_address (route->network, route->plen); + /* FIXME: take the scope from route into account */ nlmsg = _nl_msg_new_route (RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, AF_INET, - ifindex, - source, - gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, + route->ifindex, + route->rt_source, + route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, &network, - plen, - &gateway, - metric, - mss, - pref_src ? &pref_src : NULL); - - nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + route->plen, + &route->gateway, + route->metric, + route->mss, + route->pref_src ? &route->pref_src : NULL, + NULL, + 0, + route->tos, + route->window, + route->cwnd, + route->initcwnd, + route->initrwnd, + route->mtu, + ip_route_get_lock_flag ((NMPlatformIPRoute *) route)); + + nmp_object_stackinit_id_ip4_route (&obj_id, route->ifindex, network, route->plen, route->metric); return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean -ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) +ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct in6_addr network; + nm_utils_ip6_address_clear_host_address (&network, &route->network, route->plen); + + /* FIXME: take the scope from route into account */ nlmsg = _nl_msg_new_route (RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, AF_INET6, - ifindex, - source, - !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, + route->ifindex, + route->rt_source, + IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, &network, - plen, - &gateway, - metric, - mss, - NULL); - - nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); + route->plen, + &route->gateway, + route->metric, + route->mss, + !IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL, + !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? &route->src : NULL, + route->src_plen, + route->tos, + route->window, + route->cwnd, + route->initcwnd, + route->initrwnd, + route->mtu, + ip_route_get_lock_flag ((NMPlatformIPRoute *) route)); + + nmp_object_stackinit_id_ip6_route (&obj_id, route->ifindex, &network, route->plen, route->metric); return do_add_addrroute (platform, &obj_id, nlmsg); } @@ -5962,6 +6114,8 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p nm_auto_nlmsg struct nl_msg *nlmsg = NULL; NMPObject obj_id; + network = nm_utils_ip4_address_clear_host_address (network, plen); + nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); if (metric == 0) { @@ -6004,7 +6158,16 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p NULL, metric, 0, - NULL); + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); if (!nlmsg) return FALSE; @@ -6019,6 +6182,8 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu metric = nm_utils_ip6_route_metric_normalize (metric); + nm_utils_ip6_address_clear_host_address (&network, &network, plen); + nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, AF_INET6, @@ -6030,7 +6195,16 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu NULL, metric, 0, - NULL); + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); if (!nlmsg) return FALSE; @@ -6423,14 +6597,16 @@ after_read: /*****************************************************************************/ static void -cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_device) +cache_update_link_udev (NMPlatform *platform, + int ifindex, + struct udev_device *udevice) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); nm_auto_nmpobj NMPObject *obj_cache = NULL; gboolean was_visible; NMPCacheOpsType cache_op; - cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udev_device, &obj_cache, &was_visible, cache_pre_hook, platform); + cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udevice, &obj_cache, &was_visible, cache_pre_hook, platform); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { nm_auto_pop_netns NMPNetns *netns = NULL; @@ -6443,55 +6619,58 @@ cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_dev static void udev_device_added (NMPlatform *platform, - GUdevDevice *udev_device) + struct udev_device *udevice) { const char *ifname; + const char *ifindex_s; int ifindex; - ifname = g_udev_device_get_name (udev_device); + ifname = udev_device_get_sysname (udevice); if (!ifname) { _LOGD ("udev-add: failed to get device's interface"); return; } - if (!g_udev_device_get_property (udev_device, "IFINDEX")) { + ifindex_s = udev_device_get_property_value (udevice, "IFINDEX"); + if (!ifindex_s) { _LOGW ("udev-add[%s]failed to get device's ifindex", ifname); return; } - ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); + ifindex = _nm_utils_ascii_str_to_int64 (ifindex_s, 10, 1, G_MAXINT, 0); if (ifindex <= 0) { _LOGW ("udev-add[%s]: retrieved invalid IFINDEX=%d", ifname, ifindex); return; } - if (!g_udev_device_get_sysfs_path (udev_device)) { + if (!udev_device_get_syspath (udevice)) { _LOGD ("udev-add[%s,%d]: couldn't determine device path; ignoring...", ifname, ifindex); return; } _LOGT ("udev-add[%s,%d]: device added", ifname, ifindex); - cache_update_link_udev (platform, ifindex, udev_device); + cache_update_link_udev (platform, ifindex, udevice); } static gboolean -_udev_device_removed_match_link (const NMPObject *obj, gpointer udev_device) +_udev_device_removed_match_link (const NMPObject *obj, gpointer udevice) { - return obj->_link.udev.device == udev_device; + return obj->_link.udev.device == udevice; } static void udev_device_removed (NMPlatform *platform, - GUdevDevice *udev_device) + struct udev_device *udevice) { + const char *ifindex_s; int ifindex = 0; - if (g_udev_device_get_property (udev_device, "IFINDEX")) - ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); - else { + ifindex_s = udev_device_get_property_value (udevice, "IFINDEX"); + ifindex = _nm_utils_ascii_str_to_int64 (ifindex_s, 10, 1, G_MAXINT, 0); + if (ifindex <= 0) { const NMPObject *obj; obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, - 0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udev_device); + 0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udevice); if (obj) ifindex = obj->link.ifindex; } @@ -6504,9 +6683,8 @@ udev_device_removed (NMPlatform *platform, } static void -handle_udev_event (GUdevClient *client, - const char *action, - GUdevDevice *udev_device, +handle_udev_event (NMUdevClient *udev_client, + struct udev_device *udevice, gpointer user_data) { nm_auto_pop_netns NMPNetns *netns = NULL; @@ -6514,26 +6692,27 @@ handle_udev_event (GUdevClient *client, const char *subsys; const char *ifindex; guint64 seqnum; + const char *action; + + action = udev_device_get_action (udevice); + g_return_if_fail (action); - g_return_if_fail (action != NULL); + subsys = udev_device_get_subsystem (udevice); + g_return_if_fail (nm_streq0 (subsys, "net")); if (!nm_platform_netns_push (platform, &netns)) return; - /* A bit paranoid */ - subsys = g_udev_device_get_subsystem (udev_device); - g_return_if_fail (!g_strcmp0 (subsys, "net")); - - ifindex = g_udev_device_get_property (udev_device, "IFINDEX"); - seqnum = g_udev_device_get_seqnum (udev_device); + ifindex = udev_device_get_property_value (udevice, "IFINDEX"); + seqnum = udev_device_get_seqnum (udevice); _LOGD ("UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, - action, subsys, g_udev_device_get_name (udev_device), + action, subsys, udev_device_get_sysname (udevice), ifindex ? ifindex : "unknown", seqnum); - if (!strcmp (action, "add") || !strcmp (action, "move")) - udev_device_added (platform, udev_device); - if (!strcmp (action, "remove")) - udev_device_removed (platform, udev_device); + if (NM_IN_STRSET (action, "add", "move")) + udev_device_added (platform, udevice); + else if (NM_IN_STRSET (action, "remove")) + udev_device_removed (platform, udevice); } /*****************************************************************************/ @@ -6554,8 +6733,10 @@ nm_linux_platform_init (NMLinuxPlatform *self) priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData)); priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit); - if (use_udev) - priv->udev_client = g_udev_client_new ((const char *[]) { "net", NULL }); + if (use_udev) { + priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, + handle_udev_event, self); + } } static void @@ -6638,24 +6819,30 @@ constructed (GObject *_object) /* Set up udev monitoring */ if (priv->udev_client) { - GUdevEnumerator *enumerator; - GList *devices, *iter; - - g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform); + struct udev_enumerate *enumerator; + struct udev_list_entry *devices, *l; /* And read initial device list */ - enumerator = g_udev_enumerator_new (priv->udev_client); - g_udev_enumerator_add_match_subsystem (enumerator, "net"); + enumerator = nm_udev_client_enumerate_new (priv->udev_client); + + udev_enumerate_add_match_is_initialized (enumerator); - g_udev_enumerator_add_match_is_initialized (enumerator); + udev_enumerate_scan_devices (enumerator); - devices = g_udev_enumerator_execute (enumerator); - for (iter = devices; iter; iter = g_list_next (iter)) { - udev_device_added (platform, G_UDEV_DEVICE (iter->data)); - g_object_unref (G_UDEV_DEVICE (iter->data)); + devices = udev_enumerate_get_list_entry (enumerator); + for (l = devices; l; l = udev_list_entry_get_next (l)) { + struct udev_device *udevice; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator), + udev_list_entry_get_name (l)); + if (!udevice) + continue; + + udev_device_added (platform, udevice); + udev_device_unref (udevice); } - g_list_free (devices); - g_object_unref (enumerator); + + udev_enumerate_unref (enumerator); } } @@ -6675,11 +6862,6 @@ dispose (GObject *object) g_clear_pointer (&priv->prune_candidates, g_hash_table_unref); - if (priv->udev_client) { - g_signal_handlers_disconnect_by_func (priv->udev_client, G_CALLBACK (handle_udev_event), platform); - g_clear_object (&priv->udev_client); - } - G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object); } @@ -6705,6 +6887,8 @@ finalize (GObject *object) g_hash_table_destroy (priv->sysctl_get_prev_values); } + priv->udev_client = nm_udev_client_unref (priv->udev_client); + G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object); } @@ -6750,6 +6934,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_set_mtu = link_set_mtu; + platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; @@ -6758,6 +6943,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; + platform_class->link_supports_sriov = link_supports_sriov; platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; diff --git a/src/platform/nm-linux-platform.h b/src/platform/nm-linux-platform.h index b3272aae..6b66ea69 100644 --- a/src/platform/nm-linux-platform.h +++ b/src/platform/nm-linux-platform.h @@ -35,7 +35,7 @@ typedef struct _NMLinuxPlatformClass NMLinuxPlatformClass; GType nm_linux_platform_get_type (void); -NMPlatform *nm_linux_platform_new (gboolean netns_support); +NMPlatform *nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support); void nm_linux_platform_setup (void); diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 65fb01bc..b664e8a9 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -32,6 +32,7 @@ #include <linux/version.h> #include <linux/rtnetlink.h> #include <fcntl.h> +#include <libudev.h> #include "nm-utils.h" #include "nm-setting-wired.h" @@ -42,8 +43,8 @@ * utils ******************************************************************/ -extern char *if_indextoname (unsigned int __ifindex, char *__ifname); -unsigned int if_nametoindex (const char *__ifname); +extern char *if_indextoname (unsigned __ifindex, char *__ifname); +unsigned if_nametoindex (const char *__ifname); const char * nmp_utils_if_indextoname (int ifindex, char *out_ifname/*IFNAMSIZ*/) @@ -440,7 +441,7 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex, return TRUE; nm_log_dbg (LOGD_PLATFORM, "setting Wake-on-LAN options 0x%x, password '%s'", - (unsigned int) wol, wol_password); + (unsigned) wol, wol_password); wol_info.cmd = ETHTOOL_SWOL; wol_info.wolopts = 0; @@ -520,35 +521,33 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) ******************************************************************/ const char * -nmp_utils_udev_get_driver (GUdevDevice *device) +nmp_utils_udev_get_driver (struct udev_device *udevice) { - GUdevDevice *parent = NULL, *grandparent = NULL; + struct udev_device *parent = NULL, *grandparent = NULL; const char *driver, *subsys; - driver = g_udev_device_get_driver (device); + driver = udev_device_get_driver (udevice); if (driver) goto out; /* Try the parent */ - parent = g_udev_device_get_parent (device); + parent = udev_device_get_parent (udevice); if (parent) { - driver = g_udev_device_get_driver (parent); + driver = udev_device_get_driver (parent); if (!driver) { /* Try the grandparent if it's an ibmebus device or if the * subsys is NULL which usually indicates some sort of * platform device like a 'gadget' net interface. */ - subsys = g_udev_device_get_subsystem (parent); + subsys = udev_device_get_subsystem (parent); if ( (g_strcmp0 (subsys, "ibmebus") == 0) || (subsys == NULL)) { - grandparent = g_udev_device_get_parent (parent); + grandparent = udev_device_get_parent (parent); if (grandparent) - driver = g_udev_device_get_driver (grandparent); + driver = udev_device_get_driver (grandparent); } } } - g_clear_object (&parent); - g_clear_object (&grandparent); out: /* Intern the string so we don't have to worry about memory diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index 699e80c6..ea25470e 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -21,8 +21,6 @@ #ifndef __NM_PLATFORM_UTILS_H__ #define __NM_PLATFORM_UTILS_H__ -#include <gudev/gudev.h> - #include "nm-platform.h" #include "nm-setting-wired.h" @@ -66,7 +64,9 @@ gboolean nmp_utils_ethtool_get_permanent_address (int ifindex, gboolean nmp_utils_mii_supports_carrier_detect (int ifindex); -const char *nmp_utils_udev_get_driver (GUdevDevice *device); +struct udev_device; + +const char *nmp_utils_udev_get_driver (struct udev_device *udevice); NMIPConfigSource nmp_utils_ip_config_source_from_rtprot (guint8 rtprot) _nm_const; guint8 nmp_utils_ip_config_source_coerce_to_rtprot (NMIPConfigSource source) _nm_const; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index a9014b36..767187d9 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -43,10 +43,6 @@ /*****************************************************************************/ -const NMIPAddr nm_ip_addr_zero = NMIPAddrInit; - -/*****************************************************************************/ - G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX); G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address)); G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address)); @@ -62,13 +58,13 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ char __prefix[32]; \ const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const void *const __self = (self); \ + const NMPlatform *const __self = (self); \ \ - if (__self && __self != nm_platform_try_get ()) { \ + if (__self && NM_PLATFORM_GET_PRIVATE (__self)->log_with_ptr) { \ g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ __p_prefix = __prefix; \ } \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ @@ -83,12 +79,12 @@ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 }; enum { PROP_0, PROP_NETNS_SUPPORT, - PROP_REGISTER_SINGLETON, + PROP_LOG_WITH_PTR, LAST_PROP, }; typedef struct _NMPlatformPrivate { - bool register_singleton:1; + bool log_with_ptr:1; } NMPlatformPrivate; G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT) @@ -97,6 +93,14 @@ G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT) /*****************************************************************************/ +gboolean +nm_platform_get_log_with_ptr (NMPlatform *self) +{ + return NM_PLATFORM_GET_PRIVATE (self)->log_with_ptr; +} + +/*****************************************************************************/ + guint _nm_platform_signal_id_get (NMPlatformSignalIdType signal_type) { @@ -187,12 +191,6 @@ nm_platform_get () return singleton_instance; } -NMPlatform * -nm_platform_try_get (void) -{ - return singleton_instance; -} - /*****************************************************************************/ /** @@ -444,11 +442,19 @@ _link_get_all_presort (gconstpointer p_a, const NMPlatformLink *a = p_a; const NMPlatformLink *b = p_b; - if (a->ifindex < b->ifindex) + /* Loopback always first */ + if (a->ifindex == 1) return -1; - if (a->ifindex > b->ifindex) + if (b->ifindex == 1) return 1; - return 0; + + /* Initialized links first */ + if (a->initialized > b->initialized) + return -1; + if (a->initialized < b->initialized) + return 1; + + return strcmp (a->name, b->name); } /** @@ -1000,7 +1006,7 @@ nm_platform_link_get_udi (NMPlatform *self, int ifindex) return NULL; } -GObject * +struct udev_device * nm_platform_link_get_udev_device (NMPlatform *self, int ifindex) { _CHECK_SELF (self, klass, FALSE); @@ -1169,6 +1175,30 @@ nm_platform_link_supports_vlans (NMPlatform *self, int ifindex) return klass->link_supports_vlans (self, ifindex); } +gboolean +nm_platform_link_supports_sriov (NMPlatform *self, int ifindex) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex >= 0, FALSE); + + return klass->link_supports_sriov (self, ifindex); +} + +gboolean +nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + _LOGD ("link: setting %u VFs for %s (%d)", + num_vfs, + nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), + ifindex); + return klass->link_set_sriov_num_vfs (self, ifindex, num_vfs); +} + /** * nm_platform_link_set_up: * @self: platform instance @@ -1184,7 +1214,7 @@ nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmwar g_return_val_if_fail (ifindex > 0, FALSE); - _LOGD ("link: setting up '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); + _LOGD ("link: setting up %s (%d)", nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex); return klass->link_set_up (self, ifindex, out_no_firmware); } @@ -1202,7 +1232,7 @@ nm_platform_link_set_down (NMPlatform *self, int ifindex) g_return_val_if_fail (ifindex > 0, FALSE); - _LOGD ("link: setting down '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); + _LOGD ("link: setting down %s (%d)", nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex); return klass->link_set_down (self, ifindex); } @@ -1220,7 +1250,7 @@ nm_platform_link_set_arp (NMPlatform *self, int ifindex) g_return_val_if_fail (ifindex >= 0, FALSE); - _LOGD ("link: setting arp '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); + _LOGD ("link: setting arp %s (%d)", nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex); return klass->link_set_arp (self, ifindex); } @@ -3109,14 +3139,7 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute /** * nm_platform_ip4_route_add: * @self: - * @ifindex: - * @source: - * network: - * plen: - * gateway: - * pref_src: - * metric: - * mss: + * @route: * * For kernel, a gateway can be either explicitly set or left * at zero (0.0.0.0). In addition, there is the scope of the IPv4 @@ -3137,57 +3160,29 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute * Returns: %TRUE in case of success. */ gboolean -nm_platform_ip4_route_add (NMPlatform *self, - int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, - in_addr_t gateway, in_addr_t pref_src, - guint32 metric, guint32 mss) +nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (plen <= 32, FALSE); + g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (route->plen <= 32, FALSE); - if (_LOGD_ENABLED ()) { - NMPlatformIP4Route route = { 0 }; - - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.pref_src = pref_src; - - _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0)); - } - return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); + _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (route, NULL, 0)); + + return klass->ip4_route_add (self, route); } gboolean -nm_platform_ip6_route_add (NMPlatform *self, - int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) +nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (plen <= 128, FALSE); + g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (route->plen <= 128, FALSE); - if (_LOGD_ENABLED ()) { - NMPlatformIP6Route route = { 0 }; + _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (route, NULL, 0)); - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - - _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0)); - } - return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss); + return klass->ip6_route_add (self, route); } gboolean @@ -3900,6 +3895,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; char str_scope[30], s_source[50]; + char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -3909,16 +3905,35 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); + if (route->tos) + nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos); + if (route->window) + nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window); + if (route->cwnd) + nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd); + if (route->initcwnd) + nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd); + if (route->initrwnd) + nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd); + if (route->mtu) + nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu); + g_snprintf (buf, len, "%s/%d" " via %s" "%s" " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT - " src %s" /* source */ + " rt-src %s" /* protocol */ "%s" /* cloned */ "%s%s" /* scope */ "%s%s" /* pref-src */ + "%s" /* tos */ + "%s" /* window */ + "%s" /* cwnd */ + "%s" /* initcwnd */ + "%s" /* initrwnd */ + "%s" /* mtu */ "", s_network, route->plen, @@ -3931,7 +3946,13 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi route->scope_inv ? " scope " : "", route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", route->pref_src ? " pref-src " : "", - route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : ""); + route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "", + route->tos ? str_tos : "", + route->window ? str_window : "", + route->cwnd ? str_cwnd : "", + route->initcwnd ? str_initcwnd : "", + route->initrwnd ? str_initrwnd : "", + route->mtu ? str_mtu : ""); return buf; } @@ -3950,25 +3971,54 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi const char * nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len) { - char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN]; + char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN], s_pref_src[INET6_ADDRSTRLEN]; + char s_src[INET6_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50]; + char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; - inet_ntop (AF_INET6, &route->network, s_network, sizeof(s_network)); - inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway)); + inet_ntop (AF_INET6, &route->network, s_network, sizeof (s_network)); + inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof (s_gateway)); + inet_ntop (AF_INET6, &route->src, s_src, sizeof (s_src)); + + if (IN6_IS_ADDR_UNSPECIFIED (&route->pref_src)) + s_pref_src[0] = 0; + else + inet_ntop (AF_INET6, &route->pref_src, s_pref_src, sizeof (s_pref_src)); _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); + if (route->tos) + nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos); + if (route->window) + nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window); + if (route->cwnd) + nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd); + if (route->initcwnd) + nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd); + if (route->initrwnd) + nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd); + if (route->mtu) + nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu); + g_snprintf (buf, len, "%s/%d" " via %s" "%s" " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT - " src %s" /* source */ + " rt-src %s" /* protocol */ + " src %s/%u" /* source */ "%s" /* cloned */ + "%s%s" /* pref-src */ + "%s" /* tos */ + "%s" /* window */ + "%s" /* cwnd */ + "%s" /* initcwnd */ + "%s" /* initrwnd */ + "%s" /* mtu */ "", s_network, route->plen, @@ -3977,7 +4027,17 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi route->metric, route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), - route->rt_cloned ? " cloned" : ""); + s_src, route->src_plen, + route->rt_cloned ? " cloned" : "", + s_pref_src[0] ? " pref-src " : "", + s_pref_src[0] ? s_pref_src : "", + route->tos ? str_tos : "", + route->window ? str_window : "", + route->cwnd ? str_cwnd : "", + route->initcwnd ? str_initcwnd : "", + route->initrwnd ? str_initrwnd : "", + route->mtu ? str_mtu : ""); + return buf; } @@ -4253,11 +4313,16 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A } int -nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) +nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part) { _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); - _CMP_FIELD (a, b, network); + if (consider_host_part) + _CMP_FIELD (a, b, network); + else { + _CMP_DIRECT (nm_utils_ip4_address_clear_host_address (a->network, a->plen), + nm_utils_ip4_address_clear_host_address (b->network, b->plen)); + } _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, metric); _CMP_FIELD (a, b, gateway); @@ -4266,21 +4331,54 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route _CMP_FIELD (a, b, scope_inv); _CMP_FIELD (a, b, pref_src); _CMP_FIELD (a, b, rt_cloned); + _CMP_FIELD (a, b, tos); + _CMP_FIELD (a, b, lock_window); + _CMP_FIELD (a, b, lock_cwnd); + _CMP_FIELD (a, b, lock_initcwnd); + _CMP_FIELD (a, b, lock_initrwnd); + _CMP_FIELD (a, b, lock_mtu); + _CMP_FIELD (a, b, window); + _CMP_FIELD (a, b, cwnd); + _CMP_FIELD (a, b, initcwnd); + _CMP_FIELD (a, b, initrwnd); + _CMP_FIELD (a, b, mtu); return 0; } int -nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) +nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part) { _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); - _CMP_FIELD_MEMCMP (a, b, network); + if (consider_host_part) + _CMP_FIELD_MEMCMP (a, b, network); + else { + struct in6_addr n1, n2; + + nm_utils_ip6_address_clear_host_address (&n1, &a->network, a->plen); + nm_utils_ip6_address_clear_host_address (&n2, &b->network, b->plen); + _CMP_DIRECT_MEMCMP (&n1, &n2, sizeof (struct in6_addr)); + } _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, metric); _CMP_FIELD_MEMCMP (a, b, gateway); + _CMP_FIELD_MEMCMP (a, b, pref_src); + _CMP_FIELD_MEMCMP (a, b, src); + _CMP_FIELD (a, b, src_plen); _CMP_FIELD (a, b, rt_source); _CMP_FIELD (a, b, mss); _CMP_FIELD (a, b, rt_cloned); + _CMP_FIELD (a, b, tos); + _CMP_FIELD (a, b, lock_window); + _CMP_FIELD (a, b, lock_cwnd); + _CMP_FIELD (a, b, lock_initcwnd); + _CMP_FIELD (a, b, lock_initrwnd); + _CMP_FIELD (a, b, lock_mtu); + _CMP_FIELD (a, b, window); + _CMP_FIELD (a, b, cwnd); + _CMP_FIELD (a, b, initcwnd); + _CMP_FIELD (a, b, initrwnd); + _CMP_FIELD (a, b, mtu); return 0; } @@ -4411,28 +4509,27 @@ nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns) static gboolean _vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) { - return nm_platform_ip4_route_add (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->rx.rt_source, - route->r4.network, - route->rx.plen, - route->r4.gateway, - route->r4.pref_src, - metric >= 0 ? (guint32) metric : route->rx.metric, - route->rx.mss); + NMPlatformIP4Route rt = route->r4; + + if (ifindex > 0) + rt.ifindex = ifindex; + if (metric >= 0) + rt.metric = metric; + + return nm_platform_ip4_route_add (self, &rt); } static gboolean _vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) { - return nm_platform_ip6_route_add (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->rx.rt_source, - route->r6.network, - route->rx.plen, - route->r6.gateway, - metric >= 0 ? (guint32) metric : route->rx.metric, - route->rx.mss); + NMPlatformIP6Route rt = route->r6; + + if (ifindex > 0) + rt.ifindex = ifindex; + if (metric >= 0) + rt.metric = metric; + + return nm_platform_ip6_route_add (self, &rt); } static gboolean @@ -4479,7 +4576,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { .is_ip4 = TRUE, .addr_family = AF_INET, .sizeof_route = sizeof (NMPlatformIP4Route), - .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip4_route_cmp, + .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip4_route_cmp_full, .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string, .route_get_all = nm_platform_ip4_route_get_all, .route_add = _vtr_v4_route_add, @@ -4492,7 +4589,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = { .is_ip4 = FALSE, .addr_family = AF_INET6, .sizeof_route = sizeof (NMPlatformIP6Route), - .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip6_route_cmp, + .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip6_route_cmp_full, .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string, .route_get_all = nm_platform_ip6_route_get_all, .route_add = _vtr_v6_route_add, @@ -4521,9 +4618,9 @@ set_property (GObject *object, guint prop_id, self->_netns = g_object_ref (netns); } break; - case PROP_REGISTER_SINGLETON: + case PROP_LOG_WITH_PTR: /* construct-only */ - priv->register_singleton = g_value_get_boolean (value); + priv->log_with_ptr = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -4532,18 +4629,6 @@ set_property (GObject *object, guint prop_id, } static void -constructed (GObject *object) -{ - NMPlatform *self = NM_PLATFORM (object); - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self); - - G_OBJECT_CLASS (nm_platform_parent_class)->constructed (object); - - if (priv->register_singleton) - nm_platform_setup (self); -} - -static void nm_platform_init (NMPlatform *self) { self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_PLATFORM, NMPlatformPrivate); @@ -4565,7 +4650,6 @@ nm_platform_class_init (NMPlatformClass *platform_class) g_type_class_add_private (object_class, sizeof (NMPlatformPrivate)); object_class->set_property = set_property; - object_class->constructed = constructed; object_class->finalize = finalize; platform_class->wifi_set_powersave = wifi_set_powersave; @@ -4579,9 +4663,9 @@ nm_platform_class_init (NMPlatformClass *platform_class) G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_REGISTER_SINGLETON, - g_param_spec_boolean (NM_PLATFORM_REGISTER_SINGLETON, "", "", - FALSE, + (object_class, PROP_LOG_WITH_PTR, + g_param_spec_boolean (NM_PLATFORM_LOG_WITH_PTR, "", "", + TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 63dbe5a0..43be17fa 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -45,10 +45,12 @@ /*****************************************************************************/ #define NM_PLATFORM_NETNS_SUPPORT "netns-support" -#define NM_PLATFORM_REGISTER_SINGLETON "register-singleton" +#define NM_PLATFORM_LOG_WITH_PTR "log-with-ptr" /*****************************************************************************/ +struct udev_device; + /* workaround for older libnl version, that does not define these flags. */ #ifndef IFA_F_MANAGETEMPADDR #define IFA_F_MANAGETEMPADDR 0x100 @@ -91,24 +93,6 @@ typedef enum { /*< skip >*/ NM_PLATFORM_ERROR_OPNOTSUPP, } NMPlatformError; - -typedef struct { - union { - guint8 addr_ptr[1]; - in_addr_t addr4; - struct in6_addr addr6; - - /* NMIPAddr is really a union for IP addresses. - * However, as ethernet addresses fit in here nicely, ruse - * it also for an ethernet MAC address. */ - guint8 addr_eth[6 /*ETH_ALEN*/]; - }; -} NMIPAddr; - -extern const NMIPAddr nm_ip_addr_zero; - -#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT } - #define NM_PLATFORM_LINK_OTHER_NETNS (-1) #define __NMPlatformObject_COMMON \ @@ -324,9 +308,20 @@ typedef union { * of platform users. This flag is internal to track those hidden * routes. Such a route is not alive, according to nmp_object_is_alive(). */ \ bool rt_cloned:1; \ + bool lock_window:1; \ + bool lock_cwnd:1; \ + bool lock_initcwnd:1; \ + bool lock_initrwnd:1; \ + bool lock_mtu:1; \ \ guint32 metric; \ guint32 mss; \ + guint32 tos; \ + guint32 window; \ + guint32 cwnd; \ + guint32 initcwnd; \ + guint32 initrwnd; \ + guint32 mtu; \ ; typedef struct { @@ -358,6 +353,9 @@ struct _NMPlatformIP6Route { __NMPlatformIPRoute_COMMON; struct in6_addr network; struct in6_addr gateway; + struct in6_addr pref_src; + struct in6_addr src; + guint8 src_plen; }; typedef union { @@ -376,7 +374,7 @@ typedef struct { gboolean is_ip4; int addr_family; gsize sizeof_route; - int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b); + int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part); const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len); GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric); @@ -548,7 +546,7 @@ typedef struct { gboolean (*link_set_noarp) (NMPlatform *, int ifindex); const char *(*link_get_udi) (NMPlatform *self, int ifindex); - GObject *(*link_get_udev_device) (NMPlatform *self, int ifindex); + struct udev_device *(*link_get_udev_device) (NMPlatform *self, int ifindex); NMPlatformError (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled); gboolean (*link_set_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId iid); @@ -559,6 +557,7 @@ typedef struct { size_t *length); NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); + gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs); char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); guint (*link_get_dev_id) (NMPlatform *, int ifindex); @@ -571,6 +570,7 @@ typedef struct { gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); + gboolean (*link_supports_sriov) (NMPlatform *, int ifindex); gboolean (*link_enslave) (NMPlatform *, int master, int slave); gboolean (*link_release) (NMPlatform *, int master, int slave); @@ -667,12 +667,8 @@ typedef struct { GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); - gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss); - gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss); + gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route); + gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route); gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); @@ -707,7 +703,6 @@ GType nm_platform_get_type (void); void nm_platform_setup (NMPlatform *instance); NMPlatform *nm_platform_get (void); -NMPlatform *nm_platform_try_get (void); #define NM_PLATFORM_GET (nm_platform_get ()) @@ -730,6 +725,8 @@ _nm_platform_uint8_inv (guint8 scope) return (guint8) ~scope; } +gboolean nm_platform_get_log_with_ptr (NMPlatform *self); + NMPNetns *nm_platform_netns_get (NMPlatform *self); gboolean nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns); @@ -804,7 +801,7 @@ gboolean nm_platform_link_set_noarp (NMPlatform *self, int ifindex); const char *nm_platform_link_get_udi (NMPlatform *self, int ifindex); -GObject *nm_platform_link_get_udev_device (NMPlatform *self, int ifindex); +struct udev_device *nm_platform_link_get_udev_device (NMPlatform *self, int ifindex); NMPlatformError nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled); gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid); @@ -812,6 +809,7 @@ gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtils gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length); NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); +gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex); @@ -824,6 +822,7 @@ gboolean nm_platform_link_get_driver_info (NMPlatform *self, gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex); gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex); +gboolean nm_platform_link_supports_sriov (NMPlatform *self, int ifindex); gboolean nm_platform_link_enslave (NMPlatform *self, int master, int slave); gboolean nm_platform_link_release (NMPlatform *self, int master, int slave); @@ -969,12 +968,8 @@ const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifind const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); -gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss); -gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss); +gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route); +gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route); gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric); gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); @@ -1011,8 +1006,20 @@ int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVla int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b); -int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b); -int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b); +int nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part); +int nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part); + +static inline int +nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) +{ + return nm_platform_ip4_route_cmp_full (a, b, TRUE); +} + +static inline int +nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) +{ + return nm_platform_ip6_route_cmp_full (a, b, TRUE); +} gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self); gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index c9c6850d..4acd4761 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -75,7 +75,7 @@ __ns_types_to_str (int ns_types, int ns_types_already_set, char *buf, gsize len) NMPNetns *_netns = (netns); \ char _sbuf[20]; \ \ - _nm_log (_level, _NMLOG_DOMAIN, 0, \ + _nm_log (_level, _NMLOG_DOMAIN, 0, NULL, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (_netns ? nm_sprintf_buf (_sbuf, "[%p]", _netns) : "") \ diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 1503ca9a..ecec8f0f 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -24,6 +24,7 @@ #include <unistd.h> #include <linux/rtnetlink.h> +#include <libudev.h> #include "nm-utils.h" @@ -40,7 +41,7 @@ if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ const NMPObject *const __obj = (obj); \ \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ "nmp-object[%p/%s]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ __obj, \ (__obj ? NMP_OBJECT_GET_CLASS (__obj)->obj_type_name : "???") \ @@ -48,10 +49,6 @@ } \ } G_STMT_END -/* logging to trace object lifetime and references. - * Disabled by default. */ -#define _LOGr(...) G_STMT_START { if (FALSE) { _LOGt (__VA_ARGS__); } } G_STMT_END - /*****************************************************************************/ struct _NMPCache { @@ -125,14 +122,14 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map, /*****************************************************************************/ static const char * -_link_get_driver (GUdevDevice *udev_device, const char *kind, int ifindex) +_link_get_driver (struct udev_device *udevice, const char *kind, int ifindex) { const char *driver = NULL; nm_assert (kind == g_intern_string (kind)); - if (udev_device) { - driver = nmp_utils_udev_get_driver (udev_device); + if (udevice) { + driver = nmp_utils_udev_get_driver (udevice); if (driver) return driver; } @@ -214,8 +211,6 @@ nmp_object_ref (NMPObject *obj) g_return_val_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT, NULL); obj->_ref_count++; - _LOGr (obj, "ref: %d", obj->_ref_count); - return obj; } @@ -225,9 +220,6 @@ nmp_object_unref (NMPObject *obj) if (obj) { g_return_if_fail (obj->_ref_count > 0); g_return_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT); - _LOGr (obj, "%s: %d", - obj->_ref_count <= 1 ? "destroy" : "unref", - obj->_ref_count - 1); if (--obj->_ref_count <= 0) { const NMPClass *klass = obj->_class; @@ -242,7 +234,10 @@ nmp_object_unref (NMPObject *obj) static void _vt_cmd_obj_dispose_link (NMPObject *obj) { - g_clear_object (&obj->_link.udev.device); + if (obj->_link.udev.device) { + udev_device_unref (obj->_link.udev.device); + obj->_link.udev.device = NULL; + } nmp_object_unref (obj->_link.netlink.lnk); } @@ -265,7 +260,6 @@ _nmp_object_new_from_class (const NMPClass *klass) obj = g_slice_alloc0 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object)); obj->_class = klass; obj->_ref_count = 1; - _LOGr (obj, "new"); return obj; } @@ -495,7 +489,7 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin static const char * _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) { - const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); + const NMPClass *klass; char buf2[sizeof (_nm_utils_to_string_buffer)]; char *b; gsize l; @@ -619,8 +613,7 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2) return 1; /* Only compare based on pointer values. That is ugly because it's not a - * stable sort order, but probably udev gives us always the same GUdevDevice - * instance. + * stable sort order. * * Have this check as very last. */ return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1; @@ -687,15 +680,17 @@ _vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src) { if (dst->_link.udev.device != src->_link.udev.device) { if (src->_link.udev.device) - g_object_ref (src->_link.udev.device); + udev_device_ref (src->_link.udev.device); if (dst->_link.udev.device) - g_object_unref (dst->_link.udev.device); + udev_device_unref (dst->_link.udev.device); + dst->_link.udev.device = src->_link.udev.device; } if (dst->_link.netlink.lnk != src->_link.netlink.lnk) { if (src->_link.netlink.lnk) nmp_object_ref (src->_link.netlink.lnk); if (dst->_link.netlink.lnk) nmp_object_unref (dst->_link.netlink.lnk); + dst->_link.netlink.lnk = src->_link.netlink.lnk; } dst->_link = src->_link; } @@ -810,12 +805,17 @@ _vt_cmd_plobj_id_equal (ip4_route, NMPlatformIP4Route, obj1->ifindex == obj2->ifindex && obj1->plen == obj2->plen && obj1->metric == obj2->metric - && obj1->network == obj2->network); + && nm_utils_ip4_address_clear_host_address (obj1->network, obj1->plen) == nm_utils_ip4_address_clear_host_address (obj2->network, obj2->plen)); _vt_cmd_plobj_id_equal (ip6_route, NMPlatformIP6Route, obj1->ifindex == obj2->ifindex && obj1->plen == obj2->plen && obj1->metric == obj2->metric - && IN6_ARE_ADDR_EQUAL( &obj1->network, &obj2->network)); + && ({ + struct in6_addr n1, n2; + + IN6_ARE_ADDR_EQUAL(nm_utils_ip6_address_clear_host_address (&n1, &obj1->network, obj1->plen), + nm_utils_ip6_address_clear_host_address (&n2, &obj2->network, obj2->plen)); + })); guint nmp_object_id_hash (const NMPObject *obj) @@ -869,14 +869,17 @@ _vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, { hash = hash + ((guint) obj->ifindex); hash = hash * 33 + ((guint) obj->plen); hash = hash * 33 + ((guint) obj->metric); - hash = hash * 33 + ((guint) obj->network); + hash = hash * 33 + ((guint) nm_utils_ip4_address_clear_host_address (obj->network, obj->plen)); }) _vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, { hash = (guint) 3999787007u; hash = hash + ((guint) obj->ifindex); hash = hash * 33 + ((guint) obj->plen); hash = hash * 33 + ((guint) obj->metric); - hash = hash * 33 + _id_hash_ip6_addr (&obj->network); + hash = hash * 33 + ({ + struct in6_addr n1; + _id_hash_ip6_addr (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen)); + }); }) gboolean @@ -985,11 +988,6 @@ nmp_cache_id_hash (const NMPCacheId *id) guint hash = 5381; guint i, n; - /* for hashing we only iterate over the actually set bytes and skip the - * zero padding at the end (which depends on the type of the id). - * - * For the equal implementation, we don't care about that and compare the - * entire NMPCacheId sized struct. */ n = _nmp_cache_id_size_by_type (id->_id_type); for (i = 0; i < n; i++) hash = ((hash << 5) + hash) + ((char *) id)[i]; /* hash * 33 + c */ @@ -1033,6 +1031,20 @@ _nmp_cache_id_init (NMPCacheId *id, NMPCacheIdType id_type) * all structs have the packed attribute, there are no holes * due to alignment, and it becomes simple for nmp_cache_id_init_*() * to ensure that all fields are set. */ + +#if NM_MORE_ASSERTS + nm_assert (id); + { + guint i; + + /* initialized with some bogus canary to hopefully detect when we miss + * to initialize a field of the cache-id. */ + for (i = 0; i < sizeof (*id); i++) { + ((char *) id)[i] = GPOINTER_TO_UINT (id) ^ i; + } + } +#endif + id->_id_type = id_type; } @@ -1533,13 +1545,17 @@ nmp_cache_lookup_link_full (const NMPCache *cache, && strlen (ifname) <= sizeof (cache_id.link_by_ifname.ifname_short)) { p_cache_id = nmp_cache_id_init_link_by_ifname (&cache_id, ifname); ifname = NULL; - } else + } else { p_cache_id = nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, visible_only); + visible_only = FALSE; + } list = nmp_cache_lookup_multi (cache, p_cache_id, &len); for (i = 0; i < len; i++) { obj = NMP_OBJECT_UP_CAST (list[i]); + if (visible_only && !nmp_object_is_visible (obj)) + continue; if (link_type != NM_LINK_TYPE_NONE && obj->link.type != link_type) continue; if (ifname && strcmp (ifname, obj->link.name)) @@ -1857,8 +1873,8 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, _nmp_object_fixup_link_master_connected (obj, cache); /* Merge the netlink parts with what we have from udev. */ - g_clear_object (&obj->_link.udev.device); - obj->_link.udev.device = old->_link.udev.device ? g_object_ref (old->_link.udev.device) : NULL; + udev_device_unref (obj->_link.udev.device); + obj->_link.udev.device = old->_link.udev.device ? udev_device_ref (old->_link.udev.device) : NULL; _nmp_object_fixup_link_udev_fields (obj, cache->use_udev); } } else @@ -1883,7 +1899,7 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, } NMPCacheOpsType -nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data) +nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *udevice, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data) { NMPObject *old; nm_auto_nmpobj NMPObject *obj = NULL; @@ -1896,12 +1912,12 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_devi *out_was_visible = FALSE; if (!old) { - if (!udev_device) + if (!udevice) return NMP_CACHE_OPS_UNCHANGED; obj = nmp_object_new (NMP_OBJECT_TYPE_LINK, NULL); obj->link.ifindex = ifindex; - obj->_link.udev.device = g_object_ref (udev_device); + obj->_link.udev.device = udev_device_ref (udevice); _nmp_object_fixup_link_udev_fields (obj, cache->use_udev); @@ -1922,10 +1938,10 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_devi if (out_was_visible) *out_was_visible = nmp_object_is_visible (old); - if (old->_link.udev.device == udev_device) + if (old->_link.udev.device == udevice) return NMP_CACHE_OPS_UNCHANGED; - if (!udev_device && !old->_link.netlink.is_in_netlink) { + if (!udevice && !old->_link.netlink.is_in_netlink) { /* the update would make @old invalid. Remove it. */ if (pre_hook) pre_hook (cache, old, NULL, NMP_CACHE_OPS_REMOVED, user_data); @@ -1935,8 +1951,8 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_devi obj = nmp_object_clone (old, FALSE); - g_clear_object (&obj->_link.udev.device); - obj->_link.udev.device = udev_device ? g_object_ref (udev_device) : NULL; + udev_device_unref (obj->_link.udev.device); + obj->_link.udev.device = udevice ? udev_device_ref (udevice) : NULL; _nmp_object_fixup_link_udev_fields (obj, cache->use_udev); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index dd11b985..b69680f6 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -21,11 +21,11 @@ #ifndef __NMP_OBJECT_H__ #define __NMP_OBJECT_H__ -#include <gudev/gudev.h> - #include "nm-platform.h" #include "nm-multi-index.h" +struct udev_device; + typedef enum { /*< skip >*/ NMP_OBJECT_TO_STRING_ID, NMP_OBJECT_TO_STRING_PUBLIC, @@ -186,7 +186,23 @@ typedef struct { } netlink; struct { - GUdevDevice *device; + /* note that "struct udev_device" references the library context + * "struct udev", but doesn't own it. + * + * Hence, the udev.device shall not be used after the library + * context is is destroyed. + * + * In case of NMPObjectLink instances that you obtained from the + * platform cache, that means that you shall no keep references + * to those instances that outlife the NMPlatform instance. + * + * In practice, the requirement is less strict and you'll be even + * fine if the platform instance (and the "struct udev" instance) + * are already destroyed while you still hold onto a reference to + * the NMPObjectLink instance. Just don't make use of udev functions + * that cause access to the udev library context. + */ + struct udev_device *device; } udev; } NMPObjectLink; @@ -307,7 +323,7 @@ NMP_CLASS_IS_VALID (const NMPClass *klass) { return klass >= &_nmp_classes[0] && klass <= &_nmp_classes[G_N_ELEMENTS (_nmp_classes)] - && ((((char *) klass) - ((char *) NULL)) % (&_nmp_classes[1] - &_nmp_classes[0])) == 0; + && ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof (_nmp_classes[0]))) == 0; } #define NMP_REF_COUNT_STACKINIT (G_MAXINT) @@ -442,7 +458,7 @@ void ASSERT_nmp_cache_is_consistent (const NMPCache *cache); NMPCacheOpsType nmp_cache_remove (NMPCache *cache, const NMPObject *obj, gboolean equals_by_ptr, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); -NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); +NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *udevice, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); NMPCache *nmp_cache_new (gboolean use_udev); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 4ac49298..71a92cbf 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -65,12 +65,12 @@ test_cleanup_internal (void) /* Add routes and addresses */ g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL)); g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, in6addr_any, metric, mss); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss); addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 0e42a727..04db862d 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -783,6 +783,54 @@ nmtstp_ip6_address_add (NMPlatform *platform, NULL); } +void nmtstp_ip4_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + in_addr_t network, + guint8 plen, + in_addr_t gateway, + in_addr_t pref_src, + guint32 metric, + guint32 mss) +{ + NMPlatformIP4Route route = { }; + + route.ifindex = ifindex; + route.rt_source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.pref_src = pref_src; + route.metric = metric; + route.mss = mss; + + g_assert (nm_platform_ip4_route_add (platform, &route)); +} + +void nmtstp_ip6_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + struct in6_addr network, + guint8 plen, + struct in6_addr gateway, + struct in6_addr pref_src, + guint32 metric, + guint32 mss) +{ + NMPlatformIP6Route route = { }; + + route.ifindex = ifindex; + route.rt_source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.pref_src = pref_src; + route.metric = metric; + route.mss = mss; + + g_assert (nm_platform_ip6_route_add (platform, &route)); +} + /*****************************************************************************/ static void @@ -1547,7 +1595,7 @@ nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name) g_return_val_if_fail (pid > 0, 0); g_return_val_if_fail (ns_name && ns_name[0] && strlen (ns_name) < 50, 0); - nm_sprintf_buf (p, "/proc/%lu/ns/%s", (long unsigned) pid, ns_name); + nm_sprintf_buf (p, "/proc/%lu/ns/%s", (unsigned long) pid, ns_name); return open(p, O_RDONLY | O_CLOEXEC); } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 48a41de6..a52a5db5 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -26,7 +26,7 @@ if (nm_logging_enabled (__level, __domain)) { \ gint64 _ts = nm_utils_get_monotonic_timestamp_ns (); \ \ - _nm_log (__level, __domain, 0, \ + _nm_log (__level, __domain, 0, NULL, NULL, \ "%s[%ld.%09ld]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ (long) (_ts / NM_UTILS_NS_PER_SECOND), \ @@ -167,6 +167,26 @@ void nmtstp_ip6_address_del (NMPlatform *platform, struct in6_addr address, int plen); +void nmtstp_ip4_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + in_addr_t network, + guint8 plen, + in_addr_t gateway, + in_addr_t pref_src, + guint32 metric, + guint32 mss); + +void nmtstp_ip6_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + struct in6_addr network, + guint8 plen, + struct in6_addr gateway, + struct in6_addr pref_src, + guint32 metric, + guint32 mss); + /*****************************************************************************/ const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type); diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c index 658aad26..2ccfac7d 100644 --- a/src/platform/tests/test-general.c +++ b/src/platform/tests/test-general.c @@ -35,7 +35,7 @@ test_init_linux_platform (void) { gs_unref_object NMPlatform *platform = NULL; - platform = nm_linux_platform_new (NM_PLATFORM_NETNS_SUPPORT_DEFAULT); + platform = nm_linux_platform_new (TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT); } /*****************************************************************************/ @@ -46,7 +46,7 @@ test_link_get_all (void) gs_unref_object NMPlatform *platform = NULL; gs_unref_array GArray *links = NULL; - platform = nm_linux_platform_new (NM_PLATFORM_NETNS_SUPPORT_DEFAULT); + platform = nm_linux_platform_new (TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT); links = nm_platform_link_get_all (platform); } diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index c2b3de13..ed435567 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1900,7 +1900,7 @@ _test_netns_create_platform (void) netns = nmp_netns_new (); g_assert (NMP_IS_NETNS (netns)); - platform = nm_linux_platform_new (TRUE); + platform = nm_linux_platform_new (TRUE, TRUE); g_assert (NM_IS_LINUX_PLATFORM (platform)); nmp_netns_pop (netns); @@ -1961,7 +1961,7 @@ test_netns_general (gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip ()) return; - platform_1 = nm_linux_platform_new (TRUE); + platform_1 = nm_linux_platform_new (TRUE, TRUE); platform_2 = _test_netns_create_platform (); /* add some dummy devices. The "other-*" devices are there to bump the ifindex */ @@ -2061,7 +2061,7 @@ test_netns_set_netns (gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip ()) return; - platforms[0] = platform_0 = nm_linux_platform_new (TRUE); + platforms[0] = platform_0 = nm_linux_platform_new (TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform (); platforms[2] = platform_2 = _test_netns_create_platform (); @@ -2156,7 +2156,7 @@ test_netns_push (gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip ()) return; - pl[0].platform = platform_0 = nm_linux_platform_new (TRUE); + pl[0].platform = platform_0 = nm_linux_platform_new (TRUE, TRUE); pl[1].platform = platform_1 = _test_netns_create_platform (); pl[2].platform = platform_2 = _test_netns_create_platform (); @@ -2288,7 +2288,7 @@ test_netns_bind_to_path (gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip ()) return; - platforms[0] = platform_0 = nm_linux_platform_new (TRUE); + platforms[0] = platform_0 = nm_linux_platform_new (TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform (); platforms[2] = platform_2 = _test_netns_create_platform (); @@ -2404,8 +2404,6 @@ test_sysctl_rename (void) g_assert_cmpint (ifindex[0], ==, (gint32) nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_NETDIR (dirfd, s ?: "<unknown>", "ifindex"), -1)); break; } - default: - g_assert_not_reached (); } nm_platform_process_events (PL); @@ -2435,7 +2433,7 @@ test_sysctl_netns_switch (void) if (_test_netns_check_skip ()) return; - platforms[0] = platform_0 = nm_linux_platform_new (TRUE); + platforms[0] = platform_0 = nm_linux_platform_new (TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform (); platforms[2] = platform_2 = _test_netns_create_platform (); PL = platforms[nmtst_get_rand_int () % 3]; diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index f7b209de..42dfc572 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -20,7 +20,10 @@ #include "nm-default.h" +#include <libudev.h> + #include "platform/nmp-object.h" +#include "nm-utils/nm-udev-utils.h" #include "nm-test-utils-core.h" @@ -159,7 +162,7 @@ _nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, obj_old = nmp_cache_lookup_link (cache, obj->object.ifindex); if (obj_old && obj_old->_link.udev.device) - obj_clone->_link.udev.device = g_object_ref (obj_old->_link.udev.device); + obj_clone->_link.udev.device = udev_device_ref (obj_old->_link.udev.device); _nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache)); g_assert (cache); @@ -219,8 +222,8 @@ test_cache_link (void) NMPObject objs1; gboolean was_visible; NMPCacheId cache_id_storage; - GUdevDevice *udev_device_2 = g_list_nth_data (global.udev_devices, 0); - GUdevDevice *udev_device_3 = g_list_nth_data (global.udev_devices, 0); + struct udev_device *udev_device_2 = g_list_nth_data (global.udev_devices, 0); + struct udev_device *udev_device_3 = g_list_nth_data (global.udev_devices, 0); NMPCacheOpsType ops_type; cache = nmp_cache_new (nmtst_get_rand_int () % 2); @@ -390,23 +393,40 @@ int main (int argc, char **argv) { int result; - gs_unref_object GUdevClient *udev_client = NULL; + NMUdevClient *udev_client; nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); - udev_client = g_udev_client_new ((const char *[]) { "net", NULL }); + udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, + NULL, NULL); { - gs_unref_object GUdevEnumerator *udev_enumerator = g_udev_enumerator_new (udev_client); + struct udev_enumerate *enumerator; + struct udev_list_entry *devices, *l; - g_udev_enumerator_add_match_subsystem (udev_enumerator, "net"); + enumerator = nm_udev_client_enumerate_new (udev_client); /* Demand that the device is initialized (udev rules ran, * device has a stable name now) in case udev is running * (not in a container). */ if (access ("/sys", W_OK) == 0) - g_udev_enumerator_add_match_is_initialized (udev_enumerator); + udev_enumerate_add_match_is_initialized (enumerator); + + udev_enumerate_scan_devices (enumerator); + + devices = udev_enumerate_get_list_entry (enumerator); + for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) { + struct udev_device *udevice; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator), + udev_list_entry_get_name (l)); + if (udevice == NULL) + continue; - global.udev_devices = g_udev_enumerator_execute (udev_enumerator); + global.udev_devices = g_list_prepend (global.udev_devices, udevice); + } + global.udev_devices = g_list_reverse (global.udev_devices); + + udev_enumerate_unref (enumerator); } g_test_add_func ("/nmp-object/cache_link", test_cache_link); @@ -414,10 +434,12 @@ main (int argc, char **argv) result = g_test_run (); while (global.udev_devices) { - g_object_unref (global.udev_devices->data); + udev_device_unref (global.udev_devices->data); global.udev_devices = g_list_remove (global.udev_devices, global.udev_devices->data); } + nm_udev_client_unref (udev_client); + return result; } diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 59a05bd4..6862f13e 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -94,7 +94,7 @@ test_ip4_route_metric0 (void) nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); /* add the first route */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss); accept_signal (route_added); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); @@ -108,7 +108,7 @@ test_ip4_route_metric0 (void) nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); /* add the second route */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss); accept_signal (route_added); nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, 0); @@ -160,27 +160,27 @@ test_ip4_route (void) inet_pton (AF_INET, "198.51.100.1", &gateway); /* Add route to gateway */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss); accept_signal (route_added); /* Add route */ nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss); nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss); accept_signals (route_changed, 0, 1); /* Add default route */ nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss); nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, 0, 0, metric); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss); accept_signals (route_changed, 0, 1); /* Test route listing */ @@ -222,6 +222,14 @@ test_ip4_route (void) /* Remove route again */ g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + /* Remove default route */ + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, 0, 0, metric)); + accept_signal (route_removed); + + /* Remove route to gateway */ + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, gateway, 32, metric)); + accept_signal (route_removed); + free_signal (route_added); free_signal (route_changed); free_signal (route_removed); @@ -238,36 +246,55 @@ test_ip6_route (void) NMPlatformIP6Route rts[3]; struct in6_addr network; guint8 plen = 64; - struct in6_addr gateway; + struct in6_addr gateway, pref_src; /* Choose a high metric so that we hopefully don't conflict. */ int metric = 22987; int mss = 1000; inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway); + inet_pton (AF_INET6, "::42", &pref_src); + + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any, + NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)); + accept_signals (route_added, 0, 1); + + /* Wait that the address becomes non-tentative. Dummy interfaces are NOARP + * and thus don't do DAD, but the kernel sets the address as tentative for a + * small amount of time, which prevents the immediate addition of the route + * with RTA_PREFSRC */ + NMTST_WAIT_ASSERT (200, { + const NMPlatformIP6Address *plt_addr; + + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); + nm_platform_process_events (NM_PLATFORM_GET); + plt_addr = nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, pref_src, 128); + if (plt_addr && !NM_FLAGS_HAS (plt_addr->n_ifa_flags, IFA_F_TENTATIVE)) + break; + }); /* Add route to gateway */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss)); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss); accept_signal (route_added); /* Add route */ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss)); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss); g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss)); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss); accept_signals (route_changed, 0, 1); /* Add default route */ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss); g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss); accept_signals (route_changed, 0, 1); /* Test route listing */ @@ -278,6 +305,7 @@ test_ip6_route (void) rts[0].plen = 128; rts[0].ifindex = ifindex; rts[0].gateway = in6addr_any; + rts[0].pref_src = in6addr_any; rts[0].metric = nm_utils_ip6_route_metric_normalize (metric); rts[0].mss = mss; rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); @@ -285,6 +313,7 @@ test_ip6_route (void) rts[1].plen = plen; rts[1].ifindex = ifindex; rts[1].gateway = gateway; + rts[1].pref_src = pref_src; rts[1].metric = nm_utils_ip6_route_metric_normalize (metric); rts[1].mss = mss; rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); @@ -292,6 +321,7 @@ test_ip6_route (void) rts[2].plen = 0; rts[2].ifindex = ifindex; rts[2].gateway = gateway; + rts[2].pref_src = in6addr_any; rts[2].metric = nm_utils_ip6_route_metric_normalize (metric); rts[2].mss = mss; g_assert_cmpint (routes->len, ==, 3); @@ -306,6 +336,14 @@ test_ip6_route (void) /* Remove route again */ g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + /* Remove default route */ + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); + accept_signal (route_removed); + + /* Remove route to gateway */ + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, gateway, 128, metric)); + accept_signal (route_removed); + free_signal (route_added); free_signal (route_changed); free_signal (route_removed); @@ -334,6 +372,114 @@ test_ip4_zero_gateway (void) nm_platform_process_events (NM_PLATFORM_GET); } +static void +test_ip4_route_options (void) +{ + int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + NMPlatformIP4Route route = { }; + in_addr_t network; + GArray *routes; + NMPlatformIP4Route rts[1]; + + inet_pton (AF_INET, "172.16.1.0", &network); + + route.ifindex = ifindex; + route.rt_source = NM_IP_CONFIG_SOURCE_USER; + route.network = network; + route.plen = 24; + route.metric = 20; + route.tos = 0x28; + route.window = 10000; + route.cwnd = 16; + route.initcwnd = 30; + route.initrwnd = 50; + route.mtu = 1350; + route.lock_cwnd = TRUE; + + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &route)); + + /* Test route listing */ + routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + memset (rts, 0, sizeof (rts)); + rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); + rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); + rts[0].network = network; + rts[0].plen = 24; + rts[0].ifindex = ifindex; + rts[0].metric = 20; + rts[0].tos = 0x28; + rts[0].window = 10000; + rts[0].cwnd = 16; + rts[0].initcwnd = 30; + rts[0].initrwnd = 50; + rts[0].mtu = 1350; + rts[0].lock_cwnd = TRUE; + + g_assert_cmpint (routes->len, ==, 1); + nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE); + + /* Remove route */ + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, 24, 20)); + + g_array_unref (routes); +} + + +static void +test_ip6_route_options (void) +{ + int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + NMPlatformIP6Route route = { }; + struct in6_addr network; + GArray *routes; + NMPlatformIP6Route rts[3]; + + inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); + + route.ifindex = ifindex; + route.rt_source = NM_IP_CONFIG_SOURCE_USER; + route.network = network; + route.plen = 64; + route.gateway = in6addr_any; + route.metric = 1024; + route.window = 20000; + route.cwnd = 8; + route.initcwnd = 22; + route.initrwnd = 33; + route.mtu = 1300; + route.lock_mtu = TRUE; + + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &route)); + + /* Test route listing */ + routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + memset (rts, 0, sizeof (rts)); + rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); + rts[0].network = network; + rts[0].plen = 64; + rts[0].ifindex = ifindex; + rts[0].gateway = in6addr_any; + rts[0].metric = 1024; + rts[0].window = 20000; + rts[0].cwnd = 8; + rts[0].initcwnd = 22; + rts[0].initrwnd = 33; + rts[0].mtu = 1300; + rts[0].lock_mtu = TRUE; + + g_assert_cmpint (routes->len, ==, 1); + nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE); + + /* Remove route */ + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, 64, 1024)); + + g_array_unref (routes); +} + /*****************************************************************************/ NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; @@ -360,6 +506,8 @@ _nmtstp_setup_tests (void) g_test_add_func ("/route/ip4", test_ip4_route); g_test_add_func ("/route/ip6", test_ip6_route); g_test_add_func ("/route/ip4_metric0", test_ip4_route_metric0); + g_test_add_func ("/route/ip4_options", test_ip4_route_options); + g_test_add_func ("/route/ip6_options", test_ip6_route_options); if (nmtstp_is_root_test ()) g_test_add_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway); diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c index ac51678f..06eb7cb9 100644 --- a/src/platform/wifi/wifi-utils-nl80211.c +++ b/src/platform/wifi/wifi-utils-nl80211.c @@ -27,7 +27,6 @@ #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> -#include <math.h> #include <netlink/netlink.h> #include <netlink/msg.h> #include <linux/nl80211.h> @@ -35,8 +34,17 @@ #include "wifi-utils-private.h" #include "wifi-utils-nl80211.h" #include "platform/nm-platform.h" +#include "platform/nm-platform-utils.h" #include "nm-utils.h" +#define _NMLOG_PREFIX_NAME "wifi-nl80211" +#define _NMLOG(level, domain, ...) \ + G_STMT_START { \ + nm_log ((level), (domain), NULL, NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END /***************************************************************************** * Copied from libnl3/genl: @@ -219,9 +227,9 @@ out_cb_free: nl_cb_put (cb); out: if (result >= 0) - nm_log_dbg (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result); + _LOGD (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result); else - nm_log_err (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name); + _LOGE (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name); return result; } @@ -333,8 +341,8 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock, genlmsg_hdr (nlmsg_hdr (msg))->cmd == NL80211_CMD_GET_SCAN) break; - nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s", - err, nl_geterror (err)); + _LOGW (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s", + err, nl_geterror (err)); break; } } @@ -934,8 +942,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nl_freq, freq_policy); + if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, + nl_freq, freq_policy) < 0) + continue; if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; @@ -955,8 +964,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nl_freq, freq_policy); + if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, + nl_freq, freq_policy) < 0) + continue; if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; @@ -1003,7 +1013,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) case WLAN_CIPHER_SUITE_SMS4: break; default: - nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]); + _LOGD (LOGD_PLATFORM | LOGD_WIFI, + "don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", + ciphers[i]); break; } } @@ -1030,13 +1042,20 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) } WifiData * -wifi_nl80211_init (const char *iface, int ifindex) +wifi_nl80211_init (int ifindex) { WifiDataNl80211 *nl80211; struct nl_msg *msg; struct nl80211_device_info device_info = {}; + char ifname[IFNAMSIZ]; + + if (!nmp_utils_if_indextoname (ifindex, ifname)) { + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "can't determine interface name for ifindex %d", ifindex); + nm_sprintf_buf (ifname, "if %d", ifindex); + } - nl80211 = wifi_data_new (iface, ifindex, sizeof (*nl80211)); + nl80211 = wifi_data_new (ifindex, sizeof (*nl80211)); nl80211->parent.get_mode = wifi_nl80211_get_mode; nl80211->parent.set_mode = wifi_nl80211_set_mode; nl80211->parent.set_powersave = wifi_nl80211_set_powersave; @@ -1071,44 +1090,44 @@ wifi_nl80211_init (const char *iface, int ifindex) if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler, &device_info) < 0) { - nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, - "(%s): NL80211_CMD_GET_WIPHY request failed", - nl80211->parent.iface); + _LOGD (LOGD_PLATFORM | LOGD_WIFI, + "(%s): NL80211_CMD_GET_WIPHY request failed", + ifname); goto error; } if (!device_info.success) { - nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, - "(%s): NL80211_CMD_GET_WIPHY request indicated failure", - nl80211->parent.iface); + _LOGD (LOGD_PLATFORM | LOGD_WIFI, + "(%s): NL80211_CMD_GET_WIPHY request indicated failure", + ifname); goto error; } if (!device_info.supported) { - nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver does not fully support nl80211, falling back to WEXT", - nl80211->parent.iface); + _LOGD (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver does not fully support nl80211, falling back to WEXT", + ifname); goto error; } if (!device_info.can_scan_ssid) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver does not support SSID scans", - nl80211->parent.iface); + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver does not support SSID scans", + ifname); goto error; } if (device_info.num_freqs == 0 || device_info.freqs == NULL) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver reports no supported frequencies", - nl80211->parent.iface); + ifname); goto error; } if (device_info.caps == 0) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver doesn't report support of any encryption", - nl80211->parent.iface); + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver doesn't report support of any encryption", + ifname); goto error; } @@ -1120,9 +1139,9 @@ wifi_nl80211_init (const char *iface, int ifindex) if (device_info.can_wowlan) nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan; - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, - "(%s): using nl80211 for WiFi device control", - nl80211->parent.iface); + _LOGI (LOGD_PLATFORM | LOGD_WIFI, + "(%s): using nl80211 for WiFi device control", + ifname); return (WifiData *) nl80211; diff --git a/src/platform/wifi/wifi-utils-nl80211.h b/src/platform/wifi/wifi-utils-nl80211.h index b3e8c897..aff24555 100644 --- a/src/platform/wifi/wifi-utils-nl80211.h +++ b/src/platform/wifi/wifi-utils-nl80211.h @@ -23,6 +23,6 @@ #include "wifi-utils.h" -WifiData *wifi_nl80211_init (const char *iface, int ifindex); +WifiData *wifi_nl80211_init (int ifindex); #endif /* __WIFI_UTILS_NL80211_H__ */ diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h index ebe76f1b..11a0f060 100644 --- a/src/platform/wifi/wifi-utils-private.h +++ b/src/platform/wifi/wifi-utils-private.h @@ -25,7 +25,6 @@ #include "wifi-utils.h" struct WifiData { - char *iface; int ifindex; NMDeviceWifiCapabilities caps; @@ -69,7 +68,7 @@ struct WifiData { gboolean (*indicate_addressing_running) (WifiData *data, gboolean running); }; -gpointer wifi_data_new (const char *iface, int ifindex, gsize len); +gpointer wifi_data_new (int ifindex, gsize len); void wifi_data_free (WifiData *data); #endif /* __WIFI_UTILS_PRIVATE_H__ */ diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c index af8cf2de..1bc29ae8 100644 --- a/src/platform/wifi/wifi-utils-wext.c +++ b/src/platform/wifi/wifi-utils-wext.c @@ -26,7 +26,6 @@ #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> -#include <math.h> #include "wifi-utils-private.h" #include "wifi-utils-wext.h" @@ -69,8 +68,17 @@ struct iw_range_with_scan_capa /* don't need the rest... */ }; +#define _NMLOG_PREFIX_NAME "wifi-wext" +#define _NMLOG(level, domain, ...) \ + G_STMT_START { \ + nm_log ((level), (domain), NULL, NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + static guint32 -iw_freq_to_uint32 (struct iw_freq *freq) +iw_freq_to_uint32 (const struct iw_freq *freq) { if (freq->e == 0) { /* Some drivers report channel not frequency. Convert to a @@ -81,8 +89,7 @@ iw_freq_to_uint32 (struct iw_freq *freq) else if (freq->m == 14) return 2484; } - - return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000); + return (guint32) ((((double) freq->m) * nm_utils_exp10 (freq->e)) / 1000000.0); } static void @@ -94,20 +101,36 @@ wifi_wext_deinit (WifiData *parent) close (wext->fd); } +static gboolean +get_ifname (int ifindex, char *buffer, const char *op) +{ + int errsv; + + if (!nmp_utils_if_indextoname (ifindex, buffer)) { + errsv = errno; + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "error getting interface name for ifindex %d, operation '%s': %s (%d)", + ifindex, op, g_strerror (errsv), errsv); + return FALSE; + } + + return TRUE; +} + static NM80211Mode -wifi_wext_get_mode (WifiData *data) +wifi_wext_get_mode_ifname (WifiData *data, const char *ifname) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) { if (errno != ENODEV) { - nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, - "(%s): error %d getting card mode", - wext->parent.iface, errno); + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "(%s): error %d getting card mode", + ifname, errno); } return NM_802_11_MODE_UNKNOWN; } @@ -126,13 +149,28 @@ wifi_wext_get_mode (WifiData *data) return NM_802_11_MODE_UNKNOWN; } +static NM80211Mode +wifi_wext_get_mode (WifiData *data) +{ + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "get-mode")) + return FALSE; + + return wifi_wext_get_mode_ifname (data, ifname); +} + static gboolean wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "set-mode")) + return FALSE; - if (wifi_wext_get_mode (data) == mode) + if (wifi_wext_get_mode_ifname (data, ifname) == mode) return TRUE; memset (&wrq, 0, sizeof (struct iwreq)); @@ -151,11 +189,12 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) return FALSE; } - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) { if (errno != ENODEV) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting mode %d", - wext->parent.iface, mode); + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): error setting mode %d", + ifname, mode); } return FALSE; } @@ -168,6 +207,10 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "set-powersave")) + return FALSE; memset (&wrq, 0, sizeof (struct iwreq)); if (powersave == 1) { @@ -175,11 +218,12 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave) } else wrq.u.power.disabled = 1; - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) { if (errno != ENODEV) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT, - wext->parent.iface, powersave); + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): error setting powersave %" G_GUINT32_FORMAT, + ifname, powersave); } return FALSE; } @@ -192,13 +236,17 @@ wifi_wext_get_freq (WifiData *data) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "get-freq")) + return FALSE; memset (&wrq, 0, sizeof (struct iwreq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) { - nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, - "(%s): error getting frequency: %s", - wext->parent.iface, strerror (errno)); + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "(%s): error getting frequency: %s", + ifname, strerror (errno)); return 0; } @@ -226,13 +274,17 @@ wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "get-bssid")) + return FALSE; memset (&wrq, 0, sizeof (wrq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) { - nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, - "(%s): error getting associated BSSID: %s", - wext->parent.iface, strerror (errno)); + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "(%s): error getting associated BSSID: %s", + ifname, strerror (errno)); return FALSE; } memcpy (out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN); @@ -245,9 +297,13 @@ wifi_wext_get_rate (WifiData *data) WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; int err; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "get-rate")) + return FALSE; memset (&wrq, 0, sizeof (wrq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); err = ioctl (wext->fd, SIOCGIWRATE, &wrq); return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0); } @@ -264,16 +320,16 @@ wext_qual_to_percent (const struct iw_quality *qual, /* Magically convert the many different WEXT quality representations to a percentage */ - nm_log_dbg (LOGD_WIFI, - "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", - (__s8) qual->qual, qual->qual, qual->qual, - (__s8) qual->level, qual->level, qual->level, - (__s8) qual->noise, qual->noise, qual->noise, - qual->updated, - (__s8) max_qual->qual, max_qual->qual, max_qual->qual, - (__s8) max_qual->level, max_qual->level, max_qual->level, - (__s8) max_qual->noise, max_qual->noise, max_qual->noise, - max_qual->updated); + _LOGD (LOGD_WIFI, + "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", + (__s8) qual->qual, qual->qual, qual->qual, + (__s8) qual->level, qual->level, qual->level, + (__s8) qual->noise, qual->noise, qual->noise, + qual->updated, + (__s8) max_qual->qual, max_qual->qual, max_qual->qual, + (__s8) max_qual->level, max_qual->level, max_qual->level, + (__s8) max_qual->noise, max_qual->noise, max_qual->noise, + max_qual->updated); /* Try using the card's idea of the signal quality first as long as it tells us what the max quality is. * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be @@ -319,8 +375,8 @@ wext_qual_to_percent (const struct iw_quality *qual, /* A sort of signal-to-noise ratio calculation */ level_percent = (int) (100 - 70 * (((double)max_level - (double)level) / ((double)max_level - (double)noise))); - nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", - level_percent, max_level, level, noise); + _LOGD (LOGD_WIFI, "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", + level_percent, max_level, level, noise); } else if ( (max_qual->level != 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */ && !(qual->updated & IW_QUAL_LEVEL_INVALID)) { @@ -331,18 +387,18 @@ wext_qual_to_percent (const struct iw_quality *qual, /* Signal level is relavtive (0 -> max_qual->level) */ level = CLAMP (level, 0, max_qual->level); level_percent = (int)(100 * ((double)level / (double)max_qual->level)); - nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d. max_level %d, level %d.", - level_percent, max_qual->level, level); + _LOGD (LOGD_WIFI, "QL2: level_percent is %d. max_level %d, level %d.", + level_percent, max_qual->level, level); } else if (percent == -1) { - nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver. Driver is probably buggy."); + _LOGD (LOGD_WIFI, "QL: Could not get quality %% value from driver. Driver is probably buggy."); } /* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */ if ((percent < 1) && (level_percent >= 0)) percent = level_percent; - nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).", - percent, CLAMP (percent, 0, 100)); + _LOGD (LOGD_WIFI, "QL: Final quality percent is %d (%d).", + percent, CLAMP (percent, 0, 100)); return (CLAMP (percent, 0, 100)); } @@ -352,17 +408,21 @@ wifi_wext_get_qual (WifiData *data) WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; struct iw_statistics stats; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "get-qual")) + return FALSE; memset (&stats, 0, sizeof (stats)); wrq.u.data.pointer = &stats; wrq.u.data.length = sizeof (stats); wrq.u.data.flags = 1; /* Clear updated flag */ - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) { - nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, - "(%s): error getting signal strength: %s", - wext->parent.iface, strerror (errno)); + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "(%s): error getting signal strength: %s", + ifname, strerror (errno)); return -1; } @@ -392,9 +452,13 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; + char ifname[IFNAMSIZ]; + + if (!get_ifname (data->ifindex, ifname, "set-mesh-channel")) + return FALSE; memset (&wrq, 0, sizeof (struct iwreq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (channel > 0) { wrq.u.freq.flags = IW_FREQ_FIXED; @@ -403,9 +467,9 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) } if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, - "(%s): error setting channel to %d: %s", - wext->parent.iface, channel, strerror (errno)); + _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, + "(%s): error setting channel to %d: %s", + ifname, channel, strerror (errno)); return FALSE; } @@ -418,6 +482,11 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; char buf[IW_ESSID_MAX_SIZE + 1]; + char ifname[IFNAMSIZ]; + int errsv; + + if (!get_ifname (data->ifindex, ifname, "set-mesh-ssid")) + return FALSE; memset (buf, 0, sizeof (buf)); memcpy (buf, ssid, MIN (sizeof (buf) - 1, len)); @@ -426,16 +495,17 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) wrq.u.essid.length = len; wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */ - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0) return TRUE; if (errno != ENODEV) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, - "(%s): error setting SSID to '%s': %s", - wext->parent.iface, - ssid ? nm_utils_escape_ssid (ssid, len) : "(null)", - strerror (errno)); + errsv = errno; + _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, + "(%s): error setting SSID to '%s': %s", + ifname, + ssid ? nm_utils_escape_ssid (ssid, len) : "(null)", + strerror (errsv)); } return FALSE; @@ -444,12 +514,12 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) /*****************************************************************************/ static gboolean -wext_can_scan (WifiDataWext *wext) +wext_can_scan_ifname (WifiDataWext *wext, const char *ifname) { struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCSIWSCAN, &wrq) < 0) { if (errno == EOPNOTSUPP) return FALSE; @@ -458,16 +528,17 @@ wext_can_scan (WifiDataWext *wext) } static gboolean -wext_get_range (WifiDataWext *wext, - struct iw_range *range, - guint32 *response_len) +wext_get_range_ifname (WifiDataWext *wext, + const char *ifname, + struct iw_range *range, + guint32 *response_len) { int i = 26; gboolean success = FALSE; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); + nm_utils_ifname_cpy (wrq.ifr_name, ifname); wrq.u.data.pointer = (caddr_t) range; wrq.u.data.length = sizeof (struct iw_range); @@ -482,9 +553,9 @@ wext_get_range (WifiDataWext *wext, success = TRUE; break; } else if (errno != EAGAIN) { - nm_log_err (LOGD_PLATFORM | LOGD_WIFI, - "(%s): couldn't get driver range information (%d).", - wext->parent.iface, errno); + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): couldn't get driver range information (%d).", + ifname, errno); break; } @@ -492,9 +563,9 @@ wext_get_range (WifiDataWext *wext, } if (i <= 0) { - nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver took too long to respond to IWRANGE query.", - wext->parent.iface); + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver took too long to respond to IWRANGE query.", + ifname); } return success; @@ -506,7 +577,7 @@ wext_get_range (WifiDataWext *wext, NM_WIFI_DEVICE_CAP_RSN) static guint32 -wext_get_caps (WifiDataWext *wext, struct iw_range *range) +wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range) { guint32 caps = NM_WIFI_DEVICE_CAP_NONE; @@ -531,16 +602,18 @@ wext_get_caps (WifiDataWext *wext, struct iw_range *range) /* Check for cipher support but not WPA support */ if ( (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP)) && !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) { - nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; " - "WPA unavailable.", wext->parent.iface); + _LOGW (LOGD_WIFI, + "%s: device supports WPA ciphers but not WPA protocol; WPA unavailable.", + ifname); caps &= ~WPA_CAPS; } /* Check for WPA support but not cipher support */ if ( (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN)) && !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) { - nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; " - "WPA unavailable.", wext->parent.iface); + _LOGW (LOGD_WIFI, + "%s: device supports WPA protocol but not WPA ciphers; WPA unavailable.", + ifname); caps &= ~WPA_CAPS; } @@ -554,7 +627,7 @@ wext_get_caps (WifiDataWext *wext, struct iw_range *range) } WifiData * -wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) +wifi_wext_init (int ifindex, gboolean check_scan) { WifiDataWext *wext; struct iw_range range; @@ -562,8 +635,15 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) struct iw_range_with_scan_capa *scan_capa_range; int i; gboolean freq_valid = FALSE, has_5ghz = FALSE, has_2ghz = FALSE; + char ifname[IFNAMSIZ]; + + if (!nmp_utils_if_indextoname (ifindex, ifname)) { + _LOGW (LOGD_PLATFORM | LOGD_WIFI, + "can't determine interface name for ifindex %d", ifindex); + return NULL; + } - wext = wifi_data_new (iface, ifindex, sizeof (*wext)); + wext = wifi_data_new (ifindex, sizeof (*wext)); wext->parent.get_mode = wifi_wext_get_mode; wext->parent.set_mode = wifi_wext_set_mode; wext->parent.set_powersave = wifi_wext_set_powersave; @@ -582,17 +662,17 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) goto error; memset (&range, 0, sizeof (struct iw_range)); - if (wext_get_range (wext, &range, &response_len) == FALSE) { - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed", - wext->parent.iface); + if (wext_get_range_ifname (wext, ifname, &range, &response_len) == FALSE) { + _LOGI (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed", + ifname); goto error; } if ((response_len < 300) || (range.we_version_compiled < 21)) { - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver WEXT version too old (got %d, expected >= 21)", - wext->parent.iface, - range.we_version_compiled); + _LOGI (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver WEXT version too old (got %d, expected >= 21)", + ifname, + range.we_version_compiled); goto error; } @@ -612,10 +692,10 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) } /* Check for scanning capability; cards that can't scan are not supported */ - if (check_scan && (wext_can_scan (wext) == FALSE)) { - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, - "(%s): drivers that cannot scan are unsupported", - wext->parent.iface); + if (check_scan && (wext_can_scan_ifname (wext, ifname) == FALSE)) { + _LOGI (LOGD_PLATFORM | LOGD_WIFI, + "(%s): drivers that cannot scan are unsupported", + ifname); goto error; } @@ -625,18 +705,18 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) */ scan_capa_range = (struct iw_range_with_scan_capa *) ⦥ if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) { - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver supports SSID scans (scan_capa 0x%02X).", - wext->parent.iface, - scan_capa_range->scan_capa); + _LOGI (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver supports SSID scans (scan_capa 0x%02X).", + ifname, + scan_capa_range->scan_capa); } else { - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver does not support SSID scans (scan_capa 0x%02X).", - wext->parent.iface, - scan_capa_range->scan_capa); + _LOGI (LOGD_PLATFORM | LOGD_WIFI, + "(%s): driver does not support SSID scans (scan_capa 0x%02X).", + ifname, + scan_capa_range->scan_capa); } - wext->parent.caps = wext_get_caps (wext, &range); + wext->parent.caps = wext_get_caps (wext, ifname, &range); if (freq_valid) wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID; if (has_2ghz) @@ -644,9 +724,9 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) if (has_5ghz) wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ; - nm_log_info (LOGD_PLATFORM | LOGD_WIFI, - "(%s): using WEXT for WiFi device control", - wext->parent.iface); + _LOGI (LOGD_PLATFORM | LOGD_WIFI, + "(%s): using WEXT for WiFi device control", + ifname); return (WifiData *) wext; diff --git a/src/platform/wifi/wifi-utils-wext.h b/src/platform/wifi/wifi-utils-wext.h index e168fe28..3ef5a173 100644 --- a/src/platform/wifi/wifi-utils-wext.h +++ b/src/platform/wifi/wifi-utils-wext.h @@ -23,7 +23,7 @@ #include "wifi-utils.h" -WifiData *wifi_wext_init (const char *iface, int ifindex, gboolean check_scan); +WifiData *wifi_wext_init (int ifindex, gboolean check_scan); gboolean wifi_wext_is_wifi (const char *iface); diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c index b8da02c1..d0052121 100644 --- a/src/platform/wifi/wifi-utils.c +++ b/src/platform/wifi/wifi-utils.c @@ -38,12 +38,11 @@ #include "platform/nm-platform-utils.h" gpointer -wifi_data_new (const char *iface, int ifindex, gsize len) +wifi_data_new (int ifindex, gsize len) { WifiData *data; data = g_malloc0 (len); - data->iface = g_strdup (iface); data->ifindex = ifindex; return data; } @@ -51,7 +50,6 @@ wifi_data_new (const char *iface, int ifindex, gsize len) void wifi_data_free (WifiData *data) { - g_free (data->iface); memset (data, 0, sizeof (*data)); g_free (data); } @@ -59,17 +57,16 @@ wifi_data_free (WifiData *data) /*****************************************************************************/ WifiData * -wifi_utils_init (const char *iface, int ifindex, gboolean check_scan) +wifi_utils_init (int ifindex, gboolean check_scan) { WifiData *ret; - g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (ifindex > 0, NULL); - ret = wifi_nl80211_init (iface, ifindex); + ret = wifi_nl80211_init (ifindex); if (ret == NULL) { #if HAVE_WEXT - ret = wifi_wext_init (iface, ifindex, check_scan); + ret = wifi_wext_init (ifindex, check_scan); #endif } return ret; @@ -83,14 +80,6 @@ wifi_utils_get_ifindex (WifiData *data) return data->ifindex; } -const char * -wifi_utils_get_iface (WifiData *data) -{ - g_return_val_if_fail (data != NULL, NULL); - - return data->iface; -} - NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data) { diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h index 4fd5a80b..705717b0 100644 --- a/src/platform/wifi/wifi-utils.h +++ b/src/platform/wifi/wifi-utils.h @@ -30,12 +30,10 @@ typedef struct WifiData WifiData; gboolean wifi_utils_is_wifi (int dirfd, const char *ifname); -WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan); +WifiData *wifi_utils_init (int ifindex, gboolean check_scan); int wifi_utils_get_ifindex (WifiData *data); -const char *wifi_utils_get_iface (WifiData *data); - void wifi_utils_deinit (WifiData *data); NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data); diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index 1bbe29d4..c7836a8f 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -57,7 +57,8 @@ #include "introspection/org.freedesktop.NetworkManager.PPP.h" #define NM_PPPD_PLUGIN PPPD_PLUGIN_DIR "/nm-pppd-plugin.so" -#define PPP_MANAGER_SECRET_TRIES "ppp-manager-secret-tries" + +static NM_CACHED_QUARK_FCN ("ppp-manager-secret-tries", ppp_manager_secret_tries_quark) /*****************************************************************************/ @@ -149,8 +150,8 @@ monitor_cb (gpointer user_data) _LOGW ("could not read ppp stats: %s", strerror (errno)); } else { g_signal_emit (manager, signals[STATS], 0, - stats.p.ppp_ibytes, - stats.p.ppp_obytes); + (guint) stats.p.ppp_ibytes, + (guint) stats.p.ppp_obytes); } return TRUE; @@ -341,7 +342,7 @@ impl_ppp_manager_need_secrets (NMPPPManager *manager, * appear to ask a few times when they actually don't even care what you * pass back. */ - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES)); + tries = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (applied_connection), ppp_manager_secret_tries_quark())); if (tries > 1) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; @@ -352,7 +353,7 @@ impl_ppp_manager_need_secrets (NMPPPManager *manager, hints ? g_ptr_array_index (hints, 0) : NULL, ppp_secrets_cb, manager); - g_object_set_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES, GUINT_TO_POINTER (++tries)); + g_object_set_qdata (G_OBJECT (applied_connection), ppp_manager_secret_tries_quark (), GUINT_TO_POINTER (++tries)); priv->pending_secrets_context = context; if (hints) @@ -389,7 +390,7 @@ set_ip_config_common (NMPPPManager *self, /* Got successful IP config; obviously the secrets worked */ applied_connection = nm_act_request_get_applied_connection (priv->act_req); - g_object_set_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES, NULL); + g_object_set_qdata (G_OBJECT (applied_connection), ppp_manager_secret_tries_quark (), NULL); if (out_mtu) { /* Get any custom MTU */ @@ -715,6 +716,8 @@ create_pppd_cmd_line (NMPPPManager *self, NMSettingAdsl *adsl, const char *ppp_name, guint baud_override, + gboolean ip4_enabled, + gboolean ip6_enabled, GError **err) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); @@ -728,6 +731,14 @@ create_pppd_cmd_line (NMPPPManager *self, if (!pppd_binary) return NULL; + if (!ip4_enabled && !ip6_enabled) { + g_set_error_literal (err, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Neither IPv4 or IPv6 allowed."); + return NULL; + } + /* Create pppd command line */ cmd = nm_cmd_line_new (); nm_cmd_line_add_string (cmd, pppd_binary); @@ -738,9 +749,15 @@ create_pppd_cmd_line (NMPPPManager *self, /* NM handles setting the default route */ nm_cmd_line_add_string (cmd, "nodefaultroute"); - /* Allow IPv6 to be configured by IPV6CP */ - nm_cmd_line_add_string (cmd, "ipv6"); - nm_cmd_line_add_string (cmd, ","); + if (!ip4_enabled) + nm_cmd_line_add_string (cmd, "noip"); + + if (ip6_enabled) { + /* Allow IPv6 to be configured by IPV6CP */ + nm_cmd_line_add_string (cmd, "ipv6"); + nm_cmd_line_add_string (cmd, ","); + } else + nm_cmd_line_add_string (cmd, "noipv6"); ppp_debug = !!getenv ("NM_PPP_DEBUG"); if (nm_logging_enabled (LOGL_DEBUG, LOGD_PPP)) @@ -918,6 +935,9 @@ _ppp_manager_start (NMPPPManager *manager, NMCmdLine *ppp_cmd; char *cmd_str; struct stat st; + const char *ip6_method, *ip4_method; + gboolean ip6_enabled = FALSE; + gboolean ip4_enabled = FALSE; g_return_val_if_fail (NM_IS_PPP_MANAGER (manager), FALSE); g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); @@ -962,7 +982,21 @@ _ppp_manager_start (NMPPPManager *manager, adsl_setting = (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL); - ppp_cmd = create_pppd_cmd_line (manager, s_ppp, pppoe_setting, adsl_setting, ppp_name, baud_override, err); + /* Figure out what address methods should be enabled */ + ip4_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); + ip4_enabled = g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0; + ip6_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); + ip6_enabled = g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0; + + ppp_cmd = create_pppd_cmd_line (manager, + s_ppp, + pppoe_setting, + adsl_setting, + ppp_name, + baud_override, + ip4_enabled, + ip6_enabled, + err); if (!ppp_cmd) goto out; @@ -1276,7 +1310,8 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) 0, NULL, NULL, NULL, G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); + G_TYPE_UINT /*guint32 in_bytes*/, + G_TYPE_UINT /*guint32 out_bytes*/); nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class), NMDBUS_TYPE_PPP_MANAGER_SKELETON, diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 0db20979..3d6b1cfb 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -103,7 +103,7 @@ NM_DEFINE_SINGLETON_GETTER (NMAgentManager, nm_agent_manager_get, NM_TYPE_AGENT_ nm_secret_agent_get_description (__agent)); \ } else \ __prefix2[0] = '\0'; \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ __prefix1, __prefix2 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ @@ -178,7 +178,7 @@ remove_agent (NMAgentManager *self, const char *owner) while (g_hash_table_iter_next (&iter, &data, NULL)) request_remove_agent ((Request *) data, agent, &pending_reqs); - /* We cannot call request_next_agent() from from within hash iterating loop, + /* We cannot call request_next_agent() from within hash iterating loop, * because it may remove the request from the hash table, which invalidates * the iterator. So, only remove the agent from requests. And store the requests * that should be sent to other agent to a temporary list to proceed afterwards. diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 6ec96a32..b9ca34d0 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -87,7 +87,7 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ else \ g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index 0b6da136..54c5b398 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_SECRET_AGENT_H__ #define __NETWORKMANAGER_SECRET_AGENT_H__ -#include <nm-connection.h> +#include "nm-connection.h" #define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ()) #define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 81dcb698..0cb2920c 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -69,17 +69,24 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; typedef struct _NMSettingsConnectionPrivate { - gboolean removed; NMAgentManager *agent_mgr; NMSessionMonitor *session_monitor; gulong session_changed_id; NMSettingsConnectionFlags flags; - gboolean ready; + + bool removed:1; + bool ready:1; + + /* Is this connection visible by some session? */ + bool visible:1; + + bool timestamp_set:1; + + NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:3; GSList *pending_auths; /* List of pending authentication requests */ - gboolean visible; /* Is this connection is visible by some session? */ GSList *get_secret_requests; /* in-progress secrets requests */ @@ -99,12 +106,10 @@ typedef struct _NMSettingsConnectionPrivate { NMConnection *agent_secrets; guint64 timestamp; /* Up-to-date timestamp of connection use */ - gboolean timestamp_set; GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */ int autoconnect_retries; gint32 autoconnect_retry_time; - NMDeviceStateReason autoconnect_blocked_reason; char *filename; } NMSettingsConnectionPrivate; @@ -126,14 +131,13 @@ G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_E if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ char __prefix[128]; \ const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + const char *__uuid = (self) ? nm_settings_connection_get_uuid (self) : NULL; \ \ if (self) { \ - const char *__uuid = nm_settings_connection_get_uuid (self); \ - \ g_snprintf (__prefix, sizeof (__prefix), "%s[%p%s%s]", _NMLOG_PREFIX_NAME, self, __uuid ? "," : "", __uuid ? __uuid : ""); \ __p_prefix = __prefix; \ } \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, __uuid, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ @@ -493,7 +497,7 @@ set_unsaved (NMSettingsConnection *self, gboolean now_unsaved) else { flags &= ~(NM_SETTINGS_CONNECTION_FLAGS_UNSAVED | NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED); + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE); } nm_settings_connection_set_flags_all (self, flags); } @@ -556,7 +560,7 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, _LOGD ("replace settings from connection %p (%s)", new_connection, nm_connection_get_id (NM_CONNECTION (self))); nm_settings_connection_set_flags (self, - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED, + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, FALSE); /* Cache the just-updated system secrets in case something calls @@ -1648,49 +1652,6 @@ con_update_cb (NMSettingsConnection *self, update_complete (self, info, error); } -static char * -con_list_changed_props (NMConnection *old, NMConnection *new) -{ - gs_unref_hashtable GHashTable *diff = NULL; - GHashTable *setting_diff; - char *setting_name, *prop_name; - GHashTableIter iter, iter2; - gboolean same; - GString *str; - - same = nm_connection_diff (old, new, - NM_SETTING_COMPARE_FLAG_EXACT | - NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, - &diff); - - if (same || !diff) - return NULL; - - str = g_string_sized_new (32); - g_hash_table_iter_init (&iter, diff); - - while (g_hash_table_iter_next (&iter, - (gpointer *) &setting_name, - (gpointer *) &setting_diff)) { - if (!setting_diff) - continue; - - g_hash_table_iter_init (&iter2, setting_diff); - - while (g_hash_table_iter_next (&iter2, (gpointer *) &prop_name, NULL)) { - g_string_append (str, setting_name); - g_string_append_c (str, '.'); - g_string_append (str, prop_name); - g_string_append_c (str, ','); - } - } - - if (str->len) - str->str[str->len - 1] = '\0'; - - return g_string_free (str, FALSE); -} - static void update_auth_cb (NMSettingsConnection *self, GDBusMethodInvocation *context, @@ -1706,6 +1667,17 @@ update_auth_cb (NMSettingsConnection *self, return; } + if (!info->new_settings) { + /* We're just calling Save(). Just commit the existing connection. */ + if (info->save_to_disk) { + nm_settings_connection_commit_changes (self, + NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION, + con_update_cb, + info); + } + return; + } + if (!any_secrets_present (info->new_settings)) { /* If the new connection has no secrets, we do not want to remove all * secrets, rather we keep all the existing ones. Do that by merging @@ -1720,8 +1692,17 @@ update_auth_cb (NMSettingsConnection *self, update_agent_secrets_cache (self, info->new_settings); } - if (nm_audit_manager_audit_enabled (nm_audit_manager_get ())) - info->audit_args = con_list_changed_props (NM_CONNECTION (self), info->new_settings); + if (nm_audit_manager_audit_enabled (nm_audit_manager_get ())) { + gs_unref_hashtable GHashTable *diff = NULL; + gboolean same; + + same = nm_connection_diff (NM_CONNECTION (self), info->new_settings, + NM_SETTING_COMPARE_FLAG_EXACT | + NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, + &diff); + if (!same && diff) + info->audit_args = nm_utils_format_con_diff_for_audit (diff); + } if (info->save_to_disk) { nm_settings_connection_replace_and_commit (self, @@ -1855,11 +1836,7 @@ static void impl_settings_connection_save (NMSettingsConnection *self, GDBusMethodInvocation *context) { - /* Do nothing if the connection is already synced with disk */ - if (nm_settings_connection_get_unsaved (self)) - settings_connection_update_helper (self, context, NULL, TRUE); - else - g_dbus_method_invocation_return_value (context, NULL); + settings_connection_update_helper (self, context, NULL, TRUE); } static void @@ -2162,6 +2139,96 @@ nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConn /*****************************************************************************/ +static int +_cmp_timestamp (NMSettingsConnection *a, NMSettingsConnection *b) +{ + gboolean a_has_ts, b_has_ts; + guint64 ats = 0, bts = 0; + + nm_assert (NM_IS_SETTINGS_CONNECTION (a)); + nm_assert (NM_IS_SETTINGS_CONNECTION (b)); + + a_has_ts = !!nm_settings_connection_get_timestamp (a, &ats); + b_has_ts = !!nm_settings_connection_get_timestamp (b, &bts); + if (a_has_ts != b_has_ts) + return a_has_ts ? -1 : 1; + if (a_has_ts && ats != bts) + return (ats > bts) ? -1 : 1; + return 0; +} + +static int +_cmp_last_resort (NMSettingsConnection *a, NMSettingsConnection *b) +{ + int c; + + nm_assert (NM_IS_SETTINGS_CONNECTION (a)); + nm_assert (NM_IS_SETTINGS_CONNECTION (b)); + + c = g_strcmp0 (nm_connection_get_uuid (NM_CONNECTION (a)), + nm_connection_get_uuid (NM_CONNECTION (b))); + if (c) + return c; + + /* hm, same UUID. Use their pointer value to give them a stable + * order. */ + return (a > b) ? -1 : 1; +} + +/* sorting for "best" connections. + * The function sorts connections in descending timestamp order. + * That means an older connection (lower timestamp) goes after + * a newer one. + */ +int +nm_settings_connection_cmp_timestamp (NMSettingsConnection *a, NMSettingsConnection *b) +{ + int c; + + if (a == b) + return 0; + if (!a) + return 1; + if (!b) + return -1; + + if ((c = _cmp_timestamp (a, b))) + return c; + if ((c = nm_utils_cmp_connection_by_autoconnect_priority (NM_CONNECTION (a), NM_CONNECTION (b)))) + return c; + return _cmp_last_resort (a, b); +} + +int +nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + return nm_settings_connection_cmp_timestamp (*((NMSettingsConnection **) pa), + *((NMSettingsConnection **) pb)); +} + +int +nm_settings_connection_cmp_autoconnect_priority (NMSettingsConnection *a, NMSettingsConnection *b) +{ + int c; + + if (a == b) + return 0; + if ((c = nm_utils_cmp_connection_by_autoconnect_priority (NM_CONNECTION (a), NM_CONNECTION (b)))) + return c; + if ((c = _cmp_timestamp (a, b))) + return c; + return _cmp_last_resort (a, b); +} + +int +nm_settings_connection_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + return nm_settings_connection_cmp_autoconnect_priority (*((NMSettingsConnection **) pa), + *((NMSettingsConnection **) pb)); +} + +/*****************************************************************************/ + /** * nm_settings_connection_get_timestamp: * @self: the #NMSettingsConnection @@ -2483,7 +2550,7 @@ nm_settings_connection_get_autoconnect_retries (NMSettingsConnection *self) priv->autoconnect_retries = retries; } - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retries; + return priv->autoconnect_retries; } void @@ -2492,7 +2559,10 @@ nm_settings_connection_set_autoconnect_retries (NMSettingsConnection *self, { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - priv->autoconnect_retries = retries; + if (priv->autoconnect_retries != retries) { + _LOGT ("autoconnect-retries: set %d", retries); + priv->autoconnect_retries = retries; + } if (retries) priv->autoconnect_retry_time = 0; else @@ -2511,7 +2581,7 @@ nm_settings_connection_get_autoconnect_retry_time (NMSettingsConnection *self) return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retry_time; } -NMDeviceStateReason +NMSettingsAutoconnectBlockedReason nm_settings_connection_get_autoconnect_blocked_reason (NMSettingsConnection *self) { return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason; @@ -2519,8 +2589,12 @@ nm_settings_connection_get_autoconnect_blocked_reason (NMSettingsConnection *sel void nm_settings_connection_set_autoconnect_blocked_reason (NMSettingsConnection *self, - NMDeviceStateReason reason) + NMSettingsAutoconnectBlockedReason reason) { + g_return_if_fail (NM_IN_SET (reason, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_UNBLOCKED, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_BLOCKED, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS)); NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason = reason; } @@ -2533,7 +2607,7 @@ nm_settings_connection_can_autoconnect (NMSettingsConnection *self) if ( !priv->visible || priv->autoconnect_retries == 0 - || priv->autoconnect_blocked_reason != NM_DEVICE_STATE_REASON_NONE) + || priv->autoconnect_blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_UNBLOCKED) return FALSE; s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); @@ -2566,18 +2640,18 @@ nm_settings_connection_get_nm_generated (NMSettingsConnection *self) } /** - * nm_settings_connection_get_nm_generated_assumed: + * nm_settings_connection_get_volatile: * @self: an #NMSettingsConnection * - * Gets the "nm-generated-assumed" flag on @self. + * Gets the "volatile" flag on @self. * - * The connection is a generated connection especially - * generated for connection assumption. + * The connection is marked as volatile and will be removed when + * it disconnects. */ gboolean -nm_settings_connection_get_nm_generated_assumed (NMSettingsConnection *self) +nm_settings_connection_get_volatile (NMSettingsConnection *self) { - return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED); + return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_VOLATILE); } gboolean @@ -2673,7 +2747,6 @@ nm_settings_connection_init (NMSettingsConnection *self) priv->seen_bssids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); priv->autoconnect_retries = AUTOCONNECT_RETRIES_UNSET; - priv->autoconnect_blocked_reason = NM_DEVICE_STATE_REASON_NONE; g_signal_connect (self, NM_CONNECTION_SECRETS_CLEARED, G_CALLBACK (secrets_cleared_cb), NULL); g_signal_connect (self, NM_CONNECTION_CHANGED, G_CALLBACK (connection_changed_cb), NULL); @@ -2772,13 +2845,8 @@ set_property (GObject *object, guint prop_id, NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); switch (prop_id) { - case PROP_READY: - nm_settings_connection_set_ready (self, g_value_get_boolean (value)); - break; - case PROP_FLAGS: - nm_settings_connection_set_flags_all (self, g_value_get_uint (value)); - break; case PROP_FILENAME: + /* construct-only */ nm_settings_connection_set_filename (self, g_value_get_string (value)); break; default: @@ -2822,7 +2890,7 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) obj_properties[PROP_READY] = g_param_spec_boolean (NM_SETTINGS_CONNECTION_READY, "", "", TRUE, - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_FLAGS] = @@ -2830,13 +2898,14 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) NM_SETTINGS_CONNECTION_FLAGS_NONE, NM_SETTINGS_CONNECTION_FLAGS_ALL, NM_SETTINGS_CONNECTION_FLAGS_NONE, - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_FILENAME] = g_param_spec_string (NM_SETTINGS_CONNECTION_FILENAME, "", "", NULL, G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index c5ddd817..b449e2bd 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -25,7 +25,7 @@ #include <net/ethernet.h> #include "nm-exported-object.h" -#include <nm-connection.h> +#include "nm-connection.h" #define NM_TYPE_SETTINGS_CONNECTION (nm_settings_connection_get_type ()) #define NM_SETTINGS_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnection)) @@ -58,9 +58,9 @@ * @NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED: A connection is "nm-generated" if * it was generated by NetworkManger. If the connection gets modified or saved * by the user, the flag gets cleared. A nm-generated is implicitly unsaved. - * @NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED: A special kind of "nm-generated" - * connection that was specifically created for connection assumption. "nm-generated-assumed" - * implies "nm-generated". + * @NM_SETTINGS_CONNECTION_FLAGS_VOLATILE: The connection will be deleted + * when it disconnects. That is for in-memory connections (unsaved), which are + * currently active but cleanup on disconnect. * @NM_SETTINGS_CONNECTION_FLAGS_ALL: special mask, for all known flags * * #NMSettingsConnection flags. @@ -70,7 +70,7 @@ typedef enum NM_SETTINGS_CONNECTION_FLAGS_NONE = 0x00, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED = 0x01, NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED = 0x02, - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED = 0x04, + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE = 0x04, __NM_SETTINGS_CONNECTION_FLAGS_LAST, NM_SETTINGS_CONNECTION_FLAGS_ALL = ((__NM_SETTINGS_CONNECTION_FLAGS_LAST - 1) << 1) - 1, @@ -82,6 +82,12 @@ typedef enum { /*< skip >*/ NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED = (1LL << 1), } NMSettingsConnectionCommitReason; +typedef enum { + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_UNBLOCKED = 0, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_BLOCKED = 1, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = 2, +} NMSettingsAutoconnectBlockedReason; + struct _NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId; @@ -184,6 +190,11 @@ NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection NMSettingsConnectionFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set); NMSettingsConnectionFlags nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags); +int nm_settings_connection_cmp_timestamp (NMSettingsConnection *ac, NMSettingsConnection *ab); +int nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); +int nm_settings_connection_cmp_autoconnect_priority (NMSettingsConnection *a, NMSettingsConnection *b); +int nm_settings_connection_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); + gboolean nm_settings_connection_get_timestamp (NMSettingsConnection *self, guint64 *out_timestamp); @@ -210,14 +221,14 @@ void nm_settings_connection_reset_autoconnect_retries (NMSettingsConnection *sel gint32 nm_settings_connection_get_autoconnect_retry_time (NMSettingsConnection *self); -NMDeviceStateReason nm_settings_connection_get_autoconnect_blocked_reason (NMSettingsConnection *self); -void nm_settings_connection_set_autoconnect_blocked_reason (NMSettingsConnection *self, - NMDeviceStateReason reason); +NMSettingsAutoconnectBlockedReason nm_settings_connection_get_autoconnect_blocked_reason (NMSettingsConnection *self); +void nm_settings_connection_set_autoconnect_blocked_reason (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason reason); gboolean nm_settings_connection_can_autoconnect (NMSettingsConnection *self); gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *self); -gboolean nm_settings_connection_get_nm_generated_assumed (NMSettingsConnection *self); +gboolean nm_settings_connection_get_volatile (NMSettingsConnection *self); gboolean nm_settings_connection_get_ready (NMSettingsConnection *self); void nm_settings_connection_set_ready (NMSettingsConnection *self, diff --git a/src/settings/nm-settings-plugin.h b/src/settings/nm-settings-plugin.h index 8abd72ea..97bb7b65 100644 --- a/src/settings/nm-settings-plugin.h +++ b/src/settings/nm-settings-plugin.h @@ -22,7 +22,7 @@ #ifndef __NETWORKMANAGER_SETTINGS_PLUGIN_H__ #define __NETWORKMANAGER_SETTINGS_PLUGIN_H__ -#include <nm-connection.h> +#include "nm-connection.h" /* Plugin's factory function that returns a GObject that implements * NMSettingsPlugin. diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 35790a12..afd1b084 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -104,7 +104,7 @@ EXPORT(nm_settings_connection_replace_and_commit) #define IFCFG_DIR SYSCONFDIR "/sysconfig/network" #define CONF_DHCP IFCFG_DIR "/dhcp" -#define PLUGIN_MODULE_PATH "plugin-module-path" +static NM_CACHED_QUARK_FCN ("plugin-module-path", plugin_module_path_quark) #if (defined(HOSTNAME_PERSIST_SUSE) + defined(HOSTNAME_PERSIST_SLACKWARE) + defined(HOSTNAME_PERSIST_GENTOO)) > 1 #error "Can only define one of HOSTNAME_PERSIST_*" @@ -120,6 +120,9 @@ EXPORT(nm_settings_connection_replace_and_commit) #define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT #endif +static NM_CACHED_QUARK_FCN ("default-wired-connection", _default_wired_connection_quark) +static NM_CACHED_QUARK_FCN ("default-wired-device", _default_wired_device_quark) + /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE (NMSettings, @@ -390,35 +393,6 @@ error: g_clear_object (&subject); } -static int -connection_sort (gconstpointer pa, gconstpointer pb) -{ - NMConnection *a = NM_CONNECTION (pa); - NMSettingConnection *con_a; - NMConnection *b = NM_CONNECTION (pb); - NMSettingConnection *con_b; - guint64 ts_a = 0, ts_b = 0; - gboolean can_ac_a, can_ac_b; - - con_a = nm_connection_get_setting_connection (a); - g_assert (con_a); - con_b = nm_connection_get_setting_connection (b); - g_assert (con_b); - - can_ac_a = !!nm_setting_connection_get_autoconnect (con_a); - can_ac_b = !!nm_setting_connection_get_autoconnect (con_b); - if (can_ac_a != can_ac_b) - return can_ac_a ? -1 : 1; - - nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pa), &ts_a); - nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pb), &ts_b); - if (ts_a > ts_b) - return -1; - else if (ts_a == ts_b) - return 0; - return 1; -} - /** * nm_settings_get_connections: * @self: the #NMSettings @@ -444,46 +418,98 @@ nm_settings_get_connections (NMSettings *self, guint *out_len) priv = NM_SETTINGS_GET_PRIVATE (self); - if (priv->connections_cached_list) { + if (G_LIKELY (priv->connections_cached_list)) { NM_SET_OUT (out_len, g_hash_table_size (priv->connections)); return priv->connections_cached_list; } l = g_hash_table_size (priv->connections); - v = g_new (NMSettingsConnection *, l + 1); + v = g_new (NMSettingsConnection *, (gsize) l + 1); i = 0; g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) { + nm_assert (i < l); v[i++] = con; - v[i] = NULL; - + } nm_assert (i == l); + v[i] = NULL; NM_SET_OUT (out_len, l); priv->connections_cached_list = v; return v; } +/** + * nm_settings_get_connections_clone: + * @self: the #NMSetting + * @out_len: (allow-none): optional output argument + * @func: caller-supplied function for filtering connections + * @func_data: caller-supplied data passed to @func + * + * Returns: (transfer container) (element-type NMSettingsConnection): + * an NULL terminated array of #NMSettingsConnection objects that were + * filtered by @func (or all connections if no filter was specified). + * The order is arbitrary. + * Caller is responsible for freeing the returned array with free(), + * the contained values do not need to be unrefed. + */ +NMSettingsConnection ** +nm_settings_get_connections_clone (NMSettings *self, + guint *out_len, + NMSettingsConnectionFilterFunc func, + gpointer func_data) +{ + NMSettingsConnection *const*list_cached; + NMSettingsConnection **list; + guint len, i, j; + + g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); + + list_cached = nm_settings_get_connections (self, &len); + +#if NM_MORE_ASSERTS + nm_assert (list_cached); + for (i = 0; i < len; i++) + nm_assert (NM_IS_SETTINGS_CONNECTION (list_cached[i])); + nm_assert (!list_cached[i]); +#endif + + list = g_new (NMSettingsConnection *, ((gsize) len + 1)); + if (func) { + for (i = 0, j = 0; i < len; i++) { + if (func (self, list_cached[i], func_data)) + list[j++] = list_cached[i]; + } + list[j] = NULL; + len = j; + } else + memcpy (list, list_cached, sizeof (list[0]) * ((gsize) len + 1)); + + NM_SET_OUT (out_len, len); + return list; +} + /* Returns a list of NMSettingsConnections. * The list is sorted in the order suitable for auto-connecting, i.e. * first go connections with autoconnect=yes and most recent timestamp. - * Caller must free the list with g_slist_free(). + * Caller must free the list with g_free(), but not the list items. */ -GSList * -nm_settings_get_connections_sorted (NMSettings *self) +NMSettingsConnection ** +nm_settings_get_connections_sorted (NMSettings *self, guint *out_len) { - GHashTableIter iter; - gpointer data = NULL; - GSList *list = NULL; + NMSettingsConnection **connections; + guint len; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - g_hash_table_iter_init (&iter, NM_SETTINGS_GET_PRIVATE (self)->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) - list = g_slist_insert_sorted (list, data, connection_sort); - return list; + connections = nm_settings_get_connections_clone (self, &len, NULL, NULL); + if (len > 1) + g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); + + NM_SET_OUT (out_len, len); + return connections; } NMSettingsConnection * @@ -753,7 +779,7 @@ add_plugin (NMSettings *self, NMSettingsPlugin *plugin) NM_SETTINGS_PLUGIN_INFO, &pinfo, NULL); - path = g_object_get_data (G_OBJECT (plugin), PLUGIN_MODULE_PATH); + path = g_object_get_qdata (G_OBJECT (plugin), plugin_module_path_quark ()); _LOGI ("loaded plugin %s: %s%s%s%s", pname, pinfo, NM_PRINT_FMT_QUOTED (path, " (", path, ")", "")); @@ -809,8 +835,8 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) gboolean has_no_ibft; gssize idx_no_ibft, idx_ibft; - idx_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "ibft"); - idx_no_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft"); + idx_ibft = nm_utils_strv_find_first ((char **) plugins, -1, "ibft"); + idx_no_ibft = nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft"); has_no_ibft = idx_no_ibft >= 0 && idx_no_ibft > idx_ibft; #if WITH_SETTINGS_PLUGIN_IBFT add_ibft = idx_no_ibft < 0 && idx_ibft < 0; @@ -844,9 +870,9 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) continue; } - if (_nm_utils_strv_find_first ((char **) plugins, - iter - plugins, - pname) >= 0) { + if (nm_utils_strv_find_first ((char **) plugins, + iter - plugins, + pname) >= 0) { /* the plugin is already mentioned in the list previously. * Don't load a duplicate. */ continue; @@ -916,7 +942,7 @@ load_plugin: break; } - g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free); + g_object_set_qdata_full (obj, plugin_module_path_quark (), path, g_free); path = NULL; if (add_plugin (self, NM_SETTINGS_PLUGIN (obj))) list = g_slist_append (list, obj); @@ -1659,6 +1685,28 @@ nm_settings_set_transient_hostname (NMSettings *self, info); } +gboolean +nm_settings_get_transient_hostname (NMSettings *self, char **hostname) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GVariant *v_hostname; + + if (!priv->hostname.hostnamed_proxy) + return FALSE; + + v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy, + "Hostname"); + if (!v_hostname) { + _LOGT ("transient hostname retrieval failed"); + return FALSE; + } + + *hostname = g_variant_dup_string (v_hostname, NULL); + g_variant_unref (v_hostname); + + return TRUE; +} + static gboolean write_hostname (NMSettingsPrivate *priv, const char *hostname) { @@ -1935,9 +1983,6 @@ have_connection_for_device (NMSettings *self, NMDevice *device) return FALSE; } -#define DEFAULT_WIRED_CONNECTION_TAG "default-wired-connection" -#define DEFAULT_WIRED_DEVICE_TAG "default-wired-device" - static void default_wired_clear_tag (NMSettings *self, NMDevice *device, NMSettingsConnection *connection, @@ -1953,7 +1998,7 @@ default_wired_connection_removed_cb (NMSettingsConnection *connection, NMSetting * wired device to the config file and don't create a new default wired * connection for that device again. */ - device = g_object_get_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG); + device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ()); if (device) default_wired_clear_tag (self, device, connection, TRUE); } @@ -1970,7 +2015,7 @@ default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, g * considered a default wired connection, and should no longer affect * the no-auto-default configuration option. */ - device = g_object_get_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG); + device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ()); if (device) default_wired_clear_tag (self, device, connection, FALSE); } @@ -1984,11 +2029,11 @@ default_wired_clear_tag (NMSettings *self, g_return_if_fail (NM_IS_SETTINGS (self)); g_return_if_fail (NM_IS_DEVICE (device)); g_return_if_fail (NM_IS_CONNECTION (connection)); - g_return_if_fail (device == g_object_get_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG)); - g_return_if_fail (connection == g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG)); + g_return_if_fail (device == g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ())); + g_return_if_fail (connection == g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())); - g_object_set_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG, NULL); - g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG, NULL); + g_object_set_qdata (G_OBJECT (connection), _default_wired_device_quark (), NULL); + g_object_set_qdata (G_OBJECT (device), _default_wired_connection_quark (), NULL); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_removed_cb), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_updated_by_user_cb), self); @@ -2015,7 +2060,7 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) * ignore it. */ if ( !nm_device_get_managed (device, FALSE) - || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG) + || g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ()) || have_connection_for_device (self, device)) return; @@ -2037,8 +2082,8 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) return; } - g_object_set_data (G_OBJECT (added), DEFAULT_WIRED_DEVICE_TAG, device); - g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG, added); + g_object_set_qdata (G_OBJECT (added), _default_wired_device_quark (), device); + g_object_set_qdata (G_OBJECT (device), _default_wired_connection_quark (), added); g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (default_wired_connection_updated_by_user_cb), self); @@ -2071,7 +2116,7 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin G_CALLBACK (device_realized), self); - connection = g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG); + connection = g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ()); if (connection) { default_wired_clear_tag (self, device, connection, FALSE); @@ -2085,107 +2130,6 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin /*****************************************************************************/ -/* GCompareFunc helper for sorting "best" connections. - * The function sorts connections in ascending timestamp order. - * That means an older connection (lower timestamp) goes before - * a newer one. - */ -gint -nm_settings_sort_connections (gconstpointer a, gconstpointer b) -{ - NMSettingsConnection *ac = (NMSettingsConnection *) a; - NMSettingsConnection *bc = (NMSettingsConnection *) b; - guint64 ats = 0, bts = 0; - - if (ac == bc) - return 0; - if (!ac) - return -1; - if (!bc) - return 1; - - /* In the future we may use connection priorities in addition to timestamps */ - nm_settings_connection_get_timestamp (ac, &ats); - nm_settings_connection_get_timestamp (bc, &bts); - - if (ats < bts) - return -1; - else if (ats > bts) - return 1; - return 0; -} - -/** - * nm_settings_get_best_connections: - * @self: the #NMSetting - * @max_requested: if non-zero, the maximum number of connections to return - * @ctype1: an #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) to - * filter connections against - * @ctype2: a second #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) - * to filter connections against - * @func: caller-supplied function for filtering connections - * @func_data: caller-supplied data passed to @func - * - * Returns: a #GSList of #NMConnection objects in sorted order representing the - * "best" or highest-priority connections filtered by @ctype1 and/or @ctype2, - * and/or @func. Caller is responsible for freeing the returned #GSList, but - * the contained values do not need to be unreffed. - */ -GSList * -nm_settings_get_best_connections (NMSettings *self, - guint max_requested, - const char *ctype1, - const char *ctype2, - NMConnectionFilterFunc func, - gpointer func_data) -{ - NMSettingsPrivate *priv; - GSList *sorted = NULL; - GHashTableIter iter; - NMSettingsConnection *connection; - guint added = 0; - guint64 oldest = 0; - - g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - - priv = NM_SETTINGS_GET_PRIVATE (self); - - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) { - guint64 cur_ts = 0; - - if (ctype1 && !nm_connection_is_type (NM_CONNECTION (connection), ctype1)) - continue; - if (ctype2 && !nm_connection_is_type (NM_CONNECTION (connection), ctype2)) - continue; - if (func && !func (self, NM_CONNECTION (connection), func_data)) - continue; - - /* Don't bother with a connection that's older than the oldest one in the list */ - if (max_requested && added >= max_requested) { - nm_settings_connection_get_timestamp (connection, &cur_ts); - if (cur_ts <= oldest) - continue; - } - - /* List is sorted with oldest first */ - sorted = g_slist_insert_sorted (sorted, connection, nm_settings_sort_connections); - added++; - - if (max_requested && added > max_requested) { - /* Over the limit, remove the oldest one */ - sorted = g_slist_delete_link (sorted, sorted); - added--; - } - - nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (sorted->data), &oldest); - } - - return g_slist_reverse (sorted); -} - -/*****************************************************************************/ - gboolean nm_settings_get_startup_complete (NMSettings *self) { @@ -2221,7 +2165,7 @@ hostnamed_properties_changed (GDBusProxy *proxy, g_free (priv->hostname.value); priv->hostname.value = g_strdup (hostname); _notify (self, PROP_HOSTNAME); - nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); + nm_dispatcher_call_hostname (NULL, NULL, NULL); } g_variant_unref (v_hostname); diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index c8a7ebae..7110a12b 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -26,7 +26,7 @@ #ifndef __NM_SETTINGS_H__ #define __NM_SETTINGS_H__ -#include <nm-connection.h> +#include "nm-connection.h" #include "nm-exported-object.h" @@ -57,9 +57,9 @@ * * Returns: %TRUE to allow the connection, %FALSE to ignore it */ -typedef gboolean (*NMConnectionFilterFunc) (NMSettings *settings, - NMConnection *connection, - gpointer func_data); +typedef gboolean (*NMSettingsConnectionFilterFunc) (NMSettings *settings, + NMSettingsConnection *connection, + gpointer func_data); typedef struct _NMSettingsClass NMSettingsClass; @@ -97,14 +97,13 @@ void nm_settings_add_connection_dbus (NMSettings *self, NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings, guint *out_len); -GSList *nm_settings_get_connections_sorted (NMSettings *settings); +NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self, + guint *out_len, + NMSettingsConnectionFilterFunc func, + gpointer func_data); -GSList *nm_settings_get_best_connections (NMSettings *self, - guint max_requested, - const char *ctype1, - const char *ctype2, - NMConnectionFilterFunc func, - gpointer func_data); +NMSettingsConnection **nm_settings_get_connections_sorted (NMSettings *self, + guint *out_len); NMSettingsConnection *nm_settings_add_connection (NMSettings *settings, NMConnection *connection, @@ -126,8 +125,6 @@ void nm_settings_device_added (NMSettings *self, NMDevice *device); void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting); -gint nm_settings_sort_connections (gconstpointer a, gconstpointer b); - gboolean nm_settings_get_startup_complete (NMSettings *self); void nm_settings_set_transient_hostname (NMSettings *self, @@ -135,4 +132,7 @@ void nm_settings_set_transient_hostname (NMSettings *self, NMSettingsSetHostnameCb cb, gpointer user_data); +gboolean nm_settings_get_transient_hostname (NMSettings *self, + char **hostname); + #endif /* __NM_SETTINGS_H__ */ diff --git a/src/settings/plugins/ibft/nms-ibft-reader.h b/src/settings/plugins/ibft/nms-ibft-reader.h index e2be7b02..27500cc5 100644 --- a/src/settings/plugins/ibft/nms-ibft-reader.h +++ b/src/settings/plugins/ibft/nms-ibft-reader.h @@ -21,7 +21,7 @@ #ifndef __NMS_IBFT_READER_H__ #define __NMS_IBFT_READER_H__ -#include <nm-connection.h> +#include "nm-connection.h" gboolean nms_ibft_reader_load_blocks (const char *iscsiadm_path, GSList **out_blocks, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c index 33f4847e..b54f9549 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -336,43 +336,24 @@ commit_changes (NMSettingsConnection *connection, gpointer user_data) { GError *error = NULL; - NMConnection *reread; - gboolean same = FALSE, success = FALSE; + gboolean success = FALSE; char *ifcfg_path = NULL; const char *filename; - /* To ensure we don't rewrite files that are only changed from other - * processes on-disk, read the existing connection back in and only rewrite - * it if it's really changed. - */ filename = nm_settings_connection_get_filename (connection); if (filename) { - gs_free char *unhandled = NULL; - - reread = connection_from_file (filename, &unhandled, NULL, NULL); - if (reread) { - same = nm_connection_compare (NM_CONNECTION (connection), - reread, - NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | - NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS); - g_object_unref (reread); - - /* Don't bother writing anything out if in-memory and on-disk data are the same */ - if (same) { - /* But chain up to parent to handle success - emits updated signal */ - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, commit_reason, callback, user_data); - return; - } - } - success = writer_update_connection (NM_CONNECTION (connection), IFCFG_DIR, filename, + NULL, + NULL, &error); } else { success = writer_new_connection (NM_CONNECTION (connection), IFCFG_DIR, &ifcfg_path, + NULL, + NULL, &error); if (success) { nm_settings_connection_set_filename (connection, ifcfg_path); @@ -478,6 +459,11 @@ nm_ifcfg_connection_new (NMConnection *source, if (out_ignore_error) *out_ignore_error = FALSE; + if (full_path) { + /* The connection already is on the disk */ + update_unsaved = FALSE; + } + /* If we're given a connection already, prefer that instead of re-reading */ if (source) tmp = g_object_ref (source); @@ -488,9 +474,6 @@ nm_ifcfg_connection_new (NMConnection *source, out_ignore_error); if (!tmp) return NULL; - - /* If we just read the connection from disk, it's clearly not Unsaved */ - update_unsaved = FALSE; } if (unhandled_spec && g_str_has_prefix (unhandled_spec, "unmanaged:")) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index 414f593b..a3092e71 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -98,7 +98,7 @@ NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfcfg, settings_plugin_ifcfg_get, SETT #define _NMLOG_DOMAIN LOGD_SETTINGS #define _NMLOG(level, ...) \ G_STMT_START { \ - nm_log ((level), (_NMLOG_DOMAIN), \ + nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ "ifcfg-rh: " \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ @@ -687,7 +687,7 @@ add_connection (NMSettingsPlugin *config, return NULL; if (save_to_disk) { - if (!writer_new_connection (connection, IFCFG_DIR, &path, error)) + if (!writer_new_connection (connection, IFCFG_DIR, &path, NULL, NULL, error)) return NULL; } return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 46bd2de1..164f6844 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -48,6 +48,7 @@ #include "nm-setting-bridge.h" #include "nm-setting-bridge-port.h" #include "nm-setting-dcb.h" +#include "nm-setting-user.h" #include "nm-setting-proxy.h" #include "nm-setting-generic.h" #include "nm-core-internal.h" @@ -66,7 +67,7 @@ #define _NMLOG_PREFIX_NAME "ifcfg-rh" #define _NMLOG(level, ...) \ G_STMT_START { \ - nm_log ((level), (_NMLOG_DOMAIN), \ + nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME": " \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ @@ -97,14 +98,13 @@ make_connection_name (shvarFile *ifcfg, char *full_name = NULL, *name; /* If the ifcfg file already has a NAME, always use that */ - name = svGetValueString (ifcfg, "NAME"); - if (name && strlen (name)) + name = svGetValueStr_cp (ifcfg, "NAME"); + if (name) return name; /* Otherwise construct a new NAME */ - g_free (name); if (!prefix) - prefix = _("System"); + prefix = "System"; /* For cosmetic reasons, if the suggested name is the same as * the ifcfg files name, don't use it. Mainly for wifi so that @@ -142,22 +142,18 @@ make_connection_setting (const char *file, g_free (new_id); /* Try for a UUID key before falling back to hashing the file name */ - uuid = svGetValueString (ifcfg, "UUID"); - if (!uuid || !strlen (uuid)) { - g_free (uuid); + uuid = svGetValueStr_cp (ifcfg, "UUID"); + if (!uuid) uuid = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); - } - - stable_id = svGetValueString (ifcfg, "STABLE_ID"); g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NM_SETTING_CONNECTION_UUID, uuid, - NM_SETTING_CONNECTION_STABLE_ID, stable_id, + NM_SETTING_CONNECTION_STABLE_ID, svGetValue (ifcfg, "STABLE_ID", &stable_id), NULL); g_free (uuid); - value = svGetValueString (ifcfg, "DEVICE"); + value = svGetValueStr_cp (ifcfg, "DEVICE"); if (value) { GError *error = NULL; @@ -172,7 +168,7 @@ make_connection_setting (const char *file, g_free (value); } - value = svGetValueString (ifcfg, "LLDP"); + value = svGetValueStr_cp (ifcfg, "LLDP"); if (!g_strcmp0 (value, "rx")) lldp = NM_SETTING_CONNECTION_LLDP_ENABLE_RX; else @@ -196,7 +192,7 @@ make_connection_setting (const char *file, NM_SETTING_CONNECTION_LLDP, lldp, NULL); - value = svGetValueString (ifcfg, "USERS"); + value = svGetValueStr_cp (ifcfg, "USERS"); if (value) { char **items, **iter; @@ -212,15 +208,11 @@ make_connection_setting (const char *file, } - zone = svGetValueString (ifcfg, "ZONE"); - if (!zone || !strlen (zone)) { - g_free (zone); - zone = NULL; - } + zone = svGetValueStr_cp (ifcfg, "ZONE"); g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL); g_free (zone); - value = svGetValueString (ifcfg, "SECONDARY_UUIDS"); + value = svGetValueStr_cp (ifcfg, "SECONDARY_UUIDS"); if (value) { char **items, **iter; @@ -235,9 +227,9 @@ make_connection_setting (const char *file, g_strfreev (items); } - value = svGetValueString (ifcfg, "BRIDGE_UUID"); + value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID"); if (!value) - value = svGetValueString (ifcfg, "BRIDGE"); + value = svGetValueStr_cp (ifcfg, "BRIDGE"); if (value) { const char *old_value; @@ -252,7 +244,7 @@ make_connection_setting (const char *file, g_free (value); } - value = svGetValueString (ifcfg, "GATEWAY_PING_TIMEOUT"); + value = svGetValueStr_cp (ifcfg, "GATEWAY_PING_TIMEOUT"); if (value) { gint64 tmp; @@ -280,75 +272,82 @@ make_connection_setting (const char *file, static gboolean read_ip4_address (shvarFile *ifcfg, const char *tag, - char **out_addr, + gboolean *out_has_key, + guint32 *out_addr, GError **error) { - char *value = NULL; - - g_return_val_if_fail (ifcfg != NULL, FALSE); - g_return_val_if_fail (tag != NULL, FALSE); - g_return_val_if_fail (out_addr != NULL, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); + gs_free char *value_to_free = NULL; + const char *value; + guint32 a; - *out_addr = NULL; + nm_assert (ifcfg); + nm_assert (tag); + nm_assert (!error || !*error); - value = svGetValueString (ifcfg, tag); - if (!value) + value = svGetValueStr (ifcfg, tag, &value_to_free); + if (!value) { + NM_SET_OUT (out_has_key, FALSE); + NM_SET_OUT (out_addr, 0); return TRUE; + } - if (nm_utils_ipaddr_valid (AF_INET, value)) { - *out_addr = value; - return TRUE; - } else { + if (inet_pton (AF_INET, value, &a) != 1) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid %s IP4 address '%s'", tag, value); - g_free (value); return FALSE; } + + NM_SET_OUT (out_has_key, TRUE); + NM_SET_OUT (out_addr, a); + return TRUE; } -static char * -get_numbered_tag (char *tag_name, int which) +static void +_numbered_tag (char *buf, gsize buf_len, const char *tag_name, int which) { - if (which == -1) - return g_strdup (tag_name); - return g_strdup_printf ("%s%u", tag_name, which); + gsize l; + + l = g_strlcpy (buf, tag_name, buf_len); + nm_assert (l < buf_len); + if (which != -1) { + buf_len -= l; + l = g_snprintf (&buf[l], buf_len, "%d", which); + nm_assert (l < buf_len); + } } +#define numbered_tag(buf, tag_name, which) \ + ({ \ + _nm_unused char *const _buf = (buf); \ + \ + /* some static assert trying to ensure that the buffer is statically allocated. + * It disallows a buffer size of sizeof(gpointer) to catch that. */ \ + G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *) && sizeof (buf) < G_MAXINT); \ + _numbered_tag (buf, sizeof (buf), ""tag_name"", (which)); \ + buf; \ + }) static gboolean is_any_ip4_address_defined (shvarFile *ifcfg, int *idx) { - int i, ignore, *ret_idx;; + int i, ignore, *ret_idx; ret_idx = idx ? idx : &ignore; for (i = -1; i <= 2; i++) { - char *tag; - char *value; + gs_free char *value = NULL; + char tag[256]; - tag = get_numbered_tag ("IPADDR", i); - value = svGetValueString (ifcfg, tag); - g_free (tag); - if (value) { - g_free (value); + if (svGetValueStr (ifcfg, numbered_tag (tag, "IPADDR", i), &value)) { *ret_idx = i; return TRUE; } - tag = get_numbered_tag ("PREFIX", i); - value = svGetValueString (ifcfg, tag); - g_free(tag); - if (value) { - g_free (value); + if (svGetValueStr (ifcfg, numbered_tag (tag, "PREFIX", i), &value)) { *ret_idx = i; return TRUE; } - tag = get_numbered_tag ("NETMASK", i); - value = svGetValueString (ifcfg, tag); - g_free(tag); - if (value) { - g_free (value); + if (svGetValueStr (ifcfg, numbered_tag (tag, "NETMASK", i), &value)) { *ret_idx = i; return TRUE; } @@ -365,12 +364,14 @@ read_full_ip4_address (shvarFile *ifcfg, char **out_gateway, GError **error) { - char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag; - char *ip = NULL; + char tag[256]; + char prefix_tag[256]; + guint32 ipaddr; + gs_free char *value = NULL; int prefix = 0; - gboolean success = FALSE; - char *value; - guint32 tmp; + gboolean has_key; + guint32 a; + char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; g_return_val_if_fail (which >= -1, FALSE); g_return_val_if_fail (ifcfg != NULL, FALSE); @@ -378,76 +379,186 @@ read_full_ip4_address (shvarFile *ifcfg, g_return_val_if_fail (*out_address == NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - ip_tag = get_numbered_tag ("IPADDR", which); - prefix_tag = get_numbered_tag ("PREFIX", which); - netmask_tag = get_numbered_tag ("NETMASK", which); - gw_tag = get_numbered_tag ("GATEWAY", which); - /* IP address */ - if (!read_ip4_address (ifcfg, ip_tag, &ip, error)) - goto done; - if (!ip) { - if (base_addr) - ip = g_strdup (nm_ip_address_get_address (base_addr)); - else { - success = TRUE; - goto done; - } + if (!read_ip4_address (ifcfg, + numbered_tag (tag, "IPADDR", which), + &has_key, &ipaddr, error)) + return FALSE; + if (!has_key) { + if (!base_addr) + return TRUE; + nm_ip_address_get_address_binary (base_addr, &ipaddr); } /* Gateway */ if (out_gateway && !*out_gateway) { - if (!read_ip4_address (ifcfg, gw_tag, out_gateway, error)) - goto done; + if (!read_ip4_address (ifcfg, + numbered_tag (tag, "GATEWAY", which), + &has_key, &a, error)) + return FALSE; + if (has_key) + *out_gateway = g_strdup (nm_utils_inet4_ntop (a, inet_buf)); } /* Prefix */ - value = svGetValueString (ifcfg, prefix_tag); + numbered_tag (prefix_tag, "PREFIX", which); + value = svGetValueStr_cp (ifcfg, prefix_tag); if (value) { prefix = _nm_utils_ascii_str_to_int64 (value, 10, 0, 32, -1); if (prefix < 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IP4 prefix '%s'", value); - g_free (value); - goto done; + return FALSE; } - g_free (value); } else { /* Fall back to NETMASK if no PREFIX was specified */ - if (!read_ip4_address (ifcfg, netmask_tag, &value, error)) - goto done; - if (value) { - inet_pton (AF_INET, value, &tmp); - prefix = nm_utils_ip4_netmask_to_prefix (tmp); - g_free (value); - } else { + if (!read_ip4_address (ifcfg, + numbered_tag (tag, "NETMASK", which), + &has_key, &a, error)) + return FALSE; + if (has_key) + prefix = nm_utils_ip4_netmask_to_prefix (a); + else { if (base_addr) prefix = nm_ip_address_get_prefix (base_addr); else { /* Try to autodetermine the prefix for the address' class */ - if (inet_pton (AF_INET, ip, &tmp) == 1) { - prefix = nm_utils_ip4_get_default_prefix (tmp); - - PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, ip, prefix); - } else { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Missing IP4 prefix"); - goto done; - } + prefix = nm_utils_ip4_get_default_prefix (ipaddr); + PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, nm_utils_inet4_ntop (ipaddr, inet_buf), prefix); } } } - *out_address = nm_ip_address_new (AF_INET, ip, prefix, error); + *out_address = nm_ip_address_new_binary (AF_INET, &ipaddr, prefix, error); if (*out_address) - success = TRUE; + return TRUE; -done: - g_free (ip); - g_free (ip_tag); - g_free (prefix_tag); - g_free (netmask_tag); - g_free (gw_tag); + return FALSE; +} + +/* + * Use looser syntax to comprise all the possibilities. + * The validity must be checked after the match. + */ +#define IPV4_ADDR_REGEX "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}" +#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+" + +/* + * NOTE: The regexes below don't describe all variants allowed by 'ip route add', + * namely destination IP without 'to' keyword is recognized just at line start. + */ + +static gboolean +parse_route_options (NMIPRoute *route, int family, const char *line, GError **error) +{ + GRegex *regex = NULL; + GMatchInfo *match_info = NULL; + gboolean success = FALSE; + static const char *metrics[] = { NM_IP_ROUTE_ATTRIBUTE_WINDOW, NM_IP_ROUTE_ATTRIBUTE_CWND, + NM_IP_ROUTE_ATTRIBUTE_INITCWND, NM_IP_ROUTE_ATTRIBUTE_INITRWND, + NM_IP_ROUTE_ATTRIBUTE_MTU, NULL }; + char buffer[1024]; + int i; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + for (i = 0; metrics[i]; i++) { + nm_sprintf_buf (buffer, "(?:\\s|^)%s\\s+(lock\\s+)?(\\d+)(?:$|\\s)", metrics[i]); + regex = g_regex_new (buffer, 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *lock = g_match_info_fetch (match_info, 1); + gs_free char *str = g_match_info_fetch (match_info, 2); + gint64 num = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1); + + if (num == -1) { + g_match_info_free (match_info); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route %s '%s'", metrics[i], str); + goto out; + } + + nm_ip_route_set_attribute (route, metrics[i], + g_variant_new_uint32 (num)); + if (lock && lock[0]) { + nm_sprintf_buf (buffer, "lock-%s", metrics[i]); + nm_ip_route_set_attribute (route, buffer, + g_variant_new_boolean (TRUE)); + } + } + g_clear_pointer (®ex, g_regex_unref); + g_clear_pointer (&match_info, g_match_info_free); + } + + /* tos */ + regex = g_regex_new ("(?:\\s|^)tos\\s+(\\S+)(?:$|\\s)", 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *str = g_match_info_fetch (match_info, 1); + gint64 num = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT8, -1); + + if (num == -1) { + g_match_info_free (match_info); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route %s '%s'", "tos", str); + goto out; + } + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_TOS, + g_variant_new_byte ((guchar) num)); + } + g_clear_pointer (®ex, g_regex_unref); + g_clear_pointer (&match_info, g_match_info_free); + + /* from */ + if (family == AF_INET6) { + regex = g_regex_new ("(?:\\s|^)from\\s+(" IPV6_ADDR_REGEX "(?:/\\d{1,3})?)(?:$|\\s)", 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *str = g_match_info_fetch (match_info, 1); + gs_free_error GError *local_error = NULL; + GVariant *variant = g_variant_new_string (str); + + if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_FROM, variant, family, NULL, &local_error)) { + g_match_info_free (match_info); + g_variant_unref (variant); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route from '%s': %s", str, local_error->message); + goto out; + } + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_FROM, variant); + } + g_clear_pointer (®ex, g_regex_unref); + g_clear_pointer (&match_info, g_match_info_free); + } + + if (family == AF_INET) + regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV4_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL); + else + regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV6_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *str = g_match_info_fetch (match_info, 1); + gs_free_error GError *local_error = NULL; + GVariant *variant = g_variant_new_string (str); + + if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_SRC, variant, family, + NULL, &local_error)) { + g_match_info_free (match_info); + g_variant_unref (variant); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route src '%s': %s", str, local_error->message); + goto out; + } + + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_SRC, variant); + } + success = TRUE; + +out: + if (regex) + g_regex_unref (regex); + if (match_info) + g_match_info_free (match_info); return success; } @@ -459,87 +570,85 @@ read_one_ip4_route (shvarFile *ifcfg, NMIPRoute **out_route, GError **error) { - char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value; - char *dest = NULL, *next_hop = NULL; + char tag[256]; + char netmask_tag[256]; + guint32 dest; + guint32 next_hop; + guint32 netmask; + gboolean has_key; + gs_free char *value = NULL; gint64 prefix, metric; - gboolean success = FALSE; + char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (out_route != NULL, FALSE); g_return_val_if_fail (*out_route == NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - ip_tag = g_strdup_printf ("ADDRESS%u", which); - netmask_tag = g_strdup_printf ("NETMASK%u", which); - gw_tag = g_strdup_printf ("GATEWAY%u", which); - metric_tag = g_strdup_printf ("METRIC%u", which); - /* Destination */ - if (!read_ip4_address (ifcfg, ip_tag, &dest, error)) - goto out; - if (!dest) { - /* Check whether IP is missing or 0.0.0.0 */ - char *val; - val = svGetValueString (ifcfg, ip_tag); - if (!val) { - *out_route = NULL; - success = TRUE; /* missing route = success */ - goto out; - } - g_free (val); + if (!read_ip4_address (ifcfg, + numbered_tag (tag, "ADDRESS", which), + &has_key, &dest, error)) + return FALSE; + if (!has_key) { + /* missing route = success */ + *out_route = NULL; + return TRUE; } /* Next hop */ - if (!read_ip4_address (ifcfg, gw_tag, &next_hop, error)) - goto out; + if (!read_ip4_address (ifcfg, + numbered_tag (tag, "GATEWAY", which), + NULL, &next_hop, error)) + return FALSE; /* We don't make distinction between missing GATEWAY IP and 0.0.0.0 */ /* Prefix */ - if (!read_ip4_address (ifcfg, netmask_tag, &value, error)) - goto out; - if (value) { - guint32 netmask; - - inet_pton (AF_INET, value, &netmask); + if (!read_ip4_address (ifcfg, + numbered_tag (netmask_tag, "NETMASK", which), + &has_key, &netmask, error)) + return FALSE; + if (has_key) { prefix = nm_utils_ip4_netmask_to_prefix (netmask); - g_free (value); if (prefix == 0 || netmask != nm_utils_ip4_prefix_to_netmask (prefix)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, NULL)); - goto out; + "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, inet_buf)); + return FALSE; } } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IP4 route element '%s'", netmask_tag); - goto out; + return FALSE; } /* Metric */ - value = svGetValueString (ifcfg, metric_tag); + nm_clear_g_free (&value); + value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "METRIC", which)); if (value) { metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); if (metric < 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IP4 route metric '%s'", value); - g_free (value); - goto out; + return FALSE; } - g_free (value); } else metric = -1; - *out_route = nm_ip_route_new (AF_INET, dest, prefix, next_hop, metric, error); - if (*out_route) - success = TRUE; + *out_route = nm_ip_route_new_binary (AF_INET, &dest, prefix, &next_hop, metric, error); + if (!*out_route) + return FALSE; -out: - g_free (dest); - g_free (next_hop); - g_free (ip_tag); - g_free (netmask_tag); - g_free (gw_tag); - g_free (metric_tag); - return success; + /* Options */ + nm_clear_g_free (&value); + value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "OPTIONS", which)); + if (value) { + if (!parse_route_options (*out_route, AF_INET, value, error)) { + g_clear_pointer (out_route, nm_ip_route_unref); + return FALSE; + } + } + + return TRUE; } static gboolean @@ -665,6 +774,12 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError * route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error); if (!route) goto error; + + if (!parse_route_options (route, AF_INET, *iter, error)) { + nm_ip_route_unref (route); + goto error; + } + if (!nm_setting_ip_config_add_route (s_ip4, route)) PARSE_WARNING ("duplicate IP4 route"); nm_ip_route_unref (route); @@ -758,13 +873,6 @@ error: return success; } -/* IPv6 address is very complex to describe completely by a regular expression, - * so don't try to, rather use looser syntax to comprise all possibilities - * NOTE: The regexes below don't describe all variants allowed by 'ip route add', - * namely destination IP without 'to' keyword is recognized just at line start. - */ -#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+" - static gboolean read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) { @@ -786,6 +894,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */ const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */ + g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip6 != NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); @@ -891,6 +1000,12 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error g_free (next_hop); if (!route) goto error; + + if (!parse_route_options (route, AF_INET6, *iter, error)) { + nm_ip_route_unref (route); + goto error; + } + if (!nm_setting_ip_config_add_route (s_ip6, route)) PARSE_WARNING ("duplicate IP6 route"); nm_ip_route_unref (route); @@ -910,13 +1025,61 @@ error: } static NMSetting * +make_user_setting (shvarFile *ifcfg, GError **error) +{ + gboolean has_user_data = FALSE; + gs_unref_object NMSettingUser *s_user = NULL; + gs_unref_hashtable GHashTable *keys = NULL; + GHashTableIter iter; + const char *key; + nm_auto_free_gstring GString *str = NULL; + + keys = svGetKeys (ifcfg); + if (!keys) + return NULL; + + g_hash_table_iter_init (&iter, keys); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) { + const char *value; + gs_free char *value_to_free = NULL; + + if (!g_str_has_prefix (key, "NM_USER_")) + continue; + + value = svGetValue (ifcfg, key, &value_to_free); + + if (!value) + continue; + + if (!str) + str = g_string_sized_new (100); + else + g_string_set_size (str, 0); + + if (!nms_ifcfg_rh_utils_user_key_decode (key + NM_STRLEN ("NM_USER_"), str)) + continue; + + if (!s_user) + s_user = NM_SETTING_USER (nm_setting_user_new ()); + + if (nm_setting_user_set_data (s_user, str->str, + value, NULL)) + has_user_data = TRUE; + } + + return has_user_data + ? g_steal_pointer (&s_user) + : NULL; +} + +static NMSetting * make_proxy_setting (shvarFile *ifcfg, GError **error) { NMSettingProxy *s_proxy = NULL; char *value = NULL; NMSettingProxyMethod method; - value = svGetValueString (ifcfg, "PROXY_METHOD"); + value = svGetValueStr_cp (ifcfg, "PROXY_METHOD"); if (!value) return NULL; @@ -934,14 +1097,14 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_AUTO, NULL); - value = svGetValueString (ifcfg, "PAC_URL"); + value = svGetValueStr_cp (ifcfg, "PAC_URL"); if (value) { value = g_strstrip (value); g_object_set (s_proxy, NM_SETTING_PROXY_PAC_URL, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "PAC_SCRIPT"); + value = svGetValueStr_cp (ifcfg, "PAC_SCRIPT"); if (value) { value = g_strstrip (value); g_object_set (s_proxy, NM_SETTING_PROXY_PAC_SCRIPT, value, NULL); @@ -956,7 +1119,7 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) break; } - value = svGetValueString (ifcfg, "BROWSER_ONLY"); + value = svGetValueStr_cp (ifcfg, "BROWSER_ONLY"); if (value) { if (!g_ascii_strcasecmp (value, "yes")) g_object_set (s_proxy, NM_SETTING_PROXY_BROWSER_ONLY, TRUE, NULL); @@ -969,21 +1132,27 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) static NMSetting * make_ip4_setting (shvarFile *ifcfg, const char *network_file, + gboolean *out_has_defroute, GError **error) { - NMSettingIPConfig *s_ip4 = NULL; + gs_unref_object NMSettingIPConfig *s_ip4 = NULL; + gs_free char *route_path = NULL; char *value = NULL; - char *route_path = NULL; char *method; gs_free char *dns_options_free = NULL; const char *dns_options = NULL; gs_free char *gateway = NULL; - gint32 i; + int i; + guint32 a; + gboolean has_key; shvarFile *network_ifcfg; shvarFile *route_ifcfg; - gboolean never_default = FALSE; + gboolean never_default; gint64 timeout; gint priority; + char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; + + nm_assert (out_has_defroute && !*out_has_defroute); s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); @@ -992,7 +1161,13 @@ make_ip4_setting (shvarFile *ifcfg, * specified is DEFROUTE=yes which means that this connection can be used * as a default route */ - never_default = !svGetValueBoolean (ifcfg, "DEFROUTE", TRUE); + i = svGetValueBoolean (ifcfg, "DEFROUTE", -1); + if (i == -1) + never_default = FALSE; + else { + never_default = !i; + *out_has_defroute = TRUE; + } /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ network_ifcfg = svOpenFile (network_file, NULL); @@ -1000,8 +1175,8 @@ make_ip4_setting (shvarFile *ifcfg, char *gatewaydev; /* Get the connection ifcfg device name and the global gateway device */ - value = svGetValueString (ifcfg, "DEVICE"); - gatewaydev = svGetValueString (network_ifcfg, "GATEWAYDEV"); + value = svGetValueStr_cp (ifcfg, "DEVICE"); + gatewaydev = svGetValueStr_cp (network_ifcfg, "GATEWAYDEV"); dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); /* If there was a global gateway device specified, then only connections @@ -1015,7 +1190,7 @@ make_ip4_setting (shvarFile *ifcfg, svCloseFile (network_ifcfg); } - value = svGetValueString (ifcfg, "BOOTPROTO"); + value = svGetValueStr_cp (ifcfg, "BOOTPROTO"); if (!value || !*value || !g_ascii_strcasecmp (value, "none")) { if (is_any_ip4_address_defined (ifcfg, NULL)) @@ -1041,24 +1216,26 @@ make_ip4_setting (shvarFile *ifcfg, NULL); /* 1 IP address is allowed for shared connections. Read it. */ if (is_any_ip4_address_defined (ifcfg, &idx)) { + guint32 gw; NMIPAddress *addr = NULL; if (!read_full_ip4_address (ifcfg, idx, NULL, &addr, NULL, error)) - goto done; - if (!read_ip4_address (ifcfg, "GATEWAY", &gateway, error)) - goto done; + return NULL; + if (!read_ip4_address (ifcfg, "GATEWAY", NULL, &gw, error)) + return NULL; (void) nm_setting_ip_config_add_address (s_ip4, addr); nm_ip_address_unref (addr); if (never_default) PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled"); + gateway = g_strdup (nm_utils_inet4_ntop (gw, inet_buf)); g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL); } - return NM_SETTING (s_ip4); + return g_steal_pointer (&s_ip4); } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Unknown BOOTPROTO '%s'", value); g_free (value); - goto done; + return NULL; } g_free (value); @@ -1073,32 +1250,34 @@ make_ip4_setting (shvarFile *ifcfg, NULL); if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) - return NM_SETTING (s_ip4); + return g_steal_pointer (&s_ip4); /* Handle DHCP settings */ - value = svGetValueString (ifcfg, "DHCP_HOSTNAME"); - if (value && *value) + value = svGetValueStr_cp (ifcfg, "DHCP_HOSTNAME"); + if (value) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL); - g_free (value); + g_free (value); + } - value = svGetValueString (ifcfg, "DHCP_FQDN"); - if (value && *value) { + value = svGetValueStr_cp (ifcfg, "DHCP_FQDN"); + if (value) { g_object_set (s_ip4, - NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL, - NM_SETTING_IP4_CONFIG_DHCP_FQDN, value, - NULL); + NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL, + NM_SETTING_IP4_CONFIG_DHCP_FQDN, value, + NULL); + g_free (value); } - g_free (value); g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE), NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0), NULL); - value = svGetValueString (ifcfg, "DHCP_CLIENT_ID"); - if (value && strlen (value)) + value = svGetValueStr_cp (ifcfg, "DHCP_CLIENT_ID"); + if (value) { g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL); - g_free (value); + g_free (value); + } /* Read static IP addresses. * Read them even for AUTO method - in this case the addresses are @@ -1111,7 +1290,7 @@ make_ip4_setting (shvarFile *ifcfg, /* gateway will only be set if still unset. Hence, we don't leak gateway * here by calling read_full_ip4_address() repeatedly */ if (!read_full_ip4_address (ifcfg, i, NULL, &addr, &gateway, error)) - goto done; + return NULL; if (!addr) { /* The first mandatory variable is 2-indexed (IPADDR2) @@ -1132,16 +1311,17 @@ make_ip4_setting (shvarFile *ifcfg, if (network_ifcfg) { gboolean read_success; - read_success = read_ip4_address (network_ifcfg, "GATEWAY", &gateway, error); + read_success = read_ip4_address (network_ifcfg, "GATEWAY", &has_key, &a, error); svCloseFile (network_ifcfg); if (!read_success) - goto done; - - if (gateway && nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { - gs_free char *f = g_path_get_basename (svFileGetName (ifcfg)); - PARSE_WARNING ("ignoring GATEWAY (/etc/sysconfig/network) for %s " - "because the connection has no static addresses", f); - g_clear_pointer (&gateway, g_free); + return NULL; + if (has_key) { + if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { + gs_free char *f = g_path_get_basename (svFileGetName (ifcfg)); + PARSE_WARNING ("ignoring GATEWAY (/etc/sysconfig/network) for %s " + "because the connection has no static addresses", f); + } else + gateway = g_strdup (nm_utils_inet4_ntop (a, inet_buf)); } } } @@ -1154,10 +1334,10 @@ make_ip4_setting (shvarFile *ifcfg, * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) */ for (i = 1; i <= 10; i++) { - char *tag; + char tag[256]; - tag = g_strdup_printf ("DNS%u", i); - value = svGetValueString (ifcfg, tag); + numbered_tag (tag, "DNS", i); + value = svGetValueStr_cp (ifcfg, tag); if (value) { if (nm_utils_ipaddr_valid (AF_INET, value)) { if (!nm_setting_ip_config_add_dns (s_ip4, value)) @@ -1166,19 +1346,16 @@ make_ip4_setting (shvarFile *ifcfg, /* Ignore IPv6 addresses */ } else { PARSE_WARNING ("invalid DNS server address %s", value); - g_free (tag); g_free (value); - goto done; + return NULL; } g_free (value); } - - g_free (tag); } /* DNS searches */ - value = svGetValueString (ifcfg, "DOMAIN"); + value = svGetValueStr_cp (ifcfg, "DOMAIN"); if (value) { char **searches = NULL; @@ -1222,7 +1399,7 @@ make_ip4_setting (shvarFile *ifcfg, if (!read_one_ip4_route (route_ifcfg, i, &route, error)) { svCloseFile (route_ifcfg); - goto done; + return NULL; } if (!route) @@ -1236,13 +1413,12 @@ make_ip4_setting (shvarFile *ifcfg, } } else { if (!read_route_file_legacy (route_path, s_ip4, error)) - goto done; + return NULL; } - g_free (route_path); /* Legacy value NM used for a while but is incorrect (rh #459370) */ if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) { - value = svGetValueString (ifcfg, "SEARCH"); + value = svGetValueStr_cp (ifcfg, "SEARCH"); if (value) { char **searches = NULL; @@ -1266,16 +1442,11 @@ make_ip4_setting (shvarFile *ifcfg, g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (gint) (timeout <= 0 ? timeout : timeout * 1000), NULL); - return NM_SETTING (s_ip4); - -done: - g_free (route_path); - g_object_unref (s_ip4); - return NULL; + return g_steal_pointer (&s_ip4); } static void -read_aliases (NMSettingIPConfig *s_ip4, const char *filename) +read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *filename) { GDir *dir; char *dirname, *base; @@ -1301,6 +1472,7 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename) gboolean ok; while ((item = g_dir_read_name (dir))) { + gs_free char *gateway = NULL; char *full_path, *device; const char *p; @@ -1329,7 +1501,7 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename) continue; } - device = svGetValueString (parsed, "DEVICE"); + device = svGetValueStr_cp (parsed, "DEVICE"); if (!device) { PARSE_WARNING ("alias file '%s' has no DEVICE", full_path); svCloseFile (parsed); @@ -1347,12 +1519,30 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename) } addr = NULL; - ok = read_full_ip4_address (parsed, -1, base_addr, &addr, NULL, &err); - svCloseFile (parsed); + ok = read_full_ip4_address (parsed, -1, base_addr, &addr, + read_defroute ? &gateway : NULL, + &err); if (ok) { nm_ip_address_set_attribute (addr, "label", g_variant_new_string (device)); if (!nm_setting_ip_config_add_address (s_ip4, addr)) PARSE_WARNING ("duplicate IP4 address in alias file %s", item); + if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL); + if (read_defroute) { + int i; + + if (gateway) { + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL); + read_defroute = FALSE; + } + i = svGetValueBoolean (parsed, "DEFROUTE", -1); + if (i != -1) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, (gboolean) !i, + NULL); + read_defroute = FALSE; + } + } } else { PARSE_WARNING ("error reading IP4 address from alias file '%s': %s", full_path, err ? err->message : "no address"); @@ -1360,6 +1550,8 @@ read_aliases (NMSettingIPConfig *s_ip4, const char *filename) } nm_ip_address_unref (addr); + svCloseFile (parsed); + g_free (device); g_free (full_path); } @@ -1416,9 +1608,9 @@ make_ip6_setting (shvarFile *ifcfg, char *default_dev = NULL; /* Get the connection ifcfg device name and the global default route device */ - value = svGetValueString (ifcfg, "DEVICE"); - ipv6_defaultgw = svGetValueString (network_ifcfg, "IPV6_DEFAULTGW"); - ipv6_defaultdev = svGetValueString (network_ifcfg, "IPV6_DEFAULTDEV"); + value = svGetValueStr_cp (ifcfg, "DEVICE"); + ipv6_defaultgw = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); + ipv6_defaultdev = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTDEV"); dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); if (ipv6_defaultgw) { @@ -1443,7 +1635,7 @@ make_ip6_setting (shvarFile *ifcfg, /* Find out method property */ /* Is IPV6 enabled? Set method to "ignored", when not enabled */ - str_value = svGetValueString (ifcfg, "IPV6INIT"); + str_value = svGetValueStr_cp (ifcfg, "IPV6INIT"); ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); if (!str_value) { network_ifcfg = svOpenFile (network_file, NULL); @@ -1458,7 +1650,7 @@ make_ip6_setting (shvarFile *ifcfg, method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */ else { ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE); - str_value = svGetValueString (ifcfg, "IPV6_AUTOCONF"); + str_value = svGetValueStr_cp (ifcfg, "IPV6_AUTOCONF"); dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE); if (!g_strcmp0 (str_value, "shared")) @@ -1470,9 +1662,9 @@ make_ip6_setting (shvarFile *ifcfg, else { /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */ g_free (str_value); - str_value = svGetValueString (ifcfg, "IPV6ADDR"); + str_value = svGetValueStr_cp (ifcfg, "IPV6ADDR"); if (!str_value) - str_value = svGetValueString (ifcfg, "IPV6ADDR_SECONDARIES"); + str_value = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES"); if (!str_value) method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; @@ -1482,7 +1674,7 @@ make_ip6_setting (shvarFile *ifcfg, /* TODO - handle other methods */ /* Read IPv6 Privacy Extensions configuration */ - str_value = svGetValueString (ifcfg, "IPV6_PRIVACY"); + str_value = svGetValueStr_cp (ifcfg, "IPV6_PRIVACY"); if (str_value) { ip6_privacy = svParseBoolean (str_value, FALSE); if (!ip6_privacy) @@ -1512,13 +1704,13 @@ make_ip6_setting (shvarFile *ifcfg, if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) return NM_SETTING (s_ip6); - value = svGetValueString (ifcfg, "DHCPV6_HOSTNAME"); + value = svGetValueStr_cp (ifcfg, "DHCPV6_HOSTNAME"); /* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is * auto or dhcp: this is required to support old ifcfg files */ if (!value && ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP))) { - value = svGetValueString (ifcfg, "DHCP_HOSTNAME"); + value = svGetValueStr_cp (ifcfg, "DHCP_HOSTNAME"); if (value && !strchr (value, '.')) g_clear_pointer (&value, g_free); } @@ -1534,8 +1726,8 @@ make_ip6_setting (shvarFile *ifcfg, * added to the automatic ones. Note that this is not currently supported by * the legacy 'network' service (ifup-eth). */ - ipv6addr = svGetValueString (ifcfg, "IPV6ADDR"); - ipv6addr_secondaries = svGetValueString (ifcfg, "IPV6ADDR_SECONDARIES"); + ipv6addr = svGetValueStr_cp (ifcfg, "IPV6ADDR"); + ipv6addr_secondaries = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES"); value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL, ipv6addr ? ipv6addr : "", @@ -1562,12 +1754,12 @@ make_ip6_setting (shvarFile *ifcfg, /* Gateway */ if (nm_setting_ip_config_get_num_addresses (s_ip6)) { - value = svGetValueString (ifcfg, "IPV6_DEFAULTGW"); + value = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW"); if (!value) { /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */ network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { - value = svGetValueString (network_ifcfg, "IPV6_DEFAULTGW"); + value = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); svCloseFile (network_ifcfg); } } @@ -1588,7 +1780,7 @@ make_ip6_setting (shvarFile *ifcfg, } /* IPv6 addressing mode configuration */ - str_value = svGetValueString (ifcfg, "IPV6_ADDR_GEN_MODE"); + str_value = svGetValueStr_cp (ifcfg, "IPV6_ADDR_GEN_MODE"); if (str_value) { if (nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), str_value, (int *) &addr_gen_mode, NULL)) @@ -1604,7 +1796,7 @@ make_ip6_setting (shvarFile *ifcfg, } /* IPv6 tokenized interface identifier */ - str_value = svGetValueString (ifcfg, "IPV6_TOKEN"); + str_value = svGetValueStr_cp (ifcfg, "IPV6_TOKEN"); if (str_value) { g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, str_value, NULL); g_free (str_value); @@ -1614,13 +1806,13 @@ make_ip6_setting (shvarFile *ifcfg, * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) */ for (i = 1; i <= 10; i++) { - char *tag; + char tag[256]; - tag = g_strdup_printf ("DNS%u", i); - value = svGetValueString (ifcfg, tag); + numbered_tag (tag, "DNS", i); + value = svGetValueStr_cp (ifcfg, tag); if (!value) { - g_free (tag); - break; /* all done */ + /* all done */ + break; } if (nm_utils_ipaddr_valid (AF_INET6, value)) { @@ -1630,12 +1822,10 @@ make_ip6_setting (shvarFile *ifcfg, /* Ignore IPv4 addresses */ } else { PARSE_WARNING ("invalid DNS server address %s", value); - g_free (tag); g_free (value); goto error; } - g_free (tag); g_free (value); } @@ -1676,9 +1866,9 @@ check_if_bond_slave (shvarFile *ifcfg, { char *value; - value = svGetValueString (ifcfg, "MASTER_UUID"); + value = svGetValueStr_cp (ifcfg, "MASTER_UUID"); if (!value) - value = svGetValueString (ifcfg, "MASTER"); + value = svGetValueStr_cp (ifcfg, "MASTER"); if (value) { g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL); @@ -1699,9 +1889,9 @@ check_if_team_slave (shvarFile *ifcfg, { gs_free char *value = NULL; - value = svGetValueString (ifcfg, "TEAM_MASTER_UUID"); + value = svGetValueStr_cp (ifcfg, "TEAM_MASTER_UUID"); if (!value) - value = svGetValueString (ifcfg, "TEAM_MASTER"); + value = svGetValueStr_cp (ifcfg, "TEAM_MASTER"); if (!value) return FALSE; @@ -1777,7 +1967,7 @@ read_dcb_app (shvarFile *ifcfg, /* Priority */ tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app); - val = svGetValueString (ifcfg, tmp); + val = svGetValueStr_cp (ifcfg, tmp); if (val) { priority = _nm_utils_ascii_str_to_int64 (val, 0, 0, 7, -1); if (priority < 0) { @@ -1814,26 +2004,23 @@ read_dcb_bool_array (shvarFile *ifcfg, DcbSetBoolFunc set_func, GError **error) { - char *val; - gboolean success = FALSE; + gs_free char *val = NULL; guint i; - val = svGetValueString (ifcfg, prop); + val = svGetValueStr_cp (ifcfg, prop); if (!val) return TRUE; if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc); - success = TRUE; - goto out; + return TRUE; } - val = g_strstrip (val); if (strlen (val) != 8) { PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "boolean array must be 8 characters"); - goto out; + return FALSE; } /* All characters must be either 0 or 1 */ @@ -1842,15 +2029,11 @@ read_dcb_bool_array (shvarFile *ifcfg, PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid boolean digit"); - goto out; + return FALSE; } set_func (s_dcb, i, (val[i] == '1')); } - success = TRUE; - -out: - g_free (val); - return success; + return TRUE; } typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint); @@ -1865,26 +2048,23 @@ read_dcb_uint_array (shvarFile *ifcfg, DcbSetUintFunc set_func, GError **error) { - char *val; - gboolean success = FALSE; + gs_free char *val = NULL; guint i; - val = svGetValueString (ifcfg, prop); + val = svGetValueStr_cp (ifcfg, prop); if (!val) return TRUE; if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc); - success = TRUE; - goto out; + return TRUE; } - val = g_strstrip (val); if (strlen (val) != 8) { PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "uint array must be 8 characters"); - goto out; + return FALSE; } /* All characters must be either 0 - 7 or (optionally) f */ @@ -1898,14 +2078,11 @@ read_dcb_uint_array (shvarFile *ifcfg, prop, val, f_allowed ? " or 'f'" : ""); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid uint digit"); - goto out; + return FALSE; } } - success = TRUE; -out: - g_free (val); - return success; + return TRUE; } static gboolean @@ -1918,28 +2095,26 @@ read_dcb_percent_array (shvarFile *ifcfg, DcbSetUintFunc set_func, GError **error) { - char *val; - gboolean success = FALSE; - char **split = NULL, **iter; + gs_free char *val = NULL; + gs_strfreev char **split = NULL; + char **iter; guint i, sum = 0; - val = svGetValueString (ifcfg, prop); + val = svGetValueStr_cp (ifcfg, prop); if (!val) return TRUE; if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc); - success = TRUE; - goto out; + return TRUE; } - val = g_strstrip (val); split = g_strsplit_set (val, ",", 0); if (!split || (g_strv_length (split) != 8)) { PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "percent array must be 8 elements"); - goto out; + return FALSE; } for (iter = split, i = 0; iter && *iter; iter++, i++) { @@ -1950,7 +2125,7 @@ read_dcb_percent_array (shvarFile *ifcfg, PARSE_WARNING ("invalid %s percentage value '%s'", prop, *iter); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid percent element"); - goto out; + return FALSE; } set_func (s_dcb, i, (guint) tmp); sum += (guint) tmp; @@ -1960,16 +2135,10 @@ read_dcb_percent_array (shvarFile *ifcfg, PARSE_WARNING ("%s percentages do not equal 100%%", prop); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid percentage sum"); - goto out; + return FALSE; } - success = TRUE; - -out: - if (split) - g_strfreev (split); - g_free (val); - return success; + return TRUE; } static gboolean @@ -2001,7 +2170,7 @@ make_dcb_setting (shvarFile *ifcfg, return FALSE; } if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) { - val = svGetValueString (ifcfg, KEY_DCB_APP_FCOE_MODE); + val = svGetValueStr_cp (ifcfg, KEY_DCB_APP_FCOE_MODE); if (val) { if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 || strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0) @@ -2138,11 +2307,9 @@ add_one_wep_key (shvarFile *ifcfg, g_return_val_if_fail (key_idx <= 3, FALSE); g_return_val_if_fail (s_wsec != NULL, FALSE); - value = svGetValueString (ifcfg, shvar_key); - if (!value || !strlen (value)) { - g_free (value); + value = svGetValueStr_cp (ifcfg, shvar_key); + if (!value) return TRUE; - } /* Validate keys */ if (passphrase) { @@ -2195,9 +2362,10 @@ add_one_wep_key (shvarFile *ifcfg, nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); g_free (key); success = TRUE; - } else + } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid WEP key length."); + } out: g_free (value); @@ -2245,7 +2413,7 @@ read_secret_flags (shvarFile *ifcfg, const char *flags_key) g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE); g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE); - val = svGetValueString (ifcfg, flags_key); + val = svGetValueStr_cp (ifcfg, flags_key); if (val) { if (strstr (val, SECRET_FLAG_AGENT)) flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; @@ -2264,7 +2432,7 @@ make_wep_setting (shvarFile *ifcfg, const char *file, GError **error) { - NMSettingWirelessSecurity *s_wsec; + gs_unref_object NMSettingWirelessSecurity *s_wsec = NULL; char *value; shvarFile *keys_ifcfg = NULL; int default_key_idx = 0; @@ -2274,14 +2442,14 @@ make_wep_setting (shvarFile *ifcfg, s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL); - value = svGetValueString (ifcfg, "DEFAULTKEY"); + value = svGetValueStr_cp (ifcfg, "DEFAULTKEY"); if (value) { default_key_idx = _nm_utils_ascii_str_to_int64 (value, 0, 1, 4, 0); if (default_key_idx == 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid default WEP key '%s'", value); g_free (value); - goto error; + return NULL; } has_default_key = TRUE; default_key_idx--; /* convert to [0...3] */ @@ -2296,21 +2464,21 @@ make_wep_setting (shvarFile *ifcfg, /* Read keys in the ifcfg file if they are system-owned */ if (key_flags == NM_SETTING_SECRET_FLAG_NONE) { if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error)) - goto error; + return NULL; /* Try to get keys from the "shadow" key file */ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); if (keys_ifcfg) { if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) { svCloseFile (keys_ifcfg); - goto error; + return NULL; } svCloseFile (keys_ifcfg); g_assert (error == NULL || *error == NULL); } } - value = svGetValueString (ifcfg, "SECURITYMODE"); + value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); if (value) { char *lcase; @@ -2326,7 +2494,7 @@ make_wep_setting (shvarFile *ifcfg, "Invalid WEP authentication algorithm '%s'", lcase); g_free (lcase); - goto error; + return NULL; } g_free (lcase); } @@ -2347,20 +2515,14 @@ make_wep_setting (shvarFile *ifcfg, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "WEP Shared Key authentication is invalid for " "unencrypted connections."); - goto error; + return NULL; } /* Unencrypted */ - g_object_unref (s_wsec); - s_wsec = NULL; + return NULL; } - return (NMSetting *) s_wsec; - -error: - if (s_wsec) - g_object_unref (s_wsec); - return NULL; + return g_steal_pointer (&s_wsec); } static gboolean @@ -2373,7 +2535,7 @@ fill_wpa_ciphers (shvarFile *ifcfg, char **list = NULL, **iter; int i = 0; - p = value = svGetValueString (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE"); + p = value = svGetValueStr_cp (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE"); if (!value) return TRUE; @@ -2443,13 +2605,13 @@ parse_wpa_psk (shvarFile *ifcfg, /* Try to get keys from the "shadow" key file */ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); if (keys_ifcfg) { - psk = svGetValueString (keys_ifcfg, "WPA_PSK"); + psk = svGetValueStr_cp (keys_ifcfg, "WPA_PSK"); svCloseFile (keys_ifcfg); } /* Fall back to the original ifcfg */ if (!psk) - psk = svGetValueString (ifcfg, "WPA_PSK"); + psk = svGetValueStr_cp (ifcfg, "WPA_PSK"); if (!psk) return NULL; @@ -2486,7 +2648,7 @@ eap_simple_reader (const char *eap_method, NMSettingSecretFlags flags; char *value; - value = svGetValueString (ifcfg, "IEEE_8021X_IDENTITY"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY"); if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_IDENTITY for EAP method '%s'.", @@ -2501,10 +2663,10 @@ eap_simple_reader (const char *eap_method, /* Only read the password if it's system-owned */ if (flags == NM_SETTING_SECRET_FLAG_NONE) { - value = svGetValueString (ifcfg, "IEEE_8021X_PASSWORD"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PASSWORD"); if (!value && keys) { /* Try the lookaside keys file */ - value = svGetValueString (keys, "IEEE_8021X_PASSWORD"); + value = svGetValueStr_cp (keys, "IEEE_8021X_PASSWORD"); } if (!value) { @@ -2543,6 +2705,19 @@ get_full_file_path (const char *ifcfg_path, const char *file_path) return ret; } +static char * +get_cert_value (const char *ifcfg_path, const char *value, + NMSetting8021xCKScheme *out_scheme) +{ + if (strncmp (value, "pkcs11:", 7) == 0) { + *out_scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11; + return g_strdup (value); + } + + *out_scheme = NM_SETTING_802_1X_CK_SCHEME_PATH; + return get_full_file_path (ifcfg_path, value); +} + static gboolean eap_tls_reader (const char *eap_method, shvarFile *ifcfg, @@ -2551,48 +2726,58 @@ eap_tls_reader (const char *eap_method, gboolean phase2, GError **error) { + gs_free char *ca_cert = NULL; + gs_free char *privkey = NULL; + gs_free char *privkey_password = NULL; char *value; - char *ca_cert = NULL; - char *real_path = NULL; - char *client_cert = NULL; - char *privkey = NULL; - char *privkey_password = NULL; - gboolean success = FALSE; + char *ca_cert_password = NULL; + char *client_cert_password = NULL; NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT"; - const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD"; - const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY"; + const char *ca_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD"; + const char *ca_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD; + const char *ca_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CA_CERT_PASSWORD_FLAGS"; + const char *ca_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS; const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT"; - const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS": "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS"; + const char *cli_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD"; + const char *cli_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD; + const char *cli_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CLIENT_CERT_PASSWORD_FLAGS"; + const char *cli_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS; + const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY"; + const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD"; + const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS" : "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS"; const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS; NMSettingSecretFlags flags; + NMSetting8021xCKScheme scheme; - value = svGetValueString (ifcfg, "IEEE_8021X_IDENTITY"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY"); if (value) { g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); g_free (value); } - ca_cert = svGetValueString (ifcfg, ca_cert_key); + ca_cert = svGetValueStr_cp (ifcfg, ca_cert_key); if (ca_cert) { - real_path = get_full_file_path (svFileGetName (ifcfg), ca_cert); + gs_free char *real_cert_value = NULL; + + real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme); if (phase2) { - if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, - real_path, - NM_SETTING_802_1X_CK_SCHEME_PATH, - NULL, - error)) - goto done; + if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) + return FALSE; } else { - if (!nm_setting_802_1x_set_ca_cert (s_8021x, - real_path, - NM_SETTING_802_1X_CK_SCHEME_PATH, - NULL, - error)) - goto done; + if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) + return FALSE; + } + + if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { + flags = read_secret_flags (ifcfg, ca_cert_pw_flags_key); + g_object_set (s_8021x, ca_cert_pw_flags_prop, flags, NULL); + + if (flags == NM_SETTING_SECRET_FLAG_NONE) { + ca_cert_password = svGetValueStr_cp (ifcfg, ca_cert_pw_key); + g_object_set (s_8021x, ca_cert_pw_prop, ca_cert_password, NULL); + } } - g_free (real_path); - real_path = NULL; } else { PARSE_WARNING ("missing %s for EAP method '%s'; this is insecure!", ca_cert_key, eap_method); @@ -2605,10 +2790,10 @@ eap_tls_reader (const char *eap_method, /* Read the private key password if it's system-owned */ if (flags == NM_SETTING_SECRET_FLAG_NONE) { /* Private key password */ - privkey_password = svGetValueString (ifcfg, pk_pw_key); + privkey_password = svGetValueStr_cp (ifcfg, pk_pw_key); if (!privkey_password && keys) { /* Try the lookaside keys file */ - privkey_password = svGetValueString (keys, pk_pw_key); + privkey_password = svGetValueStr_cp (keys, pk_pw_key); } if (!privkey_password) { @@ -2616,40 +2801,42 @@ eap_tls_reader (const char *eap_method, "Missing %s for EAP method '%s'.", pk_pw_key, eap_method); - goto done; + return FALSE; } } /* The private key itself */ - privkey = svGetValueString (ifcfg, pk_key); + privkey = svGetValueStr_cp (ifcfg, pk_key); if (!privkey) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing %s for EAP method '%s'.", pk_key, eap_method); - goto done; + return FALSE; } - real_path = get_full_file_path (svFileGetName (ifcfg), privkey); - if (phase2) { - if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, - real_path, - privkey_password, - NM_SETTING_802_1X_CK_SCHEME_PATH, - &privkey_format, - error)) - goto done; - } else { - if (!nm_setting_802_1x_set_private_key (s_8021x, - real_path, - privkey_password, - NM_SETTING_802_1X_CK_SCHEME_PATH, - &privkey_format, - error)) - goto done; + { + gs_free char *real_cert_value = NULL; + + real_cert_value = get_cert_value (svFileGetName (ifcfg), privkey, &scheme); + if (phase2) { + if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, + real_cert_value, + privkey_password, + scheme, + &privkey_format, + error)) + return FALSE; + } else { + if (!nm_setting_802_1x_set_private_key (s_8021x, + real_cert_value, + privkey_password, + scheme, + &privkey_format, + error)) + return FALSE; + } } - g_free (real_path); - real_path = NULL; /* Only set the client certificate if the private key is not PKCS#12 format, * as NM (due to supplicant restrictions) requires. If the key was PKCS#12, @@ -2658,44 +2845,39 @@ eap_tls_reader (const char *eap_method, */ if ( privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) { - client_cert = svGetValueString (ifcfg, cli_cert_key); + gs_free char *real_cert_value = NULL; + gs_free char *client_cert = NULL; + + client_cert = svGetValueStr_cp (ifcfg, cli_cert_key); if (!client_cert) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing %s for EAP method '%s'.", cli_cert_key, eap_method); - goto done; + return FALSE; } - real_path = get_full_file_path (svFileGetName (ifcfg), client_cert); + real_cert_value = get_cert_value (svFileGetName (ifcfg), client_cert, &scheme); if (phase2) { - if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, - real_path, - NM_SETTING_802_1X_CK_SCHEME_PATH, - NULL, - error)) - goto done; + if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, real_cert_value, scheme, NULL, error)) + return FALSE; } else { - if (!nm_setting_802_1x_set_client_cert (s_8021x, - real_path, - NM_SETTING_802_1X_CK_SCHEME_PATH, - NULL, - error)) - goto done; + if (!nm_setting_802_1x_set_client_cert (s_8021x, real_cert_value, scheme, NULL, error)) + return FALSE; } - g_free (real_path); - real_path = NULL; - } - success = TRUE; + if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { + flags = read_secret_flags (ifcfg, cli_cert_pw_flags_key); + g_object_set (s_8021x, cli_cert_pw_flags_prop, flags, NULL); -done: - g_free (real_path); - g_free (ca_cert); - g_free (client_cert); - g_free (privkey); - g_free (privkey_password); - return success; + if (flags == NM_SETTING_SECRET_FLAG_NONE) { + client_cert_password = svGetValueStr_cp (ifcfg, cli_cert_pw_key); + g_object_set (s_8021x, cli_cert_pw_prop, client_cert_password, NULL); + } + } + } + + return TRUE; } static gboolean @@ -2708,28 +2890,25 @@ eap_peap_reader (const char *eap_method, { char *anon_ident = NULL; char *ca_cert = NULL; - char *real_cert_path = NULL; + char *real_cert_value = NULL; char *inner_auth = NULL; char *peapver = NULL; char *lower; char **list = NULL, **iter; gboolean success = FALSE; + NMSetting8021xCKScheme scheme; - ca_cert = svGetValueString (ifcfg, "IEEE_8021X_CA_CERT"); + ca_cert = svGetValueStr_cp (ifcfg, "IEEE_8021X_CA_CERT"); if (ca_cert) { - real_cert_path = get_full_file_path (svFileGetName (ifcfg), ca_cert); - if (!nm_setting_802_1x_set_ca_cert (s_8021x, - real_cert_path, - NM_SETTING_802_1X_CK_SCHEME_PATH, - NULL, - error)) + real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme); + if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) goto done; } else { PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", eap_method); } - peapver = svGetValueString (ifcfg, "IEEE_8021X_PEAP_VERSION"); + peapver = svGetValueStr_cp (ifcfg, "IEEE_8021X_PEAP_VERSION"); if (peapver) { if (!strcmp (peapver, "0")) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL); @@ -2746,11 +2925,11 @@ eap_peap_reader (const char *eap_method, if (svGetValueBoolean (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE)) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL); - anon_ident = svGetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY"); - if (anon_ident && strlen (anon_ident)) + anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY"); + if (anon_ident) g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); - inner_auth = svGetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); + inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); if (!inner_auth) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_INNER_AUTH_METHODS."); @@ -2797,7 +2976,7 @@ done: g_strfreev (list); g_free (inner_auth); g_free (peapver); - g_free (real_cert_path); + g_free (real_cert_value); g_free (ca_cert); g_free (anon_ident); return success; @@ -2814,30 +2993,27 @@ eap_ttls_reader (const char *eap_method, gboolean success = FALSE; char *anon_ident = NULL; char *ca_cert = NULL; - char *real_cert_path = NULL; + char *real_cert_value = NULL; char *inner_auth = NULL; char *tmp; char **list = NULL, **iter; + NMSetting8021xCKScheme scheme; - ca_cert = svGetValueString (ifcfg, "IEEE_8021X_CA_CERT"); + ca_cert = svGetValueStr_cp (ifcfg, "IEEE_8021X_CA_CERT"); if (ca_cert) { - real_cert_path = get_full_file_path (svFileGetName (ifcfg), ca_cert); - if (!nm_setting_802_1x_set_ca_cert (s_8021x, - real_cert_path, - NM_SETTING_802_1X_CK_SCHEME_PATH, - NULL, - error)) + real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme); + if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) goto done; } else { PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", eap_method); } - anon_ident = svGetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY"); - if (anon_ident && strlen (anon_ident)) + anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY"); + if (anon_ident) g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); - tmp = svGetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); + tmp = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); if (!tmp) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_INNER_AUTH_METHODS."); @@ -2885,7 +3061,7 @@ done: if (list) g_strfreev (list); g_free (inner_auth); - g_free (real_cert_path); + g_free (real_cert_value); g_free (ca_cert); g_free (anon_ident); return success; @@ -2906,17 +3082,17 @@ eap_fast_reader (const char *eap_method, char *fast_provisioning = NULL; char *lower; char **list = NULL, **iter; - const char* pac_prov_str; + const char *pac_prov_str; gboolean allow_unauth = FALSE, allow_auth = FALSE; gboolean success = FALSE; - pac_file = svGetValueString (ifcfg, "IEEE_8021X_PAC_FILE"); + pac_file = svGetValueStr_cp (ifcfg, "IEEE_8021X_PAC_FILE"); if (pac_file) { real_pac_path = get_full_file_path (svFileGetName (ifcfg), pac_file); g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL); } - fast_provisioning = svGetValueString (ifcfg, "IEEE_8021X_FAST_PROVISIONING"); + fast_provisioning = svGetValueStr_cp (ifcfg, "IEEE_8021X_FAST_PROVISIONING"); if (fast_provisioning) { list = g_strsplit_set (fast_provisioning, " \t", 0); for (iter = list; iter && *iter; iter++) { @@ -2944,11 +3120,11 @@ eap_fast_reader (const char *eap_method, goto done; } - anon_ident = svGetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY"); - if (anon_ident && strlen (anon_ident)) + anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY"); + if (anon_ident) g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); - inner_auth = svGetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); + inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); if (!inner_auth) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_INNER_AUTH_METHODS."); @@ -2998,12 +3174,12 @@ done: typedef struct { const char *method; - gboolean (*reader)(const char *eap_method, - shvarFile *ifcfg, - shvarFile *keys, - NMSetting8021x *s_8021x, - gboolean phase2, - GError **error); + gboolean (*reader) (const char *eap_method, + shvarFile *ifcfg, + shvarFile *keys, + NMSetting8021x *s_8021x, + gboolean phase2, + GError **error); gboolean wifi_phase2_only; } EAPReader; @@ -3035,7 +3211,7 @@ read_8021x_list_value (shvarFile *ifcfg, g_return_if_fail (ifcfg_var_name != NULL); g_return_if_fail (prop_name != NULL); - value = svGetValueString (ifcfg, ifcfg_var_name); + value = svGetValueStr_cp (ifcfg, ifcfg_var_name); if (!value) return; @@ -3053,12 +3229,13 @@ fill_8021x (shvarFile *ifcfg, gboolean wifi, GError **error) { + nm_auto_shvar_file_close shvarFile *keys = NULL; NMSetting8021x *s_8021x; - shvarFile *keys = NULL; char *value; char **list = NULL, **iter; + gint64 timeout; - value = svGetValueString (ifcfg, "IEEE_8021X_EAP_METHODS"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_EAP_METHODS"); if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_EAP_METHODS for key management '%s'", @@ -3104,7 +3281,7 @@ fill_8021x (shvarFile *ifcfg, found = TRUE; break; - next: +next: eap++; } @@ -3119,37 +3296,54 @@ fill_8021x (shvarFile *ifcfg, goto error; } - value = svGetValueString (ifcfg, "IEEE_8021X_SUBJECT_MATCH"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_SUBJECT_MATCH"); g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, value, NULL); g_free (value); - value = svGetValueString (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH"); g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, value, NULL); g_free (value); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS"); + if (value) { + NMSetting8021xAuthFlags flags; + char *token; + + if (nm_utils_enum_from_str (nm_setting_802_1x_auth_flags_get_type (), value, + (int *) &flags, &token)) { + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, flags, NULL); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid IEEE_8021X_PHASE1_AUTH_FLAGS flag '%s'", token); + g_free (token); + g_free (value); + goto error; + } + g_free (value); + } + read_8021x_list_value (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", s_8021x, NM_SETTING_802_1X_ALTSUBJECT_MATCHES); read_8021x_list_value (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", s_8021x, NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES); - value = svGetValueString (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH"); g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, value, NULL); g_free (value); - value = svGetValueString (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH"); g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, value, NULL); g_free (value); + timeout = svGetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", 10, 0, G_MAXINT32, 0); + g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (gint32) timeout, NULL); + if (list) g_strfreev (list); - if (keys) - svCloseFile (keys); return s_8021x; error: if (list) g_strfreev (list); - if (keys) - svCloseFile (keys); g_object_unref (s_8021x); return NULL; } @@ -3168,7 +3362,7 @@ make_wpa_setting (shvarFile *ifcfg, wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); - value = svGetValueString (ifcfg, "KEY_MGMT"); + value = svGetValueStr_cp (ifcfg, "KEY_MGMT"); wpa_psk = !g_strcmp0 (value, "WPA-PSK"); wpa_eap = !g_strcmp0 (value, "WPA-EAP"); ieee8021x = !g_strcmp0 (value, "IEEE8021X"); @@ -3188,8 +3382,8 @@ make_wpa_setting (shvarFile *ifcfg, } else { char *allow_wpa, *allow_rsn; - allow_wpa = svGetValueString (ifcfg, "WPA_ALLOW_WPA"); - allow_rsn = svGetValueString (ifcfg, "WPA_ALLOW_WPA2"); + allow_wpa = svGetValueStr_cp (ifcfg, "WPA_ALLOW_WPA"); + allow_rsn = svGetValueStr_cp (ifcfg, "WPA_ALLOW_WPA2"); if (allow_wpa && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA", TRUE)) nm_setting_wireless_security_add_proto (wsec, "wpa"); @@ -3243,7 +3437,7 @@ make_wpa_setting (shvarFile *ifcfg, g_free (value); - value = svGetValueString (ifcfg, "SECURITYMODE"); + value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); if (NM_IN_STRSET (value, NULL, "open")) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, value, NULL); @@ -3269,12 +3463,12 @@ make_leap_setting (shvarFile *ifcfg, wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); - value = svGetValueString (ifcfg, "KEY_MGMT"); + value = svGetValueStr_cp (ifcfg, "KEY_MGMT"); if (!value || strcmp (value, "IEEE8021X")) goto error; /* Not LEAP */ g_free (value); - value = svGetValueString (ifcfg, "SECURITYMODE"); + value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); if (!value || strcasecmp (value, "leap")) goto error; /* Not LEAP */ @@ -3285,12 +3479,12 @@ make_leap_setting (shvarFile *ifcfg, /* Read LEAP password if it's system-owned */ if (flags == NM_SETTING_SECRET_FLAG_NONE) { - value = svGetValueString (ifcfg, "IEEE_8021X_PASSWORD"); + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PASSWORD"); if (!value) { /* Try to get keys from the "shadow" key file */ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); if (keys_ifcfg) { - value = svGetValueString (keys_ifcfg, "IEEE_8021X_PASSWORD"); + value = svGetValueStr_cp (keys_ifcfg, "IEEE_8021X_PASSWORD"); svCloseFile (keys_ifcfg); } } @@ -3299,8 +3493,8 @@ make_leap_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "IEEE_8021X_IDENTITY"); - if (!value || !strlen (value)) { + value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY"); + if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing LEAP identity"); goto error; @@ -3392,25 +3586,25 @@ make_wireless_setting (shvarFile *ifcfg, s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); - value = svGetValueString (ifcfg, "HWADDR"); + value = svGetValueStr_cp (ifcfg, "HWADDR"); if (value) { value = g_strstrip (value); g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "MACADDR"); + value = svGetValueStr_cp (ifcfg, "MACADDR"); if (value) { value = g_strstrip (value); g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK"); + value = svGetValueStr_cp (ifcfg, "GENERATE_MAC_ADDRESS_MASK"); g_object_set (s_wireless, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, value, NULL); g_free (value); - value = svGetValueString (ifcfg, "HWADDR_BLACKLIST"); + value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); if (value) { char **strv; @@ -3420,7 +3614,7 @@ make_wireless_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "ESSID"); + value = svGetValueStr_cp (ifcfg, "ESSID"); if (value) { gs_unref_bytes GBytes *bytes = NULL; gsize ssid_len = 0; @@ -3449,7 +3643,7 @@ make_wireless_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "MODE"); + value = svGetValueStr_cp (ifcfg, "MODE"); if (value) { char *lcase; const char *mode = NULL; @@ -3475,14 +3669,14 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL); } - value = svGetValueString (ifcfg, "BSSID"); + value = svGetValueStr_cp (ifcfg, "BSSID"); if (value) { value = g_strstrip (value); g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "CHANNEL"); + value = svGetValueStr_cp (ifcfg, "CHANNEL"); if (value) { errno = 0; chan = _nm_utils_ascii_str_to_int64 (value, 10, 1, 196, 0); @@ -3496,7 +3690,7 @@ make_wireless_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "BAND"); + value = svGetValueStr_cp (ifcfg, "BAND"); if (value) { if (!strcmp (value, "a")) { if (chan && chan <= 14) { @@ -3527,7 +3721,7 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL); } - value = svGetValueString (ifcfg, "MTU"); + value = svGetValueStr_cp (ifcfg, "MTU"); if (value) { int mtu; @@ -3637,7 +3831,7 @@ wireless_connection_from_ifcfg (const char *file, printable_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); } else - printable_ssid = g_strdup_printf ("unmanaged"); + printable_ssid = g_strdup ("unmanaged"); mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting)); if (mode && !strcmp (mode, "adhoc")) @@ -3856,7 +4050,7 @@ parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *va } /* ETHTOOL_WAKE_ON_LAN = ignore overrides WoL settings in ETHTOOL_OPTS */ - wol_value = svGetValueString (ifcfg, "ETHTOOL_WAKE_ON_LAN"); + wol_value = svGetValueStr_cp (ifcfg, "ETHTOOL_WAKE_ON_LAN"); if (wol_value) { if (strcmp (wol_value, "ignore") == 0) wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; @@ -3891,7 +4085,7 @@ make_wired_setting (shvarFile *ifcfg, s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); - value = svGetValueString (ifcfg, "MTU"); + value = svGetValueStr_cp (ifcfg, "MTU"); if (value) { int mtu; @@ -3903,14 +4097,14 @@ make_wired_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "HWADDR"); + value = svGetValueStr_cp (ifcfg, "HWADDR"); if (value) { value = g_strstrip (value); g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "SUBCHANNELS"); + value = svGetValueStr_cp (ifcfg, "SUBCHANNELS"); if (value) { const char *p = value; gboolean success = TRUE; @@ -3941,28 +4135,29 @@ make_wired_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "PORTNAME"); - if (value && strlen (value)) { + value = svGetValueStr_cp (ifcfg, "PORTNAME"); + if (value) { nm_setting_wired_add_s390_option (s_wired, "portname", value); + g_free (value); } - g_free (value); - value = svGetValueString (ifcfg, "CTCPROT"); - if (value && strlen (value)) + value = svGetValueStr_cp (ifcfg, "CTCPROT"); + if (value) { nm_setting_wired_add_s390_option (s_wired, "ctcprot", value); - g_free (value); + g_free (value); + } - nettype = svGetValueString (ifcfg, "NETTYPE"); - if (nettype && strlen (nettype)) { + nettype = svGetValueStr_cp (ifcfg, "NETTYPE"); + if (nettype) { if (!strcmp (nettype, "qeth") || !strcmp (nettype, "lcs") || !strcmp (nettype, "ctc")) g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, NULL); else PARSE_WARNING ("unknown s390 NETTYPE '%s'", nettype); + g_free (nettype); } - g_free (nettype); - value = svGetValueString (ifcfg, "OPTIONS"); - if (value && strlen (value)) { + value = svGetValueStr_cp (ifcfg, "OPTIONS"); + if (value) { char **options, **iter; iter = options = g_strsplit_set (value, " ", 0); @@ -3979,21 +4174,21 @@ make_wired_setting (shvarFile *ifcfg, iter++; } g_strfreev (options); + g_free (value); } - g_free (value); - value = svGetValueString (ifcfg, "MACADDR"); + value = svGetValueStr_cp (ifcfg, "MACADDR"); if (value) { value = g_strstrip (value); g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK"); + value = svGetValueStr_cp (ifcfg, "GENERATE_MAC_ADDRESS_MASK"); g_object_set (s_wired, NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, value, NULL); g_free (value); - value = svGetValueString (ifcfg, "HWADDR_BLACKLIST"); + value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); if (value) { char **strv; @@ -4003,7 +4198,7 @@ make_wired_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "KEY_MGMT"); + value = svGetValueStr_cp (ifcfg, "KEY_MGMT"); if (value) { if (!strcmp (value, "IEEE8021X")) { *s_8021x = fill_8021x (ifcfg, file, value, FALSE, error); @@ -4078,19 +4273,19 @@ parse_infiniband_p_key (shvarFile *ifcfg, int id; gboolean ret = FALSE; - device = svGetValueString (ifcfg, "DEVICE"); + device = svGetValueStr_cp (ifcfg, "DEVICE"); if (!device) { PARSE_WARNING ("InfiniBand connection specified PKEY but not DEVICE"); goto done; } - physdev = svGetValueString (ifcfg, "PHYSDEV"); + physdev = svGetValueStr_cp (ifcfg, "PHYSDEV"); if (!physdev) { PARSE_WARNING ("InfiniBand connection specified PKEY but not PHYSDEV"); goto done; } - pkey_id = svGetValueString (ifcfg, "PKEY_ID"); + pkey_id = svGetValueStr_cp (ifcfg, "PKEY_ID"); if (!pkey_id) { PARSE_WARNING ("InfiniBand connection specified PKEY but not PKEY_ID"); goto done; @@ -4138,7 +4333,7 @@ make_infiniband_setting (shvarFile *ifcfg, s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ()); - value = svGetValueString (ifcfg, "MTU"); + value = svGetValueStr_cp (ifcfg, "MTU"); if (value) { int mtu; @@ -4150,7 +4345,7 @@ make_infiniband_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "HWADDR"); + value = svGetValueStr_cp (ifcfg, "HWADDR"); if (value) { value = g_strstrip (value); g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, value, NULL); @@ -4248,17 +4443,17 @@ make_bond_setting (shvarFile *ifcfg, NMSettingBond *s_bond; char *value; - s_bond = NM_SETTING_BOND (nm_setting_bond_new ()); - - value = svGetValueString (ifcfg, "DEVICE"); - if (!value || !strlen (value)) { + value = svGetValueStr_cp (ifcfg, "DEVICE"); + if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); - goto error; + return NULL; } g_free (value); - value = svGetValueString (ifcfg, "BONDING_OPTS"); + s_bond = NM_SETTING_BOND (nm_setting_bond_new ()); + + value = svGetValueStr_cp (ifcfg, "BONDING_OPTS"); if (value) { char **items, **iter; @@ -4271,7 +4466,7 @@ make_bond_setting (shvarFile *ifcfg, if (keys && *keys) { key = *keys; val = *(keys + 1); - if (val && strlen(key) && strlen(val)) + if (val && key[0] && val[0]) handle_bond_option (s_bond, key, val); } @@ -4283,10 +4478,6 @@ make_bond_setting (shvarFile *ifcfg, } return (NMSetting *) s_bond; - -error: - g_object_unref (s_bond); - return NULL; } static NMConnection * @@ -4342,7 +4533,7 @@ read_team_config (shvarFile *ifcfg, const char *key, GError **error) gs_free char *value = NULL; size_t l; - value = svGetValueString (ifcfg, key); + value = svGetValueStr_cp (ifcfg, key); if (!value) return NULL; @@ -4370,29 +4561,26 @@ make_team_setting (shvarFile *ifcfg, char *value; GError *local_err = NULL; - s_team = NM_SETTING_TEAM (nm_setting_team_new ()); - - value = svGetValueString (ifcfg, "DEVICE"); - if (!value || !strlen (value)) { + value = svGetValueStr_cp (ifcfg, "DEVICE"); + if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); - goto error; + return NULL; } g_free (value); value = read_team_config (ifcfg, "TEAM_CONFIG", &local_err); if (local_err) { g_propagate_error (error, local_err); - goto error; + return NULL; } + + s_team = NM_SETTING_TEAM (nm_setting_team_new ()); + g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL); g_free (value); return (NMSetting *) s_team; - -error: - g_object_unref (s_team); - return NULL; } static NMConnection * @@ -4454,23 +4642,23 @@ handle_bridge_option (NMSetting *setting, guint32 u = 0; if (!strcmp (key, "priority")) { - if (stp == FALSE) { + if (stp == FALSE) PARSE_WARNING ("'priority' invalid when STP is disabled"); - } else if (get_uint (value, &u)) + else if (get_uint (value, &u)) g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL); else PARSE_WARNING ("invalid priority value '%s'", value); } else if (!strcmp (key, "hello_time")) { - if (stp == FALSE) { + if (stp == FALSE) PARSE_WARNING ("'hello_time' invalid when STP is disabled"); - } else if (get_uint (value, &u)) + else if (get_uint (value, &u)) g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL); else PARSE_WARNING ("invalid hello_time value '%s'", value); } else if (!strcmp (key, "max_age")) { - if (stp == FALSE) { + if (stp == FALSE) PARSE_WARNING ("'max_age' invalid when STP is disabled"); - } else if (get_uint (value, &u)) + else if (get_uint (value, &u)) g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL); else PARSE_WARNING ("invalid max_age value '%s'", value); @@ -4506,7 +4694,7 @@ handle_bridging_opts (NMSetting *setting, if (keys && *keys) { key = *keys; val = *(keys + 1); - if (val && strlen(key) && strlen(val)) + if (val && strlen (key) && strlen (val)) func (setting, stp, key, val); } @@ -4527,24 +4715,24 @@ make_bridge_setting (shvarFile *ifcfg, gboolean stp = FALSE; gboolean stp_set = FALSE; - s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ()); - - value = svGetValueString (ifcfg, "DEVICE"); - if (!value || !strlen (value)) { + value = svGetValueStr_cp (ifcfg, "DEVICE"); + if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); - goto error; + return NULL; } g_free (value); - value = svGetValueString (ifcfg, "MACADDR"); + s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ()); + + value = svGetValueStr_cp (ifcfg, "MACADDR"); if (value) { value = g_strstrip (value); g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL); g_free (value); } - value = svGetValueString (ifcfg, "STP"); + value = svGetValueStr_cp (ifcfg, "STP"); if (value) { if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) { g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL); @@ -4563,7 +4751,7 @@ make_bridge_setting (shvarFile *ifcfg, g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL); } - value = svGetValueString (ifcfg, "DELAY"); + value = svGetValueStr_cp (ifcfg, "DELAY"); if (value) { if (stp) { if (get_uint (value, &u)) @@ -4575,17 +4763,13 @@ make_bridge_setting (shvarFile *ifcfg, g_free (value); } - value = svGetValueString (ifcfg, "BRIDGING_OPTS"); + value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); if (value) { handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option); g_free (value); } return (NMSetting *) s_bridge; - -error: - g_object_unref (s_bridge); - return NULL; } static NMConnection * @@ -4616,7 +4800,7 @@ bridge_connection_from_ifcfg (const char *file, g_object_unref (connection); return NULL; } - nm_connection_add_setting (connection, bridge_setting); + nm_connection_add_setting (connection, bridge_setting); return connection; } @@ -4658,14 +4842,14 @@ make_bridge_port_setting (shvarFile *ifcfg) g_return_val_if_fail (ifcfg != NULL, FALSE); - value = svGetValueString (ifcfg, "BRIDGE_UUID"); + value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID"); if (!value) - value = svGetValueString (ifcfg, "BRIDGE"); + value = svGetValueStr_cp (ifcfg, "BRIDGE"); if (value) { g_free (value); s_port = nm_setting_bridge_port_new (); - value = svGetValueString (ifcfg, "BRIDGING_OPTS"); + value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); if (value) handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option); g_free (value); @@ -4742,7 +4926,7 @@ parse_prio_map_list (NMSettingVlan *s_vlan, char *value; gchar **list = NULL, **iter; - value = svGetValueString (ifcfg, key); + value = svGetValueStr_cp (ifcfg, key); if (!value) return; @@ -4764,16 +4948,16 @@ make_vlan_setting (shvarFile *ifcfg, const char *file, GError **error) { - NMSettingVlan *s_vlan = NULL; + gs_unref_object NMSettingVlan *s_vlan = NULL; + gs_free char *parent = NULL; + gs_free char *iface_name = NULL; char *value = NULL; - char *iface_name = NULL; - char *parent = NULL; const char *p = NULL; int vlan_id = -1; guint32 vlan_flags = 0; gint gvrp, reorder_hdr; - value = svGetValueString (ifcfg, "VLAN_ID"); + value = svGetValueStr_cp (ifcfg, "VLAN_ID"); if (value) { vlan_id = _nm_utils_ascii_str_to_int64 (value, 10, 0, 4095, -1); if (vlan_id == -1) { @@ -4786,7 +4970,7 @@ make_vlan_setting (shvarFile *ifcfg, } /* Need DEVICE if we don't have a separate VLAN_ID property */ - iface_name = svGetValueString (ifcfg, "DEVICE"); + iface_name = svGetValueStr_cp (ifcfg, "DEVICE"); if (!iface_name && vlan_id < 0) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing DEVICE property; cannot determine VLAN ID."); @@ -4796,7 +4980,7 @@ make_vlan_setting (shvarFile *ifcfg, s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ()); /* Parent interface from PHYSDEV takes precedence if it exists */ - parent = svGetValueString (ifcfg, "PHYSDEV"); + parent = svGetValueStr_cp (ifcfg, "PHYSDEV"); if (iface_name) { p = strchr (iface_name, '.'); @@ -4808,8 +4992,7 @@ make_vlan_setting (shvarFile *ifcfg, /* Like initscripts, if no PHYSDEV and we get an obviously * invalid parent interface from DEVICE, fail. */ - g_free (parent); - parent = NULL; + nm_clear_g_free (&parent); } } p++; @@ -4834,17 +5017,16 @@ make_vlan_setting (shvarFile *ifcfg, if (vlan_id < 0) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Failed to determine VLAN ID from DEVICE or VLAN_ID."); - goto error; + return NULL; } g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL); if (parent == NULL) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Failed to determine VLAN parent from DEVICE or PHYSDEV"); - goto error; + return NULL; } g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL); - g_clear_pointer (&parent, g_free); vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS; @@ -4852,7 +5034,7 @@ make_vlan_setting (shvarFile *ifcfg, if (gvrp > 0) vlan_flags |= NM_VLAN_FLAG_GVRP; - value = svGetValueString (ifcfg, "VLAN_FLAGS"); + value = svGetValueStr_cp (ifcfg, "VLAN_FLAGS"); if (value) { gs_strfreev char **strv = NULL; char **ptr; @@ -4883,15 +5065,7 @@ make_vlan_setting (shvarFile *ifcfg, parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP); parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP); - g_free (iface_name); - - return (NMSetting *) s_vlan; - -error: - g_free (parent); - g_free (iface_name); - g_object_unref (s_vlan); - return NULL; + return g_steal_pointer (&s_vlan); } static NMConnection * @@ -4963,7 +5137,7 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg, nm_connection_add_setting (connection, nm_setting_generic_new ()); /* Get a spec */ - value = svGetValueString (ifcfg, "HWADDR"); + value = svGetValueStr_cp (ifcfg, "HWADDR"); if (value) { char *lower = g_ascii_strdown (value, -1); *out_spec = g_strdup_printf ("%s:mac:%s", type, lower); @@ -4972,14 +5146,14 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg, return connection; } - value = svGetValueString (ifcfg, "SUBCHANNELS"); + value = svGetValueStr_cp (ifcfg, "SUBCHANNELS"); if (value) { *out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, value); g_free (value); return connection; } - value = svGetValueString (ifcfg, "DEVICE"); + value = svGetValueStr_cp (ifcfg, "DEVICE"); if (value) { *out_spec = g_strdup_printf ("%s:interface-name:%s", type, value); g_free (value); @@ -5008,11 +5182,9 @@ uuid_from_file (const char *filename) return NULL; /* Try for a UUID key before falling back to hashing the file name */ - uuid = svGetValueString (ifcfg, "UUID"); - if (!uuid || !strlen (uuid)) { - g_free (uuid); + uuid = svGetValueStr_cp (ifcfg, "UUID"); + if (!uuid) uuid = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); - } svCloseFile (ifcfg); return uuid; @@ -5029,7 +5201,8 @@ check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6) */ if (!s_ip4 || nm_setting_ip_config_get_num_dns_searches (NM_SETTING_IP_CONFIG (s_ip4)) == 0) { /* DNS searches */ - char *value = svGetValueString (ifcfg, "DOMAIN"); + char *value = svGetValueStr_cp (ifcfg, "DOMAIN"); + if (value) { char **searches = g_strsplit (value, " ", 0); if (searches) { @@ -5055,12 +5228,13 @@ connection_from_file_full (const char *filename, GError **error, gboolean *out_ignore_error) { - NMConnection *connection = NULL; - shvarFile *parsed; + nm_auto_shvar_file_close shvarFile *parsed = NULL; + gs_unref_object NMConnection *connection = NULL; gs_free char *type = NULL; char *devtype, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL; + NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL, *s_user; const char *ifcfg_name = NULL; + gboolean has_ip4_defroute = FALSE; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (out_unhandled && !*out_unhandled, NULL); @@ -5082,30 +5256,38 @@ connection_from_file_full (const char *filename, if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); - if (!connection) + if (!connection) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "NM_CONTROLLED was false but device was not uniquely identified; device will be managed"); - goto done; + } + return g_steal_pointer (&connection); } /* iBFT is handled by the iBFT settings plugin */ - bootproto = svGetValueString (parsed, "BOOTPROTO"); + bootproto = svGetValueStr_cp (parsed, "BOOTPROTO"); if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) { if (out_ignore_error) *out_ignore_error = TRUE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring iBFT configuration"); g_free (bootproto); - goto done; + return NULL; } g_free (bootproto); - devtype = svGetValueString (parsed, "DEVICETYPE"); + devtype = svGetValueStr_cp (parsed, "DEVICETYPE"); if (devtype) { if (!strcasecmp (devtype, TYPE_TEAM)) type = g_strdup (TYPE_TEAM); - else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) - type = g_strdup (TYPE_ETHERNET); + else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) { + gs_free char *device = NULL; + + device = svGetValueStr_cp (parsed, "DEVICE"); + if (device && is_vlan_device (device, parsed)) + type = g_strdup (TYPE_VLAN); + else + type = g_strdup (TYPE_ETHERNET); + } g_free (devtype); } if (!type) { @@ -5114,33 +5296,32 @@ connection_from_file_full (const char *filename, /* Team and TeamPort types are also accepted by the mere * presense of TEAM_CONFIG/TEAM_MASTER. They don't require * DEVICETYPE. */ - t = svGetValueString (parsed, "TEAM_CONFIG"); + t = svGetValueStr_cp (parsed, "TEAM_CONFIG"); if (t) type = g_strdup (TYPE_TEAM); } if (!type) - type = svGetValueString (parsed, "TYPE"); + type = svGetValueStr_cp (parsed, "TYPE"); if (!type) { gs_free char *tmp = NULL; char *device; - if ((tmp = svGetValueString (parsed, "IPV6TUNNELIPV4"))) { + if ((tmp = svGetValueStr_cp (parsed, "IPV6TUNNELIPV4"))) { if (out_ignore_error) *out_ignore_error = TRUE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring unsupported connection due to IPV6TUNNELIPV4"); - goto done; + return NULL; } - device = svGetValueString (parsed, "DEVICE"); + device = svGetValueStr_cp (parsed, "DEVICE"); if (!device) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "File '%s' had neither TYPE nor DEVICE keys.", filename); - goto done; + return NULL; } - g_assert (device[0]); if (!strcmp (device, "lo")) { if (out_ignore_error) @@ -5148,7 +5329,7 @@ connection_from_file_full (const char *filename, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring loopback device config."); g_free (device); - goto done; + return NULL; } if (!test_type) { @@ -5196,7 +5377,7 @@ connection_from_file_full (const char *filename, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignore script for unknown device type which has a matching %s script", p_path); - goto done; + return NULL; } } @@ -5220,11 +5401,21 @@ connection_from_file_full (const char *filename, } } + if (nm_streq0 (type, TYPE_ETHERNET)) { + gs_free char *bond_options = NULL; + + if (svGetValueStr (parsed, "BONDING_OPTS", &bond_options)) { + /* initscripts consider these as bond masters */ + g_free (type); + type = g_strdup (TYPE_BOND); + } + } + if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE) && strcasecmp (type, TYPE_BOND)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "BONDING_MASTER=yes key only allowed in TYPE=bond connections"); - goto done; + return NULL; } /* Construct the connection */ @@ -5244,29 +5435,30 @@ connection_from_file_full (const char *filename, connection = bridge_connection_from_ifcfg (filename, parsed, error); else { connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled); - if (!connection) + if (!connection) { PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed"); - goto done; + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Failed to read unrecognized connection"); + } + return g_steal_pointer (&connection); } if (!connection) - goto done; + return NULL; s_ip6 = make_ip6_setting (parsed, network_file, error); - if (!s_ip6) { - g_object_unref (connection); - connection = NULL; - goto done; - } else + if (!s_ip6) + return NULL; + else nm_connection_add_setting (connection, s_ip6); - s_ip4 = make_ip4_setting (parsed, network_file, error); - if (!s_ip4) { - g_object_unref (connection); - connection = NULL; - goto done; - } else { - read_aliases (NM_SETTING_IP_CONFIG (s_ip4), filename); + s_ip4 = make_ip4_setting (parsed, network_file, &has_ip4_defroute, error); + if (!s_ip4) + return NULL; + else { + read_aliases (NM_SETTING_IP_CONFIG (s_ip4), + !has_ip4_defroute && !nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (s_ip4)), + filename); nm_connection_add_setting (connection, s_ip4); } @@ -5280,6 +5472,10 @@ connection_from_file_full (const char *filename, if (s_proxy) nm_connection_add_setting (connection, s_proxy); + s_user = make_user_setting (parsed, error); + if (s_user) + nm_connection_add_setting (connection, s_user); + /* Bridge port? */ s_port = make_bridge_port_setting (parsed); if (s_port) @@ -5290,22 +5486,15 @@ connection_from_file_full (const char *filename, if (s_port) nm_connection_add_setting (connection, s_port); - if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) { - g_object_unref (connection); - connection = NULL; - goto done; - } + if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) + return NULL; if (s_dcb) nm_connection_add_setting (connection, s_dcb); - if (!nm_connection_normalize (connection, NULL, NULL, error)) { - g_object_unref (connection); - connection = NULL; - } + if (!nm_connection_normalize (connection, NULL, NULL, error)) + return NULL; -done: - svCloseFile (parsed); - return connection; + return g_steal_pointer (&connection); } NMConnection * @@ -5348,7 +5537,7 @@ devtimeout_from_file (const char *filename) if (!ifcfg) return 0; - devtimeout_str = svGetValueString (ifcfg, "DEVTIMEOUT"); + devtimeout_str = svGetValueStr_cp (ifcfg, "DEVTIMEOUT"); if (devtimeout_str) { devtimeout = _nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0); g_free (devtimeout_str); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index d1c00976..e82ef60c 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -45,8 +45,9 @@ check_rpm_temp_suffix (const char *path) /* Matches *;[a-fA-F0-9]{8}; used by rpm */ ptr = strrchr (path, ';'); - if (ptr && (strspn (ptr + 1, "abcdefABCDEF0123456789") == 8) - && (! ptr[9])) + if ( ptr + && strspn (ptr + 1, "abcdefABCDEF0123456789") == 8 + && !ptr[9]) return TRUE; return FALSE; } @@ -100,19 +101,20 @@ utils_should_ignore_file (const char *filename, gboolean only_ifcfg) } char * -utils_cert_path (const char *parent, const char *suffix) +utils_cert_path (const char *parent, const char *suffix, const char *extension) { + gs_free char *dir = NULL; const char *name; - char *dir, *path; - g_return_val_if_fail (parent != NULL, NULL); - g_return_val_if_fail (suffix != NULL, NULL); + g_return_val_if_fail (parent, NULL); + g_return_val_if_fail (suffix, NULL); + g_return_val_if_fail (extension, NULL); name = utils_get_ifcfg_name (parent, FALSE); + g_return_val_if_fail (name, NULL); + dir = g_path_get_dirname (parent); - path = g_strdup_printf ("%s/%s-%s", dir, name, suffix); - g_free (dir); - return path; + return g_strdup_printf ("%s/%s-%s.%s", dir, name, suffix, extension); } const char * @@ -363,3 +365,117 @@ utils_detect_ifcfg_path (const char *path, gboolean only_ifcfg) return NULL; return utils_get_ifcfg_path (path); } + +void +nms_ifcfg_rh_utils_user_key_encode (const char *key, GString *str_buffer) +{ + gsize i; + + nm_assert (key); + nm_assert (str_buffer); + + for (i = 0; key[i]; i++) { + char ch = key[i]; + + /* we encode the key in only upper case letters, digits, and underscore. + * As we expect lower-case letters to be more common, we encode lower-case + * letters as upper case, and upper-case letters with a leading underscore. */ + + if (ch >= '0' && ch <= '9') { + g_string_append_c (str_buffer, ch); + continue; + } + if (ch >= 'a' && ch <= 'z') { + g_string_append_c (str_buffer, ch - 'a' + 'A'); + continue; + } + if (ch == '.') { + g_string_append (str_buffer, "__"); + continue; + } + if (ch >= 'A' && ch <= 'Z') { + g_string_append_c (str_buffer, '_'); + g_string_append_c (str_buffer, ch); + continue; + } + g_string_append_printf (str_buffer, "_%03o", (unsigned) ch); + } +} + +gboolean +nms_ifcfg_rh_utils_user_key_decode (const char *name, GString *str_buffer) +{ + gsize i; + + nm_assert (name); + nm_assert (str_buffer); + + if (!name[0]) + return FALSE; + + for (i = 0; name[i]; ) { + char ch = name[i]; + + if (ch >= '0' && ch <= '9') { + g_string_append_c (str_buffer, ch); + i++; + continue; + } + if (ch >= 'A' && ch <= 'Z') { + g_string_append_c (str_buffer, ch - 'A' + 'a'); + i++; + continue; + } + + if (ch == '_') { + ch = name[i + 1]; + if (ch == '_') { + g_string_append_c (str_buffer, '.'); + i += 2; + continue; + } + if (ch >= 'A' && ch <= 'Z') { + g_string_append_c (str_buffer, ch); + i += 2; + continue; + } + if (ch >= '0' && ch <= '7') { + char ch2, ch3; + unsigned v; + + ch2 = name[i + 2]; + if (!(ch2 >= '0' && ch2 <= '7')) + return FALSE; + + ch3 = name[i + 3]; + if (!(ch3 >= '0' && ch3 <= '7')) + return FALSE; + +#define OCTAL_VALUE(ch) ((unsigned) ((ch) - '0')) + v = (OCTAL_VALUE (ch) << 6) + + (OCTAL_VALUE (ch2) << 3) + + OCTAL_VALUE (ch3); + if ( v > 0xFF + || v == 0) + return FALSE; + ch = (char) v; + if ( (ch >= 'A' && ch <= 'Z') + || (ch >= '0' && ch <= '9') + || (ch == '.') + || (ch >= 'a' && ch <= 'z')) { + /* such characters are not expected to be encoded via + * octal representation. The encoding is invalid. */ + return FALSE; + } + g_string_append_c (str_buffer, ch); + i += 4; + continue; + } + return FALSE; + } + + return FALSE; + } + + return TRUE; +} diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index af0469e6..2b2c2755 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -31,7 +31,7 @@ #define NM_IFCFG_CONNECTION_LOG_FMTD "%s (%s,\"%s\",%p)" #define NM_IFCFG_CONNECTION_LOG_ARGD(con) NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con) -char *utils_cert_path (const char *parent, const char *suffix); +char *utils_cert_path (const char *parent, const char *suffix, const char *extension); const char *utils_get_ifcfg_name (const char *file, gboolean only_ifcfg); @@ -54,5 +54,7 @@ gboolean utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg); char *utils_detect_ifcfg_path (const char *path, gboolean only_ifcfg); -#endif /* _UTILS_H_ */ +void nms_ifcfg_rh_utils_user_key_encode (const char *key, GString *str_buffer); +gboolean nms_ifcfg_rh_utils_user_key_decode (const char *name, GString *str_buffer); +#endif /* _UTILS_H_ */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index fa8013b0..d6f33c49 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -42,11 +42,13 @@ #include "nm-setting-ip6-config.h" #include "nm-setting-pppoe.h" #include "nm-setting-vlan.h" +#include "nm-setting-user.h" #include "nm-setting-team.h" #include "nm-setting-team-port.h" #include "nm-utils.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" +#include "nm-setting-metadata.h" #include "nms-ifcfg-rh-common.h" #include "nms-ifcfg-rh-reader.h" @@ -59,7 +61,7 @@ #define _NMLOG_PREFIX_NAME "ifcfg-rh" #define _NMLOG(level, ...) \ G_STMT_START { \ - nm_log ((level), (_NMLOG_DOMAIN), \ + nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME": " \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ @@ -99,7 +101,7 @@ save_secret_flags (shvarFile *ifcfg, g_string_append (str, SECRET_FLAG_NOT_REQUIRED); } - svSetValueString (ifcfg, key, str->len ? str->str : NULL); + svSetValueStr (ifcfg, key, str->len ? str->str : NULL); g_string_free (str, TRUE); } @@ -127,7 +129,7 @@ set_secret (shvarFile *ifcfg, /* Only write the secret if it's system owned and supposed to be saved */ if (flags == NM_SETTING_SECRET_FLAG_NONE) - svSetValueString (keyfile, key, value); + svSetValueStr (keyfile, key, value); else svUnsetValue (keyfile, key); @@ -143,112 +145,70 @@ set_secret (shvarFile *ifcfg, error: /* Try setting the secret in the actual ifcfg */ - svSetValueString (ifcfg, key, value); + svSetValueStr (ifcfg, key, value); } -typedef struct ObjectType { - const char *setting_key; - NMSetting8021xCKScheme (*scheme_func)(NMSetting8021x *setting); - const char * (*path_func) (NMSetting8021x *setting); - GBytes * (*blob_func) (NMSetting8021x *setting); - const char *ifcfg_key; - const char *suffix; -} ObjectType; - -static const ObjectType ca_type = { - NM_SETTING_802_1X_CA_CERT, - nm_setting_802_1x_get_ca_cert_scheme, - nm_setting_802_1x_get_ca_cert_path, - nm_setting_802_1x_get_ca_cert_blob, - "IEEE_8021X_CA_CERT", - "ca-cert.der" -}; - -static const ObjectType phase2_ca_type = { - NM_SETTING_802_1X_PHASE2_CA_CERT, - nm_setting_802_1x_get_phase2_ca_cert_scheme, - nm_setting_802_1x_get_phase2_ca_cert_path, - nm_setting_802_1x_get_phase2_ca_cert_blob, - "IEEE_8021X_INNER_CA_CERT", - "inner-ca-cert.der" -}; - -static const ObjectType client_type = { - NM_SETTING_802_1X_CLIENT_CERT, - nm_setting_802_1x_get_client_cert_scheme, - nm_setting_802_1x_get_client_cert_path, - nm_setting_802_1x_get_client_cert_blob, - "IEEE_8021X_CLIENT_CERT", - "client-cert.der" -}; - -static const ObjectType phase2_client_type = { - NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - nm_setting_802_1x_get_phase2_client_cert_scheme, - nm_setting_802_1x_get_phase2_client_cert_path, - nm_setting_802_1x_get_phase2_client_cert_blob, - "IEEE_8021X_INNER_CLIENT_CERT", - "inner-client-cert.der" -}; - -static const ObjectType pk_type = { - NM_SETTING_802_1X_PRIVATE_KEY, - nm_setting_802_1x_get_private_key_scheme, - nm_setting_802_1x_get_private_key_path, - nm_setting_802_1x_get_private_key_blob, - "IEEE_8021X_PRIVATE_KEY", - "private-key.pem" -}; - -static const ObjectType phase2_pk_type = { - NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - nm_setting_802_1x_get_phase2_private_key_scheme, - nm_setting_802_1x_get_phase2_private_key_path, - nm_setting_802_1x_get_phase2_private_key_blob, - "IEEE_8021X_INNER_PRIVATE_KEY", - "inner-private-key.pem" -}; - -static const ObjectType p12_type = { - NM_SETTING_802_1X_PRIVATE_KEY, - nm_setting_802_1x_get_private_key_scheme, - nm_setting_802_1x_get_private_key_path, - nm_setting_802_1x_get_private_key_blob, - "IEEE_8021X_PRIVATE_KEY", - "private-key.p12" -}; - -static const ObjectType phase2_p12_type = { - NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - nm_setting_802_1x_get_phase2_private_key_scheme, - nm_setting_802_1x_get_phase2_private_key_path, - nm_setting_802_1x_get_phase2_private_key_blob, - "IEEE_8021X_INNER_PRIVATE_KEY", - "inner-private-key.p12" +typedef struct { + const NMSetting8021xSchemeVtable *vtable; + const char *ifcfg_rh_key; +} Setting8021xSchemeVtable; + +static const Setting8021xSchemeVtable setting_8021x_scheme_vtable[] = { + [NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT], + .ifcfg_rh_key = "IEEE_8021X_CA_CERT", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT], + .ifcfg_rh_key = "IEEE_8021X_INNER_CA_CERT", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT], + .ifcfg_rh_key = "IEEE_8021X_CLIENT_CERT", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT], + .ifcfg_rh_key = "IEEE_8021X_INNER_CLIENT_CERT", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY], + .ifcfg_rh_key = "IEEE_8021X_PRIVATE_KEY", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY], + .ifcfg_rh_key = "IEEE_8021X_INNER_PRIVATE_KEY", + }, }; static gboolean write_object (NMSetting8021x *s_8021x, shvarFile *ifcfg, - const ObjectType *objtype, + const Setting8021xSchemeVtable *objtype, GError **error) { NMSetting8021xCKScheme scheme; - const char *path = NULL; + const char *value = NULL; GBytes *blob = NULL; + const char *password = NULL; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + char *secret_name, *secret_flags; + const char *extension; g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (objtype != NULL, FALSE); - scheme = (*(objtype->scheme_func))(s_8021x); + scheme = (*(objtype->vtable->scheme_func))(s_8021x); switch (scheme) { case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: break; case NM_SETTING_802_1X_CK_SCHEME_BLOB: - blob = (*(objtype->blob_func))(s_8021x); + blob = (*(objtype->vtable->blob_func))(s_8021x); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: - path = (*(objtype->path_func))(s_8021x); + value = (*(objtype->vtable->path_func))(s_8021x); + break; + case NM_SETTING_802_1X_CK_SCHEME_PKCS11: + value = (*(objtype->vtable->uri_func))(s_8021x); break; default: g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -256,10 +216,26 @@ write_object (NMSetting8021x *s_8021x, return FALSE; } + /* Set the password for certificate/private key. */ + secret_name = g_strdup_printf ("%s_PASSWORD", objtype->ifcfg_rh_key); + secret_flags = g_strdup_printf ("%s_PASSWORD_FLAGS", objtype->ifcfg_rh_key); + password = (*(objtype->vtable->passwd_func))(s_8021x); + flags = (*(objtype->vtable->pwflag_func))(s_8021x); + set_secret (ifcfg, secret_name, password, secret_flags, flags); + g_free (secret_name); + g_free (secret_flags); + + if (!objtype->vtable->format_func) + extension = "der"; + else if (objtype->vtable->format_func (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) + extension = "p12"; + else + extension = "pem"; + /* If certificate/private key wasn't sent, the connection may no longer be * 802.1x and thus we clear out the paths and certs. */ - if (!path && !blob) { + if (!value && !blob) { char *standard_file; int ignored; @@ -269,20 +245,20 @@ write_object (NMSetting8021x *s_8021x, * /etc/sysconfig/network-scripts/ca-cert-Test_Write_Wifi_WPA_EAP-TLS.der * will be deleted, but /etc/pki/tls/cert.pem will not. */ - standard_file = utils_cert_path (svFileGetName (ifcfg), objtype->suffix); + standard_file = utils_cert_path (svFileGetName (ifcfg), objtype->vtable->file_suffix, extension); if (g_file_test (standard_file, G_FILE_TEST_EXISTS)) ignored = unlink (standard_file); g_free (standard_file); - svUnsetValue (ifcfg, objtype->ifcfg_key); + svUnsetValue (ifcfg, objtype->ifcfg_rh_key); return TRUE; } /* If the object path was specified, prefer that over any raw cert data that * may have been sent. */ - if (path) { - svSetValueString (ifcfg, objtype->ifcfg_key, path); + if (value) { + svSetValueStr (ifcfg, objtype->ifcfg_rh_key, value); return TRUE; } @@ -292,11 +268,11 @@ write_object (NMSetting8021x *s_8021x, char *new_file; GError *write_error = NULL; - new_file = utils_cert_path (svFileGetName (ifcfg), objtype->suffix); + new_file = utils_cert_path (svFileGetName (ifcfg), objtype->vtable->file_suffix, extension); if (!new_file) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Could not create file path for %s / %s", - NM_SETTING_802_1X_SETTING_NAME, objtype->setting_key); + NM_SETTING_802_1X_SETTING_NAME, objtype->vtable->setting_key); return FALSE; } @@ -310,13 +286,13 @@ write_object (NMSetting8021x *s_8021x, 0600, &write_error); if (success) { - svSetValueString (ifcfg, objtype->ifcfg_key, new_file); + svSetValueStr (ifcfg, objtype->ifcfg_rh_key, new_file); g_free (new_file); return TRUE; } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Could not write certificate/key for %s / %s: %s", - NM_SETTING_802_1X_SETTING_NAME, objtype->setting_key, + NM_SETTING_802_1X_SETTING_NAME, objtype->vtable->setting_key, (write_error && write_error->message) ? write_error->message : "(unknown)"); g_clear_error (&write_error); } @@ -332,71 +308,45 @@ write_8021x_certs (NMSetting8021x *s_8021x, shvarFile *ifcfg, GError **error) { - const char *password = NULL; - gboolean success = FALSE, is_pkcs12 = FALSE; - const ObjectType *otype = NULL; - NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + const Setting8021xSchemeVtable *otype = NULL; /* CA certificate */ - if (!write_object (s_8021x, ifcfg, phase2 ? &phase2_ca_type : &ca_type, error)) + if (!write_object (s_8021x, ifcfg, + phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT], + error)) return FALSE; /* Private key */ - if (phase2) { - otype = &phase2_pk_type; - if (nm_setting_802_1x_get_phase2_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { - otype = &phase2_p12_type; - is_pkcs12 = TRUE; - } - password = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); - flags = nm_setting_802_1x_get_phase2_private_key_password_flags (s_8021x); - } else { - otype = &pk_type; - if (nm_setting_802_1x_get_private_key_format (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { - otype = &p12_type; - is_pkcs12 = TRUE; - } - password = nm_setting_802_1x_get_private_key_password (s_8021x); - flags = nm_setting_802_1x_get_private_key_password_flags (s_8021x); - } + if (phase2) + otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY]; + else + otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY]; /* Save the private key */ if (!write_object (s_8021x, ifcfg, otype, error)) - goto out; - - /* Private key password */ - if (phase2) { - set_secret (ifcfg, - "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD", - password, - "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS", - flags); - } else { - set_secret (ifcfg, - "IEEE_8021X_PRIVATE_KEY_PASSWORD", - password, - "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS", - flags); - } + return FALSE; /* Client certificate */ - if (is_pkcs12) { + if (otype->vtable->format_func (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { /* Don't need a client certificate with PKCS#12 since the file is both * the client certificate and the private key in one file. */ - svSetValueString (ifcfg, - phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT", - NULL); + svSetValueStr (ifcfg, + phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT", + NULL); } else { /* Save the client certificate */ - if (!write_object (s_8021x, ifcfg, phase2 ? &phase2_client_type : &client_type, error)) - goto out; + if (!write_object (s_8021x, ifcfg, + phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT], + error)) + return FALSE; } - success = TRUE; - -out: - return success; + return TRUE; } static gboolean @@ -406,12 +356,13 @@ write_8021x_setting (NMConnection *connection, GError **error) { NMSetting8021x *s_8021x; + NMSetting8021xAuthFlags auth_flags; const char *value, *match; char *tmp = NULL; - gboolean success = FALSE; GString *phase2_auth; GString *str; guint32 i, num; + gint timeout; s_8021x = nm_connection_get_setting_802_1x (connection); if (!s_8021x) { @@ -423,7 +374,7 @@ write_8021x_setting (NMConnection *connection, /* If wired, write KEY_MGMT */ if (wired) - svSetValueString (ifcfg, "KEY_MGMT", "IEEE8021X"); + svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X"); /* EAP method */ if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) { @@ -431,14 +382,14 @@ write_8021x_setting (NMConnection *connection, if (value) tmp = g_ascii_strup (value, -1); } - svSetValueString (ifcfg, "IEEE_8021X_EAP_METHODS", tmp); + svSetValueStr (ifcfg, "IEEE_8021X_EAP_METHODS", tmp); g_free (tmp); - svSetValueString (ifcfg, "IEEE_8021X_IDENTITY", - nm_setting_802_1x_get_identity (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY", + nm_setting_802_1x_get_identity (s_8021x)); - svSetValueString (ifcfg, "IEEE_8021X_ANON_IDENTITY", - nm_setting_802_1x_get_anonymous_identity (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", + nm_setting_802_1x_get_anonymous_identity (s_8021x)); set_secret (ifcfg, "IEEE_8021X_PASSWORD", @@ -450,30 +401,30 @@ write_8021x_setting (NMConnection *connection, value = nm_setting_802_1x_get_phase1_peapver (s_8021x); svUnsetValue (ifcfg, "IEEE_8021X_PEAP_VERSION"); if (value && (!strcmp (value, "0") || !strcmp (value, "1"))) - svSetValueString (ifcfg, "IEEE_8021X_PEAP_VERSION", value); + svSetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", value); /* Force new PEAP label */ value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x); svUnsetValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL"); if (value && !strcmp (value, "1")) - svSetValueString (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", "yes"); + svSetValueStr (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", "yes"); /* PAC file */ value = nm_setting_802_1x_get_pac_file (s_8021x); svUnsetValue (ifcfg, "IEEE_8021X_PAC_FILE"); if (value) - svSetValueString (ifcfg, "IEEE_8021X_PAC_FILE", value); + svSetValueStr (ifcfg, "IEEE_8021X_PAC_FILE", value); /* FAST PAC provisioning */ value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x); svUnsetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING"); if (value) { if (strcmp (value, "1") == 0) - svSetValueString (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth"); + svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth"); else if (strcmp (value, "2") == 0) - svSetValueString (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-auth"); + svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-auth"); else if (strcmp (value, "3") == 0) - svSetValueString (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth allow-auth"); + svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth allow-auth"); } /* Phase2 auth methods */ @@ -497,16 +448,27 @@ write_8021x_setting (NMConnection *connection, g_free (tmp); } - svSetValueString (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", - phase2_auth->len ? phase2_auth->str : NULL); + auth_flags = nm_setting_802_1x_get_phase1_auth_flags (s_8021x); + if (auth_flags == NM_SETTING_802_1X_AUTH_FLAGS_NONE) { + svUnsetValue (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS"); + } else { + gs_free char *flags_str = NULL; + + flags_str = _nm_utils_enum_to_str_full (nm_setting_802_1x_auth_flags_get_type (), + auth_flags, " "); + svSetValueStr (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS", flags_str); + } + + svSetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", + phase2_auth->len ? phase2_auth->str : NULL); g_string_free (phase2_auth, TRUE); - svSetValueString (ifcfg, "IEEE_8021X_SUBJECT_MATCH", - nm_setting_802_1x_get_subject_match (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_SUBJECT_MATCH", + nm_setting_802_1x_get_subject_match (s_8021x)); - svSetValueString (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH", - nm_setting_802_1x_get_phase2_subject_match (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH", + nm_setting_802_1x_get_phase2_subject_match (s_8021x)); svUnsetValue (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES"); str = g_string_new (NULL); @@ -518,7 +480,7 @@ write_8021x_setting (NMConnection *connection, g_string_append (str, match); } if (str->len > 0) - svSetValueString (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", str->str); + svSetValueStr (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", str->str); g_string_free (str, TRUE); svUnsetValue (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES"); @@ -531,21 +493,28 @@ write_8021x_setting (NMConnection *connection, g_string_append (str, match); } if (str->len > 0) - svSetValueString (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", str->str); + svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", str->str); g_string_free (str, TRUE); - svSetValueString (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH", - nm_setting_802_1x_get_domain_suffix_match (s_8021x)); - svSetValueString (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH", - nm_setting_802_1x_get_phase2_domain_suffix_match (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH", + nm_setting_802_1x_get_domain_suffix_match (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH", + nm_setting_802_1x_get_phase2_domain_suffix_match (s_8021x)); - success = write_8021x_certs (s_8021x, FALSE, ifcfg, error); - if (success) { - /* phase2/inner certs */ - success = write_8021x_certs (s_8021x, TRUE, ifcfg, error); - } + timeout = nm_setting_802_1x_get_auth_timeout (s_8021x); + if (timeout > 0) + svSetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", timeout); + else + svUnsetValue (ifcfg, "IEEE_8021X_AUTH_TIMEOUT"); + + if (!write_8021x_certs (s_8021x, FALSE, ifcfg, error)) + return FALSE; - return success; + /* phase2/inner certs */ + if (!write_8021x_certs (s_8021x, TRUE, ifcfg, error)) + return FALSE; + + return TRUE; } static gboolean @@ -582,27 +551,27 @@ write_wireless_security_setting (NMConnection *connection, wep = TRUE; *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) { - svSetValueString (ifcfg, "KEY_MGMT", "WPA-PSK"); + svSetValueStr (ifcfg, "KEY_MGMT", "WPA-PSK"); wpa = TRUE; *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "ieee8021x")) { - svSetValueString (ifcfg, "KEY_MGMT", "IEEE8021X"); + svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X"); dynamic_wep = TRUE; } else if (!strcmp (key_mgmt, "wpa-eap")) { - svSetValueString (ifcfg, "KEY_MGMT", "WPA-EAP"); + svSetValueStr (ifcfg, "KEY_MGMT", "WPA-EAP"); wpa = TRUE; } svUnsetValue (ifcfg, "SECURITYMODE"); if (auth_alg) { if (!strcmp (auth_alg, "shared")) - svSetValueString (ifcfg, "SECURITYMODE", "restricted"); + svSetValueStr (ifcfg, "SECURITYMODE", "restricted"); else if (!strcmp (auth_alg, "open")) - svSetValueString (ifcfg, "SECURITYMODE", "open"); + svSetValueStr (ifcfg, "SECURITYMODE", "open"); else if (!strcmp (auth_alg, "leap")) { - svSetValueString (ifcfg, "SECURITYMODE", "leap"); - svSetValueString (ifcfg, "IEEE_8021X_IDENTITY", - nm_setting_wireless_security_get_leap_username (s_wsec)); + svSetValueStr (ifcfg, "SECURITYMODE", "leap"); + svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY", + nm_setting_wireless_security_get_leap_username (s_wsec)); set_secret (ifcfg, "IEEE_8021X_PASSWORD", nm_setting_wireless_security_get_leap_password (s_wsec), @@ -632,7 +601,7 @@ write_wireless_security_setting (NMConnection *connection, if (wep) { /* Default WEP TX key index */ tmp = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec) + 1); - svSetValueString (ifcfg, "DEFAULTKEY", tmp); + svSetValueStr (ifcfg, "DEFAULTKEY", tmp); g_free (tmp); for (i = 0; i < 4; i++) { @@ -688,9 +657,9 @@ write_wireless_security_setting (NMConnection *connection, for (i = 0; i < num; i++) { proto = nm_setting_wireless_security_get_proto (s_wsec, i); if (proto && !strcmp (proto, "wpa")) - svSetValueString (ifcfg, "WPA_ALLOW_WPA", "yes"); + svSetValueStr (ifcfg, "WPA_ALLOW_WPA", "yes"); else if (proto && !strcmp (proto, "rsn")) - svSetValueString (ifcfg, "WPA_ALLOW_WPA2", "yes"); + svSetValueStr (ifcfg, "WPA_ALLOW_WPA2", "yes"); } /* WPA Pairwise ciphers */ @@ -712,7 +681,7 @@ write_wireless_security_setting (NMConnection *connection, } } if (strlen (str->str) && (dynamic_wep == FALSE)) - svSetValueString (ifcfg, "CIPHER_PAIRWISE", str->str); + svSetValueStr (ifcfg, "CIPHER_PAIRWISE", str->str); g_string_free (str, TRUE); /* WPA Group ciphers */ @@ -728,7 +697,7 @@ write_wireless_security_setting (NMConnection *connection, g_free (tmp); } if (strlen (str->str) && (dynamic_wep == FALSE)) - svSetValueString (ifcfg, "CIPHER_GROUP", str->str); + svSetValueStr (ifcfg, "CIPHER_GROUP", str->str); g_string_free (str, TRUE); if (wpa) @@ -768,13 +737,13 @@ write_wireless_setting (NMConnection *connection, } device_mac = nm_setting_wireless_get_mac_address (s_wireless); - svSetValueString (ifcfg, "HWADDR", device_mac); + svSetValueStr (ifcfg, "HWADDR", device_mac); cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); - svSetValueString (ifcfg, "MACADDR", cloned_mac); + svSetValueStr (ifcfg, "MACADDR", cloned_mac); - svSetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK", - nm_setting_wireless_get_generate_mac_address_mask (s_wireless)); + svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK", + nm_setting_wireless_get_generate_mac_address_mask (s_wireless)); svUnsetValue (ifcfg, "HWADDR_BLACKLIST"); macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); @@ -782,7 +751,7 @@ write_wireless_setting (NMConnection *connection, char *blacklist_str; blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist); - svSetValueString (ifcfg, "HWADDR_BLACKLIST", blacklist_str); + svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str); g_free (blacklist_str); } @@ -790,7 +759,7 @@ write_wireless_setting (NMConnection *connection, mtu = nm_setting_wireless_get_mtu (s_wireless); if (mtu) { tmp = g_strdup_printf ("%u", mtu); - svSetValueString (ifcfg, "MTU", tmp); + svSetValueStr (ifcfg, "MTU", tmp); g_free (tmp); } @@ -838,7 +807,7 @@ write_wireless_setting (NMConnection *connection, g_string_append (str, "0x"); for (i = 0; i < ssid_len; i++) g_string_append_printf (str, "%02X", ssid_data[i]); - svSetValueString (ifcfg, "ESSID", str->str); + svSetValueStr (ifcfg, "ESSID", str->str); g_string_free (str, TRUE); } else { char buf[33]; @@ -846,17 +815,17 @@ write_wireless_setting (NMConnection *connection, nm_assert (ssid_len <= 32); memcpy (buf, ssid_data, ssid_len); buf[ssid_len] = '\0'; - svSetValueString (ifcfg, "ESSID", buf); + svSetValueStr (ifcfg, "ESSID", buf); } mode = nm_setting_wireless_get_mode (s_wireless); if (!mode || !strcmp (mode, "infrastructure")) { - svSetValueString (ifcfg, "MODE", "Managed"); + svSetValueStr (ifcfg, "MODE", "Managed"); } else if (!strcmp (mode, "adhoc")) { - svSetValueString (ifcfg, "MODE", "Ad-Hoc"); + svSetValueStr (ifcfg, "MODE", "Ad-Hoc"); adhoc = TRUE; } else if (!strcmp (mode, "ap")) { - svSetValueString (ifcfg, "MODE", "Ap"); + svSetValueStr (ifcfg, "MODE", "Ap"); } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Invalid mode '%s' in '%s' setting", @@ -869,15 +838,15 @@ write_wireless_setting (NMConnection *connection, chan = nm_setting_wireless_get_channel (s_wireless); if (chan) { tmp = g_strdup_printf ("%u", chan); - svSetValueString (ifcfg, "CHANNEL", tmp); + svSetValueStr (ifcfg, "CHANNEL", tmp); g_free (tmp); } else { /* Band only set if channel is not, since channel implies band */ - svSetValueString (ifcfg, "BAND", nm_setting_wireless_get_band (s_wireless)); + svSetValueStr (ifcfg, "BAND", nm_setting_wireless_get_band (s_wireless)); } bssid = nm_setting_wireless_get_bssid (s_wireless); - svSetValueString (ifcfg, "BSSID", bssid); + svSetValueStr (ifcfg, "BSSID", bssid); /* Ensure DEFAULTKEY and SECURITYMODE are cleared unless there's security; * otherwise there's no way to detect WEP vs. open when WEP keys aren't @@ -923,17 +892,17 @@ write_wireless_setting (NMConnection *connection, g_free (keys_path); } - svSetValueString (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL); + svSetValueStr (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL); switch (nm_setting_wireless_get_powersave (s_wireless)) { case NM_SETTING_WIRELESS_POWERSAVE_IGNORE: - svSetValueString (ifcfg, "POWERSAVE", "ignore"); + svSetValueStr (ifcfg, "POWERSAVE", "ignore"); break; case NM_SETTING_WIRELESS_POWERSAVE_DISABLE: - svSetValueString (ifcfg, "POWERSAVE", "disable"); + svSetValueStr (ifcfg, "POWERSAVE", "disable"); break; case NM_SETTING_WIRELESS_POWERSAVE_ENABLE: - svSetValueString (ifcfg, "POWERSAVE", "enable"); + svSetValueStr (ifcfg, "POWERSAVE", "enable"); break; default: case NM_SETTING_WIRELESS_POWERSAVE_DEFAULT: @@ -943,18 +912,18 @@ write_wireless_setting (NMConnection *connection, switch (nm_setting_wireless_get_mac_address_randomization (s_wireless)) { case NM_SETTING_MAC_RANDOMIZATION_NEVER: - svSetValueString (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "never"); + svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "never"); break; case NM_SETTING_MAC_RANDOMIZATION_ALWAYS: - svSetValueString (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "always"); + svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "always"); break; case NM_SETTING_MAC_RANDOMIZATION_DEFAULT: default: - svSetValueString (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "default"); + svSetValueStr (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "default"); break; } - svSetValueString (ifcfg, "TYPE", TYPE_WIRELESS); + svSetValueStr (ifcfg, "TYPE", TYPE_WIRELESS); return TRUE; } @@ -976,13 +945,13 @@ write_infiniband_setting (NMConnection *connection, shvarFile *ifcfg, GError **e } mac = nm_setting_infiniband_get_mac_address (s_infiniband); - svSetValueString (ifcfg, "HWADDR", mac); + svSetValueStr (ifcfg, "HWADDR", mac); svUnsetValue (ifcfg, "MTU"); mtu = nm_setting_infiniband_get_mtu (s_infiniband); if (mtu) { tmp = g_strdup_printf ("%u", mtu); - svSetValueString (ifcfg, "MTU", tmp); + svSetValueStr (ifcfg, "MTU", tmp); g_free (tmp); } @@ -991,17 +960,17 @@ write_infiniband_setting (NMConnection *connection, shvarFile *ifcfg, GError **e p_key = nm_setting_infiniband_get_p_key (s_infiniband); if (p_key != -1) { - svSetValueString (ifcfg, "PKEY", "yes"); + svSetValueStr (ifcfg, "PKEY", "yes"); tmp = g_strdup_printf ("%u", p_key); - svSetValueString (ifcfg, "PKEY_ID", tmp); + svSetValueStr (ifcfg, "PKEY_ID", tmp); g_free (tmp); parent = nm_setting_infiniband_get_parent (s_infiniband); if (parent) - svSetValueString (ifcfg, "PHYSDEV", parent); + svSetValueStr (ifcfg, "PHYSDEV", parent); } - svSetValueString (ifcfg, "TYPE", TYPE_INFINIBAND); + svSetValueStr (ifcfg, "TYPE", TYPE_INFINIBAND); return TRUE; } @@ -1029,13 +998,13 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) } device_mac = nm_setting_wired_get_mac_address (s_wired); - svSetValueString (ifcfg, "HWADDR", device_mac); + svSetValueStr (ifcfg, "HWADDR", device_mac); cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); - svSetValueString (ifcfg, "MACADDR", cloned_mac); + svSetValueStr (ifcfg, "MACADDR", cloned_mac); - svSetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK", - nm_setting_wired_get_generate_mac_address_mask (s_wired)); + svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK", + nm_setting_wired_get_generate_mac_address_mask (s_wired)); svUnsetValue (ifcfg, "HWADDR_BLACKLIST"); macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); @@ -1043,7 +1012,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) char *blacklist_str; blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist); - svSetValueString (ifcfg, "HWADDR_BLACKLIST", blacklist_str); + svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str); g_free (blacklist_str); } @@ -1051,7 +1020,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) mtu = nm_setting_wired_get_mtu (s_wired); if (mtu) { tmp = g_strdup_printf ("%u", mtu); - svSetValueString (ifcfg, "MTU", tmp); + svSetValueStr (ifcfg, "MTU", tmp); g_free (tmp); } @@ -1061,30 +1030,30 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) int len = g_strv_length ((char **)s390_subchannels); tmp = NULL; - if (len == 2) { - tmp = g_strdup_printf ("%s,%s", s390_subchannels[0], s390_subchannels[1]); - } else if (len == 3) { - tmp = g_strdup_printf ("%s,%s,%s", s390_subchannels[0], s390_subchannels[1], - s390_subchannels[2]); + if (len == 2) { + tmp = g_strdup_printf ("%s,%s", s390_subchannels[0], s390_subchannels[1]); + } else if (len == 3) { + tmp = g_strdup_printf ("%s,%s,%s", s390_subchannels[0], s390_subchannels[1], + s390_subchannels[2]); } - svSetValueString (ifcfg, "SUBCHANNELS", tmp); + svSetValueStr (ifcfg, "SUBCHANNELS", tmp); g_free (tmp); } svUnsetValue (ifcfg, "NETTYPE"); nettype = nm_setting_wired_get_s390_nettype (s_wired); if (nettype) - svSetValueString (ifcfg, "NETTYPE", nettype); + svSetValueStr (ifcfg, "NETTYPE", nettype); svUnsetValue (ifcfg, "PORTNAME"); portname = nm_setting_wired_get_s390_option_by_key (s_wired, "portname"); if (portname) - svSetValueString (ifcfg, "PORTNAME", portname); + svSetValueStr (ifcfg, "PORTNAME", portname); svUnsetValue (ifcfg, "CTCPROT"); ctcprot = nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot"); if (ctcprot) - svSetValueString (ifcfg, "CTCPROT", ctcprot); + svSetValueStr (ifcfg, "CTCPROT", ctcprot); svUnsetValue (ifcfg, "OPTIONS"); num_opts = nm_setting_wired_get_num_s390_options (s_wired); @@ -1102,7 +1071,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_string_append_printf (str, "%s=%s", s390_key, s390_val); } if (str->len) - svSetValueString (ifcfg, "OPTIONS", str->str); + svSetValueStr (ifcfg, "OPTIONS", str->str); g_string_free (str, TRUE); } @@ -1166,12 +1135,12 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_string_append_printf (str, "s sopass %s", wol_password); } if (str) { - svSetValueString (ifcfg, "ETHTOOL_OPTS", str->str); + svSetValueStr (ifcfg, "ETHTOOL_OPTS", str->str); g_string_free (str, TRUE); } /* End ETHTOOL_OPT stuffing */ - svSetValueString (ifcfg, "TYPE", TYPE_ETHERNET); + svSetValueStr (ifcfg, "TYPE", TYPE_ETHERNET); return TRUE; } @@ -1213,18 +1182,18 @@ write_wired_for_virtual (NMConnection *connection, shvarFile *ifcfg) has_wired = TRUE; device_mac = nm_setting_wired_get_mac_address (s_wired); - svSetValueString (ifcfg, "HWADDR", device_mac); + svSetValueStr (ifcfg, "HWADDR", device_mac); cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); - svSetValueString (ifcfg, "MACADDR", cloned_mac); + svSetValueStr (ifcfg, "MACADDR", cloned_mac); - svSetValueString (ifcfg, "GENERATE_MAC_ADDRESS_MASK", - nm_setting_wired_get_generate_mac_address_mask (s_wired)); + svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK", + nm_setting_wired_get_generate_mac_address_mask (s_wired)); mtu = nm_setting_wired_get_mtu (s_wired); if (mtu) { tmp = g_strdup_printf ("%u", mtu); - svSetValueString (ifcfg, "MTU", tmp); + svSetValueStr (ifcfg, "MTU", tmp); g_free (tmp); } else svUnsetValue (ifcfg, "MTU"); @@ -1256,13 +1225,13 @@ write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, return FALSE; } - svSetValueString (ifcfg, "VLAN", "yes"); - svSetValueString (ifcfg, "TYPE", TYPE_VLAN); - svSetValueString (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con)); - svSetValueString (ifcfg, "PHYSDEV", nm_setting_vlan_get_parent (s_vlan)); + svSetValueStr (ifcfg, "VLAN", "yes"); + svSetValueStr (ifcfg, "TYPE", TYPE_VLAN); + svSetValueStr (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con)); + svSetValueStr (ifcfg, "PHYSDEV", nm_setting_vlan_get_parent (s_vlan)); tmp = g_strdup_printf ("%d", nm_setting_vlan_get_id (s_vlan)); - svSetValueString (ifcfg, "VLAN_ID", tmp); + svSetValueStr (ifcfg, "VLAN_ID", tmp); g_free (tmp); vlan_flags = nm_setting_vlan_get_flags (s_vlan); @@ -1276,16 +1245,16 @@ write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, if (!NM_FLAGS_HAS (vlan_flags, NM_VLAN_FLAG_REORDER_HEADERS)) nm_utils_strbuf_append (&s_buf_ptr, &s_buf_len, "%sNO_REORDER_HDR", s_buf[0] ? "," : ""); - svSetValueString (ifcfg, "VLAN_FLAGS", s_buf); + svSetValueStr (ifcfg, "VLAN_FLAGS", s_buf); svSetValueBoolean (ifcfg, "MVRP", NM_FLAGS_HAS (vlan_flags, NM_VLAN_FLAG_MVRP)); tmp = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_INGRESS_MAP); - svSetValueString (ifcfg, "VLAN_INGRESS_PRIORITY_MAP", tmp); + svSetValueStr (ifcfg, "VLAN_INGRESS_PRIORITY_MAP", tmp); g_free (tmp); tmp = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_EGRESS_MAP); - svSetValueString (ifcfg, "VLAN_EGRESS_PRIORITY_MAP", tmp); + svSetValueStr (ifcfg, "VLAN_EGRESS_PRIORITY_MAP", tmp); g_free (tmp); svUnsetValue (ifcfg, "HWADDR"); @@ -1318,7 +1287,7 @@ write_bonding_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wir return FALSE; } - svSetValueString (ifcfg, "DEVICE", iface); + svSetValueStr (ifcfg, "DEVICE", iface); svUnsetValue (ifcfg, "BONDING_OPTS"); num_opts = nm_setting_bond_get_num_options (s_bond); @@ -1338,13 +1307,13 @@ write_bonding_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wir } if (str->len) - svSetValueString (ifcfg, "BONDING_OPTS", str->str); + svSetValueStr (ifcfg, "BONDING_OPTS", str->str); g_string_free (str, TRUE); } - svSetValueString (ifcfg, "TYPE", TYPE_BOND); - svSetValueString (ifcfg, "BONDING_MASTER", "yes"); + svSetValueStr (ifcfg, "TYPE", TYPE_BOND); + svSetValueStr (ifcfg, "BONDING_MASTER", "yes"); *wired = write_wired_for_virtual (connection, ifcfg); @@ -1372,9 +1341,9 @@ write_team_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, return FALSE; } - svSetValueString (ifcfg, "DEVICE", iface); + svSetValueStr (ifcfg, "DEVICE", iface); config = nm_setting_team_get_config (s_team); - svSetValueString (ifcfg, "TEAM_CONFIG", config); + svSetValueStr (ifcfg, "TEAM_CONFIG", config); *wired = write_wired_for_virtual (connection, ifcfg); @@ -1440,24 +1409,24 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error return FALSE; } - svSetValueString (ifcfg, "DEVICE", iface); + svSetValueStr (ifcfg, "DEVICE", iface); svUnsetValue (ifcfg, "BRIDGING_OPTS"); svSetValueBoolean (ifcfg, "STP", FALSE); svUnsetValue (ifcfg, "DELAY"); mac = nm_setting_bridge_get_mac_address (s_bridge); - svSetValueString (ifcfg, "MACADDR", mac); + svSetValueStr (ifcfg, "MACADDR", mac); /* Bridge options */ opts = g_string_sized_new (32); if (nm_setting_bridge_get_stp (s_bridge)) { - svSetValueString (ifcfg, "STP", "yes"); + svSetValueStr (ifcfg, "STP", "yes"); i = nm_setting_bridge_get_forward_delay (s_bridge); if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY)) { s = g_strdup_printf ("%u", i); - svSetValueString (ifcfg, "DELAY", s); + svSetValueStr (ifcfg, "DELAY", s); g_free (s); } @@ -1493,10 +1462,10 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error } if (opts->len) - svSetValueString (ifcfg, "BRIDGING_OPTS", opts->str); + svSetValueStr (ifcfg, "BRIDGING_OPTS", opts->str); g_string_free (opts, TRUE); - svSetValueString (ifcfg, "TYPE", TYPE_BRIDGE); + svSetValueStr (ifcfg, "TYPE", TYPE_BRIDGE); return TRUE; } @@ -1535,7 +1504,7 @@ write_bridge_port_setting (NMConnection *connection, shvarFile *ifcfg, GError ** } if (opts->len) - svSetValueString (ifcfg, "BRIDGING_OPTS", opts->str); + svSetValueStr (ifcfg, "BRIDGING_OPTS", opts->str); g_string_free (opts, TRUE); return TRUE; @@ -1552,7 +1521,7 @@ write_team_port_setting (NMConnection *connection, shvarFile *ifcfg, GError **er return TRUE; config = nm_setting_team_port_get_config (s_port); - svSetValueString (ifcfg, "TEAM_PORT_CONFIG", config); + svSetValueStr (ifcfg, "TEAM_PORT_CONFIG", config); return TRUE; } @@ -1563,13 +1532,13 @@ write_dcb_flags (shvarFile *ifcfg, const char *tag, NMSettingDcbFlags flags) char prop[NM_STRLEN ("DCB_xxxxxxxxxxxxxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyy")]; nm_sprintf_buf (prop, "DCB_%s_ENABLE", tag); - svSetValueString (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ENABLE) ? "yes" : NULL); + svSetValueStr (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ENABLE) ? "yes" : NULL); nm_sprintf_buf (prop, "DCB_%s_ADVERTISE", tag); - svSetValueString (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ADVERTISE) ? "yes" : NULL); + svSetValueStr (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ADVERTISE) ? "yes" : NULL); nm_sprintf_buf (prop, "DCB_%s_WILLING", tag); - svSetValueString (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_WILLING) ? "yes" : NULL); + svSetValueStr (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_WILLING) ? "yes" : NULL); } static void @@ -1609,7 +1578,7 @@ write_dcb_bool_array (shvarFile *ifcfg, str[8] = 0; for (i = 0; i < 8; i++) str[i] = get_func (s_dcb, i) ? '1' : '0'; - svSetValueString (ifcfg, key, str); + svSetValueStr (ifcfg, key, str); } typedef guint (*DcbGetUintFunc) (NMSettingDcb *, guint); @@ -1639,7 +1608,7 @@ write_dcb_uint_array (shvarFile *ifcfg, else g_assert_not_reached (); } - svSetValueString (ifcfg, key, str); + svSetValueStr (ifcfg, key, str); } static void @@ -1663,7 +1632,7 @@ write_dcb_percent_array (shvarFile *ifcfg, g_string_append_c (str, ','); g_string_append_printf (str, "%d", get_func (s_dcb, i)); } - svSetValueString (ifcfg, key, str->str); + svSetValueStr (ifcfg, key, str->str); g_string_free (str, TRUE); } @@ -1707,13 +1676,13 @@ write_dcb_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) return TRUE; } - svSetValueString (ifcfg, "DCB", "yes"); + svSetValueStr (ifcfg, "DCB", "yes"); write_dcb_app (ifcfg, "APP_FCOE", nm_setting_dcb_get_app_fcoe_flags (s_dcb), nm_setting_dcb_get_app_fcoe_priority (s_dcb)); if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) - svSetValueString (ifcfg, KEY_DCB_APP_FCOE_MODE, nm_setting_dcb_get_app_fcoe_mode (s_dcb)); + svSetValueStr (ifcfg, KEY_DCB_APP_FCOE_MODE, nm_setting_dcb_get_app_fcoe_mode (s_dcb)); else svUnsetValue (ifcfg, KEY_DCB_APP_FCOE_MODE); @@ -1749,21 +1718,21 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) char *tmp; gint i_int; - svSetValueString (ifcfg, "NAME", nm_setting_connection_get_id (s_con)); - svSetValueString (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con)); - svSetValueString (ifcfg, "STABLE_ID", nm_setting_connection_get_stable_id (s_con)); - svSetValueString (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con)); + svSetValueStr (ifcfg, "NAME", nm_setting_connection_get_id (s_con)); + svSetValueStr (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con)); + svSetValueStr (ifcfg, "STABLE_ID", nm_setting_connection_get_stable_id (s_con)); + svSetValueStr (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con)); svSetValueBoolean (ifcfg, "ONBOOT", nm_setting_connection_get_autoconnect (s_con)); i_int = nm_setting_connection_get_autoconnect_priority (s_con); tmp = i_int != NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT ? g_strdup_printf ("%d", i_int) : NULL; - svSetValueString (ifcfg, "AUTOCONNECT_PRIORITY", tmp); + svSetValueStr (ifcfg, "AUTOCONNECT_PRIORITY", tmp); g_free (tmp); i_int = nm_setting_connection_get_autoconnect_retries (s_con); tmp = i_int != -1 ? g_strdup_printf ("%d", i_int) : NULL; - svSetValueString (ifcfg, "AUTOCONNECT_RETRIES", tmp); + svSetValueStr (ifcfg, "AUTOCONNECT_RETRIES", tmp); g_free (tmp); /* Only save the value for master connections */ @@ -1773,9 +1742,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) || !g_strcmp0 (type, NM_SETTING_BRIDGE_SETTING_NAME)) { NMSettingConnectionAutoconnectSlaves autoconnect_slaves; autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con); - svSetValueString (ifcfg, "AUTOCONNECT_SLAVES", - autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES ? "yes" : - autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO ? "no" : NULL); + svSetValueStr (ifcfg, "AUTOCONNECT_SLAVES", + autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES ? "yes" : + autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO ? "no" : NULL); } else svUnsetValue (ifcfg, "AUTOCONNECT_SLAVES"); @@ -1789,7 +1758,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) default: tmp = NULL; } - svSetValueString (ifcfg, "LLDP", tmp); + svSetValueStr (ifcfg, "LLDP", tmp); /* Permissions */ svUnsetValue (ifcfg, "USERS"); @@ -1809,19 +1778,19 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL)) g_string_append (str, puser); } - svSetValueString (ifcfg, "USERS", str->str); + svSetValueStr (ifcfg, "USERS", str->str); g_string_free (str, TRUE); } - svSetValueString (ifcfg, "ZONE", nm_setting_connection_get_zone(s_con)); + svSetValueStr (ifcfg, "ZONE", nm_setting_connection_get_zone (s_con)); - svSetValueString (ifcfg, "MASTER_UUID", NULL); - svSetValueString (ifcfg, "MASTER", NULL); - svSetValueString (ifcfg, "SLAVE", NULL); - svSetValueString (ifcfg, "BRIDGE_UUID", NULL); - svSetValueString (ifcfg, "BRIDGE", NULL); - svSetValueString (ifcfg, "TEAM_MASTER_UUID", NULL); - svSetValueString (ifcfg, "TEAM_MASTER", NULL); + svSetValueStr (ifcfg, "MASTER_UUID", NULL); + svSetValueStr (ifcfg, "MASTER", NULL); + svSetValueStr (ifcfg, "SLAVE", NULL); + svSetValueStr (ifcfg, "BRIDGE_UUID", NULL); + svSetValueStr (ifcfg, "BRIDGE", NULL); + svSetValueStr (ifcfg, "TEAM_MASTER_UUID", NULL); + svSetValueStr (ifcfg, "TEAM_MASTER", NULL); master = nm_setting_connection_get_master (s_con); if (master) { @@ -1838,23 +1807,23 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) } if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BOND_SETTING_NAME)) { - svSetValueString (ifcfg, "MASTER_UUID", master); - svSetValueString (ifcfg, "MASTER", master_iface); - svSetValueString (ifcfg, "SLAVE", "yes"); + svSetValueStr (ifcfg, "MASTER_UUID", master); + svSetValueStr (ifcfg, "MASTER", master_iface); + svSetValueStr (ifcfg, "SLAVE", "yes"); } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME)) { - svSetValueString (ifcfg, "BRIDGE_UUID", master); - svSetValueString (ifcfg, "BRIDGE", master_iface); + svSetValueStr (ifcfg, "BRIDGE_UUID", master); + svSetValueStr (ifcfg, "BRIDGE", master_iface); } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) { - svSetValueString (ifcfg, "TEAM_MASTER_UUID", master); - svSetValueString (ifcfg, "TEAM_MASTER", master_iface); + svSetValueStr (ifcfg, "TEAM_MASTER_UUID", master); + svSetValueStr (ifcfg, "TEAM_MASTER", master_iface); svUnsetValue (ifcfg, "TYPE"); } } if (nm_streq0 (type, NM_SETTING_TEAM_SETTING_NAME)) - svSetValueString (ifcfg, "DEVICETYPE", TYPE_TEAM); + svSetValueStr (ifcfg, "DEVICETYPE", TYPE_TEAM); else if (master_iface && nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) - svSetValueString (ifcfg, "DEVICETYPE", TYPE_TEAM_PORT); + svSetValueStr (ifcfg, "DEVICETYPE", TYPE_TEAM_PORT); else svUnsetValue (ifcfg, "DEVICETYPE"); @@ -1876,40 +1845,94 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) if ((uuid = nm_setting_connection_get_secondary (s_con, i)) != NULL) g_string_append (str, uuid); } - svSetValueString (ifcfg, "SECONDARY_UUIDS", str->str); + svSetValueStr (ifcfg, "SECONDARY_UUIDS", str->str); g_string_free (str, TRUE); } svUnsetValue (ifcfg, "GATEWAY_PING_TIMEOUT"); if (nm_setting_connection_get_gateway_ping_timeout (s_con)) { tmp = g_strdup_printf ("%" G_GUINT32_FORMAT, nm_setting_connection_get_gateway_ping_timeout (s_con)); - svSetValueString (ifcfg, "GATEWAY_PING_TIMEOUT", tmp); + svSetValueStr (ifcfg, "GATEWAY_PING_TIMEOUT", tmp); g_free (tmp); } switch (nm_setting_connection_get_metered (s_con)) { case NM_METERED_YES: - svSetValueString (ifcfg, "CONNECTION_METERED", "yes"); + svSetValueStr (ifcfg, "CONNECTION_METERED", "yes"); break; case NM_METERED_NO: - svSetValueString (ifcfg, "CONNECTION_METERED", "no"); + svSetValueStr (ifcfg, "CONNECTION_METERED", "no"); break; default: svUnsetValue (ifcfg, "CONNECTION_METERED"); } } +static char * +get_route_attributes_string (NMIPRoute *route, int family) +{ + gs_strfreev char **names = NULL; + GVariant *attr, *lock; + GString *str; + int i; + + names = nm_ip_route_get_attribute_names (route); + if (!names || !names[0]) + return NULL; + + str = g_string_new (""); + + for (i = 0; names[i]; i++) { + attr = nm_ip_route_get_attribute (route, names[i]); + + if (!nm_ip_route_attribute_validate (names[i], attr, family, NULL, NULL)) + continue; + + if (NM_IN_STRSET (names[i], NM_IP_ROUTE_ATTRIBUTE_WINDOW, + NM_IP_ROUTE_ATTRIBUTE_CWND, + NM_IP_ROUTE_ATTRIBUTE_INITCWND, + NM_IP_ROUTE_ATTRIBUTE_INITRWND, + NM_IP_ROUTE_ATTRIBUTE_MTU)) { + char lock_name[256]; + + nm_sprintf_buf (lock_name, "lock-%s", names[i]); + lock = nm_ip_route_get_attribute (route, lock_name); + + g_string_append_printf (str, + "%s %s%u", + names[i], + (lock && g_variant_get_boolean (lock)) ? "lock " : "", + g_variant_get_uint32 (attr)); + } else if (strstr (names[i], "lock-")) { + /* handled above */ + } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) { + g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_byte (attr)); + } else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) + || nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_FROM)) { + char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) ? "src" : "from"; + + g_string_append_printf (str, "%s %s", arg, g_variant_get_string (attr, NULL)); + } else { + _LOGW ("unknown route option '%s'", names[i]); + continue; + } + if (names[i + 1]) + g_string_append_c (str, ' '); + } + + return g_string_free (str, FALSE); +} + static gboolean write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error) { const char *dest, *next_hop; char **route_items; - char *route_contents; + gs_free char *route_contents = NULL; NMIPRoute *route; guint32 prefix; gint64 metric; guint32 i, num; - gboolean success = FALSE; g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip4 != NULL, FALSE); @@ -1922,8 +1945,10 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError return TRUE; } - route_items = g_malloc0 (sizeof (char*) * (num + 1)); + route_items = g_malloc0 (sizeof (char *) * (num + 1)); for (i = 0; i < num; i++) { + gs_free char *options = NULL; + route = nm_setting_ip_config_get_route (s_ip4, i); dest = nm_ip_route_get_dest (route); @@ -1931,10 +1956,19 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError next_hop = nm_ip_route_get_next_hop (route); metric = nm_ip_route_get_metric (route); - if (metric == -1) - route_items[i] = g_strdup_printf ("%s/%u via %s\n", dest, prefix, next_hop); - else - route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, (guint32) metric); + options = get_route_attributes_string (route, AF_INET); + + if (metric == -1) { + route_items[i] = g_strdup_printf ("%s/%u via %s%s%s\n", + dest, prefix, next_hop, + options ? " " : "", + options ?: ""); + } else { + route_items[i] = g_strdup_printf ("%s/%u via %s metric %u%s%s\n", + dest, prefix, next_hop, (guint32) metric, + options ? " " : "", + options ?: ""); + } } route_items[num] = NULL; route_contents = g_strjoinv (NULL, route_items); @@ -1943,15 +1977,10 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError if (!g_file_set_contents (filename, route_contents, -1, NULL)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Writing route file '%s' failed", filename); - goto error; + return FALSE; } - success = TRUE; - -error: - g_free (route_contents); - - return success; + return TRUE; } static gboolean @@ -1972,19 +2001,19 @@ write_proxy_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) method = nm_setting_proxy_get_method (s_proxy); switch (method) { case NM_SETTING_PROXY_METHOD_AUTO: - svSetValueString (ifcfg, "PROXY_METHOD", "auto"); + svSetValueStr (ifcfg, "PROXY_METHOD", "auto"); pac_url = nm_setting_proxy_get_pac_url (s_proxy); if (pac_url) - svSetValueString (ifcfg, "PAC_URL", pac_url); + svSetValueStr (ifcfg, "PAC_URL", pac_url); pac_script = nm_setting_proxy_get_pac_script (s_proxy); if (pac_script) - svSetValueString (ifcfg, "PAC_SCRIPT", pac_script); + svSetValueStr (ifcfg, "PAC_SCRIPT", pac_script); break; case NM_SETTING_PROXY_METHOD_NONE: - svSetValueString (ifcfg, "PROXY_METHOD", "none"); + svSetValueStr (ifcfg, "PROXY_METHOD", "none"); break; } @@ -1994,14 +2023,51 @@ write_proxy_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) } static gboolean +write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingUser *s_user; + guint i, len; + const char *const*keys; + + s_user = NM_SETTING_USER (nm_connection_get_setting (connection, NM_TYPE_SETTING_USER)); + + svUnsetValuesWithPrefix (ifcfg, "NM_USER_"); + + if (!s_user) + return TRUE; + + keys = nm_setting_user_get_keys (s_user, &len); + if (len) { + nm_auto_free_gstring GString *str = g_string_sized_new (100); + + for (i = 0; i < len; i++) { + const char *key = keys[i]; + + g_string_set_size (str, 0); + g_string_append (str, "NM_USER_"); + nms_ifcfg_rh_utils_user_key_encode (key, str); + svSetValue (ifcfg, + str->str, + nm_setting_user_get_data (s_user, key)); + } + } + + return TRUE; +} + +static gboolean write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingIPConfig *s_ip4; const char *value; - char *addr_key, *prefix_key, *netmask_key, *gw_key, *metric_key, *tmp; + char *tmp; + char addr_key[64]; + char prefix_key[64]; + char netmask_key[64]; + char gw_key[64]; char *route_path = NULL; - gint32 j; - guint32 i, n, num; + gint j; + guint i, num, n; gint64 route_metric; gint priority; int timeout; @@ -2041,26 +2107,21 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svUnsetValue (ifcfg, "BOOTPROTO"); for (j = -1; j < 256; j++) { if (j == -1) { - addr_key = g_strdup ("IPADDR"); - prefix_key = g_strdup ("PREFIX"); - netmask_key = g_strdup ("NETMASK"); - gw_key = g_strdup ("GATEWAY"); + nm_sprintf_buf (addr_key, "IPADDR"); + nm_sprintf_buf (prefix_key, "PREFIX"); + nm_sprintf_buf (netmask_key, "NETMASK"); + nm_sprintf_buf (gw_key, "GATEWAY"); } else { - addr_key = g_strdup_printf ("IPADDR%d", j); - prefix_key = g_strdup_printf ("PREFIX%d", j); - netmask_key = g_strdup_printf ("NETMASK%d", j); - gw_key = g_strdup_printf ("GATEWAY%d", j); + nm_sprintf_buf (addr_key, "IPADDR%d", (guint) j); + nm_sprintf_buf (prefix_key, "PREFIX%u", (guint) j); + nm_sprintf_buf (netmask_key, "NETMASK%u", (guint) j); + nm_sprintf_buf (gw_key, "GATEWAY%u", (guint) j); } svUnsetValue (ifcfg, addr_key); svUnsetValue (ifcfg, prefix_key); svUnsetValue (ifcfg, netmask_key); svUnsetValue (ifcfg, gw_key); - - g_free (addr_key); - g_free (prefix_key); - g_free (netmask_key); - g_free (gw_key); } route_path = utils_get_route_path (svFileGetName (ifcfg)); @@ -2069,14 +2130,20 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) return TRUE; } + num = nm_setting_ip_config_get_num_addresses (s_ip4); + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) - svSetValueString (ifcfg, "BOOTPROTO", "dhcp"); - else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - svSetValueString (ifcfg, "BOOTPROTO", "none"); - else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) - svSetValueString (ifcfg, "BOOTPROTO", "autoip"); + svSetValueStr (ifcfg, "BOOTPROTO", "dhcp"); + else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + /* Preserve the archaic form of "static" if there actually + * is static configuration. */ + if (g_strcmp0 (svGetValue (ifcfg, "BOOTPROTO", &tmp), "static") || !num) + svSetValueStr (ifcfg, "BOOTPROTO", "none"); + g_free (tmp); + } else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) + svSetValueStr (ifcfg, "BOOTPROTO", "autoip"); else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) - svSetValueString (ifcfg, "BOOTPROTO", "shared"); + svSetValueStr (ifcfg, "BOOTPROTO", "shared"); /* Clear out un-numbered IP address fields */ svUnsetValue (ifcfg, "IPADDR"); @@ -2092,9 +2159,9 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) /* Write out IPADDR<n>, PREFIX<n>, GATEWAY<n> for current IP addresses * without labels. Unset obsolete NETMASK<n>. */ - num = nm_setting_ip_config_get_num_addresses (s_ip4); for (i = n = 0; i < num; i++) { NMIPAddress *addr; + guint prefix; addr = nm_setting_ip_config_get_address (s_ip4, i); @@ -2112,66 +2179,62 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) * See https://bugzilla.redhat.com/show_bug.cgi?id=771673 * and https://bugzilla.redhat.com/show_bug.cgi?id=1105770 */ - addr_key = g_strdup ("IPADDR"); - prefix_key = g_strdup ("PREFIX"); - netmask_key = g_strdup ("NETMASK"); - gw_key = g_strdup ("GATEWAY"); + nm_sprintf_buf (addr_key, "IPADDR"); + nm_sprintf_buf (prefix_key, "PREFIX"); + nm_sprintf_buf (netmask_key, "NETMASK"); + nm_sprintf_buf (gw_key, "GATEWAY"); } else { - addr_key = g_strdup_printf ("IPADDR%d", n); - prefix_key = g_strdup_printf ("PREFIX%d", n); - netmask_key = g_strdup_printf ("NETMASK%d", n); - gw_key = g_strdup_printf ("GATEWAY%d", n); + nm_sprintf_buf (addr_key, "IPADDR%u", n); + nm_sprintf_buf (prefix_key, "PREFIX%u", n); + nm_sprintf_buf (netmask_key, "NETMASK%u", n); + nm_sprintf_buf (gw_key, "GATEWAY%u", n); } - svSetValueString (ifcfg, addr_key, nm_ip_address_get_address (addr)); + svSetValueStr (ifcfg, addr_key, nm_ip_address_get_address (addr)); - tmp = g_strdup_printf ("%u", nm_ip_address_get_prefix (addr)); - svSetValueString (ifcfg, prefix_key, tmp); + prefix = nm_ip_address_get_prefix (addr); + tmp = g_strdup_printf ("%u", prefix); + svSetValueStr (ifcfg, prefix_key, tmp); g_free (tmp); - svUnsetValue (ifcfg, netmask_key); - svUnsetValue (ifcfg, gw_key); + /* If the legacy "NETMASK" is present, keep it. */ + if (svGetValue (ifcfg, netmask_key, &tmp)) { + char buf[INET_ADDRSTRLEN]; - g_free (addr_key); - g_free (prefix_key); - g_free (netmask_key); - g_free (gw_key); + g_free (tmp); + svSetValueStr (ifcfg, netmask_key, nm_utils_inet4_ntop (prefix, buf)); + } + + svUnsetValue (ifcfg, gw_key); n++; } /* Clear remaining IPADDR<n..255>, etc */ - for (; n < 256; n++) { - addr_key = g_strdup_printf ("IPADDR%d", n); - prefix_key = g_strdup_printf ("PREFIX%d", n); - netmask_key = g_strdup_printf ("NETMASK%d", n); - gw_key = g_strdup_printf ("GATEWAY%d", n); + for (i = n; i < 256; i++) { + nm_sprintf_buf (addr_key, "IPADDR%u", i); + nm_sprintf_buf (prefix_key, "PREFIX%u", i); + nm_sprintf_buf (netmask_key, "NETMASK%u", i); + nm_sprintf_buf (gw_key, "GATEWAY%u", i); svUnsetValue (ifcfg, addr_key); svUnsetValue (ifcfg, prefix_key); svUnsetValue (ifcfg, netmask_key); svUnsetValue (ifcfg, gw_key); - - g_free (addr_key); - g_free (prefix_key); - g_free (netmask_key); - g_free (gw_key); } - svSetValueString (ifcfg, "GATEWAY", nm_setting_ip_config_get_gateway (s_ip4)); + svSetValueStr (ifcfg, "GATEWAY", nm_setting_ip_config_get_gateway (s_ip4)); num = nm_setting_ip_config_get_num_dns (s_ip4); for (i = 0; i < 254; i++) { const char *dns; - addr_key = g_strdup_printf ("DNS%d", i + 1); - + nm_sprintf_buf (addr_key, "DNS%u", i + 1); if (i >= num) svUnsetValue (ifcfg, addr_key); else { dns = nm_setting_ip_config_get_dns (s_ip4, i); - svSetValueString (ifcfg, addr_key, dns); + svSetValueStr (ifcfg, addr_key, dns); } - g_free (addr_key); } num = nm_setting_ip_config_get_num_dns_searches (s_ip4); @@ -2182,7 +2245,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_string_append_c (searches, ' '); g_string_append (searches, nm_setting_ip_config_get_dns_search (s_ip4, i)); } - svSetValueString (ifcfg, "DOMAIN", searches->str); + svSetValueStr (ifcfg, "DOMAIN", searches->str); g_string_free (searches, TRUE); } else svUnsetValue (ifcfg, "DOMAIN"); @@ -2191,37 +2254,37 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueBoolean (ifcfg, "DEFROUTE", !nm_setting_ip_config_get_never_default (s_ip4)); /* Missing PEERDNS means TRUE, so write it only when is FALSE */ - svSetValueString (ifcfg, "PEERDNS", - nm_setting_ip_config_get_ignore_auto_dns (s_ip4) ? "no" : NULL); + svSetValueStr (ifcfg, "PEERDNS", + nm_setting_ip_config_get_ignore_auto_dns (s_ip4) ? "no" : NULL); /* Missing PEERROUTES means TRUE, so write it only when is FALSE */ - svSetValueString (ifcfg, "PEERROUTES", - nm_setting_ip_config_get_ignore_auto_routes (s_ip4) ? "no" : NULL); + svSetValueStr (ifcfg, "PEERROUTES", + nm_setting_ip_config_get_ignore_auto_routes (s_ip4) ? "no" : NULL); value = nm_setting_ip_config_get_dhcp_hostname (s_ip4); - svSetValueString (ifcfg, "DHCP_HOSTNAME", value); + svSetValueStr (ifcfg, "DHCP_HOSTNAME", value); value = nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)); - svSetValueString (ifcfg, "DHCP_FQDN", value); + svSetValueStr (ifcfg, "DHCP_FQDN", value); /* Missing DHCP_SEND_HOSTNAME means TRUE, and we prefer not write it explicitly * in that case, because it is NM-specific variable */ - svSetValueString (ifcfg, "DHCP_SEND_HOSTNAME", - nm_setting_ip_config_get_dhcp_send_hostname (s_ip4) ? NULL : "no"); + svSetValueStr (ifcfg, "DHCP_SEND_HOSTNAME", + nm_setting_ip_config_get_dhcp_send_hostname (s_ip4) ? NULL : "no"); value = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); - svSetValueString (ifcfg, "DHCP_CLIENT_ID", value); + svSetValueStr (ifcfg, "DHCP_CLIENT_ID", value); timeout = nm_setting_ip_config_get_dhcp_timeout (s_ip4); tmp = timeout ? g_strdup_printf ("%d", timeout) : NULL; - svSetValueString (ifcfg, "IPV4_DHCP_TIMEOUT", tmp); + svSetValueStr (ifcfg, "IPV4_DHCP_TIMEOUT", tmp); g_free (tmp); svSetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", !nm_setting_ip_config_get_may_fail (s_ip4)); route_metric = nm_setting_ip_config_get_route_metric (s_ip4); tmp = route_metric != -1 ? g_strdup_printf ("%"G_GINT64_FORMAT, route_metric) : NULL; - svSetValueString (ifcfg, "IPV4_ROUTE_METRIC", tmp); + svSetValueStr (ifcfg, "IPV4_ROUTE_METRIC", tmp); g_free (tmp); /* Static routes - route-<name> file */ @@ -2250,28 +2313,34 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) NMIPRoute *route; guint32 netmask; gint64 metric; + char metric_key[64]; + char options_key[64]; - addr_key = g_strdup_printf ("ADDRESS%d", i); - netmask_key = g_strdup_printf ("NETMASK%d", i); - gw_key = g_strdup_printf ("GATEWAY%d", i); - metric_key = g_strdup_printf ("METRIC%d", i); + nm_sprintf_buf (addr_key, "ADDRESS%u", i); + nm_sprintf_buf (netmask_key, "NETMASK%u", i); + nm_sprintf_buf (gw_key, "GATEWAY%u", i); + nm_sprintf_buf (metric_key, "METRIC%u", i); + nm_sprintf_buf (options_key, "OPTIONS%u", i); if (i >= num) { svUnsetValue (routefile, addr_key); svUnsetValue (routefile, netmask_key); svUnsetValue (routefile, gw_key); svUnsetValue (routefile, metric_key); + svUnsetValue (routefile, options_key); } else { + gs_free char *options = NULL; + route = nm_setting_ip_config_get_route (s_ip4, i); - svSetValueString (routefile, addr_key, nm_ip_route_get_dest (route)); + svSetValueStr (routefile, addr_key, nm_ip_route_get_dest (route)); memset (buf, 0, sizeof (buf)); netmask = nm_utils_ip4_prefix_to_netmask (nm_ip_route_get_prefix (route)); inet_ntop (AF_INET, (const void *) &netmask, &buf[0], sizeof (buf)); - svSetValueString (routefile, netmask_key, &buf[0]); + svSetValueStr (routefile, netmask_key, &buf[0]); - svSetValueString (routefile, gw_key, nm_ip_route_get_next_hop (route)); + svSetValueStr (routefile, gw_key, nm_ip_route_get_next_hop (route)); memset (buf, 0, sizeof (buf)); metric = nm_ip_route_get_metric (route); @@ -2279,15 +2348,14 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svUnsetValue (routefile, metric_key); else { tmp = g_strdup_printf ("%u", (guint32) metric); - svSetValueString (routefile, metric_key, tmp); + svSetValueStr (routefile, metric_key, tmp); g_free (tmp); } - } - g_free (addr_key); - g_free (netmask_key); - g_free (gw_key); - g_free (metric_key); + options = get_route_attributes_string (route, AF_INET); + if (options) + svSetValueStr (routefile, options_key, options); + } } if (!svWriteFile (routefile, 0644, error)) { svCloseFile (routefile); @@ -2305,7 +2373,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (timeout < 0) svUnsetValue (ifcfg, "ARPING_WAIT"); else if (timeout == 0) - svSetValueString (ifcfg, "ARPING_WAIT", "0"); + svSetValueStr (ifcfg, "ARPING_WAIT", "0"); else { /* Round the value up to next integer */ svSetValueInt64 (ifcfg, "ARPING_WAIT", (timeout - 1) / 1000 + 1); @@ -2325,7 +2393,7 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path) { NMSettingIPConfig *s_ip4; gs_free char *base_ifcfg_dir = NULL, *base_ifcfg_name = NULL; - const char*base_name; + const char *base_name; int i, num, base_ifcfg_name_len, base_name_len; GDir *dir; @@ -2392,13 +2460,13 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path) ifcfg = svCreateFile (path); g_free (path); - svSetValueString (ifcfg, "DEVICE", label); + svSetValueStr (ifcfg, "DEVICE", label); addr = nm_setting_ip_config_get_address (s_ip4, i); - svSetValueString (ifcfg, "IPADDR", nm_ip_address_get_address (addr)); + svSetValueStr (ifcfg, "IPADDR", nm_ip_address_get_address (addr)); tmp = g_strdup_printf ("%u", nm_ip_address_get_prefix (addr)); - svSetValueString (ifcfg, "PREFIX", tmp); + svSetValueStr (ifcfg, "PREFIX", tmp); g_free (tmp); svWriteFile (ifcfg, 0644, NULL); @@ -2409,16 +2477,13 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path) static gboolean write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) { - char **route_items; - char *route_contents; + nm_auto_free_gstring GString *contents = NULL; NMIPRoute *route; guint32 i, num; - gboolean success = FALSE; - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (s_ip6 != NULL, FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (filename, FALSE); + g_return_val_if_fail (s_ip6, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); num = nm_setting_ip_config_get_num_routes (s_ip6); if (num == 0) { @@ -2426,38 +2491,39 @@ write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **erro return TRUE; } - route_items = g_malloc0 (sizeof (char*) * (num + 1)); + contents = g_string_new (""); for (i = 0; i < num; i++) { + gs_free char *options = NULL; + route = nm_setting_ip_config_get_route (s_ip6, i); + options = get_route_attributes_string (route, AF_INET6); if (nm_ip_route_get_metric (route) == -1) { - route_items[i] = g_strdup_printf ("%s/%u via %s\n", + g_string_append_printf (contents, "%s/%u via %s%s%s", nm_ip_route_get_dest (route), nm_ip_route_get_prefix (route), - nm_ip_route_get_next_hop (route)); + nm_ip_route_get_next_hop (route), + options ? " " : "", + options ?: ""); } else { - route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", + g_string_append_printf (contents, "%s/%u via %s metric %u%s%s", nm_ip_route_get_dest (route), nm_ip_route_get_prefix (route), nm_ip_route_get_next_hop (route), - (guint32) nm_ip_route_get_metric (route)); + (unsigned) nm_ip_route_get_metric (route), + options ? " " : "", + options ?: ""); } + g_string_append (contents, "\n"); } - route_items[num] = NULL; - route_contents = g_strjoinv (NULL, route_items); - g_strfreev (route_items); - if (!g_file_set_contents (filename, route_contents, -1, NULL)) { + if (!g_file_set_contents (filename, contents->str, -1, NULL)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Writing route6 file '%s' failed", filename); - goto error; + return FALSE; } - success = TRUE; - -error: - g_free (route_contents); - return success; + return TRUE; } static void @@ -2466,7 +2532,7 @@ write_ip6_setting_dhcp_hostname (NMSettingIPConfig *s_ip6, shvarFile *ifcfg) const char *hostname; hostname = nm_setting_ip_config_get_dhcp_hostname (s_ip6); - svSetValueString (ifcfg, "DHCPV6_HOSTNAME", hostname); + svSetValueStr (ifcfg, "DHCPV6_HOSTNAME", hostname); /* Missing DHCPV6_SEND_HOSTNAME means TRUE, and we prefer not write it * explicitly in that case, because it is NM-specific variable @@ -2474,7 +2540,7 @@ write_ip6_setting_dhcp_hostname (NMSettingIPConfig *s_ip6, shvarFile *ifcfg) if (nm_setting_ip_config_get_dhcp_send_hostname (s_ip6)) svUnsetValue (ifcfg, "DHCPV6_SEND_HOSTNAME"); else - svSetValueString (ifcfg, "DHCPV6_SEND_HOSTNAME", "no"); + svSetValueStr (ifcfg, "DHCPV6_SEND_HOSTNAME", "no"); } static gboolean @@ -2483,11 +2549,9 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) NMSettingIPConfig *s_ip6; NMSettingIPConfig *s_ip4; const char *value; - char *addr_key; char *tmp; - guint32 i, num, num4; + guint i, num, num4; gint priority; - GString *searches; NMIPAddress *addr; const char *dns; gint64 route_metric; @@ -2518,28 +2582,28 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) value = nm_setting_ip_config_get_method (s_ip6); g_assert (value); if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - svSetValueString (ifcfg, "IPV6INIT", "no"); + svSetValueStr (ifcfg, "IPV6INIT", "no"); svUnsetValue (ifcfg, "DHCPV6C"); return TRUE; } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - svSetValueString (ifcfg, "IPV6INIT", "yes"); - svSetValueString (ifcfg, "IPV6_AUTOCONF", "yes"); + svSetValueStr (ifcfg, "IPV6INIT", "yes"); + svSetValueStr (ifcfg, "IPV6_AUTOCONF", "yes"); svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - svSetValueString (ifcfg, "IPV6INIT", "yes"); - svSetValueString (ifcfg, "IPV6_AUTOCONF", "no"); - svSetValueString (ifcfg, "DHCPV6C", "yes"); + svSetValueStr (ifcfg, "IPV6INIT", "yes"); + svSetValueStr (ifcfg, "IPV6_AUTOCONF", "no"); + svSetValueStr (ifcfg, "DHCPV6C", "yes"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { - svSetValueString (ifcfg, "IPV6INIT", "yes"); - svSetValueString (ifcfg, "IPV6_AUTOCONF", "no"); + svSetValueStr (ifcfg, "IPV6INIT", "yes"); + svSetValueStr (ifcfg, "IPV6_AUTOCONF", "no"); svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { - svSetValueString (ifcfg, "IPV6INIT", "yes"); - svSetValueString (ifcfg, "IPV6_AUTOCONF", "no"); + svSetValueStr (ifcfg, "IPV6INIT", "yes"); + svSetValueStr (ifcfg, "IPV6_AUTOCONF", "no"); svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - svSetValueString (ifcfg, "IPV6INIT", "yes"); - svSetValueString (ifcfg, "IPV6_AUTOCONF", "shared"); + svSetValueStr (ifcfg, "IPV6INIT", "yes"); + svSetValueStr (ifcfg, "IPV6_AUTOCONF", "shared"); svUnsetValue (ifcfg, "DHCPV6C"); } @@ -2563,9 +2627,9 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) nm_ip_address_get_address (addr), nm_ip_address_get_prefix (addr)); } - svSetValueString (ifcfg, "IPV6ADDR", ip_str1->str); - svSetValueString (ifcfg, "IPV6ADDR_SECONDARIES", ip_str2->str); - svSetValueString (ifcfg, "IPV6_DEFAULTGW", nm_setting_ip_config_get_gateway (s_ip6)); + svSetValueStr (ifcfg, "IPV6ADDR", ip_str1->str); + svSetValueStr (ifcfg, "IPV6ADDR_SECONDARIES", ip_str2->str); + svSetValueStr (ifcfg, "IPV6_DEFAULTGW", nm_setting_ip_config_get_gateway (s_ip6)); g_string_free (ip_str1, TRUE); g_string_free (ip_str2, TRUE); @@ -2574,68 +2638,68 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) num4 = s_ip4 ? nm_setting_ip_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */ num = nm_setting_ip_config_get_num_dns (s_ip6); for (i = 0; i < 254; i++) { - addr_key = g_strdup_printf ("DNS%d", i + num4 + 1); + char addr_key[64]; + + nm_sprintf_buf (addr_key, "DNS%u", i + num4 + 1); if (i >= num) svUnsetValue (ifcfg, addr_key); else { dns = nm_setting_ip_config_get_dns (s_ip6, i); - svSetValueString (ifcfg, addr_key, dns); + svSetValueStr (ifcfg, addr_key, dns); } - g_free (addr_key); } /* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */ num = nm_setting_ip_config_get_num_dns_searches (s_ip6); if (num > 0) { - char *ip4_domains; - ip4_domains = svGetValueString (ifcfg, "DOMAIN"); - searches = g_string_new (ip4_domains); + gs_free char *ip4_domains = NULL; + nm_auto_free_gstring GString *searches = NULL; + + searches = g_string_new (svGetValueStr (ifcfg, "DOMAIN", &ip4_domains)); for (i = 0; i < num; i++) { if (searches->len > 0) g_string_append_c (searches, ' '); g_string_append (searches, nm_setting_ip_config_get_dns_search (s_ip6, i)); } - svSetValueString (ifcfg, "DOMAIN", searches->str); - g_string_free (searches, TRUE); - g_free (ip4_domains); + svSetValueStr (ifcfg, "DOMAIN", searches->str); } /* handle IPV6_DEFROUTE */ /* IPV6_DEFROUTE has the opposite meaning from 'never-default' */ - if (nm_setting_ip_config_get_never_default(s_ip6)) - svSetValueString (ifcfg, "IPV6_DEFROUTE", "no"); + if (nm_setting_ip_config_get_never_default (s_ip6)) + svSetValueStr (ifcfg, "IPV6_DEFROUTE", "no"); else - svSetValueString (ifcfg, "IPV6_DEFROUTE", "yes"); + svSetValueStr (ifcfg, "IPV6_DEFROUTE", "yes"); - svSetValueString (ifcfg, "IPV6_PEERDNS", - nm_setting_ip_config_get_ignore_auto_dns (s_ip6) ? "no" : NULL); + svSetValueStr (ifcfg, "IPV6_PEERDNS", + nm_setting_ip_config_get_ignore_auto_dns (s_ip6) ? "no" : NULL); - svSetValueString (ifcfg, "IPV6_PEERROUTES", - nm_setting_ip_config_get_ignore_auto_routes (s_ip6) ? "no" : NULL); + svSetValueStr (ifcfg, "IPV6_PEERROUTES", + nm_setting_ip_config_get_ignore_auto_routes (s_ip6) ? "no" : NULL); - svSetValueString (ifcfg, "IPV6_FAILURE_FATAL", - nm_setting_ip_config_get_may_fail (s_ip6) ? "no" : "yes"); + svSetValueStr (ifcfg, "IPV6_FAILURE_FATAL", + nm_setting_ip_config_get_may_fail (s_ip6) ? "no" : "yes"); route_metric = nm_setting_ip_config_get_route_metric (s_ip6); tmp = route_metric != -1 ? g_strdup_printf ("%"G_GINT64_FORMAT, route_metric) : NULL; - svSetValueString (ifcfg, "IPV6_ROUTE_METRIC", tmp); + svSetValueStr (ifcfg, "IPV6_ROUTE_METRIC", tmp); g_free (tmp); /* IPv6 Privacy Extensions */ svUnsetValue (ifcfg, "IPV6_PRIVACY"); svUnsetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP"); - switch (nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))){ + switch (nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))) { case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - svSetValueString (ifcfg, "IPV6_PRIVACY", "no"); + svSetValueStr (ifcfg, "IPV6_PRIVACY", "no"); break; case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - svSetValueString (ifcfg, "IPV6_PRIVACY", "rfc3041"); - svSetValueString (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", "yes"); + svSetValueStr (ifcfg, "IPV6_PRIVACY", "rfc3041"); + svSetValueStr (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", "yes"); break; case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - svSetValueString (ifcfg, "IPV6_PRIVACY", "rfc3041"); + svSetValueStr (ifcfg, "IPV6_PRIVACY", "rfc3041"); break; default: break; @@ -2646,7 +2710,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) { tmp = nm_utils_enum_to_str (nm_setting_ip6_config_addr_gen_mode_get_type (), addr_gen_mode); - svSetValueString (ifcfg, "IPV6_ADDR_GEN_MODE", tmp); + svSetValueStr (ifcfg, "IPV6_ADDR_GEN_MODE", tmp); g_free (tmp); } else { svUnsetValue (ifcfg, "IPV6_ADDR_GEN_MODE"); @@ -2654,7 +2718,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) /* IPv6 tokenized interface identifier */ value = nm_setting_ip6_config_get_token (NM_SETTING_IP6_CONFIG (s_ip6)); - svSetValueString (ifcfg, "IPV6_TOKEN", value); + svSetValueStr (ifcfg, "IPV6_TOKEN", value); priority = nm_setting_ip_config_get_dns_priority (s_ip6); if (priority) @@ -2667,17 +2731,14 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (!route6_path) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Could not get route6 file path for '%s'", svFileGetName (ifcfg)); - goto error; + return FALSE; } write_route6_file (route6_path, s_ip6, error); g_free (route6_path); if (error && *error) - goto error; + return FALSE; return TRUE; - -error: - return FALSE; } static void @@ -2762,18 +2823,20 @@ write_connection (NMConnection *connection, const char *ifcfg_dir, const char *filename, char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { NMSettingConnection *s_con; - gboolean success = FALSE; - shvarFile *ifcfg = NULL; - char *ifcfg_name = NULL; + nm_auto_shvar_file_close shvarFile *ifcfg = NULL; + gs_free char *ifcfg_name = NULL; const char *type; gboolean no_8021x = FALSE; gboolean wired = FALSE; nm_assert (NM_IS_CONNECTION (connection)); - nm_assert (nm_connection_verify (connection, NULL)); + nm_assert (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS); + nm_assert (!out_reread || !*out_reread); if (!writer_can_write_connection (connection, error)) return FALSE; @@ -2802,13 +2865,12 @@ write_connection (NMConnection *connection, if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS)) { guint32 idx = 0; - g_free (ifcfg_name); + nm_clear_g_free (&ifcfg_name); while (idx++ < 500) { ifcfg_name = g_strdup_printf ("%s/ifcfg-%s-%u", ifcfg_dir, escaped, idx); if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS) == FALSE) break; - g_free (ifcfg_name); - ifcfg_name = NULL; + nm_clear_g_free (&ifcfg_name); } } g_free (escaped); @@ -2826,7 +2888,7 @@ write_connection (NMConnection *connection, if (!type) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Missing connection type!"); - goto out; + return FALSE; } if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { @@ -2835,82 +2897,113 @@ write_connection (NMConnection *connection, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Can't write connection type '%s'", NM_SETTING_PPPOE_SETTING_NAME); - goto out; + return FALSE; } if (!write_wired_setting (connection, ifcfg, error)) - goto out; + return FALSE; wired = TRUE; } else if (!strcmp (type, NM_SETTING_VLAN_SETTING_NAME)) { if (!write_vlan_setting (connection, ifcfg, &wired, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { if (!write_wireless_setting (connection, ifcfg, &no_8021x, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { if (!write_infiniband_setting (connection, ifcfg, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_BOND_SETTING_NAME)) { if (!write_bonding_setting (connection, ifcfg, &wired, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_TEAM_SETTING_NAME)) { if (!write_team_setting (connection, ifcfg, &wired, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)) { if (!write_bridge_setting (connection, ifcfg, error)) - goto out; + return FALSE; } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Can't write connection type '%s'", type); - goto out; + return FALSE; } if (!no_8021x) { if (!write_8021x_setting (connection, ifcfg, wired, error)) - goto out; + return FALSE; } if (!write_bridge_port_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_team_port_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_dcb_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_proxy_setting (connection, ifcfg, error)) - goto out; + return FALSE; + + if (!write_user_setting (connection, ifcfg, error)) + return FALSE; svUnsetValue (ifcfg, "DHCP_HOSTNAME"); svUnsetValue (ifcfg, "DHCP_FQDN"); if (!write_ip4_setting (connection, ifcfg, error)) - goto out; + return FALSE; write_ip4_aliases (connection, ifcfg_name); if (!write_ip6_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_res_options (connection, ifcfg, error)) - goto out; + return FALSE; write_connection_setting (s_con, ifcfg); if (!svWriteFile (ifcfg, 0644, error)) - goto out; + return FALSE; + + if (out_reread || out_reread_same) { + gs_unref_object NMConnection *reread = NULL; + gs_free_error GError *local = NULL; + gs_free char *unhandled = NULL; + gboolean reread_same = FALSE; + + reread = connection_from_file (ifcfg_name, &unhandled, &local, NULL); + + if (unhandled) { + _LOGW ("failure to re-read the new connection from file \"%s\": %s", + ifcfg_name, "connection is unhandled"); + g_clear_object (&reread); + } else if (!reread) { + _LOGW ("failure to re-read the new connection from file \"%s\": %s", + ifcfg_name, local ? local->message : "<unknown>"); + } else { + if (out_reread_same) { + if (nm_connection_compare (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT)) + reread_same = TRUE; + + nm_assert (reread_same == nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + nm_assert (reread_same == ({ + gs_unref_hashtable GHashTable *_settings = NULL; + + ( nm_connection_diff (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT, &_settings) + && !_settings); + })); + } + } + + NM_SET_OUT (out_reread, g_steal_pointer (&reread)); + NM_SET_OUT (out_reread_same, reread_same); + } /* Only return the filename if this was a newly written ifcfg */ if (out_filename && !filename) - *out_filename = g_strdup (ifcfg_name); - - success = TRUE; + *out_filename = g_steal_pointer (&ifcfg_name); -out: - if (ifcfg) - svCloseFile (ifcfg); - g_free (ifcfg_name); - return success; + return TRUE; } gboolean @@ -2942,15 +3035,19 @@ gboolean writer_new_connection (NMConnection *connection, const char *ifcfg_dir, char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { - return write_connection (connection, ifcfg_dir, NULL, out_filename, error); + return write_connection (connection, ifcfg_dir, NULL, out_filename, out_reread, out_reread_same, error); } gboolean writer_update_connection (NMConnection *connection, const char *ifcfg_dir, const char *filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { if (utils_has_complex_routes (filename)) { @@ -2959,6 +3056,6 @@ writer_update_connection (NMConnection *connection, return FALSE; } - return write_connection (connection, ifcfg_dir, filename, NULL, error); + return write_connection (connection, ifcfg_dir, filename, NULL, out_reread, out_reread_same, error); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h index 2662f79b..9cd9513e 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h @@ -29,11 +29,15 @@ gboolean writer_can_write_connection (NMConnection *connection, gboolean writer_new_connection (NMConnection *connection, const char *ifcfg_dir, char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); gboolean writer_update_connection (NMConnection *connection, const char *ifcfg_dir, const char *filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); #endif /* _WRITER_H_ */ diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 65bcc0d9..9fce5aa1 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -41,7 +41,7 @@ /*****************************************************************************/ -typedef struct { +struct _shvarLine { /* There are three cases: * * 1) the line is not a valid variable assignment (that is, it doesn't @@ -61,7 +61,9 @@ typedef struct { char *line; const char *key; char *key_with_prefix; -} shvarLine; +}; + +typedef struct _shvarLine shvarLine; struct _shvarFile { char *fileName; @@ -220,14 +222,12 @@ svEscape (const char *s, char **to_free) int newlen; size_t i, j, slen; - slen = strlen (s); - - for (i = 0; i < slen; i++) { - if (_char_req_escape (s[i])) + for (slen = 0; s[slen]; slen++) { + if (_char_req_escape (s[slen])) mangle++; - else if (_char_req_quotes (s[i])) + else if (_char_req_quotes (s[slen])) requires_quotes = TRUE; - else if (s[i] < ' ') { + else if (s[slen] < ' ') { /* if the string contains newline we can only express it using ANSI C quotation * (as we don't support line continuation). * Additionally, ANSI control characters look odd with regular quotation, so handle @@ -639,15 +639,19 @@ svFileGetName (const shvarFile *s) } void -svFileSetName (shvarFile *s, const char *fileName) +svFileSetName_test_only (shvarFile *s, const char *fileName) { + /* changing the file name is not supported for regular + * operation. Only allowed to use in tests, othewise, + * the filename is immutable. */ g_free (s->fileName); s->fileName = g_strdup (fileName); } void -svFileSetModified (shvarFile *s) +svFileSetModified_test_only (shvarFile *s) { + /* marking a file as modified is only for testing. */ s->modified = TRUE; } @@ -877,6 +881,30 @@ shlist_find (const GList *current, const char *key) /*****************************************************************************/ +GHashTable * +svGetKeys (shvarFile *s) +{ + GHashTable *keys = NULL; + const GList *current; + const shvarLine *line; + + nm_assert (s); + + for (current = s->lineList; current; current = current->next) { + line = current->data; + if (line->key && line->line) { + /* we don't clone the keys. The keys are only valid + * until @s gets modified. */ + if (!keys) + keys = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + g_hash_table_add (keys, (gpointer) line->key); + } + } + return keys; +} + +/*****************************************************************************/ + static const char * _svGetValue (shvarFile *s, const char *key, char **to_free) { @@ -895,39 +923,104 @@ _svGetValue (shvarFile *s, const char *key, char **to_free) } if (last) { line = last->data; - if (line->line) - return svUnescape (line->line, to_free); + if (line->line) { + const char *v; + + v = svUnescape (line->line, to_free); + if (!v) { + /* a wrongly quoted value is treated like the empty string. + * See also svWriteFile(), which handles unparsable values + * that way. */ + nm_assert (!*to_free); + return ""; + } + return v; + } } *to_free = NULL; return NULL; } +/* Returns the value for key. The value is either owned by @s + * or returned as to_free. This aims to avoid cloning the string. + * + * - like svGetValue_cp(), but avoids cloning the value if possible. + * - like svGetValueStr(), but does not ignore empty string values. + */ const char * svGetValue (shvarFile *s, const char *key, char **to_free) { - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (s, NULL); + g_return_val_if_fail (key, NULL); g_return_val_if_fail (to_free, NULL); return _svGetValue (s, key, to_free); } -/* Get the value associated with the key, and leave the current pointer - * pointing at the line containing the value. The char* returned MUST - * be freed by the caller. +/* Returns the value for key. The value is either owned by @s + * or returned as to_free. This aims to avoid cloning the string. + * + * - like svGetValue(), but does not return an empty string. + * - like svGetValueStr_cp(), but avoids cloning the value if possible. + */ +const char * +svGetValueStr (shvarFile *s, const char *key, char **to_free) +{ + const char *value; + + g_return_val_if_fail (s, NULL); + g_return_val_if_fail (key, NULL); + g_return_val_if_fail (to_free, NULL); + + value = _svGetValue (s, key, to_free); + if (!value || !value[0]) { + nm_assert (!*to_free); + return NULL; + } + return value; +} + +/* Returns the value for key. The returned value must be freed + * by the caller. + * + * - like svGetValue(), but always returns a copy of the value. + * - like svGetValueStr_cp(), but does not ignore an empty string. */ char * -svGetValueString (shvarFile *s, const char *key) +svGetValue_cp (shvarFile *s, const char *key) { char *to_free; const char *value; + g_return_val_if_fail (s, NULL); + g_return_val_if_fail (key, NULL); + value = _svGetValue (s, key, &to_free); if (!value) { nm_assert (!to_free); return NULL; } - if (!value[0]) { + return to_free ?: g_strdup (value); +} + +/* Returns the value for key. The returned value must be freed + * by the caller. + * If the key is unset or the value an empty string, NULL is returned. + * + * - like svGetValueStr(), but always returns a copy of the value. + * - like svGetValue_cp(), but returns NULL instead of an empty string. + */ +char * +svGetValueStr_cp (shvarFile *s, const char *key) +{ + char *to_free; + const char *value; + + g_return_val_if_fail (s, NULL); + g_return_val_if_fail (key, NULL); + + value = _svGetValue (s, key, &to_free); + if (!value || !value[0]) { nm_assert (!to_free); return NULL; } @@ -991,8 +1084,8 @@ svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 m /*****************************************************************************/ -/* Same as svSetValueString() but it preserves empty @value -- contrary to - * svSetValueString() for which "" effectively means to remove the value. */ +/* Same as svSetValueStr() but it preserves empty @value -- contrary to + * svSetValueStr() for which "" effectively means to remove the value. */ void svSetValue (shvarFile *s, const char *key, const char *value) { @@ -1041,7 +1134,7 @@ svSetValue (shvarFile *s, const char *key, const char *value) * to the bottom of the file. */ void -svSetValueString (shvarFile *s, const char *key, const char *value) +svSetValueStr (shvarFile *s, const char *key, const char *value) { svSetValue (s, key, value && value[0] ? value : NULL); } @@ -1066,6 +1159,27 @@ svUnsetValue (shvarFile *s, const char *key) svSetValue (s, key, NULL); } +void +svUnsetValuesWithPrefix (shvarFile *s, const char *prefix) +{ + GList *current; + + g_return_if_fail (s); + g_return_if_fail (prefix); + + for (current = s->lineList; current; current = current->next) { + shvarLine *line = current->data; + + ASSERT_shvarLine (line); + if ( line->key + && g_str_has_prefix (line->key, prefix)) { + if (nm_clear_g_free (&line->line)) + s->modified = TRUE; + } + ASSERT_shvarLine (line); + } +} + /*****************************************************************************/ /* Write the current contents iff modified. Returns FALSE on error diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index a6498fce..9d8c2364 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -34,9 +34,9 @@ typedef struct _shvarFile shvarFile; const char *svFileGetName (const shvarFile *s); -void svFileSetName (shvarFile *s, const char *fileName); -void svFileSetModified (shvarFile *s); +void svFileSetName_test_only (shvarFile *s, const char *fileName); +void svFileSetModified_test_only (shvarFile *s); /* Create the file <name>, return a shvarFile (never fails) */ shvarFile *svCreateFile (const char *name); @@ -49,10 +49,15 @@ shvarFile *svOpenFile (const char *name, GError **error); * be freed by the caller. */ const char *svGetValue (shvarFile *s, const char *key, char **to_free); -char *svGetValueString (shvarFile *s, const char *key); +char *svGetValue_cp (shvarFile *s, const char *key); + +const char *svGetValueStr (shvarFile *s, const char *key, char **to_free); +char *svGetValueStr_cp (shvarFile *s, const char *key); gint svParseBoolean (const char *value, gint def); +GHashTable *svGetKeys (shvarFile *s); + /* return TRUE if <key> resolves to any truth value (e.g. "yes", "y", "true") * return FALSE if <key> resolves to any non-truth value (e.g. "no", "n", "false") * return <def> otherwise @@ -66,13 +71,15 @@ gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, g * the key=value pair after that line. Otherwise, prepend the pair * to the top of the file. */ -void svSetValueString (shvarFile *s, const char *key, const char *value); void svSetValue (shvarFile *s, const char *key, const char *value); +void svSetValueStr (shvarFile *s, const char *key, const char *value); void svSetValueBoolean (shvarFile *s, const char *key, gboolean value); void svSetValueInt64 (shvarFile *s, const char *key, gint64 value); void svUnsetValue (shvarFile *s, const char *key); +void svUnsetValuesWithPrefix (shvarFile *s, const char *prefix); + /* Write the current contents iff modified. Returns FALSE on error * and TRUE on success. Do not write if no values have been modified. * The mode argument is only used if creating the file, not if @@ -87,4 +94,16 @@ void svCloseFile (shvarFile *s); const char *svEscape (const char *s, char **to_free); const char *svUnescape (const char *s, char **to_free); +static inline void +_nm_auto_shvar_file_close (shvarFile **p_s) +{ + if (*p_s) { + int errsv = errno; + + svCloseFile (*p_s); + errno = errsv; + } +} +#define nm_auto_shvar_file_close nm_auto(_nm_auto_shvar_file_close) + #endif /* _SHVAR_H */ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected new file mode 100644 index 00000000..d81d9187 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected @@ -0,0 +1,8 @@ +HWADDR=00:22:15:59:62:97 +TYPE=Ethernet +BRIDGING_OPTS="priority=28 hairpin_mode=1" +NAME="System test-bridge-component" +UUID=${UUID} +DEVICE=eth0 +ONBOOT=no +BRIDGE=br0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected new file mode 100644 index 00000000..d4785ff5 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected @@ -0,0 +1,17 @@ +HWADDR=00:22:15:59:62:97 +TYPE=Ethernet +BRIDGING_OPTS="priority=28 hairpin_mode=1" +NAME="System test-bridge-component" +UUID=${UUID} +DEVICE=eth0 +ONBOOT=no +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected new file mode 100644 index 00000000..59a6f79b --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected @@ -0,0 +1,22 @@ +HWADDR=00:11:22:33:44:EE +TYPE=Ethernet +KEY_MGMT=IEEE8021X +IEEE_8021X_EAP_METHODS=PEAP +IEEE_8021X_IDENTITY="Jara Cimrman" +IEEE_8021X_PASSWORD_FLAGS="user ask" +IEEE_8021X_PEAP_VERSION=1 +IEEE_8021X_INNER_AUTH_METHODS=GTC +IEEE_8021X_SUBJECT_MATCH=server1.yourdomain.tld +IEEE_8021X_PHASE2_SUBJECT_MATCH=server2.yourdomain.tld +IEEE_8021X_ALTSUBJECT_MATCHES="a.yourdomain.tld b.yourdomain.tld c.yourdomain.tld" +IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES="x.yourdomain.tld y.yourdomain.tld" +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="System test-wired-802-1X-subj-matches" +UUID=${UUID} +DEVICE=eth0 +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected new file mode 100644 index 00000000..a48be78a --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected @@ -0,0 +1,34 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +NM_USER__M_Y___053=val=MY.+ +NM_USER__M_Y___055=val=MY.- +NM_USER__M_Y___057=val=MY./ +NM_USER__M_Y__8_053_V=val=MY.8+V +NM_USER__M_Y__8_055_V=val=MY.8-V +NM_USER__M_Y__8_057_V=val=MY.8/V +NM_USER__M_Y__8_075_V=val=MY.8=V +NM_USER__M_Y__8_V=val=MY.8V +NM_USER__M_Y__8_137_V=val=MY.8_V +NM_USER__M_Y___075=val=MY.= +NM_USER__M_Y___A_V=val=MY.AV +NM_USER__M_Y___137=val=MY._ +NM_USER_MY___AV=val=my.Av +NM_USER_MY___137V=val=my._v +NM_USER_MY__KEYS__1=val=my.keys.1 +NM_USER_MY__OTHER___K_E_Y__42=val=my.other.KEY.42 +NM_USER_MY__V_053=val=my.v+ +NM_USER_MY__V_137_137AL3=val=my.v__al3 +NM_USER_MY__VAL1= +NM_USER_MY__VAL2=val=my.val2 +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test User 1" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected new file mode 100644 index 00000000..3956003d --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected @@ -0,0 +1,16 @@ +DEVICE=bond0 +BONDING_OPTS=mode=balance-rr +TYPE=Bond +BONDING_MASTER=yes +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +GATEWAY=1.1.1.1 +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Bond Main" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected new file mode 100644 index 00000000..c478db38 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected @@ -0,0 +1,8 @@ +HWADDR=31:33:33:37:BE:CD +MTU=1492 +TYPE=Ethernet +BRIDGING_OPTS="priority=50 path_cost=33" +NAME="Test Write Bridge Component" +UUID=${UUID} +ONBOOT=yes +BRIDGE=br0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected new file mode 100644 index 00000000..80e96921 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected @@ -0,0 +1,11 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Permissions" +UUID=${UUID} +ONBOOT=yes +USERS="blahblah foobar asdfasdf" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected new file mode 100644 index 00000000..716eedc2 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=auto +PAC_URL=https://wpad.neverland.org/wpad.dat +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write Proxy Basic" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected new file mode 100644 index 00000000..0b1deb80 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected @@ -0,0 +1,6 @@ +TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +NAME="Test Write Team Port" +UUID=${UUID} +ONBOOT=yes +TEAM_MASTER=team0 +DEVICETYPE=TeamPort diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected new file mode 100644 index 00000000..339f8107 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected @@ -0,0 +1,20 @@ +VLAN=yes +TYPE=Vlan +PHYSDEV=eth0 +VLAN_ID=444 +REORDER_HDR=yes +GVRP=no +MVRP=no +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write VLAN reorder_hdr" +UUID=${UUID} +ONBOOT=no diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected new file mode 100644 index 00000000..a95a58db --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected @@ -0,0 +1,18 @@ +ESSID="Test SSID" +MODE=Managed +BAND=a +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write WiFi Band A" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected new file mode 100644 index 00000000..026993b8 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected @@ -0,0 +1,18 @@ +ESSID="Test SSID" +MODE=Managed +SSID_HIDDEN=yes +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write WiFi Hidden" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected new file mode 100644 index 00000000..f3704f10 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected @@ -0,0 +1,18 @@ +MACADDR=random +ESSID="Test SSID" +MODE=Managed +MAC_ADDRESS_RANDOMIZATION=always +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write WiFi MAC always" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected new file mode 100644 index 00000000..005c6179 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected @@ -0,0 +1,17 @@ +ESSID="Test SSID" +MODE=Managed +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write WiFi MAC default" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected new file mode 100644 index 00000000..dff17ef2 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected @@ -0,0 +1,18 @@ +MACADDR=permanent +ESSID="Test SSID" +MODE=Managed +MAC_ADDRESS_RANDOMIZATION=never +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write WiFi MAC missing" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected new file mode 100644 index 00000000..94274cf9 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected @@ -0,0 +1,18 @@ +MACADDR=permanent +ESSID="Test SSID" +MODE=Managed +MAC_ADDRESS_RANDOMIZATION=never +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write WiFi MAC never" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected new file mode 100644 index 00000000..d3db19b2 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected @@ -0,0 +1,16 @@ +ESSID=blahblah +MODE=Managed +KEY_MGMT=IEEE8021X +SECURITYMODE=leap +IEEE_8021X_IDENTITY="Bill Smith" +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Wifi LEAP" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected new file mode 100644 index 00000000..32db7262 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected @@ -0,0 +1,15 @@ +ESSID=blahblah104 +MODE=Managed +SECURITYMODE=open +DEFAULTKEY=1 +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Wifi WEP 104 ASCII" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected new file mode 100644 index 00000000..8f421cfb --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected @@ -0,0 +1,15 @@ +ETHTOOL_OPTS="autoneg off speed 10 duplex half" +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write Wired Auto-Negotiate" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected new file mode 100644 index 00000000..398a3017 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected @@ -0,0 +1,15 @@ +ETHTOOL_OPTS="wol umgs sopass 00:00:00:11:22:33" +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write Wired Wake-on-LAN" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected new file mode 100644 index 00000000..60091b7b --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected @@ -0,0 +1,22 @@ +VLAN=yes +TYPE=Vlan +DEVICE=vlan43 +PHYSDEV=eth9 +VLAN_ID=43 +REORDER_HDR=yes +GVRP=yes +VLAN_FLAGS=LOOSE_BINDING +MVRP=no +VLAN_INGRESS_PRIORITY_MAP=0:1,2:5 +VLAN_EGRESS_PRIORITY_MAP=3:1,12:3,14:7 +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=none +IPADDR=192.168.43.149 +PREFIX=24 +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Vlan test-vlan-interface" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-aliasem3 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-aliasem3 new file mode 100644 index 00000000..b7bdd781 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-aliasem3 @@ -0,0 +1,11 @@ +TYPE=Ethernet +DEVICE=aliasem0 +HWADDR=00:11:22:33:44:55 +BOOTPROTO=none +ONBOOT=yes +DNS1=4.2.2.1 +DNS2=4.2.2.2 +IPADDR=192.168.1.5 +PREFIX=24 +NETMASK=255.255.255.0 +IPV6INIT=no diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-aliasem3:1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-aliasem3:1 new file mode 100644 index 00000000..5e151875 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-aliasem3:1 @@ -0,0 +1,4 @@ +DEVICE=aliasem3:1 +IPADDR=192.168.1.6 +DEFROUTE=yes +GATEWAY=192.168.1.1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected new file mode 100644 index 00000000..56e233cc --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected @@ -0,0 +1,41 @@ +TYPE=Ethernet +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_ADVERTISE=yes +DCB_APP_FCOE_WILLING=yes +DCB_APP_FCOE_PRIORITY=5 +DCB_APP_FCOE_MODE=fabric +DCB_APP_ISCSI_ENABLE=yes +DCB_APP_ISCSI_ADVERTISE=yes +DCB_APP_ISCSI_WILLING=yes +DCB_APP_ISCSI_PRIORITY=1 +DCB_APP_FIP_ENABLE=yes +DCB_APP_FIP_ADVERTISE=yes +DCB_APP_FIP_WILLING=yes +DCB_APP_FIP_PRIORITY=3 +DCB_PFC_ENABLE=yes +DCB_PFC_ADVERTISE=yes +DCB_PFC_WILLING=yes +DCB_PFC_UP=11010110 +DCB_PG_ENABLE=yes +DCB_PG_ADVERTISE=yes +DCB_PG_WILLING=yes +DCB_PG_ID=4f6f173f +DCB_PG_PCT=10,20,15,10,2,3,35,5 +DCB_PG_UPPCT=10,20,30,40,50,10,0,25 +DCB_PG_STRICT=10110001 +DCB_PG_UP2TC=34721056 +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME=dcb-test +UUID=${UUID} +DEVICE=eth0 +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected new file mode 100644 index 00000000..ead3a047 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected @@ -0,0 +1,13 @@ +ESSID=blahblah +MODE=Managed +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="random wifi connection" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected new file mode 100644 index 00000000..7bc1ae6c --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected @@ -0,0 +1,15 @@ +ESSID=SomeSSID +MODE=Managed +MAC_ADDRESS_RANDOMIZATION=default +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="random wifi connection 2" +UUID=${UUID} +ONBOOT=yes +USERS=superman +DEFAULTKEY=1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-team-slave-enp31s0f1-142.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-team-slave-enp31s0f1-142.cexpected new file mode 100644 index 00000000..367d0ddb --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-team-slave-enp31s0f1-142.cexpected @@ -0,0 +1,12 @@ +VLAN=yes +DEVICE=enp31s0f1-142 +PHYSDEV=enp31s0f1 +VLAN_ID=142 +REORDER_HDR=yes +GVRP=no +MVRP=no +NAME=team-slave-enp31s0f1-142 +UUID=74f435bb-ede4-415a-9d48-f580b60eba04 +ONBOOT=no +TEAM_MASTER=team142 +DEVICETYPE=TeamPort diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-eth-type b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-eth-type new file mode 100644 index 00000000..8d295c76 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-eth-type @@ -0,0 +1,7 @@ +DEVICE=bond0 +NM_CONTROLLED=yes +TYPE=Ethernet +BONDING_OPTS="miimon=213 mode=4 lacp_rate=1" +BONDING_MASTER=yes +ONBOOT=yes +BOOTPROTO=none diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected new file mode 100644 index 00000000..a28c5c1c --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected @@ -0,0 +1,12 @@ +HWADDR=00:16:41:11:22:33 +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME=test-static-routes-legacy +UUID=ba60d05a-7898-820d-c2db-427a88f8f2a5 +DEVICE=eth0 +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index ee2a32d8..10a63b67 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -6,3 +6,4 @@ ADDRESS1=44.55.66.77 NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 +OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy index cb7d42bd..3f02032a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy @@ -3,5 +3,5 @@ 21.31.41.0/24 via 9.9.9.9 metric 1 via 8.8.8.8 to 32.42.52.62 - 43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2 + 43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2 cwnd 14 mtu lock 9000 initrwnd 20 window lock 10000 initcwnd lock 42 src 1.2.3.4 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual index b3259ab7..8bdf0acf 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual @@ -5,3 +5,5 @@ default via dead::beaf # routes without "via" are valid abbe::cafe/64 metric 777 + +aaaa::cccc/64 from 1111::2222/48 via 3333::4444 src 5555::6666 mtu lock 1450 cwnd 13 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index f467d864..babb068d 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -33,6 +33,7 @@ #include "nm-utils.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" +#include "nm-setting-user.h" #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-setting-ip4-config.h" @@ -81,27 +82,170 @@ shvarFile *const _f = (f); \ const char *const _key = (key); \ \ - _val_string = svGetValueString (_f, _key); \ + _val_string = svGetValueStr_cp (_f, _key); \ _val = svGetValue (_f, _key, &_to_free); \ g_assert_cmpstr (_val, ==, (expected_value)); \ g_assert ( (!_val_string && (!_val || !_val[0])) \ || ( _val_string && nm_streq0 (_val, _val_string))); \ } G_STMT_END -#define _writer_update_connection(connection, ifcfg_dir, filename) \ +static void +_assert_reread_same (NMConnection *connection, NMConnection *reread) +{ + nmtst_assert_connection_verifies_without_normalization (reread); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void +_assert_reread_same_FIXME (NMConnection *connection, NMConnection *reread) +{ + gs_unref_object NMConnection *connection_normalized = NULL; + gs_unref_hashtable GHashTable *settings = NULL; + + /* FIXME: these assertion failures should not happen as we expect + * that re-reading a connection after write yields the same result. + * + * Needs investation and fixing. */ + nmtst_assert_connection_verifies_without_normalization (reread); + + connection_normalized = nmtst_connection_duplicate_and_normalize (connection); + + g_assert (!nm_connection_compare (connection_normalized, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + g_assert (!nm_connection_diff (connection_normalized, reread, NM_SETTING_COMPARE_FLAG_EXACT, &settings)); +} + +/* dummy path for an "expected" file, meaning: don't check for expected + * written ifcfg file. */ +static const char const NO_EXPECTED[1]; + +static void +_assert_expected_content (NMConnection *connection, const char *filename, const char *expected) +{ + gs_free char *content_expectd = NULL; + gs_free char *content_written = NULL; + GError *error = NULL; + gsize len_expectd = 0; + gsize len_written = 0; + gboolean success; + const char *uuid = NULL; + + g_assert (NM_IS_CONNECTION (connection)); + g_assert (filename); + g_assert (g_file_test (filename, G_FILE_TEST_EXISTS)); + + g_assert (expected); + if (expected == NO_EXPECTED) + return; + + success = g_file_get_contents (filename, &content_written, &len_written, &error); + nmtst_assert_success (success, error); + + success = g_file_get_contents (expected, &content_expectd, &len_expectd, &error); + nmtst_assert_success (success, error); + + { + gsize i, j; + + for (i = 0; i < len_expectd; ) { + if (content_expectd[i] != '$') { + i++; + continue; + } + if (g_str_has_prefix (&content_expectd[i], "${UUID}")) { + GString *str; + + if (!uuid) { + uuid = nm_connection_get_uuid (connection); + g_assert (uuid); + } + + j = strlen (uuid); + + str = g_string_new_len (content_expectd, len_expectd); + g_string_erase (str, i, NM_STRLEN ("${UUID}")); + g_string_insert_len (str, i, uuid, j); + + g_free (content_expectd); + len_expectd = str->len; + content_expectd = g_string_free (str, FALSE); + i += j; + continue; + } + + /* other '$' is not supported. If need be, support escaping of + * '$' via '$$'. */ + g_assert_not_reached (); + } + } + + if ( len_expectd != len_written + || memcmp (content_expectd, content_written, len_expectd) != 0) { + if (g_getenv ("NMTST_IFCFG_RH_UPDATE_EXPECTED")) { + if (uuid) { + gs_free char *search = g_strdup_printf ("UUID=%s\n", uuid); + const char *s; + gsize i; + GString *str; + + s = content_written; + while (TRUE) { + s = strstr (s, search); + g_assert (s); + if ( s == content_written + || s[-1] == '\n') + break; + s += strlen (search); + } + + i = s - content_written; + + str = g_string_new_len (content_written, len_written); + g_string_erase (str, i, strlen (search)); + g_string_insert (str, i, "UUID=${UUID}\n"); + + len_written = str->len; + content_written = g_string_free (str, FALSE); + } + success = g_file_set_contents (expected, content_written, len_written, &error); + nmtst_assert_success (success, error); + } else { + g_error ("The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set NMTST_IFCFG_RH_UPDATE_EXPECTED=yes to update the files inplace\n\n>>>%s<<<\n\n>>>%s<<<\n", + filename, len_written, + expected, len_expectd, + content_written, + content_expectd); + } + } +} + +#define _writer_update_connection_reread(connection, ifcfg_dir, filename, expected, out_reread, out_reread_same) \ G_STMT_START { \ - NMConnection *_connection = (connection); \ + gs_unref_object NMConnection *_connection = nmtst_connection_duplicate_and_normalize (connection); \ + NMConnection **_out_reread = (out_reread); \ + gboolean *_out_reread_same = (out_reread_same); \ const char *_ifcfg_dir = (ifcfg_dir); \ const char *_filename = (filename); \ + const char *_expected = (expected); \ GError *_error = NULL; \ gboolean _success; \ \ - g_assert (NM_IS_CONNECTION (connection)); \ g_assert (_ifcfg_dir && _ifcfg_dir[0]); \ g_assert (_filename && _filename[0]); \ \ - _success = writer_update_connection (_connection, _ifcfg_dir, _filename, &_error); \ + _success = writer_update_connection (_connection, _ifcfg_dir, _filename, _out_reread, _out_reread_same, &_error); \ nmtst_assert_success (_success, _error); \ + _assert_expected_content (_connection, _filename, _expected); \ + } G_STMT_END + +#define _writer_update_connection(connection, ifcfg_dir, filename, expected) \ + G_STMT_START { \ + gs_unref_object NMConnection *_reread = NULL; \ + NMConnection *_c = (connection); \ + gboolean _reread_same = FALSE; \ + \ + _writer_update_connection_reread (_c, ifcfg_dir, filename, expected, &_reread, &_reread_same); \ + _assert_reread_same (_c, _reread); \ + g_assert (_reread_same); \ } G_STMT_END static NMConnection * @@ -147,14 +291,19 @@ _connection_from_file_fail (const char *filename, } static void -_writer_new_connection (NMConnection *connection, - const char *ifcfg_dir, - char **out_filename) +_writer_new_connection_reread (NMConnection *connection, + const char *ifcfg_dir, + char **out_filename, + const char *expected, + NMConnection **out_reread, + gboolean *out_reread_same) { gboolean success; GError *error = NULL; char *filename = NULL; gs_unref_object NMConnection *con_verified = NULL; + gs_unref_object NMConnection *reread_copy = NULL; + NMConnection **reread = out_reread ?: ((nmtst_get_rand_int () % 2) ? &reread_copy : NULL); g_assert (NM_IS_CONNECTION (connection)); g_assert (ifcfg_dir); @@ -164,14 +313,59 @@ _writer_new_connection (NMConnection *connection, success = writer_new_connection (con_verified, ifcfg_dir, &filename, + reread, + out_reread_same, &error); nmtst_assert_success (success, error); g_assert (filename && filename[0]); + if (reread) + nmtst_assert_connection_verifies_without_normalization (*reread); + + _assert_expected_content (con_verified, filename, expected); + if (out_filename) *out_filename = filename; else g_free (filename); + +} + +static void +_writer_new_connec_exp (NMConnection *connection, + const char *ifcfg_dir, + const char *expected, + char **out_filename) +{ + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + _writer_new_connection_reread (connection, ifcfg_dir, out_filename, expected, &reread, &reread_same); + _assert_reread_same (connection, reread); + g_assert (reread_same); +} + +static void +_writer_new_connection (NMConnection *connection, + const char *ifcfg_dir, + char **out_filename) +{ + _writer_new_connec_exp (connection, ifcfg_dir, NO_EXPECTED, out_filename); +} + +static void +_writer_new_connection_FIXME (NMConnection *connection, + const char *ifcfg_dir, + char **out_filename) +{ + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + /* FIXME: this should not happen. Fix it to use _writer_new_connection() instead. */ + + _writer_new_connection_reread (connection, ifcfg_dir, out_filename, NO_EXPECTED, &reread, &reread_same); + _assert_reread_same_FIXME (connection, reread); + g_assert (!reread_same); } static void @@ -179,6 +373,8 @@ _writer_new_connection_fail (NMConnection *connection, const char *ifcfg_dir, GError **error) { + gs_unref_object NMConnection *connection_normalized = NULL; + gs_unref_object NMConnection *reread = NULL; gboolean success; GError *local = NULL; char *filename = NULL; @@ -186,12 +382,17 @@ _writer_new_connection_fail (NMConnection *connection, g_assert (NM_IS_CONNECTION (connection)); g_assert (ifcfg_dir); - success = writer_new_connection (connection, + connection_normalized = nmtst_connection_duplicate_and_normalize (connection); + + success = writer_new_connection (connection_normalized, ifcfg_dir, &filename, + &reread, + NULL, &local); nmtst_assert_no_success (success, local); g_assert (!filename); + g_assert (!reread); g_propagate_error (error, local); } @@ -897,6 +1098,62 @@ test_read_wired_obsolete_gateway_n (void) } static void +test_user_1 (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingUser *s_user; + + connection = nmtst_create_minimal_connection ("Test User 1", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL); + s_user = NM_SETTING_USER (nm_setting_user_new ()); + +#define _USER_SET_DATA(s_user, key, val) \ + G_STMT_START { \ + GError *_error = NULL; \ + gboolean _success; \ + \ + _success = nm_setting_user_set_data ((s_user), (key), (val), &_error); \ + nmtst_assert_success (_success, _error); \ + } G_STMT_END + +#define _USER_SET_DATA_X(s_user, key) \ + _USER_SET_DATA (s_user, key, "val="key"") + + _USER_SET_DATA (s_user, "my.val1", ""); + _USER_SET_DATA_X (s_user, "my.val2"); + _USER_SET_DATA_X (s_user, "my.v__al3"); + _USER_SET_DATA_X (s_user, "my._v"); + _USER_SET_DATA_X (s_user, "my.v+"); + _USER_SET_DATA_X (s_user, "my.Av"); + _USER_SET_DATA_X (s_user, "MY.AV"); + _USER_SET_DATA_X (s_user, "MY.8V"); + _USER_SET_DATA_X (s_user, "MY.8-V"); + _USER_SET_DATA_X (s_user, "MY.8_V"); + _USER_SET_DATA_X (s_user, "MY.8+V"); + _USER_SET_DATA_X (s_user, "MY.8/V"); + _USER_SET_DATA_X (s_user, "MY.8=V"); + _USER_SET_DATA_X (s_user, "MY.-"); + _USER_SET_DATA_X (s_user, "MY._"); + _USER_SET_DATA_X (s_user, "MY.+"); + _USER_SET_DATA_X (s_user, "MY./"); + _USER_SET_DATA_X (s_user, "MY.="); + _USER_SET_DATA_X (s_user, "my.keys.1"); + _USER_SET_DATA_X (s_user, "my.other.KEY.42"); + + nm_connection_add_setting (connection, NM_SETTING (s_user)); + + _writer_new_connec_exp (connection, + TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_User_1.cexpected", + &testfile); + + reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void test_read_wired_never_default (void) { NMConnection *connection; @@ -1033,6 +1290,15 @@ test_read_wired_static_routes (void) g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32); g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "192.168.1.7"); g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); g_object_unref (connection); } @@ -1094,6 +1360,14 @@ test_read_wired_static_routes_legacy (void) g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 16); g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "7.7.7.7"); g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 10000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 42); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 20); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.2.3.4"); g_object_unref (connection); } @@ -1234,7 +1508,7 @@ test_read_wired_ipv6_manual (void) g_assert_cmpint (nm_ip_address_get_prefix (ip6_addr), ==, 96); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 2); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 3); /* Route #1 */ ip6_route = nm_setting_ip_config_get_route (s_ip6, 0); g_assert (ip6_route); @@ -1249,6 +1523,17 @@ test_read_wired_ipv6_manual (void) g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64); g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, NULL); g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, 777); + /* Route #3 */ + ip6_route = nm_setting_ip_config_get_route (s_ip6, 2); + g_assert (ip6_route); + g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "aaaa::cccc"); + g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64); + g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, "3333::4444"); + nmtst_assert_route_attribute_uint32 (ip6_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 13); + nmtst_assert_route_attribute_uint32 (ip6_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1450); + nmtst_assert_route_attribute_boolean (ip6_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_string (ip6_route, NM_IP_ROUTE_ATTRIBUTE_FROM, "1111::2222/48"); + nmtst_assert_route_attribute_string (ip6_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "5555::6666"); /* DNS Addresses */ g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 2); @@ -1567,12 +1852,16 @@ test_read_write_802_1X_subj_matches (void) g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 0), ==, "x.yourdomain.tld"); g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 1), ==, "y.yourdomain.tld"); - _writer_new_connection (connection, + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected", &testfile); + g_test_assert_expected_messages (); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*missing IEEE_8021X_CA_CERT*peap*"); + "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -1624,24 +1913,38 @@ test_read_802_1x_ttls_eapgtc (void) } static void -test_read_wired_aliases_good (void) +test_read_wired_aliases_good (gconstpointer test_data) { + const int N = GPOINTER_TO_INT (test_data); NMConnection *connection; NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; - int expected_num_addresses = 4; - const char *expected_address[4] = { "192.168.1.5", "192.168.1.6", "192.168.1.9", "192.168.1.99" }; - const char *expected_label[4] = { NULL, "aliasem0:1", "aliasem0:2", "aliasem0:99" }; + int expected_num_addresses; + const char *expected_address_0[] = { "192.168.1.5", "192.168.1.6", "192.168.1.9", "192.168.1.99", NULL }; + const char *expected_address_3[] = { "192.168.1.5", "192.168.1.6", NULL }; + const char *expected_label_0[] = { NULL, "aliasem0:1", "aliasem0:2", "aliasem0:99", NULL, }; + const char *expected_label_3[] = { NULL, "aliasem3:1", NULL, }; + const char **expected_address; + const char **expected_label; int i, j; + char path[256]; - connection = _connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-aliasem0", - NULL, TYPE_ETHERNET, NULL); + expected_address = N == 0 ? expected_address_0 : expected_address_3; + expected_label = N == 0 ? expected_label_0 : expected_label_3; + expected_num_addresses = g_strv_length ((char **) expected_address); + + nm_sprintf_buf (path, TEST_IFCFG_DIR "/network-scripts/ifcfg-aliasem%d", N); + + connection = _connection_from_file (path, NULL, TYPE_ETHERNET, NULL); /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); - g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "System aliasem0"); + if (N == 0) + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "System aliasem0"); + else + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "System aliasem3"); /* ===== IPv4 SETTING ===== */ @@ -1680,6 +1983,7 @@ test_read_wired_aliases_good (void) } /* Gateway */ + g_assert (!nm_setting_ip_config_get_never_default (s_ip4)); g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1"); for (i = 0; i < expected_num_addresses; i++) @@ -1803,8 +2107,9 @@ test_clear_master (void) g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, "bridge"); /* 2. write the connection to a new file */ - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-System_test-bridge-component-a.cexpected", &testfile); /* 3. clear master and slave-type */ @@ -1816,10 +2121,13 @@ test_clear_master (void) g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, NULL); g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NULL); + nmtst_assert_connection_verifies_after_normalization (connection, 0, 0); + /* 4. update the connection on disk */ _writer_update_connection (connection, TEST_SCRATCH_DIR "/network-scripts/", - testfile); + testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-System_test-bridge-component-b.cexpected"); keyfile = utils_get_keys_path (testfile); g_assert (!g_file_test (keyfile, G_FILE_TEST_EXISTS)); @@ -1902,9 +2210,9 @@ test_write_dns_options (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -3120,8 +3428,9 @@ test_write_wifi_hidden (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected", &testfile); f = _svOpenFile (testfile); @@ -3169,6 +3478,7 @@ test_write_wifi_mac_random (gconstpointer user_data) const char *name, *write_expected; gpointer value_p; NMSettingMacRandomization value; + char cexpected[NM_STRLEN (TEST_IFCFG_DIR) + 100]; nmtst_test_data_unpack (user_data, &name, &value_p, &write_expected); value = GPOINTER_TO_INT (value_p); @@ -3203,8 +3513,9 @@ test_write_wifi_mac_random (gconstpointer user_data) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + nm_sprintf_buf (cexpected, TEST_IFCFG_DIR"/network-scripts/ifcfg-Test_Write_WiFi_MAC_%s.cexpected", name), &testfile); f = _svOpenFile (testfile); @@ -3255,12 +3566,13 @@ test_write_wired_wake_on_lan (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected", &testfile); f = _svOpenFile (testfile); - val = svGetValueString (f, "ETHTOOL_OPTS"); + val = svGetValueStr_cp (f, "ETHTOOL_OPTS"); g_assert (val); g_assert (strstr (val, "wol")); g_assert (strstr (val, "sopass 00:00:00:11:22:33")); @@ -3290,12 +3602,13 @@ test_write_wired_auto_negotiate_off (void) NM_SETTING_WIRED_SPEED, 10, NULL); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected", &testfile); f = _svOpenFile (testfile); - val = svGetValueString (f, "ETHTOOL_OPTS"); + val = svGetValueStr_cp (f, "ETHTOOL_OPTS"); g_assert (val); g_assert (strstr (val, "autoneg off")); g_assert (strstr (val, "speed 10")); @@ -3329,7 +3642,7 @@ test_write_wired_auto_negotiate_on (void) &testfile); f = _svOpenFile (testfile); - val = svGetValueString (f, "ETHTOOL_OPTS"); + val = svGetValueStr_cp (f, "ETHTOOL_OPTS"); g_assert (val); g_assert (strstr (val, "autoneg on")); g_assert (!strstr (val, "speed")); @@ -3403,8 +3716,9 @@ test_write_wifi_band_a (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected", &testfile); f = _svOpenFile (testfile); @@ -3753,6 +4067,12 @@ test_write_wired_static (void) route6 = nm_ip_route_new (AF_INET6, "::", 128, "2222:aaaa::9999", 1, &error); g_assert_no_error (error); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_TOS, g_variant_new_byte (0xb8)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (100)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1280)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, g_variant_new_boolean (TRUE)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_FROM, g_variant_new_string ("2222::bbbb/32")); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("::42")); nm_setting_ip_config_add_route (s_ip6, route6); nm_ip_route_unref (route6); @@ -3766,9 +4086,9 @@ test_write_wired_static (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); route6file = utils_get_route6_path (testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -4082,7 +4402,7 @@ test_write_wired_static_ip6_only_gw (gconstpointer user_data) nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); ifcfg = _svOpenFile (testfile); - written_ifcfg_gateway = svGetValueString (ifcfg, "IPV6_DEFAULTGW"); + written_ifcfg_gateway = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW"); svCloseFile (ifcfg); /* access the gateway from the loaded connection. */ @@ -4147,8 +4467,9 @@ test_read_write_static_routes_legacy (void) * we can clean up after the written connection in both the original * source tree and for 'make distcheck'. */ - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR_TMP, + TEST_IFCFG_DIR "/network-scripts/ifcfg-test-static-routes-legacy.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -4436,9 +4757,9 @@ test_write_wired_8021x_tls (gconstpointer test_data) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -4486,15 +4807,15 @@ test_write_wired_8021x_tls (gconstpointer test_data) } /* Clean up created certs and keys */ - tmp = utils_cert_path (testfile, "ca-cert.der"); + tmp = utils_cert_path (testfile, "ca-cert", "der"); nmtst_file_unlink_if_exists (tmp); g_free (tmp); - tmp = utils_cert_path (testfile, "client-cert.der"); + tmp = utils_cert_path (testfile, "client-cert", "der"); nmtst_file_unlink_if_exists (tmp); g_free (tmp); - tmp = utils_cert_path (testfile, "private-key.pem"); + tmp = utils_cert_path (testfile, "private-key", "pem"); nmtst_file_unlink_if_exists (tmp); g_free (tmp); } @@ -4562,22 +4883,22 @@ test_write_wired_aliases (void) /* Create some pre-existing alias files, to make sure they get overwritten / deleted. */ ifcfg = svCreateFile (TEST_SCRATCH_ALIAS_BASE ":2"); - svSetValueString (ifcfg, "DEVICE", "alias0:2"); - svSetValueString (ifcfg, "IPADDR", "192.168.1.2"); + svSetValueStr (ifcfg, "DEVICE", "alias0:2"); + svSetValueStr (ifcfg, "IPADDR", "192.168.1.2"); svWriteFile (ifcfg, 0644, NULL); svCloseFile (ifcfg); g_assert (g_file_test (TEST_SCRATCH_ALIAS_BASE ":2", G_FILE_TEST_EXISTS)); ifcfg = svCreateFile (TEST_SCRATCH_ALIAS_BASE ":5"); - svSetValueString (ifcfg, "DEVICE", "alias0:5"); - svSetValueString (ifcfg, "IPADDR", "192.168.1.5"); + svSetValueStr (ifcfg, "DEVICE", "alias0:5"); + svSetValueStr (ifcfg, "IPADDR", "192.168.1.5"); svWriteFile (ifcfg, 0644, NULL); svCloseFile (ifcfg); g_assert (g_file_test (TEST_SCRATCH_ALIAS_BASE ":5", G_FILE_TEST_EXISTS)); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); /* Re-check the alias files */ g_assert (g_file_test (TEST_SCRATCH_ALIAS_BASE ":2", G_FILE_TEST_EXISTS)); @@ -5263,8 +5584,9 @@ test_write_wifi_wep_104_ascii (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -5347,8 +5669,9 @@ test_write_wifi_leap (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -5429,9 +5752,9 @@ test_write_wifi_leap_secret_flags (gconstpointer data) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -5701,6 +6024,11 @@ test_write_wifi_wpa_eap_tls (void) nm_connection_add_setting (connection, NM_SETTING (s_8021x)); g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL); + g_object_set (s_8021x, + NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, + (guint) (NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE | + NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE), + NULL); nm_setting_802_1x_add_eap_method (s_8021x, "tls"); @@ -6080,7 +6408,8 @@ test_write_wifi_wpa_then_open (void) /* Write it back out */ _writer_update_connection (connection, TEST_SCRATCH_DIR "/network-scripts/", - testfile); + testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-random_wifi_connection.cexpected"); keyfile = utils_get_keys_path (testfile); g_assert (!g_file_test (keyfile, G_FILE_TEST_EXISTS)); @@ -6199,7 +6528,8 @@ test_write_wifi_wpa_then_wep_with_perms (void) /* Write it back out */ _writer_update_connection (connection, TEST_SCRATCH_DIR "/network-scripts/", - testfile); + testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-random_wifi_connection_2.cexpected"); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -6498,8 +6828,9 @@ test_write_permissions (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Permissions.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -6572,9 +6903,9 @@ test_write_wifi_wep_agent_keys (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -6953,8 +7284,9 @@ test_write_bridge_component (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -7198,8 +7530,9 @@ test_write_vlan (void) connection = _connection_from_file (TEST_IFCFG_VLAN_INTERFACE, NULL, TYPE_VLAN, NULL); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected", &testfile); } @@ -7278,8 +7611,9 @@ test_write_vlan_reorder_hdr (void) NM_SETTING_VLAN_FLAGS, 1, NULL); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -7374,6 +7708,28 @@ test_read_bond_main (void) } static void +test_read_bond_eth_type (void) +{ + NMConnection *connection; + NMSettingBond *s_bond; + + connection = _connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-bond-eth-type", + NULL, TYPE_ETHERNET,NULL); + + g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "bond0"); + + /* ===== Bonding SETTING ===== */ + + s_bond = nm_connection_get_setting_bond (connection); + g_assert (s_bond); + + g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON), ==, "213"); + g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_LACP_RATE), ==, "1"); + + g_object_unref (connection); +} + +static void test_write_bond_main (void) { nmtst_auto_unlinkfile char *testfile = NULL; @@ -7436,8 +7792,9 @@ test_write_bond_main (void) nmtst_assert_connection_verifies_without_normalization (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_BOND, NULL); @@ -7830,8 +8187,9 @@ test_write_dcb_basic (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts//ifcfg-dcb-test.cexpected", &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -8228,8 +8586,9 @@ test_write_team_port (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Team_Port.cexpected", &testfile); f = _svOpenFile (testfile); @@ -8269,6 +8628,69 @@ test_read_team_port_empty_config (void) } static void +test_team_reread_slave (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection_1 = NULL; + gs_unref_object NMConnection *connection_2 = NULL; + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + NMSettingConnection *s_con; + + connection_1 = nmtst_create_connection_from_keyfile ( + "[connection]\n" + "id=team-slave-enp31s0f1-142\n" + "uuid=74f435bb-ede4-415a-9d48-f580b60eba04\n" + "type=vlan\n" + "autoconnect=false\n" + "interface-name=enp31s0f1-142\n" + "master=team142\n" + "permissions=\n" + "slave-type=team\n" + "\n" + "[vlan]\n" + "egress-priority-map=\n" + "flags=1\n" + "id=142\n" + "ingress-priority-map=\n" + "parent=enp31s0f1\n" + , "/test_team_reread_slave", NULL); + + /* to double-check keyfile syntax, re-create the connection by hand. */ + connection_2 = nmtst_create_minimal_connection ("team-slave-enp31s0f1-142", "74f435bb-ede4-415a-9d48-f580b60eba04", NM_SETTING_VLAN_SETTING_NAME, &s_con); + g_object_set (s_con, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NM_SETTING_CONNECTION_INTERFACE_NAME, "enp31s0f1-142", + NM_SETTING_CONNECTION_MASTER, "team142", + NM_SETTING_CONNECTION_SLAVE_TYPE, "team", + NULL); + g_object_set (nm_connection_get_setting_vlan (connection_2), + NM_SETTING_VLAN_FLAGS, 1, + NM_SETTING_VLAN_ID, 142, + NM_SETTING_VLAN_PARENT, "enp31s0f1", + NULL); + nm_connection_add_setting (connection_2, nm_setting_team_port_new ()); + nmtst_connection_normalize (connection_2); + + nmtst_assert_connection_equals (connection_1, FALSE, connection_2, FALSE); + + _writer_new_connection_reread ((nmtst_get_rand_int () % 2) ? connection_1 : connection_2, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-team-slave-enp31s0f1-142.cexpected", + &reread, + &reread_same); + _assert_reread_same ((nmtst_get_rand_int () % 2) ? connection_1 : connection_2, reread); + g_assert (reread_same); + g_clear_object (&reread); + + reread = _connection_from_file (testfile, NULL, TYPE_VLAN, + NULL); + nmtst_assert_connection_equals ((nmtst_get_rand_int () % 2) ? connection_1 : connection_2, FALSE, + reread, FALSE); +} + +static void test_read_proxy_basic (void) { NMConnection *connection; @@ -8327,8 +8749,9 @@ test_write_proxy_basic (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected", &testfile); f = _svOpenFile (testfile); @@ -8682,12 +9105,12 @@ test_write_unknown (gconstpointer test_data) sv = _svOpenFile (testfile); - svFileSetName (sv, filename_tmp_1); - svFileSetModified (sv); + svFileSetName_test_only (sv, filename_tmp_1); + svFileSetModified_test_only (sv); if (g_str_has_suffix (testfile, "ifcfg-test-write-unknown-4")) { _svGetValue_check (sv, "NAME", "l4x"); - _svGetValue_check (sv, "NAME2", NULL); + _svGetValue_check (sv, "NAME2", ""); _svGetValue_check (sv, "NAME3", "name3-value"); svSetValue (sv, "NAME", "set-by-test1"); @@ -8944,6 +9367,8 @@ int main (int argc, char **argv) nmtst_add_test_func (TPATH "wired/read/manual/3", test_read_wired_ipv4_manual, TEST_IFCFG_DIR "/network-scripts/ifcfg-test-wired-ipv4-manual-3", "System test-wired-ipv4-manual-3"); nmtst_add_test_func (TPATH "wired/read/manual/4", test_read_wired_ipv4_manual, TEST_IFCFG_DIR "/network-scripts/ifcfg-test-wired-ipv4-manual-4", "System test-wired-ipv4-manual-4"); + g_test_add_func (TPATH "user/1", test_user_1); + g_test_add_func (TPATH "wired/ipv6-manual", test_read_wired_ipv6_manual); nmtst_add_test_func (TPATH "wired-ipv6-only/0", test_read_wired_ipv6_only, TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-ipv6-only", "System test-wired-ipv6-only"); @@ -8960,7 +9385,8 @@ int main (int argc, char **argv) g_test_add_func (TPATH "802-1x/subj-matches", test_read_write_802_1X_subj_matches); g_test_add_func (TPATH "802-1x/ttls-eapgtc", test_read_802_1x_ttls_eapgtc); - g_test_add_func (TPATH "wired/read/aliases", test_read_wired_aliases_good); + g_test_add_data_func (TPATH "wired/read/aliases/good/0", GINT_TO_POINTER (0), test_read_wired_aliases_good); + g_test_add_data_func (TPATH "wired/read/aliases/good/3", GINT_TO_POINTER (3), test_read_wired_aliases_good); g_test_add_func (TPATH "wired/read/aliases/bad1", test_read_wired_aliases_bad_1); g_test_add_func (TPATH "wired/read/aliases/bad2", test_read_wired_aliases_bad_2); g_test_add_func (TPATH "wifi/read/open", test_read_wifi_open); @@ -9112,6 +9538,7 @@ int main (int argc, char **argv) g_test_add_data_func (TPATH "fcoe/write-vn2vn", (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN, test_write_fcoe_mode); g_test_add_func (TPATH "bond/read-master", test_read_bond_main); + g_test_add_func (TPATH "bond/read-master-eth-type", test_read_bond_eth_type); g_test_add_func (TPATH "bond/read-slave", test_read_bond_slave); g_test_add_func (TPATH "bond/read-slave-ib", test_read_bond_slave_ib); g_test_add_func (TPATH "bond/write-master", test_write_bond_main); @@ -9133,6 +9560,7 @@ int main (int argc, char **argv) g_test_add_data_func (TPATH "team/read-port-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-2", test_read_team_port); g_test_add_func (TPATH "team/write-port", test_write_team_port); g_test_add_func (TPATH "team/read-port-empty-config", test_read_team_port_empty_config); + g_test_add_func (TPATH "team/reread-slave", test_team_reread_slave); g_test_add_func (TPATH "proxy/read-proxy-basic", test_read_proxy_basic); g_test_add_func (TPATH "proxy/write-proxy-basic", test_write_proxy_basic); diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c index 84f2d3f4..c5129fea 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c +++ b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c @@ -31,6 +31,7 @@ #include "settings/nm-settings-plugin.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" +#include "nm-setting-metadata.h" #include "nms-ifnet-net-utils.h" #include "nms-ifnet-wpa-parser.h" @@ -1688,96 +1689,43 @@ error: return NULL; } -typedef NMSetting8021xCKScheme (*SchemeFunc) (NMSetting8021x * setting); -typedef const char *(*PathFunc) (NMSetting8021x * setting); -typedef GBytes *(*BlobFunc) (NMSetting8021x * setting); - -typedef struct ObjectType { - const char *setting_key; - SchemeFunc scheme_func; - PathFunc path_func; - BlobFunc blob_func; - const char *conn_name_key; - const char *suffix; -} ObjectType; - -static const ObjectType ca_type = { - NM_SETTING_802_1X_CA_CERT, - nm_setting_802_1x_get_ca_cert_scheme, - nm_setting_802_1x_get_ca_cert_path, - nm_setting_802_1x_get_ca_cert_blob, - "ca_cert", - "ca-cert.der" -}; - -static const ObjectType phase2_ca_type = { - NM_SETTING_802_1X_PHASE2_CA_CERT, - nm_setting_802_1x_get_phase2_ca_cert_scheme, - nm_setting_802_1x_get_phase2_ca_cert_path, - nm_setting_802_1x_get_phase2_ca_cert_blob, - "ca_cert2", - "inner-ca-cert.der" -}; - -static const ObjectType client_type = { - NM_SETTING_802_1X_CLIENT_CERT, - nm_setting_802_1x_get_client_cert_scheme, - nm_setting_802_1x_get_client_cert_path, - nm_setting_802_1x_get_client_cert_blob, - "client_cert", - "client-cert.der" -}; - -static const ObjectType phase2_client_type = { - NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - nm_setting_802_1x_get_phase2_client_cert_scheme, - nm_setting_802_1x_get_phase2_client_cert_path, - nm_setting_802_1x_get_phase2_client_cert_blob, - "client_cert2", - "inner-client-cert.der" -}; - -static const ObjectType pk_type = { - NM_SETTING_802_1X_PRIVATE_KEY, - nm_setting_802_1x_get_private_key_scheme, - nm_setting_802_1x_get_private_key_path, - nm_setting_802_1x_get_private_key_blob, - "private_key", - "private-key.pem" -}; - -static const ObjectType phase2_pk_type = { - NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - nm_setting_802_1x_get_phase2_private_key_scheme, - nm_setting_802_1x_get_phase2_private_key_path, - nm_setting_802_1x_get_phase2_private_key_blob, - "private_key2", - "inner-private-key.pem" -}; - -static const ObjectType p12_type = { - NM_SETTING_802_1X_PRIVATE_KEY, - nm_setting_802_1x_get_private_key_scheme, - nm_setting_802_1x_get_private_key_path, - nm_setting_802_1x_get_private_key_blob, - "private_key", - "private-key.p12" -}; - -static const ObjectType phase2_p12_type = { - NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - nm_setting_802_1x_get_phase2_private_key_scheme, - nm_setting_802_1x_get_phase2_private_key_path, - nm_setting_802_1x_get_phase2_private_key_blob, - "private_key2", - "inner-private-key.p12" +typedef struct Setting8021xSchemeVtable { + const NMSetting8021xSchemeVtable *vtable; + const char *ifnet_key; +} Setting8021xSchemeVtable; + +static const Setting8021xSchemeVtable setting_8021x_scheme_vtable[] = { + [NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT], + .ifnet_key = "ca_cert", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT], + .ifnet_key = "ca_cert2", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT], + .ifnet_key = "client_cert", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT], + .ifnet_key = "client_cert2", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY], + .ifnet_key = "private_key", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY], + .ifnet_key = "private_key2", + }, }; static gboolean write_object (NMSetting8021x *s_8021x, const char *conn_name, GBytes *override_data, - const ObjectType *objtype, + const Setting8021xSchemeVtable *objtype, GError **error) { NMSetting8021xCKScheme scheme; @@ -1792,13 +1740,13 @@ write_object (NMSetting8021x *s_8021x, */ blob = override_data; else { - scheme = (*(objtype->scheme_func)) (s_8021x); + scheme = (*(objtype->vtable->scheme_func)) (s_8021x); switch (scheme) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: - blob = (*(objtype->blob_func)) (s_8021x); + blob = (*(objtype->vtable->blob_func)) (s_8021x); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: - path = (*(objtype->path_func)) (s_8021x); + path = (*(objtype->vtable->path_func)) (s_8021x); break; default: break; @@ -1809,8 +1757,8 @@ write_object (NMSetting8021x *s_8021x, * may have been sent. */ if (path) { - wpa_set_data (conn_name, (gchar *) objtype->conn_name_key, - (gchar *) path); + wpa_set_data (conn_name, (gchar *) objtype->ifnet_key, + (gchar *) path); return TRUE; } @@ -1828,17 +1776,16 @@ write_8021x_certs (NMSetting8021x *s_8021x, GError **error) { char *password = NULL; - const ObjectType *otype = NULL; + const Setting8021xSchemeVtable *otype = NULL; gboolean is_pkcs12 = FALSE, success = FALSE; GBytes *blob = NULL; GBytes *enc_key = NULL; gchar *generated_pw = NULL; /* CA certificate */ - if (phase2) - otype = &phase2_ca_type; - else - otype = &ca_type; + otype = phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT]; if (!write_object (s_8021x, conn_name, NULL, otype, error)) return FALSE; @@ -1864,14 +1811,13 @@ write_8021x_certs (NMSetting8021x *s_8021x, nm_setting_802_1x_get_private_key_password (s_8021x); } - if (is_pkcs12) - otype = phase2 ? &phase2_p12_type : &p12_type; - else - otype = phase2 ? &phase2_pk_type : &pk_type; + otype = phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY]; - if ((*(otype->scheme_func)) (s_8021x) == + if ((*(otype->vtable->scheme_func)) (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB) - blob = (*(otype->blob_func)) (s_8021x); + blob = (*(otype->vtable->blob_func)) (s_8021x); /* Only do the private key re-encrypt dance if we got the raw key data, which * by definition will be unencrypted. If we're given a direct path to the @@ -1883,7 +1829,7 @@ write_8021x_certs (NMSetting8021x *s_8021x, /* Encrypt the unencrypted private key with the fake password */ tmp_enc_key = nm_utils_rsa_key_encrypt (g_bytes_get_data (blob, NULL), g_bytes_get_size (blob), - password, &generated_pw, error); + password, &generated_pw, error); if (!tmp_enc_key) goto out; @@ -1906,12 +1852,11 @@ write_8021x_certs (NMSetting8021x *s_8021x, /* Client certificate */ if (is_pkcs12) { wpa_set_data (conn_name, - phase2 ? "client_cert2" : "client_cert", NULL); + phase2 ? "client_cert2" : "client_cert", NULL); } else { - if (phase2) - otype = &phase2_client_type; - else - otype = &client_type; + otype = phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT]; /* Save the client certificate */ if (!write_object (s_8021x, conn_name, NULL, otype, error)) diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h index e6c0e88c..51bc34b9 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h +++ b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h @@ -22,7 +22,7 @@ #ifndef _CONNECTION_PARSER_H #define _CONNECTION_PARSER_H -#include <nm-connection.h> +#include "nm-connection.h" #include "nms-ifnet-net-parser.h" diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-utils.h b/src/settings/plugins/ifnet/nms-ifnet-net-utils.h index 79d44642..cc273aa7 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-net-utils.h +++ b/src/settings/plugins/ifnet/nms-ifnet-net-utils.h @@ -26,8 +26,8 @@ #include <arpa/inet.h> -#include <nm-setting-ip6-config.h> -#include <nm-setting-ip4-config.h> +#include "nm-setting-ip6-config.h" +#include "nm-setting-ip4-config.h" #include "nms-ifnet-net-parser.h" diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.h b/src/settings/plugins/ifupdown/nms-ifupdown-parser.h index 36e52e2c..6a86bf86 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.h +++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.h @@ -24,7 +24,7 @@ #ifndef __PARSER_H__ #define __PARSER_H__ -#include <nm-connection.h> +#include "nm-connection.h" #include "nms-ifupdown-interface-parser.h" diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index 211e5d57..189b6e69 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -28,8 +28,8 @@ #include <string.h> #include <arpa/inet.h> -#include <gudev/gudev.h> #include <gmodule.h> +#include <libudev.h> #include "nm-setting-connection.h" #include "nm-dbus-interface.h" @@ -42,6 +42,7 @@ #include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-config.h" +#include "nm-utils/nm-udev-utils.h" #include "nms-ifupdown-interface-parser.h" #include "nms-ifupdown-connection.h" @@ -62,7 +63,7 @@ /*****************************************************************************/ typedef struct { - GUdevClient *client; + NMUdevClient *udev_client; GHashTable *connections; /* /e/n/i block name :: NMIfupdownConnection */ @@ -103,21 +104,21 @@ NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfupdown, settings_plugin_ifupdown_get static void bind_device_to_connection (SettingsPluginIfupdown *self, - GUdevDevice *device, + struct udev_device *device, NMIfupdownConnection *exported) { NMSettingWired *s_wired; NMSettingWireless *s_wifi; const char *iface, *address; - iface = g_udev_device_get_name (device); + iface = udev_device_get_sysname (device); if (!iface) { nm_log_warn (LOGD_SETTINGS, "failed to get ifname for device."); return; } - address = g_udev_device_get_sysfs_attr (device, "address"); - if (!address || !strlen (address)) { + address = udev_device_get_sysattr_value (device, "address"); + if (!address || !address[0]) { nm_log_warn (LOGD_SETTINGS, "failed to get MAC address for %s", iface); return; } @@ -142,14 +143,14 @@ bind_device_to_connection (SettingsPluginIfupdown *self, } static void -udev_device_added (SettingsPluginIfupdown *self, GUdevDevice *device) +udev_device_added (SettingsPluginIfupdown *self, struct udev_device *device) { SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); const char *iface, *path; NMIfupdownConnection *exported; - iface = g_udev_device_get_name (device); - path = g_udev_device_get_sysfs_path (device); + iface = udev_device_get_sysname (device); + path = udev_device_get_syspath (device); if (!iface || !path) return; @@ -165,7 +166,7 @@ udev_device_added (SettingsPluginIfupdown *self, GUdevDevice *device) return; } - g_hash_table_insert (priv->kernel_ifaces, g_strdup (iface), g_object_ref (device)); + g_hash_table_insert (priv->kernel_ifaces, g_strdup (iface), udev_device_ref (device)); if (exported) bind_device_to_connection (self, device, exported); @@ -175,13 +176,13 @@ udev_device_added (SettingsPluginIfupdown *self, GUdevDevice *device) } static void -udev_device_removed (SettingsPluginIfupdown *self, GUdevDevice *device) +udev_device_removed (SettingsPluginIfupdown *self, struct udev_device *device) { SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); const char *iface, *path; - iface = g_udev_device_get_name (device); - path = g_udev_device_get_sysfs_path (device); + iface = udev_device_get_sysname (device); + path = udev_device_get_syspath (device); if (!iface || !path) return; @@ -195,13 +196,13 @@ udev_device_removed (SettingsPluginIfupdown *self, GUdevDevice *device) } static void -udev_device_changed (SettingsPluginIfupdown *self, GUdevDevice *device) +udev_device_changed (SettingsPluginIfupdown *self, struct udev_device *device) { SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); const char *iface, *path; - iface = g_udev_device_get_name (device); - path = g_udev_device_get_sysfs_path (device); + iface = udev_device_get_sysname (device); + path = udev_device_get_syspath (device); if (!iface || !path) return; @@ -215,20 +216,21 @@ udev_device_changed (SettingsPluginIfupdown *self, GUdevDevice *device) } static void -handle_uevent (GUdevClient *client, - const char *action, - GUdevDevice *device, +handle_uevent (NMUdevClient *client, + struct udev_device *device, gpointer user_data) { SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (user_data); const char *subsys; + const char *action; + + action = udev_device_get_action (device); g_return_if_fail (action != NULL); /* A bit paranoid */ - subsys = g_udev_device_get_subsystem (device); - g_return_if_fail (subsys != NULL); - g_return_if_fail (strcmp (subsys, "net") == 0); + subsys = udev_device_get_subsystem (device); + g_return_if_fail (nm_streq0 (subsys, "net")); if (!strcmp (action, "add")) udev_device_added (self, device); @@ -271,7 +273,7 @@ get_unmanaged_specs (NMSettingsPlugin *config) SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE ((SettingsPluginIfupdown *) config); GSList *specs = NULL; GHashTableIter iter; - GUdevDevice *device; + struct udev_device *device; const char *iface; if (!ALWAYS_UNMANAGE && !priv->unmanage_well_known) @@ -284,7 +286,7 @@ get_unmanaged_specs (NMSettingsPlugin *config) while (g_hash_table_iter_next (&iter, (gpointer) &iface, (gpointer) &device)) { const char *address; - address = g_udev_device_get_sysfs_attr (device, "address"); + address = udev_device_get_sysattr_value (device, "address"); if (address) specs = g_slist_append (specs, g_strdup_printf ("mac:%s", address)); else @@ -318,17 +320,23 @@ get_property (GObject *object, guint prop_id, /*****************************************************************************/ static void +_udev_device_unref (gpointer ptr) +{ + udev_device_unref (ptr); +} + +static void init (NMSettingsPlugin *config) { SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (config); SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); GHashTable *auto_ifaces; if_block *block = NULL; - GList *keys, *iter; + struct udev_enumerate *enumerate; + struct udev_list_entry *keys; GHashTableIter con_iter; const char *block_name; NMIfupdownConnection *connection; - const char *subsys[2] = { "net", NULL }; auto_ifaces = g_hash_table_new (g_str_hash, g_str_equal); @@ -336,18 +344,15 @@ init (NMSettingsPlugin *config) priv->connections = g_hash_table_new (g_str_hash, g_str_equal); if(!priv->kernel_ifaces) - priv->kernel_ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->kernel_ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _udev_device_unref); if(!priv->eni_ifaces) priv->eni_ifaces = g_hash_table_new (g_str_hash, g_str_equal); nm_log_info (LOGD_SETTINGS, "init!"); - priv->client = g_udev_client_new (subsys); - if (!priv->client) { - nm_log_warn (LOGD_SETTINGS, " error initializing libgudev"); - } else - g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); + priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, + handle_uevent, self); /* Read in all the interfaces */ ifparser_init (ENI_INTERFACES_FILE, 0); @@ -445,12 +450,20 @@ init (NMSettingsPlugin *config) nm_log_info (LOGD_SETTINGS, "management mode: %s", priv->unmanage_well_known ? "unmanaged" : "managed"); /* Add well-known interfaces */ - keys = g_udev_client_query_by_subsystem (priv->client, "net"); - for (iter = keys; iter; iter = g_list_next (iter)) { - udev_device_added (self, G_UDEV_DEVICE (iter->data)); - g_object_unref (G_UDEV_DEVICE (iter->data)); + enumerate = nm_udev_client_enumerate_new (priv->udev_client); + udev_enumerate_scan_devices (enumerate); + keys = udev_enumerate_get_list_entry (enumerate); + for (; keys; keys = udev_list_entry_get_next (keys)) { + struct udev_device *udevice; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), + udev_list_entry_get_name (keys)); + if (udevice) { + udev_device_added (self, udevice); + udev_device_unref (udevice); + } } - g_list_free (keys); + udev_enumerate_unref (enumerate); /* Now if we're running in managed mode, let NM know there are new connections */ if (!priv->unmanage_well_known) { @@ -483,7 +496,8 @@ dispose (GObject *object) g_clear_pointer (&priv->kernel_ifaces, g_hash_table_destroy); g_clear_pointer (&priv->eni_ifaces, g_hash_table_destroy); - g_clear_object (&priv->client); + + priv->udev_client = nm_udev_client_unref (priv->udev_client); G_OBJECT_CLASS (settings_plugin_ifupdown_parent_class)->dispose (object); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index ff654acf..bd07d263 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -58,12 +58,16 @@ commit_changes (NMSettingsConnection *connection, { char *path = NULL; GError *error = NULL; + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; if (!nms_keyfile_writer_connection (NM_CONNECTION (connection), nm_settings_connection_get_filename (connection), NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), &path, + &reread, + &reread_same, &error)) { callback (connection, error, user_data); g_clear_error (&error); @@ -89,6 +93,18 @@ commit_changes (NMSettingsConnection *connection, NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); } + if (reread && !reread_same) { + gs_free_error GError *local = NULL; + + if (!nm_settings_connection_replace_settings (connection, reread, FALSE, "update-during-write", &local)) { + nm_log_warn (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection failed: %s", + NMS_KEYFILE_CONNECTION_LOG_ARG (connection), local->message); + } else { + nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection", + NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); + } + } + g_free (path); NM_SETTINGS_CONNECTION_CLASS (nms_keyfile_connection_parent_class)->commit_changes (connection, diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index 97306d66..4af80142 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -77,7 +77,7 @@ G_DEFINE_TYPE_EXTENDED (NMSKeyfilePlugin, nms_keyfile_plugin, G_TYPE_OBJECT, 0, #define _NMLOG_PREFIX_NAME "keyfile" #define _NMLOG_DOMAIN LOGD_SETTINGS #define _NMLOG(level, ...) \ - nm_log ((level), _NMLOG_DOMAIN, \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME": " \ _NM_UTILS_MACRO_REST (__VA_ARGS__)) @@ -530,12 +530,19 @@ add_connection (NMSettingsPlugin *config, { NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN (config); gs_free char *path = NULL; + gs_unref_object NMConnection *reread = NULL; if (save_to_disk) { - if (!nms_keyfile_writer_connection (connection, NULL, FALSE, &path, error)) + if (!nms_keyfile_writer_connection (connection, + NULL, + FALSE, + &path, + &reread, + NULL, + error)) return NULL; } - return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); + return NM_SETTINGS_CONNECTION (update_connection (self, reread ?: connection, path, NULL, FALSE, NULL, error)); } static GSList * diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c index 39a01480..cb4b8379 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c @@ -56,6 +56,10 @@ _fmt_warn (const char *group, NMSetting *setting, const char *property_name, con return message; } +typedef struct { + bool verbose; +} HandlerReadData; + static gboolean _handler_read (GKeyFile *keyfile, NMConnection *connection, @@ -64,11 +68,16 @@ _handler_read (GKeyFile *keyfile, void *user_data, GError **error) { + const HandlerReadData *handler_data = user_data; + if (type == NM_KEYFILE_READ_TYPE_WARN) { NMKeyfileReadTypeDataWarn *warn_data = type_data; NMLogLevel level; char *message_free = NULL; + if (!handler_data->verbose) + return TRUE; + if (warn_data->severity > NM_KEYFILE_WARN_SEVERITY_WARN) level = LOGL_ERR; else if (warn_data->severity >= NM_KEYFILE_WARN_SEVERITY_WARN) @@ -78,7 +87,9 @@ _handler_read (GKeyFile *keyfile, else level = LOGL_INFO; - nm_log (level, LOGD_SETTINGS, "keyfile: %s", + nm_log (level, LOGD_SETTINGS, NULL, + nm_connection_get_uuid (connection), + "keyfile: %s", _fmt_warn (warn_data->group, warn_data->setting, warn_data->property_name, warn_data->message, &message_free)); @@ -89,6 +100,19 @@ _handler_read (GKeyFile *keyfile, } NMConnection * +nms_keyfile_reader_from_keyfile (GKeyFile *key_file, + const char *filename, + gboolean verbose, + GError **error) +{ + HandlerReadData data = { + .verbose = verbose, + }; + + return nm_keyfile_read (key_file, filename, NULL, _handler_read, &data, error); +} + +NMConnection * nms_keyfile_reader_from_file (const char *filename, GError **error) { GKeyFile *key_file; @@ -122,7 +146,7 @@ nms_keyfile_reader_from_file (const char *filename, GError **error) if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error)) goto out; - connection = nm_keyfile_read (key_file, filename, NULL, _handler_read, NULL, error); + connection = nms_keyfile_reader_from_keyfile (key_file, filename, TRUE, error); if (!connection) goto out; diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.h b/src/settings/plugins/keyfile/nms-keyfile-reader.h index c52fea31..b60c1e69 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.h +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.h @@ -22,7 +22,12 @@ #ifndef __NMS_KEYFILE_READER_H__ #define __NMS_KEYFILE_READER_H__ -#include <nm-connection.h> +#include "nm-connection.h" + +NMConnection *nms_keyfile_reader_from_keyfile (GKeyFile *key_file, + const char *filename, + gboolean verbose, + GError **error); NMConnection *nms_keyfile_reader_from_file (const char *filename, GError **error); diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c index 95897db3..92ed2849 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c @@ -32,6 +32,7 @@ #include "nm-keyfile-internal.h" #include "nms-keyfile-utils.h" +#include "nms-keyfile-reader.h" /*****************************************************************************/ @@ -51,12 +52,12 @@ cert_writer (NMConnection *connection, NMSetting8021xCKFormat format; const char *path = NULL, *ext = "pem"; - scheme = cert_data->scheme_func (cert_data->setting); + scheme = cert_data->vtable->scheme_func (cert_data->setting); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { char *tmp = NULL; const char *accepted_path = NULL; - path = cert_data->path_func (cert_data->setting); + path = cert_data->vtable->path_func (cert_data->setting); g_assert (path); if (g_str_has_prefix (path, info->keyfile_dir)) { @@ -92,11 +93,11 @@ cert_writer (NMConnection *connection, if (!accepted_path) accepted_path = tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL); - nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, accepted_path); + nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, accepted_path); g_free (tmp); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, - cert_data->uri_func (cert_data->setting)); + nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, + cert_data->vtable->uri_func (cert_data->setting)); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { GBytes *blob; const guint8 *blob_data; @@ -105,13 +106,13 @@ cert_writer (NMConnection *connection, GError *local = NULL; char *new_path; - blob = cert_data->blob_func (cert_data->setting); + blob = cert_data->vtable->blob_func (cert_data->setting); g_assert (blob); blob_data = g_bytes_get_data (blob, &blob_len); - if (cert_data->format_func) { + if (cert_data->vtable->format_func) { /* Get the extension for a private key */ - format = cert_data->format_func (cert_data->setting); + format = cert_data->vtable->format_func (cert_data->setting); if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) ext = "p12"; } else { @@ -124,17 +125,17 @@ cert_writer (NMConnection *connection, * from now on instead of pushing around the certificate data. */ new_path = g_strdup_printf ("%s/%s-%s.%s", info->keyfile_dir, nm_connection_get_uuid (connection), - cert_data->suffix, ext); + cert_data->vtable->file_suffix, ext); success = nm_utils_file_set_contents (new_path, (const gchar *) blob_data, blob_len, 0600, &local); if (success) { /* Write the path value to the keyfile. * We know, that basename(new_path) starts with a UUID, hence no conflict with "data:;base64," */ - nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, strrchr (new_path, '/') + 1); + nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, strrchr (new_path, '/') + 1); } else { nm_log_warn (LOGD_SETTINGS, "keyfile: %s.%s: failed to write certificate to file %s: %s", - setting_name, cert_data->property_name, new_path, local->message); + setting_name, cert_data->vtable->setting_key, new_path, local->message); g_error_free (local); } g_free (new_path); @@ -174,9 +175,11 @@ _internal_write_connection (NMConnection *connection, const char *existing_path, gboolean force_rename, char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { - GKeyFile *key_file; + gs_unref_keyfile GKeyFile *key_file = NULL; gs_free char *data = NULL; gsize len; gs_free char *path = NULL; @@ -188,8 +191,15 @@ _internal_write_connection (NMConnection *connection, g_return_val_if_fail (!out_path || !*out_path, FALSE); g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE); - if (!nm_connection_verify (connection, error)) + switch (_nm_connection_verify (connection, error)) { + case NM_SETTING_VERIFY_NORMALIZABLE: + nm_assert_not_reached (); + /* fall-through */ + case NM_SETTING_VERIFY_SUCCESS: + break; + default: g_return_val_if_reached (FALSE); + } id = nm_connection_get_id (connection); g_assert (id && *id); @@ -200,7 +210,6 @@ _internal_write_connection (NMConnection *connection, if (!key_file) return FALSE; data = g_key_file_to_data (key_file, &len, error); - g_key_file_unref (key_file); if (!data) return FALSE; @@ -290,15 +299,48 @@ _internal_write_connection (NMConnection *connection, path = NULL; } + if (out_reread || out_reread_same) + { + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + reread = nms_keyfile_reader_from_keyfile (key_file, path, FALSE, NULL); + + nm_assert (NM_IS_CONNECTION (reread)); + + if ( reread + && !nm_connection_normalize (reread, NULL, NULL, NULL)) { + nm_assert_not_reached (); + g_clear_object (&reread); + } + + if (reread && out_reread_same) { + reread_same = !!nm_connection_compare (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT); + + nm_assert (reread_same == nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + nm_assert (reread_same == ({ + gs_unref_hashtable GHashTable *_settings = NULL; + + ( nm_connection_diff (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT, &_settings) + && !_settings); + })); + } + + NM_SET_OUT (out_reread, g_steal_pointer (&reread)); + NM_SET_OUT (out_reread_same, reread_same); + } + return TRUE; } gboolean nms_keyfile_writer_connection (NMConnection *connection, - const char *existing_path, - gboolean force_rename, - char **out_path, - GError **error) + const char *existing_path, + gboolean force_rename, + char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error) { return _internal_write_connection (connection, nms_keyfile_utils_get_path (), @@ -306,16 +348,20 @@ nms_keyfile_writer_connection (NMConnection *connection, existing_path, force_rename, out_path, + out_reread, + out_reread_same, error); } gboolean nms_keyfile_writer_test_connection (NMConnection *connection, - const char *keyfile_dir, - uid_t owner_uid, - pid_t owner_grp, - char **out_path, - GError **error) + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error) { return _internal_write_connection (connection, keyfile_dir, @@ -323,6 +369,8 @@ nms_keyfile_writer_test_connection (NMConnection *connection, NULL, FALSE, out_path, + out_reread, + out_reread_same, error); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h index 4f43455d..ac41dfa2 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.h +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.h @@ -22,12 +22,14 @@ #ifndef __NMS_KEYFILE_WRITER_H__ #define __NMS_KEYFILE_WRITER_H__ -#include <nm-connection.h> +#include "nm-connection.h" gboolean nms_keyfile_writer_connection (NMConnection *connection, const char *existing_path, gboolean force_rename, char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); gboolean nms_keyfile_writer_test_connection (NMConnection *connection, @@ -35,6 +37,8 @@ gboolean nms_keyfile_writer_test_connection (NMConnection *connection, uid_t owner_uid, pid_t owner_grp, char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); #endif /* __NMS_KEYFILE_WRITER_H__ */ diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection index de8373be..5cb4d726 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection @@ -34,6 +34,7 @@ routes8=1.1.1.8/18,0.0.0.0, routes9=1.1.1.9/19,0.0.0.0,0 routes10=1.1.1.10/20,,0 routes11=1.1.1.11/21,,21 +routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7 ignore-auto-routes=false ignore-auto-dns=false @@ -58,5 +59,6 @@ route3=6:7:8:9:0:1:2:3/126,,1 route4=7:8:9:0:1:2:3:4/125/::,5 route5=8:9:0:1:2:3:4:5/124,6 route6=8:9:0:1:2:3:4:6/123,, +route6_options=from=abce::/63 ignore-auto-routes=false ignore-auto-dns=false diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index f1102bd3..d9da5317 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -113,13 +113,25 @@ assert_reread_and_unlink (NMConnection *connection, gboolean normalize_connectio } static void -write_test_connection (NMConnection *connection, char **testfile) +assert_reread_same (NMConnection *connection, + NMConnection *reread) +{ + nmtst_assert_connection_verifies_without_normalization (reread); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void +write_test_connection_reread (NMConnection *connection, + char **testfile, + NMConnection **out_reread, + gboolean *out_reread_same) { uid_t owner_uid; gid_t owner_grp; gboolean success; GError *error = NULL; GError **p_error = (nmtst_get_rand_int () % 2) ? &error : NULL; + gs_unref_object NMConnection *connection_normalized = NULL; g_assert (NM_IS_CONNECTION (connection)); g_assert (testfile && !*testfile); @@ -127,13 +139,33 @@ write_test_connection (NMConnection *connection, char **testfile) owner_uid = geteuid (); owner_grp = getegid (); - success = nms_keyfile_writer_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, testfile, p_error); + connection_normalized = nmtst_connection_duplicate_and_normalize (connection); + + success = nms_keyfile_writer_test_connection (connection_normalized, + TEST_SCRATCH_DIR, + owner_uid, + owner_grp, + testfile, + out_reread, + out_reread_same, + p_error); g_assert_no_error (error); g_assert (success); g_assert (*testfile && (*testfile)[0]); } static void +write_test_connection (NMConnection *connection, char **testfile) +{ + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + write_test_connection_reread (connection, testfile, &reread, &reread_same); + assert_reread_same (connection, reread); + g_assert (reread_same); +} + +static void write_test_connection_and_reread (NMConnection *connection, gboolean normalize_connection) { gs_free char *testfile = NULL; @@ -161,6 +193,27 @@ keyfile_load_from_file (const char *testfile) return keyfile; } +static void +_setting_copy_property_gbytes (NMConnection *src, NMConnection *dst, const char *setting_name, const char *property_name) +{ + gs_unref_bytes GBytes *blob = NULL; + NMSetting *s_src; + NMSetting *s_dst; + + g_assert (NM_IS_CONNECTION (src)); + g_assert (NM_IS_CONNECTION (dst)); + g_assert (setting_name); + g_assert (property_name); + + s_src = nm_connection_get_setting_by_name (src, setting_name); + g_assert (NM_IS_SETTING (s_src)); + s_dst = nm_connection_get_setting_by_name (dst, setting_name); + g_assert (NM_IS_SETTING (s_dst)); + + g_object_get (s_src, property_name, &blob, NULL); + g_object_set (s_dst, property_name, blob, NULL); +} + /*****************************************************************************/ static void @@ -171,6 +224,7 @@ test_read_valid_wired_connection (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + NMIPRoute *route; gs_free_error GError *error = NULL; const char *mac; char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; @@ -265,6 +319,15 @@ test_read_valid_wired_connection (void) check_ip_route (s_ip4, 10, "1.1.1.10", 20, NULL, -1); check_ip_route (s_ip4, 11, "1.1.1.11", 21, NULL, 21); + /* Route attributes */ + route = nm_setting_ip_config_get_route (s_ip4, 11); + g_assert (route); + + nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10); + nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1430); + nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE); + nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "7.7.7.7"); + /* ===== IPv6 SETTING ===== */ s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); @@ -304,6 +367,11 @@ test_read_valid_wired_connection (void) check_ip_route (s_ip6, 4, "7:8:9:0:1:2:3:4", 125, NULL, 5); check_ip_route (s_ip6, 5, "8:9:0:1:2:3:4:5", 124, NULL, 6); check_ip_route (s_ip6, 6, "8:9:0:1:2:3:4:6", 123, NULL, -1); + + /* Route attributes */ + route = nm_setting_ip_config_get_route (s_ip6, 6); + g_assert (route); + nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_FROM, "abce::/63"); } static void @@ -349,6 +417,7 @@ test_write_wired_connection (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + NMIPRoute *rt; const char *mac = "99:88:77:66:55:44"; const char *dns1 = "4.2.2.1"; const char *dns2 = "4.2.2.2"; @@ -376,6 +445,7 @@ test_write_wired_connection (void) const char *route6_4 = "5:6:7:8:9:0:1:2"; const char *route6_4_nh = "::"; guint64 timestamp = 0x12345678L; + GError *error = NULL; connection = nm_simple_connection_new (); @@ -420,7 +490,14 @@ test_write_wired_connection (void) add_one_ip_route (s_ip4, route1, route1_nh, 24, 3); add_one_ip_route (s_ip4, route2, route2_nh, 8, 1); add_one_ip_route (s_ip4, route3, route3_nh, 7, -1); - add_one_ip_route (s_ip4, route4, route4_nh, 6, 4); + + rt = nm_ip_route_new (AF_INET, route4, 6, route4_nh, 4, &error); + g_assert_no_error (error); + nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (10)); + nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1492)); + nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("1.2.3.4")); + g_assert (nm_setting_ip_config_add_route (s_ip4, rt)); + nm_ip_route_unref (rt); /* DNS servers */ nm_setting_ip_config_add_dns (s_ip4, dns1); @@ -1639,11 +1716,18 @@ test_write_wired_8021x_tls_connection_path (void) gs_free_error GError *error = NULL; gs_unref_keyfile GKeyFile *keyfile = NULL; gboolean relative = FALSE; + gboolean reread_same = FALSE; connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_PATH); g_assert (connection != NULL); - write_test_connection (connection, &testfile); + write_test_connection_reread (connection, &testfile, &reread, &reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + assert_reread_same (connection, reread); + g_clear_object (&reread); /* Read the connection back in and compare it to the one we just wrote out */ reread = nms_keyfile_reader_from_file (testfile, &error); @@ -1716,6 +1800,7 @@ test_write_wired_8021x_tls_connection_blob (void) char *new_client_cert; char *new_priv_key; const char *uuid; + gboolean reread_same = FALSE; gs_free_error GError *error = NULL; GBytes *password_raw = NULL; #define PASSWORD_RAW "password-raw\0test" @@ -1733,7 +1818,13 @@ test_write_wired_8021x_tls_connection_blob (void) NULL); g_bytes_unref (password_raw); - write_test_connection (connection, &testfile); + write_test_connection_reread (connection, &testfile, &reread, &reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + assert_reread_same (connection, reread); + g_clear_object (&reread); /* Check that the new certs got written out */ s_con = nm_connection_get_setting_connection (connection); diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 8f766d7c..f9a84620 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -28,6 +28,7 @@ #include "nm-supplicant-settings-verify.h" #include "nm-setting.h" +#include "nm-auth-subject.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -828,6 +829,53 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, return TRUE; } +static gboolean +add_pkcs11_uri_with_pin (NMSupplicantConfig *self, + const char *name, + const char *uri, + const char *pin, + const NMSettingSecretFlags pin_flags, + GError **error) +{ + gs_strfreev gchar **split = NULL; + gs_free char *tmp = NULL; + gs_free char *tmp_log = NULL; + gs_free char *pin_qattr = NULL; + char *escaped = NULL; + + if (uri == NULL) + return TRUE; + + /* We ignore the attributes -- RFC 7512 suggests that some of them + * might be unsafe and we want to be on the safe side. Also, we're + * installing our attributes, so this makes things a bit easier for us. */ + split = g_strsplit (uri, "&", 2); + if (split[1]) + nm_log_info (LOGD_SUPPLICANT, "URI attributes ignored"); + + /* Fill in the PIN if required. */ + if (pin) { + escaped = g_uri_escape_string (pin, NULL, TRUE); + pin_qattr = g_strdup_printf ("pin-value=%s", escaped); + g_free (escaped); + } else if (!(pin_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { + /* Include an empty PIN to indicate the login is still needed. + * Probably a token that has a PIN path and the actual PIN will + * be entered using a protected path. */ + pin_qattr = g_strdup ("pin-value="); + } + + tmp = g_strdup_printf ("%s%s%s", split[0], + (pin_qattr ? "&" : ""), + (pin_qattr ? pin_qattr : "")); + + tmp_log = g_strdup_printf ("%s%s%s", split[0], + (pin_qattr ? "&" : ""), + (pin_qattr ? "pin-value=<hidden>" : "")); + + return add_string_val (self, tmp, name, FALSE, tmp_log, error); +} + gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, NMSetting8021x *setting, @@ -848,6 +896,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, const char *ca_path_override = NULL, *ca_cert_override = NULL; guint32 frag, hdrs; gs_free char *frag_str = NULL; + NMSetting8021xAuthFlags phase1_auth_flags; g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (setting != NULL, FALSE); @@ -934,6 +983,14 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, fast_provisoning_allowed = TRUE; } + phase1_auth_flags = nm_setting_802_1x_get_phase1_auth_flags (setting); + if (NM_FLAGS_HAS (phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE)) + g_string_append_printf (phase1, "%stls_disable_tlsv1_0=1", (phase1->len ? " " : "")); + if (NM_FLAGS_HAS (phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE)) + g_string_append_printf (phase1, "%stls_disable_tlsv1_1=1", (phase1->len ? " " : "")); + if (NM_FLAGS_HAS (phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_2_DISABLE)) + g_string_append_printf (phase1, "%stls_disable_tlsv1_2=1", (phase1->len ? " " : "")); + if (phase1->len) { if (!add_string_val (self, phase1->str, "phase1", FALSE, NULL, error)) { g_string_free (phase1, TRUE); @@ -1033,9 +1090,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - path = nm_setting_802_1x_get_ca_cert_uri (setting); - if (!add_string_val (self, path, "ca_cert", FALSE, NULL, error)) + if (!add_pkcs11_uri_with_pin (self, "ca_cert", + nm_setting_802_1x_get_ca_cert_uri (setting), + nm_setting_802_1x_get_ca_cert_password (setting), + nm_setting_802_1x_get_ca_cert_password_flags (setting), + error)) { return FALSE; + } break; default: break; @@ -1059,9 +1120,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - path = nm_setting_802_1x_get_phase2_ca_cert_uri (setting); - if (!add_string_val (self, path, "ca_cert2", FALSE, NULL, error)) + if (!add_pkcs11_uri_with_pin (self, "ca_cert2", + nm_setting_802_1x_get_phase2_ca_cert_uri (setting), + nm_setting_802_1x_get_phase2_ca_cert_password (setting), + nm_setting_802_1x_get_phase2_ca_cert_password_flags (setting), + error)) { return FALSE; + } break; default: break; @@ -1106,9 +1171,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, added = TRUE; break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - path = nm_setting_802_1x_get_private_key_uri (setting); - if (!add_string_val (self, path, "private_key", FALSE, NULL, error)) + if (!add_pkcs11_uri_with_pin (self, "private_key", + nm_setting_802_1x_get_private_key_uri (setting), + nm_setting_802_1x_get_private_key_password (setting), + nm_setting_802_1x_get_private_key_password_flags (setting), + error)) { return FALSE; + } added = TRUE; break; default: @@ -1149,9 +1218,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - path = nm_setting_802_1x_get_client_cert_uri (setting); - if (!add_string_val (self, path, "client_cert", FALSE, NULL, error)) + if (!add_pkcs11_uri_with_pin (self, "client_cert", + nm_setting_802_1x_get_client_cert_uri (setting), + nm_setting_802_1x_get_client_cert_password (setting), + nm_setting_802_1x_get_client_cert_password_flags (setting), + error)) { return FALSE; + } break; default: break; @@ -1175,9 +1248,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, added = TRUE; break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - path = nm_setting_802_1x_get_phase2_private_key_uri (setting); - if (!add_string_val (self, path, "private_key2", FALSE, NULL, error)) + if (!add_pkcs11_uri_with_pin (self, "private_key2", + nm_setting_802_1x_get_phase2_private_key_uri (setting), + nm_setting_802_1x_get_phase2_private_key_password (setting), + nm_setting_802_1x_get_phase2_private_key_password_flags (setting), + error)) { return FALSE; + } added = TRUE; break; default: @@ -1218,9 +1295,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - path = nm_setting_802_1x_get_phase2_client_cert_uri (setting); - if (!add_string_val (self, path, "client_cert2", FALSE, NULL, error)) + if (!add_pkcs11_uri_with_pin (self, "client_cert2", + nm_setting_802_1x_get_phase2_client_cert_uri (setting), + nm_setting_802_1x_get_phase2_client_cert_password (setting), + nm_setting_802_1x_get_phase2_client_cert_password_flags (setting), + error)) { return FALSE; + } break; default: break; diff --git a/src/supplicant/nm-supplicant-config.h b/src/supplicant/nm-supplicant-config.h index 40fca61b..6acfb7ee 100644 --- a/src/supplicant/nm-supplicant-config.h +++ b/src/supplicant/nm-supplicant-config.h @@ -22,10 +22,10 @@ #ifndef __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ #define __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ -#include <nm-setting-macsec.h> -#include <nm-setting-wireless.h> -#include <nm-setting-wireless-security.h> -#include <nm-setting-8021x.h> +#include "nm-setting-macsec.h" +#include "nm-setting-wireless.h" +#include "nm-setting-wireless-security.h" +#include "nm-setting-8021x.h" #include "nm-supplicant-types.h" diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index f932fe8b..71f1f9aa 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -39,14 +39,35 @@ /*****************************************************************************/ +typedef struct { + GDBusProxy *proxy; + gulong change_id; +} BssData; + +struct _AddNetworkData; + +typedef struct { + NMSupplicantInterface *self; + NMSupplicantConfig *cfg; + GCancellable *cancellable; + NMSupplicantInterfaceAssocCb callback; + gpointer user_data; + guint fail_on_idle_id; + guint blobs_left; + struct _AddNetworkData *add_network_data; +} AssocData; + +typedef struct _AddNetworkData { + /* the assoc_data at the time when doing the call. */ + AssocData *assoc_data; +} AddNetworkData; + enum { STATE, /* change in the interface's state */ REMOVED, /* interface was removed by the supplicant */ - NEW_BSS, /* interface saw a new access point from a scan */ - BSS_UPDATED, /* a BSS property changed */ + BSS_UPDATED, /* a new BSS appeared or an existing had properties changed */ BSS_REMOVED, /* supplicant removed BSS from its scan list */ SCAN_DONE, /* wifi scan is complete */ - CONNECTION_ERROR, /* an error occurred during a connection request */ CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ LAST_SIGNAL }; @@ -71,24 +92,27 @@ typedef struct { guint32 ready_count; char * object_path; - guint32 state; + NMSupplicantInterfaceState state; int disconnect_reason; - gboolean scanning; + gboolean scanning:1; + + bool scan_done_pending:1; + bool scan_done_success:1; GDBusProxy * wpas_proxy; GCancellable * init_cancellable; GDBusProxy * iface_proxy; GCancellable * other_cancellable; - GCancellable * assoc_cancellable; + + AssocData * assoc_data; + char * net_path; - guint32 blobs_left; GHashTable * bss_proxies; char * current_bss; gint32 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_s() */ - NMSupplicantConfig *cfg; } NMSupplicantInterfacePrivate; struct _NMSupplicantInterface { @@ -111,38 +135,57 @@ G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT) #define _NMLOG(level, ...) \ G_STMT_START { \ char _sbuf[64]; \ + const char *__ifname = self ? NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev : NULL; \ \ - nm_log ((level), _NMLOG_DOMAIN, \ + nm_log ((level), _NMLOG_DOMAIN, __ifname, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ - ((self) \ - ? nm_sprintf_buf (_sbuf, \ - "[%p,%s]", \ - (self), \ - NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev) \ - : "") \ + ((self) ? nm_sprintf_buf (_sbuf, "[%p,%s]", (self), __ifname) : "") \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } G_STMT_END /*****************************************************************************/ +static void scan_done_emit_signal (NMSupplicantInterface *self); + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_interface_state_to_string, NMSupplicantInterfaceState, + NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INVALID, "invalid"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INIT, "init"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_STARTING, "starting"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_READY, "ready"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISABLED, "disabled"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, "disconnected"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INACTIVE, "inactive"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_SCANNING, "scanning"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING, "authenticating"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, "associating"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, "associated"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, "4-way handshake"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, "group handshake"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, "completed"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DOWN, "down"), +); + +/*****************************************************************************/ + static void -emit_error_helper (NMSupplicantInterface *self, GError *error) +bss_data_destroy (gpointer user_data) { - char *name = NULL; + BssData *bss_data = user_data; - if (g_dbus_error_is_remote_error (error)) - name = g_dbus_error_get_remote_error (error); - - g_signal_emit (self, signals[CONNECTION_ERROR], 0, name, error->message); - g_free (name); + nm_clear_g_signal_handler (bss_data->proxy, &bss_data->change_id); + g_object_unref (bss_data->proxy); + g_slice_free (BssData, bss_data); } static void -bss_props_changed_cb (GDBusProxy *proxy, - GVariant *changed_properties, - char **invalidated_properties, - gpointer user_data) +bss_proxy_properties_changed_cb (GDBusProxy *proxy, + GVariant *changed_properties, + char **invalidated_properties, + gpointer user_data) { NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); @@ -156,63 +199,73 @@ bss_props_changed_cb (GDBusProxy *proxy, } static GVariant * -_get_bss_proxy_properties (NMSupplicantInterface *self, GDBusProxy *proxy) +bss_proxy_get_properties (NMSupplicantInterface *self, GDBusProxy *proxy) { gs_strfreev char **properties = NULL; GVariantBuilder builder; char **iter; iter = properties = g_dbus_proxy_get_cached_property_names (proxy); - if (!iter) - return NULL; g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - while (*iter) { - GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter); + if (iter) { + while (*iter) { + GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter); - g_variant_builder_add (&builder, "{sv}", *iter++, copy); - g_variant_unref (copy); + g_variant_builder_add (&builder, "{sv}", *iter++, copy); + g_variant_unref (copy); + } } - return g_variant_builder_end (&builder); } -#define BSS_PROXY_INITED "bss-proxy-inited" - static void -on_bss_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +bss_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; gs_free_error GError *error = NULL; - gs_unref_variant GVariant *props = NULL; + GVariant *props = NULL; + const char *object_path; + BssData *bss_data; - if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - self = NM_SUPPLICANT_INTERFACE (user_data); - _LOGD ("failed to acquire BSS proxy: (%s)", error->message); - g_hash_table_remove (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->bss_proxies, - g_dbus_proxy_get_object_path (proxy)); - } + g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } self = NM_SUPPLICANT_INTERFACE (user_data); - props = _get_bss_proxy_properties (self, proxy); - if (!props) + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (error) { + _LOGD ("failed to acquire BSS proxy: (%s)", error->message); + g_hash_table_remove (priv->bss_proxies, + g_dbus_proxy_get_object_path (proxy)); return; + } - g_object_set_data (G_OBJECT (proxy), BSS_PROXY_INITED, GUINT_TO_POINTER (TRUE)); + object_path = g_dbus_proxy_get_object_path (proxy); + bss_data = g_hash_table_lookup (priv->bss_proxies, object_path); + if (!bss_data) + return; - g_signal_emit (self, signals[NEW_BSS], 0, + bss_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (bss_proxy_properties_changed_cb), self); + + props = bss_proxy_get_properties (self, proxy); + g_signal_emit (self, signals[BSS_UPDATED], 0, g_dbus_proxy_get_object_path (proxy), g_variant_ref_sink (props)); + g_variant_unref (props); + + if (priv->scan_done_pending) + scan_done_emit_signal (self); } static void -handle_new_bss (NMSupplicantInterface *self, const char *object_path) +bss_add_new (NMSupplicantInterface *self, const char *object_path) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); GDBusProxy *bss_proxy; + BssData *bss_data; g_return_if_fail (object_path != NULL); @@ -226,24 +279,25 @@ handle_new_bss (NMSupplicantInterface *self, const char *object_path) "g-object-path", object_path, "g-interface-name", WPAS_DBUS_IFACE_BSS, NULL); + bss_data = g_slice_new0 (BssData); + bss_data->proxy = bss_proxy; g_hash_table_insert (priv->bss_proxies, (char *) g_dbus_proxy_get_object_path (bss_proxy), - bss_proxy); - g_signal_connect (bss_proxy, "g-properties-changed", G_CALLBACK (bss_props_changed_cb), self); + bss_data); g_async_initable_init_async (G_ASYNC_INITABLE (bss_proxy), G_PRIORITY_DEFAULT, priv->other_cancellable, - (GAsyncReadyCallback) on_bss_proxy_acquired, + (GAsyncReadyCallback) bss_proxy_acquired_cb, self); } +/*****************************************************************************/ + static void -set_state (NMSupplicantInterface *self, guint32 new_state) +set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - guint32 old_state = priv->state; - - g_return_if_fail (new_state < NM_SUPPLICANT_INTERFACE_STATE_LAST); + NMSupplicantInterfaceState old_state = priv->state; if (new_state == priv->state) return; @@ -256,20 +310,11 @@ set_state (NMSupplicantInterface *self, guint32 new_state) g_return_if_fail (new_state > NM_SUPPLICANT_INTERFACE_STATE_READY); if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) { - if (priv->other_cancellable) { - g_warn_if_fail (priv->other_cancellable == NULL); - g_cancellable_cancel (priv->other_cancellable); - g_clear_object (&priv->other_cancellable); - } + nm_clear_g_cancellable (&priv->other_cancellable); priv->other_cancellable = g_cancellable_new (); } else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - if (priv->init_cancellable) - g_cancellable_cancel (priv->init_cancellable); - g_clear_object (&priv->init_cancellable); - - if (priv->other_cancellable) - g_cancellable_cancel (priv->other_cancellable); - g_clear_object (&priv->other_cancellable); + nm_clear_g_cancellable (&priv->init_cancellable); + nm_clear_g_cancellable (&priv->other_cancellable); if (priv->iface_proxy) g_signal_handlers_disconnect_by_data (priv->iface_proxy, self); @@ -286,12 +331,12 @@ set_state (NMSupplicantInterface *self, guint32 new_state) priv->disconnect_reason = 0; g_signal_emit (self, signals[STATE], 0, - priv->state, - old_state, - priv->disconnect_reason); + (int) priv->state, + (int) old_state, + (int) priv->disconnect_reason); } -static int +static NMSupplicantInterfaceState wpas_state_string_to_enum (const char *str_state) { if (!strcmp (str_state, "interface_disabled")) @@ -315,20 +360,20 @@ wpas_state_string_to_enum (const char *str_state) else if (!strcmp (str_state, "completed")) return NM_SUPPLICANT_INTERFACE_STATE_COMPLETED; - return -1; + return NM_SUPPLICANT_INTERFACE_STATE_INVALID; } static void set_state_from_string (NMSupplicantInterface *self, const char *new_state) { - int state; + NMSupplicantInterfaceState state; state = wpas_state_string_to_enum (new_state); - if (state == -1) { + if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID) { _LOGW ("unknown supplicant state '%s'", new_state); return; } - set_state (self, (guint32) state); + set_state (self, state); } static void @@ -548,38 +593,56 @@ iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data } static void -wpas_iface_scan_done (GDBusProxy *proxy, - gboolean success, - gpointer user_data) +scan_done_emit_signal (NMSupplicantInterface *self) { - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - GVariant *props; + const char *object_path; + BssData *bss_data; + gboolean success; GHashTableIter iter; - char *bss_path; - GDBusProxy *bss_proxy; - /* Cache last scan completed time */ - priv->last_scan = nm_utils_get_monotonic_timestamp_s (); - - /* Emit NEW_BSS so that wifi device has the APs (in case it removed them) */ g_hash_table_iter_init (&iter, priv->bss_proxies); - while (g_hash_table_iter_next (&iter, (gpointer) &bss_path, (gpointer) &bss_proxy)) { - if (g_object_get_data (G_OBJECT (bss_proxy), BSS_PROXY_INITED)) { - props = _get_bss_proxy_properties (self, bss_proxy); - if (props) { - g_signal_emit (self, signals[NEW_BSS], 0, - bss_path, - g_variant_ref_sink (props)); - g_variant_unref (props); - } + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &bss_data)) { + /* we have some BSS' that need to be initialized first. Delay + * emitting signal. */ + if (!bss_data->change_id) { + priv->scan_done_pending = TRUE; + return; } } + /* Emit BSS_UPDATED so that wifi device has the APs (in case it removed them) */ + g_hash_table_iter_init (&iter, priv->bss_proxies); + while (g_hash_table_iter_next (&iter, (gpointer *) &object_path, (gpointer *) &bss_data)) { + gs_unref_variant GVariant *props = NULL; + + props = bss_proxy_get_properties (self, bss_data->proxy); + g_signal_emit (self, signals[BSS_UPDATED], 0, + object_path, + g_variant_ref_sink (props)); + } + + success = priv->scan_done_success; + priv->scan_done_success = FALSE; + priv->scan_done_pending = FALSE; g_signal_emit (self, signals[SCAN_DONE], 0, success); } static void +wpas_iface_scan_done (GDBusProxy *proxy, + gboolean success, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* Cache last scan completed time */ + priv->last_scan = nm_utils_get_monotonic_timestamp_s (); + priv->scan_done_success |= success; + scan_done_emit_signal (self); +} + +static void wpas_iface_bss_added (GDBusProxy *proxy, const char *path, GVariant *props, @@ -591,7 +654,7 @@ wpas_iface_bss_added (GDBusProxy *proxy, if (priv->scanning) priv->last_scan = nm_utils_get_monotonic_timestamp_s (); - handle_new_bss (self, path); + bss_add_new (self, path); } static void @@ -601,9 +664,14 @@ wpas_iface_bss_removed (GDBusProxy *proxy, { NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + BssData *bss_data; + bss_data = g_hash_table_lookup (priv->bss_proxies, path); + if (!bss_data) + return; + g_hash_table_steal (priv->bss_proxies, path); g_signal_emit (self, signals[BSS_REMOVED], 0, path); - g_hash_table_remove (priv->bss_proxies, path); + bss_data_destroy (bss_data); } static void @@ -651,7 +719,7 @@ props_changed_cb (GDBusProxy *proxy, if (g_variant_lookup (changed_properties, "BSSs", "^a&o", &array)) { iter = array; while (*iter) - handle_new_bss (self, *iter++); + bss_add_new (self, *iter++); g_free (array); } @@ -955,8 +1023,7 @@ interface_add (NMSupplicantInterface *self) /* Move to starting to prevent double-calls of interface_add() */ set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING); - g_warn_if_fail (priv->init_cancellable == NULL); - g_clear_object (&priv->init_cancellable); + nm_clear_g_cancellable (&priv->init_cancellable); priv->init_cancellable = g_cancellable_new (); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, @@ -1009,6 +1076,39 @@ log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) } } +/*****************************************************************************/ + +static void +assoc_return (NMSupplicantInterface *self, GError *error, const char *message) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + AssocData *assoc_data; + + assoc_data = g_steal_pointer (&priv->assoc_data); + if (!assoc_data) + return; + + if (error) { + g_dbus_error_strip_remote_error (error); + _LOGW ("assoc[%p]: %s: %s", assoc_data, message, error->message); + } else + _LOGD ("assoc[%p]: association request successful", assoc_data); + + if (assoc_data->add_network_data) { + /* signal that this request already completed */ + assoc_data->add_network_data->assoc_data = NULL; + } + + nm_clear_g_source (&assoc_data->fail_on_idle_id); + nm_clear_g_cancellable (&assoc_data->cancellable); + + if (assoc_data->callback) + assoc_data->callback (self, error, assoc_data->user_data); + + g_object_unref (assoc_data->cfg); + g_slice_free (AssocData, assoc_data); +} + void nm_supplicant_interface_disconnect (NMSupplicantInterface * self) { @@ -1019,9 +1119,11 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self) priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); /* Cancel all pending calls related to a prior connection attempt */ - if (priv->assoc_cancellable) { - g_cancellable_cancel (priv->assoc_cancellable); - g_clear_object (&priv->assoc_cancellable); + if (priv->assoc_data) { + gs_free GError *error = NULL; + + nm_utils_error_set_cancelled (&error, FALSE, "NMSupplicantInterface"); + assoc_return (self, error, "abort due to disconnect"); } /* Don't do anything if there is no connection to the supplicant yet. */ @@ -1057,42 +1159,40 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self) } static void -select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; gs_unref_variant GVariant *reply = NULL; gs_free_error GError *error = NULL; reply = g_dbus_proxy_call_finish (proxy, result, &error); - if ( !reply - && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - self = NM_SUPPLICANT_INTERFACE (user_data); - g_dbus_error_strip_remote_error (error); - _LOGW ("couldn't select network config: %s", error->message); - emit_error_helper (self, error); - } + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_SUPPLICANT_INTERFACE (user_data); + if (error) + assoc_return (self, error, "failure to select network config"); + else + assoc_return (self, NULL, NULL); } static void -call_select_network (NMSupplicantInterface *self) +assoc_call_select_network (NMSupplicantInterface *self) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - /* We only select the network after all blobs (if any) have been set */ - if (priv->blobs_left == 0) { - g_dbus_proxy_call (priv->iface_proxy, - "SelectNetwork", - g_variant_new ("(o)", priv->net_path), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_cancellable, - (GAsyncReadyCallback) select_network_cb, - self); - } + g_dbus_proxy_call (priv->iface_proxy, + "SelectNetwork", + g_variant_new ("(o)", priv->net_path), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->assoc_data->cancellable, + (GAsyncReadyCallback) assoc_select_network_cb, + self); } static void -add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; @@ -1106,19 +1206,22 @@ add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - priv->blobs_left--; - if (reply) - call_select_network (self); - else { - g_dbus_error_strip_remote_error (error); - _LOGW ("couldn't set network certificates: %s", error->message); - emit_error_helper (self, error); + if (error) { + assoc_return (self, error, "failure to set network certificates"); + return; } + + priv->assoc_data->blobs_left--; + _LOGT ("assoc[%p]: blob added (%u left)", priv->assoc_data, priv->assoc_data->blobs_left); + if (priv->assoc_data->blobs_left == 0) + assoc_call_select_network (self); } static void -add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { + AddNetworkData *add_network_data = user_data; + AssocData *assoc_data; NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; gs_unref_variant GVariant *reply = NULL; @@ -1128,71 +1231,81 @@ add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) const char *blob_name; GByteArray *blob_data; + assoc_data = add_network_data->assoc_data; + if (assoc_data) + assoc_data->add_network_data = NULL; + g_slice_free (AddNetworkData, add_network_data); + reply = _nm_dbus_proxy_call_finish (proxy, result, G_VARIANT_TYPE ("(o)"), &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + + if (!assoc_data) { + if (!error) { + gs_free char *net_path = NULL; + + /* the assoc-request was already cancelled, but the AddNetwork request succeeded. + * Cleanup the created network. + * + * This cleanup action does not work when NetworkManager is about to exit + * and leaves the mainloop. During program shutdown, we may orphan networks. */ + g_variant_get (reply, "(o)", &net_path); + g_dbus_proxy_call (proxy, + "RemoveNetwork", + g_variant_new ("(o)", net_path), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + } return; + } - self = NM_SUPPLICANT_INTERFACE (user_data); + self = NM_SUPPLICANT_INTERFACE (assoc_data->self); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - g_free (priv->net_path); - priv->net_path = NULL; - if (error) { - g_dbus_error_strip_remote_error (error); - _LOGW ("adding network to supplicant failed: %s", error->message); - emit_error_helper (self, error); + assoc_return (self, error, "failure to add network"); return; } g_variant_get (reply, "(o)", &priv->net_path); /* Send blobs first; otherwise jump to selecting the network */ - blobs = nm_supplicant_config_get_blobs (priv->cfg); - priv->blobs_left = g_hash_table_size (blobs); - - g_hash_table_iter_init (&iter, blobs); - while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) { - g_dbus_proxy_call (priv->iface_proxy, - "AddBlob", - g_variant_new ("(s@ay)", - blob_name, - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - blob_data->data, blob_data->len, 1)), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_cancellable, - (GAsyncReadyCallback) add_blob_cb, - self); - } + blobs = nm_supplicant_config_get_blobs (priv->assoc_data->cfg); + priv->assoc_data->blobs_left = g_hash_table_size (blobs); - call_select_network (self); -} + _LOGT ("assoc[%p]: network added (%s) (%u blobs left)", priv->assoc_data, priv->net_path, priv->assoc_data->blobs_left); -static void -add_network (NMSupplicantInterface *self) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - g_dbus_proxy_call (priv->iface_proxy, - "AddNetwork", - g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->cfg)), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_cancellable, - (GAsyncReadyCallback) add_network_cb, - self); + if (priv->assoc_data->blobs_left == 0) + assoc_call_select_network (self); + else { + g_hash_table_iter_init (&iter, blobs); + while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) { + g_dbus_proxy_call (priv->iface_proxy, + "AddBlob", + g_variant_new ("(s@ay)", + blob_name, + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + blob_data->data, blob_data->len, 1)), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->assoc_data->cancellable, + (GAsyncReadyCallback) assoc_add_blob_cb, + self); + } + } } static void -set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; gs_unref_variant GVariant *reply = NULL; gs_free_error GError *error = NULL; + AddNetworkData *add_network_data; reply = g_dbus_proxy_call_finish (proxy, result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) @@ -1201,62 +1314,109 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (!reply) { - g_dbus_error_strip_remote_error (error); - _LOGW ("couldn't send AP scan mode to the supplicant interface: %s", - error->message); - emit_error_helper (self, error); + if (error) { + assoc_return (self, error, "failure to set AP scan mode"); return; } - _LOGI ("config: set interface ap_scan to %d", - nm_supplicant_config_get_ap_scan (priv->cfg)); + _LOGT ("assoc[%p]: set interface ap_scan to %d", + priv->assoc_data, + nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); - add_network (self); + add_network_data = g_slice_new0 (AddNetworkData); + priv->assoc_data->add_network_data = add_network_data; + + add_network_data->assoc_data = priv->assoc_data; + + g_dbus_proxy_call (priv->iface_proxy, + "AddNetwork", + g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->assoc_data->cfg)), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) assoc_add_network_cb, + add_network_data); } -gboolean -nm_supplicant_interface_set_config (NMSupplicantInterface *self, - NMSupplicantConfig *cfg, - GError **error) +static gboolean +assoc_fail_on_idle_cb (gpointer user_data) +{ + NMSupplicantInterface *self = user_data; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + gs_free_error GError *error = NULL; + + priv->assoc_data->fail_on_idle_id = 0; + g_set_error (&error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "EAP-FAST is not supported by the supplicant"); + assoc_return (self, error, "failure due to missing supplicant support"); + return G_SOURCE_REMOVE; +} + +/** + * nm_supplicant_interface_assoc: + * @self: the supplicant interface instance + * @cfg: the configuration with the data for the association + * @callback: callback invoked when the association completes or fails. + * @user_data: data for the callback. + * + * Calls AddNetwork and SelectNetwork to start associating according to @cfg. + * + * The callback is invoked exactly once (always) and always asynchronously. + * The pending association can be aborted via nm_supplicant_interface_disconnect() + * or by destroying @self. In that case, the @callback is invoked synchornously with + * an error reason indicating cancellation/disposing (see nm_utils_error_is_cancelled()). + */ +void +nm_supplicant_interface_assoc (NMSupplicantInterface *self, + NMSupplicantConfig *cfg, + NMSupplicantInterfaceAssocCb callback, + gpointer user_data) { NMSupplicantInterfacePrivate *priv; + AssocData *assoc_data; - g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE); + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + g_return_if_fail (NM_IS_SUPPLICANT_CONFIG (cfg)); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); nm_supplicant_interface_disconnect (self); + assoc_data = g_slice_new0 (AssocData); + priv->assoc_data = assoc_data; + + assoc_data->self = self; + assoc_data->cfg = g_object_ref (cfg); + assoc_data->callback = callback; + assoc_data->user_data = user_data; + + _LOGD ("assoc[%p]: starting association...", assoc_data); + /* Make sure the supplicant supports EAP-FAST before trying to send * it an EAP-FAST configuration. */ if ( priv->fast_support == NM_SUPPLICANT_FEATURE_NO && nm_supplicant_config_fast_required (cfg)) { - g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, - "EAP-FAST is not supported by the supplicant"); - return FALSE; + assoc_data->fail_on_idle_id = g_idle_add (assoc_fail_on_idle_cb, self); + return; } - g_clear_object (&priv->cfg); - if (cfg) { - priv->assoc_cancellable = g_cancellable_new (); - priv->cfg = g_object_ref (cfg); - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE, - "ApScan", - g_variant_new_uint32 (nm_supplicant_config_get_ap_scan (priv->cfg))), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_cancellable, - (GAsyncReadyCallback) set_ap_scan_cb, - self); - } - return TRUE; + assoc_data->cancellable = g_cancellable_new(); + g_dbus_proxy_call (priv->iface_proxy, + DBUS_INTERFACE_PROPERTIES ".Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE, + "ApScan", + g_variant_new_uint32 (nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg))), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->assoc_data->cancellable, + (GAsyncReadyCallback) assoc_set_ap_scan_cb, + self); } +/*****************************************************************************/ + static void scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { @@ -1279,14 +1439,14 @@ scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) } } -gboolean +void nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArray *ssids) { NMSupplicantInterfacePrivate *priv; GVariantBuilder builder; guint i; - g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE); + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); @@ -1314,10 +1474,11 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArr priv->other_cancellable, (GAsyncReadyCallback) scan_request_cb, self); - return TRUE; } -guint32 +/*****************************************************************************/ + +NMSupplicantInterfaceState nm_supplicant_interface_get_state (NMSupplicantInterface * self) { g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NM_SUPPLICANT_INTERFACE_STATE_DOWN); @@ -1326,44 +1487,6 @@ nm_supplicant_interface_get_state (NMSupplicantInterface * self) } const char * -nm_supplicant_interface_state_to_string (guint32 state) -{ - switch (state) { - case NM_SUPPLICANT_INTERFACE_STATE_INIT: - return "init"; - case NM_SUPPLICANT_INTERFACE_STATE_STARTING: - return "starting"; - case NM_SUPPLICANT_INTERFACE_STATE_READY: - return "ready"; - case NM_SUPPLICANT_INTERFACE_STATE_DISABLED: - return "disabled"; - case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: - return "disconnected"; - case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE: - return "inactive"; - case NM_SUPPLICANT_INTERFACE_STATE_SCANNING: - return "scanning"; - case NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING: - return "authenticating"; - case NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING: - return "associating"; - case NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED: - return "associated"; - case NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE: - return "4-way handshake"; - case NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE: - return "group handshake"; - case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - return "completed"; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: - return "down"; - default: - break; - } - return "unknown"; -} - -const char * nm_supplicant_interface_get_object_path (NMSupplicantInterface *self) { g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL); @@ -1389,29 +1512,25 @@ nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self) /*****************************************************************************/ -NMSupplicantInterface * -nm_supplicant_interface_new (const char *ifname, - NMSupplicantDriver driver, - NMSupplicantFeature fast_support, - NMSupplicantFeature ap_support) -{ - g_return_val_if_fail (ifname != NULL, NULL); - - return g_object_new (NM_TYPE_SUPPLICANT_INTERFACE, - NM_SUPPLICANT_INTERFACE_IFACE, ifname, - NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver, - NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support, - NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, - NULL); -} - static void -nm_supplicant_interface_init (NMSupplicantInterface * self) +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE ((NMSupplicantInterface *) object); - priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT; - priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + switch (prop_id) { + case PROP_SCANNING: + g_value_set_boolean (value, priv->scanning); + break; + case PROP_CURRENT_BSS: + g_value_set_string (value, priv->current_bss); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -1447,30 +1566,42 @@ set_property (GObject *object, } static void -get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +nm_supplicant_interface_init (NMSupplicantInterface * self) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE ((NMSupplicantInterface *) object); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - switch (prop_id) { - case PROP_SCANNING: - g_value_set_boolean (value, priv->scanning); - break; - case PROP_CURRENT_BSS: - g_value_set_string (value, priv->current_bss); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT; + priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, bss_data_destroy); +} + +NMSupplicantInterface * +nm_supplicant_interface_new (const char *ifname, + NMSupplicantDriver driver, + NMSupplicantFeature fast_support, + NMSupplicantFeature ap_support) +{ + g_return_val_if_fail (ifname != NULL, NULL); + + return g_object_new (NM_TYPE_SUPPLICANT_INTERFACE, + NM_SUPPLICANT_INTERFACE_IFACE, ifname, + NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver, + NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support, + NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, + NULL); } static void dispose (GObject *object) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE ((NMSupplicantInterface *) object); + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (priv->assoc_data) { + gs_free GError *error = NULL; + + nm_utils_error_set_cancelled (&error, TRUE, "NMSupplicantInterface"); + assoc_return (self, error, "cancelled due to dispose of supplicant interface"); + } if (priv->iface_proxy) g_signal_handlers_disconnect_by_data (priv->iface_proxy, object); @@ -1478,7 +1609,6 @@ dispose (GObject *object) nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->other_cancellable); - nm_clear_g_cancellable (&priv->assoc_cancellable); g_clear_object (&priv->wpas_proxy); g_clear_pointer (&priv->bss_proxies, (GDestroyNotify) g_hash_table_destroy); @@ -1488,9 +1618,6 @@ dispose (GObject *object) g_clear_pointer (&priv->object_path, g_free); g_clear_pointer (&priv->current_bss, g_free); - g_clear_object (&priv->cfg); - - /* Chain up to the parent class */ G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object); } @@ -1550,7 +1677,7 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT); + G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); signals[REMOVED] = g_signal_new (NM_SUPPLICANT_INTERFACE_REMOVED, @@ -1560,14 +1687,6 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 0); - signals[NEW_BSS] = - g_signal_new (NM_SUPPLICANT_INTERFACE_NEW_BSS, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT); - signals[BSS_UPDATED] = g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_UPDATED, G_OBJECT_CLASS_TYPE (object_class), @@ -1592,14 +1711,6 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - signals[CONNECTION_ERROR] = - g_signal_new (NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); - signals[CREDENTIALS_REQUEST] = g_signal_new (NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 2ef63d1e..d60d4a54 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -28,7 +28,8 @@ * Supplicant interface states * A mix of wpa_supplicant interface states and internal states. */ -enum { +typedef enum { + NM_SUPPLICANT_INTERFACE_STATE_INVALID = -1, NM_SUPPLICANT_INTERFACE_STATE_INIT = 0, NM_SUPPLICANT_INTERFACE_STATE_STARTING, NM_SUPPLICANT_INTERFACE_STATE_READY, @@ -43,8 +44,7 @@ enum { NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, NM_SUPPLICANT_INTERFACE_STATE_DOWN, - NM_SUPPLICANT_INTERFACE_STATE_LAST -}; +} NMSupplicantInterfaceState; #define NM_TYPE_SUPPLICANT_INTERFACE (nm_supplicant_interface_get_type ()) #define NM_SUPPLICANT_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterface)) @@ -64,11 +64,9 @@ enum { /* Signals */ #define NM_SUPPLICANT_INTERFACE_STATE "state" #define NM_SUPPLICANT_INTERFACE_REMOVED "removed" -#define NM_SUPPLICANT_INTERFACE_NEW_BSS "new-bss" #define NM_SUPPLICANT_INTERFACE_BSS_UPDATED "bss-updated" #define NM_SUPPLICANT_INTERFACE_BSS_REMOVED "bss-removed" #define NM_SUPPLICANT_INTERFACE_SCAN_DONE "scan-done" -#define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error" #define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request" typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass; @@ -83,19 +81,25 @@ NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self, gboolean available); -gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface, - NMSupplicantConfig * cfg, - GError **error); +typedef void (*NMSupplicantInterfaceAssocCb) (NMSupplicantInterface *iface, + GError *error, + gpointer user_data); + +void +nm_supplicant_interface_assoc (NMSupplicantInterface *self, + NMSupplicantConfig *cfg, + NMSupplicantInterfaceAssocCb callback, + gpointer user_data); void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface); const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface); -gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self, const GPtrArray *ssids); +void nm_supplicant_interface_request_scan (NMSupplicantInterface * self, const GPtrArray *ssids); -guint32 nm_supplicant_interface_get_state (NMSupplicantInterface * self); +NMSupplicantInterfaceState nm_supplicant_interface_get_state (NMSupplicantInterface * self); -const char *nm_supplicant_interface_state_to_string (guint32 state); +const char *nm_supplicant_interface_state_to_string (NMSupplicantInterfaceState state); gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self); diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c index cf53fb41..49650ab7 100644 --- a/src/supplicant/nm-supplicant-manager.c +++ b/src/supplicant/nm-supplicant-manager.c @@ -63,7 +63,7 @@ G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT) /*****************************************************************************/ -G_DEFINE_QUARK (nm-supplicant-error-quark, nm_supplicant_error); +NM_CACHED_QUARK_FCN ("nm-supplicant-error-quark", nm_supplicant_error_quark) /*****************************************************************************/ @@ -398,10 +398,7 @@ dispose (GObject *object) nm_clear_g_source (&priv->die_count_reset_id); - if (priv->cancellable) { - g_cancellable_cancel (priv->cancellable); - g_clear_object (&priv->cancellable); - } + nm_clear_g_cancellable (&priv->cancellable); if (priv->ifaces) { for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c index 9e220808..ce3e46d8 100644 --- a/src/supplicant/nm-supplicant-settings-verify.c +++ b/src/supplicant/nm-supplicant-settings-verify.c @@ -81,7 +81,10 @@ const char * phase1_allowed[] = {"peapver=0", "peapver=1", "peaplabel=1", "peap_outer_success=0", "include_tls_length=1", "sim_min_num_chal=3", "fast_provisioning=0", "fast_provisioning=1", "fast_provisioning=2", - "fast_provisioning=3", NULL }; + "fast_provisioning=3", "tls_disable_tlsv1_0=0", + "tls_disable_tlsv1_0=1", "tls_disable_tlsv1_1=0", + "tls_disable_tlsv1_1=1", "tls_disable_tlsv1_2=0", + "tls_disable_tlsv1_2=1", NULL }; const char * phase2_allowed[] = {"auth=PAP", "auth=CHAP", "auth=MSCHAP", "auth=MSCHAPV2", "auth=GTC", "auth=OTP", "auth=MD5", "auth=TLS", "autheap=MD5", diff --git a/src/systemd/sd-adapt/env-util.h b/src/systemd/sd-adapt/env-util.h new file mode 100644 index 00000000..637892c2 --- /dev/null +++ b/src/systemd/sd-adapt/env-util.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/src/systemd/sd-adapt/nm-sd-adapt.h b/src/systemd/sd-adapt/nm-sd-adapt.h index cf27c1af..a8ff18bc 100644 --- a/src/systemd/sd-adapt/nm-sd-adapt.h +++ b/src/systemd/sd-adapt/nm-sd-adapt.h @@ -56,7 +56,7 @@ _slog_level_to_nm (int slevel) if (nm_logging_enabled (_nm_l, LOGD_SYSTEMD)) { \ const char *_nm_location = strrchr ((""file), '/'); \ \ - _nm_log_impl (_nm_location ? _nm_location + 1 : (""file), (line), (func), _nm_l, LOGD_DHCP, _nm_e, ("%s"format), "libsystemd: ", ## __VA_ARGS__); \ + _nm_log_impl (_nm_location ? _nm_location + 1 : (""file), (line), (func), _nm_l, LOGD_DHCP, _nm_e, NULL, NULL, ("%s"format), "libsystemd: ", ## __VA_ARGS__); \ } \ (_nm_e > 0 ? -_nm_e : _nm_e); \ }) diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index 8ef0db7f..711580a4 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -32,6 +32,7 @@ #include "alloc-util.h" #include "ctype.h" +#include "env-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" @@ -555,13 +556,14 @@ static int parse_env_file_internal( } } - if (state == PRE_VALUE || - state == VALUE || - state == VALUE_ESCAPE || - state == SINGLE_QUOTE_VALUE || - state == SINGLE_QUOTE_VALUE_ESCAPE || - state == DOUBLE_QUOTE_VALUE || - state == DOUBLE_QUOTE_VALUE_ESCAPE) { + if (IN_SET(state, + PRE_VALUE, + VALUE, + VALUE_ESCAPE, + SINGLE_QUOTE_VALUE, + SINGLE_QUOTE_VALUE_ESCAPE, + DOUBLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE_ESCAPE)) { key[n_key] = 0; @@ -588,14 +590,9 @@ fail: return r; } -static int parse_env_file_push( +static int check_utf8ness_and_warn( const char *filename, unsigned line, - const char *key, char *value, - void *userdata, - int *n_pushed) { - - const char *k; - va_list aq, *ap = userdata; + const char *key, char *value) { if (!utf8_is_valid(key)) { _cleanup_free_ char *p = NULL; @@ -613,6 +610,23 @@ static int parse_env_file_push( return -EINVAL; } + return 0; +} + +static int parse_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata, + int *n_pushed) { + + const char *k; + va_list aq, *ap = userdata; + int r; + + r = check_utf8ness_and_warn(filename, line, key, value); + if (r < 0) + return r; + va_copy(aq, *ap); while ((k = va_arg(aq, const char *))) { @@ -655,6 +669,7 @@ int parse_env_file( return r < 0 ? r : n_pushed; } +#if 0 /* NM_IGNORED */ static int load_env_file_push( const char *filename, unsigned line, const char *key, char *value, @@ -664,27 +679,19 @@ static int load_env_file_push( char *p; int r; - if (!utf8_is_valid(key)) { - _cleanup_free_ char *t = utf8_escape_invalid(key); - - log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); - return -EINVAL; - } - - if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *t = utf8_escape_invalid(value); - - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); - return -EINVAL; - } + r = check_utf8ness_and_warn(filename, line, key, value); + if (r < 0) + return r; - p = strjoin(key, "=", strempty(value)); + p = strjoin(key, "=", value); if (!p) return -ENOMEM; - r = strv_consume(m, p); - if (r < 0) + r = strv_env_replace(m, p); + if (r < 0) { + free(p); return r; + } if (n_pushed) (*n_pushed)++; @@ -718,19 +725,9 @@ static int load_env_file_push_pairs( char ***m = userdata; int r; - if (!utf8_is_valid(key)) { - _cleanup_free_ char *t = utf8_escape_invalid(key); - - log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); - return -EINVAL; - } - - if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *t = utf8_escape_invalid(value); - - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); - return -EINVAL; - } + r = check_utf8ness_and_warn(filename, line, key, value); + if (r < 0) + return r; r = strv_extend(m, key); if (r < 0) @@ -769,6 +766,52 @@ int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ** return 0; } +static int merge_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata, + int *n_pushed) { + + char ***env = userdata; + char *expanded_value; + + assert(env); + + if (!value) { + log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key); + return 0; + } + + if (!env_name_is_valid(key)) { + log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key); + free(value); + return 0; + } + + expanded_value = replace_env(value, *env, + REPLACE_ENV_USE_ENVIRONMENT| + REPLACE_ENV_ALLOW_BRACELESS| + REPLACE_ENV_ALLOW_EXTENDED); + if (!expanded_value) + return -ENOMEM; + + free_and_replace(value, expanded_value); + + return load_env_file_push(filename, line, key, value, env, n_pushed); +} + +int merge_env_file( + char ***env, + FILE *f, + const char *fname) { + + /* NOTE: this function supports braceful and braceless variable expansions, + * plus "extended" substitutions, unlike other exported parsing functions. + */ + + return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL); +} + static void write_env_var(FILE *f, const char *v) { const char *p; @@ -828,6 +871,7 @@ int write_env_file(const char *fname, char **l) { unlink(p); return r; } +#endif /* NM_IGNORED */ int executable_is_script(const char *path, char **interpreter) { int r; @@ -1349,6 +1393,25 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { return fd; } +int open_serialization_fd(const char *ident) { + int fd = -1; + + fd = memfd_create(ident, MFD_CLOEXEC); + if (fd < 0) { + const char *path; + + path = getpid() == 1 ? "/run/systemd" : "/tmp"; + fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC); + if (fd < 0) + return fd; + + log_debug("Serializing %s to %s.", ident, path); + } else + log_debug("Serializing %s to memfd.", ident); + + return fd; +} + int link_tmpfile(int fd, const char *path, const char *target) { assert(fd >= 0); diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h index 17b38a5d..e547614c 100644 --- a/src/systemd/src/basic/fileio.h +++ b/src/systemd/src/basic/fileio.h @@ -48,6 +48,8 @@ int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); +int merge_env_file(char ***env, FILE *f, const char *fname); + int write_env_file(const char *fname, char **l); int executable_is_script(const char *path, char **interpreter); @@ -84,6 +86,7 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) int open_tmpfile_unlinkable(const char *directory, int flags); int open_tmpfile_linkable(const char *target, int flags, char **ret_path); +int open_serialization_fd(const char *ident); int link_tmpfile(int fd, const char *path, const char *target); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index 3919fbcd..5e980329 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -730,6 +730,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -errno; if (S_ISLNK(st.st_mode)) { + char *joined; + _cleanup_free_ char *destination = NULL; /* This is a symlink, in this case read the destination. But let's make sure we don't follow @@ -753,9 +755,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fd < 0) return -errno; - free_and_replace(buffer, destination); - - todo = buffer; free(done); /* Note that we do not revalidate the root, we take it as is. */ @@ -767,19 +766,17 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - } else { - char *joined; + } - /* A relative destination. If so, this is what we'll prefix what's left to do with what - * we just read, and start the loop again, but remain in the current directory. */ + /* Prefix what's left to do with what we just read, and start the loop again, + * but remain in the current directory. */ - joined = strjoin("/", destination, todo); - if (!joined) - return -ENOMEM; + joined = strjoin("/", destination, todo); + if (!joined) + return -ENOMEM; - free(buffer); - todo = buffer = joined; - } + free(buffer); + todo = buffer = joined; continue; } @@ -806,8 +803,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - *ret = done; - done = NULL; + if (ret) { + *ret = done; + done = NULL; + } return exists; } diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 5fe5c71f..094acf17 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -91,3 +91,9 @@ static inline void rmdir_and_free(char *p) { free(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free); + +static inline void unlink_and_free(char *p) { + (void) unlink(p); + free(p); +} +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c index 950e3230..2da8f8a2 100644 --- a/src/systemd/src/basic/hexdecoct.c +++ b/src/systemd/src/basic/hexdecoct.c @@ -74,10 +74,10 @@ int unhexchar(char c) { } char *hexmem(const void *p, size_t l) { - char *r, *z; const uint8_t *x; + char *r, *z; - z = r = malloc(l * 2 + 1); + z = r = new(char, l * 2 + 1); if (!r) return NULL; @@ -99,6 +99,9 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { assert(len); assert(p); + if (l % 2 != 0) + return -EINVAL; + z = r = malloc((l + 1) / 2 + 1); if (!r) return -ENOMEM; @@ -109,12 +112,10 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { a = unhexchar(x[0]); if (a < 0) return a; - else if (x+1 < p + l) { - b = unhexchar(x[1]); - if (b < 0) - return b; - } else - b = 0; + + b = unhexchar(x[1]); + if (b < 0) + return b; *(z++) = (uint8_t) a << 4 | (uint8_t) b; } diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c index 732a0ce7..823aa26a 100644 --- a/src/systemd/src/basic/hostname-util.c +++ b/src/systemd/src/basic/hostname-util.c @@ -47,6 +47,7 @@ bool hostname_is_set(void) { return true; } +#if 0 /* NM_IGNORED */ char* gethostname_malloc(void) { struct utsname u; @@ -57,10 +58,11 @@ char* gethostname_malloc(void) { assert_se(uname(&u) >= 0); if (isempty(u.nodename) || streq(u.nodename, "(none)")) - return strdup(u.sysname); + return strdup(FALLBACK_HOSTNAME); return strdup(u.nodename); } +#endif /* NM_IGNORED */ int gethostname_strict(char **ret) { struct utsname u; diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c index 37dc14f0..1140ca76 100644 --- a/src/systemd/src/basic/in-addr-util.c +++ b/src/systemd/src/basic/in-addr-util.c @@ -68,6 +68,18 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) { return -EAFNOSUPPORT; } +int in_addr_is_multicast(int family, const union in_addr_union *u) { + assert(u); + + if (family == AF_INET) + return IN_MULTICAST(be32toh(u->in.s_addr)); + + if (family == AF_INET6) + return IN6_IS_ADDR_MULTICAST(&u->in6); + + return -EAFNOSUPPORT; +} + bool in4_addr_is_localhost(const struct in_addr *a) { assert(a); diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h index 64a812c3..51a5aa67 100644 --- a/src/systemd/src/basic/in-addr-util.h +++ b/src/systemd/src/basic/in-addr-util.h @@ -39,6 +39,8 @@ struct in_addr_data { bool in4_addr_is_null(const struct in_addr *a); int in_addr_is_null(int family, const union in_addr_union *u); +int in_addr_is_multicast(int family, const union in_addr_union *u); + bool in4_addr_is_link_local(const struct in_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h index ccf2930f..d8335d12 100644 --- a/src/systemd/src/basic/log.h +++ b/src/systemd/src/basic/log.h @@ -216,13 +216,13 @@ bool log_on_console(void) _pure_; const char *log_target_to_string(LogTarget target) _const_; LogTarget log_target_from_string(const char *s) _pure_; -/* Helpers to prepare various fields for structured logging */ +/* Helper to prepare various field for structured logging */ #define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ -#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x) void log_received_signal(int level, const struct signalfd_siginfo *si); void log_set_upgrade_syslog_to_journal(bool b); +void log_set_always_reopen_console(bool b); int log_syntax_internal( const char *unit, diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index 9a7a0bbc..8ffd9464 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -25,7 +25,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <xlocale.h> #include "alloc-util.h" #include "extract-word.h" diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index dec95041..12ba6ae7 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -705,10 +705,7 @@ bool filename_is_valid(const char *p) { if (isempty(p)) return false; - if (streq(p, ".")) - return false; - - if (streq(p, "..")) + if (dot_or_dot_dot(p)) return false; e = strchrnul(p, '/'); @@ -727,14 +724,17 @@ bool path_is_safe(const char *p) { if (isempty(p)) return false; - if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) + if (dot_or_dot_dot(p)) + return false; + + if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) return false; if (strlen(p)+1 > PATH_MAX) return false; /* The following two checks are not really dangerous, but hey, they still are confusing */ - if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) + if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) return false; if (strstr(p, "//")) @@ -900,3 +900,16 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version) return false; } #endif /* NM_IGNORED */ + +bool dot_or_dot_dot(const char *path) { + if (!path) + return false; + if (path[0] != '.') + return false; + if (path[1] == 0) + return true; + if (path[1] != '.') + return false; + + return path[2] == 0; +} diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index 349cdac7..35aef3ad 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -141,3 +141,5 @@ bool is_device_path(const char *path); bool is_deviceallow_pattern(const char *path); int systemd_installation_has_version(const char *root, unsigned minimal_version); + +bool dot_or_dot_dot(const char *path); diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index 57bc4b70..e63dd0db 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -116,6 +116,30 @@ int socket_address_parse(SocketAddress *a, const char *s) { memcpy(a->sockaddr.un.sun_path+1, s+1, l); a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l; + } else if (startswith(s, "vsock:")) { + /* AF_VSOCK socket in vsock:cid:port notation */ + const char *cid_start = s + strlen("vsock:"); + + e = strchr(cid_start, ':'); + if (!e) + return -EINVAL; + + r = safe_atou(e+1, &u); + if (r < 0) + return r; + + n = strndupa(cid_start, e - cid_start); + if (!isempty(n)) { + r = safe_atou(n, &a->sockaddr.vm.svm_cid); + if (r < 0) + return r; + } else + a->sockaddr.vm.svm_cid = VMADDR_CID_ANY; + + a->sockaddr.vm.svm_family = AF_VSOCK; + a->sockaddr.vm.svm_port = u; + a->size = sizeof(struct sockaddr_vm); + } else { e = strchr(s, ':'); if (e) { @@ -292,6 +316,15 @@ int socket_address_verify(const SocketAddress *a) { return 0; + case AF_VSOCK: + if (a->size != sizeof(struct sockaddr_vm)) + return -EINVAL; + + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) + return -EINVAL; + + return 0; + default: return -EAFNOSUPPORT; } @@ -397,6 +430,15 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { break; + case AF_VSOCK: + if (a->sockaddr.vm.svm_cid != b->sockaddr.vm.svm_cid) + return false; + + if (a->sockaddr.vm.svm_port != b->sockaddr.vm.svm_port) + return false; + + break; + default: /* Cannot compare, so we assume the addresses are different */ return false; @@ -483,15 +525,27 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { return socket_address_equal(a, &b); } -int sockaddr_port(const struct sockaddr *_sa) { +int sockaddr_port(const struct sockaddr *_sa, unsigned *port) { union sockaddr_union *sa = (union sockaddr_union*) _sa; assert(sa); - if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) - return -EAFNOSUPPORT; + switch (sa->sa.sa_family) { + case AF_INET: + *port = be16toh(sa->in.sin_port); + return 0; - return be16toh(sa->sa.sa_family == AF_INET6 ? sa->in6.sin6_port : sa->in.sin_port); + case AF_INET6: + *port = be16toh(sa->in6.sin6_port); + return 0; + + case AF_VSOCK: + *port = sa->vm.svm_port; + return 0; + + default: + return -EAFNOSUPPORT; + } } int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { @@ -594,6 +648,18 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ break; + case AF_VSOCK: + if (include_port) + r = asprintf(&p, + "vsock:%u:%u", + sa->vm.svm_cid, + sa->vm.svm_port); + else + r = asprintf(&p, "vsock:%u", sa->vm.svm_cid); + if (r < 0) + return -ENOMEM; + break; + default: return -EOPNOTSUPP; } @@ -751,6 +817,9 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b if (a->sa.sa_family == AF_INET6) return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0; + if (a->sa.sa_family == AF_VSOCK) + return a->vm.svm_cid == b->vm.svm_cid; + return false; } @@ -811,7 +880,7 @@ bool ifname_valid(const char *p) { if (strlen(p) >= IFNAMSIZ) return false; - if (STR_IN_SET(p, ".", "..")) + if (dot_or_dot_dot(p)) return false; while (*p) { @@ -834,6 +903,26 @@ bool ifname_valid(const char *p) { return true; } +bool address_label_valid(const char *p) { + + if (isempty(p)) + return false; + + if (strlen(p) >= IFNAMSIZ) + return false; + + while (*p) { + if ((uint8_t) *p >= 127U) + return false; + + if ((uint8_t) *p <= 31U) + return false; + p++; + } + + return true; +} + int getpeercred(int fd, struct ucred *ucred) { socklen_t n = sizeof(struct ucred); struct ucred u; @@ -1012,6 +1101,7 @@ fallback: return (ssize_t) k; } +#if 0 /* NM_IGNORED */ int flush_accept(int fd) { struct pollfd pollfd = { @@ -1081,3 +1171,4 @@ int socket_ioctl_fd(void) { return fd; } +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index 2ef572ba..19a9ddb2 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -30,6 +30,7 @@ #include <linux/if_packet.h> #include "macro.h" +#include "missing.h" #include "util.h" union sockaddr_union { @@ -40,6 +41,9 @@ union sockaddr_union { struct sockaddr_nl nl; struct sockaddr_storage storage; struct sockaddr_ll ll; +#if 0 /* NM_IGNORED */ + struct sockaddr_vm vm; +#endif /* NM_IGNORED */ }; typedef struct SocketAddress { @@ -100,7 +104,7 @@ const char* socket_address_get_path(const SocketAddress *a); bool socket_ipv6_is_supported(void); -int sockaddr_port(const struct sockaddr *_sa) _pure_; +int sockaddr_port(const struct sockaddr *_sa, unsigned *port); int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); int getpeername_pretty(int fd, bool include_port, char **ret); @@ -124,6 +128,7 @@ int ip_tos_to_string_alloc(int i, char **s); int ip_tos_from_string(const char *s); bool ifname_valid(const char *p); +bool address_label_valid(const char *p); int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c index aeb9e2a9..406d6d3c 100644 --- a/src/systemd/src/basic/string-util.c +++ b/src/systemd/src/basic/string-util.c @@ -825,6 +825,7 @@ int free_and_strdup(char **p, const char *s) { return 1; } +#if !HAVE_DECL_EXPLICIT_BZERO /* * Pointer to memset is volatile so that compiler must de-reference * the pointer and can't assume that it points to any function in @@ -835,19 +836,19 @@ typedef void *(*memset_t)(void *,int,size_t); static volatile memset_t memset_func = memset; -void* memory_erase(void *p, size_t l) { - return memset_func(p, 'x', l); +void explicit_bzero(void *p, size_t l) { + memset_func(p, '\0', l); } +#endif char* string_erase(char *x) { - if (!x) return NULL; /* A delicious drop of snake-oil! To be called on memory where * we stored passphrases or so, after we used them. */ - - return memory_erase(x, strlen(x)); + explicit_bzero(x, strlen(x)); + return x; } char *string_free_erase(char *s) { diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index e99f7964..be44dedf 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -189,7 +189,10 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const return memmem(haystack, haystacklen, needle, needlelen); } -void* memory_erase(void *p, size_t l); +#if !HAVE_DECL_EXPLICIT_BZERO +void explicit_bzero(void *p, size_t l); +#endif + char *string_erase(char *x); char *string_free_erase(char *s); diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index fa488787..e8158d55 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -187,7 +187,7 @@ usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) { usec_t timespec_load(const struct timespec *ts) { assert(ts); - if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) + if (ts->tv_sec < 0 || ts->tv_nsec < 0) return USEC_INFINITY; if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) @@ -201,7 +201,7 @@ usec_t timespec_load(const struct timespec *ts) { nsec_t timespec_load_nsec(const struct timespec *ts) { assert(ts); - if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) + if (ts->tv_sec < 0 || ts->tv_nsec < 0) return NSEC_INFINITY; if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC) @@ -213,7 +213,8 @@ nsec_t timespec_load_nsec(const struct timespec *ts) { struct timespec *timespec_store(struct timespec *ts, usec_t u) { assert(ts); - if (u == USEC_INFINITY) { + if (u == USEC_INFINITY || + u / USEC_PER_SEC >= TIME_T_MAX) { ts->tv_sec = (time_t) -1; ts->tv_nsec = (long) -1; return ts; @@ -229,8 +230,7 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u) { usec_t timeval_load(const struct timeval *tv) { assert(tv); - if (tv->tv_sec == (time_t) -1 && - tv->tv_usec == (suseconds_t) -1) + if (tv->tv_sec < 0 || tv->tv_usec < 0) return USEC_INFINITY; if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) @@ -244,7 +244,8 @@ usec_t timeval_load(const struct timeval *tv) { struct timeval *timeval_store(struct timeval *tv, usec_t u) { assert(tv); - if (u == USEC_INFINITY) { + if (u == USEC_INFINITY|| + u / USEC_PER_SEC > TIME_T_MAX) { tv->tv_sec = (time_t) -1; tv->tv_usec = (suseconds_t) -1; } else { @@ -291,9 +292,11 @@ static char *format_timestamp_internal( if (t <= 0 || t == USEC_INFINITY) return NULL; /* Timestamp is unset */ + /* Let's not format times with years > 9999 */ + if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) + return NULL; + sec = (time_t) (t / USEC_PER_SEC); /* Round down */ - if ((usec_t) sec != (t / USEC_PER_SEC)) - return NULL; /* overflow? */ if (!localtime_or_gmtime_r(&sec, &tm, utc)) return NULL; @@ -556,12 +559,12 @@ void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { } int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { - unsigned long long a, b; + uint64_t a, b; assert(value); assert(t); - if (sscanf(value, "%llu %llu", &a, &b) != 2) { + if (sscanf(value, "%" PRIu64 "%" PRIu64, &a, &b) != 2) { log_debug("Failed to parse dual timestamp value \"%s\": %m", value); return -EINVAL; } @@ -835,16 +838,23 @@ parse_usec: from_tm: x = mktime_or_timegm(&tm, utc); - if (x == (time_t) -1) + if (x < 0) return -EINVAL; if (weekday >= 0 && tm.tm_wday != weekday) return -EINVAL; ret = (usec_t) x * USEC_PER_SEC + x_usec; + if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX) + return -EINVAL; finish: + if (ret + plus < ret) /* overflow? */ + return -EINVAL; ret += plus; + if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX) + return -EINVAL; + if (ret > minus) ret -= minus; else diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index f67a4474..7463507f 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -181,3 +181,14 @@ static inline usec_t usec_sub(usec_t timestamp, int64_t delta) { return timestamp - delta; } + +#if SIZEOF_TIME_T == 8 +/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit year + * territory. However, since we want to stay away from this in all timezones we take one day off. */ +#define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000) +#elif SIZEOF_TIME_T == 4 +/* With a 32bit time_t we can't go beyond 2038... */ +#define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000) +#else +#error "Yuck, time_t is neither 4 not 8 bytes wide?" +#endif diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 09651e7d..563ee87e 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -61,9 +61,6 @@ #include "user-util.h" #include "util.h" -/* Put this test here for a lack of better place */ -assert_cc(EAGAIN == EWOULDBLOCK); - #if 0 /* NM_IGNORED */ int saved_argc = 0; char **saved_argv = NULL; @@ -85,146 +82,6 @@ size_t page_size(void) { } #if 0 /* NM_IGNORED */ -static int do_execute(char **directories, usec_t timeout, char *argv[]) { - _cleanup_hashmap_free_free_ Hashmap *pids = NULL; - _cleanup_set_free_free_ Set *seen = NULL; - char **directory; - - /* We fork this all off from a child process so that we can - * somewhat cleanly make use of SIGALRM to set a time limit */ - - (void) reset_all_signal_handlers(); - (void) reset_signal_mask(); - - assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); - - pids = hashmap_new(NULL); - if (!pids) - return log_oom(); - - seen = set_new(&string_hash_ops); - if (!seen) - return log_oom(); - - STRV_FOREACH(directory, directories) { - _cleanup_closedir_ DIR *d; - struct dirent *de; - - d = opendir(*directory); - if (!d) { - if (errno == ENOENT) - continue; - - return log_error_errno(errno, "Failed to open directory %s: %m", *directory); - } - - FOREACH_DIRENT(de, d, break) { - _cleanup_free_ char *path = NULL; - pid_t pid; - int r; - - if (!dirent_is_file(de)) - continue; - - if (set_contains(seen, de->d_name)) { - log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name); - continue; - } - - r = set_put_strdup(seen, de->d_name); - if (r < 0) - return log_oom(); - - path = strjoin(*directory, "/", de->d_name); - if (!path) - return log_oom(); - - if (null_or_empty_path(path)) { - log_debug("%s is empty (a mask).", path); - continue; - } - - pid = fork(); - if (pid < 0) { - log_error_errno(errno, "Failed to fork: %m"); - continue; - } else if (pid == 0) { - char *_argv[2]; - - assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); - - if (!argv) { - _argv[0] = path; - _argv[1] = NULL; - argv = _argv; - } else - argv[0] = path; - - execv(path, argv); - return log_error_errno(errno, "Failed to execute %s: %m", path); - } - - log_debug("Spawned %s as " PID_FMT ".", path, pid); - - r = hashmap_put(pids, PID_TO_PTR(pid), path); - if (r < 0) - return log_oom(); - path = NULL; - } - } - - /* Abort execution of this process after the timout. We simply - * rely on SIGALRM as default action terminating the process, - * and turn on alarm(). */ - - if (timeout != USEC_INFINITY) - alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); - - while (!hashmap_isempty(pids)) { - _cleanup_free_ char *path = NULL; - pid_t pid; - - pid = PTR_TO_PID(hashmap_first_key(pids)); - assert(pid > 0); - - path = hashmap_remove(pids, PID_TO_PTR(pid)); - assert(path); - - wait_for_terminate_and_warn(path, pid, true); - } - - return 0; -} - -void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) { - pid_t executor_pid; - int r; - char *name; - char **dirs = (char**) directories; - - assert(!strv_isempty(dirs)); - - name = basename(dirs[0]); - assert(!isempty(name)); - - /* Executes all binaries in the directories in parallel and waits - * for them to finish. Optionally a timeout is applied. If a file - * with the same name exists in more than one directory, the - * earliest one wins. */ - - executor_pid = fork(); - if (executor_pid < 0) { - log_error_errno(errno, "Failed to fork: %m"); - return; - - } else if (executor_pid == 0) { - r = do_execute(dirs, timeout, argv); - _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); - } - - wait_for_terminate_and_warn(name, executor_pid, true); -} - bool plymouth_running(void) { return access("/run/plymouth/pid", F_OK) >= 0; } diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index c3802a81..c7da6c39 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -65,8 +65,6 @@ static inline const char* enable_disable(bool b) { return b ? "enable" : "disable"; } -void execute_directories(const char* const* directories, usec_t timeout, char *argv[]); - bool plymouth_running(void); bool display_is_local(const char *display) _pure_; diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index 8c678626..69bd3e75 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -60,7 +60,7 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about*/ + /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */ diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index bba3a752..4466a050 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -49,6 +49,13 @@ int lldp_network_bind_raw_socket(int ifindex) { .filter = (struct sock_filter*) filter, }; + struct packet_mreq mreq = { + .mr_ifindex = ifindex, + .mr_type = PACKET_MR_MULTICAST, + .mr_alen = ETH_ALEN, + .mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 } + }; + union sockaddr_union saddrll = { .ll.sll_family = AF_PACKET, .ll.sll_ifindex = ifindex, @@ -68,6 +75,20 @@ int lldp_network_bind_raw_socket(int ifindex) { if (r < 0) return -errno; + r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (r < 0) + return -errno; + + mreq.mr_address[ETH_ALEN - 1] = 0x03; + r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (r < 0) + return -errno; + + mreq.mr_address[ETH_ALEN - 1] = 0x0E; + r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (r < 0) + return -errno; + r = bind(fd, &saddrll.sa, sizeof(saddrll.ll)); if (r < 0) return -errno; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 7809a812..17393e20 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -829,6 +829,15 @@ static int client_send_request(sd_dhcp_client *client) { return r; } + if (client->vendor_class_identifier) { + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, + strlen(client->vendor_class_identifier), + client->vendor_class_identifier); + if (r < 0) + return r; + } + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 913c1adb..3976768b 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -244,8 +244,6 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) goto fail; - - acd->n_conflict = 0; } else { r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 2420c99f..47fc141c 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -250,6 +250,12 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); } +int sd_ipv4ll_restart(sd_ipv4ll *ll) { + ll->address = 0; + + return sd_ipv4ll_start(ll); +} + #define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) int sd_ipv4ll_start(sd_ipv4ll *ll) { diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index 66c9780e..2a64a99b 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -21,6 +21,7 @@ #include "nm-sd-adapt.h" #include <arpa/inet.h> +#include <linux/sockios.h> #include "sd-lldp.h" diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index a51ab9e6..3f7b703e 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -732,7 +732,6 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig /* If all the mask is all-zero we can get rid of the structure */ hashmap_remove(e->signal_data, &d->priority); - assert(!d->current); safe_close(d->fd); free(d); return; @@ -2230,11 +2229,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { } static int source_dispatch(sd_event_source *s) { + EventSourceType saved_type; int r = 0; assert(s); assert(s->pending || s->type == SOURCE_EXIT); + /* Save the event source type, here, so that we still know it after the event callback which might invalidate + * the event. */ + saved_type = s->type; + if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) { r = source_set_pending(s, false); if (r < 0) @@ -2322,7 +2326,7 @@ static int source_dispatch(sd_event_source *s) { if (r < 0) log_debug_errno(r, "Event source %s (type %s) returned error, disabling: %m", - strna(s->description), event_source_type_to_string(s->type)); + strna(s->description), event_source_type_to_string(saved_type)); if (s->n_ref == 0) source_free(s); diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h index 3bb886be..97c39438 100644 --- a/src/systemd/src/systemd/_sd-common.h +++ b/src/systemd/src/systemd/_sd-common.h @@ -22,8 +22,8 @@ /* This is a private header; never even think of including this directly! */ -#if __INCLUDE_LEVEL__ <= 1 -#error "Do not include _sd-common.h directly; it is a private header." +#if defined(__INCLUDE_LEVEL__) && __INCLUDE_LEVEL__ <= 1 +# error "Do not include _sd-common.h directly; it is a private header." #endif #ifndef _sd_printf_ diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index cc26b7df..f8cb8956 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -69,7 +69,7 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); -#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED +#if defined _GNU_SOURCE || _POSIX_C_SOURCE >= 199309L typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); #else typedef void* sd_event_child_handler_t; diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index 6cc8e4ac..9b38969b 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -100,6 +100,9 @@ int sd_id128_get_invocation(sd_id128_t *ret); ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ 0 }) +#define SD_ID128_MAKE_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + #a #b #c #d #e #f #g #h #i #j #k #l #m #n #o #p + _sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) { return memcmp(&a, &b, 16) == 0; } diff --git a/src/systemd/src/systemd/sd-ipv4ll.h b/src/systemd/src/systemd/sd-ipv4ll.h index 1109ec52..5ba92083 100644 --- a/src/systemd/src/systemd/sd-ipv4ll.h +++ b/src/systemd/src/systemd/sd-ipv4ll.h @@ -47,6 +47,7 @@ int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); int sd_ipv4ll_is_running(sd_ipv4ll *ll); +int sd_ipv4ll_restart(sd_ipv4ll *ll); int sd_ipv4ll_start(sd_ipv4ll *ll); int sd_ipv4ll_stop(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index dd2a58a0..edb5c1aa 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -97,7 +97,7 @@ setup_config (GError **error, const char *config_file, const char *intern_config argv = (char **)args->pdata; argc = args->len; - cli = nm_config_cmd_line_options_new (); + cli = nm_config_cmd_line_options_new (FALSE); context = g_option_context_new (NULL); nm_config_cmd_line_options_add_to_entries (cli, context); diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c index fbed7799..492e1b1f 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -751,7 +751,7 @@ _mi_rebucket (GRand *rand, guint num_values, guint num_buckets, NMMultiIndexOper op == MI_OP_ADD ? "ADD" : (op == MI_OP_REMOVE ? "REM" : "MOV"), bucket_old, had_bucket_old ? '*' : ' ', bucket, had_bucket ? '*' : ' ', - (long long unsigned) buckets_old, (long long unsigned) v->buckets, + (unsigned long long) buckets_old, (unsigned long long) v->buckets, buckets_old != v->buckets ? "(changed)" : "(unchanged)"); #endif diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 81d8e05c..37bbc5ca 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -23,6 +23,9 @@ #include <string.h> #include <errno.h> +/* need math.h for isinf() and INFINITY. No need to link with -lm */ +#include <math.h> + #include "NetworkManagerUtils.h" #include "nm-core-internal.h" @@ -225,7 +228,7 @@ test_nm_utils_log_connection_diff (void) * early without doing anything. Hence, in the normal testing, this test does nothing. * It only gets interesting, when run verbosely with NMTST_DEBUG=debug ... */ - nm_log (LOGL_DEBUG, LOGD_CORE, "START TEST test_nm_utils_log_connection_diff..."); + nm_log (LOGL_DEBUG, LOGD_CORE, NULL, NULL, "START TEST test_nm_utils_log_connection_diff..."); connection = nm_simple_connection_new (); nm_connection_add_setting (connection, nm_setting_connection_new ()); @@ -309,6 +312,30 @@ _match_connection_new (void) return connection; } +static NMConnection * +_match_connection (GSList *connections, + NMConnection *original, + gboolean device_has_carrier, + gint64 default_v4_metric, + gint64 default_v6_metric) +{ + NMConnection **list; + guint i, len; + + len = g_slist_length (connections); + g_assert (len < 10); + + list = g_alloca ((len + 1) * sizeof (NMConnection *)); + for (i = 0; i < len; i++, connections = connections->next) { + g_assert (connections); + g_assert (connections->data); + list[i] = connections->data; + } + list[i] = NULL; + + return nm_utils_match_connection (list, original, device_has_carrier, default_v4_metric, default_v6_metric, NULL, NULL); +} + static void test_connection_match_basic (void) { @@ -320,7 +347,7 @@ test_connection_match_basic (void) copy = nm_simple_connection_new_clone (orig); connections = g_slist_append (connections, copy); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); /* Now change a material property like IPv4 method and ensure matching fails */ @@ -329,7 +356,7 @@ test_connection_match_basic (void) g_object_set (G_OBJECT (s_ip4), NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == NULL); g_slist_free (connections); @@ -365,7 +392,7 @@ test_connection_match_ip6_method (void) NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); g_slist_free (connections); @@ -399,7 +426,7 @@ test_connection_match_ip6_method_ignore (void) NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); g_slist_free (connections); @@ -433,7 +460,7 @@ test_connection_match_ip6_method_ignore_auto (void) NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); g_slist_free (connections); @@ -469,11 +496,11 @@ test_connection_match_ip4_method (void) NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, NULL); - matched = nm_utils_match_connection (connections, orig, FALSE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, FALSE, 0, 0); g_assert (matched == copy); /* Ensure when carrier=true matching fails */ - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == NULL); g_slist_free (connections); @@ -507,7 +534,7 @@ test_connection_match_interface_name (void) NM_SETTING_CONNECTION_INTERFACE_NAME, NULL, NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); g_slist_free (connections); @@ -544,7 +571,7 @@ test_connection_match_wired (void) NM_SETTING_WIRED_S390_NETTYPE, "qeth", NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); g_slist_free (connections); @@ -576,7 +603,7 @@ test_connection_match_wired2 (void) * the connections match. It can happen if assuming VLAN devices. */ nm_connection_remove_setting (orig, NM_TYPE_SETTING_WIRED); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == copy); g_slist_free (connections); @@ -601,7 +628,7 @@ test_connection_match_cloned_mac (void) NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "52:54:00:ab:db:23", NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == fuzzy); exact = nm_simple_connection_new_clone (orig); @@ -612,14 +639,14 @@ test_connection_match_cloned_mac (void) NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "52:54:00:ab:db:23", NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == exact); g_object_set (G_OBJECT (s_wired), NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "52:54:00:ab:db:24", NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched == fuzzy); g_slist_free (connections); @@ -679,7 +706,7 @@ test_connection_no_match_ip4_addr (void) nm_setting_ip_config_add_address (s_ip4, nm_addr); nm_ip_address_unref (nm_addr); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched != copy); g_slist_free (connections); @@ -725,7 +752,7 @@ test_connection_no_match_vlan (void) NM_SETTING_VLAN_FLAGS, 0, NULL); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched != copy); /* Check that the connections do not match if VLAN priorities differ */ @@ -735,7 +762,7 @@ test_connection_no_match_vlan (void) g_object_set (G_OBJECT (s_vlan_copy), NM_SETTING_VLAN_FLAGS, 0, NULL); nm_setting_vlan_add_priority_str (s_vlan_copy, NM_VLAN_INGRESS_MAP, "4:2"); - matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL); + matched = _match_connection (connections, orig, TRUE, 0, 0); g_assert (matched != copy); g_slist_free (connections); @@ -775,7 +802,7 @@ test_connection_match_ip4_routes1 (void) nmtst_setting_ip_config_add_route (s_ip4, "172.25.17.0", 24, "10.0.0.3", 20); /* Try to match the connections */ - matched = nm_utils_match_connection (connections, orig, FALSE, 100, 0, NULL, NULL); + matched = _match_connection (connections, orig, FALSE, 100, 0); g_assert (matched == NULL); } @@ -812,9 +839,9 @@ test_connection_match_ip4_routes2 (void) nmtst_setting_ip_config_add_route (s_ip4, "172.25.16.0", 24, "10.0.0.2", 100); /* Try to match the connections using different default metrics */ - matched = nm_utils_match_connection (connections, orig, FALSE, 100, 0, NULL, NULL); + matched = _match_connection (connections, orig, FALSE, 100, 0); g_assert (matched == copy); - matched = nm_utils_match_connection (connections, orig, FALSE, 500, 0, NULL, NULL); + matched = _match_connection (connections, orig, FALSE, 500, 0); g_assert (matched == NULL); } @@ -849,9 +876,9 @@ test_connection_match_ip6_routes (void) nmtst_setting_ip_config_add_route (s_ip6, "2001:db8:a:b:0:0:0:0", 64, "fd01::16", 50); /* Try to match the connections */ - matched = nm_utils_match_connection (connections, orig, FALSE, 0, 100, NULL, NULL); + matched = _match_connection (connections, orig, FALSE, 0, 100); g_assert (matched == NULL); - matched = nm_utils_match_connection (connections, orig, FALSE, 0, 50, NULL, NULL); + matched = _match_connection (connections, orig, FALSE, 0, 50); g_assert (matched == copy); } @@ -870,6 +897,12 @@ _create_connection_autoconnect (const char *id, gboolean autoconnect, int autoco return c; } +static int +_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + return nm_utils_cmp_connection_by_autoconnect_priority (*((NMConnection **) pa), *((NMConnection **) pb)); +} + static void _test_connection_sort_autoconnect_priority_one (NMConnection **list, gboolean shuffle) { @@ -892,12 +925,12 @@ _test_connection_sort_autoconnect_priority_one (NMConnection **list, gboolean sh } /* sort it... */ - g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority); + g_ptr_array_sort_with_data (connections, _cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; i < count; i++) { if (list[i] == connections->pdata[i]) continue; - if (shuffle && nm_utils_cmp_connection_by_autoconnect_priority (&list[i], (NMConnection **) &connections->pdata[i]) == 0) + if (shuffle && nm_utils_cmp_connection_by_autoconnect_priority (list[i], connections->pdata[i]) == 0) continue; g_message ("After sorting, the order of connections is not as expected!! Offending index: %d", i); for (j = 0; j < count; j++) @@ -956,13 +989,25 @@ test_connection_sort_autoconnect_priority (void) /*****************************************************************************/ #define MATCH_S390 "S390:" +#define MATCH_DRIVER "DRIVER:" static NMMatchSpecMatchType _test_match_spec_device (const GSList *specs, const char *match_str) { if (match_str && g_str_has_prefix (match_str, MATCH_S390)) - return nm_match_spec_device (specs, NULL, NULL, NULL, &match_str[NM_STRLEN (MATCH_S390)]); - return nm_match_spec_device (specs, match_str, NULL, NULL, NULL); + return nm_match_spec_device (specs, NULL, NULL, NULL, NULL, NULL, &match_str[NM_STRLEN (MATCH_S390)]); + if (match_str && g_str_has_prefix (match_str, MATCH_DRIVER)) { + gs_free char *s = g_strdup (&match_str[NM_STRLEN (MATCH_DRIVER)]); + char *t; + + t = strchr (s, '|'); + if (t) { + t[0] = '\0'; + t++; + } + return nm_match_spec_device (specs, NULL, NULL, s, t, NULL, NULL); + } + return nm_match_spec_device (specs, match_str, NULL, NULL, NULL, NULL, NULL); } static void @@ -1067,6 +1112,10 @@ test_match_spec_device (void) S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"), NULL, NULL); + _do_test_match_spec_device ("except:*", + NULL, + S (NULL), + S ("a")); _do_test_match_spec_device ("interface-name:=em*", S ("em*"), NULL, @@ -1108,6 +1157,23 @@ test_match_spec_device (void) NULL, S (NULL), S (MATCH_S390"0.0.1000", MATCH_S390"0.0.1000,deadbeef", MATCH_S390"0.0.1000,0.0.1001", MATCH_S390"0.0.1000,0.0.1002")); + + _do_test_match_spec_device ("driver:DRV", + S (MATCH_DRIVER"DRV", MATCH_DRIVER"DRV|1.6"), + S (MATCH_DRIVER"DR", MATCH_DRIVER"DR*"), + NULL); + _do_test_match_spec_device ("driver:DRV//", + S (MATCH_DRIVER"DRV/"), + S (MATCH_DRIVER"DRV/|1.6", MATCH_DRIVER"DR", MATCH_DRIVER"DR*"), + NULL); + _do_test_match_spec_device ("driver:DRV//*", + S (MATCH_DRIVER"DRV/", MATCH_DRIVER"DRV/|1.6"), + S (MATCH_DRIVER"DR", MATCH_DRIVER"DR*"), + NULL); + _do_test_match_spec_device ("driver:DRV//1.5*", + S (MATCH_DRIVER"DRV/|1.5", MATCH_DRIVER"DRV/|1.5.2"), + S (MATCH_DRIVER"DRV/", MATCH_DRIVER"DRV/|1.6", MATCH_DRIVER"DR", MATCH_DRIVER"DR*"), + NULL); #undef S } @@ -1590,6 +1656,53 @@ test_stable_id_generated_complete (void) /*****************************************************************************/ +static void +test_nm_utils_exp10 (void) +{ +#define FLOAT_CMP(a, b) \ + G_STMT_START { \ + double _a = (a); \ + double _b = (b); \ + \ + if (isinf (_b)) \ + g_assert (isinf (_a)); \ + else if (_b >= 0.0 && _b <= 0.0) \ + g_assert (_a - _b < G_MINFLOAT); \ + else { \ + double _x = (_a) - (_b); \ + g_assert (_b > 0.0); \ + if (_x < 0.0) \ + _x = -_x; \ + g_assert (_x / _b < 1E-10); \ + } \ + } G_STMT_END + + FLOAT_CMP (nm_utils_exp10 (G_MININT16), 0.0); + FLOAT_CMP (nm_utils_exp10 (-310), 0.0); + FLOAT_CMP (nm_utils_exp10 (-309), 0.0); + FLOAT_CMP (nm_utils_exp10 (-308), 1e-308); + FLOAT_CMP (nm_utils_exp10 (-307), 1e-307); + FLOAT_CMP (nm_utils_exp10 (-1), 1e-1); + FLOAT_CMP (nm_utils_exp10 (-2), 1e-2); + FLOAT_CMP (nm_utils_exp10 (0), 1e0); + FLOAT_CMP (nm_utils_exp10 (1), 1e1); + FLOAT_CMP (nm_utils_exp10 (2), 1e2); + FLOAT_CMP (nm_utils_exp10 (3), 1e3); + FLOAT_CMP (nm_utils_exp10 (4), 1e4); + FLOAT_CMP (nm_utils_exp10 (5), 1e5); + FLOAT_CMP (nm_utils_exp10 (6), 1e6); + FLOAT_CMP (nm_utils_exp10 (7), 1e7); + FLOAT_CMP (nm_utils_exp10 (122), 1e122); + FLOAT_CMP (nm_utils_exp10 (200), 1e200); + FLOAT_CMP (nm_utils_exp10 (307), 1e307); + FLOAT_CMP (nm_utils_exp10 (308), 1e308); + FLOAT_CMP (nm_utils_exp10 (309), INFINITY); + FLOAT_CMP (nm_utils_exp10 (310), INFINITY); + FLOAT_CMP (nm_utils_exp10 (G_MAXINT16), INFINITY); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -1603,6 +1716,8 @@ main (int argc, char **argv) g_test_add_func ("/general/nm_utils_ip6_address_same_prefix", test_nm_utils_ip6_address_same_prefix); g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff); + g_test_add_func ("/general/exp10", test_nm_utils_exp10); + g_test_add_func ("/general/connection-match/basic", test_connection_match_basic); g_test_add_func ("/general/connection-match/ip6-method", test_connection_match_ip6_method); g_test_add_func ("/general/connection-match/ip6-method-ignore", test_connection_match_ip6_method_ignore); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 505f9a5d..7e83625c 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -37,8 +37,8 @@ build_test_config (void) config = nm_ip6_config_new (1); nm_ip6_config_add_address (config, nmtst_platform_ip6_address ("abcd:1234:4321::cdde", "1:2:3:4::5", 64)); - nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2")); - nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234")); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL)); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234", NULL)); nm_ip6_config_set_gateway (config, nmtst_inet6_from_string ("3001:abba::3234")); @@ -74,7 +74,7 @@ test_subtract (void) /* add a couple more things to the test config */ dst = build_test_config (); nm_ip6_config_add_address (dst, nmtst_platform_ip6_address (expected_addr, NULL, expected_addr_plen)); - nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop)); + nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop, NULL)); expected_ns1 = *nmtst_inet6_from_string ("2222:3333:4444::5555"); nm_ip6_config_add_nameserver (dst, &expected_ns1); @@ -139,7 +139,7 @@ test_compare_with_source (void) nm_ip6_config_add_address (b, &addr); /* Route */ - route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); @@ -203,7 +203,7 @@ test_add_route_with_source (void) a = nm_ip6_config_new (1); /* Test that a higher priority source is not overwritten */ - route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index df43dd98..6650d26c 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -33,6 +33,10 @@ typedef struct { int ifindex0, ifindex1; } test_fixture; +NMRouteManager *route_manager_get (void); + +NM_DEFINE_SINGLETON_GETTER (NMRouteManager, route_manager_get, NM_TYPE_ROUTE_MANAGER); + /*****************************************************************************/ static void @@ -60,7 +64,7 @@ setup_dev0_ip4 (int ifindex, guint mss_of_first_route, guint32 metric_of_second_ route.mss = 0; g_array_append_val (routes, route); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, TRUE); + nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE); g_array_free (routes, TRUE); } @@ -75,16 +79,15 @@ setup_dev1_ip4 (int ifindex) /* Add some route outside of route manager. The route manager * should get rid of it upon sync. */ - if (!nm_platform_ip4_route_add (NM_PLATFORM_GET, - route.ifindex, - NM_IP_CONFIG_SOURCE_USER, - nmtst_inet4_from_string ("9.0.0.0"), - 8, - INADDR_ANY, - 0, - 10, - route.mss)) - g_assert_not_reached (); + nmtstp_ip4_route_add (NM_PLATFORM_GET, + route.ifindex, + NM_IP_CONFIG_SOURCE_USER, + nmtst_inet4_from_string ("9.0.0.0"), + 8, + INADDR_ANY, + 0, + 10, + route.mss); route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); inet_pton (AF_INET, "6.6.6.0", &route.network); @@ -107,7 +110,7 @@ setup_dev1_ip4 (int ifindex) route.metric = 22; g_array_append_val (routes, route); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, TRUE); + nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE); g_array_free (routes, TRUE); } @@ -134,7 +137,7 @@ update_dev0_ip4 (int ifindex) route.metric = 21; g_array_append_val (routes, route); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, TRUE); + nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE); g_array_free (routes, TRUE); } @@ -346,7 +349,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state2, routes->len, TRUE); g_array_free (routes, TRUE); - nm_route_manager_route_flush (nm_route_manager_get (), fixture->ifindex0); + nm_route_manager_route_flush (route_manager_get (), fixture->ifindex0); /* 6.6.6.0/24 is now on dev1 * 6.6.6.0/24 is also still on dev1 with bumped metric 21. @@ -358,7 +361,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state3, routes->len, TRUE); g_array_free (routes, TRUE); - nm_route_manager_route_flush (nm_route_manager_get (), fixture->ifindex1); + nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1); /* No routes left. */ routes = ip4_routes (fixture); @@ -409,7 +412,7 @@ setup_dev0_ip6 (int ifindex) 0); g_array_append_val (routes, *route); - nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, TRUE); + nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE); g_array_free (routes, TRUE); } @@ -421,15 +424,15 @@ setup_dev1_ip6 (int ifindex) /* Add some route outside of route manager. The route manager * should get rid of it upon sync. */ - if (!nm_platform_ip6_route_add (NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - *nmtst_inet6_from_string ("2001:db8:8088::"), - 48, - in6addr_any, - 10, - 0)) - g_assert_not_reached (); + nmtstp_ip6_route_add (NM_PLATFORM_GET, + ifindex, + NM_IP_CONFIG_SOURCE_USER, + *nmtst_inet6_from_string ("2001:db8:8088::"), + 48, + in6addr_any, + in6addr_any, + 10, + 0); route = nmtst_platform_ip6_route_full ("2001:db8:8086::", 48, @@ -467,7 +470,7 @@ setup_dev1_ip6 (int ifindex) 0); g_array_append_val (routes, *route); - nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, TRUE); + nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE); g_array_free (routes, TRUE); } @@ -514,7 +517,7 @@ update_dev0_ip6 (int ifindex) 0); g_array_append_val (routes, *route); - nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE, TRUE); + nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE); g_array_free (routes, TRUE); } @@ -760,7 +763,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data) nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state2, routes->len, TRUE); g_array_free (routes, TRUE); - nm_route_manager_route_flush (nm_route_manager_get (), fixture->ifindex0); + nm_route_manager_route_flush (route_manager_get (), fixture->ifindex0); /* 2001:db8:abad:c0de::/64 on dev1 is still there, went away from dev0 * 2001:db8:8086::/48 is now on dev1 @@ -772,7 +775,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data) nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state3, routes->len, TRUE); g_array_free (routes, TRUE); - nm_route_manager_route_flush (nm_route_manager_get (), fixture->ifindex1); + nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1); /* No routes left. */ routes = ip6_routes (fixture); @@ -807,7 +810,7 @@ _assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NM c.r6 = route->r6; c.rx.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (c.rx.rt_source); } - if (!r || vtable->route_cmp (r, &c) != 0) { + if (!r || vtable->route_cmp (r, &c, TRUE) != 0) { g_error ("Invalid route. Expect %s, has %s", vtable->route_to_string (&c, NULL, 0), vtable->route_to_string (r, buf, sizeof (buf))); @@ -836,7 +839,7 @@ test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data) g_array_set_size (routes, 2); g_array_index (routes, NMPlatformIP4Route, 0) = r01; g_array_index (routes, NMPlatformIP4Route, 1) = r02; - nm_route_manager_ip4_route_sync (nm_route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE); + nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02); @@ -848,7 +851,7 @@ test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data) _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE); + nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02); @@ -856,13 +859,13 @@ test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data) g_array_set_size (routes, 1); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE); + nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01); _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r02); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE); + nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01); _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r02); diff --git a/src/tests/test-systemd.c b/src/tests/test-systemd.c index 07887960..f6cf9b58 100644 --- a/src/tests/test-systemd.c +++ b/src/tests/test-systemd.c @@ -54,6 +54,8 @@ _nm_log_impl (const char *file, NMLogLevel level, NMLogDomain domain, int error, + const char *ifname, + const char *con_uuid, const char *fmt, ...) { diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 3d4536e7..ecc82068 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -40,6 +40,7 @@ #include "NetworkManagerUtils.h" #include "settings/nm-settings-connection.h" #include "nm-dispatcher.h" +#include "nm-netns.h" #include "settings/nm-agent-manager.h" #include "nm-core-internal.h" #include "nm-pacrunner-manager.h" @@ -109,7 +110,7 @@ typedef struct { VpnState vpn_state; guint dispatcher_id; - NMVpnConnectionStateReason failure_reason; + NMActiveConnectionStateReason failure_reason; NMVpnServiceState service_state; guint start_timeout; @@ -120,13 +121,15 @@ typedef struct { /* Firewall */ NMFirewallManagerCallId fw_call; - NMDefaultRouteManager *default_route_manager; - NMRouteManager *route_manager; + NMNetns *netns; + GDBusProxy *proxy; GCancellable *cancellable; GVariant *connect_hash; guint connect_timeout; NMProxyConfig *proxy_config; + NMPacrunnerManager *pacrunner_manager; + NMPacrunnerCallId *pacrunner_call_id; gboolean has_ip4; NMIP4Config *ip4_config; guint32 ip4_internal_gw; @@ -159,13 +162,13 @@ struct _NMVpnConnectionClass { /* Signals */ void (*vpn_state_changed) (NMVpnConnection *self, NMVpnConnectionState new_state, - NMVpnConnectionStateReason reason); + NMActiveConnectionStateReason reason); /* not exported over D-Bus */ void (*internal_state_changed) (NMVpnConnection *self, NMVpnConnectionState new_state, NMVpnConnectionState old_state, - NMVpnConnectionStateReason reason); + NMActiveConnectionStateReason reason); void (*internal_failed_retry) (NMVpnConnection *self); }; @@ -189,7 +192,7 @@ static void plugin_interactive_secrets_required (NMVpnConnection *self, static void _set_vpn_state (NMVpnConnection *self, VpnState vpn_state, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, gboolean quitting); /*****************************************************************************/ @@ -200,18 +203,15 @@ static void _set_vpn_state (NMVpnConnection *self, #define __NMLOG_prefix_buf_len 128 static const char * -__LOG_create_prefix (char *buf, NMVpnConnection *self) +__LOG_create_prefix (char *buf, NMVpnConnection *self, NMConnection *con) { NMVpnConnectionPrivate *priv; - NMConnection *con; const char *id; if (!self) return _NMLOG_PREFIX_NAME; priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - con = NM_CONNECTION (_get_settings_connection (self, TRUE)); id = con ? nm_connection_get_id (con) : NULL; g_snprintf (buf, __NMLOG_prefix_buf_len, @@ -236,13 +236,16 @@ __LOG_create_prefix (char *buf, NMVpnConnection *self) #define _NMLOG(level, ...) \ G_STMT_START { \ const NMLogLevel __level = (level); \ + NMConnection *__con = (self) ? (NMConnection *) _get_settings_connection (self, TRUE) : NULL; \ \ if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ char __prefix[__NMLOG_prefix_buf_len]; \ \ _nm_log (__level, _NMLOG_DOMAIN, 0, \ + (self) ? NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_iface : NULL, \ + (__con) ? nm_connection_get_uuid (__con) : NULL, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - __LOG_create_prefix (__prefix, self) \ + __LOG_create_prefix (__prefix, (self), __con) \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END @@ -358,21 +361,6 @@ disconnect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) } static void -call_plugin_disconnect (NMVpnConnection *self) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - g_dbus_proxy_call (priv->proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) disconnect_cb, - g_object_ref (self)); -} - -static void fw_call_cleanup (NMVpnConnection *self) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); @@ -406,9 +394,9 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev) NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (priv->ip_ifindex) { - nm_platform_link_set_down (NM_PLATFORM_GET, priv->ip_ifindex); - nm_route_manager_route_flush (priv->route_manager, priv->ip_ifindex); - nm_platform_address_flush (NM_PLATFORM_GET, priv->ip_ifindex); + nm_platform_link_set_down (nm_netns_get_platform (priv->netns), priv->ip_ifindex); + nm_route_manager_route_flush (nm_netns_get_route_manager (priv->netns), priv->ip_ifindex); + nm_platform_address_flush (nm_netns_get_platform (priv->netns), priv->ip_ifindex); } remove_parent_device_config (self, parent_dev); @@ -447,7 +435,7 @@ dispatcher_pre_down_done (guint call_id, gpointer user_data) NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); priv->dispatcher_id = 0; - _set_vpn_state (self, STATE_DISCONNECTED, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_DISCONNECTED, NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE); } static void @@ -457,7 +445,7 @@ dispatcher_pre_up_done (guint call_id, gpointer user_data) NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); priv->dispatcher_id = 0; - _set_vpn_state (self, STATE_ACTIVATED, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_ACTIVATED, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } static void @@ -474,13 +462,14 @@ dispatcher_cleanup (NMVpnConnection *self) static void _set_vpn_state (NMVpnConnection *self, VpnState vpn_state, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, gboolean quitting) { NMVpnConnectionPrivate *priv; VpnState old_vpn_state; NMVpnConnectionState new_external_state, old_external_state; NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); + NMConnection *applied; g_return_if_fail (NM_IS_VPN_CONNECTION (self)); @@ -500,15 +489,16 @@ _set_vpn_state (NMVpnConnection *self, /* Update active connection base class state */ nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), - _state_to_ac_state (vpn_state)); + _state_to_ac_state (vpn_state), + reason); /* Clear any in-progress secrets request */ cancel_get_secrets (self); dispatcher_cleanup (self); - nm_default_route_manager_ip4_update_default_route (priv->default_route_manager, self); - nm_default_route_manager_ip6_update_default_route (priv->default_route_manager, self); + nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); + nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); /* The connection gets destroyed by the VPN manager when it enters the * disconnected/failed state, but we need to keep it around for a bit @@ -535,7 +525,7 @@ _set_vpn_state (NMVpnConnection *self, */ break; case STATE_PRE_UP: - if (!nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_PRE_UP, + if (!nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_PRE_UP, _get_settings_connection (self, FALSE), _get_applied_connection (self), parent_dev, @@ -551,13 +541,15 @@ _set_vpn_state (NMVpnConnection *self, } break; case STATE_ACTIVATED: + applied = _get_applied_connection (self); + /* Secrets no longer needed now that we're connected */ nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); /* Let dispatcher scripts know we're up and running */ - nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_UP, + nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_UP, _get_settings_connection (self, FALSE), - _get_applied_connection (self), + applied, parent_dev, priv->ip_iface, priv->proxy_config, @@ -568,27 +560,35 @@ _set_vpn_state (NMVpnConnection *self, NULL); if (priv->proxy_config) { - nm_pacrunner_manager_send (nm_pacrunner_manager_get (), - priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config); + nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, + &priv->pacrunner_call_id); + if (!priv->pacrunner_manager) { + /* the pending call doesn't keep NMPacrunnerManager alive. + * Take a reference to it. */ + priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ()); + } + priv->pacrunner_call_id = nm_pacrunner_manager_send (priv->pacrunner_manager, + priv->ip_iface, + priv->proxy_config, + priv->ip4_config, + priv->ip6_config); } break; case STATE_DEACTIVATING: + applied = _get_applied_connection (self); if (quitting) { - nm_dispatcher_call_vpn_sync (DISPATCHER_ACTION_VPN_PRE_DOWN, + nm_dispatcher_call_vpn_sync (NM_DISPATCHER_ACTION_VPN_PRE_DOWN, _get_settings_connection (self, FALSE), - _get_applied_connection (self), + applied, parent_dev, priv->ip_iface, priv->proxy_config, priv->ip4_config, priv->ip6_config); } else { - if (!nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_PRE_DOWN, + if (!nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_PRE_DOWN, _get_settings_connection (self, FALSE), - _get_applied_connection (self), + applied, parent_dev, priv->ip_iface, priv->proxy_config, @@ -602,8 +602,8 @@ _set_vpn_state (NMVpnConnection *self, } } - /* Remove config from PacRunner */ - nm_pacrunner_manager_remove (nm_pacrunner_manager_get(), priv->ip_iface); + nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, + &priv->pacrunner_call_id); break; case STATE_FAILED: case STATE_DISCONNECTED: @@ -611,7 +611,7 @@ _set_vpn_state (NMVpnConnection *self, && old_vpn_state <= STATE_DEACTIVATING) { /* Let dispatcher scripts know we're about to go down */ if (quitting) { - nm_dispatcher_call_vpn_sync (DISPATCHER_ACTION_VPN_DOWN, + nm_dispatcher_call_vpn_sync (NM_DISPATCHER_ACTION_VPN_DOWN, _get_settings_connection (self, FALSE), _get_applied_connection (self), parent_dev, @@ -620,7 +620,7 @@ _set_vpn_state (NMVpnConnection *self, NULL, NULL); } else { - nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN, + nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_DOWN, _get_settings_connection (self, FALSE), _get_applied_connection (self), parent_dev, @@ -635,7 +635,17 @@ _set_vpn_state (NMVpnConnection *self, } /* Tear down and clean up the connection */ - call_plugin_disconnect (self); + if (priv->proxy) { + g_dbus_proxy_call (priv->proxy, + "Disconnect", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) disconnect_cb, + g_object_ref (self)); + } + vpn_cleanup (self, parent_dev); /* fall through */ default: @@ -679,12 +689,12 @@ device_state_changed (NMActiveConnection *active, if (new_state <= NM_DEVICE_STATE_DISCONNECTED) { _set_vpn_state (NM_VPN_CONNECTION (active), STATE_DISCONNECTED, - NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, FALSE); } else if (new_state == NM_DEVICE_STATE_FAILED) { _set_vpn_state (NM_VPN_CONNECTION (active), STATE_FAILED, - NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, FALSE); } @@ -845,13 +855,13 @@ plugin_failed (NMVpnConnection *self, guint reason) switch (reason) { case NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED: - priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED; + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED; break; case NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG: - priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID; + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID; break; default: - priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN; + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; break; } } @@ -884,23 +894,6 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_vpn_state_to_string, VpnState, ); #define vpn_state_to_string(state) NM_UTILS_LOOKUP_STR (_vpn_state_to_string, state) -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_vpn_reason_to_string, NMVpnConnectionStateReason, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED, "user-disconnected"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, "device-disconnected"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED, "service-stopped"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, "ip-config-invalid"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, "connect-timeout"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, "service-start-timeout"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, "service-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, "no-secrets"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED, "login-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED, "connection-removed"), -); -#define vpn_reason_to_string(reason) NM_UTILS_LOOKUP_STR (_vpn_reason_to_string, reason) - static void plugin_state_changed (NMVpnConnection *self, NMVpnServiceState new_service_state) { @@ -920,12 +913,10 @@ plugin_state_changed (NMVpnConnection *self, NMVpnServiceState new_service_state if ((priv->vpn_state >= STATE_WAITING) && (priv->vpn_state <= STATE_ACTIVATED)) { VpnState old_state = priv->vpn_state; - _LOGI ("VPN plugin: state change reason: %s (%d)", - vpn_reason_to_string (priv->failure_reason), priv->failure_reason); _set_vpn_state (self, STATE_FAILED, priv->failure_reason, FALSE); /* Reset the failure reason */ - priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN; + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; /* If the connection failed, the service cannot persist, but the * connection can persist, ask listeners to re-activate the connection. @@ -938,7 +929,7 @@ plugin_state_changed (NMVpnConnection *self, NMVpnServiceState new_service_state } else if (new_service_state == NM_VPN_SERVICE_STATE_STARTING && old_service_state == NM_VPN_SERVICE_STATE_STARTED) { /* The VPN service got disconnected and is attempting to reconnect */ - _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); + _set_vpn_state (self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); } } @@ -1103,10 +1094,13 @@ nm_vpn_connection_apply_config (NMVpnConnection *self) NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (priv->ip_ifindex > 0) { - nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL); + nm_platform_link_set_up (nm_netns_get_platform (priv->netns), priv->ip_ifindex, NULL); if (priv->ip4_config) { - if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex, + if (!nm_ip4_config_commit (priv->ip4_config, + nm_netns_get_platform (priv->netns), + nm_netns_get_route_manager (priv->netns), + priv->ip_ifindex, TRUE, nm_vpn_connection_get_ip4_route_metric (self))) return FALSE; @@ -1114,23 +1108,25 @@ nm_vpn_connection_apply_config (NMVpnConnection *self) if (priv->ip6_config) { if (!nm_ip6_config_commit (priv->ip6_config, + nm_netns_get_platform (priv->netns), + nm_netns_get_route_manager (priv->netns), priv->ip_ifindex, TRUE)) return FALSE; } - if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ip_ifindex)) - nm_platform_link_set_mtu (NM_PLATFORM_GET, priv->ip_ifindex, priv->mtu); + if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (nm_netns_get_platform (priv->netns), priv->ip_ifindex)) + nm_platform_link_set_mtu (nm_netns_get_platform (priv->netns), priv->ip_ifindex, priv->mtu); } apply_parent_device_config (self); - nm_default_route_manager_ip4_update_default_route (priv->default_route_manager, self); - nm_default_route_manager_ip6_update_default_route (priv->default_route_manager, self); + nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); + nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self); _LOGI ("VPN connection: (IP Config Get) complete"); if (priv->vpn_state < STATE_PRE_UP) - _set_vpn_state (self, STATE_PRE_UP, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_PRE_UP, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); return TRUE; } @@ -1143,7 +1139,7 @@ _cleanup_failed_config (NMVpnConnection *self) nm_exported_object_clear_and_unexport (&priv->ip6_config); _LOGW ("VPN connection: did not receive valid IP config information"); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); } static void @@ -1279,10 +1275,10 @@ process_generic_config (NMVpnConnection *self, GVariant *dict) if (priv->ip_iface) { /* Grab the interface index for address/routing operations */ - priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); + priv->ip_ifindex = nm_platform_link_get_ifindex (nm_netns_get_platform (priv->netns), priv->ip_iface); if (priv->ip_ifindex <= 0) { - nm_platform_process_events (NM_PLATFORM_GET); - priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); + nm_platform_process_events (nm_netns_get_platform (priv->netns)); + priv->ip_ifindex = nm_platform_link_get_ifindex (nm_netns_get_platform (priv->netns), priv->ip_iface); } if (priv->ip_ifindex <= 0) { _LOGE ("failed to look up VPN interface index for \"%s\"", priv->ip_iface); @@ -1348,7 +1344,7 @@ nm_vpn_connection_config_get (NMVpnConnection *self, GVariant *dict) _LOGI ("VPN connection: (IP Config Get) reply received."); if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); if (!process_generic_config (self, dict)) return; @@ -1408,7 +1404,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); if (priv->vpn_state > STATE_ACTIVATED) { _LOGI ("VPN connection: (IP4 Config Get) ignoring, the connection is no longer active"); @@ -1582,7 +1578,7 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) _LOGI ("VPN connection: (IP6 Config Get) reply received"); if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); if (priv->vpn_state > STATE_ACTIVATED) { _LOGI ("VPN connection: (IP6 Config Get) ignoring, the connection is no longer active"); @@ -1735,7 +1731,7 @@ connect_timeout_cb (gpointer user_data) if (priv->vpn_state == STATE_CONNECT || priv->vpn_state == STATE_IP_CONFIG_GET) { _LOGW ("VPN connection: connect timeout exceeded."); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); } return FALSE; @@ -1785,7 +1781,7 @@ connect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) g_dbus_error_strip_remote_error (error); _LOGW ("VPN connection: failed to connect: '%s'", error->message); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); } else connect_success (self); } @@ -1823,7 +1819,7 @@ connect_interactive_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d g_dbus_error_strip_remote_error (error); _LOGW ("VPN connection: failed to connect interactively: '%s'", error->message); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); } else connect_success (self); } @@ -1898,7 +1894,7 @@ really_activate (NMVpnConnection *self, const char *username) self); } - _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } static void @@ -2004,7 +2000,7 @@ _name_owner_changed (GObject *object, _nm_dbus_signal_connect (priv->proxy, "Ip6Config", G_VARIANT_TYPE ("(a{sv})"), G_CALLBACK (ip6_config_cb), self); - _set_vpn_state (self, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); /* Kick off the secrets requests; first we get existing system secrets * and ask the plugin if these are sufficient, next we get all existing @@ -2016,7 +2012,7 @@ _name_owner_changed (GObject *object, /* service went away */ priv->service_running = FALSE; _LOGI ("VPN service disappeared"); - nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED, FALSE); + nm_vpn_connection_disconnect (self, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED, FALSE); } g_free (owner); @@ -2031,7 +2027,7 @@ _daemon_exec_timeout (gpointer data) _LOGW ("Timed out waiting for the service to start"); priv->start_timeout = 0; - nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, FALSE); + nm_vpn_connection_disconnect (self, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, FALSE); return G_SOURCE_REMOVE; } @@ -2158,7 +2154,7 @@ on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data) error->message); _set_vpn_state (self, STATE_FAILED, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); return; } @@ -2176,7 +2172,7 @@ on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data) _LOGW ("Could not launch the VPN service. error: %s.", error->message); - nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); + nm_vpn_connection_disconnect (self, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); } } @@ -2226,7 +2222,7 @@ nm_vpn_connection_activate (NMVpnConnection *self, (GAsyncReadyCallback) on_proxy_acquired, self); - _set_vpn_state (self, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_PREPARE, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } NMVpnConnectionState @@ -2350,7 +2346,7 @@ nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *self) void nm_vpn_connection_disconnect (NMVpnConnection *self, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, gboolean quitting) { g_return_if_fail (NM_IS_VPN_CONNECTION (self)); @@ -2360,7 +2356,7 @@ nm_vpn_connection_disconnect (NMVpnConnection *self, gboolean nm_vpn_connection_deactivate (NMVpnConnection *self, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, gboolean quitting) { NMVpnConnectionPrivate *priv; @@ -2399,7 +2395,7 @@ plugin_need_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d _LOGE ("plugin NeedSecrets request #%d failed: %s", priv->secrets_idx + 1, error->message); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); return; } @@ -2415,7 +2411,7 @@ plugin_need_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d /* More secrets required */ if (priv->secrets_idx == SECRETS_REQ_NEW) { _LOGE ("final secrets request failed to provide sufficient secrets"); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); } else { _LOGD ("service indicated additional secrets required"); get_secrets (self, priv->secrets_idx + 1, NULL); @@ -2441,9 +2437,9 @@ plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da g_dbus_error_strip_remote_error (error); _LOGE ("sending new secrets to the plugin failed: %s", error->message); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); } else - _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } static void @@ -2473,7 +2469,7 @@ get_secrets_cb (NMSettingsConnection *connection, if (error && priv->secrets_idx >= SECRETS_REQ_NEW) { _LOGE ("Failed to request VPN secrets #%d: %s", priv->secrets_idx + 1, error->message); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); return; } @@ -2574,7 +2570,7 @@ plugin_interactive_secrets_required (NMVpnConnection *self, priv->vpn_state == STATE_NEED_AUTH); priv->secrets_idx = SECRETS_REQ_INTERACTIVE; - _set_vpn_state (self, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); /* Copy hints and add message to the end */ hints = g_malloc0 (sizeof (char *) * (secrets_len + 2)); @@ -2627,8 +2623,7 @@ nm_vpn_connection_init (NMVpnConnection *self) priv->vpn_state = STATE_WAITING; priv->secrets_idx = SECRETS_REQ_SYSTEM; - priv->default_route_manager = g_object_ref (nm_default_route_manager_get ()); - priv->route_manager = g_object_ref (nm_route_manager_get ()); + priv->netns = g_object_ref (nm_netns_get ()); } static void @@ -2647,10 +2642,8 @@ dispose (GObject *object) cancel_get_secrets (self); - if (priv->cancellable) { - g_cancellable_cancel (priv->cancellable); - g_clear_object (&priv->cancellable); - } + nm_clear_g_cancellable (&priv->cancellable); + g_clear_object (&priv->proxy_config); nm_exported_object_clear_and_unexport (&priv->ip4_config); nm_exported_object_clear_and_unexport (&priv->ip6_config); @@ -2659,10 +2652,11 @@ dispose (GObject *object) fw_call_cleanup (self); - G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object); + nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, + &priv->pacrunner_call_id); + g_clear_object (&priv->pacrunner_manager); - g_clear_object (&priv->default_route_manager); - g_clear_object (&priv->route_manager); + G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object); } static void @@ -2677,6 +2671,8 @@ finalize (GObject *object) g_free (priv->ip6_external_gw); G_OBJECT_CLASS (nm_vpn_connection_parent_class)->finalize (object); + + g_clear_object (&priv->netns); } static gboolean diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 8393f081..038d0efd 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -62,10 +62,10 @@ const char * nm_vpn_connection_get_banner (NMVpnConnection *self); const gchar * nm_vpn_connection_get_service (NMVpnConnection *self); gboolean nm_vpn_connection_deactivate (NMVpnConnection *self, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, gboolean quitting); void nm_vpn_connection_disconnect (NMVpnConnection *self, - NMVpnConnectionStateReason reason, + NMActiveConnectionStateReason reason, gboolean quitting); NMProxyConfig * nm_vpn_connection_get_proxy_config (NMVpnConnection *self); |