lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250912195339.20635-15-yana2bsh@gmail.com>
Date: Fri, 12 Sep 2025 22:53:37 +0300
From: Yana Bashlykova <yana2bsh@...il.com>
To: "David S. Miller" <davem@...emloft.net>
Cc: Yana Bashlykova <yana2bsh@...il.com>,
	Eric Dumazet <edumazet@...gle.com>,
	Jakub Kicinski <kuba@...nel.org>,
	Paolo Abeni <pabeni@...hat.com>,
	Shuah Khan <shuah@...nel.org>,
	netdev@...r.kernel.org,
	linux-kselftest@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	lvc-project@...uxtesting.org
Subject: [PATCH 6.1 14/15] selftests: net: genetlink: add Netlink and Generic Netlink test suite

This commit introduces a comprehensive test suite for Netlink and Generic Netlink
functionality. The tests cover:

- Basic socket operations and protocol validation
- Controller family resolution and policy checks
- Multicast group communication
- Error handling and edge cases
- Socket option testing (EXT_ACK, NO_ENOBUFS, etc.)
- Stress testing and race conditions

The test suite uses kselftest harness and includes both positive and negative
test cases to validate kernel behavior under various conditions.

Signed-off-by: Yana Bashlykova <yana2bsh@...il.com>
---
 tools/testing/selftests/net/genetlink.c | 3881 +++++++++++++++++++++++
 1 file changed, 3881 insertions(+)

diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selftests/net/genetlink.c
index 361840aae918..a166f2c474b4 100644
--- a/tools/testing/selftests/net/genetlink.c
+++ b/tools/testing/selftests/net/genetlink.c
@@ -81,10 +81,34 @@
 
 #define LARGE_GENL_FAMILY_NAME "LARGE_GENL"
 
+#define SOME_RANDOM_CMD 99
+
 /**
  * Callback data structures - used to pass data between test cases and message handlers
  */
 
+struct callback_data {
+	int int_value;
+	char *message;
+	char *some_info;
+};
+
+struct callback_data_parallel_dump {
+	char *name;
+	char *desc;
+};
+
+struct callback_data_parallel_dump data_check[] = {
+	{ "TEST_GENL", "one" },
+	{ "PARALLEL_GENL", "two" },
+	{ "THIRD_GENL", "three" },
+	{ "LARGE_GENL", "four" },
+};
+
+#define DATA_SIZE (sizeof(data_check) / sizeof(data_check[0]))
+
+static int elems;
+
 struct callback_data_ctrl {
 	int family_id;
 	char *family_name;
@@ -93,6 +117,221 @@ struct callback_data_ctrl {
 	int family_index;
 };
 
+struct callback_data_third {
+	char *message;
+	int flag;
+};
+
+int validate_cb_parallel(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *attrs[PARALLEL_GENL_ATTR_MAX + 1];
+	int ret = 0;
+	char *message = NULL;
+
+	ret = genlmsg_parse(nlmsg_hdr(msg), 0, attrs, PARALLEL_GENL_ATTR_MAX,
+			    NULL);
+
+	if (ret < 0) {
+		printf("Failed to parse attributes: %d\n", ret);
+		return NL_STOP;
+	}
+
+	struct callback_data *data = (struct callback_data *)arg;
+
+	switch (gnlh->cmd) {
+	case PARALLEL_GENL_CMD_SEND:
+		if (attrs[PARALLEL_GENL_ATTR_DATA]) {
+			message =
+				nla_get_string(attrs[PARALLEL_GENL_ATTR_DATA]);
+			data->message = strdup(message);
+			if (data->message == NULL) {
+				perror("strdup failed");
+				return NL_SKIP;
+			}
+		} else {
+			printf("Attribute not found.\n");
+			return NL_SKIP;
+		}
+		return NL_OK;
+	case PARALLEL_GENL_CMD_GET_VALUE:
+		if (attrs[PARALLEL_GENL_ATTR_DATA]) {
+			message =
+				nla_get_string(attrs[PARALLEL_GENL_ATTR_DATA]);
+			data->message = strdup(message);
+			if (data->message == NULL) {
+				perror("strdup failed");
+				return NL_SKIP;
+			}
+		}
+		return NL_OK;
+	}
+	return NL_OK;
+}
+
+int validate_cb_parallel_dump(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *attrs[PARALLEL_GENL_ATTR_MAX + 1];
+	int ret = 0;
+	char *name;
+	char *desc;
+
+	ret = genlmsg_parse(nlmsg_hdr(msg), 0, attrs, PARALLEL_GENL_ATTR_MAX,
+			    NULL);
+
+	if (ret < 0) {
+		printf("Failed to parse attributes: %d\n", ret);
+		return NL_STOP;
+	}
+
+	struct callback_data_parallel_dump *data =
+		(struct callback_data_parallel_dump *)arg;
+	switch (gnlh->cmd) {
+	case PARALLEL_GENL_CMD_DUMP_INFO:
+		if (attrs[PARALLEL_GENL_ATTR_NAME]) {
+			name = nla_get_string(attrs[PARALLEL_GENL_ATTR_NAME]);
+			data->name = strdup(name);
+			if (data->name == NULL) {
+				perror("strdup failed");
+				free(data);
+				return NL_SKIP;
+			}
+
+			if (strcmp(data->name, data_check[elems].name))
+				printf("[FAILED]\n");
+		}
+		if (attrs[PARALLEL_GENL_ATTR_DESC]) {
+			desc = nla_get_string(attrs[PARALLEL_GENL_ATTR_DESC]);
+			data->desc = strdup(desc);
+			if (data->desc == NULL) {
+				perror("strdup failed");
+				return NL_SKIP;
+			}
+			if (strcmp(data->desc, data_check[elems].desc))
+				printf("[FAILED]\n");
+		}
+		elems++;
+		return NL_OK;
+	}
+	return NL_OK;
+}
+
+int validate_cb_third(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *attrs[PARALLEL_GENL_ATTR_MAX + 1];
+	int ret = 0;
+	int flag = -1;
+	char *message = NULL;
+
+	ret = genlmsg_parse(nlmsg_hdr(msg), 0, attrs, PARALLEL_GENL_ATTR_MAX,
+			    NULL);
+
+	if (ret < 0) {
+		printf("Failed to parse attributes: %d\n", ret);
+		return NL_STOP;
+	}
+
+	struct callback_data_third *data = (struct callback_data_third *)arg;
+
+	switch (gnlh->cmd) {
+	case THIRD_GENL_CMD_ECHO:
+		if (attrs[THIRD_GENL_ATTR_DATA]) {
+			message = nla_get_string(attrs[THIRD_GENL_ATTR_DATA]);
+			data->message = strdup(message);
+			if (data->message == NULL) {
+				perror("strdup failed");
+				return NL_SKIP;
+			}
+		}
+		if (attrs[THIRD_GENL_ATTR_FLAG]) {
+			flag = nla_get_flag(attrs[THIRD_GENL_ATTR_FLAG]);
+			data->flag = flag;
+		}
+		return NL_OK;
+	}
+	return NL_OK;
+}
+
+int validate_cb(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *attrs[MY_GENL_ATTR_MAX + 1];
+	int ret = 0;
+	int int_value = 30;
+
+	ret = genlmsg_parse(nlmsg_hdr(msg), 0, attrs, MY_GENL_ATTR_MAX, NULL);
+
+	if (ret < 0) {
+		printf("Failed to parse attributes: %d\n", ret);
+		return NL_STOP;
+	}
+
+	struct callback_data *data = (struct callback_data *)arg;
+
+	switch (gnlh->cmd) {
+	case MY_GENL_CMD_GET_VALUE:
+		if (attrs[MY_GENL_ATTR_VALUE]) {
+			if (nla_len(attrs[MY_GENL_ATTR_VALUE]) >= sizeof(int)) {
+				int_value =
+					nla_get_u32(attrs[MY_GENL_ATTR_VALUE]);
+				data->int_value = int_value;
+			} else {
+				fprintf(stderr,
+					"MY_GENL_ATTR_VALUE has incorrect size");
+				return NL_STOP;
+			}
+		}
+		return NL_OK;
+
+	case MY_GENL_CMD_SET_VALUE:
+		if (attrs[MY_GENL_ATTR_VALUE]) {
+			if (nla_len(attrs[MY_GENL_ATTR_VALUE]) >= sizeof(int)) {
+				int_value =
+					nla_get_u32(attrs[MY_GENL_ATTR_VALUE]);
+				data->int_value = int_value;
+			} else {
+				fprintf(stderr,
+					"MY_GENL_ATTR_VALUE has incorrect size");
+				return NL_STOP;
+			}
+		}
+		return NL_OK;
+
+	case MY_GENL_CMD_ECHO:
+		if (attrs[MY_GENL_ATTR_DATA]) {
+			char *message =
+				nla_get_string(attrs[MY_GENL_ATTR_DATA]);
+			data->message = strdup(message);
+			if (data->message == NULL) {
+				perror("strdup failed");
+				return NL_SKIP;
+			}
+		} else {
+			printf("Attribute not found.\n");
+			return NL_SKIP;
+		}
+		return NL_OK;
+
+	case MY_GENL_SMALL_CMD_GET:
+		if (attrs[MY_GENL_ATTR_DATA]) {
+			char *message =
+				nla_get_string(attrs[MY_GENL_ATTR_DATA]);
+			data->message = strdup(message);
+			if (data->message == NULL) {
+				perror("strdup failed");
+				return NL_SKIP;
+			}
+		}
+		return NL_OK;
+	default:
+		printf("Unknown command: %u\n", gnlh->cmd);
+		break;
+	}
+	return NL_OK;
+}
+
 static int elem;
 
 static int id_elem;
@@ -479,6 +718,91 @@ int validate_cb_ctrl(struct nl_msg *msg, void *arg)
 	return NL_OK;
 }
 
+#define BUFFER_SIZE 256
+
+int read_string_from_sysfs(const char *path, char *buffer, size_t buffer_size)
+{
+	int fd = open(path, O_RDONLY);
+
+	if (fd < 0) {
+		fprintf(stderr, "Error opening %s for reading sysfs: %s\n",
+			path, strerror(errno));
+		return -errno;
+	}
+
+	ssize_t len = read(fd, buffer, buffer_size - 1);
+
+	if (len < 0) {
+		fprintf(stderr, "Error reading to %s: %s\n", path,
+			strerror(errno));
+		close(fd);
+		return -errno;
+	}
+
+	buffer[len] = '\0';
+	close(fd);
+	return 0;
+}
+
+int read_int_from_sysfs(const char *path, int *value)
+{
+	char buffer[BUFFER_SIZE];
+	int ret;
+
+	ret = read_string_from_sysfs(path, buffer, sizeof(buffer));
+
+	if (ret != 0)
+		return ret;
+
+	char *endptr;
+	long val = strtol(buffer, &endptr, 10);
+
+	if (endptr == buffer) {
+		fprintf(stderr, "Conversion error: %s\n", strerror(errno));
+		return -errno;
+	}
+
+	*value = (int)val;
+	return 0;
+}
+
+int write_string_to_sysfs(const char *path, const char *value)
+{
+	int fd = open(path, O_WRONLY);
+
+	if (fd < 0) {
+		fprintf(stderr, "Error opening %s for writing sysfs: %s\n",
+			path, strerror(errno));
+		return -errno;
+	}
+
+	ssize_t len = write(fd, value, strlen(value));
+
+	if (len < 0) {
+		fprintf(stderr, "Error writing to %s: %s\n", path,
+			strerror(errno));
+		close(fd);
+		return -errno;
+	}
+
+	close(fd);
+	return 0;
+}
+
+int write_int_to_sysfs(const char *path, int value)
+{
+	char buffer[32];
+
+	int ret = snprintf(buffer, sizeof(buffer), "%d", value);
+
+	if (ret < 0 || ret >= sizeof(buffer)) {
+		fprintf(stderr, "Conversion error: %s\n", strerror(errno));
+		return -errno;
+	}
+
+	return write_string_to_sysfs(path, buffer);
+}
+
 struct nl_sock *socket_alloc_and_conn(void)
 {
 	struct nl_sock *socket;
@@ -1179,6 +1503,3563 @@ TEST(resolve_large_family_id)
 	EXPECT_TRUE(no_family_id > 0);
 }
 
+/**
+ * TEST(genl_small_cmd_get_value) - Tests small command in Generic Netlink family
+ *
+ * Validates:
+ * 1. Family resolution and socket setup
+ * 2. Message formatting and transmission
+ * 3. Response validation
+ * 4. Sysfs integration check
+ *
+ * Test Flow:
+ * 1. Resolves target Generic Netlink family
+ * 2. Prepares request with MY_GENL_SMALL_CMD_GET
+ * 3. Validates response through callback
+ * 4. Compares result with sysfs reference data
+ * 5. Cleans up test artifacts
+ *
+ * Special Handling:
+ * - Requires root for sysfs operations
+ * - Uses custom validation callback
+ * - Resets sysfs state after test
+ */
+
+TEST(genl_small_cmd_get_value)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err = 0;
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: getting value using small cmd...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr, "Failed to resolve family id: %d\n", family_id);
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_SMALL_CMD_GET, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	char *str = malloc(BUFFER_SIZE);
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = read_string_from_sysfs(PATH_GENL_TEST_MES, str, BUFFER_SIZE);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_STREQ(str, cb_data.message);
+
+	err = write_string_to_sysfs(PATH_GENL_TEST_MES, "default");
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	free(str);
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(genl_parallel) - Tests message exchange with PARALLEL_GENL Generic Netlink family
+ *
+ * Validates end-to-end communication with PARALLEL_GENL family:
+ * 1. Establishes connection to PARALLEL_GENL family
+ * 2. Sends PARALLEL_GENL_CMD_SEND command
+ * 3. Checks results with sysfs reference data
+ *
+ * Test Flow:
+ * 1. Resolves PARALLEL_GENL family ID
+ * 2. Prepares and sends command message
+ * 3. Receives and validates response
+ * 4. Compares with sysfs reference data
+ * 5. Resets test environment
+ *
+ * Requirements:
+ * - Root privileges (for sysfs access)
+ * - Loaded parallel_genl kernel module
+ * - Properly configured sysfs interface
+ *
+ * Error Handling:
+ * - Validates all intermediate steps
+ * - Cleans up resources on failure
+ * - Resets sysfs state after test
+ */
+
+TEST(genl_parallel)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err = 0;
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: sending message to parallel_genl...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr, "Failed to resolve family id: %d\n", family_id);
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, PARALLEL_GENL_CMD_SEND, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	char *str = malloc(BUFFER_SIZE);
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel,
+			&cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = read_string_from_sysfs(PATH_PARALLEL_GENL_MES, str, BUFFER_SIZE);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_STREQ(str, cb_data.message);
+
+	err = write_string_to_sysfs(PATH_PARALLEL_GENL_MES, "default");
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	free(str);
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(genl_parallel_dump) - Tests parallel dump operation in Generic Netlink
+ *
+ * Validates the parallel dump functionality of the PARALLEL_GENL family by:
+ * 1. Sending a dump request (NLM_F_DUMP flag) with PARALLEL_GENL_CMD_DUMP_INFO command
+ * 2. Processing multiple response messages through callback validation
+ * 3. Verifying correct handling of parallel data streams
+ *
+ * Key Features Tested:
+ * - Multi-message dump handling capability
+ * - Parallel data stream processing
+ * - Callback validation of dump contents
+ * - Resource management during extended operations
+ *
+ * Test Flow:
+ * 1. Resolve PARALLEL_GENL family ID
+ * 2. Prepare dump request message:
+ *    - Sets NLM_F_DUMP flag
+ *    - Uses PARALLEL_GENL_CMD_DUMP_INFO command
+ * 3. Configure callback (validate_cb_parallel_dump) for message processing
+ * 4. Execute send/receive operations
+ * 5. Validate results through callback
+ *
+ * Error Handling:
+ * - Verifies all intermediate steps
+ * - Proper resource cleanup on failure
+ * - Callback determines final test status
+ */
+
+TEST(genl_parallel_dump)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err = 0;
+
+	struct callback_data_parallel_dump cb_data;
+
+	printf("Running Test: doing parallel dump with genl_parallel_dump...\n");
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr, "Failed to resolve family id: %d\n", family_id);
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_DUMP, PARALLEL_GENL_CMD_DUMP_INFO, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	char *str = malloc(BUFFER_SIZE);
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+			validate_cb_parallel_dump, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	// callback function determines whether the test is successful
+
+	EXPECT_EQ(elems, DATA_SIZE);
+	elems = 0;
+
+error:
+	free(str);
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+static struct nl_msg *genl_generate_messages(int family_id, int nonblock)
+{
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	char *data;
+	int err;
+
+	msg = nlmsg_alloc();
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		return NULL;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, PARALLEL_GENL_CMD_SEND, 0);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	if (nonblock) {
+		if (nla_put_flag(msg, PARALLEL_GENL_ATTR_FLAG_NONBLOCK) < 0) {
+			fprintf(stderr,
+				"Failed to add PARALLEL_GENL_ATTR_FLAG_NONBLOCK flag attribute: %s\n",
+				strerror(errno));
+			nlmsg_free(msg);
+			return NULL;
+		}
+	} else {
+		if (nla_put_flag(msg, PARALLEL_GENL_ATTR_FLAG_BLOCK) < 0) {
+			fprintf(stderr,
+				"Failed to add PARALLEL_GENL_ATTR_FLAG_BLOCK flag attribute: %s\n",
+				strerror(errno));
+			nlmsg_free(msg);
+			return NULL;
+		}
+	}
+
+	int data_size = 4068;
+
+	data = malloc(data_size);
+	if (!data) {
+		fprintf(stderr, "Failed to allocate data buffer\n");
+		nlmsg_free(msg);
+		return NULL;
+	}
+	memset(data, 1, data_size);
+
+	err = nla_put(msg, PARALLEL_GENL_ATTR_BINARY, data_size, data);
+	if (err < 0) {
+		fprintf(stderr,
+			"Failed to add PARALLEL_GENL_ATTR_BINARY attribute: %s\n",
+			strerror(errno));
+		free(data);
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+/**
+ * TEST(incorrect_genl_parallel_with_flag_nonblock_sock) - Tests buffer overflow in
+ * non-blocking Generic Netlink socket
+ *
+ * Validates kernel behavior under buffer overflow conditions by:
+ * 1. Creating a non-blocking socket with reduced buffer size (5000 bytes)
+ * 2. Rapidly sending multiple messages (20x) without waiting for responses
+ * 3. Verifying proper error handling when buffer capacity is exceeded
+ *
+ * Expected Behavior:
+ * - First receive attempt should fail with NLE_NOMEM (ENOBUFS)
+ * - Subsequent receives should return NLE_AGAIN (EAGAIN)
+ * - Number of successfully received messages should be less than sent (kernel drops packets)
+ *
+ * Test Methodology:
+ * 1. Configure non-blocking socket with small buffer
+ * 2. Flood the socket with back-to-back messages
+ * 3. Verify error sequence:
+ *    a) Initial ENOBUFS when buffer is full
+ *    b) Subsequent EAGAIN for empty buffer
+ * 4. Confirm packet loss (recv_count < send_count)
+ *
+ * Technical Notes:
+ * - Requires root for socket configuration
+ * - Uses custom message generator (genl_generate_messages)
+ * - Tests kernel's congestion control mechanisms
+ * - Validates Netlink's non-blocking error handling
+ */
+
+TEST(incorrect_genl_parallel_with_flag_nonblock_sock)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err = 0;
+	int send_c;
+	int recv_c;
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: trying to overflow buffer of nonblock socket...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr, "Failed to resolve family id: %d\n", family_id);
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	err = nl_socket_set_buffer_size(sock, 5000, 5000);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to change socket buffer size: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_socket_set_nonblocking(sock);
+	EXPECT_EQ(err, 0);
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel,
+			&cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	send_c = 20;
+	recv_c = 0;
+	for (int i = 0; i < send_c; i++) {
+		msg = genl_generate_messages(family_id, 1);
+		EXPECT_NE(NULL, msg);
+		if (!msg) {
+			fprintf(stderr, "Failed to create message\n");
+			goto error;
+		}
+		err = nl_send_auto(sock, msg);
+		EXPECT_GE(err, 0);
+		if (err < 0) {
+			fprintf(stderr, "Failed to send message: %s\n",
+				nl_geterror(err));
+			goto error;
+		}
+		nlmsg_free(msg);
+	}
+
+	// the buffer is full
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, -NLE_NOMEM);
+	EXPECT_EQ(errno, ENOBUFS);
+
+	for (int i = 1; i < send_c; i++) {
+		err = nl_recvmsgs(sock, cb);
+		if (err < 0) {
+			EXPECT_EQ(err, -NLE_AGAIN);
+			EXPECT_EQ(errno, EAGAIN);
+		}
+		if (err == 0)
+			recv_c++;
+	}
+	EXPECT_LT(recv_c, send_c);
+
+error:
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(incorrect_genl_parallel_with_flag_block_sock) - Tests buffer overflow behavior in
+ * blocking Generic Netlink socket
+ *
+ * Validates kernel packet handling under buffer overflow conditions with blocking sockets:
+ * 1. Configures socket with small buffer (1000 bytes) and 1-second timeout
+ * 2. Sends burst of messages (8x) to trigger overflow
+ * 3. Verifies correct error sequence and packet loss
+ *
+ * Expected Behavior:
+ * - Initial receive returns NLE_NOMEM (ENOBUFS) when buffer is full
+ * - Subsequent receives get partial messages (recv_count < send_count)
+ * - Final receive returns NLE_AGAIN (EAGAIN) when queue is empty
+ *
+ * Test Methodology:
+ * 1. Reduce socket buffer size to force quick overflow
+ * 2. Set conservative timeout (1s) for blocked receives
+ * 3. Send message burst without waiting for responses
+ * 4. Verify:
+ *    a) Initial ENOBUFS error
+ *    b) Partial message delivery
+ *    c) Terminal EAGAIN condition
+ *
+ * Technical Notes:
+ * - Demonstrates kernel's congestion control with blocking sockets
+ * - Shows Netlink's reliability limits under overload
+ * - Uses SO_RCVTIMEO to prevent indefinite blocking
+ * - Requires root for socket configuration
+ */
+
+TEST(incorrect_genl_parallel_with_flag_block_sock)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err = 0;
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	struct timeval tv = { 1, 0 };
+
+	int send_c;
+	int recv_c;
+
+	printf("Running Test: trying to overflow buffer of block socket...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr, "Failed to resolve family id: %d\n", family_id);
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	err = nl_socket_set_buffer_size(sock, 1000, 1000);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to change socket buffer size: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = setsockopt(nl_socket_get_fd(sock), SOL_SOCKET, SO_RCVTIMEO, &tv,
+			 sizeof(tv));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to set timeout for block socket\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel,
+			&cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	send_c = 8;
+	for (int i = 0; i < send_c; i++) {
+		msg = genl_generate_messages(family_id, 0);
+		EXPECT_NE(NULL, msg);
+		if (!msg) {
+			fprintf(stderr, "Failed to create message\n");
+			goto error;
+		}
+		err = nl_send_auto(sock, msg);
+		EXPECT_GE(err, 0);
+		if (err < 0) {
+			fprintf(stderr, "Failed to send message: %s\n",
+				nl_geterror(err));
+			goto error;
+		}
+		nlmsg_free(msg);
+	}
+
+	recv_c = 0;
+
+	// the buffer is full
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, -NLE_NOMEM);
+	EXPECT_EQ(errno, ENOBUFS);
+
+	for (int i = 1; i < send_c; i++) {
+		err = nl_recvmsgs(sock, cb);
+		if (err == 0)
+			recv_c++;
+
+		if (err < 0) {
+			EXPECT_EQ(err, -NLE_AGAIN);
+			EXPECT_EQ(errno, EAGAIN);
+		}
+	}
+
+	EXPECT_TRUE(err == -NLE_AGAIN && errno == EAGAIN);
+	EXPECT_LT(recv_c, send_c);
+
+error:
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(genl_test_get_value) - Tests basic communication with TEST_GENL family
+ *
+ * Validates end-to-end message exchange including:
+ * 1. Family and multicast group resolution
+ * 2. Message formatting and transmission
+ * 3. Response validation through callback
+ * 4. Sysfs integration verification
+ *
+ * Test Flow:
+ * 1. Establish connection to TEST_GENL
+ * 2. Resolve multicast group MY_MCGRP_GENL
+ * 3. Prepare GET_VALUE request message:
+ *    - Sets MY_GENL_CMD_GET_VALUE command
+ *    - Includes path attribute (PATH_GENL_TEST_NUM)
+ * 4. Send request and validate response
+ * 5. Compare result with sysfs reference data
+ * 6. Reset test environment
+ *
+ * Special Handling:
+ * - Requires root privileges (sysfs access)
+ * - Uses custom validation callback
+ * - Verifies both Netlink and sysfs interfaces
+ * - Automatic cleanup of test artifacts
+ */
+
+TEST(genl_test_get_value)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err = 0;
+	int int_value = -10;
+	struct genlmsghdr *user_hdr;
+	struct callback_data cb_data;
+
+	cb_data.int_value = 20;
+	cb_data.message = NULL;
+
+	printf("Running Test: getting value from sysfs via Netlink message...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock)
+		return;
+
+	family_id = genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		nl_socket_free(nl_sock);
+		err = family_id;
+		return;
+	}
+
+	mcgrp_id = genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME,
+					 MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		nl_socket_free(nl_sock);
+		err = mcgrp_id;
+		return;
+	}
+
+	err = nl_socket_add_membership(nl_sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0)
+		goto error;
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		nlmsg_free(msg);
+		nl_cb_put(cb);
+		return;
+	}
+
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		nlmsg_free(msg);
+		nl_cb_put(cb);
+		return;
+	}
+
+	err = read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_EQ(int_value, cb_data.int_value);
+
+	err = write_int_to_sysfs(PATH_GENL_TEST_NUM, -20);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(genl_test_echo) - Tests multicast echo functionality in TEST_GENL family
+ *
+ * Validates the echo request/reply mechanism through multicast groups by:
+ * 1. Configuring socket with CAP_ACK capability
+ * 2. Sending echo request (NLM_F_ECHO flag) with MY_GENL_CMD_ECHO command
+ * 3. Receiving and validating multicast response
+ * 4. Verifying message content against sysfs reference
+ *
+ * Protocol Details:
+ * - Uses NETLINK_CAP_ACK for reliable multicast delivery
+ * - Leverages multicast group (MY_MCGRP_GENL) for replies
+ * - Validates both Netlink and sysfs message content
+ *
+ * Test Flow:
+ * 1. Establish Netlink connection
+ * 2. Enable CAP_ACK socket option
+ * 3. Resolve family and multicast group IDs
+ * 4. Join multicast group
+ * 5. Prepare and send echo request
+ * 6. Receive and validate multicast reply
+ * 7. Compare with sysfs reference data
+ * 8. Reset test environment
+ *
+ * Requirements:
+ * - Root privileges (for sysfs and socket configuration)
+ * - Properly configured multicast group in kernel
+ * - Validated echo handler in kernel module
+ */
+
+TEST(genl_test_echo)
+{
+	struct nl_sock *sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err = 0;
+	int sock_fd;
+	int cap_ack = 1;
+	int optval;
+	socklen_t optlen = sizeof(optval);
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: getting message that was sent to mcast groups...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock)
+		return;
+
+	sock_fd = nl_socket_get_fd(sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		nl_socket_free(sock);
+		err = sock_fd;
+		return;
+	}
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_CAP_ACK, &cap_ack,
+			 sizeof(cap_ack));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_CAP_ACK, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(sock);
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	mcgrp_id =
+		genl_ctrl_resolve_grp(sock, MY_GENL_FAMILY_NAME, MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		err = mcgrp_id;
+		fprintf(stderr, "Failed to resolve multicast group: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_socket_add_membership(sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to add membership: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_ECHO, MY_GENL_CMD_ECHO, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	char *str = malloc(BUFFER_SIZE);
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0)
+		goto error;
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		free(str);
+		nlmsg_free(msg);
+		nl_cb_put(cb);
+		return;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		free(str);
+		nlmsg_free(msg);
+		nl_cb_put(cb);
+		return;
+	}
+
+	err = read_string_from_sysfs(PATH_GENL_TEST_MES, str, BUFFER_SIZE);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_STREQ(str, cb_data.message);
+
+	err = write_string_to_sysfs(PATH_GENL_TEST_MES, "default");
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	free(str);
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(genl_test_set_value) - Tests value setting functionality in TEST_GENL family
+ *
+ * Validates the complete SET_VALUE operation workflow:
+ * 1. Configures socket with STRICT_CHK option for robust message validation
+ * 2. Sends properly formatted SET_VALUE command with:
+ *    - Target path (PATH_GENL_TEST_NUM)
+ *    - Integer value to set (1)
+ * 3. Verifies correct processing through:
+ *    - Netlink response validation
+ *    - Sysfs value verification
+ *
+ * Key Features Tested:
+ * - Strict checking option (NETLINK_GET_STRICT_CHK)
+ * - Multicast group communication
+ * - Attribute packing and unpacking
+ * - End-to-end sysfs integration
+ *
+ * Test Flow:
+ * 1. Initialize Netlink connection with strict checking
+ * 2. Resolve family and multicast group IDs
+ * 3. Prepare SET_VALUE request with path and value attributes
+ * 4. Send request and validate response
+ * 5. Verify sysfs value was updated correctly
+ * 6. Reset test environment
+ *
+ * Special Handling:
+ * - Requires root privileges (sysfs modification)
+ * - Uses custom validation callback
+ * - Automatic cleanup of test artifacts
+ */
+
+TEST(genl_test_set_value)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err = 0;
+	int int_value;
+	int sock_fd;
+	int up = 1;
+	struct genlmsghdr *user_hdr;
+	int optval;
+
+	socklen_t optlen = sizeof(optval);
+
+	struct callback_data cb_data;
+
+	cb_data.int_value = 74;
+	cb_data.message = NULL;
+
+	printf("Running Test: sending correct value for sysfs to genl_test...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock)
+		return;
+
+	sock_fd = nl_socket_get_fd(nl_sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		err = sock_fd;
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &up,
+			 sizeof(up));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		nl_socket_free(nl_sock);
+		err = family_id;
+		return;
+	}
+
+	mcgrp_id = genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME,
+					 MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		nl_socket_free(nl_sock);
+		err = mcgrp_id;
+		return;
+	}
+
+	err = nl_socket_add_membership(nl_sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_CMD_SET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	if (nla_put_u32(msg, MY_GENL_ATTR_VALUE, 1) < 0) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		nlmsg_free(msg);
+		nl_cb_put(cb);
+		return;
+	}
+
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_TRUE(err == 0 || err == -NLE_PERM);
+	if (err < 0) {
+		if (geteuid() != 0)
+			EXPECT_EQ(err, -NLE_PERM);
+
+		EXPECT_EQ(err, 0);
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		nlmsg_free(msg);
+		nl_cb_put(cb);
+		return;
+	}
+
+	err = read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_EQ(int_value, cb_data.int_value);
+
+	err = write_int_to_sysfs(PATH_GENL_TEST_NUM, -20);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(incorrect_genl_test_set_value) - Tests error handling in TEST_GENL family
+ *
+ * Validates proper error reporting for invalid SET_VALUE operations by:
+ * 1. Enabling extended ACK (NETLINK_EXT_ACK) for detailed error messages
+ * 2. Configuring broadcast error reporting (NETLINK_BROADCAST_ERROR)
+ * 3. Sending intentionally incorrect value (34) to trigger error
+ * 4. Verifying kernel returns appropriate error codes:
+ *    - NLE_INVAL for root (invalid value)
+ *    - NLE_PERM for non-root (permission denied)
+ *
+ * Key Features Tested:
+ * - Extended ACK error reporting mechanism
+ * - Broadcast error propagation
+ * - Kernel validation of input values
+ * - Permission checking
+ *
+ * Test Flow:
+ * 1. Configure socket with EXT_ACK and BROADCAST_ERROR options
+ * 2. Resolve family and multicast group IDs
+ * 3. Prepare SET_VALUE request with invalid value (34)
+ * 4. Send request and verify error response
+ * 5. Validate error code matches expectations
+ *
+ * Special Handling:
+ * - Different expected errors for root/non-root
+ * - Uses kernel's extended ACK reporting
+ * - Tests both value validation and permission checks
+ */
+
+TEST(incorrect_genl_test_set_value)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err;
+	int sock_fd;
+	int ext_ack = 1;
+	int broadcast_error = 1;
+	struct genlmsghdr *user_hdr;
+
+	int optval;
+
+	socklen_t optlen = sizeof(optval);
+
+	struct callback_data cb_data;
+
+	cb_data.int_value = 74;
+	cb_data.message = NULL;
+
+	printf("Running Test: sending incorrect value for sysfs to genl_test...\n");
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock) {
+		printf("socket for my_genl is NULL\n");
+		return;
+	}
+
+	sock_fd = nl_socket_get_fd(nl_sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		fprintf(stderr, "Failed to get socket file descriptor\n");
+		err = sock_fd;
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &ext_ack,
+			 sizeof(ext_ack));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	EXPECT_EQ(optval, 1);
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_BROADCAST_ERROR,
+			 &broadcast_error, sizeof(broadcast_error));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_BROADCAST_ERROR, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	EXPECT_EQ(optval, 1);
+
+	family_id = genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr, "Failed to resolve family id: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	mcgrp_id = genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME,
+					 MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		err = mcgrp_id;
+		fprintf(stderr, "Failed to resolve multicast group: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_socket_add_membership(nl_sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to add membership: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_CMD_SET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) {
+		fprintf(stderr,
+			"Failed to add MY_GENL_ATTR_PATH attribute: %s\n",
+			strerror(errno));
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	if (nla_put_u32(msg, MY_GENL_ATTR_VALUE, 34) < 0) {
+		fprintf(stderr,
+			"Failed to add MY_GENL_ATTR_VALUE attribute: %s\n",
+			strerror(errno));
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		printf("Error setting callback\n");
+		goto error;
+	}
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	// nl_recvmsgs gets error code from error ACK from kernel
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_TRUE(err == -NLE_PERM || err == -NLE_INVAL);
+	if (err < 0) {
+		if (geteuid() != 0)
+			EXPECT_EQ(err, -NLE_PERM);
+
+		if (geteuid() == 0)
+			EXPECT_EQ(err, -NLE_INVAL);
+	}
+	EXPECT_LT(err, 0);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(incorrect_family) - Tests handling of non-existent Generic Netlink family
+ *
+ * Validates proper error reporting when attempting to resolve:
+ * 1. A deliberately non-existent Generic Netlink family
+ * 2. Expected error code (NLE_OBJ_NOTFOUND)
+ *
+ * Key Features Tested:
+ * - Controller behavior for unknown family names
+ * - Correct error code propagation
+ * - Graceful handling of resolution failures
+ *
+ * Test Methodology:
+ * 1. Creates standard Netlink socket
+ * 2. Attempts to resolve "SOME_RANDOM_NAME" family
+ * 3. Verifies:
+ *    - Return value is negative (error)
+ *    - Specific error code is NLE_OBJ_NOTFOUND
+ *    - Clean resource deallocation
+ *
+ * Negative Testing:
+ * - Demonstrates proper error handling for invalid inputs
+ * - Verifies kernel API contract for unknown families
+ */
+
+TEST(incorrect_family)
+{
+	struct nl_sock *sock;
+	int family_id;
+
+	printf("Running Test: trying to find id of incorrect Netlink family...\n");
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, "SOME_RANDOM_NAME");
+	EXPECT_EQ(family_id, -NLE_OBJ_NOTFOUND);
+
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(incorrect_family_id) - Tests error handling for invalid family ID
+ *
+ * Validates proper error reporting when sending messages to:
+ * 1. A deliberately incorrect family ID (valid ID + 1)
+ * 2. With otherwise valid command (MY_GENL_SMALL_CMD_GET)
+ *
+ * Expected Behavior:
+ * - Kernel should return NLE_OPNOTSUPP ("Operation not supported")
+ * - Demonstrates proper error propagation through Netlink stack
+ *
+ * Test Methodology:
+ * 1. Resolves valid family ID for reference
+ * 2. Creates message with intentionally invalid family ID (+1)
+ * 3. Verifies:
+ *    - Message transmission succeeds
+ *    - Kernel responds with NLE_OPNOTSUPP
+ *    - Resources are properly cleaned up
+ *
+ * Negative Testing:
+ * - Confirms kernel validates family IDs
+ * - Tests error handling for invalid destinations
+ * - Verifies API contract for unsupported operations
+ */
+
+TEST(incorrect_family_id)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err;
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: trying to send a message to incorrect id of Netlink family (== nonexistent cmd)...\n");
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr, "Failed to resolve family id: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	// put incorrect id for Netlink message
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id + 1, 0,
+			       NLM_F_REQUEST, MY_GENL_SMALL_CMD_GET, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, -NLE_OPNOTSUPP);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(incorrect_cmd) - Tests error handling for invalid Generic Netlink commands
+ *
+ * Validates proper error reporting when:
+ * 1. Sending a message with deliberately invalid command (SOME_RANDOM_CMD)
+ * 2. Using otherwise correct family ID and message format
+ *
+ * Expected Behavior:
+ * - Kernel should return NLE_OPNOTSUPP ("Operation not supported")
+ * - Demonstrates command validation in Generic Netlink subsystem
+ *
+ * Test Methodology:
+ * 1. Resolves valid family ID
+ * 2. Creates message with invalid command number
+ * 3. Verifies:
+ *    - Message transmission succeeds (invalid command is syntactically valid)
+ *    - Kernel responds with NLE_OPNOTSUPP
+ *    - Resources are properly cleaned up
+ *
+ * Negative Testing:
+ * - Confirms kernel validates command numbers
+ * - Tests error handling for unsupported operations
+ * - Verifies API contract for invalid commands
+ */
+
+TEST(incorrect_cmd)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err;
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: trying to send incorrect == non-existent cmd...\n");
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr, "Failed to resolve family id: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, SOME_RANDOM_CMD, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, -NLE_OPNOTSUPP);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(incorrect_ctrl_family_name) - Tests error handling for invalid family names
+ * in controller requests
+ *
+ * Validates that the Generic Netlink controller:
+ * 1. Properly rejects requests with non-existent family names
+ * 2. Returns appropriate error code (NLE_INVAL)
+ * 3. Maintains system stability when receiving invalid parameters
+ *
+ * Test Methodology:
+ * 1. Creates valid connection to genl_ctrl
+ * 2. Prepares GETFAMILY request with invalid family name
+ * 3. Verifies:
+ *    - Controller rejects request with NLE_INVAL
+ *    - Error is properly propagated to userspace
+ *    - Resources are correctly cleaned up
+ *
+ * Expected Behavior:
+ * - Kernel should return NLE_INVAL ("Invalid input data or parameter")
+ * - Controller should maintain stable operation
+ * - No memory leaks or resource issues
+ *
+ * Negative Testing:
+ * - Confirms input validation in Generic Netlink controller
+ * - Tests error handling for non-existent entities
+ * - Verifies API contract for invalid parameters
+ */
+
+TEST(incorrect_ctrl_family_name)
+{
+	struct nl_sock *ctrl_sock;
+	int genl_ctrl_family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb_ctrl;
+	int err;
+	struct callback_data_ctrl cb_ctrl_data;
+
+	cb_ctrl_data.family_id = -30;
+	cb_ctrl_data.family_name = NULL;
+	cb_ctrl_data.op = -100;
+
+	printf("Running Test: sending invalid family name to genl_ctrl...\n");
+
+	ctrl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, ctrl_sock);
+	if (!ctrl_sock) {
+		fprintf(stderr, "socket for genl_ctrl is NULL\n");
+		return;
+	}
+
+	genl_ctrl_family_id = genl_ctrl_resolve(ctrl_sock, GENL_CTRL);
+	EXPECT_GT(genl_ctrl_family_id, 0);
+	if (genl_ctrl_family_id < 0) {
+		err = genl_ctrl_family_id;
+		fprintf(stderr,
+			"Failed to resolve family id for genl_ctrl: %s\n",
+			nl_geterror(err));
+		nl_socket_free(ctrl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(ctrl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
+			       genl_ctrl_family_id, 0, NLM_F_REQUEST,
+			       CTRL_CMD_GETFAMILY, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(ctrl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, "SOME_RANDOM_NAME") <
+	    0) {
+		fprintf(stderr,
+			"Failed to add incorrect CTRL_ATTR_FAMILY_NAME attribute: %s\n",
+			strerror(errno));
+		nlmsg_free(msg);
+		nl_socket_free(ctrl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb_ctrl = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb_ctrl);
+	if (!cb_ctrl) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(ctrl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb_ctrl, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_ctrl,
+			&cb_ctrl_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(ctrl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(ctrl_sock, cb_ctrl);
+	EXPECT_EQ(err, -NLE_INVAL);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb_ctrl);
+	nl_socket_free(ctrl_sock);
+}
+
+/**
+ * TEST(incorrect_genl_parallel_with_flag_nonblock_sock_enobufs) - Tests
+ * NETLINK_NO_ENOBUFS socket option behavior
+ *
+ * Validates the interaction of buffer overflow handling with NETLINK_NO_ENOBUFS by:
+ * 1. Configuring socket with NETLINK_NO_ENOBUFS option
+ * 2. Artificially creating buffer overflow conditions
+ * 3. Verifying the absence of ENOBUFS errors
+ * 4. Confirming packet loss occurs during overflow
+ *
+ * Key Features Tested:
+ * - NETLINK_NO_ENOBUFS socket option functionality
+ * - Non-blocking socket behavior under congestion
+ * - Kernel packet dropping policy
+ * - Error code propagation
+ *
+ * Test Methodology:
+ * 1. Configure socket with:
+ *    - Small buffer size (2000 bytes)
+ *    - Non-blocking mode
+ *    - NETLINK_NO_ENOBUFS option
+ * 2. Flood the socket with back-to-back messages (15x)
+ * 3. Verify:
+ *    - No ENOBUFS errors occur
+ *    - Only EAGAIN is reported when buffer is empty
+ *    - Packet loss occurs (recv_count < send_count)
+ *
+ * Expected Behavior:
+ * - Kernel should suppress ENOBUFS errors when NETLINK_NO_ENOBUFS is set
+ * - Messages should be silently dropped when buffer is full
+ * - Application should only see EAGAIN for empty buffer
+ */
+
+TEST(incorrect_genl_parallel_with_flag_nonblock_sock_enobufs)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err = 0;
+	int send_c;
+	int recv_c;
+
+	int no_enobufs_val = 1;
+	int sock_fd;
+
+	int optval;
+
+	socklen_t optlen = sizeof(optval);
+
+	struct callback_data cb_data;
+
+	cb_data.int_value = -30;
+	cb_data.message = NULL;
+
+	printf("Running Test: trying to overflow buffer of nonblock socket with NETLINK_NO_ENOBUFS socket option...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	sock_fd = nl_socket_get_fd(sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		err = sock_fd;
+		fprintf(stderr, "Failed to get socket file descriptor: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS,
+			 &no_enobufs_val, sizeof(no_enobufs_val));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to set NETLINK_NO_ENOBUFS: %s\n",
+			strerror(errno));
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to get NETLINK_NO_ENOBUFS: %s\n",
+			strerror(errno));
+		nl_socket_free(sock);
+		return;
+	}
+
+	EXPECT_EQ(optval, 1);
+
+	family_id = genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr, "Failed to resolve family id: %d\n", family_id);
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_socket_set_buffer_size(sock, 2000, 2000);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to change socket buffer size: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_socket_set_nonblocking(sock);
+	EXPECT_EQ(err, 0);
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel,
+			&cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	send_c = 15;
+	recv_c = 0;
+	for (int i = 0; i < send_c; i++) {
+		msg = genl_generate_messages(family_id, 1);
+		EXPECT_NE(NULL, msg);
+		if (!msg) {
+			fprintf(stderr, "Failed to create message\n");
+			goto error;
+		}
+		err = nl_send_auto(sock, msg);
+		EXPECT_GE(err, 0);
+		if (err < 0) {
+			fprintf(stderr, "Failed to send message: %s\n",
+				nl_geterror(err));
+			goto error;
+		}
+		nlmsg_free(msg);
+	}
+
+	for (int i = 0; i < send_c; i++) {
+		err = nl_recvmsgs(sock, cb);
+		if (err < 0) {
+			EXPECT_EQ(err, -NLE_AGAIN);
+			EXPECT_EQ(errno, EAGAIN);
+		}
+		if (err == 0)
+			recv_c++;
+
+		EXPECT_NE(errno, ENOBUFS);
+	}
+	EXPECT_LT(recv_c, send_c);
+
+error:
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(genl_test_get_value_sock_option) - Tests NETLINK_NO_ENOBUFS socket option functionality
+ *
+ * Validates the complete workflow of setting and using the NETLINK_NO_ENOBUFS socket option:
+ * 1. Sets and verifies NETLINK_NO_ENOBUFS socket option
+ * 2. Performs standard GET_VALUE operation
+ * 3. Verifies successful message exchange despite option being set
+ *
+ * Key Features Tested:
+ * - NETLINK_NO_ENOBUFS option setting and verification
+ * - Normal operation with the option enabled
+ * - Integration with existing GET_VALUE functionality
+ * - Sysfs value verification
+ *
+ * Test Flow:
+ * 1. Configure socket with NETLINK_NO_ENOBUFS option
+ * 2. Verify option was correctly set
+ * 3. Resolve family and multicast group IDs
+ * 4. Prepare and send GET_VALUE request
+ * 5. Validate response and sysfs value
+ * 6. Clean up test environment
+ *
+ * Special Considerations:
+ * - Requires root privileges for sysfs access
+ * - Tests both socket option functionality and normal operation
+ * - Maintains backward compatibility with existing behavior
+ */
+
+TEST(genl_test_get_value_sock_option)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err;
+	int int_value;
+	int no_enobufs_val = 1;
+	int sock_fd;
+
+	int optval;
+
+	socklen_t optlen = sizeof(optval);
+
+	struct genlmsghdr *user_hdr;
+
+	struct callback_data cb_data;
+
+	printf("Running Test: sending a message with NETLINK_NO_ENOBUFS socket option...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock) {
+		printf("socket for my_genl is NULL\n");
+		return;
+	}
+
+	sock_fd = nl_socket_get_fd(nl_sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		err = sock_fd;
+		fprintf(stderr, "Failed to get socket file descriptor: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS,
+			 &no_enobufs_val, sizeof(no_enobufs_val));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to set NETLINK_NO_ENOBUFS: %s\n",
+			strerror(errno));
+		err = -errno;
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to get NETLINK_NO_ENOBUFS: %s\n",
+			strerror(errno));
+		err = -errno;
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	EXPECT_EQ(optval, 1);
+
+	family_id = genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr, "Failed to resolve family id: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	mcgrp_id = genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME,
+					 MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		err = mcgrp_id;
+		fprintf(stderr, "Failed to resolve multicast group: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_socket_add_membership(nl_sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to add membership: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) {
+		fprintf(stderr,
+			"Failed to add MY_GENL_ATTR_PATH attribute: %s\n",
+			strerror(errno));
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_EQ(int_value, cb_data.int_value);
+
+	err = write_int_to_sysfs(PATH_GENL_TEST_NUM, -20);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(incorrect_genl_test_ext_ack) - NETLINK_EXT_ACK error handling verification
+ *
+ * Validates extended error acknowledgment mechanism by:
+ * 1. Testing successful setting of NETLINK_EXT_ACK socket option
+ * 2. Sending deliberately malformed Generic Netlink message:
+ *    - Contains invalid path attribute (MY_GENL_ATTR_PATH="some/random/path")
+ * 3. Verifying kernel returns expected error (EINVAL/NLE_INVAL)
+ * 4. Checking proper delivery of extended error information via EXT_ACK
+ *
+ * Expected behavior:
+ * - NETLINK_EXT_ACK option should be successfully set (optval == 1)
+ * - Kernel should reject malformed message with -NLE_INVAL error
+ *
+ * Implementation notes:
+ * - Uses synthetic invalid path to guarantee error generation
+ * - Tests complete workflow: option setup -> message send -> error handling
+ * - Covers both basic error code and extended error information
+ */
+
+TEST(incorrect_genl_test_ext_ack)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err;
+	int up;
+	int sock_fd;
+
+	int optval;
+
+	socklen_t optlen = sizeof(optval);
+
+	struct genlmsghdr *user_hdr;
+	struct callback_data cb_data;
+
+	printf("Running Test: sending a message with NETLINK_EXT_ACK socket option and incorrect path value...\n");
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock) {
+		fprintf(stderr, "socket for my_genl is NULL\n");
+		return;
+	}
+
+	sock_fd = nl_socket_get_fd(nl_sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		err = sock_fd;
+		fprintf(stderr, "Failed to get socket file descriptor: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	up = 1;
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &up,
+			 sizeof(up));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to set NETLINK_EXT_ACK: %s",
+			strerror(errno));
+		err = -errno;
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = getsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval,
+			 &optlen);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to get NETLINK_EXT_ACK: %s",
+			strerror(errno));
+		err = -errno;
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	EXPECT_EQ(optval, 1);
+
+	family_id = genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr, "Failed to resolve family id: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	mcgrp_id = genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME,
+					 MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		err = mcgrp_id;
+		fprintf(stderr, "Failed to resolve multicast group: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_socket_add_membership(nl_sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to add membership: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, MY_GENL_ATTR_PATH, "some/random/path") < 0) {
+		fprintf(stderr,
+			"Failed to add MY_GENL_ATTR_PATH attribute: %s\n",
+			strerror(errno));
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_EQ(err, -NLE_INVAL);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(genl_test_sock_listen_all_nsid) - Tests NETLINK_LISTEN_ALL_NSID socket option functionality
+ *
+ * Validates the behavior of NETLINK_LISTEN_ALL_NSID socket option by:
+ * 1. Setting the NETLINK_LISTEN_ALL_NSID option on a netlink socket
+ * 2. Verifying proper socket operation with this option enabled
+ * 3. Testing permission enforcement (root privileges required)
+ * 4. Performing end-to-end communication with the option set
+ *
+ * Test flow:
+ * - Creates netlink socket with increased buffer size
+ * - Sets NETLINK_LISTEN_ALL_NSID option
+ * - Configures Generic Netlink communication:
+ *   - Resolves family and multicast group IDs
+ *   - Sets up message and callback
+ * - Performs round-trip message exchange
+ * - Verifies sysfs interaction matches received data
+ *
+ * Special considerations:
+ * - Requires root privileges (checks and skips if not root)
+ * - No getsockopt available for NETLINK_LISTEN_ALL_NSID verification
+ * - Tests both successful operation and permission error cases
+ * - Includes sysfs value validation for complete functionality check
+ *
+ * Expected results:
+ * - Root user: Successful option setting and normal operation
+ * - Correct message handling through entire communication chain
+ * - Proper sysfs value synchronization with received data
+ * - Non-root: Graceful test skipping
+ */
+
+TEST(genl_test_sock_listen_all_nsid)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	int mcgrp_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err;
+	int int_value;
+	int up;
+	int sock_fd;
+
+	struct genlmsghdr *user_hdr;
+	struct callback_data cb_data;
+
+	printf("Running Test: setting NETLINK_LISTEN_ALL_NSID option for socket...\n");
+
+	// Only root can listen to different Netlink namespaces
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock) {
+		printf("socket for my_genl is NULL\n");
+		return;
+	}
+
+	err = nl_socket_set_buffer_size(nl_sock, 8000, 8000);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to change socket buffer size: %s\n",
+			strerror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	sock_fd = nl_socket_get_fd(nl_sock);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		err = sock_fd;
+		fprintf(stderr, "Failed to get socket file descriptor: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	up = 1;
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &up,
+			 sizeof(up));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to set NETLINK_LISTEN_ALL_NSID: %s\n",
+			strerror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr, "Failed to resolve family id: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	mcgrp_id = genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME,
+					 MY_MCGRP_NAME);
+	EXPECT_GE(mcgrp_id, 0);
+	if (mcgrp_id < 0) {
+		err = mcgrp_id;
+		fprintf(stderr, "Failed to resolve multicast group: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_socket_add_membership(nl_sock, mcgrp_id);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to add membership: %s\n",
+			nl_geterror(err));
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) {
+		fprintf(stderr,
+			"Failed to add MY_GENL_ATTR_PATH attribute: %s\n",
+			strerror(errno));
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_EQ(int_value, cb_data.int_value);
+
+	err = write_int_to_sysfs(PATH_GENL_TEST_NUM, -20);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(genl_third_echo) - Validates NLM_F_ECHO flag functionality in Generic Netlink
+ *
+ * Tests the echo/reply mechanism by:
+ * 1. Creating a Netlink socket and resolving the third_genl family
+ * 2. Sending a message with NLM_F_ECHO flag set
+ * 3. Verifying proper echo reply handling through:
+ *    - Callback validation (validate_cb_third)
+ *    - Sysfs value comparison
+ *
+ * Test Flow:
+ * - Requires root privileges (for sysfs operations)
+ * - Allocates and configures Netlink socket and message
+ * - Sets up callback for reply validation
+ * - Sends echo request and waits for reply
+ * - Compares received message with sysfs content
+ * - Cleans up sysfs state after verification
+ *
+ * Key Validations:
+ * - Successful message round-trip with echo flag
+ * - Correct message content in callback vs sysfs
+ * - Proper resource cleanup in all code paths
+ * - Root permission enforcement
+ *
+ * Expected Behavior:
+ * - Message with NLM_F_ECHO should trigger reply from kernel
+ * - Callback should receive matching message content
+ * - Sysfs should reflect the same message content
+ * - Non-root users should be properly handled
+ */
+
+TEST(genl_third_echo)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err;
+
+	struct callback_data_third cb_data;
+
+	printf("Running Test: sending message to third_genl...\n");
+
+	// Only root can write to sysfs (needs for testing)
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = my_genl_ctrl_resolve(THIRD_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr,
+			"Failed to resolve family id for THIRD_GENL: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_ECHO, THIRD_GENL_CMD_ECHO, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	char *str = malloc(BUFFER_SIZE);
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_third,
+			&cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to receive message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = read_string_from_sysfs(PATH_THIRD_GENL_MES, str, BUFFER_SIZE);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to read from sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+	EXPECT_STREQ(str, cb_data.message);
+
+	err = write_string_to_sysfs(PATH_THIRD_GENL_MES, "default");
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr, "Failed to write to sysfs: %s\n",
+			strerror(err));
+		goto error;
+	}
+
+error:
+	free(str);
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(incorrect_genl_third_echo_flags) - Validates Netlink flag enforcement
+ *
+ * Tests kernel's handling of invalid Netlink message flags by:
+ * 1. Sending a message with explicitly prohibited flag combination (NLM_F_ECHO | NLM_F_ATOMIC)
+ * 2. Verifying proper error response (EINVAL/NLE_INVAL)
+ *
+ * Test Flow:
+ * 1. Creates and configures Netlink socket
+ * 2. Resolves THIRD_GENL family
+ * 3. Constructs message with invalid flags:
+ *    - Uses valid NLM_F_ECHO
+ *    - Adds invalid NLM_F_ATOMIC (prohibited for Generic Netlink)
+ * 4. Sets up validation callback
+ * 5. Sends message and verifies error response
+ *
+ * Key Validations:
+ * - Kernel rejects messages with invalid flag combinations
+ * - Correct error code (NLE_INVAL) is returned
+ * - Proper resource cleanup in all execution paths
+ *
+ * Expected Behavior:
+ * - Kernel should reject message with EINVAL/NLE_INVAL
+ * - No callback validation should occur (message fails before processing)
+ * - All allocated resources should be properly freed
+ *
+ * Note:
+ * - Only these flags are valid for Generic Netlink:
+ *   NLM_F_REQUEST, NLM_F_ACK, NLM_F_ECHO, NLM_F_DUMP
+ * - NLM_F_ATOMIC is explicitly invalid for Generic Netlink
+ */
+
+TEST(incorrect_genl_third_echo_flags)
+{
+	struct nl_sock *sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct genlmsghdr *user_hdr;
+	struct nl_cb *cb;
+	int err;
+
+	struct callback_data_third cb_data;
+
+	printf("Running Test: sending message with incorrect flags to third_genl...\n");
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "socket is NULL\n");
+		return;
+	}
+
+	family_id = genl_ctrl_resolve(sock, "THIRD_GENL");
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		err = family_id;
+		fprintf(stderr,
+			"Failed to resolve family id for THIRD_GENL: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate message\n");
+		nl_socket_free(sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_ECHO | NLM_F_ATOMIC, THIRD_GENL_CMD_ECHO,
+			       0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		fprintf(stderr, "Failed to genlmsg_put\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_third,
+			&cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(sock, cb);
+	EXPECT_EQ(err, -NLE_INVAL);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(sock);
+}
+
+/**
+ * TEST(new_socket_netlink_usersock) - Validates NETLINK_USERSOCK socket lifecycle
+ *
+ * Tests the creation and cleanup of NETLINK_USERSOCK sockets by:
+ * 1. Creating and connecting a NETLINK_USERSOCK socket
+ * 2. Verifying its presence in /proc/net/netlink
+ * 3. Checking proper cleanup after socket release
+ *
+ * Test Methodology:
+ * 1. Socket Allocation:
+ *    - Creates socket using nl_socket_alloc()
+ *    - Binds to NETLINK_USERSOCK protocol (2)
+ *
+ * 2. System Validation:
+ *    - Parses /proc/net/netlink to count active sockets
+ *    - Verifies exactly one new NETLINK_USERSOCK exists
+ *    - Includes 2-second delay for kernel state synchronization
+ *    - Re-checks /proc after socket release
+ *
+ * 3. Cleanup Verification:
+ *    - Confirms socket count returns to baseline
+ *    - Validates proper resource deallocation
+ *
+ * Key Validations:
+ * - Correct socket creation in kernel space
+ * - Accurate /proc filesystem reporting
+ * - Proper socket cleanup on free
+ * - Robust parsing of /proc/net/netlink format
+ *
+ * Expected Behavior:
+ * - Socket appears in /proc/net/netlink after creation
+ * - Socket disappears from /proc/net/netlink after release
+ * - Final count matches initial baseline
+ * - All file handles properly closed
+ *
+ * Note:
+ * - Uses 2-second delay to account for kernel cleanup latency
+ * - Handles potential /proc/net/netlink parsing errors gracefully
+ * - Validates both presence and absence of socket record
+ */
+
+TEST(new_socket_netlink_usersock)
+{
+#define NETLINK_USERSOCK 2 // Reserved for user mode socket protocols
+	int err;
+
+	struct nl_sock *sock;
+	char *header;
+
+	printf("Running Test: creating socket for user mode and checking it existence in the system...\n");
+
+	sock = nl_socket_alloc();
+	EXPECT_NE(NULL, sock);
+	if (!sock) {
+		fprintf(stderr, "Failed to allocate socket\n");
+		return;
+	}
+
+	err = nl_connect(sock, NETLINK_USERSOCK);
+	EXPECT_EQ(err, 0);
+	if (err) {
+		fprintf(stderr,
+			"Failed to connect to Netlink using NETLINK_USERSOCK: %s\n",
+			nl_geterror(err));
+		nl_socket_free(sock);
+		return;
+	}
+
+	FILE *file;
+	char line[256];
+	char sk[20];
+	int Eth, Pid;
+	unsigned int Groups, Rmem, Wmem, Dump, Locks, Drops, Inode;
+
+	int count_user_socks = 0;
+
+	file = fopen("/proc/net/netlink", "r");
+	EXPECT_NE(NULL, file);
+	if (file == NULL) {
+		perror("fopen");
+		return;
+	}
+
+	// Skip header
+	header = fgets(line, sizeof(line), file);
+	EXPECT_NE(NULL, header);
+	if (header == NULL) {
+		fclose(file);
+		nl_socket_free(sock);
+		return;
+	}
+
+	// Parse line
+	while (fgets(line, sizeof(line), file) != NULL) {
+		if (!isxdigit(
+			    line[0])) { // check if the first column is 16-number value
+			break;
+		}
+		if (sscanf(line,
+			   "%19s %d %d %x %u %u %u %u %u %u", // limit sk len to 19 symbols
+			   sk, &Eth, &Pid, &Groups, &Rmem, &Wmem, &Dump, &Locks,
+			   &Drops, &Inode) == 10) {
+			if (Eth == NETLINK_USERSOCK)
+				count_user_socks += 1;
+
+		} else {
+			fprintf(stderr, "Failed to parse line: %s", line);
+			EXPECT_EQ(0, 1);
+		}
+	}
+
+	fclose(file);
+
+	nl_socket_free(sock);
+
+	sleep(2);
+
+	file = fopen("/proc/net/netlink", "r");
+	EXPECT_NE(NULL, file);
+	if (file == NULL) {
+		perror("fopen");
+		return;
+	}
+
+	header = fgets(line, sizeof(line), file);
+	EXPECT_NE(NULL, header);
+	if (header == NULL) {
+		fclose(file);
+		return;
+	}
+
+	while (fgets(line, sizeof(line), file) != NULL) {
+		if (!isxdigit(line[0]))
+			break;
+
+		if (sscanf(line, "%19s %d %d %x %u %u %u %u %u %u", sk, &Eth,
+			   &Pid, &Groups, &Rmem, &Wmem, &Dump, &Locks, &Drops,
+			   &Inode) == 10) {
+			if (Eth == NETLINK_USERSOCK)
+				count_user_socks -= 1;
+
+		} else {
+			fprintf(stderr, "Failed to parse line: %s", line);
+			EXPECT_EQ(0, 1);
+		}
+	}
+
+	fclose(file);
+
+	EXPECT_TRUE(count_user_socks == 1);
+}
+
+/**
+ * TEST(incorrect_parallel_genl_reject_policy_set_value) - Validates reject policy enforcement
+ *
+ * Tests the Generic Netlink reject policy by:
+ * 1. Sending a properly formatted message to a command with reject policy
+ * 2. Verifying the kernel rejects the message with EINVAL
+ * 3. Confirming all attributes are properly skipped
+ *
+ * Test Methodology:
+ * 1. Creates Generic Netlink socket and resolves parallel_genl family
+ * 2. Constructs message with:
+ *    - Valid path attribute (PATH_PARALLEL_GENL_MES)
+ *    - Test data ("value for reject")
+ *    - SET_VALUE command (PARALLEL_GENL_CMD_SET_VALUE)
+ * 3. Configures validation callback
+ * 4. Sends message and verifies rejection
+ *
+ * Key Validations:
+ * - Kernel properly enforces reject policy
+ * - Correct error code (NLE_INVAL) is returned
+ * - Message attributes are ignored as expected
+ * - Resources are properly cleaned up
+ *
+ * Expected Behavior:
+ * - Kernel should reject message with EINVAL/NLE_INVAL
+ * - No callback validation should occur (message rejected by policy)
+ * - All allocated resources should be freed
+ *
+ * Special Considerations:
+ * - Tests edge case of valid message format but rejected by policy
+ * - Verifies proper attribute handling under reject policy
+ * - Validates correct error propagation to userspace
+ */
+
+TEST(incorrect_parallel_genl_reject_policy_set_value)
+{
+	struct nl_sock *nl_sock;
+	int family_id;
+	struct nl_msg *msg;
+	struct nl_cb *cb;
+	int err = 0;
+	char *value;
+	struct genlmsghdr *user_hdr;
+	struct callback_data cb_data;
+
+	printf("Running Test: sending correct value for sysfs to parallel_genl to check reject policy...\n");
+
+	nl_sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, nl_sock);
+	if (!nl_sock)
+		return;
+
+	family_id = genl_ctrl_resolve(nl_sock, PARALLEL_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		nl_socket_free(nl_sock);
+		err = family_id;
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	EXPECT_NE(NULL, msg);
+	if (!msg) {
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0,
+			       NLM_F_REQUEST, PARALLEL_GENL_CMD_SET_VALUE, 0);
+	EXPECT_NE(NULL, user_hdr);
+	if (!user_hdr) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	if (nla_put_string(msg, PARALLEL_GENL_ATTR_PATH,
+			   PATH_PARALLEL_GENL_MES) < 0) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	value = "value for reject";
+	if (nla_put_string(msg, PARALLEL_GENL_ATTR_DATA, value) < 0) {
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		ASSERT_EQ(0, 1);
+		return;
+	}
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	EXPECT_NE(NULL, cb);
+	if (!cb) {
+		fprintf(stderr, "Failed to allocate callback\n");
+		nlmsg_free(msg);
+		nl_socket_free(nl_sock);
+		return;
+	}
+
+	err = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data);
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Error setting callback: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_send_auto(nl_sock, msg);
+	EXPECT_GE(err, 0);
+	if (err < 0) {
+		fprintf(stderr, "Failed to send message: %s\n",
+			nl_geterror(err));
+		goto error;
+	}
+
+	err = nl_recvmsgs(nl_sock, cb);
+	EXPECT_EQ(err, -NLE_INVAL);
+
+error:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	nl_socket_free(nl_sock);
+}
+
+/**
+ * TEST(connect_sock) - Validates raw Netlink socket operations using system calls
+ *
+ * Tests the complete lifecycle of a Netlink socket using low-level system calls:
+ * 1. Creates a raw NETLINK_GENERIC socket
+ * 2. Binds to the socket with process-specific PID
+ * 3. Connects to the kernel (pid 0)
+ * 4. Properly closes the socket
+ *
+ * Test Methodology:
+ * 1. Initial Setup:
+ *    - Uses libnl to resolve Generic Netlink family (for verification)
+ *    - Releases libnl socket to test raw system calls
+ *
+ * 2. System Call Validation:
+ *    - Creates socket with AF_NETLINK/SOCK_RAW
+ *    - Binds to process PID (getpid())
+ *    - Connects to kernel (pid 0)
+ *    - Verifies each operation succeeds
+ *
+ * 3. Cleanup:
+ *    - Proper socket closure
+ *    - Resource cleanup
+ *
+ * Key Validations:
+ * - Correct socket creation with NETLINK_GENERIC
+ * - Proper binding with AF_NETLINK
+ * - Successful connection to kernel
+ * - Error handling for all system calls
+ * - Resource cleanup
+ *
+ * Expected Behavior:
+ * - All system calls should succeed
+ * - Socket should be properly bound to process PID
+ * - Connection to kernel (pid 0) should establish
+ * - No resource leaks after close()
+ *
+ * Note:
+ * - Uses both libnl and raw system calls for comprehensive validation
+ * - Tests the fundamental Netlink socket operations
+ * - Verifies proper kernel/userspace communication setup
+ */
+
+TEST(connect_sock)
+{
+	int sock_fd;
+	struct sockaddr_nl src_addr, dest_addr;
+	int family_id;
+	struct nl_sock *sock;
+	int err;
+
+	printf("Running Test: using system calls to operate with Netlink socket...\n");
+
+	sock = socket_alloc_and_conn();
+	EXPECT_NE(NULL, sock);
+	if (!sock)
+		return;
+
+	family_id = genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME);
+	EXPECT_GT(family_id, 0);
+	if (family_id < 0) {
+		fprintf(stderr,
+			"Failed to resolve family id for TEST_GENL: %d\n",
+			family_id);
+		nl_socket_free(sock);
+		err = family_id;
+		return;
+	}
+
+	nl_socket_free(sock);
+
+	sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+	EXPECT_GE(sock_fd, 0);
+	if (sock_fd < 0) {
+		perror("socket()");
+		err = sock_fd;
+		return;
+	}
+
+	memset(&src_addr, 0, sizeof(src_addr));
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+
+	err = bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		perror("bind()");
+		close(sock_fd);
+		return;
+	}
+
+	memset(&dest_addr, 0, sizeof(dest_addr));
+	dest_addr.nl_family = AF_NETLINK;
+	dest_addr.nl_pid = 0;
+	dest_addr.nl_groups = 0;
+
+	err = connect(sock_fd, (struct sockaddr *)&dest_addr,
+		      sizeof(dest_addr));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		perror("connect()");
+		close(sock_fd);
+		return;
+	}
+
+	close(sock_fd);
+}
+
+/**
+ * TEST(netfilter_unbind_grp) - Validates Netlink group membership bind/unbind operations
+ *
+ * Tests the NETLINK_ADD_MEMBERSHIP and NETLINK_DROP_MEMBERSHIP socket options
+ * using NETLINK_NETFILTER protocol which implements bind/unbind callbacks.
+ *
+ * Test Methodology:
+ * 1. Creates NETLINK_NETFILTER socket (requires root privileges)
+ * 2. Exercises group membership operations:
+ *    - Adds membership to NFNLGRP_NFTABLES (group 3)
+ *    - Adds membership to NFNLGRP_NFTRACE (group 4)
+ *    - Drops membership from group 3
+ *    - Re-adds membership to group 3
+ * 3. Completes socket lifecycle:
+ *    - Binds socket to process PID
+ *    - Connects to kernel (pid 0)
+ *    - Closes socket
+ *
+ * Key Validations:
+ * - Successful group membership operations
+ * - Proper bind/unbind callback execution
+ * - Socket option error handling
+ * - Root privilege enforcement
+ * - Socket cleanup
+ *
+ * Expected Behavior:
+ * - All membership operations should succeed (return 0)
+ * - Bind/connect operations should complete successfully
+ * - Non-root execution should skip test gracefully
+ *
+ * Protocol Selection Rationale:
+ * - NETLINK_NETFILTER specifically implements .bind/.unbind callbacks (in netlink_kernel_cfg)
+ * - Other Netlink protocols may not support these operations
+ * - Provides concrete test case for callback functionality
+ *
+ * Note:
+ * - Requires root privileges for group operations
+ * - Tests both single and multiple group scenarios
+ * - Verifies re-adding previously dropped groups
+ */
+
+TEST(netfilter_unbind_grp)
+{
+	int sock_fd;
+	struct sockaddr_nl src_addr, dest_addr;
+	int err;
+	int group_3, group_4;
+
+	printf("Running Test: trying to unbind groups from releasing socket...\n");
+
+	// Only root can NETLINK_ADD_MEMBERSHIP and NETLINK_DROP_MEMBERSHIP
+	if (geteuid()) {
+		SKIP(return, "test requires root");
+		return;
+	}
+
+	sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
+	ASSERT_GE(sock_fd, 0);
+
+	memset(&src_addr, 0, sizeof(src_addr));
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+
+	group_3 = NFNLGRP_NFTABLES;
+	group_4 = NFNLGRP_NFTRACE;
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group_3,
+			 sizeof(group_3));
+	EXPECT_EQ(err, 0);
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group_4,
+			 sizeof(group_4));
+	EXPECT_EQ(err, 0);
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+			 &group_3, sizeof(group_3));
+	EXPECT_EQ(err, 0);
+
+	err = setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group_3,
+			 sizeof(group_3));
+	EXPECT_EQ(err, 0);
+
+	err = bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		perror("bind()");
+		close(sock_fd);
+		return;
+	}
+
+	memset(&dest_addr, 0, sizeof(dest_addr));
+	dest_addr.nl_family = AF_NETLINK;
+	dest_addr.nl_pid = 0;
+
+	err = connect(sock_fd, (struct sockaddr *)&dest_addr,
+		      sizeof(dest_addr));
+	EXPECT_EQ(err, 0);
+	if (err < 0) {
+		perror("connect()");
+		close(sock_fd);
+		return;
+	}
+
+	close(sock_fd);
+}
+
+#define ITERATIONS 5000
+
+void socket_worker(int iterations)
+{
+	srand(time(NULL) ^ getpid());
+
+	for (int i = 0; i < iterations; i++) {
+		int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+
+		if (fd < 0) {
+			perror("socket");
+			continue;
+		}
+
+		struct sockaddr_nl addr = {
+			.nl_family = AF_NETLINK,
+			.nl_pid = getpid(),
+			.nl_groups = 0,
+		};
+
+		if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+			perror("bind");
+			close(fd);
+			continue;
+		}
+
+		// Short random delay
+		struct timespec ts = { .tv_sec = 0, .tv_nsec = rand() % 1000 };
+
+		nanosleep(&ts, NULL);
+
+		close(fd);
+	}
+}
+
+/**
+ * TEST(netlink_grab_table_check_wait) - Stress tests Netlink table locking mechanism
+ *
+ * Creates a race condition scenario to validate Netlink table grabbing behavior by:
+ * 1. Spawning two concurrent processes
+ * 2. Each process performs rapid socket create/bind/close cycles
+ * 3. Introduces random micro-delays to increase race condition probability
+ * 4. Verifies system stability under contention
+ *
+ * Test Methodology:
+ * 1. Process Creation:
+ *    - Forks two child processes
+ *    - Each executes socket_worker(ITERATIONS)
+ *
+ * 2. Worker Behavior (per iteration):
+ *    - Creates NETLINK_GENERIC socket
+ *    - Binds to process PID
+ *    - Adds random 0-1μs delay
+ *    - Closes socket
+ *    - Repeats 5000 times (ITERATIONS)
+ *
+ * 3. Validation:
+ *    - Parent waits for both children
+ *    - Checks for deadlocks/crashes
+ *    - Verifies proper resource cleanup
+ *
+ * Key Stress Points:
+ * - Concurrent table access attempts
+ * - Rapid socket lifecycle churn
+ * - Randomized timing variations
+ * - Kernel table locking contention
+ *
+ * Expected Behavior:
+ * - System should remain stable throughout
+ * - No deadlocks or resource leaks
+ * - Proper serialization of table access
+ * - Correct error handling under contention
+ *
+ * Race Condition Verification:
+ * - Tests kernel's ability to handle:
+ *   - Simultaneous socket operations
+ *   - Table grabbing contention
+ *   - Resource cleanup under load
+ *
+ * Note:
+ * - Uses 5000 iterations for significant stress
+ * - Micro-delays increase race probability
+ * - Tests both success and failure paths
+ * - Verifies proper process cleanup
+ */
+
+TEST(netlink_grab_table_check_wait)
+{
+	int status;
+
+	printf("Running Test: making one process waiting a grab for a netlink table...\n");
+
+	pid_t p1 = fork();
+
+	if (p1 == 0) {
+		socket_worker(ITERATIONS);
+		exit(0);
+	}
+
+	pid_t p2 = fork();
+
+	if (p2 == 0) {
+		socket_worker(ITERATIONS);
+		exit(0);
+	}
+
+	waitpid(p1, &status, 0);
+	EXPECT_EQ(WEXITSTATUS(status), 0);
+
+	waitpid(p2, &status, 0);
+	EXPECT_EQ(WEXITSTATUS(status), 0);
+}
+
 /**
  * TEST(capture_end) - Terminates Netlink traffic monitoring session
  *
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ