1 /* SCTP kernel Implementation 2 * (C) Copyright IBM Corp. 2001, 2003 3 * Copyright (C) 1999 Cisco 4 * Copyright (C) 1999-2000 Motorola 5 # Copyright (C) 2001 Nokia 6 * Copyright (C) 2001 La Monte H.P. Yarroll 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 * Narasimha Budihal <narsi (at) refcode.org> 38 * Karl Knutson <karl (at) athena.chicago.il.us> 39 * Jon Grimm <jgrimm (at) us.ibm.com> 40 * Daisy Chang <daisyc (at) us.ibm.com> 41 * Sridhar Samudrala <sri (at) us.ibm.com> 42 */ 43 44 #include <stdio.h> 45 #include <errno.h> 46 #include <ctype.h> 47 #include <string.h> 48 #include <sys/types.h> 49 #include <sys/socket.h> 50 #include <sys/uio.h> 51 #include <netinet/in.h> 52 #include <sys/errno.h> 53 #include <errno.h> 54 #include <malloc.h> 55 #include "netinet/sctp.h" 56 #include "sctputil.h" 57 58 /* This function prints the cmsg data. */ 59 void 60 test_print_cmsg(sctp_cmsg_t type, sctp_cmsg_data_t *data) 61 { 62 switch(type) { 63 case SCTP_INIT: 64 printf("INIT\n"); 65 printf(" sinit_num_ostreams %d\n", 66 data->init.sinit_num_ostreams); 67 printf(" sinit_max_instreams %d\n", 68 data->init.sinit_max_instreams); 69 printf(" sinit_max_attempts %d\n", 70 data->init.sinit_max_attempts); 71 printf(" sinit_max_init_timeo %d\n", 72 data->init.sinit_max_init_timeo); 73 74 break; 75 case SCTP_SNDRCV: 76 printf("SNDRCV\n"); 77 printf(" sinfo_stream %u\n", data->sndrcv.sinfo_stream); 78 printf(" sinfo_ssn %u\n", data->sndrcv.sinfo_ssn); 79 printf(" sinfo_flags 0x%x\n", data->sndrcv.sinfo_flags); 80 printf(" sinfo_ppid %u\n", data->sndrcv.sinfo_ppid); 81 printf(" sinfo_context %x\n", data->sndrcv.sinfo_context); 82 printf(" sinfo_tsn %u\n", data->sndrcv.sinfo_tsn); 83 printf(" sinfo_cumtsn %u\n", data->sndrcv.sinfo_cumtsn); 84 printf(" sinfo_assoc_id %u\n", data->sndrcv.sinfo_assoc_id); 85 86 break; 87 88 default: 89 printf("UNKNOWN CMSG: %d\n", type); 90 break; 91 } 92 } 93 94 /* This function prints the message. */ 95 void 96 test_print_message(int sk, struct msghdr *msg, size_t msg_len) 97 { 98 sctp_cmsg_data_t *data; 99 struct cmsghdr *cmsg; 100 int i; 101 int done = 0; 102 char save; 103 union sctp_notification *sn; 104 105 for (cmsg = CMSG_FIRSTHDR(msg); 106 cmsg != NULL; 107 cmsg = CMSG_NXTHDR(msg, cmsg)) { 108 data = (sctp_cmsg_data_t *)CMSG_DATA(cmsg); 109 test_print_cmsg(cmsg->cmsg_type, data); 110 } 111 112 if (!(MSG_NOTIFICATION & msg->msg_flags)) { 113 int index = 0; 114 /* Make sure that everything is printable and that we 115 * are NUL terminated... 116 */ 117 printf("DATA(%d): ", msg_len); 118 while ( msg_len > 0 ) { 119 char *text; 120 int len; 121 122 text = msg->msg_iov[index].iov_base; 123 len = msg->msg_iov[index].iov_len; 124 125 save = text[msg_len-1]; 126 if ( len > msg_len ) { 127 text[(len = msg_len) - 1] = '\0'; 128 } 129 130 if ( (msg_len -= len) > 0 ) { index++; } 131 132 for (i = 0; i < len - 1; ++i) { 133 if (!isprint(text[i])) text[i] = '.'; 134 } 135 136 printf("%s", text); 137 text[msg_len-1] = save; 138 139 if ( (done = !strcmp(text, "exit")) ) { break; } 140 } 141 } else { 142 printf("NOTIFICATION: "); 143 sn = (union sctp_notification *)msg->msg_iov[0].iov_base; 144 switch (sn->sn_header.sn_type) { 145 case SCTP_ASSOC_CHANGE: 146 switch (sn->sn_assoc_change.sac_state) { 147 case SCTP_COMM_UP: 148 printf("ASSOC_CHANGE - COMM_UP"); 149 break; 150 case SCTP_COMM_LOST: 151 printf("ASSOC_CHANGE - COMM_LOST"); 152 break; 153 case SCTP_RESTART: 154 printf("ASSOC_CHANGE - RESTART"); 155 break; 156 case SCTP_SHUTDOWN_COMP: 157 printf("ASSOC_CHANGE - SHUTDOWN_COMP"); 158 break; 159 case SCTP_CANT_STR_ASSOC: 160 printf("ASSOC_CHANGE - CANT_STR_ASSOC"); 161 break; 162 default: 163 printf("ASSOC_CHANGE - UNEXPECTED(%d)", 164 sn->sn_assoc_change.sac_state); 165 break; 166 } 167 break; 168 default: 169 printf("%d", sn->sn_header.sn_type); 170 break; 171 } 172 } 173 174 printf("\n"); 175 } 176 177 /* Check if a buf/msg_flags matches a notification, its type, and possibly an 178 * additional field in the corresponding notification structure. 179 */ 180 void 181 test_check_buf_notification(void *buf, int datalen, int msg_flags, 182 int expected_datalen, uint16_t expected_sn_type, 183 uint32_t expected_additional) 184 { 185 union sctp_notification *sn; 186 187 if (!(msg_flags & MSG_NOTIFICATION)) 188 tst_brkm(TBROK, tst_exit, 189 "Got a datamsg, expecting notification"); 190 191 if (expected_datalen <= 0) 192 return; 193 194 if (datalen != expected_datalen) 195 tst_brkm(TBROK, tst_exit, 196 "Got a notification of unexpected length:%d, expected length:%d", 197 datalen, expected_datalen); 198 199 sn = (union sctp_notification *)buf; 200 if (sn->sn_header.sn_type != expected_sn_type) 201 tst_brkm(TBROK, tst_exit, 202 "Unexpected notification:%d expected:%d", 203 sn->sn_header.sn_type, expected_sn_type); 204 205 switch(sn->sn_header.sn_type){ 206 case SCTP_ASSOC_CHANGE: 207 if (sn->sn_assoc_change.sac_state != expected_additional) 208 tst_brkm(TBROK, tst_exit, 209 "Unexpected sac_state:%d expected:%d", 210 sn->sn_assoc_change.sac_state, expected_additional); 211 break; 212 default: 213 break; 214 } 215 } 216 217 /* Check if a message matches a notification, its type, and possibly an 218 * additional field in the corresponding notification structure. 219 */ 220 void 221 test_check_msg_notification(struct msghdr *msg, int datalen, 222 int expected_datalen, uint16_t expected_sn_type, 223 uint32_t expected_additional) 224 { 225 test_check_buf_notification(msg->msg_iov[0].iov_base, datalen, 226 msg->msg_flags, expected_datalen, 227 expected_sn_type, expected_additional); 228 } 229 230 /* Check if a buf/msg_flags/sinfo corresponds to data, its length, msg_flags, 231 * stream and ppid. 232 */ 233 void 234 test_check_buf_data(void *buf, int datalen, int msg_flags, 235 struct sctp_sndrcvinfo *sinfo, int expected_datalen, 236 int expected_msg_flags, uint16_t expected_stream, 237 uint32_t expected_ppid) 238 { 239 if (msg_flags & MSG_NOTIFICATION) 240 tst_brkm(TBROK, tst_exit, 241 "Got a notification, expecting a datamsg"); 242 243 if (expected_datalen <= 0) 244 return; 245 246 if (datalen != expected_datalen) 247 tst_brkm(TBROK, tst_exit, 248 "Got a datamsg of unexpected length:%d, expected length:%d", 249 datalen, expected_datalen); 250 251 if ((msg_flags & ~0x80000000) != expected_msg_flags) 252 tst_brkm(TBROK, tst_exit, 253 "Unexpected msg_flags:0x%x expecting:0x%x", 254 msg_flags, expected_msg_flags); 255 256 if ((0 == expected_stream) && (0 == expected_ppid)) 257 return; 258 259 if (!sinfo) 260 tst_brkm(TBROK, tst_exit, 261 "Null sinfo, but expected stream:%d expected ppid:%d", 262 expected_stream, expected_ppid); 263 264 if (sinfo->sinfo_stream != expected_stream) 265 tst_brkm(TBROK, tst_exit, 266 "stream mismatch: expected:%x got:%x", 267 expected_stream, sinfo->sinfo_stream); 268 if (sinfo->sinfo_ppid != expected_ppid) 269 tst_brkm(TBROK, tst_exit, 270 "ppid mismatch: expected:%x got:%x\n", 271 expected_ppid, sinfo->sinfo_ppid); 272 } 273 274 /* Check if a message corresponds to data, its length, msg_flags, stream and 275 * ppid. 276 */ 277 void 278 test_check_msg_data(struct msghdr *msg, int datalen, int expected_datalen, 279 int expected_msg_flags, uint16_t expected_stream, 280 uint32_t expected_ppid) 281 { 282 struct cmsghdr *cmsg = NULL; 283 struct sctp_sndrcvinfo *sinfo = NULL; 284 285 /* Receive auxiliary data in msgh. */ 286 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 287 cmsg = CMSG_NXTHDR(msg, cmsg)){ 288 if (IPPROTO_SCTP == cmsg->cmsg_level && 289 SCTP_SNDRCV == cmsg->cmsg_type) 290 break; 291 } /* for( all cmsgs) */ 292 293 if ((!cmsg) || 294 (cmsg->cmsg_len < CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))) 295 sinfo = NULL; 296 else 297 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 298 299 test_check_buf_data(msg->msg_iov[0].iov_base, datalen, msg->msg_flags, 300 sinfo, expected_datalen, expected_msg_flags, 301 expected_stream, expected_ppid); 302 303 } 304 305 306 /* Allocate a buffer of requested len and fill in with data. */ 307 void * 308 test_build_msg(int len) 309 { 310 int i = len - 1; 311 int n; 312 unsigned char msg[] = 313 "012345678901234567890123456789012345678901234567890"; 314 char *msg_buf, *p; 315 316 msg_buf = (char *)malloc(len); 317 if (!msg_buf) 318 tst_brkm(TBROK, tst_exit, "malloc failed"); 319 320 p = msg_buf; 321 322 do { 323 n = ((i > 50)?50:i); 324 memcpy(p, msg, ((i > 50)?50:i)); 325 p += n; 326 i -= n; 327 } while (i > 0); 328 329 msg_buf[len-1] = '\0'; 330 331 return(msg_buf); 332 } 333 334 /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ 335 void test_enable_assoc_change(int fd) 336 { 337 struct sctp_event_subscribe subscribe; 338 339 memset(&subscribe, 0, sizeof(subscribe)); 340 subscribe.sctp_data_io_event = 1; 341 subscribe.sctp_association_event = 1; 342 test_setsockopt(fd, SCTP_EVENTS, (char *)&subscribe, 343 sizeof(subscribe)); 344 } 345 346 static int cmp_addr(sockaddr_storage_t *addr1, sockaddr_storage_t *addr2) 347 { 348 if (addr1->sa.sa_family != addr2->sa.sa_family) 349 return 0; 350 switch (addr1->sa.sa_family) { 351 case AF_INET6: 352 if (addr1->v6.sin6_port != addr2->v6.sin6_port) 353 return -1; 354 return memcmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr, 355 sizeof(addr1->v6.sin6_addr)); 356 case AF_INET: 357 if (addr1->v4.sin_port != addr2->v4.sin_port) 358 return 0; 359 return memcmp(&addr1->v4.sin_addr, &addr2->v4.sin_addr, 360 sizeof(addr1->v4.sin_addr)); 361 default: 362 tst_brkm(TBROK, tst_exit, 363 "invalid address type %d", addr1->sa.sa_family); 364 return -1; 365 } 366 } 367 368 /* Test peer addresses for association. */ 369 int test_peer_addr(int sk, sctp_assoc_t asoc, sockaddr_storage_t *peers, int count) 370 { 371 struct sockaddr *addrs; 372 int error, i, j; 373 struct sockaddr *sa_addr; 374 socklen_t addrs_size = 0; 375 void *addrbuf; 376 char found[count]; 377 memset(found, 0, count); 378 379 error = sctp_getpaddrs(sk, asoc, &addrs); 380 if (-1 == error) { 381 tst_brkm(TBROK, tst_exit, 382 "sctp_getpaddrs: %s", strerror(errno)); 383 return error; 384 } 385 if (error != count) { 386 sctp_freepaddrs(addrs); 387 tst_brkm(TBROK, tst_exit, 388 "peer count %d mismatch, expected %d", 389 error, count); 390 } 391 addrbuf = addrs; 392 for (i = 0; i < count; i++) { 393 sa_addr = (struct sockaddr *)addrbuf; 394 switch (sa_addr->sa_family) { 395 case AF_INET: 396 addrs_size += sizeof(struct sockaddr_in); 397 addrbuf += sizeof(struct sockaddr_in); 398 break; 399 case AF_INET6: 400 addrs_size += sizeof(struct sockaddr_in6); 401 addrbuf += sizeof(struct sockaddr_in6); 402 break; 403 default: 404 errno = EINVAL; 405 sctp_freepaddrs(addrs); 406 tst_brkm(TBROK, tst_exit, 407 "sctp_getpaddrs: %s", strerror(errno)); 408 return -1; 409 } 410 for (j = 0; j < count; j++) { 411 if (cmp_addr((sockaddr_storage_t *)sa_addr, 412 &peers[j]) == 0) { 413 found[j] = 1; 414 } 415 } 416 } 417 for (j = 0; j < count; j++) { 418 if (found[j] == 0) { 419 tst_brkm(TBROK, tst_exit, 420 "peer address %d not found", j); 421 } 422 } 423 sctp_freepaddrs(addrs); 424 return 0; 425 } 426