1/* SCTP kernel Implementation 2 * (C) Copyright IBM Corp. 2002, 2003 3 * Copyright (c) 1999-2001 Motorola, Inc. 4 * 5 * The SCTP implementation is free software; 6 * you can redistribute it and/or modify it under the terms of 7 * the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * The SCTP implementation is distributed in the hope that it 12 * will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 * ************************ 14 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 * See the GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU CC; see the file COPYING. If not, write to 19 * the Free Software Foundation, 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 21 * 22 * Please send any bug reports or fixes you make to the 23 * email address(es): 24 * lksctp developers <lksctp-developers@lists.sourceforge.net> 25 * 26 * Or submit a bug report through the following website: 27 * http://www.sf.net/projects/lksctp 28 * 29 * Any bugs reported given to us we will try to fix... any fixes shared will 30 * be incorporated into the next SCTP release. 31 * 32 * Written or modified by: 33 * Sridhar Samudrala <sri@us.ibm.com> 34 */ 35 36/* This is a kernel test to verify the one-to-many style sctp_connectx() 37 * in blocking and non-blocking modes. 38 */ 39 40#include <stdio.h> 41#include <unistd.h> 42#include <stdlib.h> 43#include <string.h> 44#include <fcntl.h> 45#include <sys/types.h> 46#include <sys/socket.h> 47#include <sys/uio.h> 48#include <netinet/in.h> 49#include <errno.h> 50#include <netinet/sctp.h> 51#include <sctputil.h> 52#include "tst_kernel.h" 53 54char *TCID = __FILE__; 55int TST_TOTAL = 9; 56int TST_CNT = 0; 57 58#define NUMADDR 6 59#define SCTP_IP_LOOPBACK_I(I) htonl(0x7f000001 + I) 60 61#define NIPQUAD(addr) \ 62 ((unsigned char *)&addr)[0], \ 63 ((unsigned char *)&addr)[1], \ 64 ((unsigned char *)&addr)[2], \ 65 ((unsigned char *)&addr)[3] 66 67int 68main(void) 69{ 70 int svr_sk, clt_sk1, clt_sk2, peeloff_sk; 71 sctp_assoc_t associd, svr_associd1, svr_associd2, clt_associd1, clt_associd2; 72 struct iovec iov; 73 struct msghdr inmessage; 74 int error, i; 75 struct sctp_assoc_change *sac; 76 char *big_buffer; 77 int flags; 78 struct sockaddr_in svr_loop[NUMADDR]; 79 struct sockaddr_in svr_try[NUMADDR]; 80 struct sockaddr_in clt_loop1[NUMADDR]; 81 struct sockaddr_in clt_loop2[NUMADDR]; 82 struct sockaddr_in clt_loop3[NUMADDR]; 83 sockaddr_storage_t svr_test[NUMADDR], clt_test1[NUMADDR], clt_test2[NUMADDR]; 84 85 if (tst_check_driver("sctp")) 86 tst_brkm(TCONF, tst_exit, "sctp driver not available"); 87 88 /* Rather than fflush() throughout the code, set stdout to 89 * be unbuffered. 90 */ 91 setvbuf(stdout, NULL, _IONBF, 0); 92 93 for (i = 0; i < NUMADDR; i++) { 94 /* Initialize the server and client addresses. */ 95 svr_loop[i].sin_family = AF_INET; 96 svr_loop[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); 97 svr_loop[i].sin_port = htons(SCTP_TESTPORT_1); 98 svr_test[i].v4.sin_family = AF_INET; 99 svr_test[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); 100 svr_test[i].v4.sin_port = htons(SCTP_TESTPORT_1); 101 svr_try[i].sin_family = AF_INET; 102 if (i < (NUMADDR-1)) { 103 svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); 104 } else { 105 /* Make last address invalid. */ 106 svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x400); 107 } 108 svr_try[i].sin_port = htons(SCTP_TESTPORT_1); 109 clt_loop1[i].sin_family = AF_INET; 110 clt_loop1[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100); 111 clt_loop1[i].sin_port = htons(SCTP_TESTPORT_2); 112 clt_test1[i].v4.sin_family = AF_INET; 113 clt_test1[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100); 114 clt_test1[i].v4.sin_port = htons(SCTP_TESTPORT_2); 115 clt_loop2[i].sin_family = AF_INET; 116 clt_loop2[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200); 117 clt_loop2[i].sin_port = htons(SCTP_TESTPORT_2+1); 118 clt_test2[i].v4.sin_family = AF_INET; 119 clt_test2[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200); 120 clt_test2[i].v4.sin_port = htons(SCTP_TESTPORT_2+1); 121 clt_loop3[i].sin_family = AF_INET; 122 clt_loop3[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x300); 123 clt_loop3[i].sin_port = htons(SCTP_TESTPORT_2+2); 124 } 125 126 /* Create and bind the server socket. */ 127 svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 128 test_bind(svr_sk, (struct sockaddr *)&svr_loop[0], sizeof(svr_loop[0])); 129 test_bindx_add(svr_sk, (struct sockaddr *)&svr_loop[1], NUMADDR-1); 130 131 /* Mark server socket as being able to accept new associations. */ 132 test_listen(svr_sk, 1); 133 134 /* Create and bind the client sockets. */ 135 clt_sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 136 test_bind(clt_sk1, (struct sockaddr *)&clt_loop1[0], sizeof(clt_loop1)); 137 test_bindx_add(clt_sk1, (struct sockaddr *)&clt_loop1[1], NUMADDR-1); 138 clt_sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 139 test_bind(clt_sk2, (struct sockaddr *)&clt_loop2[0], sizeof(clt_loop2)); 140 test_bindx_add(clt_sk2, (struct sockaddr *)&clt_loop2[1], NUMADDR-1); 141 142 /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ 143 test_enable_assoc_change(svr_sk); 144 test_enable_assoc_change(clt_sk1); 145 test_enable_assoc_change(clt_sk2); 146 147 /* Set clt_sk1 as non-blocking. */ 148 flags = fcntl(clt_sk1, F_GETFL, 0); 149 if (flags < 0) 150 tst_brkm(TBROK, tst_exit, "fcntl F_GETFL: %s", strerror(errno)); 151 if (fcntl(clt_sk1, F_SETFL, flags | O_NONBLOCK) < 0) 152 tst_brkm(TBROK, tst_exit, "fcntl F_SETFL: %s", strerror(errno)); 153 154 /* Do a non-blocking connectx from clt_sk1 to svr_sk */ 155 error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR, 156 &associd); 157 /* Non-blocking connectx should return immediately with EINPROGRESS. */ 158 if ((error != -1) || (EINPROGRESS != errno)) 159 tst_brkm(TBROK, tst_exit, "non-blocking connectx error: %d " 160 "errno:%d", error, errno); 161 162 tst_resm(TPASS, "non-blocking connectx"); 163 164 /* Doing a connectx on a socket to create an association that is 165 * is already established should return EISCONN. 166 */ 167 error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR, 168 NULL); 169 if ((error != -1) || (EISCONN != errno)) 170 tst_brkm(TBROK, tst_exit, "connectx on a socket to create an " 171 "assoc that is already established error:%d errno:%d", 172 error, errno); 173 174 tst_resm(TPASS, "connectx on a socket to create an assoc that is " 175 "already established"); 176 177 /* Initialize inmessage for all receives. */ 178 memset(&inmessage, 0, sizeof(inmessage)); 179 big_buffer = test_malloc(REALLY_BIG); 180 iov.iov_base = big_buffer; 181 iov.iov_len = REALLY_BIG; 182 inmessage.msg_iov = &iov; 183 inmessage.msg_iovlen = 1; 184 inmessage.msg_control = NULL; 185 186 /* Get COMM_UP on clt_sk1 */ 187 error = test_recvmsg(clt_sk1, &inmessage, MSG_WAITALL); 188 test_check_msg_notification(&inmessage, error, 189 sizeof(struct sctp_assoc_change), 190 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 191 sac = (struct sctp_assoc_change *)iov.iov_base; 192 clt_associd1 = sac->sac_assoc_id; 193 194 if (associd) { 195 if (associd != clt_associd1) 196 tst_brkm(TBROK, tst_exit, "Association id mismatch: " 197 "connectx returned %d, notification returned:%d", 198 associd, clt_associd1); 199 tst_resm(TPASS, "Association id match between sctp_connectx()" 200 " and notification."); 201 } 202 203 /* Get COMM_UP on svr_sk */ 204 error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); 205 test_check_msg_notification(&inmessage, error, 206 sizeof(struct sctp_assoc_change), 207 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 208 sac = (struct sctp_assoc_change *)iov.iov_base; 209 svr_associd1 = sac->sac_assoc_id; 210 211 /* Do a blocking connectx from clt_sk2 to svr_sk. 212 * Blocking connectx should block until the association is established 213 * and return success. 214 */ 215 test_connectx(clt_sk2, (struct sockaddr *)svr_try, NUMADDR); 216 217 /* Get COMM_UP on clt_sk2 */ 218 error = test_recvmsg(clt_sk2, &inmessage, MSG_WAITALL); 219 test_check_msg_notification(&inmessage, error, 220 sizeof(struct sctp_assoc_change), 221 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 222 sac = (struct sctp_assoc_change *)iov.iov_base; 223 clt_associd2 = sac->sac_assoc_id; 224 225 /* Get COMM_UP on svr_sk */ 226 error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); 227 test_check_msg_notification(&inmessage, error, 228 sizeof(struct sctp_assoc_change), 229 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 230 sac = (struct sctp_assoc_change *)iov.iov_base; 231 svr_associd2 = sac->sac_assoc_id; 232 233 tst_resm(TPASS, "blocking connectx"); 234 235 peeloff_sk = test_sctp_peeloff(svr_sk, svr_associd1); 236 237 /* Doing a connectx on a peeled off socket should fail. */ 238 error = sctp_connectx(peeloff_sk, (struct sockaddr *)clt_loop3, NUMADDR, 239 NULL); 240 if ((error != -1) || (EISCONN != errno)) 241 tst_brkm(TBROK, tst_exit, "connectx on a peeled off socket " 242 "error:%d, errno:%d", error, errno); 243 244 tst_resm(TPASS, "connectx on a peeled off socket"); 245 246 /* Trying to create an association on a socket that matches an 247 * existing peeled-off association should fail. 248 */ 249 error = sctp_connectx(svr_sk, (struct sockaddr *)clt_loop1, NUMADDR, 250 NULL); 251 if ((error != -1) || (EADDRNOTAVAIL != errno)) 252 tst_brkm(TBROK, tst_exit, "connectx to create an assoc that " 253 "matches a peeled off assoc error:%d errno:%d", 254 error, errno); 255 256 tst_resm(TPASS, "connectx to create an assoc that matches a peeled off " 257 "assoc"); 258 259 test_peer_addr(peeloff_sk, svr_associd1, clt_test1, NUMADDR); 260 tst_resm(TPASS, "server association 1 peers ok"); 261 test_peer_addr(svr_sk, svr_associd2, clt_test2, NUMADDR); 262 tst_resm(TPASS, "server association 2 peers ok"); 263 test_peer_addr(clt_sk1, clt_associd1, svr_test, NUMADDR); 264 tst_resm(TPASS, "client association 1 peers ok"); 265 test_peer_addr(clt_sk2, clt_associd2, svr_test, NUMADDR); 266 tst_resm(TPASS, "client association 2 peers ok"); 267 close(svr_sk); 268 close(clt_sk1); 269 close(clt_sk2); 270 close(peeloff_sk); 271 272 /* Indicate successful completion. */ 273 return 0; 274} 275