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. */
59void
60test_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. */
95void
96test_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 */
180void
181test_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, "Got a datamsg, expecting "
189			 "notification");
190
191	if (expected_datalen <= 0)
192		return;
193
194	if (datalen != expected_datalen)
195		tst_brkm(TBROK, tst_exit, "Got a notification of unexpected "
196			 "length:%d, expected length:%d", datalen,
197			 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, "Unexpected notification:%d"
202			 "expected:%d", sn->sn_header.sn_type,
203			  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, "Unexpected sac_state:%d "
209				 "expected:%d", sn->sn_assoc_change.sac_state,
210				  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 */
220void
221test_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 */
233void
234test_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, "Got a notification, expecting a"
241			 "datamsg");
242
243	if (expected_datalen <= 0)
244		return;
245
246	if (datalen != expected_datalen)
247		tst_brkm(TBROK, tst_exit, "Got a datamsg of unexpected "
248			 "length:%d, expected length:%d", datalen,
249			 expected_datalen);
250
251	if ((msg_flags & ~0x80000000) != expected_msg_flags)
252		tst_brkm(TBROK, tst_exit, "Unexpected msg_flags:0x%x "
253			 "expecting:0x%x", msg_flags, expected_msg_flags);
254
255	if ((0 == expected_stream) && (0 == expected_ppid))
256		return;
257
258	if (!sinfo)
259		tst_brkm(TBROK, tst_exit, "Null sinfo, but expected "
260			 "stream:%d expected ppid:%d", expected_stream,
261			 expected_ppid);
262
263	if (sinfo->sinfo_stream != expected_stream)
264		tst_brkm(TBROK, tst_exit, "stream mismatch: expected:%x "
265			 "got:%x", expected_stream, sinfo->sinfo_stream);
266	if (sinfo->sinfo_ppid != expected_ppid)
267		tst_brkm(TBROK, tst_exit, "ppid mismatch: expected:%x "
268			 "got:%x\n", expected_ppid, sinfo->sinfo_ppid);
269}
270
271/* Check if a message corresponds to data, its length, msg_flags, stream and
272 * ppid.
273 */
274void
275test_check_msg_data(struct msghdr *msg, int datalen, int expected_datalen,
276		    int expected_msg_flags, uint16_t expected_stream,
277		    uint32_t expected_ppid)
278{
279	struct cmsghdr *cmsg = NULL;
280	struct sctp_sndrcvinfo *sinfo = NULL;
281
282	/* Receive auxiliary data in msgh. */
283	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
284				 cmsg = CMSG_NXTHDR(msg, cmsg)){
285		if (IPPROTO_SCTP == cmsg->cmsg_level &&
286		    SCTP_SNDRCV == cmsg->cmsg_type)
287			break;
288	} /* for( all cmsgs) */
289
290	if ((!cmsg) ||
291	    (cmsg->cmsg_len < CMSG_LEN(sizeof(struct sctp_sndrcvinfo))))
292		sinfo = NULL;
293	else
294		sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
295
296	test_check_buf_data(msg->msg_iov[0].iov_base, datalen, msg->msg_flags,
297			    sinfo, expected_datalen, expected_msg_flags,
298			    expected_stream, expected_ppid);
299
300}
301
302
303/* Allocate a buffer of requested len and fill in with data. */
304void *
305test_build_msg(int len)
306{
307	int i = len - 1;
308	int n;
309	unsigned char msg[] =
310		"012345678901234567890123456789012345678901234567890";
311	char *msg_buf, *p;
312
313	msg_buf = (char *)malloc(len);
314	if (!msg_buf)
315		tst_brkm(TBROK, tst_exit, "malloc failed");
316
317	p = msg_buf;
318
319	do {
320		n = ((i > 50)?50:i);
321		memcpy(p, msg, ((i > 50)?50:i));
322		p += n;
323		i -= n;
324	} while (i > 0);
325
326	msg_buf[len-1] = '\0';
327
328	return(msg_buf);
329}
330
331/* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
332void test_enable_assoc_change(int fd)
333{
334	struct sctp_event_subscribe subscribe;
335
336	memset(&subscribe, 0, sizeof(subscribe));
337	subscribe.sctp_data_io_event = 1;
338	subscribe.sctp_association_event = 1;
339	test_setsockopt(fd, SCTP_EVENTS, (char *)&subscribe,
340		        sizeof(subscribe));
341}
342
343static int cmp_addr(sockaddr_storage_t *addr1, sockaddr_storage_t *addr2)
344{
345	if (addr1->sa.sa_family != addr2->sa.sa_family)
346		return 0;
347	switch (addr1->sa.sa_family) {
348	case AF_INET6:
349		if (addr1->v6.sin6_port != addr2->v6.sin6_port)
350			return -1;
351		return memcmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr,
352			      sizeof(addr1->v6.sin6_addr));
353	case AF_INET:
354		if (addr1->v4.sin_port != addr2->v4.sin_port)
355			return 0;
356		return memcmp(&addr1->v4.sin_addr, &addr2->v4.sin_addr,
357			      sizeof(addr1->v4.sin_addr));
358	default:
359		tst_brkm(TBROK, tst_exit, "invalid address type %d",
360			 addr1->sa.sa_family);
361		return -1;
362	}
363}
364
365/* Test peer addresses for association. */
366int test_peer_addr(int sk, sctp_assoc_t asoc, sockaddr_storage_t *peers, int count)
367{
368	struct sockaddr *addrs;
369	int error, i, j;
370	struct sockaddr *sa_addr;
371	socklen_t addrs_size = 0;
372	void *addrbuf;
373	char found[count];
374	memset(found, 0, count);
375
376	error = sctp_getpaddrs(sk, asoc, &addrs);
377	if (-1 == error) {
378		tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno));
379		return error;
380	}
381	if (error != count) {
382		sctp_freepaddrs(addrs);
383		tst_brkm(TBROK, tst_exit, "peer count %d mismatch, expected %d",
384			 error, count);
385	}
386	addrbuf = addrs;
387	for (i = 0; i < count; i++) {
388		sa_addr = (struct sockaddr *)addrbuf;
389		switch (sa_addr->sa_family) {
390		case AF_INET:
391			addrs_size += sizeof(struct sockaddr_in);
392			addrbuf += sizeof(struct sockaddr_in);
393			break;
394		case AF_INET6:
395			addrs_size += sizeof(struct sockaddr_in6);
396			addrbuf += sizeof(struct sockaddr_in6);
397			break;
398		default:
399			errno = EINVAL;
400			sctp_freepaddrs(addrs);
401			tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno));
402			return -1;
403		}
404		for (j = 0; j < count; j++) {
405			if (cmp_addr((sockaddr_storage_t *)sa_addr,
406				     &peers[j]) == 0) {
407				found[j] = 1;
408			}
409		}
410	}
411	for (j = 0; j < count; j++) {
412		if (found[j] == 0) {
413			tst_brkm(TBROK, tst_exit, "peer address %d not found", j);
414		}
415	}
416	sctp_freepaddrs(addrs);
417	return 0;
418}
419