1 /* 2 * Copyright (c) 2016 Cyril Hrubis <chrubis (at) suse.cz> 3 * Copyright (c) 2016 Michal Kubecek <mkubecek (at) suse.cz> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 /* 20 * This is a regression test for kernel commit: 21 * 22 * 197c949e7798 udp: properly support MSG_PEEK with truncated buffers 23 * 24 * NOTE: The testcase will hang on upatched stable kernel. 25 */ 26 27 #include <string.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 35 #include "tst_test.h" 36 #include "lapi/socket.h" 37 38 static const char msg[] = "Michael Gilfix was here\341\210\264\r\n"; 39 static const unsigned msglen = ARRAY_SIZE(msg) - 1; 40 static unsigned char buff[25]; 41 static const int bufflen = ARRAY_SIZE(buff); 42 43 static int sdr, sdw; 44 45 static void verify_recvmsg(void) 46 { 47 struct sockaddr_in6 addr_init = { 48 .sin6_family = AF_INET6, 49 .sin6_port = htons(0), 50 .sin6_addr = IN6ADDR_LOOPBACK_INIT, 51 }; 52 struct sockaddr_in6 addr_r, addr_w, addr_f; 53 socklen_t addrlen_r, addrlen_w; 54 struct iovec iov = { 55 .iov_base = buff, 56 .iov_len = sizeof(buff), 57 }; 58 struct msghdr msghdr = { 59 .msg_name = &addr_f, 60 .msg_namelen = sizeof(addr_f), 61 .msg_iov = &iov, 62 .msg_iovlen = 1, 63 .msg_control = NULL, 64 .msg_controllen = 0, 65 .msg_flags = 0, 66 }; 67 int R; 68 69 sdr = SAFE_SOCKET(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP); 70 SAFE_BIND(sdr, (struct sockaddr*)&addr_init, sizeof(addr_init)); 71 addrlen_r = sizeof(addr_r); 72 SAFE_GETSOCKNAME(sdr, (struct sockaddr*)&addr_r, &addrlen_r); 73 sdw = SAFE_SOCKET(PF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP); 74 SAFE_BIND(sdw, (struct sockaddr*)&addr_init, sizeof(addr_init)); 75 addrlen_w = sizeof(addr_w); 76 SAFE_GETSOCKNAME(sdw, (struct sockaddr*)&addr_w, &addrlen_w); 77 78 R = sendto(sdw, msg, msglen, 0, (struct sockaddr*)&addr_r, addrlen_r); 79 if (R < 0) 80 tst_brk(TBROK | TERRNO, "sendto()"); 81 82 R = recvmsg(sdr, &msghdr, MSG_PEEK); 83 if (R < 0) { 84 tst_res(TFAIL | TERRNO, "recvmsg(..., MSG_PEEK)"); 85 return; 86 } 87 88 tst_res(TINFO, "received %d bytes", R); 89 90 if ((R == bufflen) && !memcmp(msg, buff, R)) 91 tst_res(TPASS, "recvmsg(..., MSG_PEEK) works fine"); 92 else 93 tst_res(TPASS, "recvmsg(..., MSG_PEEK) failed"); 94 95 SAFE_CLOSE(sdw); 96 SAFE_CLOSE(sdr); 97 } 98 99 static void cleanup(void) 100 { 101 if (sdw > 0 && close(sdw)) 102 tst_res(TWARN | TERRNO, "close(sdw) failed"); 103 104 if (sdr > 0 && close(sdr)) 105 tst_res(TWARN | TERRNO, "close(sdr) failed"); 106 } 107 108 static struct tst_test test = { 109 .tid = "recvmsg02", 110 .min_kver = "2.6.27", 111 .test_all = verify_recvmsg, 112 .cleanup = cleanup, 113 }; 114