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
FIXTURE(scm_inq)14 FIXTURE(scm_inq)
15 {
16 int fd[2];
17 };
18
FIXTURE_VARIANT(scm_inq)19 FIXTURE_VARIANT(scm_inq)
20 {
21 int type;
22 };
23
FIXTURE_VARIANT_ADD(scm_inq,stream)24 FIXTURE_VARIANT_ADD(scm_inq, stream)
25 {
26 .type = SOCK_STREAM,
27 };
28
FIXTURE_VARIANT_ADD(scm_inq,dgram)29 FIXTURE_VARIANT_ADD(scm_inq, dgram)
30 {
31 .type = SOCK_DGRAM,
32 };
33
FIXTURE_VARIANT_ADD(scm_inq,seqpacket)34 FIXTURE_VARIANT_ADD(scm_inq, seqpacket)
35 {
36 .type = SOCK_SEQPACKET,
37 };
38
FIXTURE_SETUP(scm_inq)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
FIXTURE_TEARDOWN(scm_inq)47 FIXTURE_TEARDOWN(scm_inq)
48 {
49 close(self->fd[0]);
50 close(self->fd[1]);
51 }
52
send_chunks(struct __test_metadata * _metadata,FIXTURE_DATA (scm_inq)* self)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
recv_chunks(struct __test_metadata * _metadata,FIXTURE_DATA (scm_inq)* self)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
TEST_F(scm_inq,basic)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