1// SPDX-License-Identifier: GPL-2.0-or-later 2 3/*\ 4 * Test recvmmsg() errors: 5 * 6 * - EBADF Bad socket file descriptor 7 * - EFAULT Bad message vector address 8 * - EINVAL Bad seconds value for the timeout argument 9 * - EINVAL Bad nanoseconds value for the timeout argument 10 * - EFAULT Bad timeout address 11 */ 12 13#define _GNU_SOURCE 14#include "../sendmmsg/sendmmsg.h" 15 16static int send_sockfd; 17static int receive_sockfd; 18 19#define VLEN 1 20 21static struct mmsghdr *msg; 22static struct iovec *iov; 23 24static void *bad_addr; 25static int bad_fd = -1; 26 27static struct tst_ts ts; 28 29struct test_case { 30 const char *desc; 31 int *fd; 32 long tv_sec; 33 long tv_nsec; 34 int exp_errno; 35 struct mmsghdr **msg_vec; 36 int bad_ts_addr; 37}; 38 39static struct test_case tcase[] = { 40 { 41 .desc = "bad socket file descriptor", 42 .fd = &bad_fd, 43 .exp_errno = EBADF, 44 .msg_vec = &msg, 45 }, 46 { 47 .desc = "bad message vector address", 48 .fd = &receive_sockfd, 49 .exp_errno = EFAULT, 50 .msg_vec = (void*)&bad_addr, 51 }, 52 { 53 .desc = "negative seconds in timeout", 54 .fd = &receive_sockfd, 55 .tv_sec = -1, 56 .tv_nsec = 0, 57 .exp_errno = EINVAL, 58 .msg_vec = &msg, 59 }, 60 { 61 .desc = "overflow in nanoseconds in timeout", 62 .fd = &receive_sockfd, 63 .tv_sec = 1, 64 .tv_nsec = 1000000001, 65 .exp_errno = EINVAL, 66 .msg_vec = &msg, 67 }, 68 { 69 .desc = "bad timeout address", 70 .fd = &receive_sockfd, 71 .exp_errno = EFAULT, 72 .msg_vec = &msg, 73 .bad_ts_addr = 1, 74 } 75}; 76 77static void do_test(unsigned int i) 78{ 79 struct time64_variants *tv = &variants[tst_variant]; 80 struct test_case *tc = &tcase[i]; 81 void *timeout; 82 83 ts.type = tv->ts_type; 84 tst_ts_set_sec(&ts, tc->tv_sec); 85 tst_ts_set_nsec(&ts, tc->tv_nsec); 86 87 if (tc->bad_ts_addr) 88 timeout = bad_addr; 89 else 90 timeout = tst_ts_get(&ts); 91 92 TST_EXP_FAIL2(tv->recvmmsg(*tc->fd, *tc->msg_vec, VLEN, 0, timeout), 93 tc->exp_errno, "recvmmsg() %s", tc->desc); 94} 95 96static void setup(void) 97{ 98 struct sockaddr_in addr; 99 unsigned int port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM); 100 struct time64_variants *tv = &variants[tst_variant]; 101 102 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); 103 104 send_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); 105 receive_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); 106 107 addr.sin_family = AF_INET; 108 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 109 addr.sin_port = port; 110 111 SAFE_BIND(receive_sockfd, (struct sockaddr *)&addr, sizeof(addr)); 112 SAFE_CONNECT(send_sockfd, (struct sockaddr *)&addr, sizeof(addr)); 113 114 msg[0].msg_hdr.msg_iov = iov; 115 msg[0].msg_hdr.msg_iovlen = 1; 116 117 TEST(tv->sendmmsg(send_sockfd, msg, 1, 0)); 118 119 if (TST_RET != 1) { 120 tst_res(TFAIL | TTERRNO, "sendmmsg() failed"); 121 return; 122 } 123 124 bad_addr = tst_get_bad_addr(NULL); 125} 126 127static void cleanup(void) 128{ 129 if (send_sockfd > 0) 130 SAFE_CLOSE(send_sockfd); 131 132 if (receive_sockfd > 0) 133 SAFE_CLOSE(receive_sockfd); 134} 135 136static struct tst_test test = { 137 .test = do_test, 138 .tcnt = ARRAY_SIZE(tcase), 139 .setup = setup, 140 .cleanup = cleanup, 141 .test_variants = ARRAY_SIZE(variants), 142 .bufs = (struct tst_buffers []) { 143 {&iov, .iov_sizes = (int[]){1, -1}}, 144 {&msg, .size = VLEN * sizeof(*msg)}, 145 {}, 146 } 147}; 148