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