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