xref: /linux/tools/testing/selftests/net/netlink-dumps.c (revision fcc79e1714e8c2b8e216dc3149812edd37884eef)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <sys/socket.h>
9 #include <sys/stat.h>
10 #include <sys/syscall.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 
14 #include <linux/genetlink.h>
15 #include <linux/netlink.h>
16 #include <linux/mqueue.h>
17 
18 #include "../kselftest_harness.h"
19 
20 static const struct {
21 	struct nlmsghdr nlhdr;
22 	struct genlmsghdr genlhdr;
23 	struct nlattr ahdr;
24 	__u16 val;
25 	__u16 pad;
26 } dump_policies = {
27 	.nlhdr = {
28 		.nlmsg_len	= sizeof(dump_policies),
29 		.nlmsg_type	= GENL_ID_CTRL,
30 		.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
31 		.nlmsg_seq	= 1,
32 	},
33 	.genlhdr = {
34 		.cmd		= CTRL_CMD_GETPOLICY,
35 		.version	= 2,
36 	},
37 	.ahdr = {
38 		.nla_len	= 6,
39 		.nla_type	= CTRL_ATTR_FAMILY_ID,
40 	},
41 	.val = GENL_ID_CTRL,
42 	.pad = 0,
43 };
44 
45 // Sanity check for the test itself, make sure the dump doesn't fit in one msg
46 TEST(test_sanity)
47 {
48 	int netlink_sock;
49 	char buf[8192];
50 	ssize_t n;
51 
52 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
53 	ASSERT_GE(netlink_sock, 0);
54 
55 	n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
56 	ASSERT_EQ(n, sizeof(dump_policies));
57 
58 	n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
59 	ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));
60 
61 	n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
62 	ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));
63 
64 	close(netlink_sock);
65 }
66 
67 TEST(close_in_progress)
68 {
69 	int netlink_sock;
70 	ssize_t n;
71 
72 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
73 	ASSERT_GE(netlink_sock, 0);
74 
75 	n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
76 	ASSERT_EQ(n, sizeof(dump_policies));
77 
78 	close(netlink_sock);
79 }
80 
81 TEST(close_with_ref)
82 {
83 	char cookie[NOTIFY_COOKIE_LEN] = {};
84 	int netlink_sock, mq_fd;
85 	struct sigevent sigev;
86 	ssize_t n;
87 
88 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
89 	ASSERT_GE(netlink_sock, 0);
90 
91 	n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
92 	ASSERT_EQ(n, sizeof(dump_policies));
93 
94 	mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0);
95 	ASSERT_GE(mq_fd, 0);
96 
97 	memset(&sigev, 0, sizeof(sigev));
98 	sigev.sigev_notify		= SIGEV_THREAD;
99 	sigev.sigev_value.sival_ptr	= cookie;
100 	sigev.sigev_signo		= netlink_sock;
101 
102 	syscall(__NR_mq_notify, mq_fd, &sigev);
103 
104 	close(netlink_sock);
105 
106 	// give mqueue time to fire
107 	usleep(100 * 1000);
108 }
109 
110 TEST_HARNESS_MAIN
111