Imported Upstream version 1.0.10
[platform/upstream/lksctp-tools.git] / src / testlib / sctputil.c
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
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
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 
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 
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
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
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 *
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. */
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
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. */
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 = (char *) malloc(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 }