Imported Upstream version 1.0.10
[platform/upstream/lksctp-tools.git] / src / apps / sctp_darn.c
1 /* SCTP kernel Implementation
2  * (C) Copyright IBM Corp. 2001, 2003
3  * Copyright (c) 1999 Cisco
4  * Copyright (c) 1999, 2000, 2001 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  *    Karl Knutson <karl@athena.chicago.il.us>
38  *    Hui Huang <hui.huang@nokia.com>
39  *    Daisy Chang <daisyc@us.ibm.com>
40  *    Sridhar Samudrala <sri@us.ibm.com>
41  */
42
43 /* This is a userspace test application for the SCTP kernel 
44  * implementation state machine.  It is vaguely inspired by Stevens'
45  * program "sock".
46  *
47  * It has the limited ability to send messages and to listen for messages
48  * sent via SCTP.
49  */
50
51 #include <stdio.h>
52 #include <fcntl.h>
53 #include <stdlib.h>
54 //#define _GNU_SOURCE
55 #include <getopt.h>
56 #include <netdb.h>
57
58 #include <ctype.h>
59 #include <sys/types.h>
60 #include <sys/socket.h>
61 #include <sys/uio.h>
62 #include <netinet/in.h>
63 #include <sys/errno.h>
64 #include <sys/param.h>
65 #include <sys/poll.h>
66 #include <arpa/inet.h>
67 #include <errno.h>
68 #include <net/if.h>
69 #include <netinet/sctp.h>
70 #include <unistd.h>
71 #include <string.h>
72 #include <signal.h>
73 #include "sctp_darn.h"
74
75 char *TCID = __FILE__;
76 int TST_TOTAL = 1;
77 int TST_CNT = 0;
78
79 #define GEN_DATA_FIRST  0x21
80 #define GEN_DATA_LAST   0x7e
81
82 /* Display an IPv4 address in readable format.  */
83 #define NIPQUAD(addr) \
84         ((unsigned char *)&addr)[0], \
85         ((unsigned char *)&addr)[1], \
86         ((unsigned char *)&addr)[2], \
87         ((unsigned char *)&addr)[3]
88
89 /* Display an IPv6 address in readable format.  */
90 #define NIP6(addr) \
91         ntohs((addr).s6_addr16[0]), \
92         ntohs((addr).s6_addr16[1]), \
93         ntohs((addr).s6_addr16[2]), \
94         ntohs((addr).s6_addr16[3]), \
95         ntohs((addr).s6_addr16[4]), \
96         ntohs((addr).s6_addr16[5]), \
97         ntohs((addr).s6_addr16[6]), \
98         ntohs((addr).s6_addr16[7])
99
100 /* These are the global options.  */
101 char *local_host = NULL;
102 int local_port = 0;
103 char *remote_host = NULL;
104 int remote_port = 0;
105 command_t command = COMMAND_NONE;
106 struct sockaddr *bindx_add_addrs = NULL;
107 int bindx_add_count = 0;
108 struct sockaddr *bindx_rem_addrs = NULL;
109 int bindx_rem_count = 0;
110 struct sockaddr *connectx_addrs = NULL;
111 int connectx_count = 0;
112 int interactive_mode = 0;
113 int poll_skn = 0;
114 int nonblocking = 0;
115 int opt_space = 0;
116 char gen_data = GEN_DATA_FIRST;
117 char *inter_outbuf = NULL;
118 int inter_outlen = 0;
119 int inter_sk = 0;
120 int poll_snd_size = 0;
121 int use_poll = 0;
122 int socket_type = SOCK_SEQPACKET;
123 sctp_assoc_t associd = 0;
124 int echo = 0;
125 char *interface = "eth0";
126 int if_index = 0;
127 sockaddr_storage_t remote_addr;
128 sa_family_t ra_family;  /* What family is remote_addr? */
129 int ra_len = 0;         /* How long is remote_addr? */
130 void *ra_raw;           /* This is the addr part of remote_addr. */
131 int new_connection = 1;
132
133 enum inter_cmd_num {
134         INTER_SND = 0,
135         INTER_RCV,
136         INTER_SNDBUF,
137         INTER_RCVBUF,
138         INTER_BINDX_ADD,
139         INTER_BINDX_REM,
140         INTER_SET_PRIM,
141         INTER_SET_PEER_PRIM,
142         INTER_SHUTDOWN,
143         INTER_ABORT,
144         INTER_NODELAY,
145         INTER_MAXSEG
146 };
147
148 enum shutdown_type {
149         SHUTDOWN_ABORT = 0,
150         SHUTDOWN_SHUTDOWN
151 };
152
153 struct inter_entry {
154         char *cmd;
155         int cmd_num;
156 };
157
158 struct inter_entry inter_commands[] = {
159         {"snd", INTER_SND},
160         {"rcv", INTER_RCV},
161         {"sndbuf", INTER_SNDBUF},
162         {"rcvbuf", INTER_RCVBUF},
163         {"bindx-add", INTER_BINDX_ADD},
164         {"bindx-rem", INTER_BINDX_REM},
165         {"primary", INTER_SET_PRIM},
166         {"peer_primary", INTER_SET_PEER_PRIM},
167         {"shutdown", INTER_SHUTDOWN},
168         {"abort", INTER_ABORT},
169         {"nodelay", INTER_NODELAY},
170         {"maxseg", INTER_MAXSEG},
171         {NULL, -1},
172 };
173
174 #define POLL_SK_MAX     256     /* The max number of sockets to select/poll. */
175 int poll_sks[POLL_SK_MAX];              /* The array for using select(). */
176 struct pollfd poll_fds[POLL_SK_MAX];    /* The array for using poll().  */
177 #define POLL_SND_SIZE   16384   /* Default message size in the poll mode. */
178
179
180 struct sockaddr *append_addr(const char *parm, struct sockaddr *addrs,
181                              int *ret_count) ;
182 int build_endpoint(char *argv0, int portnum);
183 static int parse_inter_commands(char *, char *, int);
184 static void snd_func(char *);
185 static void sndbuf_func(char *, int, int, int);
186 static void rcvbuf_func(char *, int, int, int);
187 static struct sockaddr *get_bindx_addr(char *, int *);
188 static int bindx_func(char *, int, struct sockaddr *, int, int, int);
189 static int connectx_func(char *, int, struct sockaddr *, int);
190 static void  primary_func(char *, int, char *, int);
191 static void  peer_primary_func(char *, int, char *, int);
192 static int nodelay_func(char *, int, int val, int set);
193 static int maxseg_func(char *, int, int val, int set);
194 static int shutdown_func(char *argv0, int *skp, int shutdown_type);
195 static int test_sk_for_assoc(int sk, sctp_assoc_t assoc_id);
196 static char * gen_message(int);
197 static sctp_assoc_t test_recv_assoc_change(int);
198 static sctp_assoc_t test_verify_assoc_change(struct msghdr *);
199 void print_addr_buf(void * laddrs, int n_laddrs);
200 int print_sockaddr(struct sockaddr *sa_addr);
201
202 int
203 main(int argc, char *argv[]) {
204         int sk = -1;
205         int error = 0;
206         int i;
207
208         signal(SIGPIPE, SIG_IGN);
209
210         parse_arguments(argc, argv);
211
212         switch(command) {
213         case COMMAND_NONE:
214                 fprintf(stderr, "%s: Please specify a command.\n",
215                         argv[0]);
216                 exit(1);
217                 break;
218         case COMMAND_LISTEN:
219                 sk = build_endpoint(argv[0], local_port);
220                 error = command_listen(argv[0], sk);
221                 break;
222         case COMMAND_SEND:
223                 sk = build_endpoint(argv[0], local_port);
224                 error = command_send(argv[0], &sk);
225                 break;
226         case COMMAND_POLL:
227                 if (use_poll) {
228                         for (i = 0; i < poll_skn; i++) {
229                                 poll_fds[i].fd = build_endpoint(argv[0],
230                                         local_port + i);
231                         }
232                 } else {
233                         for (i = 0; i < poll_skn; i++) {
234                                 poll_sks[i] = build_endpoint(argv[0],
235                                         local_port + i);
236                         }
237                 }
238                 error = command_poll(argv[0]);
239                 break;
240         default:
241                 fprintf(stderr, "%s: illegal command %d\n",
242                         argv[0], command);
243                 exit(1);
244         }
245
246         /* Shut down the link.  */
247         if (COMMAND_POLL != command) {
248                 close(sk);
249         } else {
250                 /* Shutdown all links.  */
251                 if (use_poll) {
252                         for (i = 0; i < poll_skn; i++) {
253                                 close(poll_fds[i].fd);
254                         }
255                 } else {
256                         for (i = 0; i < poll_skn; i++) {
257                                 close(poll_sks[i]);
258                         }
259                 }
260         }
261
262         exit(error);
263 }
264
265 /********************************************************************
266  * 2nd Level Abstractions
267  ********************************************************************/
268
269 void
270 parse_arguments(int argc, char *argv[]) {
271         int option_index = 0;
272         int c;
273         struct sockaddr *tmp_addrs = NULL;
274
275         static struct option long_options[] = {
276                 {"local",       1, 0, 1},
277                 {"local-port",  1, 0, 2},
278                 {"remote",      1, 0, 3},
279                 {"remote-port", 1, 0, 4},
280                 {"listen",      0, 0, 10},
281                 {"send",        0, 0, 11},
282                 {"bindx-add",   1, 0, 15},
283                 {"bindx-rem",   1, 0, 16},
284                 {"use-poll",    0, 0, 20},
285                 {"echo",        0, 0, 'e'},
286                 {"interface",   optional_argument, 0, 5,},
287                 {"connectx",    1, 0, 17},
288                 {0,             0, 0, 0}
289         };
290
291         /* Parse the arguments.  */
292         while (1) {
293                 c = getopt_long (argc, argv, "B:H:IP:b:h:i:p:lm:nstz:ec:",
294                                  long_options, &option_index);
295                 if (c == -1)
296                         break;
297
298                 switch (c) {
299                 case 0:
300                         printf("option %s", long_options[option_index].name);
301                         if (optarg) {
302                                 printf(" with arg %s", optarg);
303                         }
304                         printf("\n");
305                         break;
306                 case 1:         /* local host */
307                 case 'H':
308                         local_host = optarg;
309                         break;
310                 case 2:         /* local port */
311                 case 'P':
312                         local_port = atoi(optarg);
313                         break;
314                 case 3:         /* remote host */
315                 case 'h':
316                         remote_host = optarg;
317                         break;
318                 case 4:         /* remote port */
319                 case 'p':
320                         remote_port = atoi(optarg);
321                         break;
322                 case 5:  /* interface for sin6_scope_id */
323                         if (optarg)
324                                 interface = optarg;
325                         if_index = if_nametoindex(interface);
326                         if (!if_index) {
327                                 printf("Interface %s unknown\n", interface);
328                                 exit(1);
329                         }
330                         break;
331                         /* COMMANDS */
332                 case 10:        /* listen */
333                 case 'l':
334                         if (command) {
335                                 fprintf(stderr,
336                                         "%s: pick ONE of listen or send\n",
337                                         argv[0]);
338                                 exit(1);
339                         } else {
340                                 command = COMMAND_LISTEN;
341                         }
342                         break;
343
344                 case 11:        /* send */
345                 case 's':
346                         if (command) {
347                                 fprintf(stderr,
348                                         "%s: pick ONE of listen or send\n",
349                                         argv[0]);
350                                 exit(1);
351                         } else {
352                                 command = COMMAND_SEND;
353                         }
354                         break;
355
356                 case 15:                /* bindx_add */
357                 case 'B':
358                         tmp_addrs =
359                                 append_addr(optarg, bindx_add_addrs,
360                                             &bindx_add_count);
361                         if (NULL == tmp_addrs) {
362                                 /* We have no memory, so keep fprintf()
363                                  * from trying to allocate more.
364                                  */
365                                 fprintf(stderr, "No memory to add ");
366                                 fprintf(stderr, optarg);
367                                 fprintf(stderr, "\n");
368                                 exit(2);
369                         }
370                         bindx_add_addrs = tmp_addrs;
371
372                         break;
373
374                 case 16:                /* bindx_rem */
375                 case 'b':
376                         tmp_addrs =
377                                 append_addr(optarg, bindx_rem_addrs,
378                                             &bindx_rem_count);
379                         if (NULL == tmp_addrs) {
380                                 /* We have no memory, so keep fprintf()
381                                  * from trying to allocate more.
382                                  */
383                                 fprintf(stderr, "No memory to add ");
384                                 fprintf(stderr, optarg);
385                                 fprintf(stderr, "\n");
386                                 exit(2);
387                         }
388                         bindx_rem_addrs = tmp_addrs;
389                         break;
390                 case 17:                /* connectx */
391                 case 'c':
392                         tmp_addrs =
393                                 append_addr(optarg, connectx_addrs,
394                                             &connectx_count);
395                         if (NULL == tmp_addrs) {
396                                 /* We have no memory, so keep fprintf()
397                                  * from trying to allocate more.
398                                  */
399                                 fprintf(stderr, "No memory to add ");
400                                 fprintf(stderr, optarg);
401                                 fprintf(stderr, "\n");
402                                 exit(2);
403                         }
404                         connectx_addrs = tmp_addrs;
405                         break;
406                 case 20:                /* use-poll */
407                         use_poll = 1;
408                         break;
409                 case 'I':
410                         interactive_mode = 1;
411                         break;
412                 case 'i':
413                         command = COMMAND_POLL;
414                         poll_skn = atoi(optarg);
415                         if (poll_skn <= 0 || poll_skn > POLL_SK_MAX) {
416                                 fprintf(stderr, "Too many sockets for ");
417                                 fprintf(stderr, "for polling\n");
418                                 exit(2);
419                         }
420                         break;
421                 case 'm':
422                         opt_space = atoi(optarg);
423                         break;
424                 case 'n':
425                         nonblocking = 1;
426                         break;
427                 case 't':
428                         socket_type = SOCK_STREAM;
429                         break;
430                 case 'z':
431                         poll_snd_size = atoi(optarg);
432                         if (poll_snd_size <= 0) {
433                                 fprintf(stderr, "Bad message size.\n");
434                                 exit(2);
435                         }
436                         break;
437                 case 'e':
438                         echo = 1;
439                         break;
440                 case '?':
441                         usage(argv[0]);
442                         exit(1);
443
444                 default:
445                         printf ("%s: unrecognized option 0%c\n",
446                                 argv[0], c);
447                         usage(argv[0]);
448                         exit(1);
449                 }
450         }
451
452         if (optind < argc)
453         {
454                 fprintf(stderr, "%s: non-option arguments are illegal: ",
455                         argv[0]);
456                 while (optind < argc)
457                         fprintf(stderr, "%s ", argv[optind++]);
458                 fprintf (stderr, "\n");
459                 usage(argv[0]);
460                 exit(1);
461         }
462
463
464         if (NULL == local_host) {
465                 fprintf(stderr, "%s: You MUST provide a local host.\n",
466                         argv[0]);
467                 usage(argv[0]);
468                 exit(1);
469         }
470
471         if (command == COMMAND_SEND && NULL == remote_host
472             && connectx_count == 0) {
473                 fprintf(stderr, "%s: You MUST provide a remote host for sending.\n",
474                         argv[0]);
475                 usage(argv[0]);
476                 exit(1);
477         }
478
479         if (remote_host != NULL && connectx_count != 0) {
480                 fprintf(stderr, "%s: You can not provide both -h and -c options.\n",
481                         argv[0]);
482                 usage(argv[0]);
483                 exit(1);
484         }
485 } /* parse_arguments() */
486
487 /* Set up the local endpoint.  */
488 int
489 build_endpoint(char *argv0, int portnum)
490 {
491         int retval;
492         struct hostent *hst;
493         sockaddr_storage_t local_addr;
494         sa_family_t la_family;  /* What family is local_addr? */
495         int la_len;             /* How long is local_addr? */
496         void *la_raw;           /* This is the addr part of local_addr. */
497         int error;
498         struct sctp_event_subscribe subscribe;
499
500         /* Get the transport address for the local host name.  */
501         hst = gethostbyname(local_host);
502         if (hst == NULL) {
503                 hst = gethostbyname2(local_host, AF_INET6);
504         }
505
506         if (hst == NULL || hst->h_length < 1) {
507                 fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host);
508                 exit(1);
509         }
510
511         la_family = hst->h_addrtype;
512         switch (la_family) {
513         case AF_INET:
514                 la_len = sizeof(local_addr.v4);
515                 la_raw = &local_addr.v4.sin_addr;
516                 local_addr.v4.sin_port = htons(portnum);
517                 local_addr.v4.sin_family = AF_INET;
518                 break;
519         case AF_INET6:
520                 la_len = sizeof(local_addr.v6);
521                 la_raw = &local_addr.v6.sin6_addr;
522                 local_addr.v6.sin6_port = htons(portnum);
523                 local_addr.v6.sin6_family = AF_INET6;
524                 local_addr.v6.sin6_scope_id = if_index;
525                 break;
526         default:
527                 fprintf(stderr, "Invalid address type.\n");
528                 exit(1);
529                 break;
530         }
531         memcpy(la_raw, hst->h_addr_list[0], hst->h_length);
532
533         /* Create the local endpoint.  */
534         retval = socket(la_family, socket_type, IPPROTO_SCTP);
535         if (retval < 0) {
536                 fprintf(stderr, "%s: failed to create socket:  %s.\n",
537                         argv0, strerror(errno));
538                 exit(1);
539         }
540
541         if (SOCK_SEQPACKET == socket_type) {
542                 memset(&subscribe, 0, sizeof(subscribe));
543                 subscribe.sctp_data_io_event = 1;
544                 subscribe.sctp_association_event = 1;
545                 error = setsockopt(retval, SOL_SCTP, SCTP_EVENTS,
546                                    (char *)&subscribe, sizeof(subscribe));
547                 if (error) {
548                         fprintf(stderr, "SCTP_EVENTS: error: %d\n", error);
549                         exit(1);
550                 }
551         }
552
553         /* Bind this socket to the test port.  */
554         error = bind(retval, &local_addr.sa, la_len);
555         if (error != 0) {
556                 fprintf(stderr, "%s: can not bind to %s:%d: %s.\n",
557                         argv0, local_host, portnum,
558                         strerror(errno));
559                 exit(1);
560         }
561
562         /* Do we need to do bindx() to add any additional addresses? */
563         if (bindx_add_addrs) {
564                 if (0 != bindx_func(argv0, retval, bindx_add_addrs,
565                         bindx_add_count, SCTP_BINDX_ADD_ADDR, portnum)) {
566                         fprintf(stderr, "bindx_func (add) failed.\n");
567                         exit(1);
568                 }
569         } /* if (bindx_add_addrs) */
570
571         /* Do we need to do bindx() to remove any bound addresses? */
572         if (bindx_rem_addrs) {
573                 if (0 != bindx_func(argv0, retval, bindx_rem_addrs,
574                         bindx_rem_count, SCTP_BINDX_REM_ADDR, portnum)) {
575                         fprintf(stderr, "bindx_func (remove) failed.\n");
576                         exit(1);
577                 }
578         } /* if (bindx_rem_addrs) */
579
580         /* Do we want to run in the non-blocking mode? */
581         if (nonblocking) {
582                 error = fcntl(retval, F_SETFL, O_NONBLOCK);
583                 if (error != 0) {
584                         fprintf(stderr, "%s: error fcntl: %s.\n",
585                                 argv0, strerror(errno));
586                         exit(1);
587                 }
588         }
589
590         if (opt_space) {
591                 sndbuf_func(argv0, retval, opt_space, 1);
592                 rcvbuf_func(argv0, retval, opt_space, 1);
593         }
594
595         return retval;
596
597 } /* build_endpoint() */
598
599 /* Convenience structure to determine space needed for cmsg. */
600 typedef union {
601         struct sctp_initmsg init;
602         struct sctp_sndrcvinfo sndrcvinfo;
603 } _sctp_cmsg_data_t;
604
605
606 /* Listen on the socket, printing out anything that arrives.  */
607 int
608 command_listen(char *argv0, int sk)
609 {
610         char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
611         struct iovec iov;
612         struct msghdr inmessage;
613         sockaddr_storage_t msgname;
614         char message[REALLY_BIG];
615         int done = 0;
616         int error;
617         int c;
618         int recvsk = 0;
619
620         /* Mark sk as being able to accept new associations */
621         error = listen(sk, 5);
622         if (error != 0) {
623                 printf("\n\n\t\tlisten Failure:  %s.\n\n\n",
624                        strerror(errno));
625                 exit(1);
626         }
627
628         if (nonblocking) {
629                 if (!interactive_mode) {
630                         printf("Use -I for interactive mode with");
631                        printf(" -n nonblocking\n");
632                        exit(1);
633                  }
634         }
635
636         /* Initialize the global value for interactive mode functions.  */
637         if (interactive_mode) {
638                 inter_sk = sk;
639         }
640
641         /* Initialize inmessage with enough space for DATA... */
642         memset(&inmessage, 0, sizeof(inmessage));
643         if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
644                 printf("%s: Can't allocate memory.\n", argv0);
645                 exit(1);
646         }
647         iov.iov_len = REALLY_BIG;
648         inmessage.msg_iov = &iov;
649         inmessage.msg_iovlen = 1;
650         /* or a control message.  */
651         inmessage.msg_control = incmsg;
652         inmessage.msg_controllen = sizeof(incmsg);
653         inmessage.msg_name = &msgname;
654         inmessage.msg_namelen = sizeof(msgname);
655
656         printf("%s listening...\n", argv0);
657         /* Get the messages sent */
658         done = 0;
659         while (!done) {
660                 if (interactive_mode) {
661                         /* Read from the user.  */
662                         if (remote_host) {
663                                 printf("%s:%d-%s:%d Interactive mode> ",
664                                         local_host, local_port, remote_host,
665                                         remote_port);
666                         } else {
667                                 printf("%s:%d-", local_host, local_port);
668                                 if (associd) {
669                                         print_sockaddr(&remote_addr.sa);
670                                 } else {
671                                         printf("?:%d", remote_port);
672                                 }
673                                 printf(" Interactive mode> ");
674                         }
675                         fflush(stdout);
676                         if (NULL == fgets(message, REALLY_BIG, stdin)) {
677                                 done = 1;
678                                 continue;
679                         }
680
681                         if (0 <= (c = parse_inter_commands(argv0, message,
682                                 0))) {
683                                 if (INTER_RCV != c) {
684                                         continue;
685                                 }
686                         } else {
687                                 continue;
688                         }
689                 }
690
691                 if (socket_type == SOCK_STREAM) {
692                         socklen_t len = 0;
693
694                         if (!recvsk) {
695                                 if ((recvsk = accept(sk, NULL, &len)) < 0) {
696                                         fprintf(stderr, "%s: error: %s.\n",
697                                                 argv0, strerror(errno));
698                                         exit(1);
699                                 }
700                         }
701
702                 } else {
703                         recvsk = sk;
704                 }
705
706                 error = recvmsg(recvsk, &inmessage, MSG_WAITALL);
707                 if (error < 0) {
708                         if (nonblocking && (EAGAIN == errno)) {
709                                 error = 0;
710                                 continue;
711                         }
712
713                         if (socket_type == SOCK_STREAM) {
714                                 if (ENOTCONN != errno)
715                                         break;
716                                 printf("No association is present now!!\n");
717                                 close(recvsk);
718                                 recvsk = 0;
719                                 continue;
720                         }
721                         break;
722                 }
723
724                 /* Update the associd when a notification is received on a
725                  * UDP-style socket.
726                  */
727                 if (inmessage.msg_flags & MSG_NOTIFICATION)
728                         associd = test_verify_assoc_change(&inmessage);
729
730                 if (echo) {
731                         if( !(MSG_NOTIFICATION & inmessage.msg_flags)) {
732                                 sendto(recvsk, inmessage.msg_iov->iov_base,
733                                        error, 0, (struct sockaddr *)&msgname,
734                                        sizeof(msgname));
735                         }
736                 }
737
738                 test_print_message(sk, &inmessage, error);
739
740                 inmessage.msg_control = incmsg;
741                 inmessage.msg_controllen = sizeof(incmsg);
742                 inmessage.msg_name = &msgname;
743                 inmessage.msg_namelen = sizeof(msgname);
744                 iov.iov_len = REALLY_BIG;
745
746                 /* Verify that the association is no longer present.  */
747                 if (0 != test_sk_for_assoc(recvsk, associd)) {
748                         printf("No association is present now!!\n");
749                         if (socket_type == SOCK_STREAM) {
750                                 close(recvsk);
751                                 recvsk = 0;
752                         }
753                 }
754         }
755
756         if (error < 0) {
757                 fprintf(stderr, "%s: error: %s.\n",
758                         argv0, strerror(errno));
759                 exit(1);
760         }
761
762         return error;
763
764 } /* command_listen() */
765
766 /* Read lines from stdin and send them to the socket.  */
767 int
768 command_send(char *argv0, int *skp)
769 {
770         struct msghdr outmsg;
771         struct iovec iov;
772         int done = 0;
773         char message[REALLY_BIG];
774         struct hostent *hst;
775         int c;
776         struct sockaddr *addrs;
777         int msglen;
778         int error = 0;
779         int sk = *skp;
780
781         /* Set up the destination.  */
782         if (remote_host != NULL) {
783                 hst = gethostbyname(remote_host);
784                 if (hst == NULL) {
785                         hst = gethostbyname2(remote_host, AF_INET6);
786                 }
787
788                 if (hst == NULL || hst->h_length < 1) {
789                         fprintf(stderr, "%s: bad hostname: %s\n",
790                                 argv0, remote_host);
791                         exit(1);
792                 }
793
794                 ra_family = hst->h_addrtype;
795                 switch (ra_family) {
796                 case AF_INET:
797                         ra_len = sizeof(remote_addr.v4);
798                         ra_raw = &remote_addr.v4.sin_addr;
799                         remote_addr.v4.sin_port = htons(remote_port);
800                         remote_addr.v4.sin_family = AF_INET;
801                         break;
802                 case AF_INET6:
803                         ra_len = sizeof(remote_addr.v6);
804                         ra_raw = &remote_addr.v6.sin6_addr;
805                         remote_addr.v6.sin6_port = htons(remote_port);
806                         remote_addr.v6.sin6_family = AF_INET6;
807                         remote_addr.v6.sin6_scope_id = if_index;
808                         break;
809                 default:
810                         fprintf(stderr, "Invalid address type.\n");
811                         exit(1);
812                         break;
813                 }
814                 memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
815         }
816
817         /* Initialize the global value for interactive mode functions.  */
818         if (interactive_mode) {
819                 inter_sk = sk;
820         }
821
822         printf("%s ready to send...\n", argv0);
823         while (!done) {
824                 /* Read from the user.  */
825                 if (remote_host) {
826                         if (interactive_mode) {
827                                 printf("%s:%d-%s:%d Interactive mode> ",
828                                         local_host, local_port, remote_host,
829                                         remote_port);
830                         } else {
831                                 printf("%s:%d-%s:%d> ",
832                                        local_host, local_port,
833                                        remote_host, remote_port);
834                         }
835                 } else {
836                         printf("%s:%d-", local_host, local_port);
837                         if (associd) {
838                                 print_sockaddr(&remote_addr.sa);
839                         } else {
840                                 printf("XXXXXX:%d", remote_port);
841                         }
842                         if (interactive_mode) {
843                                 printf(" Interactive mode> ");
844                         } else {
845                                 printf("> ");
846                         }
847                 }
848                 fflush(stdout);
849                 if (NULL == fgets(message, REALLY_BIG, stdin)) {
850                         done = 1;
851                         continue;
852                 }
853
854                 if (interactive_mode) {
855                         /* This is the send only agent.  */
856                         if (0 <= (c = parse_inter_commands(argv0, message,
857                                 1))) {
858                                 if (INTER_SND == c) {
859                                         iov.iov_base = inter_outbuf;
860                                         msglen = inter_outlen;
861                                         iov.iov_len = msglen;
862
863                                 } else {
864                                         continue;
865                                 }
866
867                         } else {
868                                 continue;
869                         }
870                 } else {
871                         /* Send to our neighbor.  */
872                         msglen = strlen(message) + 1;
873                         iov.iov_len = msglen;
874                 }
875
876                 /* For a UDP-style socket, verify if an existing association
877                  * has gone. If so, receive the pending SCTP_ASSOC_CHANGE
878                  * notification.
879                  */
880                 if ((SOCK_SEQPACKET == socket_type) && associd &&
881                     (0 != test_sk_for_assoc(sk, associd))) {
882                         associd = test_recv_assoc_change(sk);
883                         printf("Old association gone, Starting a new one!\n");
884                         new_connection = 1;
885                 }
886
887                 if (new_connection && connectx_count != 0) {
888                         /* Do a sctp_connectx() to establish a connection. */
889                         error = connectx_func(argv0, sk, connectx_addrs,
890                                               connectx_count);
891                         if (0 != error) {
892                                 if (error == -2) {
893                                         printf("Connection refused\n");
894                                         if (SOCK_SEQPACKET == socket_type) {
895                                                 associd = test_recv_assoc_change(sk);
896                                         }
897                                         continue;
898                                 }
899                                 fprintf(stderr, "connectx failed.\n");
900                                 exit(1);
901                         }
902                         if (SOCK_SEQPACKET == socket_type) {
903                                 associd = test_recv_assoc_change(sk);
904                         } else {
905                                 associd = 1;
906                         }
907                         int rc = sctp_getpaddrs(sk, associd, &addrs);
908                         if (0 >= rc) {
909                                 if (rc == 0) {
910                                         fprintf(stderr, "sctp_getpaddrs failed, no peers.\n");
911                                 } else {
912                                         fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno);
913                                 }
914                                 exit(1);
915                         }
916                         printf("New connection, peer addresses\n");
917                         print_addr_buf(addrs, rc);
918                         ra_family = addrs[0].sa_family;
919                         switch (ra_family) {
920                         case AF_INET:
921                                 ra_len = sizeof(remote_addr.v4);
922                                 break;
923                         case AF_INET6:
924                                 ra_len = sizeof(remote_addr.v6);
925                                 break;
926                         default:
927                                 fprintf(stderr, "Invalid address type.\n");
928                                 exit(1);
929                         }
930                         memcpy(&remote_addr, &addrs[0], ra_len);
931                         sctp_freepaddrs(addrs);
932                         new_connection = 0;
933                 }
934
935                 do {
936                         if (SOCK_SEQPACKET == socket_type ||
937                             (connectx_count == 0 && new_connection)) {
938                                 /* Initialize the message struct we use to pass
939                                  * messages to the remote socket.
940                                  */
941                                 if (!interactive_mode) {
942                                         iov.iov_base = message;
943                                         iov.iov_len = msglen;
944                                 }
945                                 outmsg.msg_iov = &iov;
946                                 outmsg.msg_iovlen = 1;
947                                 outmsg.msg_control = NULL;
948                                 outmsg.msg_controllen = 0;
949                                 outmsg.msg_name = &remote_addr;
950                                 outmsg.msg_namelen = ra_len;
951
952                                 error = sendmsg(sk, &outmsg, 0);
953                         } else {
954                                 error = send(sk, message, msglen, 0);
955                                 if (error == -1 && errno == EPIPE) {
956                                         error = close(sk);
957                                         if (error != 0) {
958                                                 fprintf(stderr, "close failed %s\n", strerror(errno));
959                                                 exit(1);
960                                         }
961                                         *skp = sk = build_endpoint(argv0, local_port);
962                                         break;
963                                 }
964                         }
965
966                         if (error != msglen) {
967                                 fprintf(stderr, "%s: error: %s.\n",
968                                         argv0, strerror(errno));
969                                 if (nonblocking && EAGAIN == errno) {
970                                         if (interactive_mode) {
971                                                 break;
972                                         }
973                                         continue;
974                                 }
975                                 exit(1);
976                         } else {
977                                 break;
978                         }
979                 } while (error != msglen);
980
981                 /* If this is the first message sent over a UDP-style socket,
982                  * get the associd from the SCTP_ASSOC_CHANGE notification.
983                  */
984                 if ((SOCK_SEQPACKET == socket_type) && (0 == associd))
985                         associd = test_recv_assoc_change(sk);
986
987                 /* Verify there is no association.  */
988                 if (0 != test_sk_for_assoc(sk, associd)) {
989                         printf("No association is present now!!\n");
990                         new_connection = 1;
991                 } else {
992                         if (new_connection) {
993                                 int rc = sctp_getpaddrs(sk, associd, &addrs);
994                                 if (0 >= rc) {
995                                         if (rc == 0) {
996                                                 fprintf(stderr, "sctp_getpaddrs failed, no peers.\n");
997                                         } else {
998                                                 fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno);
999                                         }
1000                                         exit(1);
1001                                 }
1002                                 printf("New connection, peer addresses\n");
1003                                 print_addr_buf(addrs, rc);
1004                                 sctp_freepaddrs(addrs);
1005                                 new_connection = 0;
1006                         }
1007                 }
1008
1009                 /* Clean up.  */
1010                 if (interactive_mode) {
1011                         free(inter_outbuf);
1012                         inter_outbuf = NULL;
1013                 }
1014         } /* while(!done) */
1015
1016         return error;
1017
1018 } /* command_send() */
1019
1020 /* Listen on the array of sockets, printing out anything that arrives.  */
1021 int
1022 command_poll(char *argv0)
1023 {
1024         char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
1025         struct iovec iov;
1026         struct msghdr inmessage;
1027         int done = 0;
1028         int error = 0;
1029         int max_fd, i, ret;
1030         int size;
1031         fd_set *ibitsp = NULL;
1032         fd_set *obitsp = NULL;
1033         fd_set *xbitsp = NULL;
1034
1035         struct msghdr outmsg;
1036         struct hostent *hst;
1037         int msglen;
1038         int temp_fd, temp_set;
1039
1040
1041
1042         /* If a remote host is specified, initialize the destination. */
1043         if (remote_host) {
1044                 /* Set up the destination.  */
1045                 hst = gethostbyname(remote_host);
1046                 if (hst == NULL) {
1047                         hst = gethostbyname2(remote_host, AF_INET6);
1048                 }
1049
1050                 if (hst == NULL || hst->h_length < 1) {
1051                         fprintf(stderr, "%s: bad hostname: %s\n",
1052                                 argv0, remote_host);
1053                         exit(1);
1054                 }
1055
1056                 ra_family = hst->h_addrtype;
1057                 switch (ra_family) {
1058                 case AF_INET:
1059                         ra_len = sizeof(remote_addr.v4);
1060                         ra_raw = &remote_addr.v4.sin_addr;
1061                         remote_addr.v4.sin_port = htons(remote_port);
1062                         remote_addr.v4.sin_family = AF_INET;
1063                         break;
1064                 case AF_INET6:
1065                         ra_len = sizeof(remote_addr.v6);
1066                         ra_raw = &remote_addr.v6.sin6_addr;
1067                         remote_addr.v6.sin6_port = htons(remote_port);
1068                         remote_addr.v6.sin6_family = AF_INET6;
1069                         remote_addr.v6.sin6_scope_id = if_index;
1070                         break;
1071                 default:
1072                         fprintf(stderr, "Invalid address type.\n");
1073                         exit(1);
1074                         break;
1075                 }
1076                 memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
1077
1078                 /* Initialize the message struct we use to pass messages to
1079                  * the remote socket.
1080                  */
1081                 outmsg.msg_iov = &iov;
1082                 outmsg.msg_iovlen = 1;
1083                 outmsg.msg_control = NULL;
1084                 outmsg.msg_controllen = 0;
1085                 outmsg.msg_name = &remote_addr;
1086                 outmsg.msg_namelen = ra_len;
1087         }
1088
1089
1090         max_fd = -1;
1091
1092         /* Set all of the sockets to be ready for listening. */
1093         if (use_poll) {
1094                 for (i = 0; i < poll_skn; i++) {
1095                         error = listen(poll_fds[i].fd, 1);
1096                         if (error != 0) {
1097                                 printf("%s: Listen failed on socket number ",
1098                                         argv0);
1099                                 printf("%d: %s.\n", i, strerror(errno));
1100                                 exit(1);
1101                         }
1102                 }
1103                 printf("%s listening...\n", argv0);
1104         } else {
1105                 for (i = 0; i < poll_skn; i++) {
1106                         error = listen(poll_sks[i], 1);
1107                         if (error != 0) {
1108                                 printf("%s: Listen failed on socket number ",
1109                                         argv0);
1110                                 printf("%d: %s.\n", i, strerror(errno));
1111                                 exit(1);
1112                         }
1113                         if (poll_sks[i] > max_fd) {
1114                                 max_fd = poll_sks[i];
1115                         }
1116                 }
1117                 printf("%s listening...\n", argv0);
1118
1119                 size = howmany(max_fd + 1, NFDBITS) * sizeof(fd_mask);
1120                 if ((ibitsp = (fd_set *)malloc(size)) == NULL) {
1121                         printf("%s: Can't allocate memory.\n", argv0);
1122                         exit(1);
1123                 }
1124                 if ((obitsp = (fd_set *)malloc(size)) == NULL) {
1125                         printf("%s: Can't allocate memory.\n", argv0);
1126                         exit(1);
1127                 }
1128                 if ((xbitsp = (fd_set *)malloc(size)) == NULL) {
1129                         printf("%s: Can't allocate memory.\n", argv0);
1130                         exit(1);
1131                 }
1132                 memset(ibitsp, 0, size);
1133                 memset(obitsp, 0, size);
1134                 memset(xbitsp, 0, size);
1135         }
1136
1137
1138         /* Initialize inmessage with enough space for DATA... */
1139         memset(&inmessage, 0, sizeof(inmessage));
1140         if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
1141                 printf("%s: Can't allocate memory.\n", argv0);
1142                 exit(1);
1143         }
1144         iov.iov_len = REALLY_BIG;
1145         inmessage.msg_iov = &iov;
1146         inmessage.msg_iovlen = 1;
1147         /* or a control message.  */
1148         inmessage.msg_control = incmsg;
1149         inmessage.msg_controllen = sizeof(incmsg);
1150
1151
1152         done = 0;
1153         /* Set the default send message size.  */
1154         if (!poll_snd_size) {
1155                 poll_snd_size = POLL_SND_SIZE;
1156         }
1157
1158         while (!done) {
1159
1160                 if (use_poll) {
1161                         for (i = 0; i < poll_skn; i++) {
1162                                 poll_fds[i].events = POLLIN;
1163                         }
1164                         if (remote_host) {
1165                                 /* Poll output on the first socket.  */
1166                                 poll_fds[0].events |= POLLOUT;
1167                         }
1168
1169                         if ((ret = poll(poll_fds, poll_skn, -1))) {
1170                                 if (ret == -1) {
1171                                         break;
1172                                 }
1173                         }
1174                 } else {
1175                         for (i = 0; i < poll_skn; i++) {
1176                                 FD_SET(poll_sks[i], ibitsp);
1177                                 FD_SET(poll_sks[i], xbitsp);
1178                         }
1179                         if (remote_host) {
1180                                 /* Only select output on the first socket.  */
1181                                 FD_SET(poll_sks[0], obitsp);
1182                         }
1183
1184
1185                         if ((ret = select(max_fd + 1, ibitsp, obitsp, xbitsp,
1186                                 (struct timeval *)0)) < 0) {
1187                                 if (ret == -1) {
1188                                         break;
1189                                 }
1190                         }
1191
1192                 }
1193
1194                 if (remote_host) {
1195                         if (use_poll) {
1196                                 temp_set = poll_fds[0].revents & POLLOUT;
1197                                 temp_fd = poll_fds[0].fd;
1198                         } else {
1199                                 temp_set = FD_ISSET(poll_sks[0], obitsp);
1200                                 temp_fd = poll_sks[0];
1201                         }
1202
1203                         if (temp_set) {
1204                                 inter_outbuf = gen_message(poll_snd_size);
1205                                 if (!inter_outbuf) {
1206                                         fprintf(stderr,
1207                                         "Cannot allocate out message.\n");
1208                                         exit(1);
1209                                 }
1210                                 iov.iov_base = inter_outbuf;
1211                                 msglen = poll_snd_size;
1212                                 iov.iov_len = msglen;
1213
1214                                 error = sendmsg(temp_fd, &outmsg, 0);
1215                                 fprintf(stderr,
1216                                         "sent a message, msglen = %d\n",
1217                                         msglen);
1218
1219                                 if (error != msglen) {
1220                                         fprintf(stderr, "%s: error: %s.\n",
1221                                                 argv0, strerror(errno));
1222                                         if ((!nonblocking) ||
1223                                             (EAGAIN != errno)) {
1224                                                 exit(1);
1225                                         }
1226                                 }
1227
1228                                 /* Clean up.  */
1229                                 free(inter_outbuf);
1230                                 inter_outbuf = NULL;
1231                         }
1232
1233                 } /* while(!done) */
1234
1235                 for (i = 0; !done && (i < poll_skn); i++) {
1236                         if (use_poll) {
1237                                 temp_set = poll_fds[i].revents & POLLIN;
1238                                 temp_fd = poll_fds[i].fd;
1239                         } else {
1240                                 temp_set = FD_ISSET(poll_sks[i], ibitsp);
1241                                 temp_fd = poll_sks[i];
1242                         }
1243                         if (temp_set) {
1244                                 error = recvmsg(temp_fd, &inmessage,
1245                                         MSG_WAITALL);
1246                                 if (error < 0) {
1247                                         if ((EAGAIN == errno)) {
1248                                                 error = 0;
1249                                                 continue;
1250                                         }
1251                                         else {
1252                                                 fprintf(stderr,
1253                                                         "%s: error: %s.\n",
1254                                                         argv0,
1255                                                         strerror(errno));
1256                                                 exit(1);
1257                                         }
1258                                 }
1259                                 test_print_message(temp_fd, &inmessage, error);
1260                                 inmessage.msg_control = incmsg;
1261                                 inmessage.msg_controllen = sizeof(incmsg);
1262                                 iov.iov_len = REALLY_BIG;
1263                         }
1264
1265                         /* Update the associd when a notification is received
1266                          * on a UDP-style socket.
1267                          */
1268                         if (inmessage.msg_flags & MSG_NOTIFICATION)
1269                                 associd = test_verify_assoc_change(&inmessage);
1270
1271                         /* Verify there is no association. */
1272                         if (0 != test_sk_for_assoc(poll_sks[i], associd)) {
1273                                 printf("No association is present in sk "
1274                                        "No.%d now!!\n",i);
1275                         }
1276                 }
1277
1278         }
1279
1280         if (!use_poll) {
1281                 free(ibitsp);
1282                 free(obitsp);
1283                 free(xbitsp);
1284         }
1285
1286         return error;
1287
1288 } /* command_poll() */
1289
1290 /********************************************************************
1291  * 3rd Level Abstractions
1292  ********************************************************************/
1293
1294 #define FPS(arg) fprintf(stderr, arg)
1295
1296 void
1297 usage(char *argv0)
1298 {
1299         /*
1300          * The bindx options, --bindx-add and --bindx-rem, are added to
1301          *
1302          * 1. provide first testcases for the new bindx system call
1303          *
1304          * 2. continue to grow sctp_darn with more functions and
1305          * features so it will be equivalent to the "sock" tool for
1306          * TCP as for SCTP.
1307          *
1308          * FIXME -
1309          *
1310          * It is not very effective to use these two options in the
1311          * current command line mode of sctp_darn. For example, the
1312          * --bindx-rem option can only be used in conjunction with the
1313          * --bindx-add simply to test the function in the kernel
1314          * path. Ideally, bindx needs to be tested by a tool which
1315          * provides an interactive mode for users to change parameters
1316          * and configuration dynamically with existing endpoints and
1317          * associations.
1318          */
1319         fprintf(stderr, "Usage: %s -H <localhost> -P <localport> "
1320                 "[-h <remotehost>] [-p <remoteport>] -l|s\n"
1321                 " -H, --local\t\tspecify one of the local addresses,\n"
1322                 " -P, --local-port\tspecify the port number for local addresses,\n"
1323                 " -h, --remote\t\tspecify the peer address,\n"
1324                 " -p, --remote-port\tspecify the port number for the peer address,\n"
1325                 " -l, --listen\t\tprint messages received from the peer,\n"
1326                 " -s, --send\t\tsend messages to the peer,\n"
1327                 " -B, --bindx-add"
1328                 "\tadd the specified address(es) as additional bind\n"
1329                 "\t\t\taddresses to the local socket. Multiple addresses can\n"
1330                 "\t\t\tbe specified by using this argument multiple times.\n"
1331                 "\t\t\tFor example, '-B 10.0.0.1 -B 20.0.0.2'.\n"
1332                 " -b, --bindx-rem"
1333                 "\tremove the specified address(es) from the bind\n"
1334                 "\t\t\taddresses of the local socket. Multiple addresses can\n"
1335                 "\t\t\tbe specified by using this argument multiple times.\n"
1336                 "\t\t\tFor example, '-b 10.0.0.1 -b 20.0.0.2'.\n"
1337                 " -c, --connectx"
1338                 "\t\tuse the specified address(es) for connection to the\n"
1339                 "\t\t\tpeer socket. Multiple addresses can be specified by\n"
1340                 "\t\t\tusing this argument multiple times.\n"
1341                 "\t\t\tFor example, '-c 10.0.0.1 -c 20.0.0.2'.\n"
1342                 "\t\t\tThis option is incompatible with the -h option.\n"
1343                 " -I\t\t\tuse the interactive mode.\n"
1344                 " -i\t\t\tsetup the specified number of endpoints by using the\n"
1345                 "\t\t\tspecified local host (-H) and local port (-P). The port\n"
1346                 "\t\t\tnumber will be incremented by one for each additional\n"
1347                 "\t\t\tendpoint.  All of these endpoints will be listening.\n"
1348                 "\t\t\tIf a remote host (-h) and a remote port are also\n"
1349                 "\t\t\tspecified, the first endpoint will start sending fixed\n"
1350                 "\t\t\tsized messages to the remote host.\n"
1351                 " -m\t\t\tspecify the sockopt sndbuf/rcvbuf size.\n"
1352                 " -n\t\t\tset the socket(s) to be in the non-blocking mode.\n"
1353                 "\t\t\tcollect messages from stdin and deliver them to the\n"
1354                 "\t\t\tpeer,\n"
1355                 "--use-poll\t\tuse system call poll() for polling among the\n"
1356                 "\t\t\tnumber of endpoints specified by the -i option. Without\n"
1357                 "\t\t\tthis option, select() would be used as default.\n"
1358                 " -t\t\t\tuse SOCK_STREAM tcp-style sockets.\n"
1359                 " -z\t\t\tspecify the message size to be sent.  The default\n"
1360                 "\t\t\tmessage size generated would be 16K.\n"
1361                 " --interface=\"ifname\"\tselect interface for sin6_scope_id.\n",
1362                 argv0);
1363 }
1364
1365
1366 /* This function checks messages to see if they are of type 'event'
1367  * and if they are well-formed.
1368  */
1369 int
1370 user_test_check_message(struct msghdr *msg,
1371                         int controllen,
1372                         sctp_cmsg_t event)
1373 {
1374
1375
1376         if (msg->msg_controllen != controllen) {
1377                 fprintf(stderr,
1378                         "Got control structure of length %d, not %d\n",
1379                         msg->msg_controllen, controllen);
1380                 exit(1);
1381         }
1382         if (controllen > 0 && event != CMSG_FIRSTHDR(msg)->cmsg_type) {
1383                 fprintf(stderr, "Wrong kind of event: %d, not %d\n",
1384                         CMSG_FIRSTHDR(msg)->cmsg_type, event);
1385                 exit(1);
1386         }
1387
1388         return 1;
1389
1390 } /* user_test_check_message() */
1391
1392 /* Add another address represented as the string 'parm' to the list
1393  * addrs.  The argument count is the number of addrs on input and is
1394  * adjusted for output.
1395  */
1396 struct sockaddr *
1397 append_addr(const char *parm, struct sockaddr *addrs, int *ret_count)
1398 {
1399         struct sockaddr *new_addrs = NULL;
1400         void *aptr;
1401         struct sockaddr *sa_addr;
1402         struct sockaddr_in *b4ap;
1403         struct sockaddr_in6 *b6ap;
1404         struct hostent *hst4 = NULL;
1405         struct hostent *hst6 = NULL;
1406         int i4 = 0;
1407         int i6 = 0;
1408         int j;
1409         int orig_count = *ret_count;
1410         int count = orig_count;
1411
1412
1413         /* Get the entries for this host.  */
1414         hst4 = gethostbyname(parm);
1415         hst6 = gethostbyname2(parm, AF_INET6);
1416
1417         if ((NULL == hst4 || hst4->h_length < 1)
1418             && (NULL == hst6 || hst6->h_length < 1)) {
1419                 fprintf(stderr, "bad hostname: %s\n", parm);
1420                 goto finally;
1421         }
1422
1423
1424         /* Figure out the number of addresses.  */
1425         if (NULL != hst4) {
1426                 for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) {
1427                         count++;
1428                 }
1429         }
1430         if (NULL != hst6) {
1431                 for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) {
1432                         count++;
1433                 }
1434         }
1435
1436         /* Expand memory for the new addresses.  Assume all the addresses 
1437          * are v6 addresses.
1438          */
1439         new_addrs = (struct sockaddr *)
1440                 realloc(addrs, sizeof(struct sockaddr_in6) * count);
1441
1442         if (NULL == new_addrs) {
1443                 count = *ret_count;
1444                 goto finally;
1445         }
1446
1447         /* Skip the existing addresses. */
1448         aptr = new_addrs; 
1449         for (j = 0; j < orig_count; j++) {
1450                 sa_addr = (struct sockaddr *)aptr;
1451                 switch(sa_addr->sa_family) {
1452                 case AF_INET:
1453                         aptr += sizeof(struct sockaddr_in);
1454                         break;
1455                 case AF_INET6:
1456                         aptr += sizeof(struct sockaddr_in6);
1457                         break;
1458                 default:
1459                         count = orig_count;
1460                         goto finally;
1461                 }
1462         }       
1463                                         
1464         /* Put the new addresses away.  */
1465         if (NULL != hst4) {
1466                 for (j = 0; j < i4; ++j) {
1467                         b4ap = (struct sockaddr_in *)aptr;
1468                         bzero(b4ap, sizeof(*b4ap));
1469                         b4ap->sin_family = AF_INET;
1470                         b4ap->sin_port = htons(local_port);
1471                         bcopy(hst4->h_addr_list[j], &b4ap->sin_addr,
1472                               hst4->h_length);
1473
1474                         aptr += sizeof(struct sockaddr_in);
1475                 } /* for (loop through the new v4 addresses) */
1476         }
1477
1478         if (NULL != hst6) {
1479                 for (j = 0; j < i6; ++j) {
1480                         b6ap = (struct sockaddr_in6 *)aptr;
1481                         bzero(b6ap, sizeof(*b6ap));
1482                         b6ap->sin6_family = AF_INET6;
1483                         b6ap->sin6_port =  htons(local_port);
1484                         b6ap->sin6_scope_id = if_index;
1485                         bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr,
1486                               hst6->h_length);
1487
1488                         aptr += sizeof(struct sockaddr_in6);
1489                 } /* for (loop through the new v6 addresses) */
1490         }
1491
1492  finally:
1493
1494         *ret_count = count;
1495
1496         return new_addrs;
1497
1498 } /* append_addr() */
1499
1500 static int
1501 parse_inter_commands(char *argv0, char *input, int snd_only)
1502 {
1503         int i;
1504         char *p;
1505         int len;
1506         int set = 0;
1507         int val;
1508         struct sockaddr *tmp_addrs = NULL;
1509
1510
1511         p = input;
1512         if (*p == '?' || *p == '\n') {
1513                 printf("Interactive commands:\n");
1514                 printf("snd=<int>        - Do a sendmsg with the specified");
1515                 printf(" length.\n");
1516                 printf("rcv=<int>        - Do a recvmsg.");
1517                 printf("The length is ignored for now.\n");
1518                 printf("bindx-add=<addr> - Add a local address");
1519                 printf(" with bindx. \n");
1520                 printf("bindx-rem=<addr> - Remove a local address");
1521                 printf(" with bindx. \n");
1522                 printf("rcvbuf=<int>     - Get/Set receive buffer size\n");
1523                 printf("sndbuf=<int>     - Get/Set send buffer size.\n");
1524                 printf("primary=<addr>   - Get/Set association's primary\n");
1525                 printf("peer_primary=addr- Set association's peer_primary\n");
1526                 printf("maxseg=<int>     - Get/Set Maximum fragment size.\n");
1527                 printf("nodelay=<0|1>    - Get/Set NODELAY option.\n");
1528                 printf("shutdown         - Shutdown the association.\n");
1529                 printf("abort            - Abort the association.\n");
1530                 printf("?                - Help. Display this message.\n");
1531                 return -1;
1532         }
1533
1534         for (i = 0; i < REALLY_BIG; i++) {
1535                 if (('=' == *p) ||
1536                     ('?' == *p) ||
1537                     ('\n' == *p)) {
1538                         if ('=' == *p) {
1539                                 set = 1;
1540                         }
1541                         *p++ = '\0';
1542                         break;
1543                 }
1544                 p++;
1545         }
1546         if (i >= REALLY_BIG) {
1547                 printf("Invalid input.\n");
1548                 return -1;
1549         }
1550
1551         i = 0;
1552         while (NULL != inter_commands[i].cmd) {
1553                 if (!strcmp(input, inter_commands[i].cmd)) {
1554                         switch (i) {
1555                         case INTER_SND:
1556                                 if (snd_only) {
1557                                         if (*p < '0' || *p > '9') {
1558                                                 goto err_input;
1559                                         }
1560                                         snd_func(p);
1561                                 } else {
1562                                         goto err_input;
1563                                 }
1564                                 break;
1565                         case INTER_RCV:
1566                                 if (snd_only) {
1567                                         goto err_input;
1568                                 }
1569                                 break;
1570                         case INTER_SNDBUF:
1571                                 if (set) {
1572                                         if (*p < '0' || *p > '9') {
1573                                                 goto err_input;
1574                                         }
1575                                 }
1576                                 len = (set) ? atoi(p) : 0;
1577                                 sndbuf_func(argv0, inter_sk, len, set);
1578                                 break;
1579                         case INTER_RCVBUF:
1580                                 if (set) {
1581                                         if (*p < '0' || *p > '9') {
1582                                                 goto err_input;
1583                                         }
1584                                 }
1585                                 len = (set) ? atoi(p) : 0;
1586                                 rcvbuf_func(argv0, inter_sk, len, set);
1587                                 break;
1588                         case INTER_BINDX_ADD:
1589                                 tmp_addrs = get_bindx_addr(p, &len);
1590                                 bindx_func(argv0, inter_sk, tmp_addrs, len,
1591                                         SCTP_BINDX_ADD_ADDR, local_port);
1592                                 free(tmp_addrs);
1593                                 break;
1594                         case INTER_BINDX_REM:
1595                                 tmp_addrs = get_bindx_addr(p, &len);
1596                                 bindx_func(argv0, inter_sk, tmp_addrs, len,
1597                                         SCTP_BINDX_REM_ADDR, local_port);
1598                                 free(tmp_addrs);
1599                                 break;
1600                         case INTER_SET_PRIM:
1601                                 primary_func(argv0, inter_sk, p, set);
1602                                 break;
1603                         case INTER_SET_PEER_PRIM:
1604                                 peer_primary_func(argv0, inter_sk, p, set);
1605                                 break;
1606                         case INTER_SHUTDOWN:
1607                                 shutdown_func(argv0, &inter_sk, SHUTDOWN_SHUTDOWN);
1608                                 break;
1609                         case INTER_ABORT:
1610                                 shutdown_func(argv0, &inter_sk, SHUTDOWN_ABORT);
1611                                 break;
1612                         case INTER_NODELAY:
1613                                 if (set) {
1614                                         if (*p < '0' || *p > '9') {
1615                                                 goto err_input;
1616                                         }
1617                                 }
1618                                 val = (set) ? atoi(p) : 0;
1619                                 nodelay_func(argv0, inter_sk, val, set);
1620                                 break;
1621                         case INTER_MAXSEG:
1622                                 if (set) {
1623                                         if (*p < '0' || *p > '9') {
1624                                                 goto err_input;
1625                                         }
1626                                 }
1627                                 val = (set) ? atoi(p) : 0;
1628                                 maxseg_func(argv0, inter_sk, val, set);
1629                                 break;
1630                         default:
1631                                 goto err_input;
1632                                 break;
1633                         }
1634
1635                         return i;
1636                 }
1637                 i++;
1638         }
1639
1640 err_input:
1641         printf("Invalid input.\n");
1642         return -1;
1643
1644 } /* parse_inter_commands() */
1645
1646 static char *
1647 gen_message(int len)
1648 {
1649
1650         char *buf;
1651         char *p;
1652         int i;
1653
1654         buf = malloc(len);
1655
1656         if (NULL != buf) {
1657                 for (i = 0, p = buf; i < len; i++, p++) {
1658                         if (gen_data > GEN_DATA_LAST) {
1659                                 gen_data = GEN_DATA_FIRST;
1660                         }
1661                         *p = gen_data++;
1662                 }
1663         }
1664
1665         return(buf);
1666
1667 } /* gen_message() */
1668
1669 static void
1670 snd_func(char *input)
1671 {
1672
1673         int len;
1674
1675         len = atoi(input);
1676         if (!(inter_outbuf = gen_message(len))) {
1677                 fprintf(stderr, "Cannot allocate out message.\n");
1678                 exit(1);
1679         }
1680         inter_outlen = len;
1681
1682 } /* snd_func() */
1683
1684 static void
1685 sndbuf_func(char *argv0, int sk, int len, int set)
1686 {
1687         int error;
1688         socklen_t optlen;
1689
1690         if (set) {
1691                 error = setsockopt(sk, SOL_SOCKET, SO_SNDBUF,
1692                         (char *)&len, sizeof(len));
1693         } else {
1694                 optlen = sizeof(len);
1695                 error = getsockopt(sk, SOL_SOCKET, SO_SNDBUF,
1696                         (char *)&len, &optlen);
1697         }
1698         if (error != 0) {
1699                 fprintf(stderr, "%s: Error setting/getting sndbuf: %s.\n",
1700                         argv0, strerror(errno));
1701                 exit(1);
1702         }
1703
1704         if (!set) {
1705                 printf("sndbuf is %d.\n", len);
1706         }
1707
1708 } /* sndbuf_func() */
1709
1710 static void
1711 rcvbuf_func(char *argv0, int sk, int len, int set)
1712 {
1713         int error;
1714         socklen_t optlen;
1715
1716         if (set) {
1717                 error = setsockopt(sk, SOL_SOCKET, SO_RCVBUF,
1718                         (char *)&len, sizeof(len));
1719         } else {
1720                 optlen = sizeof(len);
1721                 error = getsockopt(sk, SOL_SOCKET, SO_RCVBUF,
1722                         (char *)&len, &optlen);
1723         }
1724         if (error != 0) {
1725                 fprintf(stderr, "%s: Error setting/getting rcvbuf: %s.\n",
1726                         argv0, strerror(errno));
1727                 exit(1);
1728         }
1729
1730         if (!set) {
1731                 printf("rcvbuf is %d.\n", len);
1732         }
1733
1734 } /* rcvbuf_func() */
1735
1736
1737 static struct sockaddr *
1738 get_bindx_addr(char *in, int *count)
1739 {
1740
1741         struct sockaddr *tmp_addrs = NULL;
1742         char *p = in;
1743
1744         /* Set the buffer for address parsing.  */
1745         while ('\n' != *p) {
1746                 p++;
1747         }
1748         *p = '\0';
1749
1750         *count = 0;
1751
1752         tmp_addrs = append_addr(in, tmp_addrs, count);
1753         if (NULL == tmp_addrs) {
1754                 /* We have no memory, so keep fprintf()
1755                  * from trying to allocate more.
1756                  */
1757                 fprintf(stderr, "No memory to add ");
1758                 fprintf(stderr, in);
1759                 fprintf(stderr, "\n");
1760                 exit(2);
1761         }
1762         return tmp_addrs;
1763
1764 } /* get_bindx_addr() */
1765
1766 static int
1767 bindx_func(char *argv0, int sk, struct sockaddr *addrs, int count, int flag, int portnum)
1768 {
1769
1770         int error;
1771         int i;
1772         struct sockaddr *sa_addr;
1773         void *aptr;
1774
1775
1776         if (0 == portnum) {
1777                 fprintf(stderr, "%s: A non-0 local port number is ", argv0);
1778                 fprintf(stderr, "required for bindx to work!\n");
1779                 return -1 ;
1780         }
1781
1782         /* Set the port in every address.  */
1783         aptr = addrs;
1784         for (i = 0; i < count; i++) {
1785                 sa_addr = (struct sockaddr *)aptr;
1786
1787                 switch(sa_addr->sa_family) {
1788                 case AF_INET:
1789                         ((struct sockaddr_in *)sa_addr)->sin_port =
1790                                 htons(portnum);
1791                         aptr += sizeof(struct sockaddr_in);
1792                         break;
1793                 case AF_INET6:
1794                         ((struct sockaddr_in6 *)sa_addr)->sin6_port =
1795                                 htons(portnum);
1796                         aptr += sizeof(struct sockaddr_in6);
1797                         break;
1798                 default:
1799                         fprintf(stderr, "Invalid address family\n");
1800                         return -1;
1801                 }
1802         }
1803
1804         error = sctp_bindx(sk, addrs, count, flag);
1805
1806         if (error != 0) {
1807                 if (flag == SCTP_BINDX_ADD_ADDR) {
1808                         fprintf(stderr, "%s: error adding addrs: %s.\n",
1809                                 argv0, strerror(errno));
1810                         return -1;
1811                 } else {
1812                         fprintf(stderr, "%s: error removing addrs: %s.\n",
1813                                 argv0, strerror(errno));
1814                         return -1;
1815                 }
1816         }
1817
1818         return 0;
1819
1820 } /* bindx_func() */
1821
1822 static int
1823 connectx_func(char *argv0, int sk, struct sockaddr *addrs, int count)
1824 {
1825
1826         int error;
1827         int i;
1828         struct sockaddr *sa_addr;
1829         void *aptr;
1830
1831
1832         if (0 == remote_port) {
1833                 fprintf(stderr, "%s: A non-0 remote port number is ", argv0);
1834                 fprintf(stderr, "required for connectx to work!\n");
1835                 return -1 ;
1836         }
1837
1838         /* Set the port in every address.  */
1839         aptr = addrs;
1840         for (i = 0; i < count; i++) {
1841                 sa_addr = (struct sockaddr *)aptr;
1842
1843                 switch(sa_addr->sa_family) {
1844                 case AF_INET:
1845                         ((struct sockaddr_in *)sa_addr)->sin_port =
1846                                 htons(remote_port);
1847                         aptr += sizeof(struct sockaddr_in);
1848                         break;
1849                 case AF_INET6:
1850                         ((struct sockaddr_in6 *)sa_addr)->sin6_port =
1851                                 htons(remote_port);
1852                         aptr += sizeof(struct sockaddr_in6);
1853                         break;
1854                 default:
1855                         fprintf(stderr, "Invalid address family\n");
1856                         return -1;
1857                 }
1858         }
1859
1860         error = sctp_connectx(sk, addrs, count, NULL);
1861
1862         if (error != 0) {
1863                 if (errno == ECONNREFUSED)
1864                         return -2;
1865                 fprintf(stderr, "%s: error connecting to addrs: %s.\n",
1866                         argv0, strerror(errno));
1867                 return -1;
1868         }
1869
1870         return 0;
1871
1872 } /* connectx_func() */
1873
1874 static void
1875 primary_func(char *argv0, int sk, char *cp, int set)
1876 {
1877         struct sctp_prim prim;
1878         struct sockaddr_in *in_addr;
1879         struct sockaddr_in6 *in6_addr;
1880         struct sockaddr *saddr;
1881         socklen_t prim_len;
1882         int ret;
1883         char *p = cp;
1884         char addr_buf[INET6_ADDRSTRLEN];
1885         const char *ap = NULL;
1886
1887         prim_len = sizeof(struct sctp_prim);
1888         if (!set) {
1889                 prim.ssp_assoc_id = associd;
1890                 ret = getsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
1891                                    &prim, &prim_len); 
1892                 if (ret < 0)
1893                         goto err;
1894         
1895                 saddr = (struct sockaddr *)&prim.ssp_addr;      
1896                 if (AF_INET == saddr->sa_family) {
1897                         in_addr = (struct sockaddr_in *)&prim.ssp_addr;
1898                         ap = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf,
1899                                        INET6_ADDRSTRLEN);
1900                 } else if (AF_INET6 == saddr->sa_family) {
1901                         in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr;
1902                         ap = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf,
1903                                        INET6_ADDRSTRLEN);
1904                 }
1905                 if (!ap)
1906                         goto err;
1907                 printf("%s\n", ap);
1908                 return;
1909         }
1910
1911         /* Set the buffer for address parsing.  */
1912         while ('\n' != *p)
1913                 p++;
1914         *p = '\0';
1915
1916         prim.ssp_assoc_id = associd;    
1917         if (strchr(cp, '.')) {
1918                 in_addr = (struct sockaddr_in *)&prim.ssp_addr;
1919                 in_addr->sin_port = htons(remote_port);
1920                 in_addr->sin_family = AF_INET;
1921                 ret = inet_pton (AF_INET, cp, &in_addr->sin_addr);
1922                 if (ret <= 0)
1923                         goto err;               
1924         } else if (strchr(cp, ':')) {
1925                 in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr;
1926                 in6_addr->sin6_port = htons(remote_port);
1927                 in6_addr->sin6_family = AF_INET6;
1928                 ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
1929                 if (ret <= 0)
1930                         goto err;               
1931         } else
1932                 goto err;
1933
1934         ret = setsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
1935                             &prim, sizeof(struct sctp_prim)); 
1936         if (ret < 0)
1937                 goto err;
1938
1939         return;
1940 err:
1941         if (!errno)
1942                 errno = EINVAL;
1943         fprintf(stderr, "%s: error %s primary: %s.\n", argv0,
1944                 (set)?"setting":"getting", strerror(errno));
1945 }
1946
1947 static void
1948 peer_primary_func(char *argv0, int sk, char *cp, int set)
1949 {
1950         struct sctp_setpeerprim setpeerprim;
1951         struct sockaddr_in *in_addr;
1952         struct sockaddr_in6 *in6_addr;
1953         int peer_prim_len, ret;
1954         char *p = cp;
1955
1956         if (!set) {
1957                 goto err;
1958         }
1959
1960         peer_prim_len = sizeof(struct sctp_setpeerprim);
1961         /* Set the buffer for address parsing.  */
1962         while ('\n' != *p)
1963                 p++;
1964         *p = '\0';
1965
1966         setpeerprim.sspp_assoc_id = associd;    
1967         if (strchr(cp, '.')) {
1968                 in_addr = (struct sockaddr_in *)&setpeerprim.sspp_addr;
1969                 in_addr->sin_port = htons(local_port);
1970                 in_addr->sin_family = AF_INET;
1971                 ret = inet_pton (AF_INET, cp, &in_addr->sin_addr);
1972                 if (ret <= 0)
1973                         goto err;               
1974         } else if (strchr(cp, ':')) {
1975                 in6_addr = (struct sockaddr_in6 *)&setpeerprim.sspp_addr;
1976                 in6_addr->sin6_port = htons(local_port);
1977                 in6_addr->sin6_family = AF_INET6;
1978                 ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
1979                 if (ret <= 0)
1980                         goto err;               
1981         } else
1982                 goto err;
1983
1984         ret = setsockopt(sk, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR,
1985                             &setpeerprim, sizeof(struct sctp_setpeerprim)); 
1986         if (ret < 0)
1987                 goto err;
1988
1989         return;
1990 err:
1991         if (!errno)
1992                 errno = EINVAL;
1993         fprintf(stderr, "%s: error %s peer_primary: %s.\n", argv0,
1994                 (set)?"setting":"getting", strerror(errno));
1995 }
1996
1997 static int
1998 nodelay_func(char *argv0, int sk, int val, int set)
1999 {
2000         socklen_t optlen;
2001         int error;
2002
2003         if (set) {
2004                 error = setsockopt(sk, SOL_SCTP, SCTP_NODELAY,
2005                         (char *)&val, sizeof(val));
2006         } else {
2007                 optlen = sizeof(val);
2008                 error = getsockopt(sk, SOL_SCTP, SCTP_NODELAY,
2009                         (char *)&val, &optlen);
2010         }
2011         if (error != 0) {
2012                 fprintf(stderr, "%s: Error setting/getting nodelay: %s.\n",
2013                         argv0, strerror(errno));
2014                 exit(1);
2015         }
2016
2017         if (!set) {
2018                 printf("nodelay is %d.\n", val);
2019         }
2020
2021         return error;
2022 }
2023
2024 static int
2025 maxseg_func(char *argv0, int sk, int val, int set)
2026 {
2027         socklen_t optlen;
2028         int error;
2029
2030         if (set) {
2031                 error = setsockopt(sk, SOL_SCTP, SCTP_MAXSEG,
2032                         (char *)&val, sizeof(val));
2033         } else {
2034                 optlen = sizeof(val);
2035                 error = getsockopt(sk, SOL_SCTP, SCTP_MAXSEG,
2036                         (char *)&val, &optlen);
2037         }
2038         if (error != 0) {
2039                 fprintf(stderr, "%s: Error setting/getting maxseg: %s.\n",
2040                         argv0, strerror(errno));
2041                 exit(1);
2042         }
2043
2044         if (!set) {
2045                 printf("maxseg is %d.\n", val);
2046         }
2047
2048         return error;
2049 }
2050
2051 static int
2052 shutdown_func(char *argv0, int *skp, int shutdown_type)
2053 {
2054         struct msghdr outmessage;
2055         char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
2056         struct cmsghdr *cmsg;
2057         int error=0, bytes_sent;
2058         struct sctp_sndrcvinfo *sinfo;
2059         struct hostent *hst;
2060         char *sd_type;
2061         int sk = *skp;
2062
2063         if (shutdown_type == SHUTDOWN_ABORT)
2064                 sd_type = "ABORT";
2065         else
2066                 sd_type = "SHUTDOWN";
2067
2068         /* Verify that the association is present. */
2069         error = test_sk_for_assoc(sk, associd);
2070         if (error != 0) {
2071                 printf("The association isn't present yet! Cannot %s!\n", sd_type);
2072                 return -1;
2073         }
2074
2075         if (socket_type == SOCK_SEQPACKET) {
2076                 /* Set up the destination.  */
2077                 if (remote_host) {
2078                         hst = gethostbyname(remote_host);
2079                         if (hst == NULL) {
2080                                 hst = gethostbyname2(remote_host, AF_INET6);
2081                         }
2082
2083                         if (hst == NULL || hst->h_length < 1) {
2084                                 fprintf(stderr, "%s: bad hostname: %s\n",
2085                                         argv0, remote_host);
2086                                 exit(1);
2087                         }
2088
2089                         ra_family = hst->h_addrtype;
2090                         switch (ra_family) {
2091                         case AF_INET:
2092                                 ra_len = sizeof(remote_addr.v4);
2093                                 ra_raw = &remote_addr.v4.sin_addr;
2094                                 remote_addr.v4.sin_port = htons(remote_port);
2095                                 remote_addr.v4.sin_family = AF_INET;
2096                                 break;
2097                         case AF_INET6:
2098                                 ra_len = sizeof(remote_addr.v6);
2099                                 ra_raw = &remote_addr.v6.sin6_addr;
2100                                 remote_addr.v6.sin6_port = htons(remote_port);
2101                                 remote_addr.v6.sin6_family = AF_INET6;
2102                                 break;
2103                         default:
2104                                 fprintf(stderr, "Invalid address type.\n");
2105                                 exit(1);
2106                                 break;
2107                         }
2108                         memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
2109                 }
2110
2111                 /* Initialize the message struct we use to pass messages to
2112                  * the remote socket.
2113                  */
2114                 outmessage.msg_name = &remote_addr;
2115                 outmessage.msg_namelen = ra_len;
2116
2117                 outmessage.msg_iov = NULL;
2118                 outmessage.msg_iovlen = 0;
2119                 outmessage.msg_control = outcmsg;
2120                 outmessage.msg_controllen = sizeof(outcmsg);
2121                 outmessage.msg_flags = 0;
2122
2123                 cmsg = CMSG_FIRSTHDR(&outmessage);
2124                 cmsg->cmsg_level = IPPROTO_SCTP;
2125                 cmsg->cmsg_type = SCTP_SNDRCV;
2126                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
2127                 outmessage.msg_controllen = cmsg->cmsg_len;
2128                 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
2129                 memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
2130                 if (shutdown_type == SHUTDOWN_ABORT)
2131                         sinfo->sinfo_flags |= SCTP_ABORT;
2132                 else
2133                         sinfo->sinfo_flags |= SCTP_EOF;
2134
2135                 sinfo->sinfo_assoc_id = associd;
2136         
2137                 bytes_sent = sendmsg(sk, &outmessage, 0);
2138                 if (bytes_sent != 0) {
2139                         printf("Failure:  %s.\n", strerror(errno));
2140                         return -1;
2141                 }
2142
2143                 /* Receive the COMM_LOST or SHUTDOWN_COMP event. */
2144                 test_recv_assoc_change(sk);
2145         } else {
2146                 if (shutdown_type == SHUTDOWN_ABORT) {
2147                         struct  linger {
2148                                 int  l_onoff; 
2149                                 int  l_linger;
2150                         } data = {1, 0};
2151                         error = setsockopt(sk, SOL_SOCKET, SO_LINGER,
2152                                            (char *)&data, sizeof(data));
2153                         if (error != 0) {
2154                                 printf("setsockopt failed %s\n", strerror(errno));
2155                                 exit(1);
2156                         }
2157                 }
2158                 error = close(sk);
2159                 if (error != 0) {
2160                         printf("close failed %s\n", strerror(errno));
2161                         exit(1);
2162                 }
2163                 *skp = sk = build_endpoint(argv0, local_port);
2164         }
2165
2166         /* Verify that the association is no longer present.  */
2167         error = test_sk_for_assoc(sk, associd);
2168         if (error != 0) {
2169                 printf("Successfully %s the original association\n", sd_type);
2170                 associd = 0;
2171                 new_connection = 1;
2172         } else {
2173                 printf("%s failed\n", sd_type);
2174                 exit(1);
2175         }
2176
2177         return 0;
2178 }
2179
2180 static int
2181 test_sk_for_assoc(int sk, sctp_assoc_t assoc_id)
2182 {
2183         int error = 0;
2184         struct sctp_status status;
2185         socklen_t status_len;
2186
2187         memset(&status, 0, sizeof(status));
2188         if (assoc_id)
2189                 status.sstat_assoc_id = assoc_id;
2190         status_len = sizeof(struct sctp_status);
2191         error = getsockopt(sk, SOL_SCTP, SCTP_STATUS,
2192                         (char *)&status, &status_len);
2193         return error;
2194 }
2195
2196 /* Receive a notification and return the corresponding associd if the event is
2197  * SCTP_COMM_UP. Return 0 for any other event.
2198  */
2199 static sctp_assoc_t
2200 test_recv_assoc_change(int sk)
2201 {
2202         struct msghdr inmessage;
2203         struct iovec iov;
2204         char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
2205         int error;
2206
2207         /* Initialize inmessage with enough space for DATA... */
2208         memset(&inmessage, 0, sizeof(inmessage));
2209         if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
2210                 printf("%s: Can't allocate memory.\n", __FUNCTION__);
2211                 exit(1);
2212         }
2213         iov.iov_len = REALLY_BIG;
2214         inmessage.msg_iov = &iov;
2215         inmessage.msg_iovlen = 1;
2216         /* or a control message.  */
2217         inmessage.msg_control = incmsg;
2218         inmessage.msg_controllen = sizeof(incmsg);
2219
2220         error = recvmsg(sk, &inmessage, MSG_WAITALL);
2221         if (error < 0) {
2222                 printf("%s: recvmsg: %s\n", __FUNCTION__, strerror(errno));
2223                 exit(1);
2224         }
2225
2226         return test_verify_assoc_change(&inmessage);
2227 }
2228
2229 /* Verify a notification and return the corresponding associd if the event is
2230  * SCTP_COMM_UP. Return 0 for any other event.
2231  */
2232 static sctp_assoc_t
2233 test_verify_assoc_change(struct msghdr *msg)
2234 {
2235         union sctp_notification *sn;
2236
2237         if (!(msg->msg_flags & MSG_NOTIFICATION)) {
2238                 fprintf(stderr, "%s: Received data when notification is expected\n",
2239                        __FUNCTION__);
2240                 exit(1);
2241         }
2242
2243         sn = (union sctp_notification *)msg->msg_iov->iov_base;
2244         if (SCTP_ASSOC_CHANGE != sn->sn_header.sn_type) {
2245                 fprintf(stderr, "%s: Received unexpected notification: %d",
2246                         __FUNCTION__, sn->sn_header.sn_type);
2247                 exit(1);
2248         }
2249
2250         switch(sn->sn_assoc_change.sac_state)
2251         {
2252         case SCTP_COMM_UP:
2253                 printf("Recieved SCTP_COMM_UP\n");
2254                 break;
2255         case SCTP_COMM_LOST:
2256                 printf("Recieved SCTP_COMM_LOST\n");
2257                 break;
2258         case SCTP_RESTART:
2259                 printf("Recieved SCTP_RESTART\n");
2260                 break;
2261         case SCTP_SHUTDOWN_COMP:
2262                 printf("Recieved SCTP_SHUTDOWN_COMP\n");
2263                 break;
2264         case SCTP_CANT_STR_ASSOC:
2265                 printf("Recieved SCTP_CANT_STR_ASSOC\n");
2266                 break;
2267         }
2268
2269         if (SCTP_COMM_UP == sn->sn_assoc_change.sac_state)
2270                 return sn->sn_assoc_change.sac_assoc_id;
2271         else
2272                 return 0;
2273 }
2274
2275 void print_addr_buf(void * laddrs, int n_laddrs)
2276 {
2277         void *addr_buf = laddrs;
2278         int i;
2279
2280         for (i = 0; i < n_laddrs; i++) {
2281                 addr_buf += print_sockaddr((struct sockaddr *)addr_buf);
2282                 printf("\n");
2283         }
2284 }
2285
2286 int print_sockaddr(struct sockaddr *sa_addr)
2287 {
2288         struct sockaddr_in *in_addr;
2289         struct sockaddr_in6 *in6_addr;
2290
2291         if (AF_INET == sa_addr->sa_family) {
2292                 in_addr = (struct sockaddr_in *)sa_addr;
2293                 printf("%d.%d.%d.%d:%d",
2294                        NIPQUAD(in_addr->sin_addr),
2295                        ntohs(in_addr->sin_port));
2296                 return sizeof(struct sockaddr_in);
2297         } else {
2298                 in6_addr = (struct sockaddr_in6 *)sa_addr;
2299                 printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%d",
2300                        NIP6(in6_addr->sin6_addr),
2301                        ntohs(in6_addr->sin6_port));
2302                 return sizeof(struct sockaddr_in6);
2303         }
2304 }