xref: /linux/tools/testing/selftests/net/getsockopt_iter.c (revision 00599d4841790d05401820a96cf7edb193888b00)
1d39887f5SBreno Leitao // SPDX-License-Identifier: GPL-2.0
2d39887f5SBreno Leitao /*
3d39887f5SBreno Leitao  * Quick test for getsockopt{_iter} tests.
4d39887f5SBreno Leitao  *
5d39887f5SBreno Leitao  * Each fixture targets one converted protocol and pins down the
6d39887f5SBreno Leitao  * returned-length / errno semantics across buffer-size variations,
7d39887f5SBreno Leitao  * an unknown optname and a bogus level.
8d39887f5SBreno Leitao  *
9d39887f5SBreno Leitao  * - netlink: NETLINK_PKTINFO covers the flag-style int path; the
10d39887f5SBreno Leitao  *   NETLINK_LIST_MEMBERSHIPS cases cover the size-discovery path
11d39887f5SBreno Leitao  *   that always reports the required buffer length back via optlen,
12d39887f5SBreno Leitao  *   even when the user buffer is too small to receive any group bits.
13d39887f5SBreno Leitao  * - vsock:   SO_VM_SOCKETS_BUFFER_SIZE covers the u64 path.
14d39887f5SBreno Leitao  *
15d39887f5SBreno Leitao  * Author: Breno Leitao <leitao@debian.org>
16d39887f5SBreno Leitao  */
17d39887f5SBreno Leitao 
18d39887f5SBreno Leitao #include <errno.h>
19d39887f5SBreno Leitao #include <stdint.h>
20d39887f5SBreno Leitao #include <stdio.h>
21d39887f5SBreno Leitao #include <string.h>
22d39887f5SBreno Leitao #include <unistd.h>
23d39887f5SBreno Leitao #include <linux/netlink.h>
24d39887f5SBreno Leitao #include <linux/rtnetlink.h>
25*c8c2bd2bSBreno Leitao #include <linux/time_types.h>
26d39887f5SBreno Leitao #include <linux/vm_sockets.h>
27d39887f5SBreno Leitao #include <sys/socket.h>
28d39887f5SBreno Leitao #include "kselftest_harness.h"
29d39887f5SBreno Leitao 
30d39887f5SBreno Leitao #ifndef AF_VSOCK
31d39887f5SBreno Leitao #define AF_VSOCK 40
32d39887f5SBreno Leitao #endif
33d39887f5SBreno Leitao 
34d39887f5SBreno Leitao /* ---------- netlink ---------- */
35d39887f5SBreno Leitao 
36d39887f5SBreno Leitao FIXTURE(netlink)
37d39887f5SBreno Leitao {
38d39887f5SBreno Leitao 	int fd;
39d39887f5SBreno Leitao };
40d39887f5SBreno Leitao 
41d39887f5SBreno Leitao FIXTURE_SETUP(netlink)
42d39887f5SBreno Leitao {
43d39887f5SBreno Leitao 	int group = RTNLGRP_LINK;
44d39887f5SBreno Leitao 
45d39887f5SBreno Leitao 	self->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
46d39887f5SBreno Leitao 	if (self->fd < 0)
47d39887f5SBreno Leitao 		SKIP(return, "AF_NETLINK socket: %s", strerror(errno));
48d39887f5SBreno Leitao 
49d39887f5SBreno Leitao 	/* Joining a multicast group grows nlk->ngroups so the
50d39887f5SBreno Leitao 	 * NETLINK_LIST_MEMBERSHIPS path has a non-zero size to report.
51d39887f5SBreno Leitao 	 */
52d39887f5SBreno Leitao 	if (setsockopt(self->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
53d39887f5SBreno Leitao 		       &group, sizeof(group)) < 0)
54d39887f5SBreno Leitao 		SKIP(return, "NETLINK_ADD_MEMBERSHIP: %s", strerror(errno));
55d39887f5SBreno Leitao }
56d39887f5SBreno Leitao 
57d39887f5SBreno Leitao FIXTURE_TEARDOWN(netlink)
58d39887f5SBreno Leitao {
59d39887f5SBreno Leitao 	if (self->fd >= 0)
60d39887f5SBreno Leitao 		close(self->fd);
61d39887f5SBreno Leitao }
62d39887f5SBreno Leitao 
63d39887f5SBreno Leitao TEST_F(netlink, pktinfo_exact)
64d39887f5SBreno Leitao {
65*c8c2bd2bSBreno Leitao 	socklen_t optlen;
66d39887f5SBreno Leitao 	int val = -1;
67*c8c2bd2bSBreno Leitao 
68*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
69d39887f5SBreno Leitao 
70d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
71d39887f5SBreno Leitao 				&val, &optlen));
72d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(int), optlen);
73d39887f5SBreno Leitao 	ASSERT_TRUE(val == 0 || val == 1);
74d39887f5SBreno Leitao }
75d39887f5SBreno Leitao 
76d39887f5SBreno Leitao TEST_F(netlink, pktinfo_oversize_clamped)
77d39887f5SBreno Leitao {
78d39887f5SBreno Leitao 	char buf[16] = {};
79*c8c2bd2bSBreno Leitao 	socklen_t optlen;
80*c8c2bd2bSBreno Leitao 
81*c8c2bd2bSBreno Leitao 	optlen = sizeof(buf);
82d39887f5SBreno Leitao 
83d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
84d39887f5SBreno Leitao 				buf, &optlen));
85d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(int), optlen);
86d39887f5SBreno Leitao }
87d39887f5SBreno Leitao 
88d39887f5SBreno Leitao TEST_F(netlink, pktinfo_undersize)
89d39887f5SBreno Leitao {
90d39887f5SBreno Leitao 	char buf[2] = {};
91*c8c2bd2bSBreno Leitao 	socklen_t optlen;
92*c8c2bd2bSBreno Leitao 
93*c8c2bd2bSBreno Leitao 	optlen = sizeof(buf);
94d39887f5SBreno Leitao 
95d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
96d39887f5SBreno Leitao 				 buf, &optlen));
97d39887f5SBreno Leitao 	ASSERT_EQ(EINVAL, errno);
98*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(buf), optlen);
99d39887f5SBreno Leitao }
100d39887f5SBreno Leitao 
101d39887f5SBreno Leitao TEST_F(netlink, list_memberships_size_discovery)
102d39887f5SBreno Leitao {
103d39887f5SBreno Leitao 	socklen_t optlen = 0;
104d39887f5SBreno Leitao 	char dummy;
105d39887f5SBreno Leitao 
106d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
107d39887f5SBreno Leitao 				NETLINK_LIST_MEMBERSHIPS,
108d39887f5SBreno Leitao 				&dummy, &optlen));
109d39887f5SBreno Leitao 	ASSERT_GT(optlen, 0);
110d39887f5SBreno Leitao 	ASSERT_EQ(0, optlen % sizeof(__u32));
111d39887f5SBreno Leitao }
112d39887f5SBreno Leitao 
113d39887f5SBreno Leitao TEST_F(netlink, list_memberships_full_read)
114d39887f5SBreno Leitao {
115d39887f5SBreno Leitao 	__u32 buf[64] = {};
116*c8c2bd2bSBreno Leitao 	socklen_t optlen;
117*c8c2bd2bSBreno Leitao 
118*c8c2bd2bSBreno Leitao 	optlen = sizeof(buf);
119d39887f5SBreno Leitao 
120d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
121d39887f5SBreno Leitao 				NETLINK_LIST_MEMBERSHIPS,
122d39887f5SBreno Leitao 				buf, &optlen));
123d39887f5SBreno Leitao 	ASSERT_GT(optlen, 0);
124d39887f5SBreno Leitao 	ASSERT_LE(optlen, sizeof(buf));
125d39887f5SBreno Leitao 	ASSERT_EQ(0, optlen % sizeof(__u32));
126d39887f5SBreno Leitao }
127d39887f5SBreno Leitao 
128d39887f5SBreno Leitao TEST_F(netlink, bad_level)
129d39887f5SBreno Leitao {
130*c8c2bd2bSBreno Leitao 	socklen_t optlen;
131d39887f5SBreno Leitao 	int val;
132*c8c2bd2bSBreno Leitao 
133*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
134d39887f5SBreno Leitao 
135d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1, NETLINK_PKTINFO,
136d39887f5SBreno Leitao 				 &val, &optlen));
137d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
138*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(val), optlen);
139d39887f5SBreno Leitao }
140d39887f5SBreno Leitao 
141d39887f5SBreno Leitao TEST_F(netlink, bad_optname)
142d39887f5SBreno Leitao {
143*c8c2bd2bSBreno Leitao 	socklen_t optlen;
144d39887f5SBreno Leitao 	int val;
145*c8c2bd2bSBreno Leitao 
146*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
147d39887f5SBreno Leitao 
148d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, 0x7fff,
149d39887f5SBreno Leitao 				 &val, &optlen));
150d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
151*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(val), optlen);
152d39887f5SBreno Leitao }
153d39887f5SBreno Leitao 
154d39887f5SBreno Leitao /* ---------- vsock ---------- */
155d39887f5SBreno Leitao 
156d39887f5SBreno Leitao FIXTURE(vsock)
157d39887f5SBreno Leitao {
158d39887f5SBreno Leitao 	int fd;
159d39887f5SBreno Leitao };
160d39887f5SBreno Leitao 
161d39887f5SBreno Leitao FIXTURE_SETUP(vsock)
162d39887f5SBreno Leitao {
163d39887f5SBreno Leitao 	self->fd = socket(AF_VSOCK, SOCK_STREAM, 0);
164d39887f5SBreno Leitao 	if (self->fd < 0)
165d39887f5SBreno Leitao 		SKIP(return, "AF_VSOCK socket: %s", strerror(errno));
166d39887f5SBreno Leitao }
167d39887f5SBreno Leitao 
168d39887f5SBreno Leitao FIXTURE_TEARDOWN(vsock)
169d39887f5SBreno Leitao {
170d39887f5SBreno Leitao 	if (self->fd >= 0)
171d39887f5SBreno Leitao 		close(self->fd);
172d39887f5SBreno Leitao }
173d39887f5SBreno Leitao 
174d39887f5SBreno Leitao TEST_F(vsock, buffer_size_exact)
175d39887f5SBreno Leitao {
176*c8c2bd2bSBreno Leitao 	socklen_t optlen;
177d39887f5SBreno Leitao 	uint64_t val = 0;
178*c8c2bd2bSBreno Leitao 
179*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
180d39887f5SBreno Leitao 
181d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
182d39887f5SBreno Leitao 				SO_VM_SOCKETS_BUFFER_SIZE,
183d39887f5SBreno Leitao 				&val, &optlen));
184d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(uint64_t), optlen);
185d39887f5SBreno Leitao 	ASSERT_GT(val, 0);
186d39887f5SBreno Leitao }
187d39887f5SBreno Leitao 
188d39887f5SBreno Leitao TEST_F(vsock, buffer_size_oversize_clamped)
189d39887f5SBreno Leitao {
190d39887f5SBreno Leitao 	char buf[16] = {};
191*c8c2bd2bSBreno Leitao 	socklen_t optlen;
192*c8c2bd2bSBreno Leitao 
193*c8c2bd2bSBreno Leitao 	optlen = sizeof(buf);
194d39887f5SBreno Leitao 
195d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
196d39887f5SBreno Leitao 				SO_VM_SOCKETS_BUFFER_SIZE,
197d39887f5SBreno Leitao 				buf, &optlen));
198d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(uint64_t), optlen);
199d39887f5SBreno Leitao }
200d39887f5SBreno Leitao 
201d39887f5SBreno Leitao TEST_F(vsock, buffer_size_undersize)
202d39887f5SBreno Leitao {
203d39887f5SBreno Leitao 	char buf[4] = {};
204*c8c2bd2bSBreno Leitao 	socklen_t optlen;
205*c8c2bd2bSBreno Leitao 
206*c8c2bd2bSBreno Leitao 	optlen = sizeof(buf);
207d39887f5SBreno Leitao 
208d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
209d39887f5SBreno Leitao 				 SO_VM_SOCKETS_BUFFER_SIZE,
210d39887f5SBreno Leitao 				 buf, &optlen));
211d39887f5SBreno Leitao 	ASSERT_EQ(EINVAL, errno);
212*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(buf), optlen);
213d39887f5SBreno Leitao }
214d39887f5SBreno Leitao 
215d39887f5SBreno Leitao TEST_F(vsock, bad_level)
216d39887f5SBreno Leitao {
217*c8c2bd2bSBreno Leitao 	socklen_t optlen;
218d39887f5SBreno Leitao 	uint64_t val;
219*c8c2bd2bSBreno Leitao 
220*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
221d39887f5SBreno Leitao 
222d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1,
223d39887f5SBreno Leitao 				 SO_VM_SOCKETS_BUFFER_SIZE,
224d39887f5SBreno Leitao 				 &val, &optlen));
225d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
226*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(val), optlen);
227d39887f5SBreno Leitao }
228d39887f5SBreno Leitao 
229d39887f5SBreno Leitao TEST_F(vsock, bad_optname)
230d39887f5SBreno Leitao {
231*c8c2bd2bSBreno Leitao 	socklen_t optlen;
232d39887f5SBreno Leitao 	uint64_t val;
233*c8c2bd2bSBreno Leitao 
234*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
235d39887f5SBreno Leitao 
236d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 0x7fff,
237d39887f5SBreno Leitao 				 &val, &optlen));
238d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
239*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(val), optlen);
240*c8c2bd2bSBreno Leitao }
241*c8c2bd2bSBreno Leitao 
242*c8c2bd2bSBreno Leitao /* SO_VM_SOCKETS_CONNECT_TIMEOUT_{NEW,OLD} return a sock_timeval-shaped
243*c8c2bd2bSBreno Leitao  * payload, which is wider than u64 on 64-bit. They exercise the path
244*c8c2bd2bSBreno Leitao  * where the protocol's reported lv (16 bytes) is larger than the
245*c8c2bd2bSBreno Leitao  * common 8-byte u64 case covered above.
246*c8c2bd2bSBreno Leitao  */
247*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_new_exact)
248*c8c2bd2bSBreno Leitao {
249*c8c2bd2bSBreno Leitao 	struct __kernel_sock_timeval tv = {};
250*c8c2bd2bSBreno Leitao 	socklen_t optlen;
251*c8c2bd2bSBreno Leitao 
252*c8c2bd2bSBreno Leitao 	optlen = sizeof(tv);
253*c8c2bd2bSBreno Leitao 
254*c8c2bd2bSBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
255*c8c2bd2bSBreno Leitao 				SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
256*c8c2bd2bSBreno Leitao 				&tv, &optlen));
257*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(tv), optlen);
258*c8c2bd2bSBreno Leitao }
259*c8c2bd2bSBreno Leitao 
260*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_new_oversize_clamped)
261*c8c2bd2bSBreno Leitao {
262*c8c2bd2bSBreno Leitao 	char buf[sizeof(struct __kernel_sock_timeval) * 2] = {};
263*c8c2bd2bSBreno Leitao 	socklen_t optlen;
264*c8c2bd2bSBreno Leitao 
265*c8c2bd2bSBreno Leitao 	optlen = sizeof(buf);
266*c8c2bd2bSBreno Leitao 
267*c8c2bd2bSBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
268*c8c2bd2bSBreno Leitao 				SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
269*c8c2bd2bSBreno Leitao 				buf, &optlen));
270*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(struct __kernel_sock_timeval), optlen);
271*c8c2bd2bSBreno Leitao }
272*c8c2bd2bSBreno Leitao 
273*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_new_undersize)
274*c8c2bd2bSBreno Leitao {
275*c8c2bd2bSBreno Leitao 	socklen_t optlen;
276*c8c2bd2bSBreno Leitao 	uint64_t val;
277*c8c2bd2bSBreno Leitao 
278*c8c2bd2bSBreno Leitao 	optlen = sizeof(val);
279*c8c2bd2bSBreno Leitao 
280*c8c2bd2bSBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
281*c8c2bd2bSBreno Leitao 				 SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
282*c8c2bd2bSBreno Leitao 				 &val, &optlen));
283*c8c2bd2bSBreno Leitao 	ASSERT_EQ(EINVAL, errno);
284*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(val), optlen);
285*c8c2bd2bSBreno Leitao }
286*c8c2bd2bSBreno Leitao 
287*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_old_exact)
288*c8c2bd2bSBreno Leitao {
289*c8c2bd2bSBreno Leitao 	struct __kernel_old_timeval tv = {};
290*c8c2bd2bSBreno Leitao 	socklen_t optlen;
291*c8c2bd2bSBreno Leitao 
292*c8c2bd2bSBreno Leitao 	optlen = sizeof(tv);
293*c8c2bd2bSBreno Leitao 
294*c8c2bd2bSBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
295*c8c2bd2bSBreno Leitao 				SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD,
296*c8c2bd2bSBreno Leitao 				&tv, &optlen));
297*c8c2bd2bSBreno Leitao 	ASSERT_EQ(sizeof(tv), optlen);
298d39887f5SBreno Leitao }
299d39887f5SBreno Leitao 
300d39887f5SBreno Leitao TEST_HARNESS_MAIN
301