xref: /linux/tools/testing/selftests/net/getsockopt_iter.c (revision d39887f55d8edaacdb4fbc4cbfecff31dec1dc6a)
1*d39887f5SBreno Leitao // SPDX-License-Identifier: GPL-2.0
2*d39887f5SBreno Leitao /*
3*d39887f5SBreno Leitao  * Quick test for getsockopt{_iter} tests.
4*d39887f5SBreno Leitao  *
5*d39887f5SBreno Leitao  * Each fixture targets one converted protocol and pins down the
6*d39887f5SBreno Leitao  * returned-length / errno semantics across buffer-size variations,
7*d39887f5SBreno Leitao  * an unknown optname and a bogus level.
8*d39887f5SBreno Leitao  *
9*d39887f5SBreno Leitao  * - netlink: NETLINK_PKTINFO covers the flag-style int path; the
10*d39887f5SBreno Leitao  *   NETLINK_LIST_MEMBERSHIPS cases cover the size-discovery path
11*d39887f5SBreno Leitao  *   that always reports the required buffer length back via optlen,
12*d39887f5SBreno Leitao  *   even when the user buffer is too small to receive any group bits.
13*d39887f5SBreno Leitao  * - vsock:   SO_VM_SOCKETS_BUFFER_SIZE covers the u64 path.
14*d39887f5SBreno Leitao  *
15*d39887f5SBreno Leitao  * Author: Breno Leitao <leitao@debian.org>
16*d39887f5SBreno Leitao  */
17*d39887f5SBreno Leitao 
18*d39887f5SBreno Leitao #include <errno.h>
19*d39887f5SBreno Leitao #include <stdint.h>
20*d39887f5SBreno Leitao #include <stdio.h>
21*d39887f5SBreno Leitao #include <string.h>
22*d39887f5SBreno Leitao #include <unistd.h>
23*d39887f5SBreno Leitao #include <linux/netlink.h>
24*d39887f5SBreno Leitao #include <linux/rtnetlink.h>
25*d39887f5SBreno Leitao #include <linux/vm_sockets.h>
26*d39887f5SBreno Leitao #include <sys/socket.h>
27*d39887f5SBreno Leitao #include "kselftest_harness.h"
28*d39887f5SBreno Leitao 
29*d39887f5SBreno Leitao #ifndef AF_VSOCK
30*d39887f5SBreno Leitao #define AF_VSOCK 40
31*d39887f5SBreno Leitao #endif
32*d39887f5SBreno Leitao 
33*d39887f5SBreno Leitao /* ---------- netlink ---------- */
34*d39887f5SBreno Leitao 
35*d39887f5SBreno Leitao FIXTURE(netlink)
36*d39887f5SBreno Leitao {
37*d39887f5SBreno Leitao 	int fd;
38*d39887f5SBreno Leitao };
39*d39887f5SBreno Leitao 
40*d39887f5SBreno Leitao FIXTURE_SETUP(netlink)
41*d39887f5SBreno Leitao {
42*d39887f5SBreno Leitao 	int group = RTNLGRP_LINK;
43*d39887f5SBreno Leitao 
44*d39887f5SBreno Leitao 	self->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
45*d39887f5SBreno Leitao 	if (self->fd < 0)
46*d39887f5SBreno Leitao 		SKIP(return, "AF_NETLINK socket: %s", strerror(errno));
47*d39887f5SBreno Leitao 
48*d39887f5SBreno Leitao 	/* Joining a multicast group grows nlk->ngroups so the
49*d39887f5SBreno Leitao 	 * NETLINK_LIST_MEMBERSHIPS path has a non-zero size to report.
50*d39887f5SBreno Leitao 	 */
51*d39887f5SBreno Leitao 	if (setsockopt(self->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
52*d39887f5SBreno Leitao 		       &group, sizeof(group)) < 0)
53*d39887f5SBreno Leitao 		SKIP(return, "NETLINK_ADD_MEMBERSHIP: %s", strerror(errno));
54*d39887f5SBreno Leitao }
55*d39887f5SBreno Leitao 
56*d39887f5SBreno Leitao FIXTURE_TEARDOWN(netlink)
57*d39887f5SBreno Leitao {
58*d39887f5SBreno Leitao 	if (self->fd >= 0)
59*d39887f5SBreno Leitao 		close(self->fd);
60*d39887f5SBreno Leitao }
61*d39887f5SBreno Leitao 
62*d39887f5SBreno Leitao TEST_F(netlink, pktinfo_exact)
63*d39887f5SBreno Leitao {
64*d39887f5SBreno Leitao 	int val = -1;
65*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(val);
66*d39887f5SBreno Leitao 
67*d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
68*d39887f5SBreno Leitao 				&val, &optlen));
69*d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(int), optlen);
70*d39887f5SBreno Leitao 	ASSERT_TRUE(val == 0 || val == 1);
71*d39887f5SBreno Leitao }
72*d39887f5SBreno Leitao 
73*d39887f5SBreno Leitao TEST_F(netlink, pktinfo_oversize_clamped)
74*d39887f5SBreno Leitao {
75*d39887f5SBreno Leitao 	char buf[16] = {};
76*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(buf);
77*d39887f5SBreno Leitao 
78*d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
79*d39887f5SBreno Leitao 				buf, &optlen));
80*d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(int), optlen);
81*d39887f5SBreno Leitao }
82*d39887f5SBreno Leitao 
83*d39887f5SBreno Leitao TEST_F(netlink, pktinfo_undersize)
84*d39887f5SBreno Leitao {
85*d39887f5SBreno Leitao 	char buf[2] = {};
86*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(buf);
87*d39887f5SBreno Leitao 
88*d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
89*d39887f5SBreno Leitao 				 buf, &optlen));
90*d39887f5SBreno Leitao 	ASSERT_EQ(EINVAL, errno);
91*d39887f5SBreno Leitao }
92*d39887f5SBreno Leitao 
93*d39887f5SBreno Leitao TEST_F(netlink, list_memberships_size_discovery)
94*d39887f5SBreno Leitao {
95*d39887f5SBreno Leitao 	socklen_t optlen = 0;
96*d39887f5SBreno Leitao 	char dummy;
97*d39887f5SBreno Leitao 
98*d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
99*d39887f5SBreno Leitao 				NETLINK_LIST_MEMBERSHIPS,
100*d39887f5SBreno Leitao 				&dummy, &optlen));
101*d39887f5SBreno Leitao 	ASSERT_GT(optlen, 0);
102*d39887f5SBreno Leitao 	ASSERT_EQ(0, optlen % sizeof(__u32));
103*d39887f5SBreno Leitao }
104*d39887f5SBreno Leitao 
105*d39887f5SBreno Leitao TEST_F(netlink, list_memberships_full_read)
106*d39887f5SBreno Leitao {
107*d39887f5SBreno Leitao 	__u32 buf[64] = {};
108*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(buf);
109*d39887f5SBreno Leitao 
110*d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
111*d39887f5SBreno Leitao 				NETLINK_LIST_MEMBERSHIPS,
112*d39887f5SBreno Leitao 				buf, &optlen));
113*d39887f5SBreno Leitao 	ASSERT_GT(optlen, 0);
114*d39887f5SBreno Leitao 	ASSERT_LE(optlen, sizeof(buf));
115*d39887f5SBreno Leitao 	ASSERT_EQ(0, optlen % sizeof(__u32));
116*d39887f5SBreno Leitao }
117*d39887f5SBreno Leitao 
118*d39887f5SBreno Leitao TEST_F(netlink, bad_level)
119*d39887f5SBreno Leitao {
120*d39887f5SBreno Leitao 	int val;
121*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(val);
122*d39887f5SBreno Leitao 
123*d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1, NETLINK_PKTINFO,
124*d39887f5SBreno Leitao 				 &val, &optlen));
125*d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
126*d39887f5SBreno Leitao }
127*d39887f5SBreno Leitao 
128*d39887f5SBreno Leitao TEST_F(netlink, bad_optname)
129*d39887f5SBreno Leitao {
130*d39887f5SBreno Leitao 	int val;
131*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(val);
132*d39887f5SBreno Leitao 
133*d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, 0x7fff,
134*d39887f5SBreno Leitao 				 &val, &optlen));
135*d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
136*d39887f5SBreno Leitao }
137*d39887f5SBreno Leitao 
138*d39887f5SBreno Leitao /* ---------- vsock ---------- */
139*d39887f5SBreno Leitao 
140*d39887f5SBreno Leitao FIXTURE(vsock)
141*d39887f5SBreno Leitao {
142*d39887f5SBreno Leitao 	int fd;
143*d39887f5SBreno Leitao };
144*d39887f5SBreno Leitao 
145*d39887f5SBreno Leitao FIXTURE_SETUP(vsock)
146*d39887f5SBreno Leitao {
147*d39887f5SBreno Leitao 	self->fd = socket(AF_VSOCK, SOCK_STREAM, 0);
148*d39887f5SBreno Leitao 	if (self->fd < 0)
149*d39887f5SBreno Leitao 		SKIP(return, "AF_VSOCK socket: %s", strerror(errno));
150*d39887f5SBreno Leitao }
151*d39887f5SBreno Leitao 
152*d39887f5SBreno Leitao FIXTURE_TEARDOWN(vsock)
153*d39887f5SBreno Leitao {
154*d39887f5SBreno Leitao 	if (self->fd >= 0)
155*d39887f5SBreno Leitao 		close(self->fd);
156*d39887f5SBreno Leitao }
157*d39887f5SBreno Leitao 
158*d39887f5SBreno Leitao TEST_F(vsock, buffer_size_exact)
159*d39887f5SBreno Leitao {
160*d39887f5SBreno Leitao 	uint64_t val = 0;
161*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(val);
162*d39887f5SBreno Leitao 
163*d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
164*d39887f5SBreno Leitao 				SO_VM_SOCKETS_BUFFER_SIZE,
165*d39887f5SBreno Leitao 				&val, &optlen));
166*d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(uint64_t), optlen);
167*d39887f5SBreno Leitao 	ASSERT_GT(val, 0);
168*d39887f5SBreno Leitao }
169*d39887f5SBreno Leitao 
170*d39887f5SBreno Leitao TEST_F(vsock, buffer_size_oversize_clamped)
171*d39887f5SBreno Leitao {
172*d39887f5SBreno Leitao 	char buf[16] = {};
173*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(buf);
174*d39887f5SBreno Leitao 
175*d39887f5SBreno Leitao 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
176*d39887f5SBreno Leitao 				SO_VM_SOCKETS_BUFFER_SIZE,
177*d39887f5SBreno Leitao 				buf, &optlen));
178*d39887f5SBreno Leitao 	ASSERT_EQ(sizeof(uint64_t), optlen);
179*d39887f5SBreno Leitao }
180*d39887f5SBreno Leitao 
181*d39887f5SBreno Leitao TEST_F(vsock, buffer_size_undersize)
182*d39887f5SBreno Leitao {
183*d39887f5SBreno Leitao 	char buf[4] = {};
184*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(buf);
185*d39887f5SBreno Leitao 
186*d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
187*d39887f5SBreno Leitao 				 SO_VM_SOCKETS_BUFFER_SIZE,
188*d39887f5SBreno Leitao 				 buf, &optlen));
189*d39887f5SBreno Leitao 	ASSERT_EQ(EINVAL, errno);
190*d39887f5SBreno Leitao }
191*d39887f5SBreno Leitao 
192*d39887f5SBreno Leitao TEST_F(vsock, bad_level)
193*d39887f5SBreno Leitao {
194*d39887f5SBreno Leitao 	uint64_t val;
195*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(val);
196*d39887f5SBreno Leitao 
197*d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1,
198*d39887f5SBreno Leitao 				 SO_VM_SOCKETS_BUFFER_SIZE,
199*d39887f5SBreno Leitao 				 &val, &optlen));
200*d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
201*d39887f5SBreno Leitao }
202*d39887f5SBreno Leitao 
203*d39887f5SBreno Leitao TEST_F(vsock, bad_optname)
204*d39887f5SBreno Leitao {
205*d39887f5SBreno Leitao 	uint64_t val;
206*d39887f5SBreno Leitao 	socklen_t optlen = sizeof(val);
207*d39887f5SBreno Leitao 
208*d39887f5SBreno Leitao 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 0x7fff,
209*d39887f5SBreno Leitao 				 &val, &optlen));
210*d39887f5SBreno Leitao 	ASSERT_EQ(ENOPROTOOPT, errno);
211*d39887f5SBreno Leitao }
212*d39887f5SBreno Leitao 
213*d39887f5SBreno Leitao TEST_HARNESS_MAIN
214