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, "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 */
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, "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 */
274 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)275 test_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. */
304 void *
test_build_msg(int len)305 test_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. */
test_enable_assoc_change(int fd)332 void 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
cmp_addr(sockaddr_storage_t * addr1,sockaddr_storage_t * addr2)343 static 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. */
test_peer_addr(int sk,sctp_assoc_t asoc,sockaddr_storage_t * peers,int count)366 int 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