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