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