xref: /linux/tools/testing/selftests/net/af_unix/scm_inq.c (revision d2b007374551ac09db16badde575cdd698f6fc92)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2025 Google LLC */
3 
4 #include <linux/sockios.h>
5 #include <sys/ioctl.h>
6 #include <sys/socket.h>
7 #include <sys/types.h>
8 
9 #include "../../kselftest_harness.h"
10 
11 #define NR_CHUNKS	100
12 #define MSG_LEN		256
13 
14 FIXTURE(scm_inq)
15 {
16 	int fd[2];
17 };
18 
19 FIXTURE_VARIANT(scm_inq)
20 {
21 	int type;
22 };
23 
24 FIXTURE_VARIANT_ADD(scm_inq, stream)
25 {
26 	.type = SOCK_STREAM,
27 };
28 
29 FIXTURE_VARIANT_ADD(scm_inq, dgram)
30 {
31 	.type = SOCK_DGRAM,
32 };
33 
34 FIXTURE_VARIANT_ADD(scm_inq, seqpacket)
35 {
36 	.type = SOCK_SEQPACKET,
37 };
38 
39 FIXTURE_SETUP(scm_inq)
40 {
41 	int err;
42 
43 	err = socketpair(AF_UNIX, variant->type | SOCK_NONBLOCK, 0, self->fd);
44 	ASSERT_EQ(0, err);
45 }
46 
47 FIXTURE_TEARDOWN(scm_inq)
48 {
49 	close(self->fd[0]);
50 	close(self->fd[1]);
51 }
52 
53 static void send_chunks(struct __test_metadata *_metadata,
54 			FIXTURE_DATA(scm_inq) *self)
55 {
56 	char buf[MSG_LEN] = {};
57 	int i, ret;
58 
59 	for (i = 0; i < NR_CHUNKS; i++) {
60 		ret = send(self->fd[0], buf, sizeof(buf), 0);
61 		ASSERT_EQ(sizeof(buf), ret);
62 	}
63 }
64 
65 static void recv_chunks(struct __test_metadata *_metadata,
66 			FIXTURE_DATA(scm_inq) *self)
67 {
68 	char cmsg_buf[CMSG_SPACE(sizeof(int))];
69 	struct msghdr msg = {};
70 	struct iovec iov = {};
71 	struct cmsghdr *cmsg;
72 	char buf[MSG_LEN];
73 	int i, ret;
74 	int inq;
75 
76 	msg.msg_iov = &iov;
77 	msg.msg_iovlen = 1;
78 	msg.msg_control = cmsg_buf;
79 	msg.msg_controllen = sizeof(cmsg_buf);
80 
81 	iov.iov_base = buf;
82 	iov.iov_len = sizeof(buf);
83 
84 	for (i = 0; i < NR_CHUNKS; i++) {
85 		memset(buf, 0, sizeof(buf));
86 		memset(cmsg_buf, 0, sizeof(cmsg_buf));
87 
88 		ret = recvmsg(self->fd[1], &msg, 0);
89 		ASSERT_EQ(MSG_LEN, ret);
90 
91 		cmsg = CMSG_FIRSTHDR(&msg);
92 		ASSERT_NE(NULL, cmsg);
93 		ASSERT_EQ(CMSG_LEN(sizeof(int)), cmsg->cmsg_len);
94 		ASSERT_EQ(SOL_SOCKET, cmsg->cmsg_level);
95 		ASSERT_EQ(SCM_INQ, cmsg->cmsg_type);
96 
97 		ret = ioctl(self->fd[1], SIOCINQ, &inq);
98 		ASSERT_EQ(0, ret);
99 		ASSERT_EQ(*(int *)CMSG_DATA(cmsg), inq);
100 	}
101 }
102 
103 TEST_F(scm_inq, basic)
104 {
105 	int err, inq;
106 
107 	err = setsockopt(self->fd[1], SOL_SOCKET, SO_INQ, &(int){1}, sizeof(int));
108 	if (variant->type != SOCK_STREAM) {
109 		ASSERT_EQ(-ENOPROTOOPT, -errno);
110 		return;
111 	}
112 
113 	ASSERT_EQ(0, err);
114 
115 	err = ioctl(self->fd[1], SIOCINQ, &inq);
116 	ASSERT_EQ(0, err);
117 	ASSERT_EQ(0, inq);
118 
119 	send_chunks(_metadata, self);
120 	recv_chunks(_metadata, self);
121 }
122 
123 TEST_HARNESS_MAIN
124