1 /* SCTP kernel Implementation 2 * (C) Copyright IBM Corp. 2001, 2003 3 * Copyright (c) 1999-2000 Cisco, Inc. 4 * Copyright (c) 1999-2001 Motorola, Inc. 5 * Copyright (c) 2001 Intel Corp. 6 * Copyright (c) 2001 Nokia, Inc. 7 * 8 * The SCTP implementation is free software; 9 * you can redistribute it and/or modify it under the terms of 10 * the GNU General Public License as published by 11 * the Free Software Foundation; either version 2, or (at your option) 12 * any later version. 13 * 14 * The SCTP implementation is distributed in the hope that it 15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied 16 * ************************ 17 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 18 * See the GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with GNU CC; see the file COPYING. If not, write to 22 * the Free Software Foundation, 59 Temple Place - Suite 330, 23 * Boston, MA 02111-1307, USA. 24 * 25 * Please send any bug reports or fixes you make to the 26 * email address(es): 27 * lksctp developers <lksctp-developers (at) lists.sourceforge.net> 28 * 29 * Or submit a bug report through the following website: 30 * http://www.sf.net/projects/lksctp 31 * 32 * Any bugs reported to us we will try to fix... any fixes shared will 33 * be incorporated into the next SCTP release. 34 * 35 * Written or modified by: 36 * La Monte H.P. Yarroll <piggy (at) acm.org> 37 * Karl Knutson <karl (at) athena.chicago.il.us> 38 * Hui Huang <hui.huang (at) nokia.com> 39 * Jon Grimm <jgrimm (at) us.ibm.com> 40 * Sridhar Samudrala <sri (at) us.ibm.com> 41 */ 42 43 /* This is a functional test to verify the data fragmentation, reassembly 44 * support and SCTP_DISABLE_FRAGMENTS socket option. 45 * The following tests are done in sequence. 46 * - Verify SCTP_DISABLE_FRAGMENTS socket option by doing a setsockopt() 47 * followed by a getsockopt(). 48 * - Verify that a message size exceeding the association fragmentation 49 * point cannot be sent when fragmentation is disabled. 50 * - Send and receive a set of messages that are bigger than the path mtu. 51 * The different message sizes to be tested are specified in the array 52 * msg_sizes[]. 53 */ 54 55 #include <stdio.h> 56 #include <unistd.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <sys/types.h> 60 #include <sys/socket.h> 61 #include <sys/uio.h> 62 #include <netinet/in.h> 63 #include <sys/errno.h> 64 #include <errno.h> 65 #include <netinet/sctp.h> 66 #include <sctputil.h> 67 68 char *TCID = __FILE__; 69 int TST_TOTAL = 4; 70 int TST_CNT = 0; 71 72 int msg_sizes[] = {1353, 2000, 5000, 10000, 20000, 32768}; 73 74 int 75 main(int argc, char *argv[]) 76 { 77 int sk1, sk2; 78 sockaddr_storage_t loop1; 79 sockaddr_storage_t loop2; 80 struct iovec iov; 81 struct msghdr inmessage; 82 struct msghdr outmessage; 83 char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; 84 char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 85 struct cmsghdr *cmsg; 86 struct sctp_sndrcvinfo *sinfo; 87 struct iovec out_iov; 88 int error, bytes_sent; 89 int pf_class; 90 uint32_t ppid; 91 uint32_t stream; 92 char *big_buffer; 93 int msg_len, msg_cnt, i; 94 void *msg_buf; 95 int disable_frag; 96 socklen_t optlen; 97 98 /* Rather than fflush() throughout the code, set stdout to 99 * be unbuffered. 100 */ 101 setvbuf(stdout, NULL, _IONBF, 0); 102 103 /* Set some basic values which depend on the address family. */ 104 #if TEST_V6 105 pf_class = PF_INET6; 106 107 loop1.v6.sin6_family = AF_INET6; 108 loop1.v6.sin6_addr = in6addr_loopback; 109 loop1.v6.sin6_port = htons(SCTP_TESTPORT_1); 110 111 loop2.v6.sin6_family = AF_INET6; 112 loop2.v6.sin6_addr = in6addr_loopback; 113 loop2.v6.sin6_port = htons(SCTP_TESTPORT_2); 114 #else 115 pf_class = PF_INET; 116 117 loop1.v4.sin_family = AF_INET; 118 loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; 119 loop1.v4.sin_port = htons(SCTP_TESTPORT_1); 120 121 loop2.v4.sin_family = AF_INET; 122 loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; 123 loop2.v4.sin_port = htons(SCTP_TESTPORT_2); 124 #endif /* TEST_V6 */ 125 126 /* Create the two endpoints which will talk to each other. */ 127 sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); 128 sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); 129 130 /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ 131 test_enable_assoc_change(sk1); 132 test_enable_assoc_change(sk2); 133 134 /* Bind these sockets to the test ports. */ 135 test_bind(sk1, &loop1.sa, sizeof(loop1)); 136 test_bind(sk2, &loop2.sa, sizeof(loop2)); 137 138 /* Mark sk2 as being able to accept new associations. */ 139 test_listen(sk2, 1); 140 141 /* Send the first message. This will create the association. */ 142 outmessage.msg_name = &loop2; 143 outmessage.msg_namelen = sizeof(loop2); 144 outmessage.msg_iov = &out_iov; 145 outmessage.msg_iovlen = 1; 146 outmessage.msg_control = outcmsg; 147 outmessage.msg_controllen = sizeof(outcmsg); 148 outmessage.msg_flags = 0; 149 cmsg = CMSG_FIRSTHDR(&outmessage); 150 cmsg->cmsg_level = IPPROTO_SCTP; 151 cmsg->cmsg_type = SCTP_SNDRCV; 152 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 153 outmessage.msg_controllen = cmsg->cmsg_len; 154 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 155 memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); 156 ppid = rand(); /* Choose an arbitrary value. */ 157 stream = 1; 158 sinfo->sinfo_ppid = ppid; 159 sinfo->sinfo_stream = stream; 160 msg_len = 10; 161 msg_buf = test_build_msg(10); 162 outmessage.msg_iov->iov_base = msg_buf; 163 outmessage.msg_iov->iov_len = msg_len; 164 test_sendmsg(sk1, &outmessage, 0, msg_len); 165 166 167 /* Initialize inmessage for all receives. */ 168 big_buffer = test_malloc(REALLY_BIG); 169 memset(&inmessage, 0, sizeof(inmessage)); 170 iov.iov_base = big_buffer; 171 iov.iov_len = REALLY_BIG; 172 inmessage.msg_iov = &iov; 173 inmessage.msg_iovlen = 1; 174 inmessage.msg_control = incmsg; 175 176 /* Get the communication up message on sk2. */ 177 inmessage.msg_controllen = sizeof(incmsg); 178 error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); 179 test_check_msg_notification(&inmessage, error, 180 sizeof(struct sctp_assoc_change), 181 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 182 #if 0 183 sac = (struct sctp_assoc_change *)iov.iov_base; 184 associd2 = sac->sac_assoc_id; 185 #endif 186 /* Get the communication up message on sk1. */ 187 inmessage.msg_controllen = sizeof(incmsg); 188 error = test_recvmsg(sk1, &inmessage, MSG_WAITALL); 189 test_check_msg_notification(&inmessage, error, 190 sizeof(struct sctp_assoc_change), 191 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 192 #if 0 193 sac = (struct sctp_assoc_change *)iov.iov_base; 194 associd1 = sac->sac_assoc_id; 195 #endif 196 /* Get the first message which was sent. */ 197 inmessage.msg_controllen = sizeof(incmsg); 198 error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); 199 test_check_msg_data(&inmessage, error, msg_len, MSG_EOR, stream, ppid); 200 201 free(msg_buf); 202 203 /* Disable fragmentation. */ 204 disable_frag = 1; 205 test_setsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag, 206 sizeof(disable_frag)); 207 208 tst_resm(TPASS, "setsockopt(SCTP_DISABLE_FRAGMENTS)"); 209 210 /* Do a getsockopt() and verify that fragmentation is disabled. */ 211 disable_frag = 0; 212 optlen = sizeof(disable_frag); 213 error = test_getsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag, 214 &optlen); 215 if ((error != 0) && (disable_frag != 1)) 216 tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DISABLE_FRAGMENTS) " 217 "error:%d errno:%d disable_frag:%d", 218 error, errno, disable_frag); 219 220 tst_resm(TPASS, "getsockopt(SCTP_DISABLE_FRAGMENTS)"); 221 222 /* Try to send a messsage that exceeds association fragmentation point 223 * and verify that it fails. 224 */ 225 msg_len = 100000; 226 msg_buf = test_build_msg(msg_len); 227 outmessage.msg_iov->iov_base = msg_buf; 228 outmessage.msg_iov->iov_len = msg_len; 229 error = sendmsg(sk1, &outmessage, 0); 230 if ((error != -1) || (errno != EMSGSIZE)) 231 tst_brkm(TBROK, tst_exit, "Send a message that exceeds " 232 "assoc frag point error:%d errno:%d", error, errno); 233 234 tst_resm(TPASS, "Send a message that exceeds assoc frag point"); 235 236 /* Enable Fragmentation. */ 237 disable_frag = 0; 238 test_setsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag, 239 sizeof(disable_frag)); 240 241 msg_cnt = sizeof(msg_sizes) / sizeof(int); 242 243 /* Send and receive the messages of different sizes specified in the 244 * msg_sizes array in a loop. 245 */ 246 for (i = 0; i < msg_cnt; i++) { 247 248 msg_len = msg_sizes[i]; 249 msg_buf = test_build_msg(msg_len); 250 outmessage.msg_iov->iov_base = msg_buf; 251 outmessage.msg_iov->iov_len = msg_len; 252 bytes_sent = test_sendmsg(sk1, &outmessage, 0, msg_len); 253 254 tst_resm(TINFO, "Sent %d byte message", bytes_sent); 255 256 inmessage.msg_controllen = sizeof(incmsg); 257 error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); 258 /* Handle Partial Reads. */ 259 if (inmessage.msg_flags & MSG_EOR) { 260 test_check_msg_data(&inmessage, error, bytes_sent, 261 MSG_EOR, stream, ppid); 262 tst_resm(TINFO, "Received %d byte message", error); 263 } else { 264 int remain; 265 266 test_check_msg_data(&inmessage, error, error, 0, 267 stream, ppid); 268 tst_resm(TINFO, "Received %d byte message", error); 269 270 /* Read the remaining message. */ 271 inmessage.msg_controllen = sizeof(incmsg); 272 remain = test_recvmsg(sk2, &inmessage, MSG_WAITALL); 273 test_check_msg_data(&inmessage, remain, 274 bytes_sent - error, 275 MSG_EOR, stream, ppid); 276 tst_resm(TINFO, "Received %d byte message", error); 277 } 278 279 free(msg_buf); 280 } 281 282 tst_resm(TPASS, "Send/Receive fragmented messages"); 283 284 /* Shut down the link. */ 285 close(sk1); 286 287 /* Get the shutdown complete notification. */ 288 inmessage.msg_controllen = sizeof(incmsg); 289 error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); 290 test_check_msg_notification(&inmessage, error, 291 sizeof(struct sctp_assoc_change), 292 SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); 293 294 close(sk2); 295 296 /* Indicate successful completion. */ 297 return 0; 298 } 299