about summary refs log tree commit diff
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-connection.c29
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c1
-rw-r--r--shared/nm-glib-aux/nm-glib.h8
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.c11
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.h3
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c121
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h23
-rw-r--r--shared/nm-keyfile/nm-keyfile-utils.c1
-rw-r--r--shared/nm-keyfile/nm-keyfile.c86
-rw-r--r--shared/nm-test-utils-impl.c2
-rw-r--r--shared/nm-version-macros.h4
11 files changed, 191 insertions, 98 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
index a5c8ea66..30514e28 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
@@ -1136,6 +1136,13 @@ int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
         return 0;
 }
 
+/*
+ * Returns:
+ *  0                     on success
+ *  N_DHCP4_E_MALFORMED   if a malformed packet was received
+ *  N_DHCP4_E_UNEXPECTED  if the packet received contains unexpected data
+ *  N_DHCP4_E_AGAIN       if there was another error (non fatal for the client)
+ */
 int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                      NDhcp4Incoming **messagep) {
         _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
@@ -1150,10 +1157,11 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                                  connection->scratch_buffer,
                                                  sizeof(connection->scratch_buffer),
                                                  &message);
-                if (r)
+                if (!r)
+                        break;
+                else if (r == N_DHCP4_E_MALFORMED)
                         return r;
-
-                break;
+                return N_DHCP4_E_AGAIN;
         case N_DHCP4_C_CONNECTION_STATE_DRAINING:
                 r = n_dhcp4_c_socket_packet_recv(connection->fd_packet,
                                                  connection->scratch_buffer,
@@ -1161,8 +1169,10 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                                  &message);
                 if (!r)
                         break;
-                else if (r != N_DHCP4_E_AGAIN)
+                else if (r == N_DHCP4_E_MALFORMED)
                         return r;
+                else if (r != N_DHCP4_E_AGAIN)
+                        return N_DHCP4_E_AGAIN;
 
                 /*
                  * The UDP socket is open and the packet socket has been shut down
@@ -1180,18 +1190,21 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                               connection->scratch_buffer,
                                               sizeof(connection->scratch_buffer),
                                               &message);
-                if (r)
+                if (!r)
+                        break;
+                else if (r == N_DHCP4_E_MALFORMED)
                         return r;
-
-                break;
+                return N_DHCP4_E_AGAIN;
         default:
                 abort();
                 return -ENOTRECOVERABLE;
         }
 
         r = n_dhcp4_c_connection_verify_incoming(connection, message, &type);
-        if (r)
+        if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED)
                 return r;
+        else if (r != 0)
+                return N_DHCP4_E_AGAIN;
 
         if (type == N_DHCP4_MESSAGE_OFFER || type == N_DHCP4_MESSAGE_ACK) {
                 n_dhcp4_c_log(connection->client_config, LOG_INFO,
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
index e4477a7c..5e971298 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -1242,6 +1242,7 @@ int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events)
                         return 0;
                 }
 
+                abort();
                 return r;
         }
 
diff --git a/shared/nm-glib-aux/nm-glib.h b/shared/nm-glib-aux/nm-glib.h
index 4ecba9ff..7a5b8edd 100644
--- a/shared/nm-glib-aux/nm-glib.h
+++ b/shared/nm-glib-aux/nm-glib.h
@@ -622,4 +622,12 @@ g_hash_table_steal_extended (GHashTable    *hash_table,
 
 /*****************************************************************************/
 
+__attribute__((__deprecated__("Don't use g_cancellable_reset(). Create a new cancellable instead.")))
+void _nm_g_cancellable_reset (GCancellable *cancellable);
+
+#undef g_cancellable_reset
+#define g_cancellable_reset(cancellable) _nm_g_cancellable_reset(cancellable)
+
+/*****************************************************************************/
+
 #endif  /* __NM_GLIB_H__ */
diff --git a/shared/nm-glib-aux/nm-hash-utils.c b/shared/nm-glib-aux/nm-hash-utils.c
index 0a701d06..232c62c0 100644
--- a/shared/nm-glib-aux/nm-hash-utils.c
+++ b/shared/nm-glib-aux/nm-hash-utils.c
@@ -265,6 +265,17 @@ nm_ppdirect_equal (gconstpointer a, gconstpointer b)
 /*****************************************************************************/
 
 guint
+nm_gbytes_hash (gconstpointer p)
+{
+	GBytes *ptr = (GBytes *) p;
+	gconstpointer arr;
+	gsize len;
+
+	arr = g_bytes_get_data (ptr, &len);
+	return nm_hash_mem (792701303u, arr, len);
+}
+
+guint
 nm_pgbytes_hash (gconstpointer p)
 {
 	GBytes *const*ptr = p;
diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h
index 9f2e9766..be69bfa8 100644
--- a/shared/nm-glib-aux/nm-hash-utils.h
+++ b/shared/nm-glib-aux/nm-hash-utils.h
@@ -315,6 +315,9 @@ gboolean nm_ppdirect_equal (gconstpointer a, gconstpointer b);
 
 /*****************************************************************************/
 
+guint nm_gbytes_hash (gconstpointer p);
+#define nm_gbytes_equal g_bytes_equal
+
 guint nm_pgbytes_hash (gconstpointer p);
 gboolean nm_pgbytes_equal (gconstpointer a, gconstpointer b);
 
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index c06399dd..5dd099a7 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -397,6 +397,24 @@ truncate:
 
 /*****************************************************************************/
 
+GBytes *
+nm_gbytes_get_empty (void)
+{
+	static GBytes *bytes = NULL;
+	GBytes *b;
+
+again:
+	b = g_atomic_pointer_get (&bytes);
+	if (G_UNLIKELY (!b)) {
+		b = g_bytes_new_static ("", 0);
+		if (!g_atomic_pointer_compare_and_exchange (&bytes, NULL, b)) {
+			g_bytes_unref (b);
+			goto again;
+		}
+	}
+	return b;
+}
+
 /**
  * nm_utils_gbytes_equals:
  * @bytes: (allow-none): a #GBytes array to compare. Note that
@@ -3655,9 +3673,9 @@ _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...)
 typedef struct {
 	gpointer callback_user_data;
 	GCancellable *cancellable;
+	GSource *source;
 	NMUtilsInvokeOnIdleCallback callback;
 	gulong cancelled_id;
-	guint idle_id;
 } InvokeOnIdleData;
 
 static gboolean
@@ -3665,12 +3683,13 @@ _nm_utils_invoke_on_idle_cb_idle (gpointer user_data)
 {
 	InvokeOnIdleData *data = user_data;
 
-	data->idle_id = 0;
 	nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id);
 
 	data->callback (data->callback_user_data, data->cancellable);
+
 	nm_g_object_unref (data->cancellable);
-	g_slice_free (InvokeOnIdleData, data);
+	g_source_destroy (data->source);
+	nm_g_slice_free (data);
 	return G_SOURCE_REMOVE;
 }
 
@@ -3680,41 +3699,87 @@ _nm_utils_invoke_on_idle_cb_cancelled (GCancellable *cancellable,
 {
 	/* on cancellation, we invoke the callback synchronously. */
 	nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id);
-	nm_clear_g_source (&data->idle_id);
+	nm_clear_g_source_inst (&data->source);
 	data->callback (data->callback_user_data, data->cancellable);
 	nm_g_object_unref (data->cancellable);
-	g_slice_free (InvokeOnIdleData, data);
+	nm_g_slice_free (data);
 }
 
-void
-nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback,
-                         gpointer callback_user_data,
-                         GCancellable *cancellable)
+static void
+_nm_utils_invoke_on_idle_start (gboolean use_timeout,
+                                guint timeout_msec,
+                                GCancellable *cancellable,
+                                NMUtilsInvokeOnIdleCallback callback,
+                                gpointer callback_user_data)
 {
 	InvokeOnIdleData *data;
+	GSource *source;
 
 	g_return_if_fail (callback);
 
 	data = g_slice_new (InvokeOnIdleData);
-	data->callback = callback;
-	data->callback_user_data = callback_user_data;
-	data->cancellable = nm_g_object_ref (cancellable);
-	if (   cancellable
-	    && !g_cancellable_is_cancelled (cancellable)) {
-		/* if we are passed a non-cancelled cancellable, we register to the "cancelled"
-		 * signal an invoke the callback synchronously (from the signal handler).
-		 *
-		 * We don't do that,
-		 *  - if the cancellable is already cancelled (because we don't want to invoke
-		 *    the callback synchronously from the caller).
-		 *  - if we have no cancellable at hand. */
-		data->cancelled_id = g_signal_connect (cancellable,
-		                                       "cancelled",
-		                                       G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled),
-		                                       data);
-	} else
-		data->cancelled_id = 0;
-	data->idle_id = g_idle_add (_nm_utils_invoke_on_idle_cb_idle, data);
+	*data = (InvokeOnIdleData) {
+		.callback           = callback,
+		.callback_user_data = callback_user_data,
+		.cancellable        = nm_g_object_ref (cancellable),
+		.cancelled_id       = 0,
+	};
+
+	if (cancellable) {
+		if (g_cancellable_is_cancelled (cancellable)) {
+			/* the cancellable is already cancelled. We ignore the timeout
+			 * and always schedule an idle action. */
+			use_timeout = FALSE;
+		} else {
+			/* if we are passed a non-cancelled cancellable, we register to the "cancelled"
+			 * signal an invoke the callback synchronously (from the signal handler).
+			 *
+			 * We don't do that,
+			 *  - if the cancellable is already cancelled (because we don't want to invoke
+			 *    the callback synchronously from the caller).
+			 *  - if we have no cancellable at hand. */
+			data->cancelled_id = g_signal_connect (cancellable,
+			                                       "cancelled",
+			                                       G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled),
+			                                       data);
+		}
+	}
+
+	if (use_timeout) {
+		source = nm_g_timeout_source_new (timeout_msec,
+		                                  G_PRIORITY_DEFAULT,
+		                                  _nm_utils_invoke_on_idle_cb_idle,
+		                                  data,
+		                                  NULL);
+	} else {
+		source = nm_g_idle_source_new (G_PRIORITY_DEFAULT,
+		                               _nm_utils_invoke_on_idle_cb_idle,
+		                               data,
+		                               NULL);
+	}
+
+	/* use the current thread default context. */
+	g_source_attach (source,
+	                 g_main_context_get_thread_default ());
+
+	data->source = source;
+}
+
+void
+nm_utils_invoke_on_idle (GCancellable *cancellable,
+                         NMUtilsInvokeOnIdleCallback callback,
+                         gpointer callback_user_data)
+{
+	_nm_utils_invoke_on_idle_start (FALSE, 0, cancellable, callback, callback_user_data);
+}
+
+void
+nm_utils_invoke_on_timeout (guint timeout_msec,
+                            GCancellable *cancellable,
+                            NMUtilsInvokeOnIdleCallback callback,
+                            gpointer callback_user_data)
+{
+	_nm_utils_invoke_on_idle_start (TRUE, timeout_msec, cancellable, callback, callback_user_data);
 }
 
 /*****************************************************************************/
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index 537b402b..d5990c2d 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -280,6 +280,14 @@ gboolean nm_utils_ipaddr_is_normalized (int addr_family,
             return (_a < _b) ? -1 : 1; \
     } G_STMT_END
 
+/* In the general case, direct pointer comparison is undefined behavior in C.
+ * Avoid that by casting pointers to void* and then to uintptr_t. This comparison
+ * is not really meaningful, except that it provides some kind of stable sort order
+ * between pointers (that can otherwise not be compared). */
+#define NM_CMP_DIRECT_PTR(a, b) \
+	NM_CMP_DIRECT ((uintptr_t) ((void *) (a)), \
+	               (uintptr_t) ((void *) (b)))
+
 #define NM_CMP_DIRECT_MEMCMP(a, b, size) \
     NM_CMP_RETURN (memcmp ((a), (b), (size)))
 
@@ -381,6 +389,8 @@ nm_utils_is_separator (const char c)
 
 /*****************************************************************************/
 
+GBytes *nm_gbytes_get_empty (void);
+
 static inline gboolean
 nm_gbytes_equal0 (GBytes *a, GBytes *b)
 {
@@ -1621,12 +1631,17 @@ void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...);
 
 /*****************************************************************************/
 
-typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer callback_user_data,
+typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer user_data,
                                              GCancellable *cancellable);
 
-void nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback,
-                              gpointer callback_user_data,
-                              GCancellable *cancellable);
+void nm_utils_invoke_on_idle (GCancellable *cancellable,
+                              NMUtilsInvokeOnIdleCallback callback,
+                              gpointer callback_user_data);
+
+void nm_utils_invoke_on_timeout (guint timeout_msec,
+                                 GCancellable *cancellable,
+                                 NMUtilsInvokeOnIdleCallback callback,
+                                 gpointer callback_user_data);
 
 /*****************************************************************************/
 
diff --git a/shared/nm-keyfile/nm-keyfile-utils.c b/shared/nm-keyfile/nm-keyfile-utils.c
index e18db20d..041b5eab 100644
--- a/shared/nm-keyfile/nm-keyfile-utils.c
+++ b/shared/nm-keyfile/nm-keyfile-utils.c
@@ -124,7 +124,6 @@ nm_keyfile_plugin_kf_get_##stype##_list (GKeyFile *kf, \
 			list = g_key_file_get_##stype##_list (kf, alias, key, &l, &local); \
 		} \
 	} \
-	nm_assert ((!local) != (!list)); \
 	if (local) \
 		g_propagate_error (error, local); \
 	if (!list) \
diff --git a/shared/nm-keyfile/nm-keyfile.c b/shared/nm-keyfile/nm-keyfile.c
index 15485747..879b1b00 100644
--- a/shared/nm-keyfile/nm-keyfile.c
+++ b/shared/nm-keyfile/nm-keyfile.c
@@ -167,9 +167,10 @@ read_array_of_uint (GKeyFile *file,
 	gsize length;
 	gsize i;
 	gs_free int *tmp = NULL;
+	gs_free_error GError *error = NULL;
 
-	tmp = nm_keyfile_plugin_kf_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
-	if (length > G_MAXUINT)
+	tmp = nm_keyfile_plugin_kf_get_integer_list (file, nm_setting_get_name (setting), key, &length, &error);
+	if (error)
 		return;
 
 	array = g_array_sized_new (FALSE, FALSE, sizeof (guint), length);
@@ -934,13 +935,19 @@ ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const cha
 }
 
 static void
-mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length, gboolean cloned_mac_addr)
+mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize addr_len, gboolean cloned_mac_addr)
 {
 	const char *setting_name = nm_setting_get_name (setting);
+	char addr_str[NM_UTILS_HWADDR_LEN_MAX * 3];
+	guint8 addr_bin[NM_UTILS_HWADDR_LEN_MAX];
 	gs_free char *tmp_string = NULL;
-	const char *p, *mac_str;
-	gs_free guint8 *buf_arr = NULL;
-	guint buf_len = 0;
+	gs_free int *int_list = NULL;
+	const char *mac_str;
+	gsize int_list_len;
+	gsize i;
+
+	nm_assert (addr_len > 0);
+	nm_assert (addr_len <= NM_UTILS_HWADDR_LEN_MAX);
 
 	tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
 
@@ -950,60 +957,31 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
 		goto out;
 	}
 
-	if (tmp_string && tmp_string[0]) {
-		/* Look for enough ':' characters to signify a MAC address */
-		guint i = 0;
-
-		p = tmp_string;
-		while (*p) {
-			if (*p == ':')
-				i++;
-			p++;
-		}
-
-		if (enforce_length == 0 || enforce_length == i+1) {
-			/* If we found enough it's probably a string-format MAC address */
-			buf_len = i + 1;
-			buf_arr = g_new (guint8, buf_len);
-			if (!nm_utils_hwaddr_aton (tmp_string, buf_arr, buf_len))
-				nm_clear_g_free (&buf_arr);
-		}
-	}
-	nm_clear_g_free (&tmp_string);
-
-	if (!buf_arr) {
-		gs_free int *tmp_list = NULL;
-		gsize length;
+	if (   tmp_string
+	    && nm_utils_hwaddr_aton (tmp_string, addr_bin, addr_len))
+		goto good_addr_bin;
 
-		/* Old format; list of ints */
-		tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
-		if (length > 0 && (enforce_length == 0 || enforce_length == length)) {
-			gsize i;
+	/* Old format; list of ints */
+	int_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &int_list_len, NULL);
+	if (int_list_len == addr_len) {
+		for (i = 0; i < addr_len; i++) {
+			const int val = int_list[i];
 
-			buf_len = length;
-			buf_arr = g_new (guint8, buf_len);
-			for (i = 0; i < length; i++) {
-				int val = tmp_list[i];
-
-				if (val < 0 || val > 255) {
-					handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-					             _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
-					             val);
-					return;
-				}
-				buf_arr[i] = (guint8) val;
-			}
+			if (val < 0 || val > 255)
+				break;
+			addr_bin[i] = (guint8) val;
 		}
+		if (i == addr_len)
+			goto good_addr_bin;
 	}
 
-	if (!buf_arr) {
-		handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-		             _("ignoring invalid MAC address"));
-		return;
-	}
+	handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+	             _("ignoring invalid MAC address"));
+	return;
 
-	tmp_string = nm_utils_hwaddr_ntoa (buf_arr, buf_len);
-	mac_str = tmp_string;
+good_addr_bin:
+	nm_utils_bin2hexstr_full (addr_bin, addr_len, ':', TRUE, addr_str);
+	mac_str = addr_str;
 
 out:
 	g_object_set (setting, key, mac_str, NULL);
diff --git a/shared/nm-test-utils-impl.c b/shared/nm-test-utils-impl.c
index 0ef6591f..ce7cc8d1 100644
--- a/shared/nm-test-utils-impl.c
+++ b/shared/nm-test-utils-impl.c
@@ -454,7 +454,7 @@ _context_object_new_do_cb (GObject *source_object,
 static GObject *
 _context_object_new_do (GType gtype,
                         gboolean sync,
-                        const gchar *first_property_name,
+                        const char *first_property_name,
                         va_list var_args)
 {
 	gs_free_error GError *error = NULL;
diff --git a/shared/nm-version-macros.h b/shared/nm-version-macros.h
index a085c115..b98a4e1d 100644
--- a/shared/nm-version-macros.h
+++ b/shared/nm-version-macros.h
@@ -22,7 +22,7 @@
  * Evaluates to the minor version number of NetworkManager which this source
  * is compiled against.
  */
-#define NM_MINOR_VERSION (23)
+#define NM_MINOR_VERSION (24)
 
 /**
  * NM_MICRO_VERSION:
@@ -30,7 +30,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (90)
+#define NM_MICRO_VERSION (0)
 
 /**
  * NM_CHECK_VERSION: