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
TEST(test_sanity)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, sizeof(struct nlmsghdr));
60
61 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
62 ASSERT_GE(n, sizeof(struct nlmsghdr));
63
64 close(netlink_sock);
65 }
66
TEST(close_in_progress)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
TEST(close_with_ref)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