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