Home | History | Annotate | Download | only in testlib
      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