1 /*
2 * Check decoding of getsockopt and setsockopt for SOL_NETLINK level.
3 *
4 * Copyright (c) 2017-2023 Dmitry V. Levin <ldv@strace.io>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "netlink.h"
12 #include <stdio.h>
13
14 #ifndef SOL_NETLINK
15 # define SOL_NETLINK 270
16 #endif
17
18 static int rc;
19 static const char *errstr;
20
21 static int
22 get_sockopt(int fd, int name, void *val, socklen_t *len)
23 {
24 rc = getsockopt(fd, SOL_NETLINK, name, val, len);
25 errstr = sprintrc(rc);
26 return rc;
27 }
28
29 static int
30 set_sockopt(int fd, int name, void *val, socklen_t len)
31 {
32 rc = setsockopt(fd, SOL_NETLINK, name, val, len);
33 errstr = sprintrc(rc);
34 return rc;
35 }
36
37 int
38 main(void)
39 {
40 static const struct {
41 int val;
42 const char *str;
43 } names[] = {
44 #ifdef NETLINK_ADD_MEMBERSHIP
45 { ARG_STR(NETLINK_ADD_MEMBERSHIP) },
46 #endif
47 #ifdef NETLINK_DROP_MEMBERSHIP
48 { ARG_STR(NETLINK_DROP_MEMBERSHIP) },
49 #endif
50 #ifdef NETLINK_PKTINFO
51 { ARG_STR(NETLINK_PKTINFO) },
52 #endif
53 #ifdef NETLINK_BROADCAST_ERROR
54 { ARG_STR(NETLINK_BROADCAST_ERROR) },
55 #endif
56 #ifdef NETLINK_NO_ENOBUFS
57 { ARG_STR(NETLINK_NO_ENOBUFS) },
58 #endif
59 #ifdef NETLINK_RX_RING
60 { ARG_STR(NETLINK_RX_RING) },
61 #endif
62 #ifdef NETLINK_TX_RING
63 { ARG_STR(NETLINK_TX_RING) },
64 #endif
65 #ifdef NETLINK_LISTEN_ALL_NSID
66 { ARG_STR(NETLINK_LISTEN_ALL_NSID) },
67 #endif
68 #ifdef NETLINK_LIST_MEMBERSHIPS
69 { ARG_STR(NETLINK_LIST_MEMBERSHIPS) },
70 #endif
71 #ifdef NETLINK_CAP_ACK
72 { ARG_STR(NETLINK_CAP_ACK) },
73 #endif
74 #ifdef NETLINK_EXT_ACK
75 { ARG_STR(NETLINK_EXT_ACK) },
76 #endif
77 };
78
79 TAIL_ALLOC_OBJECT_CONST_PTR(int, val);
80 TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
81 void *const efault = val + 1;
82 int fd = socket(AF_NETLINK, SOCK_RAW, 0);
83 if (fd < 0)
84 perror_msg_and_skip("socket AF_NETLINK SOCK_RAW");
85
86 for (unsigned int i = 0; i < ARRAY_SIZE(names); ++i) {
87 /* getsockopt */
88
89 /* classic */
90 *len = sizeof(*val);
91 get_sockopt(fd, names[i].val, val, len);
92 printf("getsockopt(%d, SOL_NETLINK, %s, ", fd, names[i].str);
93 if (rc)
94 printf("%p", val);
95 else
96 printf("[%d]", *val);
97 printf(", [%d", (int) sizeof(*val));
98 if ((int) sizeof(*val) != *len)
99 printf(" => %d", *len);
100 printf("]) = %s\n", errstr);
101
102 /* optlen larger than necessary - shortened */
103 *len = sizeof(*val) + 1;
104 get_sockopt(fd, names[i].val, val, len);
105 printf("getsockopt(%d, SOL_NETLINK, %s, ", fd, names[i].str);
106 if (rc)
107 printf("%p", val);
108 else
109 printf("[%d]", *val);
110 printf(", [%d", (int) sizeof(*val) + 1);
111 if ((int) sizeof(*val) + 1 != *len)
112 printf(" => %d", *len);
113 printf("]) = %s\n", errstr);
114
115 /* zero optlen - print returned optlen */
116 *len = 0;
117 get_sockopt(fd, names[i].val, NULL, len);
118 printf("getsockopt(%d, SOL_NETLINK, %s, NULL, [0",
119 fd, names[i].str);
120 if (*len)
121 printf(" => %d", *len);
122 printf("]) = %s\n", errstr);
123
124 #ifdef NETLINK_LIST_MEMBERSHIPS
125 if (names[i].val != NETLINK_LIST_MEMBERSHIPS) {
126 #endif
127 /* optlen shorter than necessary - print address */
128 *len = sizeof(*val) - 1;
129 get_sockopt(fd, names[i].val, val, len);
130 printf("getsockopt(%d, SOL_NETLINK, %s, %p, [%d",
131 fd, names[i].str, val, (int) sizeof(*val) - 1);
132 if ((int) sizeof(*val) - 1 != *len)
133 printf(" => %d", *len);
134 printf("]) = %s\n", errstr);
135 #ifdef NETLINK_LIST_MEMBERSHIPS
136 } else {
137 /* optlen shorter than required for the first element */
138 *len = sizeof(*val) - 1;
139 get_sockopt(fd, names[i].val, efault, len);
140 printf("getsockopt(%d, SOL_NETLINK, %s, ",
141 fd, names[i].str);
142 if (rc)
143 printf("%p", efault);
144 else
145 printf("[]");
146 printf(", [%d", (int) sizeof(*val) - 1);
147 if ((int) sizeof(*val) - 1 != *len)
148 printf(" => %d", *len);
149 printf("]) = %s\n", errstr);
150 }
151 #endif
152
153 /* optval EFAULT - print address */
154 *len = sizeof(*val);
155 get_sockopt(fd, names[i].val, efault, len);
156 printf("getsockopt(%d, SOL_NETLINK, %s, %p",
157 fd, names[i].str, efault);
158 printf(", [%d", (int) sizeof(*val));
159 if ((int) sizeof(*val) != *len)
160 printf(" => %d", *len);
161 printf("]) = %s\n", errstr);
162
163 /* optlen EFAULT - print address */
164 get_sockopt(fd, names[i].val, val, len + 1);
165 printf("getsockopt(%d, SOL_NETLINK, %s, %p, %p) = %s\n",
166 fd, names[i].str, val, len + 1, errstr);
167
168 /* setsockopt */
169
170 /* classic */
171 *val = 0xdefaced;
172 set_sockopt(fd, names[i].val, val, sizeof(*val));
173 printf("setsockopt(%d, SOL_NETLINK, %s, [%d], %d) = %s\n",
174 fd, names[i].str, *val, (int) sizeof(*val), errstr);
175
176 /* optlen larger than necessary - shortened */
177 set_sockopt(fd, names[i].val, val, sizeof(*val) + 1);
178 printf("setsockopt(%d, SOL_NETLINK, %s, [%d], %d) = %s\n",
179 fd, names[i].str, *val, (int) sizeof(*val) + 1, errstr);
180
181 /* optlen < 0 - print address */
182 set_sockopt(fd, names[i].val, val, -1U);
183 printf("setsockopt(%d, SOL_NETLINK, %s, %p, -1) = %s\n",
184 fd, names[i].str, val, errstr);
185
186 /* optlen smaller than necessary - print address */
187 set_sockopt(fd, names[i].val, val, sizeof(*val) - 1);
188 printf("setsockopt(%d, SOL_NETLINK, %s, %p, %d) = %s\n",
189 fd, names[i].str, val, (int) sizeof(*val) - 1, errstr);
190
191 /* optval EFAULT - print address */
192 set_sockopt(fd, names[i].val, efault, sizeof(*val));
193 printf("setsockopt(%d, SOL_NETLINK, %s, %p, %d) = %s\n",
194 fd, names[i].str, efault, (int) sizeof(*val), errstr);
195 }
196
197 puts("+++ exited with 0 +++");
198 return 0;
199 }