diff --git a/0001-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch b/0002-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch similarity index 97% rename from 0001-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch rename to 0002-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch index b1f09af..ac84527 100644 --- a/0001-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch +++ b/0002-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch @@ -1,4 +1,4 @@ -From bf2a90588410a7d81ff86a6dcf09521316f23ffb Mon Sep 17 00:00:00 2001 +From 1ea56b82121d3f024859da41337cf2406e7f2e61 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 10 May 2017 15:31:15 +0200 Subject: [PATCH 1/1] utils: fix maybe-uninitialized in "nm-udev-utils.c" diff --git a/0003-fix-device-run-state-unknown-rh1440171.patch b/0003-fix-device-run-state-unknown-rh1440171.patch new file mode 100644 index 0000000..7f2778b --- /dev/null +++ b/0003-fix-device-run-state-unknown-rh1440171.patch @@ -0,0 +1,140 @@ +From f2d099c8c534ee426dbc31a3a61fcf27c18b92d8 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Thu, 11 May 2017 19:26:28 +0200 +Subject: [PATCH 1/2] core: cleanup logging reading device-state + +- print string value instead of numerical "managed" +- for missing state, print the same format. After all, + some defaults apply and it is interesting to know what + they are. + +(cherry picked from commit 81008c90ac9832ade1c9783078823fdd45221225) +(cherry picked from commit 8da225283b9977554a6b78e73dc03d22b8703027) +--- + src/nm-config.c | 30 +++++++++++++----------------- + 1 file changed, 13 insertions(+), 17 deletions(-) + +diff --git a/src/nm-config.c b/src/nm-config.c +index 2cdf855..954cad7 100644 +--- a/src/nm-config.c ++++ b/src/nm-config.c +@@ -1873,6 +1873,13 @@ _nm_config_state_set (NMConfig *self, + #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_PERM_HW_ADDR_FAKE "perm-hw-addr-fake" + #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID "connection-uuid" + ++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"), ++); ++ + static NMConfigDeviceStateData * + _config_device_state_data_new (int ifindex, GKeyFile *kf) + { +@@ -1968,27 +1975,16 @@ nm_config_device_state_load (int ifindex) + + device_state = _config_device_state_data_new (ifindex, kf); + +- if (kf) { +- _LOGT ("device-state: read #%d (%s); managed=%d%s%s%s%s%s%s", +- ifindex, path, +- device_state->managed, +- NM_PRINT_FMT_QUOTED (device_state->connection_uuid, ", connection-uuid=", device_state->connection_uuid, "", ""), +- NM_PRINT_FMT_QUOTED (device_state->perm_hw_addr_fake, ", perm-hw-addr-fake=", device_state->perm_hw_addr_fake, "", "")); +- } else { +- _LOGT ("device-state: read #%d (%s); no persistent state", +- ifindex, path); +- } ++ _LOGT ("device-state: %s #%d (%s); managed=%s%s%s%s%s%s%s", ++ kf ? "read" : "miss", ++ ifindex, path, ++ _device_state_managed_type_to_str (device_state->managed), ++ NM_PRINT_FMT_QUOTED (device_state->connection_uuid, ", connection-uuid=", device_state->connection_uuid, "", ""), ++ NM_PRINT_FMT_QUOTED (device_state->perm_hw_addr_fake, ", perm-hw-addr-fake=", device_state->perm_hw_addr_fake, "", "")); + + 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 (int ifindex, + NMConfigDeviceStateManagedType managed, +-- +2.9.3 + + +From 41ff1247a2dcfd6c781cbce2fac12ab6ae657727 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Thu, 11 May 2017 19:40:55 +0200 +Subject: [PATCH 2/2] core: fix reading device state file + +For manged=unknown, we don't write the value to the +device state keyfile. The results in an empty file, +or at least, a keyfile that doesn't have device.managed +set. + +On read, we must treat a missing device.managed flag as +unknown, and not as unmanaged. Otherwise, on restart +a device becomes marked as explicitly unmanaged. + +This was broken by commit 142ebb1 "core: only persist explicit managed +state in device's state file", where we started conditionally +to no longer write the managed state. + +Reported-by: Michael Biebl +Fixes: 142ebb10376ec592593f15b0359f38be89c97620 +(cherry picked from commit 348ffdec183ee198499dad1365906e8d16ff4122) +(cherry picked from commit 33d3ec3b3e5d2e737afc8db6c64850e67db5c12d) +--- + src/nm-config.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/src/nm-config.c b/src/nm-config.c +index 954cad7..54ccf9a 100644 +--- a/src/nm-config.c ++++ b/src/nm-config.c +@@ -1894,21 +1894,23 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf) + nm_assert (ifindex > 0); + + if (kf) { +- gboolean managed; +- +- managed = nm_config_keyfile_get_boolean (kf, +- DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, +- DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED, +- FALSE); +- managed_type = managed +- ? NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED +- : NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; +- +- if (managed) { ++ switch (nm_config_keyfile_get_boolean (kf, ++ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, ++ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED, ++ -1)) { ++ case TRUE: ++ managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED; + connection_uuid = nm_config_keyfile_get_value (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); ++ break; ++ case FALSE: ++ managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; ++ break; ++ case -1: ++ /* missing property in keyfile. */ ++ break; + } + + perm_hw_addr_fake = nm_config_keyfile_get_value (kf, +-- +2.9.3 + diff --git a/0004-proxy-crash-rh1450459.patch b/0004-proxy-crash-rh1450459.patch new file mode 100644 index 0000000..473cd7f --- /dev/null +++ b/0004-proxy-crash-rh1450459.patch @@ -0,0 +1,65 @@ +From 4bf6a4dd5b73fcea36fcfa4a97091665b233bc15 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Thu, 11 May 2017 12:09:45 +0200 +Subject: [PATCH 1/2] proxy: fix refcount handing for DestroyProxyConfiguration + operation + +Fixes: e895beb0da38fc87ce93fe7403a6b50e92f0dd82 +(cherry picked from commit df137fdf9a7077c20d8923f068568c22fb479e5a) +(cherry picked from commit 10373de9072f0318ea1150c85fd7b7ebfa5a9655) +--- + src/nm-pacrunner-manager.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c +index cfc028c..fd3d1f8 100644 +--- a/src/nm-pacrunner-manager.c ++++ b/src/nm-pacrunner-manager.c +@@ -250,6 +250,7 @@ pacrunner_send_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) + _LOG2D (config, "sent"); + + if (config->removed) { ++ config_ref (config); + g_dbus_proxy_call (priv->pacrunner, + "DestroyProxyConfiguration", + g_variant_new ("(o)", config->path), +-- +2.9.3 + + +From 617aa8fd2fccbd8a8cb76fbf9bce3e74eac78f8c Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Thu, 11 May 2017 12:32:22 +0200 +Subject: [PATCH 2/2] proxy: fix passing cancellable to async D-Bus operations + +We must not cancel pacrunner_cancellable when the D-Bus proxy is +created. Instead, keep it around and use it later for the asynchronous +D-Bus operations. + +This doesn't really matter at the moment, because the pacrunner manager +is only destroyed when NetworkManager is about to terminated. That is +the only time when we actually cancel the asynchronous request. Also, +at that time we no longer iterate the mainloop, so the pending requests +are never completed anyway. + +(cherry picked from commit a08540d967812457af192ebd34497412da5d143e) +(cherry picked from commit 6cfd9279625366c24808d86e1c3b04a18a036eb6) +--- + src/nm-pacrunner-manager.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c +index fd3d1f8..87e0a36 100644 +--- a/src/nm-pacrunner-manager.c ++++ b/src/nm-pacrunner-manager.c +@@ -330,7 +330,6 @@ pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) + priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + + priv->pacrunner = proxy; +- nm_clear_g_cancellable (&priv->pacrunner_cancellable); + + g_signal_connect (priv->pacrunner, "notify::g-name-owner", + G_CALLBACK (name_owner_changed_cb), self); +-- +2.9.3 + diff --git a/0005-device-fix-wait-carrier-rh1450444.patch b/0005-device-fix-wait-carrier-rh1450444.patch new file mode 100644 index 0000000..50918dd --- /dev/null +++ b/0005-device-fix-wait-carrier-rh1450444.patch @@ -0,0 +1,586 @@ +From fde61a81ee3ff70c85aed230bcfda79f2fb70ea8 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 12 May 2017 16:17:18 +0200 +Subject: [PATCH 1/7] device: don't call virtual function carrier_changed() + directly + +Don't give the subclass the ability to override the parents +behavior. The parent implementation is not intended to allow +for that. Instead, restrict the flexibility of how the virtual +function integrates with the larger picture. That means, the +virtual function is only called at one place, and there is only +one implementation in NMDeviceEthernet (and it doesn't really +matter whether the implementation chains up the parent implementation +or not). + +(cherry picked from commit 5a7374d8be33086a5c00a450a472069595ba1734) +(cherry picked from commit e9aa3cc3575b8456eb712c0e06dc815940b49cbc) +--- + src/devices/nm-device-ethernet.c | 7 +++---- + src/devices/nm-device.c | 17 ++++++++++++----- + src/devices/nm-device.h | 2 +- + 3 files changed, 16 insertions(+), 10 deletions(-) + +diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c +index 4c5aeb5..8a04d40 100644 +--- a/src/devices/nm-device-ethernet.c ++++ b/src/devices/nm-device-ethernet.c +@@ -1597,12 +1597,11 @@ get_link_speed (NMDevice *device) + } + + static void +-carrier_changed (NMDevice *device, gboolean carrier) ++carrier_changed_notify (NMDevice *device, gboolean carrier) + { + if (carrier) + get_link_speed (device); +- +- NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->carrier_changed (device, carrier); ++ NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->carrier_changed_notify (device, carrier); + } + + static void +@@ -1764,7 +1763,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) + parent_class->deactivate = deactivate; + parent_class->get_s390_subchannels = get_s390_subchannels; + parent_class->update_connection = update_connection; +- parent_class->carrier_changed = carrier_changed; ++ parent_class->carrier_changed_notify = carrier_changed_notify; + parent_class->link_changed = link_changed; + parent_class->is_available = is_available; + parent_class->can_reapply_change = can_reapply_change; +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 9c30790..652bede 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2168,10 +2168,18 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) + } + + static void ++carrier_changed_notify (NMDevice *self, gboolean carrier) ++{ ++ /* stub */ ++} ++ ++static void + carrier_changed (NMDevice *self, gboolean carrier) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + ++ NM_DEVICE_GET_CLASS (self)->carrier_changed_notify (self, carrier); ++ + if (priv->state <= NM_DEVICE_STATE_UNMANAGED) + return; + +@@ -2245,7 +2253,7 @@ link_disconnect_action_cb (gpointer user_data) + + priv->carrier_defer_id = 0; + +- NM_DEVICE_GET_CLASS (self)->carrier_changed (self, FALSE); ++ carrier_changed (self, FALSE); + + return FALSE; + } +@@ -2266,7 +2274,6 @@ void + nm_device_set_carrier (NMDevice *self, gboolean carrier) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); +- NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); + NMDeviceState state = nm_device_get_state (self); + + if (priv->carrier == carrier) +@@ -2278,7 +2285,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + if (priv->carrier) { + _LOGI (LOGD_DEVICE, "link connected"); + link_disconnect_action_cancel (self); +- klass->carrier_changed (self, TRUE); ++ carrier_changed (self, TRUE); + + if (nm_clear_g_source (&priv->carrier_wait_id)) { + nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); +@@ -2287,7 +2294,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + } else if ( state <= NM_DEVICE_STATE_DISCONNECTED + && !priv->queued_act_request) { + _LOGD (LOGD_DEVICE, "link disconnected"); +- klass->carrier_changed (self, FALSE); ++ carrier_changed (self, FALSE); + } else { + priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, + link_disconnect_action_cb, self); +@@ -14162,7 +14169,7 @@ nm_device_class_init (NMDeviceClass *klass) + klass->can_unmanaged_external_down = can_unmanaged_external_down; + klass->realize_start_notify = realize_start_notify; + klass->unrealize_notify = unrealize_notify; +- klass->carrier_changed = carrier_changed; ++ klass->carrier_changed_notify = carrier_changed_notify; + klass->get_ip_iface_identifier = get_ip_iface_identifier; + klass->unmanaged_on_quit = unmanaged_on_quit; + klass->deactivate_reset_hw_addr = deactivate_reset_hw_addr; +diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h +index be328eb..5e6abb4 100644 +--- a/src/devices/nm-device.h ++++ b/src/devices/nm-device.h +@@ -261,7 +261,7 @@ typedef struct { + gboolean (*can_unmanaged_external_down) (NMDevice *self); + + /* Carrier state (IFF_LOWER_UP) */ +- void (*carrier_changed) (NMDevice *, gboolean carrier); ++ void (*carrier_changed_notify) (NMDevice *, gboolean carrier); + + gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid); + +-- +2.9.4 + + +From 02daf0bdd66115456c6d9ccbf99909996013239d Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 12 May 2017 16:21:55 +0200 +Subject: [PATCH 2/7] device/trivial: rename functions related to "carrier" + +(cherry picked from commit a07c6255a02e098dae934ee0e6765e1ce5b927ae) +(cherry picked from commit 0ed6b5bfff4d8a915e69866d15027d26e3785271) +--- + src/devices/nm-device.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 652bede..e615f32 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2167,6 +2167,8 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) + } + } + ++/*****************************************************************************/ ++ + static void + carrier_changed_notify (NMDevice *self, gboolean carrier) + { +@@ -2244,7 +2246,7 @@ carrier_changed (NMDevice *self, gboolean carrier) + #define LINK_DISCONNECT_DELAY 4 + + static gboolean +-link_disconnect_action_cb (gpointer user_data) ++carrier_disconnected_action_cb (gpointer user_data) + { + NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); +@@ -2259,7 +2261,7 @@ link_disconnect_action_cb (gpointer user_data) + } + + static void +-link_disconnect_action_cancel (NMDevice *self) ++carrier_disconnected_action_cancel (NMDevice *self) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + +@@ -2284,7 +2286,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + + if (priv->carrier) { + _LOGI (LOGD_DEVICE, "link connected"); +- link_disconnect_action_cancel (self); ++ carrier_disconnected_action_cancel (self); + carrier_changed (self, TRUE); + + if (nm_clear_g_source (&priv->carrier_wait_id)) { +@@ -2297,12 +2299,14 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + carrier_changed (self, FALSE); + } else { + priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, +- link_disconnect_action_cb, self); ++ carrier_disconnected_action_cb, self); + _LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)", + LINK_DISCONNECT_DELAY, priv->carrier_defer_id); + } + } + ++/*****************************************************************************/ ++ + static void + device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) + { +@@ -13775,7 +13779,7 @@ dispose (GObject *object) + + nm_clear_g_source (&priv->stats.timeout_id); + +- link_disconnect_action_cancel (self); ++ carrier_disconnected_action_cancel (self); + + if (priv->ifindex > 0) { + priv->ifindex = 0; +-- +2.9.4 + + +From 5385cb00a8686c55e84f1924038ec20102939ac9 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 12 May 2017 16:22:47 +0200 +Subject: [PATCH 3/7] device: minor cleanup of + carrier_disconnected_action_cancel() + +(cherry picked from commit 6c5d883a4bd9ef167ee4fe8ec2b0187c7bc77142) +(cherry picked from commit 62f1875766a181528c36596b7bd16a78663879cc) +--- + src/devices/nm-device.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index e615f32..dabe87e 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2254,9 +2254,7 @@ carrier_disconnected_action_cb (gpointer user_data) + _LOGD (LOGD_DEVICE, "link disconnected (calling deferred action) (id=%u)", priv->carrier_defer_id); + + priv->carrier_defer_id = 0; +- + carrier_changed (self, FALSE); +- + return FALSE; + } + +@@ -2264,11 +2262,11 @@ static void + carrier_disconnected_action_cancel (NMDevice *self) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ guint id = priv->carrier_defer_id; + +- if (priv->carrier_defer_id) { +- g_source_remove (priv->carrier_defer_id); +- _LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)", priv->carrier_defer_id); +- priv->carrier_defer_id = 0; ++ if (nm_clear_g_source (&priv->carrier_defer_id)) { ++ _LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)", ++ id); + } + } + +-- +2.9.4 + + +From 68703df31190d899d881490ce3f0742890a3f5d2 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 12 May 2017 16:48:57 +0200 +Subject: [PATCH 4/7] device: downgrade logging messages about (non) pending + action + +Adding/Removing a pending action with assert_not_yet_pending/ +assert_is_pending means that we expect that no action is taken. + +Downgrade the logging level in those cases to . + +(cherry picked from commit eaba285375248a691aaa896fecdd991ad695c1b1) +(cherry picked from commit f4600c7fa5afd960fb3657ca6d694e56f5dc5dac) +--- + src/devices/nm-device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index dabe87e..d58c50d 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -11821,7 +11821,7 @@ nm_device_add_pending_action (NMDevice *self, const char *action, gboolean asser + count + g_slist_length (iter), action); + g_return_val_if_reached (FALSE); + } else { +- _LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)", ++ _LOGT (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)", + count + g_slist_length (iter), action); + } + return FALSE; +@@ -11882,7 +11882,7 @@ nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean as + _LOGW (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action); + g_return_val_if_reached (FALSE); + } else +- _LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action); ++ _LOGT (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action); + + return FALSE; + } +-- +2.9.4 + + +From 8615608b36b72f8c47ae813583bad31ae7f7ec0c Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Sun, 14 May 2017 22:08:26 +0200 +Subject: [PATCH 5/7] device: rename and minor refactoring of check_carrier() + +The name should mirror what we already have: nm_device_set_carrier(). +Also, move the code closer to nm_device_set_carrier() and refactor +it a bit. + +(cherry picked from commit 7e472b4eb36347684e81e1c3a2bd7348e19eb628) +(cherry picked from commit 83c2243d800fb20a651f787b65e6c5586a6f970d) +--- + src/devices/nm-device.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index d58c50d..4a330d0 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2303,6 +2303,16 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + } + } + ++static void ++nm_device_set_carrier_from_platform (NMDevice *self) ++{ ++ if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { ++ nm_device_set_carrier (self, ++ nm_platform_link_is_connected (nm_device_get_platform (self), ++ nm_device_get_ip_ifindex (self))); ++ } ++} ++ + /*****************************************************************************/ + + static void +@@ -2881,15 +2891,6 @@ config_changed (NMConfig *config, + } + + static void +-check_carrier (NMDevice *self) +-{ +- int ifindex = nm_device_get_ip_ifindex (self); +- +- if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) +- nm_device_set_carrier (self, nm_platform_link_is_connected (nm_device_get_platform (self), ifindex)); +-} +- +-static void + realize_start_notify (NMDevice *self, + const NMPlatformLink *pllink) + { +@@ -3020,7 +3021,7 @@ realize_start_setup (NMDevice *self, + } + + if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { +- check_carrier (self); ++ nm_device_set_carrier_from_platform (self); + _LOGD (LOGD_PLATFORM, + "carrier is %s%s", + priv->carrier ? "ON" : "OFF", +@@ -10343,7 +10344,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) + + /* Store carrier immediately. */ + if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) +- check_carrier (self); ++ nm_device_set_carrier_from_platform (self); + + device_is_up = nm_device_is_up (self); + if (block && !device_is_up) { +-- +2.9.4 + + +From 1520c770db02577c54bf25736adba5d344378568 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Mon, 15 May 2017 11:35:41 +0200 +Subject: [PATCH 6/7] device: cleanup nm_device_set_carrier_from_platform() + +nm_device_set_carrier_from_platform() is only called from two places. + +- both check for NM_DEVICE_CAP_CARRIER_DETECT, so move that check + inside the function. +- drop the logging in realize_start_setup(). nm_device_set_carrier() already + does logging. +- always set the fake carrier in nm_device_set_carrier_from_platform(). + For the fake carrer, we anyway expect it to be already TRUE in most + case, so usually this should have no effect. + Also emit a property changed signal. That is necessary to refresh the + D-Bus property. + +(cherry picked from commit 02bb4ce7eb518bf955ed802511f1efde921bc919) +(cherry picked from commit 3786e17c0f86561e23779490ec5032b432aa7178) +--- + src/devices/nm-device.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 4a330d0..851e0a3 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2306,10 +2306,20 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + static void + nm_device_set_carrier_from_platform (NMDevice *self) + { +- if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { +- nm_device_set_carrier (self, +- nm_platform_link_is_connected (nm_device_get_platform (self), +- nm_device_get_ip_ifindex (self))); ++ if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { ++ if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { ++ nm_device_set_carrier (self, ++ nm_platform_link_is_connected (nm_device_get_platform (self), ++ nm_device_get_ip_ifindex (self))); ++ } ++ } else { ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ ++ /* Fake online link when carrier detection is not available. */ ++ if (!priv->carrier) { ++ priv->carrier = TRUE; ++ _notify (self, PROP_CARRIER); ++ } + } + } + +@@ -3020,16 +3030,7 @@ realize_start_setup (NMDevice *self, + self); + } + +- if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { +- nm_device_set_carrier_from_platform (self); +- _LOGD (LOGD_PLATFORM, +- "carrier is %s%s", +- priv->carrier ? "ON" : "OFF", +- priv->ignore_carrier ? " (but ignored)" : ""); +- } else { +- /* Fake online link when carrier detection is not available. */ +- priv->carrier = TRUE; +- } ++ nm_device_set_carrier_from_platform (self); + + device_init_sriov_num_vfs (self); + +@@ -10343,8 +10344,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) + } + + /* Store carrier immediately. */ +- if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) +- nm_device_set_carrier_from_platform (self); ++ nm_device_set_carrier_from_platform (self); + + device_is_up = nm_device_is_up (self); + if (block && !device_is_up) { +-- +2.9.4 + + +From 15bb8709410d829c63b502ac845b93a8c95c3f15 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 12 May 2017 16:32:15 +0200 +Subject: [PATCH 7/7] device: fix delaying startup complete waiting for carrier + + platform: signal: link changed: 2: eth0 mtu ... + ... + device[0x7f90c29c64d0] (eth0): bringing up device + ... + platform: signal: link changed: 2: eth0 mtu ... + ... + device (eth0): link connected + ... + device[0x7f90c29c64d0] (eth0): add_pending_action (2): 'carrier wait' + +Note how we schedule the pending action 'carrier-wait', although the device +already has carrier. That means, the pending action will not be removed +until timeout, 5 seconds later. + +Avoid scheduling 'carrier-wait' if we already have carrier. + +However, don't just add the pending action 'carrier-wait' only during +nm_device_bring_up(). Instead, always schedule the carrier_wait timeout. +This gives a grace period during which we keep setting 'carrier-wait' whenever +we have no carrier. This should prevent two cases: + - during nm_device_bring_up() the platform state might not yet have + caught up. If we don't add the pending action there, we will add + it a moment later when carrier goes away. + - bringing the interface up might cause carrier to get lost for a + moment (flapping). If that happens within the timeout, also add the + pending action. + +(cherry picked from commit 9f874d166d260bb4b9af32cb8d12d287341a9a8b) +(cherry picked from commit 51a1fc3cd9f281f1348cf0ec1ea17d4d03ecd0b7) +--- + src/devices/nm-device.c | 47 +++++++++++++++++++++++++++++------------------ + 1 file changed, 29 insertions(+), 18 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 851e0a3..8540b4c 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2287,19 +2287,23 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) + carrier_disconnected_action_cancel (self); + carrier_changed (self, TRUE); + +- if (nm_clear_g_source (&priv->carrier_wait_id)) { +- nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); ++ if (priv->carrier_wait_id) { ++ nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + _carrier_wait_check_queued_act_request (self); + } +- } else if ( state <= NM_DEVICE_STATE_DISCONNECTED +- && !priv->queued_act_request) { +- _LOGD (LOGD_DEVICE, "link disconnected"); +- carrier_changed (self, FALSE); + } else { +- priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, +- carrier_disconnected_action_cb, self); +- _LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)", +- LINK_DISCONNECT_DELAY, priv->carrier_defer_id); ++ if (priv->carrier_wait_id) ++ nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); ++ if ( state <= NM_DEVICE_STATE_DISCONNECTED ++ && !priv->queued_act_request) { ++ _LOGD (LOGD_DEVICE, "link disconnected"); ++ carrier_changed (self, FALSE); ++ } else { ++ priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, ++ carrier_disconnected_action_cb, self); ++ _LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)", ++ LINK_DISCONNECT_DELAY, priv->carrier_defer_id); ++ } + } + } + +@@ -10297,12 +10301,12 @@ static gboolean + carrier_wait_timeout (gpointer user_data) + { + NMDevice *self = NM_DEVICE (user_data); ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + +- NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0; +- nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); +- +- _carrier_wait_check_queued_act_request (self); +- ++ priv->carrier_wait_id = 0; ++ nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); ++ if (!priv->carrier) ++ _carrier_wait_check_queued_act_request (self); + return G_SOURCE_REMOVE; + } + +@@ -10379,8 +10383,14 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) + * a timeout is reached. + */ + if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { +- if (!nm_clear_g_source (&priv->carrier_wait_id)) +- nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); ++ /* we start a grace period of 5 seconds during which we will schedule ++ * a pending action whenever we have no carrier. ++ * ++ * If during that time carrier goes away, we declare the interface ++ * as not ready. */ ++ nm_clear_g_source (&priv->carrier_wait_id); ++ if (!priv->carrier) ++ nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + priv->carrier_wait_id = g_timeout_add_seconds (5, carrier_wait_timeout, self); + } + +@@ -13793,7 +13803,8 @@ dispose (GObject *object) + + available_connections_del_all (self); + +- nm_clear_g_source (&priv->carrier_wait_id); ++ if (nm_clear_g_source (&priv->carrier_wait_id)) ++ nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + + _clear_queued_act_request (priv); + +-- +2.9.4 + diff --git a/0006-dhcp-don-t-add-route-to-DHCP4-server-rh1448987.patch b/0006-dhcp-don-t-add-route-to-DHCP4-server-rh1448987.patch new file mode 100644 index 0000000..d122472 --- /dev/null +++ b/0006-dhcp-don-t-add-route-to-DHCP4-server-rh1448987.patch @@ -0,0 +1,85 @@ +From bed605f5bd8524779b3cf3d3e02baf06a76f4054 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 10 May 2017 16:17:48 +0200 +Subject: [PATCH] dhcp: don't add route to DHCP4 server + +This basically reverts commit 31fe84e46773 "core: Add host route for +DHCP4 server if outside assigned subnet (bgo #721767)" because the +additional route added by NM does more harm than good. + +First, the code does not consider routes pushed by the server and thus +it can add a route conflicting with the ones from the network +administrator. + +Second, there is no specification on what a DHCP client should do when +the server is not reachable via unicast, and adding arbitrary logic +into the client is likely to break things in specific cases. If +network administrators want to make the DHCP server reachable from a +client in a different subnet, they should push proper routes with the +lease. + +In any case, if the DHCP server is not reachable through unicast, +before the lease expiration (after timeout T2) the client will resort +to broadcast and so there won't be any network disruption; the renewal +will only happen at a later time. + +Fixes: 31fe84e467732463eabc8f70c2a419008e7a227c + +https://bugzilla.redhat.com/show_bug.cgi?id=1448987 +(cherry picked from commit 36e97f5d7beba7ab5446c2b7c6c22523b1bca476) +(cherry picked from commit cbf5a776f72d1895405b71f45a74cf4fe9046dae) +--- + src/dhcp/nm-dhcp-utils.c | 37 ------------------------------------- + 1 file changed, 37 deletions(-) + +diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c +index e020ca3..e55a21b 100644 +--- a/src/dhcp/nm-dhcp-utils.c ++++ b/src/dhcp/nm-dhcp-utils.c +@@ -450,43 +450,6 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex, + } + } + +- /* +- * RFC 2132, section 9.7 +- * DHCP clients use the contents of the 'server identifier' field +- * as the destination address for any DHCP messages unicast to +- * the DHCP server. +- * +- * Some ISP's provide leases from central servers that are on +- * different subnets that the address offered. If the host +- * does not configure the interface as the default route, the +- * dhcp server may not be reachable via unicast, and a host +- * specific route is needed. +- **/ +- str = g_hash_table_lookup (options, "dhcp_server_identifier"); +- if (str) { +- if (inet_pton (AF_INET, str, &tmp_addr) > 0) { +- +- _LOG2I (LOGD_DHCP4, iface, " server identifier %s", str); +- if ( nm_utils_ip4_address_clear_host_address(tmp_addr, address.plen) != nm_utils_ip4_address_clear_host_address(address.address, address.plen) +- && !nm_ip4_config_get_direct_route_for_host (ip4_config, tmp_addr)) { +- /* DHCP server not on assigned subnet and the no direct route was returned. Add route */ +- NMPlatformIP4Route route = { 0 }; +- +- route.network = tmp_addr; +- route.plen = 32; +- /* this will be a device route if gwaddr is 0 */ +- route.gateway = gwaddr; +- route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; +- route.metric = priority; +- nm_ip4_config_add_route (ip4_config, &route); +- _LOG2D (LOGD_IP, iface, "adding route for server identifier: %s", +- nm_platform_ip4_route_to_string (&route, NULL, 0)); +- } +- } +- else +- _LOG2W (LOGD_DHCP4, iface, "ignoring invalid server identifier '%s'", str); +- } +- + str = g_hash_table_lookup (options, "dhcp_lease_time"); + if (str) { + address.lifetime = address.preferred = strtoul (str, NULL, 10); +-- +2.9.3 + diff --git a/0007-device-update-ext-conf-before-commit-rh1449873.patch b/0007-device-update-ext-conf-before-commit-rh1449873.patch new file mode 100644 index 0000000..dc7c947 --- /dev/null +++ b/0007-device-update-ext-conf-before-commit-rh1449873.patch @@ -0,0 +1,108 @@ +From b870115d83ddb2f7091e7b5e1f65b64261c53557 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 12 May 2017 12:00:20 +0200 +Subject: [PATCH 1/2] device: update external configuration before commit + +If the platform signaled that the external configuration changed (and +thus update_ipX_config() is scheduled) and we are doing a commit of +the new configuration, update priv->ext_ipX_config. Without this, the +commit will remove addresses added externally but not yet captured in +the external configuration. + +https://bugzilla.redhat.com/show_bug.cgi?id=1449873 +(cherry picked from commit a21b8882cc9defc43248afc94bf59ca0f84f0d27) +(cherry picked from commit bf5407992f54440b586e1d0b3792f93eb2c464f3) +--- + src/devices/nm-device.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 8540b4c..87cd296 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -5487,8 +5487,15 @@ ip4_config_merge_and_apply (NMDevice *self, + composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); + init_ip4_config_dns_priority (self, composite); + +- if (commit) ++ if (commit) { + ensure_con_ip4_config (self); ++ if (priv->queued_ip4_config_id) { ++ g_clear_object (&priv->ext_ip4_config); ++ priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_platform (self), ++ nm_device_get_ifindex (self), ++ FALSE); ++ } ++ } + + if (priv->dev_ip4_config) { + nm_ip4_config_merge (composite, priv->dev_ip4_config, +@@ -6223,8 +6230,18 @@ ip6_config_merge_and_apply (NMDevice *self, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + init_ip6_config_dns_priority (self, composite); + +- if (commit) ++ if (commit) { + ensure_con_ip6_config (self); ++ if (priv->queued_ip6_config_id) { ++ g_clear_object (&priv->ext_ip6_config); ++ 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); ++ priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); ++ } ++ } + + /* Merge all the IP configs into the composite config */ + if (priv->ac_ip6_config) { +-- +2.9.3 + +From 2d0d1643e59f4ac935e2288a02da8774b6b237dc Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 17 May 2017 09:46:22 +0200 +Subject: [PATCH 2/2] device: fix crash in ip6_config_merge_and_apply() + +nm_ip6_config_capture() returns NULL for slaves. Fixes the following: + + nm_ip6_config_new_cloned: assertion 'NM_IS_IP6_CONFIG (src)' failed + + #0 g_logv () at /lib64/libglib-2.0.so.0 + #1 g_log () at /lib64/libglib-2.0.so.0 + #2 nm_ip6_config_new_cloned (src=0x0) at src/nm-ip6-config.c:2272 + #3 ip6_config_merge_and_apply (self=self@entry=0x200d8f0, commit=commit@entry=1) at src/devices/nm-device.c:6192 + #4 nm_device_bring_up (self=self@entry=0x200d8f0, block=block@entry=1, no_firmware=no_firmware@entry=0x0) at src/devices/nm-device.c:10369 + #5 _hw_addr_set (self=self@entry=0x200d8f0, addr=addr@entry=0x2095ea0 "6A:1C:00:2A:68:7C", operation=operation@entry=0x64f8ba "set", detail=detail@entry=0x67369d "restore") at src/devices/nm-device.c:13225 + #6 nm_device_hw_addr_set (self=self@entry=0x200d8f0, addr=addr@entry=0x2095ea0 "6A:1C:00:2A:68:7C", detail=detail@entry=0x67369d "restore", set_permanent=set_permanent@entry=0) at src/devices/nm-device.c:13255 + #7 release_slave (device=0x200d8f0, slave=0x1ef2990, configure=) at src/devices/nm-device-bond.c:463 + #8 nm_device_master_release_one_slave (self=self@entry=0x200d8f0, slave=slave@entry=0x1ef2990, configure=1, reason=reason@entry=NM_DEVICE_STATE_REASON_CONNECTION_REMOVED) at src/devices/nm-device.c:2041 + #9 slave_state_changed (slave=0x1ef2990, slave_new_state=NM_DEVICE_STATE_DEACTIVATING, slave_old_state=NM_DEVICE_STATE_ACTIVATED, reason=NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, self=0x200d8f0) + at src/devices/nm-device.c:3366 + ... + +Fixes: a21b8882cc9defc43248afc94bf59ca0f84f0d27 +(cherry picked from commit 1e78f50b8e5e24d13547b478165170117c1ac8ae) +(cherry picked from commit bf28e0845fa38cdd3556fb61a7e725ac42a7d50a) +--- + src/devices/nm-device.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 87cd296..b14dc49 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -6239,7 +6239,8 @@ ip6_config_merge_and_apply (NMDevice *self, + nm_device_get_ifindex (self), + FALSE, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); +- priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); ++ if (priv->ext_ip6_config_captured) ++ priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); + } + } + +-- +2.9.3 + diff --git a/0008-utf8safe-fixes-rh1443114.patch b/0008-utf8safe-fixes-rh1443114.patch new file mode 100644 index 0000000..2a410bd --- /dev/null +++ b/0008-utf8safe-fixes-rh1443114.patch @@ -0,0 +1,1803 @@ +From 7f3d60df818fb2b1dd99b12f893a50fd2402968f Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 17 May 2017 16:45:46 +0200 +Subject: [PATCH 01/13] libnm: fix unterminated NUL string when parsing UDev + properties + +This can result in trailing garbage (which fails UTF-8 validation +checks) or even worse, in read-out-of-bounds. + +Fixes: 6808bf8195d427975638610781f8c5384228218d + +https://bugzilla.redhat.com/show_bug.cgi?id=1443114 +https://bugzilla.redhat.com/show_bug.cgi?id=1451160 +https://bugzilla.redhat.com/show_bug.cgi?id=1451286 +(cherry picked from commit 9594ee6e6921c3e37615a572de7e986274a68500) +(cherry picked from commit 5eb11aa8ec4e402b3e5795723519cdaab1cfb828) +--- + shared/nm-utils/nm-udev-utils.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/shared/nm-utils/nm-udev-utils.c b/shared/nm-utils/nm-udev-utils.c +index bf0ad5b..1f1811c 100644 +--- a/shared/nm-utils/nm-udev-utils.c ++++ b/shared/nm-utils/nm-udev-utils.c +@@ -89,6 +89,7 @@ nm_udev_utils_property_decode (const char *uproperty, char **to_free) + return uproperty; + } + ++ *n++ = '\0'; + return (*to_free = unescaped); + } + +-- +2.9.4 + + +From be2a87e07f7a75e568d68afed1532b24edbee414 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 17 May 2017 17:04:13 +0200 +Subject: [PATCH 02/13] libnm: don't cunescape \x00 encoding in + nm_udev_utils_property_decode() + +UDev never creates such invalid escape sequences. Anyway, +we cannot accept a NUL character at this point. Just take +the ill escape verbatim -- it should never happen anyway. + +(cherry picked from commit c15eae92c0c5fc12017dd84a66ee0bbb9638b270) +(cherry picked from commit 822282754d1653ac24f6e5a9bf616fc74f957050) +--- + shared/nm-utils/nm-udev-utils.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/shared/nm-utils/nm-udev-utils.c b/shared/nm-utils/nm-udev-utils.c +index 1f1811c..79d4426 100644 +--- a/shared/nm-utils/nm-udev-utils.c ++++ b/shared/nm-utils/nm-udev-utils.c +@@ -67,8 +67,9 @@ nm_udev_utils_property_decode (const char *uproperty, char **to_free) + if ( p[0] == '\\' + && p[1] == 'x' + && (a = g_ascii_xdigit_value (p[2])) >= 0 +- && (b = g_ascii_xdigit_value (p[3])) >= 0) { +- if (!unescaped) { ++ && (b = g_ascii_xdigit_value (p[3])) >= 0 ++ && (a || b)) { ++ if (!n) { + gssize l = p - uproperty; + + unescaped = g_malloc (l + strlen (p) + 1 - 3); +@@ -84,7 +85,7 @@ nm_udev_utils_property_decode (const char *uproperty, char **to_free) + } + } + +- if (!unescaped) { ++ if (!n) { + *to_free = NULL; + return uproperty; + } +-- +2.9.4 + + +From e1679a6a48ba7367528927f3e7f0021be71e37d6 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 17 May 2017 15:18:20 +0200 +Subject: [PATCH 03/13] device: fix setting device's UDI property + +Fixes: e8139f56c26ae3bcc5e14abdb29970ae07e93299 +(cherry picked from commit 5eac18b58d2be9b5b611f4b4e356b2ac59e46bce) +(cherry picked from commit 4ae14d3677609ef3c702c1a7a706b6bc38030958) +--- + src/devices/nm-device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index b14dc49..62cb5dd 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -2460,7 +2460,7 @@ device_link_changed (NMDevice *self) + info = *pllink; + + udi = nm_platform_link_get_udi (nm_device_get_platform (self), info.ifindex); +- if (udi && g_strcmp0 (udi, priv->udi)) { ++ if (udi && !nm_streq0 (udi, priv->udi)) { + /* Update UDI to what udev gives us */ + g_free (priv->udi); + priv->udi = g_strdup (udi); +@@ -2841,7 +2841,7 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) + g_return_if_fail (plink != NULL); + + udi = nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex); +- if (udi && !g_strcmp0 (udi, priv->udi)) { ++ if (udi && !nm_streq0 (udi, priv->udi)) { + g_free (priv->udi); + priv->udi = g_strdup (udi); + _notify (self, PROP_UDI); +-- +2.9.4 + + +From 84b1c78c2474d9e579955fa0ebdfc6a8c0761548 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 17 May 2017 15:01:10 +0200 +Subject: [PATCH 04/13] device: make UDI property construct-only + +(cherry picked from commit e216d5eac0768b5936f3415cde7808982c74f0ac) +(cherry picked from commit c3b180198fe10d1fe84fea8b9944834be4f4ad56) +--- + src/devices/nm-device.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 62cb5dd..ed9bc49 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -13894,14 +13894,11 @@ set_property (GObject *object, guint prop_id, + + switch (prop_id) { + case PROP_UDI: +- if (g_value_get_string (value)) { +- g_free (priv->udi); +- priv->udi = g_value_dup_string (value); +- } ++ /* construct-only */ ++ priv->udi = g_value_dup_string (value); + break; + case PROP_IFACE: + /* construct-only */ +- g_return_if_fail (!priv->iface); + priv->iface = g_value_dup_string (value); + break; + case PROP_DRIVER: +@@ -14212,7 +14209,7 @@ nm_device_class_init (NMDeviceClass *klass) + obj_properties[PROP_UDI] = + g_param_spec_string (NM_DEVICE_UDI, "", "", + NULL, +- G_PARAM_READWRITE | G_PARAM_CONSTRUCT | ++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IFACE] = + g_param_spec_string (NM_DEVICE_IFACE, "", "", +-- +2.9.4 + + +From c63800b21cb46b7fbdc318205ed6af93aac9aeac Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Tue, 16 May 2017 18:50:21 +0200 +Subject: [PATCH 05/13] shared: add nm_utils_str_utf8safe_*() API to sanitize + UTF-8 strings + +Use C-style backslash escaping to sanitize non-UTF-8 strings. +The functions are compatible with glib's g_strcompress() and +g_strescape(). + +The difference is only that g_strescape() escapes all non-printable, +non ASCII character as well, while nm_utils_str_utf8safe_escape() +-- depending on the flags -- preserves valid UTF-8 sequence except +backslash. + +The flags allow to optionally escape ASCII control characters and +all non-ASCII (valid UTF-8) characters. But the option to preserve +valid UTF-8 (non-ASCII) characters verbatim, is what distinguishes +from g_strescape(). + +(cherry picked from commit df6d27b33a86e2ecdc5a8e1deff275d19b2cbde1) +(cherry picked from commit 52105f27df974715a8481fb240f98f73a6a8be08) +--- + libnm-core/tests/test-general.c | 95 ++++++++++++++++++++++++++ + shared/nm-utils/nm-shared-utils.c | 138 ++++++++++++++++++++++++++++++++++++++ + shared/nm-utils/nm-shared-utils.h | 16 +++++ + 3 files changed, 249 insertions(+) + +diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c +index 7ecd681..fbcfa7d 100644 +--- a/libnm-core/tests/test-general.c ++++ b/libnm-core/tests/test-general.c +@@ -5248,6 +5248,100 @@ static void test_nm_utils_enum (void) + + /*****************************************************************************/ + ++static void ++do_test_utils_str_utf8safe (const char *str, const char *expected, NMUtilsStrUtf8SafeFlags flags) ++{ ++ const char *str_safe, *s; ++ gs_free char *str2 = NULL; ++ gs_free char *str3 = NULL; ++ ++ str_safe = nm_utils_str_utf8safe_escape (str, flags, &str2); ++ ++ str3 = nm_utils_str_utf8safe_escape_cp (str, flags); ++ g_assert_cmpstr (str3, ==, str_safe); ++ g_assert ((!str && !str3) || (str != str3)); ++ g_clear_pointer (&str3, g_free); ++ ++ if (expected == NULL) { ++ g_assert (str_safe == str); ++ g_assert (!str2); ++ if (str) { ++ g_assert (!strchr (str, '\\')); ++ g_assert (g_utf8_validate (str, -1, NULL)); ++ } ++ ++ g_assert (str == nm_utils_str_utf8safe_unescape (str_safe, &str3)); ++ g_assert (!str3); ++ ++ str3 = nm_utils_str_utf8safe_unescape_cp (str_safe); ++ if (str) { ++ g_assert (str3 != str); ++ g_assert_cmpstr (str3, ==, str); ++ } else ++ g_assert (!str3); ++ g_clear_pointer (&str3, g_free); ++ return; ++ } ++ ++ g_assert (str); ++ g_assert (str_safe != str); ++ g_assert (str_safe == str2); ++ g_assert ( strchr (str, '\\') ++ || !g_utf8_validate (str, -1, NULL) ++ || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) ++ && NM_STRCHAR_ANY (str, ch, (guchar) ch >= 127)) ++ || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) ++ && NM_STRCHAR_ANY (str, ch, (guchar) ch < ' '))); ++ g_assert (g_utf8_validate (str_safe, -1, NULL)); ++ ++ str3 = g_strcompress (str_safe); ++ g_assert_cmpstr (str, ==, str3); ++ g_clear_pointer (&str3, g_free); ++ ++ str3 = nm_utils_str_utf8safe_unescape_cp (str_safe); ++ g_assert (str3 != str); ++ g_assert_cmpstr (str3, ==, str); ++ g_clear_pointer (&str3, g_free); ++ ++ s = nm_utils_str_utf8safe_unescape (str_safe, &str3); ++ g_assert (str3 != str); ++ g_assert (s == str3); ++ g_assert_cmpstr (str3, ==, str); ++ g_clear_pointer (&str3, g_free); ++ ++ g_assert_cmpstr (str_safe, ==, expected); ++} ++ ++static void ++test_utils_str_utf8safe (void) ++{ ++ do_test_utils_str_utf8safe (NULL, NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\314", "\\314", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\314\315x\315\315x", "\\314\\315x\\315\\315x", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\314\315xx", "\\314\\315xx", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\314xx", "\\314xx", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\xa0", "\\240", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\xe2\x91\xa0", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\xe2\xe2\x91\xa0", "\\342\xe2\x91\xa0", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("\xe2\xe2\x91\xa0\xa0", "\\342\xe2\x91\xa0\\240", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("a", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("ab", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("ab\314", "ab\\314", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("ab\314adsf", "ab\\314adsf", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("abadsf", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("abäb", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("x\xa0", "x\\240", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("Ä\304ab\\äb", "Ä\\304ab\\\\äb", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("Äab\\äb", "Äab\\\\äb", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("ÄÄab\\äb", "ÄÄab\\\\äb", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("㈞abä㈞b", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE); ++ do_test_utils_str_utf8safe ("abäb", "ab\\303\\244b", NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII); ++ do_test_utils_str_utf8safe ("ab\ab", "ab\\007b", NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL); ++} ++ ++/*****************************************************************************/ ++ + static int + _test_nm_in_set_get (int *call_counter, gboolean allow_called, int value) + { +@@ -5605,6 +5699,7 @@ int main (int argc, char **argv) + nmtst_init (&argc, &argv, TRUE); + + /* The tests */ ++ g_test_add_func ("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe); + g_test_add_func ("/core/general/test_nm_in_set", test_nm_in_set); + g_test_add_func ("/core/general/test_nm_in_strset", test_nm_in_strset); + g_test_add_func ("/core/general/test_setting_vpn_items", test_setting_vpn_items); +diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c +index 413526d..e7f31cb 100644 +--- a/shared/nm-utils/nm-shared-utils.c ++++ b/shared/nm-utils/nm-shared-utils.c +@@ -364,3 +364,141 @@ nm_g_object_set_property (GObject *object, + } + + /*****************************************************************************/ ++ ++static void ++_str_append_escape (GString *s, char ch) ++{ ++ g_string_append_c (s, '\\'); ++ g_string_append_c (s, '0' + ((((guchar) ch) >> 6) & 07)); ++ g_string_append_c (s, '0' + ((((guchar) ch) >> 3) & 07)); ++ g_string_append_c (s, '0' + ( ((guchar) ch) & 07)); ++} ++ ++/** ++ * nm_utils_str_utf8safe_escape: ++ * @str: NUL terminated input string, possibly in utf-8 encoding ++ * @flags: #NMUtilsStrUtf8SafeFlags flags ++ * @to_free: (out): return the pointer location of the string ++ * if a copying was necessary. ++ * ++ * Returns the possible non-UTF-8 NUL terminated string @str ++ * and uses backslash escaping (C escaping, like g_strescape()) ++ * to sanitize non UTF-8 characters. The result is valid ++ * UTF-8. ++ * ++ * The operation can be reverted with g_strcompress() or ++ * nm_utils_str_utf8safe_unescape(). ++ * ++ * Depending on @flags, valid UTF-8 characters are not escaped at all ++ * (except the escape character '\\'). This is the difference to g_strescape(), ++ * which escapes all non-ASCII characters. This allows to pass on ++ * valid UTF-8 characters as-is and can be directly shown to the user ++ * as UTF-8 -- with exception of the backslash escape character, ++ * invalid UTF-8 sequences, and other (depending on @flags). ++ * ++ * Returns: the escaped input string, as valid UTF-8. If no escaping ++ * is necessary, it returns the input @str. Otherwise, an allocated ++ * string @to_free is returned which must be freed by the caller ++ * with g_free. The escaping can be reverted by g_strcompress(). ++ **/ ++const char * ++nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free) ++{ ++ const char *p = NULL; ++ GString *s; ++ ++ g_return_val_if_fail (to_free, NULL); ++ ++ *to_free = NULL; ++ if (!str || !str[0]) ++ return str; ++ ++ if ( g_utf8_validate (str, -1, &p) ++ && !NM_STRCHAR_ANY (str, ch, ++ ( ch == '\\' \ ++ || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \ ++ && ch < ' ') \ ++ || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \ ++ && ((guchar) ch) >= 127)))) ++ return str; ++ ++ s = g_string_sized_new ((p - str) + strlen (p) + 5); ++ ++ do { ++ for (; str < p; str++) { ++ char ch = str[0]; ++ ++ if (ch == '\\') ++ g_string_append (s, "\\\\"); ++ else if ( ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \ ++ && ch < ' ') \ ++ || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \ ++ && ((guchar) ch) >= 127)) ++ _str_append_escape (s, ch); ++ else ++ g_string_append_c (s, ch); ++ } ++ ++ if (p[0] == '\0') ++ break; ++ _str_append_escape (s, p[0]); ++ ++ str = &p[1]; ++ g_utf8_validate (str, -1, &p); ++ } while (TRUE); ++ ++ *to_free = g_string_free (s, FALSE); ++ return *to_free; ++} ++ ++const char * ++nm_utils_str_utf8safe_unescape (const char *str, char **to_free) ++{ ++ g_return_val_if_fail (to_free, NULL); ++ ++ if (!str || !strchr (str, '\\')) { ++ *to_free = NULL; ++ return str; ++ } ++ return (*to_free = g_strcompress (str)); ++} ++ ++/** ++ * nm_utils_str_utf8safe_escape_cp: ++ * @str: NUL terminated input string, possibly in utf-8 encoding ++ * @flags: #NMUtilsStrUtf8SafeFlags flags ++ * ++ * Like nm_utils_str_utf8safe_escape(), except the returned value ++ * is always a copy of the input and must be freed by the caller. ++ * ++ * Returns: the escaped input string in UTF-8 encoding. The returned ++ * value should be freed with g_free(). ++ * The escaping can be reverted by g_strcompress(). ++ **/ ++char * ++nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags) ++{ ++ char *s; ++ ++ nm_utils_str_utf8safe_escape (str, flags, &s); ++ return s ?: g_strdup (str); ++} ++ ++char * ++nm_utils_str_utf8safe_unescape_cp (const char *str) ++{ ++ return str ? g_strcompress (str) : NULL; ++} ++ ++char * ++nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags) ++{ ++ char *str_to_free; ++ ++ nm_utils_str_utf8safe_escape (str, flags, &str_to_free); ++ if (str_to_free) { ++ g_free (str); ++ return str_to_free; ++ } ++ return str; ++} +diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h +index f1f9f51..69f9533 100644 +--- a/shared/nm-utils/nm-shared-utils.h ++++ b/shared/nm-utils/nm-shared-utils.h +@@ -86,4 +86,20 @@ gboolean nm_g_object_set_property (GObject *object, + + /*****************************************************************************/ + ++typedef enum { ++ NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002, ++} NMUtilsStrUtf8SafeFlags; ++ ++const char *nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free); ++const char *nm_utils_str_utf8safe_unescape (const char *str, char **to_free); ++ ++char *nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags); ++char *nm_utils_str_utf8safe_unescape_cp (const char *str); ++ ++char *nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags); ++ ++/*****************************************************************************/ ++ + #endif /* __NM_SHARED_UTILS_H__ */ +-- +2.9.4 + + +From e9eee9c65818e7dd85e79c1db6ad4c32b4c7fb52 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Tue, 16 May 2017 14:11:07 +0200 +Subject: [PATCH 06/13] device: sanitze UTF-8 values for D-Bus + + ip link add name $'d\xccf\\c' type dummy + +Use nm_utils_str_utf8safe_escape() to sanitize non UTF-8 sequences +before exposing them on D-Bus. The operation can be reverted client +side via nm_utils_str_utf8safe_unescape() or simply g_strcompress(). + +Note that this preserves all valid UTF-8 sequences as-is, with exception +of the backslash escape character and ASCII control characters. Thus, this +is a change in behavior for strings that contain such characters. + +Note that nmcli is not changed to somehow unescape the string before +printing. As the string is not valid UTF-8 (or contains ASCII characters +that need escaping), they are not printable as-is, so unescaping before +printing makes little sense. + +(cherry picked from commit 0870906540506d0157f305df32b6b1f65b10ee85) +(cherry picked from commit 3a96772918a391ec8186183b5c14c9b165322d3a) +--- + .../org.freedesktop.NetworkManager.Device.xml | 15 +++++++++++ + src/devices/nm-device.c | 31 ++++++++++++++++------ + 2 files changed, 38 insertions(+), 8 deletions(-) + +diff --git a/introspection/org.freedesktop.NetworkManager.Device.xml b/introspection/org.freedesktop.NetworkManager.Device.xml +index ee42410..be0a612 100644 +--- a/introspection/org.freedesktop.NetworkManager.Device.xml ++++ b/introspection/org.freedesktop.NetworkManager.Device.xml +@@ -21,6 +21,9 @@ + each device in your application, use the object path. If you're looking + for a way to track a specific piece of hardware across reboot or hotplug, + use a MAC address or USB serial number. ++ ++ Note that non-UTF-8 characters are backslash escaped. Use g_strcompress() ++ to obtain the true (non-UTF-8) string. + --> + + +@@ -28,6 +31,9 @@ + Interface: + + The name of the device's control (and often data) interface. ++ Note that non UTF-8 characters are backslash escaped, so the ++ resulting name may be longer then 15 characters. Use g_strcompress() ++ to revert the escaping. + --> + + +@@ -38,6 +44,9 @@ + not refer to the actual data interface until the device has successfully + established a data connection, indicated by the device's State becoming + ACTIVATED. ++ Note that non UTF-8 characters are backslash escaped, so the ++ resulting name may be longer then 15 characters. Use g_strcompress() ++ to revert the escaping. + --> + + +@@ -45,6 +54,8 @@ + Driver: + + The driver handling the device. ++ Non-UTF-8 sequences are backslash escaped. Use g_strcompress() ++ to revert. + --> + + +@@ -52,6 +63,8 @@ + DriverVersion: + + The version of the driver handling the device. ++ Non-UTF-8 sequences are backslash escaped. Use g_strcompress() ++ to revert. + --> + + +@@ -59,6 +72,8 @@ + FirmwareVersion: + + The firmware version for the device. ++ Non-UTF-8 sequences are backslash escaped. Use g_strcompress() ++ to revert. + --> + + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index ed9bc49..e61bde3 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -13993,28 +13993,43 @@ get_property (GObject *object, guint prop_id, + + switch (prop_id) { + case PROP_UDI: +- g_value_set_string (value, priv->udi); ++ /* UDI is (depending on the device type) a path to sysfs and can contain ++ * non-UTF-8. ++ * ip link add name $'d\xccf\\c' type dummy */ ++ g_value_take_string (value, ++ nm_utils_str_utf8safe_escape_cp (priv->udi, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_NONE)); + break; + case PROP_IFACE: +- g_value_set_string (value, priv->iface); ++ g_value_take_string (value, ++ nm_utils_str_utf8safe_escape_cp (priv->iface, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); + break; + case PROP_IP_IFACE: +- if (ip_config_valid (priv->state)) +- g_value_set_string (value, nm_device_get_ip_iface (self)); +- else ++ if (ip_config_valid (priv->state)) { ++ g_value_take_string (value, ++ nm_utils_str_utf8safe_escape_cp (nm_device_get_ip_iface (self), ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); ++ } else + g_value_set_string (value, NULL); + break; + case PROP_IFINDEX: + g_value_set_int (value, priv->ifindex); + break; + case PROP_DRIVER: +- g_value_set_string (value, priv->driver); ++ g_value_take_string (value, ++ nm_utils_str_utf8safe_escape_cp (priv->driver, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); + break; + case PROP_DRIVER_VERSION: +- g_value_set_string (value, priv->driver_version); ++ g_value_take_string (value, ++ nm_utils_str_utf8safe_escape_cp (priv->driver_version, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); + break; + case PROP_FIRMWARE_VERSION: +- g_value_set_string (value, priv->firmware_version); ++ g_value_take_string (value, ++ nm_utils_str_utf8safe_escape_cp (priv->firmware_version, ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); + break; + case PROP_CAPABILITIES: + g_value_set_uint (value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK)); +-- +2.9.4 + + +From 0b8676b887f63a708e6444f6b3d19003a2f9b4c8 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 17 May 2017 11:48:53 +0200 +Subject: [PATCH 07/13] libnm: UTF-8 sanitize strings from UDev in NMDevice + +(cherry picked from commit b9e9f7616556f693e2642ed433f3289f9c6da452) +(cherry picked from commit d7b184d99257a6e6e59b22709007675430ec308b) +--- + libnm/nm-device.c | 273 ++++++++++++++++++++++++++++++------------------------ + 1 file changed, 152 insertions(+), 121 deletions(-) + +diff --git a/libnm/nm-device.c b/libnm/nm-device.c +index 9cbdbd0..7e8feb1 100644 +--- a/libnm/nm-device.c ++++ b/libnm/nm-device.c +@@ -81,7 +81,7 @@ typedef struct { + GPtrArray *available_connections; + + struct udev *udev; +- char *product, *short_product; ++ char *product; + char *vendor, *short_vendor; + char *description, *bus_name; + +@@ -320,7 +320,6 @@ finalize (GObject *object) + g_free (priv->driver_version); + g_free (priv->firmware_version); + g_free (priv->product); +- g_free (priv->short_product); + g_free (priv->vendor); + g_free (priv->short_vendor); + g_free (priv->description); +@@ -1357,6 +1356,17 @@ _get_udev_property (NMDevice *device, + return db_value; + } + ++static char * ++_get_udev_property_utf8safe (NMDevice *device, ++ const char *enc_prop, /* ID_XXX_ENC */ ++ const char *db_prop) /* ID_XXX_FROM_DATABASE */ ++{ ++ return nm_utils_str_utf8safe_escape_take (_get_udev_property (device, ++ enc_prop, ++ db_prop), ++ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL); ++} ++ + /** + * nm_device_get_product: + * @device: a #NMDevice +@@ -1365,6 +1375,9 @@ _get_udev_property (NMDevice *device, + * + * Returns: the product name of the device. This is the internal string used by the + * device, and must not be modified. ++ * ++ * The string is backslash escaped (C escaping) for invalid characters. The escaping ++ * can be reverted with g_strcompress(), however the result may not be valid UTF-8. + **/ + const char * + nm_device_get_product (NMDevice *device) +@@ -1374,15 +1387,16 @@ nm_device_get_product (NMDevice *device) + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); + + priv = NM_DEVICE_GET_PRIVATE (device); +- if (!priv->product) +- priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_MODEL_FROM_DATABASE"); ++ if (!priv->product) { ++ priv->product = _get_udev_property_utf8safe (device, "ID_MODEL_ENC", "ID_MODEL_FROM_DATABASE"); + +- /* Sometimes ID_PRODUCT_FROM_DATABASE is used? */ +- if (!priv->product) +- priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_PRODUCT_FROM_DATABASE"); ++ /* Sometimes ID_PRODUCT_FROM_DATABASE is used? */ ++ if (!priv->product) ++ priv->product = _get_udev_property_utf8safe (device, "ID_MODEL_ENC", "ID_PRODUCT_FROM_DATABASE"); + +- if (!priv->product) +- priv->product = g_strdup (""); ++ if (!priv->product) ++ priv->product = g_strdup (""); ++ } + + return priv->product; + } +@@ -1395,6 +1409,9 @@ nm_device_get_product (NMDevice *device) + * + * Returns: the vendor name of the device. This is the internal string used by the + * device, and must not be modified. ++ * ++ * The string is backslash escaped (C escaping) for invalid characters. The escaping ++ * can be reverted with g_strcompress(), however the result may not be valid UTF-8. + **/ + const char * + nm_device_get_vendor (NMDevice *device) +@@ -1406,7 +1423,7 @@ nm_device_get_vendor (NMDevice *device) + priv = NM_DEVICE_GET_PRIVATE (device); + + if (!priv->vendor) +- priv->vendor = _get_udev_property (device, "ID_VENDOR_ENC", "ID_VENDOR_FROM_DATABASE"); ++ priv->vendor = _get_udev_property_utf8safe (device, "ID_VENDOR_ENC", "ID_VENDOR_FROM_DATABASE"); + + if (!priv->vendor) + priv->vendor = g_strdup (""); +@@ -1414,128 +1431,146 @@ nm_device_get_vendor (NMDevice *device) + return priv->vendor; + } + +-static const char * const ignored_words[] = { +- "Semiconductor", +- "Components", +- "Corporation", +- "Communications", +- "Company", +- "Corp.", +- "Corp", +- "Co.", +- "Inc.", +- "Inc", +- "Incorporated", +- "Ltd.", +- "Limited.", +- "Intel?", +- "chipset", +- "adapter", +- "[hex]", +- "NDIS", +- "Module", +- NULL +-}; +- +-static const char * const ignored_phrases[] = { +- "Multiprotocol MAC/baseband processor", +- "Wireless LAN Controller", +- "Wireless LAN Adapter", +- "Wireless Adapter", +- "Network Connection", +- "Wireless Cardbus Adapter", +- "Wireless CardBus Adapter", +- "54 Mbps Wireless PC Card", +- "Wireless PC Card", +- "Wireless PC", +- "PC Card with XJACK(r) Antenna", +- "Wireless cardbus", +- "Wireless LAN PC Card", +- "Technology Group Ltd.", +- "Communication S.p.A.", +- "Business Mobile Networks BV", +- "Mobile Broadband Minicard Composite Device", +- "Mobile Communications AB", +- "(PC-Suite Mode)", +- NULL +-}; +- + static char * + fixup_desc_string (const char *desc) + { +- char *p, *temp; +- char **words, **item; +- GString *str; ++ static const char *const IGNORED_PHRASES[] = { ++ "Multiprotocol MAC/baseband processor", ++ "Wireless LAN Controller", ++ "Wireless LAN Adapter", ++ "Wireless Adapter", ++ "Network Connection", ++ "Wireless Cardbus Adapter", ++ "Wireless CardBus Adapter", ++ "54 Mbps Wireless PC Card", ++ "Wireless PC Card", ++ "Wireless PC", ++ "PC Card with XJACK(r) Antenna", ++ "Wireless cardbus", ++ "Wireless LAN PC Card", ++ "Technology Group Ltd.", ++ "Communication S.p.A.", ++ "Business Mobile Networks BV", ++ "Mobile Broadband Minicard Composite Device", ++ "Mobile Communications AB", ++ "(PC-Suite Mode)", ++ }; ++ static const char *const IGNORED_WORDS[] = { ++ "Semiconductor", ++ "Components", ++ "Corporation", ++ "Communications", ++ "Company", ++ "Corp.", ++ "Corp", ++ "Co.", ++ "Inc.", ++ "Inc", ++ "Incorporated", ++ "Ltd.", ++ "Limited.", ++ "Intel?", ++ "chipset", ++ "adapter", ++ "[hex]", ++ "NDIS", ++ "Module", ++ }; ++ char *desc_full; ++ char *p, *q; + int i; + +- if (!desc) ++ if (!desc || !desc[0]) + return NULL; + +- p = temp = g_strdup (desc); +- while (*p) { +- if (*p == '_' || *p == ',') ++ /* restore original non-UTF-8-safe text. */ ++ desc_full = nm_utils_str_utf8safe_unescape_cp (desc); ++ ++ /* replace all invalid UTF-8 bytes with space. */ ++ p = desc_full; ++ while (!g_utf8_validate (p, -1, (const char **) &q)) { ++ /* the byte is invalid UTF-8. Replace it with space and proceed. */ ++ *q = ' '; ++ p = q + 1; ++ } ++ ++ /* replace '_', ',', and ASCII controll characters with space. */ ++ for (p = desc_full; p[0]; p++) { ++ if ( NM_IN_SET (*p, '_', ',') ++ || *p < ' ') + *p = ' '; +- p++; + } + + /* Attempt to shorten ID by ignoring certain phrases */ +- for (i = 0; ignored_phrases[i]; i++) { +- p = strstr (temp, ignored_phrases[i]); ++ for (i = 0; i < G_N_ELEMENTS (IGNORED_PHRASES); i++) { ++ p = strstr (desc_full, IGNORED_PHRASES[i]); + if (p) { +- guint32 ignored_len = strlen (ignored_phrases[i]); ++ const char *eow = &p[strlen (IGNORED_PHRASES[i])]; + +- memmove (p, p + ignored_len, strlen (p + ignored_len) + 1); /* +1 for the \0 */ ++ memmove (p, eow, strlen (eow) + 1); /* +1 for the \0 */ + } + } + +- /* Attempt to shorten ID by ignoring certain individual words */ +- words = g_strsplit (temp, " ", 0); +- str = g_string_new_len (NULL, strlen (temp)); +- g_free (temp); +- +- for (item = words; *item; item++) { +- gboolean ignore = FALSE; +- +- if (**item == '\0') +- continue; +- +- for (i = 0; ignored_words[i]; i++) { +- if (!strcmp (*item, ignored_words[i])) { +- ignore = TRUE; +- break; +- } ++ /* Attempt to shorten ID by ignoring certain individual words. ++ * - word-split the description at spaces ++ * - coalesce multiple spaces ++ * - skip over IGNORED_WORDS */ ++ p = desc_full; ++ q = desc_full; ++ for (;;) { ++ char *eow; ++ gsize l; ++ ++ /* skip leading spaces. */ ++ while (p[0] == ' ') ++ p++; ++ ++ if (!p[0]) ++ break; ++ ++ /* split leading word on first space */ ++ eow = strchr (p, ' '); ++ if (eow) ++ *eow = '\0'; ++ ++ if (nm_utils_strv_find_first ((char **) IGNORED_WORDS, ++ G_N_ELEMENTS (IGNORED_WORDS), ++ p) < 0) ++ goto next; ++ ++ l = strlen (p); ++ if (q != p) { ++ if (q != desc_full) ++ *q++ = ' '; ++ memmove (q, p, l); + } ++ q += l; + +- if (!ignore) { +- if (str->len) +- g_string_append_c (str, ' '); +- g_string_append (str, *item); +- } ++next: ++ if (!eow) ++ break; ++ p = eow + 1; + } +- g_strfreev (words); + +- temp = str->str; +- g_string_free (str, FALSE); ++ *q++ = '\0'; + +- return temp; ++ if (!desc_full[0]) { ++ g_free (desc_full); ++ return NULL; ++ } ++ ++ nm_assert (g_utf8_validate (desc_full, -1, NULL)); ++ return desc_full; + } + + static void +-get_description (NMDevice *device) ++ensure_description (NMDevice *device) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); +- const char *dev_product; +- const char *dev_vendor; +- char *pdown; +- char *vdown; +- GString *str; + GParamSpec *name_prop; ++ gs_free char *short_product = NULL; + +- dev_product = nm_device_get_product (device); +- priv->short_product = fixup_desc_string (dev_product); +- +- dev_vendor = nm_device_get_vendor (device); +- priv->short_vendor = fixup_desc_string (dev_vendor); ++ priv->short_vendor = nm_str_realloc (fixup_desc_string (nm_device_get_vendor (device))); + + /* Grab device's preferred name, if any */ + name_prop = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (device)), "name"); +@@ -1546,28 +1581,24 @@ get_description (NMDevice *device) + g_clear_pointer (&priv->description, g_free); + } + +- if (!dev_product || !dev_vendor) { +- priv->description = g_strdup (nm_device_get_iface (device)); ++ if ( !priv->short_vendor ++ || !(short_product = fixup_desc_string (nm_device_get_product (device)))) { ++ priv->description = g_strdup (nm_device_get_iface (device) ?: ""); + return; + } + +- str = g_string_new_len (NULL, strlen (priv->short_vendor) + strlen (priv->short_product) + 1); +- + /* Another quick hack; if all of the fixed up vendor string + * is found in product, ignore the vendor. + */ +- pdown = g_ascii_strdown (priv->short_product, -1); +- vdown = g_ascii_strdown (priv->short_vendor, -1); +- if (!strstr (pdown, vdown)) { +- g_string_append (str, priv->short_vendor); +- g_string_append_c (str, ' '); ++ { ++ gs_free char *pdown = g_ascii_strdown (short_product, -1); ++ gs_free char *vdown = g_ascii_strdown (priv->short_vendor, -1); ++ ++ if (!strstr (pdown, vdown)) ++ priv->description = g_strconcat (priv->short_vendor, " ", short_product, NULL); ++ else ++ priv->description = g_steal_pointer (&short_product); + } +- g_free (pdown); +- g_free (vdown); +- +- g_string_append (str, priv->short_product); +- +- priv->description = g_string_free (str, FALSE); + } + + static const char * +@@ -1580,7 +1611,7 @@ get_short_vendor (NMDevice *device) + priv = NM_DEVICE_GET_PRIVATE (device); + + if (!priv->description) +- get_description (device); ++ ensure_description (device); + + return priv->short_vendor; + } +@@ -1604,7 +1635,7 @@ nm_device_get_description (NMDevice *device) + priv = NM_DEVICE_GET_PRIVATE (device); + + if (!priv->description) +- get_description (device); ++ ensure_description (device); + + return priv->description; + } +-- +2.9.4 + + +From aee0c50ffa840e67642749189bd323620fff8d93 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 19 May 2017 10:18:59 +0200 +Subject: [PATCH 08/13] libnm: fix device description in fixup_desc_string() + +Fixes: b9e9f7616556f693e2642ed433f3289f9c6da452 +(cherry picked from commit 12c881ad40c4829eb430bd0148fa5dbbdfd0ec01) +(cherry picked from commit c22075dc98fc79021e9a4847b57188f09b489ddd) +--- + libnm/nm-device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libnm/nm-device.c b/libnm/nm-device.c +index 7e8feb1..6c27190 100644 +--- a/libnm/nm-device.c ++++ b/libnm/nm-device.c +@@ -1535,7 +1535,7 @@ fixup_desc_string (const char *desc) + + if (nm_utils_strv_find_first ((char **) IGNORED_WORDS, + G_N_ELEMENTS (IGNORED_WORDS), +- p) < 0) ++ p) >= 0) + goto next; + + l = strlen (p); +-- +2.9.4 + + +From 47527d343339cf0df13fa852ef73c5d0e4713890 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 19 May 2017 11:01:23 +0200 +Subject: [PATCH 09/13] libnm: ignore phrases in fixup device description only + when delimited by space + +(cherry picked from commit 72104ea10a26d4b4ff245ed60c5ccd5c043c5fe0) +(cherry picked from commit aa60b77146641db5f5d670356d8244f46dd90f81) +--- + libnm/nm-device.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libnm/nm-device.c b/libnm/nm-device.c +index 6c27190..3a6052b 100644 +--- a/libnm/nm-device.c ++++ b/libnm/nm-device.c +@@ -1507,7 +1507,11 @@ fixup_desc_string (const char *desc) + if (p) { + const char *eow = &p[strlen (IGNORED_PHRASES[i])]; + +- memmove (p, eow, strlen (eow) + 1); /* +1 for the \0 */ ++ /* require that the phrase is delimited by space, or ++ * at the beginning or end of the description. */ ++ if ( (p == desc_full || p[-1] == ' ') ++ && NM_IN_SET (eow[0], '\0', ' ')) ++ memmove (p, eow, strlen (eow) + 1); /* +1 for the \0 */ + } + } + +-- +2.9.4 + + +From 6bc607bd944e83eb4e1c668bba5f750ac98ea451 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 19 May 2017 10:19:25 +0200 +Subject: [PATCH 10/13] libnm: add testable libnm/nm-libnm-utils.c file + +Previously, internal parts of libnm were not testable. +Instead, add "libnm/nm-libnm-utils.c" and "libnm/libnm-utils.la" +to contain code that can be statically linked with a new +test "libnm/tests/test-general". + +(cherry picked from commit 8df944c7e495d18bfecaf9d8316ef7783039c94b) +(cherry picked from commit 1ebac60d2219dd29634e5d375f487d5ffa624266) +--- + Makefile.am | 45 ++++++++++++++++++++++++++++++++++++++------- + libnm/nm-libnm-utils.c | 27 +++++++++++++++++++++++++++ + libnm/nm-libnm-utils.h | 26 ++++++++++++++++++++++++++ + libnm/tests/test-general.c | 34 ++++++++++++++++++++++++++++++++++ + 4 files changed, 125 insertions(+), 7 deletions(-) + create mode 100644 libnm/nm-libnm-utils.c + create mode 100644 libnm/nm-libnm-utils.h + create mode 100644 libnm/tests/test-general.c + +diff --git a/Makefile.am b/Makefile.am +index 709d79b..a6776e9 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -734,6 +734,7 @@ libnm_lib_h_pub_nointrospect = \ + libnm_lib_h_pub_mkenums = \ + libnm/nm-enum-types.h + libnm_lib_h_priv = \ ++ libnm/nm-libnm-utils.h \ + libnm/nm-dbus-helpers.h \ + libnm/nm-device-private.h \ + libnm/nm-dhcp4-config.h \ +@@ -790,6 +791,14 @@ libnm_lib_c_real = \ + libnm_lib_c_mkenums = \ + libnm/nm-enum-types.c + ++libnm_lib_cppflags = \ ++ $(dflt_cppflags_libnm_core) \ ++ -I$(srcdir)/libnm \ ++ -I$(builddir)/libnm \ ++ -DG_LOG_DOMAIN=\""libnm"\" \ ++ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIB \ ++ -DNMRUNDIR=\"$(nmrundir)\" ++ + libnminclude_HEADERS += \ + $(libnm_lib_h_pub_real) \ + $(libnm_lib_h_pub_nointrospect) +@@ -799,6 +808,23 @@ nodist_libnminclude_HEADERS += \ + + ############################################################################### + ++lib_LTLIBRARIES += libnm/libnm-utils.la ++ ++libnm_libnm_utils_la_CPPFLAGS = \ ++ $(libnm_lib_cppflags) ++ ++libnm_libnm_utils_la_SOURCES = \ ++ libnm/nm-libnm-utils.c ++ ++libnm_libnm_utils_la_LIBADD = \ ++ libnm-core/libnm-core.la \ ++ introspection/libnmdbus.la \ ++ $(GLIB_LIBS) ++ ++$(libnm_libnm_utils_la_OBJECTS) : $(libnm_lib_h_pub_mkenums) ++ ++############################################################################### ++ + lib_LTLIBRARIES += libnm/libnm.la + + GLIB_GENERATED += \ +@@ -817,13 +843,8 @@ $(libnm_libnm_la_OBJECTS): $(libnm_lib_h_pub_mkenum + $(libnm_tests_libnm_vpn_plugin_utils_test_la_OBJECTS): $(libnm_core_lib_h_pub_mkenums) + + libnm_libnm_la_CPPFLAGS = \ +- $(dflt_cppflags_libnm_core) \ +- -I$(srcdir)/libnm \ +- -I$(builddir)/libnm \ +- $(LIBUDEV_CFLAGS) \ +- -DG_LOG_DOMAIN=\""libnm"\" \ +- -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIB \ +- -DNMRUNDIR=\"$(nmrundir)\" ++ $(libnm_lib_cppflags) \ ++ $(LIBUDEV_CFLAGS) + + libnm_libnm_la_SOURCES = \ + $(libnm_lib_h_pub_real) \ +@@ -841,6 +862,7 @@ EXTRA_libnm_libnm_la_DEPENDENCIES = \ + libnm_libnm_la_LIBADD = \ + libnm-core/libnm-core.la \ + introspection/libnmdbus.la \ ++ libnm/libnm-utils.la \ + $(DL_LIBS) \ + $(GLIB_LIBS) \ + $(UUID_LIBS) \ +@@ -947,6 +969,7 @@ EXTRA_DIST += \ + ############################################################################### + + libnm_tests_programs = \ ++ libnm/tests/test-general \ + libnm/tests/test-nm-client \ + libnm/tests/test-remote-settings-client \ + libnm/tests/test-secret-agent +@@ -964,10 +987,14 @@ libnm_tests_ldadd = \ + libnm/libnm.la \ + $(GLIB_LIBS) + ++libnm_tests_test_general_CPPFLAGS = $(libnm_tests_cppflags) + libnm_tests_test_nm_client_CPPFLAGS = $(libnm_tests_cppflags) + libnm_tests_test_remote_settings_client_CPPFLAGS = $(libnm_tests_cppflags) + libnm_tests_test_secret_agent_CPPFLAGS = $(libnm_tests_cppflags) + ++libnm_tests_test_general_SOURCES = \ ++ libnm/tests/test-general.c ++ + libnm_tests_test_nm_client_SOURCES = \ + shared/nm-test-utils-impl.c \ + shared/nm-test-libnm-utils.h \ +@@ -983,10 +1010,14 @@ libnm_tests_test_secret_agent_SOURCES = \ + shared/nm-test-libnm-utils.h \ + libnm/tests/test-secret-agent.c + ++libnm_tests_test_general_LDADD = \ ++ libnm/libnm-utils.la \ ++ $(libnm_tests_ldadd) + libnm_tests_test_nm_client_LDADD = $(libnm_tests_ldadd) + libnm_tests_test_remote_settings_client_LDADD = $(libnm_tests_ldadd) + libnm_tests_test_secret_agent_LDADD = $(libnm_tests_ldadd) + ++$(libnm_tests_test_general_OBJECTS): $(libnm_core_lib_h_pub_mkenums) + $(libnm_tests_test_nm_client_OBJECTS): $(libnm_core_lib_h_pub_mkenums) + $(libnm_tests_test_remote_settings_client_OBJECTS): $(libnm_core_lib_h_pub_mkenums) + $(libnm_tests_test_secret_agent_OBJECTS): $(libnm_core_lib_h_pub_mkenums) +diff --git a/libnm/nm-libnm-utils.c b/libnm/nm-libnm-utils.c +new file mode 100644 +index 0000000..8cea276 +--- /dev/null ++++ b/libnm/nm-libnm-utils.c +@@ -0,0 +1,27 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ * Boston, MA 02110-1301 USA. ++ * ++ * Copyright 2007 - 2008 Novell, Inc. ++ * Copyright 2007 - 2017 Red Hat, Inc. ++ */ ++ ++#include "nm-default.h" ++ ++#include "nm-libnm-utils.h" ++ ++/*****************************************************************************/ ++ +diff --git a/libnm/nm-libnm-utils.h b/libnm/nm-libnm-utils.h +new file mode 100644 +index 0000000..356b2f9 +--- /dev/null ++++ b/libnm/nm-libnm-utils.h +@@ -0,0 +1,26 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; 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 __NM_LIBNM_UTILS_H__ ++#define __NM_LIBNM_UTILS_H__ ++ ++ ++ ++#endif /* __NM_LIBNM_UTILS_H__ */ +diff --git a/libnm/tests/test-general.c b/libnm/tests/test-general.c +new file mode 100644 +index 0000000..2653cb9 +--- /dev/null ++++ b/libnm/tests/test-general.c +@@ -0,0 +1,34 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* ++ * ++ * 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, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT SC 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. ++ */ ++ ++#include "nm-default.h" ++ ++#include "nm-utils/nm-test-utils.h" ++ ++/*****************************************************************************/ ++ ++NMTST_DEFINE (); ++ ++int main (int argc, char **argv) ++{ ++ nmtst_init (&argc, &argv, TRUE); ++ ++ return g_test_run (); ++} +-- +2.9.4 + + +From 3ac56f2ad81a4104f0bc3b95ebcc648fe8445c1d Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 19 May 2017 10:32:13 +0200 +Subject: [PATCH 11/13] libnm: move fixup_desc_string() to nm-libnm-utils.c + +(cherry picked from commit e255ad2a03c84f806f9606b420fa12757bbd883f) +(cherry picked from commit ea0fd21428bd3b287a6537d9238a53f174c8854c) +--- + libnm/nm-device.c | 141 +-------------------------------------------- + libnm/nm-libnm-utils.c | 135 +++++++++++++++++++++++++++++++++++++++++++ + libnm/nm-libnm-utils.h | 2 +- + libnm/tests/test-general.c | 35 +++++++++++ + 4 files changed, 174 insertions(+), 139 deletions(-) + +diff --git a/libnm/nm-device.c b/libnm/nm-device.c +index 3a6052b..969d08a 100644 +--- a/libnm/nm-device.c ++++ b/libnm/nm-device.c +@@ -26,6 +26,7 @@ + #include + #include + ++#include "nm-libnm-utils.h" + #include "nm-dbus-interface.h" + #include "nm-active-connection.h" + #include "nm-device-bt.h" +@@ -1431,142 +1432,6 @@ nm_device_get_vendor (NMDevice *device) + return priv->vendor; + } + +-static char * +-fixup_desc_string (const char *desc) +-{ +- static const char *const IGNORED_PHRASES[] = { +- "Multiprotocol MAC/baseband processor", +- "Wireless LAN Controller", +- "Wireless LAN Adapter", +- "Wireless Adapter", +- "Network Connection", +- "Wireless Cardbus Adapter", +- "Wireless CardBus Adapter", +- "54 Mbps Wireless PC Card", +- "Wireless PC Card", +- "Wireless PC", +- "PC Card with XJACK(r) Antenna", +- "Wireless cardbus", +- "Wireless LAN PC Card", +- "Technology Group Ltd.", +- "Communication S.p.A.", +- "Business Mobile Networks BV", +- "Mobile Broadband Minicard Composite Device", +- "Mobile Communications AB", +- "(PC-Suite Mode)", +- }; +- static const char *const IGNORED_WORDS[] = { +- "Semiconductor", +- "Components", +- "Corporation", +- "Communications", +- "Company", +- "Corp.", +- "Corp", +- "Co.", +- "Inc.", +- "Inc", +- "Incorporated", +- "Ltd.", +- "Limited.", +- "Intel?", +- "chipset", +- "adapter", +- "[hex]", +- "NDIS", +- "Module", +- }; +- char *desc_full; +- char *p, *q; +- int i; +- +- if (!desc || !desc[0]) +- return NULL; +- +- /* restore original non-UTF-8-safe text. */ +- desc_full = nm_utils_str_utf8safe_unescape_cp (desc); +- +- /* replace all invalid UTF-8 bytes with space. */ +- p = desc_full; +- while (!g_utf8_validate (p, -1, (const char **) &q)) { +- /* the byte is invalid UTF-8. Replace it with space and proceed. */ +- *q = ' '; +- p = q + 1; +- } +- +- /* replace '_', ',', and ASCII controll characters with space. */ +- for (p = desc_full; p[0]; p++) { +- if ( NM_IN_SET (*p, '_', ',') +- || *p < ' ') +- *p = ' '; +- } +- +- /* Attempt to shorten ID by ignoring certain phrases */ +- for (i = 0; i < G_N_ELEMENTS (IGNORED_PHRASES); i++) { +- p = strstr (desc_full, IGNORED_PHRASES[i]); +- if (p) { +- const char *eow = &p[strlen (IGNORED_PHRASES[i])]; +- +- /* require that the phrase is delimited by space, or +- * at the beginning or end of the description. */ +- if ( (p == desc_full || p[-1] == ' ') +- && NM_IN_SET (eow[0], '\0', ' ')) +- memmove (p, eow, strlen (eow) + 1); /* +1 for the \0 */ +- } +- } +- +- /* Attempt to shorten ID by ignoring certain individual words. +- * - word-split the description at spaces +- * - coalesce multiple spaces +- * - skip over IGNORED_WORDS */ +- p = desc_full; +- q = desc_full; +- for (;;) { +- char *eow; +- gsize l; +- +- /* skip leading spaces. */ +- while (p[0] == ' ') +- p++; +- +- if (!p[0]) +- break; +- +- /* split leading word on first space */ +- eow = strchr (p, ' '); +- if (eow) +- *eow = '\0'; +- +- if (nm_utils_strv_find_first ((char **) IGNORED_WORDS, +- G_N_ELEMENTS (IGNORED_WORDS), +- p) >= 0) +- goto next; +- +- l = strlen (p); +- if (q != p) { +- if (q != desc_full) +- *q++ = ' '; +- memmove (q, p, l); +- } +- q += l; +- +-next: +- if (!eow) +- break; +- p = eow + 1; +- } +- +- *q++ = '\0'; +- +- if (!desc_full[0]) { +- g_free (desc_full); +- return NULL; +- } +- +- nm_assert (g_utf8_validate (desc_full, -1, NULL)); +- return desc_full; +-} +- + static void + ensure_description (NMDevice *device) + { +@@ -1574,7 +1439,7 @@ ensure_description (NMDevice *device) + GParamSpec *name_prop; + gs_free char *short_product = NULL; + +- priv->short_vendor = nm_str_realloc (fixup_desc_string (nm_device_get_vendor (device))); ++ priv->short_vendor = nm_str_realloc (nm_utils_fixup_desc_string (nm_device_get_vendor (device))); + + /* Grab device's preferred name, if any */ + name_prop = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (device)), "name"); +@@ -1586,7 +1451,7 @@ ensure_description (NMDevice *device) + } + + if ( !priv->short_vendor +- || !(short_product = fixup_desc_string (nm_device_get_product (device)))) { ++ || !(short_product = nm_utils_fixup_desc_string (nm_device_get_product (device)))) { + priv->description = g_strdup (nm_device_get_iface (device) ?: ""); + return; + } +diff --git a/libnm/nm-libnm-utils.c b/libnm/nm-libnm-utils.c +index 8cea276..fbbfe2c 100644 +--- a/libnm/nm-libnm-utils.c ++++ b/libnm/nm-libnm-utils.c +@@ -25,3 +25,138 @@ + + /*****************************************************************************/ + ++char * ++nm_utils_fixup_desc_string (const char *desc) ++{ ++ static const char *const IGNORED_PHRASES[] = { ++ "Multiprotocol MAC/baseband processor", ++ "Wireless LAN Controller", ++ "Wireless LAN Adapter", ++ "Wireless Adapter", ++ "Network Connection", ++ "Wireless Cardbus Adapter", ++ "Wireless CardBus Adapter", ++ "54 Mbps Wireless PC Card", ++ "Wireless PC Card", ++ "Wireless PC", ++ "PC Card with XJACK(r) Antenna", ++ "Wireless cardbus", ++ "Wireless LAN PC Card", ++ "Technology Group Ltd.", ++ "Communication S.p.A.", ++ "Business Mobile Networks BV", ++ "Mobile Broadband Minicard Composite Device", ++ "Mobile Communications AB", ++ "(PC-Suite Mode)", ++ }; ++ static const char *const IGNORED_WORDS[] = { ++ "Semiconductor", ++ "Components", ++ "Corporation", ++ "Communications", ++ "Company", ++ "Corp.", ++ "Corp", ++ "Co.", ++ "Inc.", ++ "Inc", ++ "Incorporated", ++ "Ltd.", ++ "Limited.", ++ "Intel?", ++ "chipset", ++ "adapter", ++ "[hex]", ++ "NDIS", ++ "Module", ++ }; ++ char *desc_full; ++ char *p, *q; ++ int i; ++ ++ if (!desc || !desc[0]) ++ return NULL; ++ ++ /* restore original non-UTF-8-safe text. */ ++ desc_full = nm_utils_str_utf8safe_unescape_cp (desc); ++ ++ /* replace all invalid UTF-8 bytes with space. */ ++ p = desc_full; ++ while (!g_utf8_validate (p, -1, (const char **) &q)) { ++ /* the byte is invalid UTF-8. Replace it with space and proceed. */ ++ *q = ' '; ++ p = q + 1; ++ } ++ ++ /* replace '_', ',', and ASCII controll characters with space. */ ++ for (p = desc_full; p[0]; p++) { ++ if ( NM_IN_SET (*p, '_', ',') ++ || *p < ' ') ++ *p = ' '; ++ } ++ ++ /* Attempt to shorten ID by ignoring certain phrases */ ++ for (i = 0; i < G_N_ELEMENTS (IGNORED_PHRASES); i++) { ++ p = strstr (desc_full, IGNORED_PHRASES[i]); ++ if (p) { ++ const char *eow = &p[strlen (IGNORED_PHRASES[i])]; ++ ++ /* require that the phrase is delimited by space, or ++ * at the beginning or end of the description. */ ++ if ( (p == desc_full || p[-1] == ' ') ++ && NM_IN_SET (eow[0], '\0', ' ')) ++ memmove (p, eow, strlen (eow) + 1); /* +1 for the \0 */ ++ } ++ } ++ ++ /* Attempt to shorten ID by ignoring certain individual words. ++ * - word-split the description at spaces ++ * - coalesce multiple spaces ++ * - skip over IGNORED_WORDS */ ++ p = desc_full; ++ q = desc_full; ++ for (;;) { ++ char *eow; ++ gsize l; ++ ++ /* skip leading spaces. */ ++ while (p[0] == ' ') ++ p++; ++ ++ if (!p[0]) ++ break; ++ ++ /* split leading word on first space */ ++ eow = strchr (p, ' '); ++ if (eow) ++ *eow = '\0'; ++ ++ if (nm_utils_strv_find_first ((char **) IGNORED_WORDS, ++ G_N_ELEMENTS (IGNORED_WORDS), ++ p) >= 0) ++ goto next; ++ ++ l = strlen (p); ++ if (q != p) { ++ if (q != desc_full) ++ *q++ = ' '; ++ memmove (q, p, l); ++ } ++ q += l; ++ ++next: ++ if (!eow) ++ break; ++ p = eow + 1; ++ } ++ ++ *q++ = '\0'; ++ ++ if (!desc_full[0]) { ++ g_free (desc_full); ++ return NULL; ++ } ++ ++ nm_assert (g_utf8_validate (desc_full, -1, NULL)); ++ return desc_full; ++} +diff --git a/libnm/nm-libnm-utils.h b/libnm/nm-libnm-utils.h +index 356b2f9..4a5a361 100644 +--- a/libnm/nm-libnm-utils.h ++++ b/libnm/nm-libnm-utils.h +@@ -21,6 +21,6 @@ + #ifndef __NM_LIBNM_UTILS_H__ + #define __NM_LIBNM_UTILS_H__ + +- ++char *nm_utils_fixup_desc_string (const char *desc); + + #endif /* __NM_LIBNM_UTILS_H__ */ +diff --git a/libnm/tests/test-general.c b/libnm/tests/test-general.c +index 2653cb9..7e0b7bb 100644 +--- a/libnm/tests/test-general.c ++++ b/libnm/tests/test-general.c +@@ -20,15 +20,50 @@ + + #include "nm-default.h" + ++#include "nm-libnm-utils.h" ++ + #include "nm-utils/nm-test-utils.h" + + /*****************************************************************************/ + ++static void ++do_test_fixup_desc_string (const char *desc, const char *expected) ++{ ++ gs_free char *result = NULL; ++ ++ result = nm_utils_fixup_desc_string (desc); ++ g_assert_cmpstr (result, ==, expected); ++} ++ ++#define do_test_fixup_desc_string_same(desc) (do_test_fixup_desc_string (""desc"", ""desc"")) ++ ++static void ++test_fixup_desc_string (void) ++{ ++ do_test_fixup_desc_string (NULL, NULL); ++ do_test_fixup_desc_string ("", NULL); ++ do_test_fixup_desc_string_same ("a"); ++ do_test_fixup_desc_string_same ("a b"); ++ do_test_fixup_desc_string ("a b ", "a b"); ++ do_test_fixup_desc_string (" a bbc ", "a bbc"); ++ do_test_fixup_desc_string (" a \xcc bbc ", "a bbc"); ++ do_test_fixup_desc_string (" a\xcc bbc ", "a bbc"); ++ do_test_fixup_desc_string (" a\xcc""bbc Wireless PC", "a bbc"); ++ do_test_fixup_desc_string (" a\xcc""bbc Wireless PC ", "a bbc"); ++ do_test_fixup_desc_string (" a\xcc""bbcWireless PC ", "a bbcWireless PC"); ++ do_test_fixup_desc_string (" a\xcc""bbc Wireless PCx", "a bbc Wireless PCx"); ++ do_test_fixup_desc_string (" a\xcc""bbc Inc Wireless PC ", "a bbc"); ++} ++ ++/*****************************************************************************/ ++ + NMTST_DEFINE (); + + int main (int argc, char **argv) + { + nmtst_init (&argc, &argv, TRUE); + ++ g_test_add_func ("/libnm/general/fixup_desc_string", test_fixup_desc_string); ++ + return g_test_run (); + } +-- +2.9.4 + + +From 1e5a95c89c35fadbefd6db21c20fcc4a7750063a Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 19 May 2017 14:13:37 +0200 +Subject: [PATCH 12/13] build: don't install intermediate library + libnm/libnm-utils.la + +Fixes: 8df944c7e495d18bfecaf9d8316ef7783039c94b +(cherry picked from commit 733160c862452721821c508465429ffbbda203ae) +(cherry picked from commit 23b5bdd8435bfaf729488e1d3d8821cce948e92e) +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index a6776e9..7ba3603 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -808,7 +808,7 @@ nodist_libnminclude_HEADERS += \ + + ############################################################################### + +-lib_LTLIBRARIES += libnm/libnm-utils.la ++noinst_LTLIBRARIES += libnm/libnm-utils.la + + libnm_libnm_utils_la_CPPFLAGS = \ + $(libnm_lib_cppflags) +-- +2.9.4 + + +From 32ec4059fd17a30003571c6d97c9859e84de92ed Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 19 May 2017 14:24:14 +0200 +Subject: [PATCH 13/13] build: don't link static libraries multiple times + +libnm-core.a should only be linked once in libnm.so. Previously, +it was linked twice, once as part of libnm-utils.a and once +directly in libnm.so. + +Fixes: 8df944c7e495d18bfecaf9d8316ef7783039c94b +(cherry picked from commit 5a67130e1548bd9314fbd007e131ef378d8b51c7) +(cherry picked from commit da2a02138dc7f0c5aff41019a0517854f379a44c) +--- + Makefile.am | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 7ba3603..909847e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -860,8 +860,6 @@ EXTRA_libnm_libnm_la_DEPENDENCIES = \ + libnm/libnm.ver + + libnm_libnm_la_LIBADD = \ +- libnm-core/libnm-core.la \ +- introspection/libnmdbus.la \ + libnm/libnm-utils.la \ + $(DL_LIBS) \ + $(GLIB_LIBS) \ +-- +2.9.4 + diff --git a/0009-ifcfg-rh-fix-null-next-hop.patch b/0009-ifcfg-rh-fix-null-next-hop.patch new file mode 100644 index 0000000..8210672 --- /dev/null +++ b/0009-ifcfg-rh-fix-null-next-hop.patch @@ -0,0 +1,140 @@ +From a3d2153b90f3f56f1548d01be674a0ab5e82e6b7 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 19 May 2017 16:18:55 +0200 +Subject: [PATCH] ifcfg-rh: omit empty next hop for routes in legacy format + +Don't add "via (null)" if the next hop is missing. + +https://bugzilla.redhat.com/show_bug.cgi?id=1452648 +(cherry picked from commit af8aac9b544cb64df3b77a413dfded23e976d1b0) +(cherry picked from commit cb5ba08f00691b18d272bfb08e4929d00fa246bb) +--- + .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 77 ++++++++++------------ + 1 file changed, 36 insertions(+), 41 deletions(-) + +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 d6f33c4..400e9bd 100644 +--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c ++++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +@@ -1926,12 +1926,8 @@ get_route_attributes_string (NMIPRoute *route, int family) + static gboolean + write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error) + { +- const char *dest, *next_hop; +- char **route_items; +- gs_free char *route_contents = NULL; ++ nm_auto_free_gstring GString *contents = NULL; + NMIPRoute *route; +- guint32 prefix; +- gint64 metric; + guint32 i, num; + + g_return_val_if_fail (filename != NULL, FALSE); +@@ -1945,36 +1941,34 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError + return TRUE; + } + +- route_items = g_malloc0 (sizeof (char *) * (num + 1)); ++ contents = g_string_new (""); ++ + for (i = 0; i < num; i++) { ++ const char *next_hop; + gs_free char *options = NULL; ++ gint64 metric; + + route = nm_setting_ip_config_get_route (s_ip4, i); +- +- dest = nm_ip_route_get_dest (route); +- prefix = nm_ip_route_get_prefix (route); + next_hop = nm_ip_route_get_next_hop (route); + metric = nm_ip_route_get_metric (route); +- + 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 ?: ""); ++ g_string_append_printf (contents, "%s/%u", ++ nm_ip_route_get_dest (route), ++ nm_ip_route_get_prefix (route)); ++ if (next_hop) ++ g_string_append_printf (contents, " via %s", next_hop); ++ if (metric >= 0) ++ g_string_append_printf (contents, " metric %u", (guint) metric); ++ if (options) { ++ g_string_append_c (contents, ' '); ++ g_string_append (contents, options); + } ++ ++ g_string_append_c (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, contents->len, NULL)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Writing route file '%s' failed", filename); + return FALSE; +@@ -2492,32 +2486,33 @@ write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **erro + } + + contents = g_string_new (""); ++ + for (i = 0; i < num; i++) { + gs_free char *options = NULL; ++ const char *next_hop; ++ gint64 metric; + + route = nm_setting_ip_config_get_route (s_ip6, i); ++ next_hop = nm_ip_route_get_next_hop (route); ++ metric = nm_ip_route_get_metric (route); + options = get_route_attributes_string (route, AF_INET6); + +- if (nm_ip_route_get_metric (route) == -1) { +- 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), +- options ? " " : "", +- options ?: ""); +- } else { +- 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), +- (unsigned) nm_ip_route_get_metric (route), +- options ? " " : "", +- options ?: ""); ++ g_string_append_printf (contents, "%s/%u", ++ nm_ip_route_get_dest (route), ++ nm_ip_route_get_prefix (route)); ++ if (next_hop) ++ g_string_append_printf (contents, " via %s", next_hop); ++ if (metric >= 0) ++ g_string_append_printf (contents, " metric %u", (guint) metric); ++ if (options) { ++ g_string_append_c (contents, ' '); ++ g_string_append (contents, options); + } +- g_string_append (contents, "\n"); ++ ++ g_string_append_c (contents, '\n'); + } + +- if (!g_file_set_contents (filename, contents->str, -1, NULL)) { ++ if (!g_file_set_contents (filename, contents->str, contents->len, NULL)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Writing route6 file '%s' failed", filename); + return FALSE; +-- +2.9.3 + diff --git a/NetworkManager.spec b/NetworkManager.spec index 4248cd3..ae7f3cb 100644 --- a/NetworkManager.spec +++ b/NetworkManager.spec @@ -10,7 +10,7 @@ %global epoch_version 1 %global rpm_version 1.8.0 %global real_version 1.8.0 -%global release_version 1 +%global release_version 2 %global snapshot %{nil} %global git_sha %{nil} @@ -76,7 +76,14 @@ Source1: NetworkManager.conf Source2: 00-server.conf Source3: 20-connectivity-fedora.conf -Patch1: 0001-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch +Patch2: 0002-utils-fix-maybe-uninitialized-in-nm-udev-utils.c.patch +Patch3: 0003-fix-device-run-state-unknown-rh1440171.patch +Patch4: 0004-proxy-crash-rh1450459.patch +Patch5: 0005-device-fix-wait-carrier-rh1450444.patch +Patch6: 0006-dhcp-don-t-add-route-to-DHCP4-server-rh1448987.patch +Patch7: 0007-device-update-ext-conf-before-commit-rh1449873.patch +Patch8: 0008-utf8safe-fixes-rh1443114.patch +Patch9: 0009-ifcfg-rh-fix-null-next-hop.patch Requires(post): systemd Requires(preun): systemd @@ -332,7 +339,14 @@ by nm-connection-editor and nm-applet in a non-graphical environment. %prep %setup -q -n NetworkManager-%{real_version} -%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 %build %if %{with regen_docs} @@ -635,6 +649,17 @@ fi %endif %changelog +* Sat May 20 2017 Thomas Haller - 1:1.8.0-2 +- dhcp: don't add route to DHCP4 server (rh #1448987) +- device: update external configuration before commit (rh #1449873) +- libnm: fix NUL termination of device's description (rh #1443114) +- libnm, core: ensure valid UTF-8 in device properties (rh #1443114) +- core: fix device's UDI property on D-Bus (rh #1443114) +- ifcfg-rh: omit empty next hop for routes in legacy format (rh #1452648) +- core: fix persisting managed state of device (rh #1440171) +- proxy: fix use-after-free (rh #1450459) +- device: don't wrongly delay startup complete waiting for carrier (rh #1450444) + * Wed May 10 2017 Thomas Haller - 1:1.8.0-1 - Update to 1.8.0 release