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 (at) 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 (at) 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 53 char *TCID = __FILE__; 54 int TST_TOTAL = 9; 55 int TST_CNT = 0; 56 57 #define NUMADDR 6 58 #define SCTP_IP_LOOPBACK_I(I) htonl(0x7f000001 + I) 59 60 #define NIPQUAD(addr) \ 61 ((unsigned char *)&addr)[0], \ 62 ((unsigned char *)&addr)[1], \ 63 ((unsigned char *)&addr)[2], \ 64 ((unsigned char *)&addr)[3] 65 66 int 67 main(int argc, char *argv[]) 68 { 69 int svr_sk, clt_sk1, clt_sk2, peeloff_sk; 70 sctp_assoc_t associd, svr_associd1, svr_associd2, clt_associd1, clt_associd2; 71 struct iovec iov; 72 struct msghdr inmessage; 73 int error, i; 74 struct sctp_assoc_change *sac; 75 char *big_buffer; 76 int flags; 77 struct sockaddr_in svr_loop[NUMADDR]; 78 struct sockaddr_in svr_try[NUMADDR]; 79 struct sockaddr_in clt_loop1[NUMADDR]; 80 struct sockaddr_in clt_loop2[NUMADDR]; 81 struct sockaddr_in clt_loop3[NUMADDR]; 82 sockaddr_storage_t svr_test[NUMADDR], clt_test1[NUMADDR], clt_test2[NUMADDR]; 83 84 /* Rather than fflush() throughout the code, set stdout to 85 * be unbuffered. 86 */ 87 setvbuf(stdout, NULL, _IONBF, 0); 88 89 for (i = 0; i < NUMADDR; i++) { 90 /* Initialize the server and client addresses. */ 91 svr_loop[i].sin_family = AF_INET; 92 svr_loop[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); 93 svr_loop[i].sin_port = htons(SCTP_TESTPORT_1); 94 svr_test[i].v4.sin_family = AF_INET; 95 svr_test[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); 96 svr_test[i].v4.sin_port = htons(SCTP_TESTPORT_1); 97 svr_try[i].sin_family = AF_INET; 98 if (i < (NUMADDR-1)) { 99 svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); 100 } else { 101 /* Make last address invalid. */ 102 svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x400); 103 } 104 svr_try[i].sin_port = htons(SCTP_TESTPORT_1); 105 clt_loop1[i].sin_family = AF_INET; 106 clt_loop1[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100); 107 clt_loop1[i].sin_port = htons(SCTP_TESTPORT_2); 108 clt_test1[i].v4.sin_family = AF_INET; 109 clt_test1[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100); 110 clt_test1[i].v4.sin_port = htons(SCTP_TESTPORT_2); 111 clt_loop2[i].sin_family = AF_INET; 112 clt_loop2[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200); 113 clt_loop2[i].sin_port = htons(SCTP_TESTPORT_2+1); 114 clt_test2[i].v4.sin_family = AF_INET; 115 clt_test2[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200); 116 clt_test2[i].v4.sin_port = htons(SCTP_TESTPORT_2+1); 117 clt_loop3[i].sin_family = AF_INET; 118 clt_loop3[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x300); 119 clt_loop3[i].sin_port = htons(SCTP_TESTPORT_2+2); 120 } 121 122 /* Create and bind the server socket. */ 123 svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 124 test_bind(svr_sk, (struct sockaddr *)&svr_loop[0], sizeof(svr_loop[0])); 125 test_bindx_add(svr_sk, (struct sockaddr *)&svr_loop[1], NUMADDR-1); 126 127 /* Mark server socket as being able to accept new associations. */ 128 test_listen(svr_sk, 1); 129 130 /* Create and bind the client sockets. */ 131 clt_sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 132 test_bind(clt_sk1, (struct sockaddr *)&clt_loop1[0], sizeof(clt_loop1)); 133 test_bindx_add(clt_sk1, (struct sockaddr *)&clt_loop1[1], NUMADDR-1); 134 clt_sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 135 test_bind(clt_sk2, (struct sockaddr *)&clt_loop2[0], sizeof(clt_loop2)); 136 test_bindx_add(clt_sk2, (struct sockaddr *)&clt_loop2[1], NUMADDR-1); 137 138 /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ 139 test_enable_assoc_change(svr_sk); 140 test_enable_assoc_change(clt_sk1); 141 test_enable_assoc_change(clt_sk2); 142 143 /* Set clt_sk1 as non-blocking. */ 144 flags = fcntl(clt_sk1, F_GETFL, 0); 145 if (flags < 0) 146 tst_brkm(TBROK, tst_exit, "fcntl F_GETFL: %s", strerror(errno)); 147 if (fcntl(clt_sk1, F_SETFL, flags | O_NONBLOCK) < 0) 148 tst_brkm(TBROK, tst_exit, "fcntl F_SETFL: %s", strerror(errno)); 149 150 /* Do a non-blocking connectx from clt_sk1 to svr_sk */ 151 error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR, 152 &associd); 153 /* Non-blocking connectx should return immediately with EINPROGRESS. */ 154 if ((error != -1) || (EINPROGRESS != errno)) 155 tst_brkm(TBROK, tst_exit, "non-blocking connectx error: %d" 156 "errno:%d", error, errno); 157 158 tst_resm(TPASS, "non-blocking connectx"); 159 160 /* Doing a connectx on a socket to create an association that is 161 * is already established should return EISCONN. 162 */ 163 error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR, 164 NULL); 165 if ((error != -1) || (EISCONN != errno)) 166 tst_brkm(TBROK, tst_exit, "connectx on a socket to create an " 167 "assoc that is already established error:%d errno:%d", 168 error, errno); 169 170 tst_resm(TPASS, "connectx on a socket to create an assoc that is " 171 "already established"); 172 173 /* Initialize inmessage for all receives. */ 174 memset(&inmessage, 0, sizeof(inmessage)); 175 big_buffer = test_malloc(REALLY_BIG); 176 iov.iov_base = big_buffer; 177 iov.iov_len = REALLY_BIG; 178 inmessage.msg_iov = &iov; 179 inmessage.msg_iovlen = 1; 180 inmessage.msg_control = NULL; 181 182 /* Get COMM_UP on clt_sk1 */ 183 error = test_recvmsg(clt_sk1, &inmessage, MSG_WAITALL); 184 test_check_msg_notification(&inmessage, error, 185 sizeof(struct sctp_assoc_change), 186 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 187 sac = (struct sctp_assoc_change *)iov.iov_base; 188 clt_associd1 = sac->sac_assoc_id; 189 190 if (associd) { 191 if (associd != clt_associd1) 192 tst_brkm(TBROK, tst_exit, "Association id mismatch: " 193 "connectx returned %d, notification returned:%d", 194 associd, clt_associd1); 195 tst_resm(TPASS, "Association id match between sctp_connectx()" 196 " and notification."); 197 } 198 199 /* Get COMM_UP on svr_sk */ 200 error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); 201 test_check_msg_notification(&inmessage, error, 202 sizeof(struct sctp_assoc_change), 203 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 204 sac = (struct sctp_assoc_change *)iov.iov_base; 205 svr_associd1 = sac->sac_assoc_id; 206 207 /* Do a blocking connectx from clt_sk2 to svr_sk. 208 * Blocking connectx should block until the association is established 209 * and return success. 210 */ 211 test_connectx(clt_sk2, (struct sockaddr *)svr_try, NUMADDR); 212 213 /* Get COMM_UP on clt_sk2 */ 214 error = test_recvmsg(clt_sk2, &inmessage, MSG_WAITALL); 215 test_check_msg_notification(&inmessage, error, 216 sizeof(struct sctp_assoc_change), 217 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 218 sac = (struct sctp_assoc_change *)iov.iov_base; 219 clt_associd2 = sac->sac_assoc_id; 220 221 /* Get COMM_UP on svr_sk */ 222 error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); 223 test_check_msg_notification(&inmessage, error, 224 sizeof(struct sctp_assoc_change), 225 SCTP_ASSOC_CHANGE, SCTP_COMM_UP); 226 sac = (struct sctp_assoc_change *)iov.iov_base; 227 svr_associd2 = sac->sac_assoc_id; 228 229 tst_resm(TPASS, "blocking connectx"); 230 231 peeloff_sk = test_sctp_peeloff(svr_sk, svr_associd1); 232 233 /* Doing a connectx on a peeled off socket should fail. */ 234 error = sctp_connectx(peeloff_sk, (struct sockaddr *)clt_loop3, NUMADDR, 235 NULL); 236 if ((error != -1) || (EISCONN != errno)) 237 tst_brkm(TBROK, tst_exit, "connectx on a peeled off socket " 238 "error:%d, errno:%d", error, errno); 239 240 tst_resm(TPASS, "connectx on a peeled off socket"); 241 242 /* Trying to create an association on a socket that matches an 243 * existing peeled-off association should fail. 244 */ 245 error = sctp_connectx(svr_sk, (struct sockaddr *)clt_loop1, NUMADDR, 246 NULL); 247 if ((error != -1) || (EADDRNOTAVAIL != errno)) 248 tst_brkm(TBROK, tst_exit, "connectx to create an assoc that " 249 "matches a peeled off assoc error:%d errno:%d", 250 error, errno); 251 252 tst_resm(TPASS, "connectx to create an assoc that matches a peeled off " 253 "assoc"); 254 255 test_peer_addr(peeloff_sk, svr_associd1, clt_test1, NUMADDR); 256 tst_resm(TPASS, "server association 1 peers ok"); 257 test_peer_addr(svr_sk, svr_associd2, clt_test2, NUMADDR); 258 tst_resm(TPASS, "server association 2 peers ok"); 259 test_peer_addr(clt_sk1, clt_associd1, svr_test, NUMADDR); 260 tst_resm(TPASS, "client association 1 peers ok"); 261 test_peer_addr(clt_sk2, clt_associd2, svr_test, NUMADDR); 262 tst_resm(TPASS, "client association 2 peers ok"); 263 close(svr_sk); 264 close(clt_sk1); 265 close(clt_sk2); 266 close(peeloff_sk); 267 268 /* Indicate successful completion. */ 269 return 0; 270 } 271