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