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@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@acm.org>
37  *    Narasimha Budihal <narsi@refcode.org>
38  *    Karl Knutson <karl@athena.chicago.il.us>
39  *    Jon Grimm <jgrimm@us.ibm.com>
40  *    Daisy Chang <daisyc@us.ibm.com>
41  *    Sridhar Samudrala <sri@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
test_print_cmsg(sctp_cmsg_t type,sctp_cmsg_data_t * data)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
test_print_message(int sk,struct msghdr * msg,size_t msg_len)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
test_check_buf_notification(void * buf,int datalen,int msg_flags,int expected_datalen,uint16_t expected_sn_type,uint32_t expected_additional)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
test_check_msg_notification(struct msghdr * msg,int datalen,int expected_datalen,uint16_t expected_sn_type,uint32_t expected_additional)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
test_check_buf_data(void * buf,int datalen,int msg_flags,struct sctp_sndrcvinfo * sinfo,int expected_datalen,int expected_msg_flags,uint16_t expected_stream,uint32_t expected_ppid)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
test_check_msg_data(struct msghdr * msg,int datalen,int expected_datalen,int expected_msg_flags,uint16_t expected_stream,uint32_t expected_ppid)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 *
test_build_msg(int len)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. */
test_enable_assoc_change(int fd)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 
cmp_addr(sockaddr_storage_t * addr1,sockaddr_storage_t * addr2)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. */
test_peer_addr(int sk,sctp_assoc_t asoc,sockaddr_storage_t * peers,int count)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