aboutsummaryrefslogtreecommitdiff
path: root/utils/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/sctp')
-rw-r--r--utils/sctp/Makefile53
-rw-r--r--utils/sctp/func_tests/Makefile73
-rw-r--r--utils/sctp/func_tests/test_1_to_1_accept_close.c233
-rw-r--r--utils/sctp/func_tests/test_1_to_1_addrs.c269
-rw-r--r--utils/sctp/func_tests/test_1_to_1_connect.c223
-rw-r--r--utils/sctp/func_tests/test_1_to_1_connectx.c226
-rw-r--r--utils/sctp/func_tests/test_1_to_1_events.c190
-rw-r--r--utils/sctp/func_tests/test_1_to_1_initmsg_connect.c120
-rw-r--r--utils/sctp/func_tests/test_1_to_1_nonblock.c209
-rw-r--r--utils/sctp/func_tests/test_1_to_1_recvfrom.c194
-rw-r--r--utils/sctp/func_tests/test_1_to_1_recvmsg.c205
-rw-r--r--utils/sctp/func_tests/test_1_to_1_rtoinfo.c114
-rw-r--r--utils/sctp/func_tests/test_1_to_1_send.c230
-rw-r--r--utils/sctp/func_tests/test_1_to_1_sendmsg.c366
-rw-r--r--utils/sctp/func_tests/test_1_to_1_sendto.c164
-rw-r--r--utils/sctp/func_tests/test_1_to_1_shutdown.c217
-rw-r--r--utils/sctp/func_tests/test_1_to_1_socket_bind_listen.c268
-rw-r--r--utils/sctp/func_tests/test_1_to_1_sockopt.c414
-rw-r--r--utils/sctp/func_tests/test_1_to_1_threads.c196
-rw-r--r--utils/sctp/func_tests/test_assoc_abort.c244
-rw-r--r--utils/sctp/func_tests/test_assoc_shutdown.c246
-rw-r--r--utils/sctp/func_tests/test_autoclose.c168
-rw-r--r--utils/sctp/func_tests/test_basic.c456
-rw-r--r--utils/sctp/func_tests/test_connect.c219
-rw-r--r--utils/sctp/func_tests/test_connectx.c270
-rw-r--r--utils/sctp/func_tests/test_fragments.c298
-rw-r--r--utils/sctp/func_tests/test_getname.c258
-rw-r--r--utils/sctp/func_tests/test_inaddr_any.c251
-rw-r--r--utils/sctp/func_tests/test_peeloff.c299
-rw-r--r--utils/sctp/func_tests/test_recvmsg.c160
-rw-r--r--utils/sctp/func_tests/test_sctp_sendrecvmsg.c380
-rw-r--r--utils/sctp/func_tests/test_sockopt.c1147
-rw-r--r--utils/sctp/func_tests/test_tcp_style.c463
-rw-r--r--utils/sctp/func_tests/test_timetolive.c406
-rw-r--r--utils/sctp/include/netinet/sctp.h867
-rw-r--r--utils/sctp/lib/Makefile31
-rw-r--r--utils/sctp/lib/addrs.c155
-rw-r--r--utils/sctp/lib/bindx.c78
-rw-r--r--utils/sctp/lib/connectx.c185
-rw-r--r--utils/sctp/lib/opt_info.c62
-rw-r--r--utils/sctp/lib/peeloff.c47
-rw-r--r--utils/sctp/lib/recvmsg.c101
-rw-r--r--utils/sctp/lib/sendmsg.c106
-rw-r--r--utils/sctp/testlib/Makefile41
-rw-r--r--utils/sctp/testlib/sctputil.c418
-rw-r--r--utils/sctp/testlib/sctputil.h324
46 files changed, 11644 insertions, 0 deletions
diff --git a/utils/sctp/Makefile b/utils/sctp/Makefile
new file mode 100644
index 000000000..181e6f3d5
--- /dev/null
+++ b/utils/sctp/Makefile
@@ -0,0 +1,53 @@
+#
+# network/sctp test suite Makefile.
+#
+# Copyright (C) 2009, Cisco Systems Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Garrett Cooper, July 2009
+#
+
+top_srcdir ?= ../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+LIBSCTPDIR := lib
+LIBSCTPUTILDIR := testlib
+LIBSCTP := $(LIBSCTPDIR)/libsctp.a
+LIBSCTPUTIL := $(LIBSCTPUTILDIR)/libsctputil.a
+
+FILTER_OUT_DIRS := $(LIBSCTPDIR) $(LIBSCTPUTILDIR)
+
+$(LIBSCTPDIR) $(LIBSCTPUTILDIR):
+ mkdir -p "$@"
+
+lib-clean:: $(LIBSCTPDIR) $(LIBSCTPUTILDIR)
+ for i in $^; do \
+ $(MAKE) -C "$$i" -f "$(abs_srcdir)/$$i/Makefile" clean; \
+ done
+
+
+$(LIBSCTP): $(LIBSCTPDIR)
+ $(MAKE) -C "$^" -f "$(abs_srcdir)/$^/Makefile" all
+
+$(LIBSCTPUTIL): $(LIBSCTPUTILDIR)
+ $(MAKE) -C "$^" -f "$(abs_srcdir)/$^/Makefile" all
+
+trunk-all: $(LIBSCTP) $(LIBSCTPUTIL)
+
+trunk-clean:: | lib-clean
+
+include $(top_srcdir)/include/mk/generic_trunk_target.mk
diff --git a/utils/sctp/func_tests/Makefile b/utils/sctp/func_tests/Makefile
new file mode 100644
index 000000000..d296c652a
--- /dev/null
+++ b/utils/sctp/func_tests/Makefile
@@ -0,0 +1,73 @@
+#
+# (C) Copyright IBM Corp. 2001, 2003
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+# the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+###########################################################################
+# name of file : Makefile #
+###########################################################################
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+CPPFLAGS += -I$(abs_srcdir)/../include -I$(abs_srcdir)/../testlib -DLTP
+
+LDFLAGS += $(addprefix -L$(abs_builddir)/../,lib testlib)
+
+LDLIBS += -lsctputil -lsctp -lpthread
+
+V4_TARGETS := $(patsubst $(abs_srcdir)/%.c,%,$(wildcard $(abs_srcdir)/*.c))
+
+V6_TARGETS := test_basic_v6 test_fragments_v6 test_getname_v6 \
+ test_inaddr_any_v6 test_peeloff_v6 \
+ test_sctp_sendrecvmsg_v6 test_sockopt_v6 \
+ test_tcp_style_v6 test_timetolive_v6
+
+$(V6_TARGETS): CPPFLAGS += -DTEST_V6=1
+
+%_v6.o: %.c
+ $(COMPILE.c) $(OUTPUT_OPTION) $<
+
+MAKE_TARGETS := $(V4_TARGETS) $(V6_TARGETS)
+
+v4test: $(V4_TARGETS)
+ @for a in $^; \
+ do \
+ echo "./$$a"; \
+ if ./$$a; then \
+ echo "$$a - passed"; \
+ echo ""; \
+ else \
+ echo "$$a - failed"; \
+ exit 1; \
+ fi; \
+ done
+
+v6test: $(V6_TARGETS)
+ @for a in $^; \
+ do \
+ echo "./$$a"; \
+ if ./$$a; then \
+ echo "$$a - passed"; \
+ echo ""; \
+ else \
+ echo "$$a - failed"; \
+ exit 1; \
+ fi; \
+ done
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/utils/sctp/func_tests/test_1_to_1_accept_close.c b/utils/sctp/func_tests/test_1_to_1_accept_close.c
new file mode 100644
index 000000000..ea1c57aad
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_accept_close.c
@@ -0,0 +1,233 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the accept () and close () call for
+ * 1-1 style sockets
+ *
+ * accept () Tests:
+ * ---------------
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: Invalid address
+ * TEST4: On a non-listening socket
+ * TEST5: On a established socket
+ * TEST6: On a CLOSED association
+ * TEST7: Extracting the association on the listening socket
+ *
+ * close () Tests:
+ * --------------
+ * TEST8: Bad socket descriptor
+ * TEST9: valid socket descriptor
+ * TEST10: Closed socket descriptor
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT = 0;
+
+#define SK_MAX 10
+
+int
+main(int argc, char *argv[])
+{
+ socklen_t len;
+ int i;
+ int sk,lstn_sk,clnt_sk[SK_MAX],acpt_sk,pf_class;
+ int new_sk[SK_MAX],clnt2_sk[SK_MAX];
+ int error;
+
+ struct sockaddr_in conn_addr,lstn_addr,acpt_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ for (i=0 ; i < SK_MAX ; i++)
+ new_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /* Creating a regular socket */
+ for (i = 0 ; i < SK_MAX ; i++)
+ clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ for (i = 0 ; i < SK_MAX ; i++)
+ clnt2_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /* Creating a listen socket */
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /* Binding the listen socket */
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /* Listening many sockets as we are calling too many connect here */
+ test_listen(lstn_sk, SK_MAX );
+
+ /* connect() is called just to make sure accept() doesn't block the
+ * program
+ */
+ i = 0;
+ len = sizeof(struct sockaddr_in);
+ test_connect(clnt_sk[i++], (struct sockaddr *) &conn_addr, len);
+
+ /* accept() TEST1: Bad socket descriptor EBADF, Expected error */
+ error = accept(-1, (struct sockaddr *) &acpt_addr, &len);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "accept with a bad socket descriptor"
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() with a bad socket descriptor - EBADF");
+
+ /*accept() TEST2: Invalid socket ENOTSOCK, Expected error*/
+ error = accept(0, (struct sockaddr *) &acpt_addr, &len);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "accept with invalid socket"
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() with invalid socket - ENOTSOCK");
+
+ /*accept() TEST3: Invalid address EFAULT, Expected error*/
+ error = accept(lstn_sk, (struct sockaddr *) -1, &len);
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "accept with invalid address"
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() with invalid address - EFAULT");
+
+ test_connect(clnt_sk[i++], (struct sockaddr *) &conn_addr, len);
+
+ /*accept() TEST4: on a non-listening socket EINVAL, Expected error*/
+ error = accept(sk, (struct sockaddr *) &acpt_addr, &len);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "accept on a non-listening socket"
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() on a non-listening socket - EINVAL");
+
+ test_connect(clnt_sk[i++], (struct sockaddr *) &conn_addr, len);
+
+ /*Calling accept to establish the connection*/
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len);
+
+ /*accept() TEST5: On a established socket EINVAL, Expected error*/
+ error = accept(acpt_sk, (struct sockaddr *) &acpt_addr, &len);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "accept on an established socket"
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() on an established socket - EINVAL");
+
+ /*Closing the previously established association*/
+ close(acpt_sk);
+
+ test_connect(clnt_sk[i], (struct sockaddr *) &conn_addr, len);
+
+ /*accept() TEST6: On the CLOSED association should succeed*/
+ acpt_sk = accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len);
+ if (acpt_sk < 0)
+ tst_brkm(TBROK, tst_exit, "accept a closed association"
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() a closed association - SUCCESS");
+
+ close(acpt_sk);
+
+ /*accept() TEST7: Extracting the association on the listening socket
+ as new socket, new socket socket descriptor should return*/
+ for (i = 0 ; i < (SK_MAX - 1); i++)
+ test_connect(clnt2_sk[i], (struct sockaddr *) &conn_addr, len);
+
+ for (i = 0 ; i < (SK_MAX - 1); i++)
+ new_sk[i] = test_accept(lstn_sk, (struct sockaddr *)&acpt_addr,
+ &len);
+
+ tst_resm(TPASS, "accept() on a listening socket - SUCCESS");
+
+
+ /*close() TEST8: Bad socket descriptor, EBADF Expected error*/
+ error = close(-1);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "close with a bad socket descriptor "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "close() with a bad socket descriptor - EBADF");
+
+ /*close() TEST9: valid socket descriptor should succeed*/
+ error = close(sk);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "close with a valid socket descriptor"
+ " error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "close() with a valid socket descriptor - SUCCESS");
+
+ /*close() TEST10: closed socket descriptor, EBADF Expected error*/
+ error = close(sk);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "close with a closed socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "close() with a closed socket descriptor - EBADF");
+
+ for (i = 0 ; i < SK_MAX ; i++) {
+ close(clnt_sk[i]);
+ close(new_sk[i]);
+ close(clnt2_sk[i]);
+ }
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_addrs.c b/utils/sctp/func_tests/test_1_to_1_addrs.c
new file mode 100644
index 000000000..40eed7fe5
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_addrs.c
@@ -0,0 +1,269 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the sctp_getladdrs (), sctp_freealddrs (),
+ * sctp_getpaddrs (), sctp_freeapaddrs () for 1-1 style sockets
+ *
+ * sctp_getladdrs () Tests:
+ * -----------------------
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: Socket of different protocol
+ * TEST4: Getting the local addresses
+ *
+ * sctp_freealddrs () Tests:
+ * ------------------------
+ * TEST5: Freeing the local address
+ *
+ * sctp_getpaddrs () Tests:
+ * -----------------------
+ * TEST6: Bad socket descriptor
+ * TEST7: Invalid socket
+ * TEST8: Socket of different protocol
+ * TEST9: Getting the peers addresses
+ *
+ * sctp_freeapddrs () Tests:
+ * ------------------------
+ * TEST10: Freeing the peer's address
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int error;
+ socklen_t len;
+ int lstn_sk,clnt_sk,acpt_sk,pf_class,sk1;
+ struct msghdr outmessage;
+ struct msghdr inmessage;
+ char *message = "hello, world!\n";
+ struct iovec iov_rcv;
+ struct sctp_sndrcvinfo *sinfo;
+ int msg_count;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct iovec out_iov;
+ char * buffer_rcv;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ struct sockaddr *laddrs, *paddrs;
+
+ struct sockaddr_in conn_addr,lstn_addr,acpt_addr;
+ struct sockaddr_in *addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ /*Creating a regular socket*/
+ clnt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*Creating a listen socket*/
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening many sockets as we are calling too many connect here*/
+ test_listen(lstn_sk, 1);
+
+ len = sizeof(struct sockaddr_in);
+
+ test_connect(clnt_sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len);
+
+ memset(&inmessage, 0, sizeof(inmessage));
+ buffer_rcv = malloc(REALLY_BIG);
+
+ iov_rcv.iov_base = buffer_rcv;
+ iov_rcv.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov_rcv;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ msg_count = strlen(message) + 1;
+
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &lstn_addr;
+ outmessage.msg_namelen = sizeof(lstn_addr);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = msg_count;
+
+ test_sendmsg(clnt_sk, &outmessage, MSG_NOSIGNAL, msg_count);
+
+ test_recvmsg(acpt_sk, &inmessage, MSG_NOSIGNAL);
+
+ /*sctp_getladdrs() TEST1: Bad socket descriptor, EBADF Expected error*/
+ error = sctp_getladdrs(-1, 0, &laddrs);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "sctp_getladdrs with a bad socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_getladdrs() with a bad socket descriptor - "
+ "EBADF");
+
+ /*sctp_getladdrs() TEST2: Invalid socket, ENOTSOCK Expected error*/
+ error = sctp_getladdrs(0, 0, &laddrs);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "sctp_getladdrs with invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_getladdrs() with invalid socket - ENOTSOCK");
+
+ /*sctp_getladdrs() TEST3: socket of different protocol
+ EOPNOTSUPP Expected error*/
+ sk1 = socket(pf_class, SOCK_STREAM, IPPROTO_IP);
+ error = sctp_getladdrs(sk1, 0, &laddrs);
+ if (error != -1 || errno != EOPNOTSUPP)
+ tst_brkm(TBROK, tst_exit, "sctp_getladdrs with socket of "
+ "different protocol error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_getladdrs() with socket of different protocol - "
+ "EOPNOTSUPP");
+
+ /*sctp_getladdrs() TEST4: Getting the local addresses*/
+ error = sctp_getladdrs(lstn_sk, 0, &laddrs);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "sctp_getladdrs with valid socket "
+ "error:%d, errno:%d", error, errno);
+
+ addr = (struct sockaddr_in *)laddrs;
+ if (addr->sin_port != lstn_addr.sin_port ||
+ addr->sin_family != lstn_addr.sin_family ||
+ addr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr)
+ tst_brkm(TBROK, tst_exit, "sctp_getladdrs comparision failed");
+
+ tst_resm(TPASS, "sctp_getladdrs() - SUCCESS");
+
+ /*sctp_freealddrs() TEST5: freeing the local address*/
+ if ((sctp_freeladdrs(laddrs)) < 0)
+ tst_brkm(TBROK, tst_exit, "sctp_freeladdrs "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_freeladdrs() - SUCCESS");
+
+ /*sctp_getpaddrs() TEST6: Bad socket descriptor, EBADF Expected error*/
+ error = sctp_getpaddrs(-1, 0, &paddrs);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with a bad socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_getpaddrs() with a bad socket descriptor - "
+ "EBADF");
+
+ /*sctp_getpaddrs() TEST7: Invalid socket, ENOTSOCK Expected error*/
+ error = sctp_getpaddrs(0, 0, &paddrs);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_getpaddrs() with invalid socket - ENOTSOCK");
+
+ /*sctp_getpaddrs() TEST8: socket of different protocol
+ EOPNOTSUPP Expected error*/
+ error = sctp_getpaddrs(sk1, 0, &laddrs);
+ if (error != -1 || errno != EOPNOTSUPP)
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with socket of "
+ "different protocol error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_getpaddrs() with socket of different protocol - "
+ "EOPNOTSUPP");
+
+ /*sctp_getpaddrs() TEST9: Getting the peer addresses*/
+ error = sctp_getpaddrs(acpt_sk, 0, &paddrs);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with valid socket "
+ "error:%d, errno:%d", error, errno);
+
+ addr = (struct sockaddr_in *)paddrs;
+ if (addr->sin_port != acpt_addr.sin_port ||
+ addr->sin_family != acpt_addr.sin_family ||
+ addr->sin_addr.s_addr != acpt_addr.sin_addr.s_addr)
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs comparision failed");
+
+ tst_resm(TPASS, "sctp_getpaddrs() - SUCCESS");
+
+ /*sctp_freeapddrs() TEST10: freeing the peer address*/
+ if ((sctp_freepaddrs(paddrs)) < 0)
+ tst_brkm(TBROK, tst_exit, "sctp_freepaddrs "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_freepaddrs() - SUCCESS");
+
+ close(clnt_sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_connect.c b/utils/sctp/func_tests/test_1_to_1_connect.c
new file mode 100644
index 000000000..6670f72dc
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_connect.c
@@ -0,0 +1,223 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the connect () call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: Invalid address
+ * TEST4: Invalid address length
+ * TEST5: Invalid address family
+ * TEST6: Valid blocking connect
+ * TEST7: Connect when accept queue is full
+ * TEST8: On a listening socket
+ * TEST9: On established socket
+ * TEST10: Connect to re-establish a closed association.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <netinet/sctp.h>
+#include "sctputil.h"
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT = 0;
+
+#define SK_MAX 10
+
+int
+main(int argc, char *argv[])
+{
+ int error,i;
+ socklen_t len;
+ int sk,lstn_sk,clnt_sk[SK_MAX],acpt_sk[SK_MAX],pf_class;
+ int sk1,clnt2_sk;
+
+ struct sockaddr_in conn_addr,lstn_addr,acpt_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*Creating a listen socket*/
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*Creating a regular socket*/
+ for (i = 0 ; i < SK_MAX ; i++)
+ clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ clnt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, SK_MAX-1);
+
+
+ /*connect () TEST1: Bad socket descriptor, EBADF Expected error*/
+ len = sizeof(struct sockaddr_in);
+ error = connect(-1, (const struct sockaddr *) &conn_addr, len);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "connect with bad socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() with bad socket descriptor - EBADF");
+
+ /*connect () TEST2: Invalid socket, ENOTSOCK Expected error*/
+ error = connect(0, (const struct sockaddr *) &conn_addr, len);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "connect with invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() with invalid socket - ENOTSOCK");
+
+ /*connect () TEST3: Invalid address, EFAULT Expected error*/
+ error = connect(sk, (const struct sockaddr *) -1, len);
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "connect with invalid address "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() with invalid address - EFAULT");
+
+ /*connect () TEST4: Invalid address length, EINVAL Expected error*/
+ error = connect(sk, (const struct sockaddr *) &conn_addr, (len - 3));
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "connect with invalid address length "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() with invalid address length - EINVAL");
+
+ /*connect () TEST5: Invalid address family, EINVAL Expect error*/
+ conn_addr.sin_family = 9090; /*Assigning invalid address family*/
+ error = connect(sk, (const struct sockaddr *) &conn_addr, len);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "connect with invalid address family "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() with invalid address family - EINVAL");
+
+ conn_addr.sin_family = AF_INET;
+
+ /*connect () TEST6: Blocking connect, should pass*/
+ /*All the be below blocking connect should pass as socket will be
+ listening SK_MAX clients*/
+ for (i = 0 ; i < SK_MAX ; i++) {
+ error = connect(clnt_sk[i], (const struct sockaddr *)&conn_addr,
+ len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "valid blocking connect "
+ "error:%d, errno:%d", error, errno);
+ }
+
+ tst_resm(TPASS, "valid blocking connect() - SUCCESS");
+
+ /*connect () TEST7: connect when accept queue is full, ECONNREFUSED
+ Expect error*/
+ /*Now that accept queue is full, the below connect should fail*/
+ error = connect(clnt2_sk, (const struct sockaddr *) &conn_addr, len);
+ if (error != -1 || errno != ECONNREFUSED)
+ tst_brkm(TBROK, tst_exit, "connect when accept queue is full "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() when accept queue is full - ECONNREFUSED");
+
+ /*Calling a accept first to estblish the pending connections*/
+ for (i=0 ; i < SK_MAX ; i++)
+ acpt_sk[i] = test_accept(lstn_sk,
+ (struct sockaddr *) &acpt_addr, &len);
+
+ /*connect () TEST8: from a listening socket, EISCONN Expect error*/
+ error = connect(lstn_sk, (const struct sockaddr *) &lstn_addr, len);
+ if (error != -1 || errno != EISCONN)
+ tst_brkm(TBROK, tst_exit, "connect on a listening socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() on a listening socket - EISCONN");
+
+ /*connect() TEST9: On established socket, EISCONN Expect error*/
+ i=0;
+ error = connect(acpt_sk[i], (const struct sockaddr *) &lstn_addr, len);
+ if (error != -1 || errno != EISCONN)
+ tst_brkm(TBROK, tst_exit, "connect on an established socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() on an established socket - EISCONN");
+
+ for (i = 0 ; i < 4 ; i++) {
+ close(clnt_sk[i]);
+ close(acpt_sk[i]);
+ }
+
+ /* connect() TEST10: Re-establish an association that is closed.
+ * should succeed.
+ */
+ error = connect(sk1, (const struct sockaddr *)&conn_addr, len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "Re-establish an association that "
+ "is closed error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect() to re-establish a closed association - "
+ "SUCCESS");
+
+ close(sk);
+ close(sk1);
+ close(lstn_sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_connectx.c b/utils/sctp/func_tests/test_1_to_1_connectx.c
new file mode 100644
index 000000000..04e20bf1b
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_connectx.c
@@ -0,0 +1,226 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the sctp_connectx () call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: Invalid address
+ * TEST4: Invalid address length
+ * TEST5: Invalid address family
+ * TEST6: Valid blocking sctp_connectx
+ * TEST7: Connect when accept queue is full
+ * TEST8: On a listening socket
+ * TEST9: On established socket
+ * TEST10: Connect to re-establish a closed association.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <netinet/sctp.h>
+#include "sctputil.h"
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT = 0;
+
+#define SK_MAX 10
+
+int
+main(int argc, char *argv[])
+{
+ int error,i;
+ socklen_t len;
+ int sk,lstn_sk,clnt_sk[SK_MAX],acpt_sk[SK_MAX],pf_class;
+ int sk1,clnt2_sk;
+
+ struct sockaddr_in conn_addr,lstn_addr,acpt_addr;
+ struct sockaddr *tmp_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*Creating a listen socket*/
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*Creating a regular socket*/
+ for (i = 0 ; i < SK_MAX ; i++)
+ clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ clnt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, SK_MAX-1);
+
+
+ /*sctp_connectx () TEST1: Bad socket descriptor, EBADF Expected error*/
+ len = sizeof(struct sockaddr_in);
+ error = sctp_connectx(-1, (struct sockaddr *) &conn_addr, 1, NULL);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx with bad socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() with bad socket descriptor - EBADF");
+
+ /*sctp_connectx () TEST2: Invalid socket, ENOTSOCK Expected error*/
+ error = sctp_connectx(0, (struct sockaddr *) &conn_addr, 1, NULL);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() with invalid socket - ENOTSOCK");
+
+ /*sctp_connectx () TEST3: Invalid address, EINVAL Expected error*/
+ tmp_addr = (struct sockaddr *) malloc(sizeof(struct sockaddr) - 1);
+ tmp_addr->sa_family = AF_INET;
+ error = sctp_connectx(sk, tmp_addr, 1, NULL);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() with invalid address - EINVAL");
+
+ /*sctp_connectx () TEST4: Invalid address length, EINVAL Expected error*/
+ error = sctp_connectx(sk, (struct sockaddr *) &conn_addr, 0, NULL);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address length "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() with invalid address length - EINVAL");
+
+ /*sctp_connectx () TEST5: Invalid address family, EINVAL Expect error*/
+ conn_addr.sin_family = 9090; /*Assigning invalid address family*/
+ error = sctp_connectx(sk, (struct sockaddr *) &conn_addr, 1, NULL);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address family "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() with invalid address family - EINVAL");
+
+ conn_addr.sin_family = AF_INET;
+
+ /*sctp_connectx () TEST6: Blocking sctp_connectx, should pass*/
+ /*All the be below blocking sctp_connectx should pass as socket will be
+ listening SK_MAX clients*/
+ for (i = 0 ; i < SK_MAX ; i++) {
+ error = sctp_connectx(clnt_sk[i], (struct sockaddr *)&conn_addr,
+ 1, NULL);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "valid blocking sctp_connectx "
+ "error:%d, errno:%d", error, errno);
+ }
+
+ tst_resm(TPASS, "valid blocking sctp_connectx() - SUCCESS");
+
+ /*sctp_connectx () TEST7: sctp_connectx when accept queue is full, ECONNREFUSED
+ Expect error*/
+ /*Now that accept queue is full, the below sctp_connectx should fail*/
+ error = sctp_connectx(clnt2_sk, (struct sockaddr *) &conn_addr, 1, NULL);
+ if (error != -1 || errno != ECONNREFUSED)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx when accept queue is full "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() when accept queue is full - ECONNREFUSED");
+
+ /*Calling a accept first to estblish the pending sctp_connectxions*/
+ for (i=0 ; i < SK_MAX ; i++)
+ acpt_sk[i] = test_accept(lstn_sk,
+ (struct sockaddr *) &acpt_addr, &len);
+
+ /*sctp_connectx () TEST8: from a listening socket, EISCONN Expect error*/
+ error = sctp_connectx(lstn_sk, (struct sockaddr *) &lstn_addr, 1, NULL);
+ if (error != -1 || errno != EISCONN)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx on a listening socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() on a listening socket - EISCONN");
+
+ /*sctp_connectx() TEST9: On established socket, EISCONN Expect error*/
+ i=0;
+ error = sctp_connectx(acpt_sk[i], (struct sockaddr *) &lstn_addr, 1, NULL);
+ if (error != -1 || errno != EISCONN)
+ tst_brkm(TBROK, tst_exit, "sctp_connectx on an established socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() on an established socket - EISCONN");
+
+ for (i = 0 ; i < 4 ; i++) {
+ close(clnt_sk[i]);
+ close(acpt_sk[i]);
+ }
+
+ /* sctp_connectx() TEST10: Re-establish an association that is closed.
+ * should succeed.
+ */
+ error = sctp_connectx(sk1, (struct sockaddr *)&conn_addr, 1, NULL);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "Re-establish an association that "
+ "is closed error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sctp_connectx() to re-establish a closed association - "
+ "SUCCESS");
+
+ close(sk);
+ close(sk1);
+ close(lstn_sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_events.c b/utils/sctp/func_tests/test_1_to_1_events.c
new file mode 100644
index 000000000..352534680
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_events.c
@@ -0,0 +1,190 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This test tests the events for 1-1 style sockets.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h> /* needed by linux/sctp.h */
+#include <sys/uio.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+#include <string.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 4;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk,acpt_sk;
+ struct sockaddr_in svr_loop, clt_loop,acpt_loop;
+ struct iovec iov, out_iov;
+ struct msghdr inmessage, outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ int error;
+ socklen_t len;
+ char *big_buffer;
+ struct sctp_event_subscribe event;
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ char *message = "hello, world!\n";
+ uint32_t ppid;
+ uint32_t stream;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Initialize the server and client addresses. */
+ svr_loop.sin_family = AF_INET;
+ svr_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.sin_port = htons(SCTP_TESTPORT_1);
+
+ clt_loop.sin_family = AF_INET;
+ clt_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop.sin_port = htons(SCTP_TESTPORT_1);
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
+ test_bind(svr_sk, (struct sockaddr *) &svr_loop, sizeof(svr_loop));
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 3);
+
+ /* Create the client socket. */
+ clt_sk = test_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
+
+ event.sctp_data_io_event = 1;
+ event.sctp_association_event = 1;
+ event.sctp_shutdown_event = 1;
+ len = sizeof(struct sctp_event_subscribe);
+ test_setsockopt(svr_sk, SCTP_EVENTS, &event, len);
+ test_setsockopt(clt_sk, SCTP_EVENTS, &event, len);
+
+ len = sizeof(struct sockaddr_in);
+ test_connect(clt_sk, (struct sockaddr *) &clt_loop, len);
+
+ acpt_sk = test_accept(svr_sk, (struct sockaddr *) &acpt_loop, &len);
+
+ /* Build up a msghdr structure we can use for all sending. */
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &svr_loop;
+ outmessage.msg_namelen = sizeof(svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = (strlen(message) + 1);
+
+ /* Send . This will create the association*/
+ test_sendmsg(clt_sk, &outmessage, 0, strlen(message)+1);
+
+ memset(&inmessage, 0, sizeof(inmessage));
+ /* NOW initialize inmessage with enough space for DATA... */
+ big_buffer = malloc(REALLY_BIG);
+ if (!big_buffer) { DUMP_CORE; }
+
+ /* Let's do a test to do a recvmsg when we are not listening and
+ * when we have no associations.
+ */
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ error = test_recvmsg(clt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage,
+ error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE,
+ SCTP_COMM_UP);
+
+ tst_resm(TPASS, "COMM_UP notification on client socket - SUCCESS");
+
+ error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage,
+ error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE,
+ SCTP_COMM_UP);
+
+ tst_resm(TPASS, "COMM_UP notification on server socket - SUCCESS");
+
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+
+ tst_resm(TPASS, "Data message on server socket - SUCCESS");
+
+ close(clt_sk);
+ error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage,
+ error,
+ sizeof(struct sctp_shutdown_event),
+ SCTP_SHUTDOWN_EVENT,
+ 0);
+
+ tst_resm(TPASS, "SHUTDOWN notification on accepted socket - SUCCESS");
+ close(svr_sk);
+ close(acpt_sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_initmsg_connect.c b/utils/sctp/func_tests/test_1_to_1_initmsg_connect.c
new file mode 100644
index 000000000..8efb4f59c
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_initmsg_connect.c
@@ -0,0 +1,120 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * When init timeout is set to zero, a connect () crashed the system. This case
+ * tests the fix for the same.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+int
+main (int argc, char **argv)
+{
+ int sk1, sk2, sk3, pf_class;
+ socklen_t len;
+ struct sockaddr_in lstn_addr, acpt_addr;
+ struct sockaddr_in conn_addr;
+ char * buffer_rcv;
+ struct sctp_initmsg sinmsg;
+ char *message = "Hello World!\n";
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ /* Opening the socket*/
+
+ pf_class = PF_INET;
+
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ sk3 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ test_bind(sk3, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ len = sizeof(struct sctp_initmsg);
+ sinmsg.sinit_num_ostreams = 65535;
+ sinmsg.sinit_max_instreams = 10;
+ sinmsg.sinit_max_attempts = 1;
+ sinmsg.sinit_max_init_timeo = 0;
+ test_setsockopt(sk1, SCTP_INITMSG, &sinmsg, len);
+ sinmsg.sinit_num_ostreams = 10;
+ sinmsg.sinit_max_instreams = 65535;
+ test_setsockopt(sk3, SCTP_INITMSG, &sinmsg, len);
+
+ test_listen(sk3, 1);
+
+ len = sizeof(struct sockaddr_in);
+ test_connect(sk1, (struct sockaddr *) &conn_addr, len);
+
+ sk2 = test_accept(sk3, (struct sockaddr *) &acpt_addr, &len);
+
+ test_sctp_sendmsg(sk1, message, strlen(message) + 1,
+ (struct sockaddr *)&conn_addr, len,
+ 0, 0, 65534, 0, 0);
+
+ buffer_rcv = malloc(100);
+ test_recv(sk2, buffer_rcv, (strlen(message) + 1), MSG_NOSIGNAL);
+
+ tst_resm(TPASS, "connect() with init timeout set to 0 - SUCCESS");
+
+ close (sk1);
+ close (sk2);
+ close (sk3);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_nonblock.c b/utils/sctp/func_tests/test_1_to_1_nonblock.c
new file mode 100644
index 000000000..1179fb16b
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_nonblock.c
@@ -0,0 +1,209 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the Non-Blocking mode of connect(),
+ * accept() and recvmsg() calls.
+ *
+ * TEST1: Non blocking accept return EAGAIN if connect is not called
+ * TEST2: Non blocking connect should return EINPROGRESS
+ * TEST3: accept() passes when connect called in Non-blocking mode
+ * TEST4: Non blocking recvmsg should return EAGAIN
+ * TEST5: recvmsg() should succeed if data present to receive in non blocking
+ * mode
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 5;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int error,msg_count;
+ socklen_t len;
+ int sk,pf_class,lstn_sk,acpt_sk,flag,cflag,sflag;
+ struct msghdr outmessage;
+ struct msghdr inmessage;
+ char *message = "hello, world!\n";
+ struct iovec iov_rcv;
+ struct sctp_sndrcvinfo *sinfo;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct iovec out_iov;
+ char * buffer_rcv;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+
+ struct sockaddr_in conn_addr,lstn_addr,svr_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbufferd
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+ flag = MSG_NOSIGNAL;
+
+ /*Setting server socket non-blocking*/
+ sflag = fcntl(lstn_sk, F_GETFL, 0);
+ if (sflag < 0)
+ tst_brkm(TBROK, tst_exit, "fcnt F_GETFL failed "
+ "sflag:%d, errno:%d", sflag, errno);
+
+ error = fcntl(lstn_sk, F_SETFL, sflag | O_NONBLOCK);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "fcnt F_SETFL failed "
+ "error:%d, errno:%d", error, errno);
+
+ /* TEST1: accept should return EAGAIN instead blocking. */
+ error = accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+ if (error != -1 || errno != EAGAIN)
+ tst_brkm(TBROK, tst_exit, "non-blocking accept "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "non-blocking accept() - EAGAIN");
+
+ /* TEST2: Non Block connect should return EINPROGRESS */
+ /*Set client socket as non-blocking*/
+ cflag = fcntl(sk, F_GETFL, 0);
+ if (cflag < 0)
+ tst_brkm(TBROK, tst_exit, "fcnt F_GETFL failed "
+ "cflag:%d, errno:%d", cflag, errno);
+
+ error = fcntl(sk, F_SETFL, sflag | O_NONBLOCK);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "fcnt F_SETFL failed "
+ "error:%d, errno:%d", error, errno);
+
+ error = connect(sk, (const struct sockaddr *) &conn_addr, len);
+ if (error != -1 || errno != EINPROGRESS)
+ tst_brkm(TBROK, tst_exit, "non-blocking connect "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "non-blocking connect() - EINPROGRESS");
+
+ /* TEST3: Now that connect() called, accept will succeed */
+ acpt_sk = accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+ if (acpt_sk < 0)
+ tst_brkm(TBROK, tst_exit, "accept after a non-blocking connect "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept() after a non-blocking connect - SUCCESS");
+
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &svr_addr;
+ outmessage.msg_namelen = sizeof(svr_addr);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+
+ memset(&inmessage, 0, sizeof(inmessage));
+ buffer_rcv = malloc(REALLY_BIG);
+
+ iov_rcv.iov_base = buffer_rcv;
+ iov_rcv.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov_rcv;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ msg_count = strlen(message) + 1;
+
+ /* TEST4: recvmsg() should return EAGAIN instead blocking */
+ error = recvmsg(sk, &inmessage, MSG_WAITALL);
+ if ( error != -1 || errno != EAGAIN)
+ tst_brkm(TBROK, tst_exit, "non-blocking recvmsg "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "non-blocking recvmsg() - EAGAIN");
+
+ test_sendmsg(acpt_sk, &outmessage, flag, msg_count);
+
+ /* TEST5: recvmsg() should succeed now as data is available. */
+ error = test_recvmsg(sk, &inmessage, flag);
+ test_check_msg_data(&inmessage, error, msg_count, MSG_EOR, 0, 0);
+
+ tst_resm(TPASS, "non-blocking recvmsg() when data is available - "
+ "SUCCESS");
+
+ close(lstn_sk);
+ close(acpt_sk);
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_recvfrom.c b/utils/sctp/func_tests/test_1_to_1_recvfrom.c
new file mode 100644
index 000000000..a4bdf6a41
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_recvfrom.c
@@ -0,0 +1,194 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the recvfrom () call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: Invalid message pointer
+ * TEST4: On a listening socket
+ * TEST5: Reading on a socket that received SHUTDOWN
+ * TEST6: Reading the pending message on socket that received SHUTDOWN
+ * TEST7: No more message and association is shutdown
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 7;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int msg_count;
+ socklen_t len;
+ int sk,pf_class,lstn_sk,acpt_sk, flag;
+ char *message = "hello, world!\n";
+ char *message_rcv;
+ int count;
+
+ struct sockaddr_in conn_addr,lstn_addr,svr_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ message_rcv = malloc(512);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ msg_count = (strlen(message) + 1);
+
+ flag = MSG_NOSIGNAL;
+ /*Sending the message*/
+ count = test_send(sk, message, msg_count, flag);
+
+ /*recvfrom () TEST1: Bad socket descriptor, EBADF Expected error*/
+ count = recvfrom(-1, message_rcv, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "recvfrom with a bad socket "
+ "descriptor count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvfrom() with a bad socket descriptor - EBADF");
+
+ /*recvfrom () TEST2: Invalid socket , ENOTSOCK Expected error*/
+ count = recvfrom(0, message_rcv, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "recvfrom with invalid socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvfrom() with invalid socket - ENOTSOCK");
+
+ /*recvfrom () TEST3: Invalid message pointer EFAULT, Expected error*/
+ count = recvfrom(acpt_sk, (char *)-1, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "recvfrom with invalid message "
+ "pointer count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvfrom() with invalid message ptr - EFAULT");
+
+ /*TEST4: recvfrom on listening socket,ENOTCONN Expected error*/
+ count = recvfrom(lstn_sk, message_rcv, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count != -1 || errno != ENOTCONN)
+ tst_brkm(TBROK, tst_exit, "recvfrom on listening socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvfrom() on listening socket - ENOTCONN");
+
+ count = test_send(acpt_sk, message, msg_count, flag);
+
+ test_shutdown(sk, SHUT_WR);
+
+ /*recvfrom () TEST5:reading on a socket that received SHUTDOWN*/
+ count = recvfrom(acpt_sk, message_rcv, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count < 0)
+ tst_brkm(TBROK, tst_exit, "recvfrom on a socket that has "
+ "received shutdown count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvfrom() on a socket that has received shutdown - "
+ "EOF");
+
+ /*recvfrom () TEST6:reading the pending message on socket that sent
+ SHUTDOWN*/
+ count = recvfrom(sk, message_rcv, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count < 0)
+ tst_brkm(TBROK, tst_exit, "recvfrom on a socket with pending "
+ "message that has sent shutdown count:%d, errno:%d",
+ count, errno);
+
+ tst_resm(TPASS, "recvfrom() on a socket with pending message that has "
+ "sent shutdown - SUCCESS");
+
+ /*recvfrom () TEST7: No more message and association is shutdown,
+ ENOTCONN Expected error*/
+ count = recvfrom(sk, message_rcv, msg_count, flag,
+ (struct sockaddr *)&svr_addr, &len);
+ if (count != -1 || errno != ENOTCONN)
+ tst_brkm(TBROK, tst_exit, "recvfrom on a socket with no "
+ "pending messages and has sent shutdown count:%d, "
+ "errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvfrom() on a socket with no pending messages and "
+ " has sent shutdown - ENOTCONN");
+
+ close(sk);
+ close(lstn_sk);
+ close(acpt_sk);
+ return 0;
+
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_recvmsg.c b/utils/sctp/func_tests/test_1_to_1_recvmsg.c
new file mode 100644
index 000000000..ceccc311c
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_recvmsg.c
@@ -0,0 +1,205 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the recvmsg() call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: Invalid iovec pointer
+ * TEST4: Invalid msghdr pointer
+ * TEST5: On a listening socket
+ * TEST6: Reading on a socket that received SHUTDOWN
+ * TEST7: Reading the pending message socket that received SHUTDOWN
+ * TEST8: No more message and association is shutdown
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 8;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ socklen_t len;
+ int sk,pf_class,lstn_sk,acpt_sk;
+ int flag = 0;
+ struct msghdr inmessage;
+ char *message = "hello, world!\n";
+ struct iovec iov_rcv;
+ int count;
+ char * buffer_rcv;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char *message1 = "hello, world!\n";
+
+ struct sockaddr_in conn_addr,lstn_addr,svr_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ memset(&inmessage, 0, sizeof(inmessage));
+ buffer_rcv = malloc(REALLY_BIG);
+
+ iov_rcv.iov_base = buffer_rcv;
+ iov_rcv.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov_rcv;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ /*recvmsg () TEST1: Bad socket descriptor, EBADF Expected error*/
+ count = recvmsg(-1, &inmessage, flag);
+ if (count != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "recvmsg with a bad socket "
+ "descriptor count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() with a bad socket descriptor - EBADF");
+
+ /*recvmsg () TEST2: Invalid socket , ENOTSOCK Expected error*/
+ count = recvmsg(0, &inmessage, flag);
+ if (count != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "recvmsg with invalid socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() with invalid socket - ENOTSOCK");
+
+ /*recvmsg () TEST3: Invalid iovec pointer EFAULT, Expected error*/
+ inmessage.msg_iov = (struct iovec *)-1;
+ count = recvmsg(acpt_sk, &inmessage, flag);
+ if (count != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "recvmsg with invalid iovec "
+ "pointer count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() with invalid iovec ptr - EFAULT");
+
+ inmessage.msg_iov = &iov_rcv;
+
+ /*recvmsg () TEST4: Invalid msghdr pointer EFAULT, Expected error*/
+ count = recvmsg(acpt_sk, (struct msghdr *)-1, flag);
+ if (count != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "recvmsg with invalid msghdr "
+ "pointer count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() with invalid msghdr ptr - EFAULT");
+
+ /*recvmsg () TEST5:recvmsg on listening socket,ENOTCONN Expected error*/
+ count = recvmsg(lstn_sk, &inmessage, flag);
+ if (count != -1 || errno != ENOTCONN)
+ tst_brkm(TBROK, tst_exit, "recvmsg on listening socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() on listening socket - ENOTCONN");
+
+ count = test_send(acpt_sk, message1, strlen(message), 0);
+
+ test_shutdown(sk, SHUT_WR);
+
+ flag = MSG_NOSIGNAL;
+ /*recvmsg () TEST6:reading on a socket that received SHUTDOWN*/
+ count = recvmsg(acpt_sk, &inmessage, flag);
+ if (count < 0)
+ tst_brkm(TBROK, tst_exit, "recvmsg on a socket that has "
+ "received shutdown count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() on a socket that has received shutdown - "
+ "EOF");
+
+ /*recvmsg () TEST7:reading the pending message socket that sent
+ SHUTDOWN*/
+ count = recvmsg(sk, &inmessage, flag);
+ if (count < 0)
+ tst_brkm(TBROK, tst_exit, "recvmsg on a socket with pending "
+ "message that has sent shutdown count:%d, errno:%d",
+ count, errno);
+
+ tst_resm(TPASS, "recvmsg() on a socket with pending message that has "
+ "sent shutdown - SUCCESS");
+
+ /*recvmsg () TEST8: No more message and association is shutdown,
+ ENOTCONN Expected error*/
+ count = recvmsg(sk, &inmessage, flag);
+ if (count != -1 || errno != ENOTCONN)
+ tst_brkm(TBROK, tst_exit, "recvmsg on a socket with no "
+ "pending messages and has sent shutdown count:%d, "
+ "errno:%d", count, errno);
+
+ tst_resm(TPASS, "recvmsg() on a socket with no pending messages and "
+ " has sent shutdown - ENOTCONN");
+
+ close(sk);
+ close(lstn_sk);
+ close(acpt_sk);
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_rtoinfo.c b/utils/sctp/func_tests/test_1_to_1_rtoinfo.c
new file mode 100644
index 000000000..cb46e3920
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_rtoinfo.c
@@ -0,0 +1,114 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the getsockopt () and sectsockopt () with
+ * SCTP_RTOINFO option on 1-1 style socket
+ *
+ * This program first gets the default values using getsockopt(). It also sets
+ * the value using setsockopt() and gets the set value using getsockopt().
+ * A comparison between set values and get values are performed.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+#include <linux/in.h> /* for sockaddr_in */
+#include <linux/in6.h> /* for sockaddr_in6 */
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 3;
+int TST_CNT = 0;
+
+int
+main(void)
+{
+
+ int sd, ret;
+ socklen_t len;
+ struct sctp_rtoinfo srtoinfo; /*setting the variables*/
+ struct sctp_rtoinfo grtoinfo; /*Getting the variables*/
+
+ sd = test_socket (PF_INET, SOCK_STREAM, IPPROTO_SCTP);
+
+ len = sizeof(struct sctp_rtoinfo);
+
+ /*TEST1 Getting the default values using getsockopt()*/
+ ret = getsockopt(sd, IPPROTO_SCTP, SCTP_RTOINFO, &grtoinfo, &len);
+ if (ret < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_RTOINFO "
+ "ret:%d, errno:%d", ret, errno);
+
+ tst_resm(TPASS, "getsockopt() SCTP_RTOINFO - SUCCESS");
+
+ /*Assigning the values to RTO initial and max and min bounds*/
+ srtoinfo.srto_initial=60;
+ srtoinfo.srto_max=100;
+ srtoinfo.srto_min=40;
+
+ /*TEST2 Setting the values using setsockopt()*/
+ ret = setsockopt(sd, IPPROTO_SCTP, SCTP_RTOINFO, &srtoinfo,
+ sizeof(struct sctp_rtoinfo));
+ if (ret < 0)
+ tst_brkm(TBROK, tst_exit, "setsockopt SCTP_RTOINFO "
+ "ret:%d, errno:%d", ret, errno);
+
+ tst_resm(TPASS, "setsockopt() SCTP_RTOINFO - SUCCESS");
+
+ /*Getting the values which are set using setsockopt()*/
+ ret = getsockopt(sd, IPPROTO_SCTP, SCTP_RTOINFO, &grtoinfo, &len);
+ if (ret < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_RTOINFO "
+ "ret:%d, errno:%d", ret, errno);
+
+ /* TEST3 Compare the get values with the set values. */
+ if (srtoinfo.srto_initial != grtoinfo.srto_initial &&
+ srtoinfo.srto_max != grtoinfo.srto_max &&
+ srtoinfo.srto_min != grtoinfo.srto_min)
+ tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_RTOINFO "
+ "compare failed");
+
+ tst_resm(TPASS, "setsockopt()/getsockopt SCTP_RTOINFO compare - "
+ "SUCCESS");
+
+ close(sd);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_send.c b/utils/sctp/func_tests/test_1_to_1_send.c
new file mode 100644
index 000000000..4966020a7
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_send.c
@@ -0,0 +1,230 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the send() call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: On a listening socket
+ * TEST4: On a closed association
+ * TEST5: Invalid message address
+ * TEST6: send from client to server
+ * TEST7: send from server to client
+ * TEST8: sending partial data from a buffer
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 8;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ socklen_t len,len_snd;
+ int msg_count;
+ int sk,sk1,pf_class,lstn_sk,acpt_sk,acpt1_sk, flag, count;
+ char *message = "hello, world!\n";
+ char *message_rcv;
+
+ struct sockaddr_in conn_addr,lstn_addr,svr_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ len_snd = (strlen(message) + 1);
+
+ flag = MSG_NOSIGNAL;
+ /*send () TEST1: Bad socket descriptor, EBADF Expected error*/
+ count = send(-1, message, len_snd, flag);
+ if (count != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "send with a bad socket "
+ "descriptor count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() with a bad socket descriptor - EBADF");
+
+ /*send () TEST2: Invalid socket, ENOTSOCK Expected error*/
+ count = send(0, message, len_snd, flag);
+ if (count != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "send with invalid socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() with invalid socket - ENOTSOCK");
+
+ /*send () TEST3: send on listening socket, EPIPE Expected error*/
+ count = send(lstn_sk, message, len_snd, flag);
+ if (count != -1 || errno != EPIPE)
+ tst_brkm(TBROK, tst_exit, "send on a listening socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() on a listening socket - EPIPE");
+#if 0
+ /*send () TEST4: Invalid message address, EFAULT Expected error*/
+ /* FIXME this test should pass. Don't catch why... */
+ count = send(sk, (char *)0x1, len_snd, flag);
+ if (count != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "send with invalid message "
+ "pointer count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() with invalid message ptr - EFAULT");
+#endif
+
+ test_connect(sk1, (struct sockaddr *) &lstn_addr, len);
+
+ count = test_send(sk1, message, len_snd, flag);
+
+ close(sk1);
+
+ acpt1_sk = test_accept(lstn_sk, (struct sockaddr *)&conn_addr, &len);
+
+ /*send () TEST5: send on closed association, EPIPE Expected error*/
+ count = send(acpt1_sk, message, len_snd, flag);
+ if (count != -1 || errno != EPIPE)
+ tst_brkm(TBROK, tst_exit, "send on a closed association "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() on a closed association - EPIPE");
+
+ close(acpt1_sk);
+ close(sk);
+ close(lstn_sk);
+ close(acpt_sk);
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ message_rcv = malloc(512);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ len = sizeof(struct sockaddr_in);
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ msg_count = strlen(message) + 1;
+
+ /*send() TEST6: Sending data from client socket to server socket*/
+ count = send(sk, message, msg_count, flag);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "send from client to server "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() from client to server - SUCCESS");
+
+ test_recv(acpt_sk, message_rcv, msg_count, flag);
+
+ strncpy(message_rcv,"\0",512);
+
+ /*send() TEST7: Sending data from accept socket to client socket*/
+ count = send(acpt_sk, message, msg_count, flag);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "send from accept socket to client "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "send() from accept socket to client - SUCCESS");
+
+ test_recv(sk, message_rcv, msg_count, flag);
+
+ /*send() TEST8: Sending less number of data from the buffer*/
+ /*Sending only 5 bytes so that only hello is received*/
+ test_send(sk, message, 5 , flag);
+ test_recv(acpt_sk, message_rcv, 5, flag);
+
+ tst_resm(TPASS, "send() partial data from a buffer - SUCCESS");
+
+ /* TEST9: sctp_send with no sinfo */
+ test_sctp_send(sk, message, strlen(message) + 1 , NULL, flag);
+ test_recv(acpt_sk, message_rcv, strlen(message) + 1, flag);
+ tst_resm(TPASS, "sctp_send() with no sinfo - SUCCESS");
+
+ close(sk1);
+ close(lstn_sk);
+ close(acpt_sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_sendmsg.c b/utils/sctp/func_tests/test_1_to_1_sendmsg.c
new file mode 100644
index 000000000..7ac0b54d9
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_sendmsg.c
@@ -0,0 +1,366 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the sendmsg() call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: On a listening socket
+ * TEST4: Invalid iovec pointer
+ * TEST5: Invalid iovec length
+ * TEST6: Invalid msghdr pointer
+ * TEST7: Invalid sinfo flags
+ * TEST8: SCTP_EOF flag set
+ * TEST9: SCTP_ABORT flag set
+ * TEST10: On a closed association
+ *
+ * TEST11: Sending data from server socket to client socket
+ * TEST12: Sending data from client socket to server socket
+ * TEST13: Sending data from unconnected client to server
+ * TEST14: Sending a message on SHUT_RD socket
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 14;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ socklen_t len;
+ int msg_count;
+ int sk,sk1,pf_class,lstn_sk,acpt_sk,acpt1_sk, flag;
+ struct msghdr outmessage;
+ char *message = "hello, world!\n";
+ struct sctp_sndrcvinfo *sinfo;
+ int count;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct iovec out_iov;
+ struct msghdr inmessage;
+ char * buffer_rcv;
+ struct sockaddr_in conn_addr,lstn_addr,svr_addr;
+ struct iovec iov_rcv;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &conn_addr;
+ outmessage.msg_namelen = sizeof(conn_addr);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+
+ flag = MSG_NOSIGNAL;
+ /*sendmsg () TEST1: Bad socket descriptor, EBADF Expected error*/
+ count = sendmsg(-1, &outmessage, flag);
+ if (count != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "sendmsg with a bad socket "
+ "descriptor count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with a bad socket descriptor - EBADF");
+
+ /*sendmsg () TEST2: Invalid socket, ENOTSOCK Expected error*/
+ count = sendmsg(0, &outmessage, flag);
+ if (count != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "sendmsg with invalid socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with invalid socket - ENOTSOCK");
+
+ /*sendmsg () TEST3: sendmsg on listening socket, EPIPE Expected error*/
+ count = sendmsg(lstn_sk, &outmessage, flag);
+ if (count != -1 || errno != EPIPE)
+ tst_brkm(TBROK, tst_exit, "sendmsg on a listening socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() on a listening socket - EPIPE");
+
+ /*sendmsg () TEST4: Invalid iovec pointer EFAULT, Expected error*/
+ outmessage.msg_iov = (struct iovec *)-1;
+ count = sendmsg(sk, &outmessage, flag);
+ if (count != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "sendmsg with invalid iovec "
+ "pointer count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with invalid iovec ptr - EFAULT");
+
+ outmessage.msg_iov = &out_iov;
+
+ /*sendmsg () TEST5: Invalid iovec count EINVAL, Expected error*/
+ outmessage.msg_iovlen = 0;
+ count = sendmsg(sk, &outmessage, flag);
+ if (count != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sendmsg with invalid iovec "
+ "length count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with invalid iovec length - EINVAL");
+
+ outmessage.msg_iovlen = 1;
+
+ /*sendmsg () TEST6: Invalid msghdr pointer EFAULT, Expected error*/
+ count = sendmsg(sk, (struct msghdr *)-1, flag);
+ if (count != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "sendmsg with invalid msghdr "
+ "pointer count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with invalid msghdr ptr - EFAULT");
+
+ /*sendmsg () TEST7: Invalid sinfo flag EINVAL, Expected error*/
+ sinfo->sinfo_flags = 999;
+ count = sendmsg(sk, &outmessage, -1);
+ if (count != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sendmsg with invalid sinfo "
+ "flags count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with invalid sinfo flags - EINVAL");
+
+ /*sendmsg () TEST8: SCTP_EOF flag EINVAL, Expected error*/
+ sinfo->sinfo_flags = SCTP_EOF;
+ count = sendmsg(sk, &outmessage, flag);
+ if (count != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_EOF flag "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with SCTP_EOF flag - EINVAL");
+
+ /*sendmsg () TEST9: SCTP_ABORT flag EINVAL, Expected error*/
+ sinfo->sinfo_flags = SCTP_ABORT;
+ count = sendmsg(sk, &outmessage, flag);
+ if (count != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_ABORT flag "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() with SCTP_ABORT flag - EINVAL");
+
+ sinfo->sinfo_flags = 0;
+
+ test_connect(sk1, (struct sockaddr *) &lstn_addr, len);
+
+ test_sendmsg(sk1, &outmessage, flag, strlen(message)+1);
+
+ close(sk1);
+ acpt1_sk = test_accept(lstn_sk, (struct sockaddr *)&conn_addr, &len);
+
+ /*sendmsg () TEST10:sendmsg on closed association, EPIPE Expected error*/
+ count = sendmsg(acpt1_sk, &outmessage, flag);
+ if (count != -1 || errno != EPIPE)
+ tst_brkm(TBROK, tst_exit, "sendmsg on a closed association "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() on a closed association - EPIPE");
+
+ close(acpt1_sk);
+ close(sk);
+ close(lstn_sk);
+ close(acpt_sk);
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+ flag = MSG_NOSIGNAL;
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &svr_addr;
+ outmessage.msg_namelen = sizeof(svr_addr);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+
+ memset(&inmessage, 0, sizeof(inmessage));
+ buffer_rcv = malloc(REALLY_BIG);
+
+ iov_rcv.iov_base = buffer_rcv;
+ iov_rcv.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov_rcv;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ msg_count = strlen(message) + 1;
+
+ /*sendmsg() TEST11: Sending data from server socket to client socket*/
+ count = sendmsg(acpt_sk, &outmessage, flag);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendmsg from accept socket to "
+ "client count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() from accept socket to client - SUCCESS");
+
+ count = test_recvmsg(sk, &inmessage, flag);
+ test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0);
+
+ outmessage.msg_name = &conn_addr;
+ outmessage.msg_namelen = sizeof(conn_addr);
+ /*sendmsg() TEST12: Sending data from client socket to server socket*/
+ count = sendmsg(sk, &outmessage, flag);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendmsg from client to server "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() from client to server - SUCCESS");
+
+ count = test_recvmsg(acpt_sk, &inmessage, flag);
+ test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0);
+
+ outmessage.msg_name = &conn_addr;
+ outmessage.msg_namelen = sizeof(conn_addr);
+ close(sk);
+ close(acpt_sk);
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*sendmsg() TEST13: Sending data from unconnected client socket to
+ server socket*/
+ count = sendmsg(sk1, &outmessage, flag);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendmsg from unconnected client to "
+ "server count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() from unconnected clt to server - SUCCESS");
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ count = test_recvmsg(acpt_sk, &inmessage, flag);
+ test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0);
+
+ test_shutdown(sk1, SHUT_RD);
+
+ /*sendmsg() TEST14: Sending a message on SHUT_RD socket*/
+ count = sendmsg(sk1, &outmessage, flag);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendmsg on a SHUT_RD socket "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendmsg() on a SHUT_RD socket - SUCCESS");
+
+ count = test_recvmsg(acpt_sk, &inmessage, flag);
+ test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0);
+
+ close(sk1);
+ close(lstn_sk);
+ close(acpt_sk);
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_sendto.c b/utils/sctp/func_tests/test_1_to_1_sendto.c
new file mode 100644
index 000000000..8f5804ce1
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_sendto.c
@@ -0,0 +1,164 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the sendto () call
+ * for 1-1 style sockets
+ *
+ * TEST1: Sending data from client socket to server socket
+ * TEST2: Sending data from accept (server) socket to client socket
+ * TEST3: Sending data from unconnected client socket to server
+ * TEST4: sending partial data from a buffer
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 4;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int msg_count;
+ socklen_t len;
+ int sk,sk1,pf_class,lstn_sk,acpt_sk,flag;
+ char *message = "hello, world!\n";
+ char *message_rcv;
+ int count;
+
+ struct sockaddr_in conn_addr,lstn_addr,svr_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbufferd
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ message_rcv = malloc(512);
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ /*Binding the listen socket*/
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ /*Listening the socket*/
+ test_listen(lstn_sk, 10);
+
+ len = sizeof(struct sockaddr_in);
+ flag = MSG_NOSIGNAL;
+
+ test_connect(sk, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ msg_count = strlen(message) + 1;
+
+ /*sendto() TEST1: Sending data from client socket to server socket*/
+ count = sendto(sk, message, msg_count, flag,
+ (const struct sockaddr *) &conn_addr, len);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendto from client to server "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendto() from client to server - SUCCESS");
+
+ test_recv(acpt_sk, message_rcv, msg_count, flag);
+
+ strncpy(message_rcv,"\0",512);
+
+ /*sendto() TEST2: Sending data from accept socket to client socket*/
+ count = sendto(acpt_sk, message, msg_count, flag,
+ (const struct sockaddr *) &svr_addr, len);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendto from accept socket to client "
+ "count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendto() from accept socket to client - SUCCESS");
+
+ test_recv(sk, message_rcv, msg_count, flag);
+
+ close(sk);
+ close(acpt_sk);
+
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*sendto() TEST3: Sending data from unconnected client socket to
+ server socket*/
+ count = sendto(sk1, message, msg_count, flag,
+ (const struct sockaddr *) &conn_addr, len);
+ if (count != msg_count)
+ tst_brkm(TBROK, tst_exit, "sendto from unconnected client to "
+ "server count:%d, errno:%d", count, errno);
+
+ tst_resm(TPASS, "sendto() from unconnected client to server - SUCCESS");
+
+ acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len);
+
+ test_recv(acpt_sk, message_rcv, msg_count, flag);
+
+ /*send() TEST4: Sending less number of data from the buffer*/
+ /*Sending only 5 bytes so that only hello is received*/
+ test_sendto(sk, message, 5 , flag, (const struct sockaddr *)&conn_addr,
+ len);
+ test_recv(acpt_sk, message_rcv, 5, flag);
+
+ tst_resm(TPASS, "sendto() partial data from a buffer - SUCCESS");
+
+ close(sk1);
+ close(lstn_sk);
+ close(acpt_sk);
+ return 0;
+
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_shutdown.c b/utils/sctp/func_tests/test_1_to_1_shutdown.c
new file mode 100644
index 000000000..de505f78e
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_shutdown.c
@@ -0,0 +1,217 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the shutdown() call for 1-1 style sockets
+ *
+ * TEST1: Bad socket descriptor
+ * TEST2: Invalid socket
+ * TEST3: shutdown with SHUT_WR flag to disable new send
+ * TEST4: shutdown with SHUT_RD flag to disable new receive
+ * TEST5: shutdown with SHUT_RDWR flag to disable new receive/send
+ * TEST6: Unconnected socket
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+
+#include <stdio.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/socket.h>
+#include <netinet/sctp.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 6;
+int TST_CNT = 0;
+
+#define MAX_CLIENTS 10
+
+int
+main(int argc, char *argv[])
+{
+ int clnt_sk[MAX_CLIENTS], acpt_sk[MAX_CLIENTS],sk;
+ int lstn_sk;
+ struct sockaddr_in lstn_addr, acpt_addr;
+ socklen_t addrlen;
+ int error, i;
+ char *message = "hello, world!\n";
+ char msgbuf[100];
+ int pf_class;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ /* Initialize the server and client addresses. */
+ pf_class = PF_INET;
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+
+ test_listen(lstn_sk, MAX_CLIENTS);
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ test_connect(clnt_sk[i], (struct sockaddr *)&lstn_addr,
+ sizeof(lstn_addr));
+ }
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ addrlen = sizeof(acpt_addr);
+ acpt_sk[i] = test_accept(lstn_sk, (struct sockaddr *)&acpt_addr,
+ &addrlen);
+ }
+
+ /*shutdown() TEST1: Bad socket descriptor, EBADF Expected error*/
+ error = shutdown(-1, SHUT_WR);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "shutdown with a bad socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "shutdown() with a bad socket descriptor - EBADF");
+
+ /*shutdown() TEST2: Invalid socket, ENOTSOCK Expected error*/
+ error = shutdown(0, SHUT_WR);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "shutdown with an invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "shutdown() with an invalid socket - ENOTSOCK");
+
+ errno = 0;
+ /*Do a send first before doing shutdown*/
+ test_send(acpt_sk[0], message, strlen(message), 0);
+
+ /*shutdown() TEST3: shutdown with SHUT_WR flag to disable new send*/
+ error = shutdown(clnt_sk[0], SHUT_WR);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "shutdown with SHUT_WR flag "
+ "error:%d, errno:%d", error, errno);
+
+ /* Reading on a socket that has received SHUTDOWN should return 0
+ * indicating EOF.
+ */
+ error = recv(acpt_sk[0], msgbuf, 100, 0);
+ if ((error != 0) || (errno != 0))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN received socket "
+ "error:%d, errno:%d", error, errno);
+
+ /* Read the pending message on clnt_sk[0] that was received before
+ * SHUTDOWN call.
+ */
+ test_recv(clnt_sk[0], msgbuf, 100, 0);
+
+ /* No more messages and the association is SHUTDOWN, should fail. */
+ error = recv(clnt_sk[0], msgbuf, 100, 0);
+ if ((error != -1) || (errno != ENOTCONN))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_WR socket with no "
+ "messages error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "shutdown() with SHUT_WR flag - SUCCESS");
+
+ errno = 0;
+
+ /*shutdown() TEST4: shutdown with SHUT_RD flag to disable new receive*/
+ test_shutdown(clnt_sk[1], SHUT_RD);
+
+ error = recv(clnt_sk[1], msgbuf, 100, 0);
+ if ((error != 0) || (errno != 0))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket "
+ "error:%d, errno:%d", error, errno);
+
+ /* Sending a message on SHUT_RD socket. */
+ error = test_send(clnt_sk[1], message, strlen(message), 0);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "send on a SHUT_RD socket "
+ "error:%d, errno:%d", error, errno);
+
+ /* Receive the message sent on SHUT_RD socket. */
+ test_recv(acpt_sk[1], msgbuf, 100, 0);
+
+ /* Send a message to the SHUT_RD socket. */
+ test_send(acpt_sk[1], message, strlen(message), 0);
+
+ /* We should not receive the message as the socket is SHUT_RD */
+ error = recv(clnt_sk[1], msgbuf, 100, 0);
+ if ((error != 0) || (errno != 0))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "shutdown() with SHUT_RD flag - SUCCESS");
+
+ /*shutdown() TEST5: shutdown with SHUT_RDWR flag to disable new
+ receive/send*/
+ test_shutdown(clnt_sk[2], SHUT_RDWR);
+
+ error = recv(acpt_sk[2], msgbuf, 100, 0);
+ if ((error != 0) || (errno != 0))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN received socket "
+ "error:%d, errno:%d", error, errno);
+
+ error = recv(clnt_sk[2], msgbuf, 100, 0);
+ if ((error != 0) || (errno != 0))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RDWR socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "shutdown() with SHUT_RDWR flag - SUCCESS");
+
+ /*shutdown() TEST6: Unconnected socket, ENOTCONN Expected error*/
+ error = shutdown(sk, SHUT_RD);
+ if ((error != -1) || (errno != ENOTCONN))
+ tst_brkm(TBROK, tst_exit, "shutdown on an unconnected socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "shutdown() on an unconnected socket - SUCCESS");
+
+ for (i = 0; i < MAX_CLIENTS; i++)
+ close(clnt_sk[i]);
+ for (i = 0; i < MAX_CLIENTS; i++)
+ close(acpt_sk[i]);
+
+
+ close(lstn_sk);
+ close(sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_socket_bind_listen.c b/utils/sctp/func_tests/test_1_to_1_socket_bind_listen.c
new file mode 100644
index 000000000..6ba9c98f1
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_socket_bind_listen.c
@@ -0,0 +1,268 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test the socket (), bind () and listen () for
+ * 1-1 style sockets
+ *
+ * socket () Tests:
+ * ---------------
+ * TEST1: Invalid domain
+ * TEST2: Invalid type
+ * TEST3: Opening a TCP style socket
+ *
+ * bind () Tests:
+ * -------------
+ * TEST4: Invalid address
+ * TEST5: Invalid address length
+ * TEST6: Invalid socket descriptor
+ * TEST7: Invalid host name
+ * TEST8: On a socket that is already bound
+ * TEST9: On reserved ports
+ * TEST10: INADDR_ANY address and non-zero port
+ * TEST11: INADDR_ANY address and zero port
+ * TEST12: Local address and zero port
+ *
+ * listen () Tests:
+ * ---------------
+ * TEST13: Bad socket descriptor
+ * TEST14: Invalid socket
+ * TEST15: Listening a bound socket
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <sctputil.h>
+
+#define SCTP_RESERVED_PORT 7
+#define SCTP_INV_LOOPBACK "172.31.43.112"
+
+char *TCID = __FILE__;
+int TST_TOTAL = 15;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int sk,pf_class;
+ int error = 0;
+ int uid;
+
+ struct sockaddr_in bind_addr;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ /* socket() TEST1: Invalid domain, EAFNOSUPPORT Expected error */
+ sk = socket(-1, SOCK_STREAM, IPPROTO_SCTP);
+ if (sk != -1 || errno != EAFNOSUPPORT)
+ tst_brkm(TBROK, tst_exit, "socket() with invalid domain "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "socket() with invalid domain - EAFNOSUPPORT");
+
+ /*socket() TEST2 : Invalid type, EINVAL Expected error*/
+ sk = socket(pf_class, -1, IPPROTO_SCTP);
+ if (sk != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "socket() with invalid type "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "socket() with invalid type - EINVAL");
+
+ /*socket() TEST3: opening a socket*/
+ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ if (sk < 0)
+ tst_brkm(TBROK, tst_exit, "valid socket() call "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "socket() - SUCCESS");
+
+ /*bind() TEST4: Invalid structure, EFAULT Expected error */
+ error = bind(sk, (struct sockaddr *)-1, sizeof(struct sockaddr_in));
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "bind() with invalid address ptr "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with invalid address ptr - EFAULT");
+
+ /*bind() TEST5: Invalid address length, EINVAL Expect error*/
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ bind_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr)-2);
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "bind() with invalid address length "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with invalid address length - EINVAL");
+
+ /*bind() TEST6: Invalid socket descriptor, ENOTSOCK Expect Error*/
+ error = bind(0, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "bind() with invalid socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with invalid socket descriptor - ENOTSOCK");
+
+ /*bind() TEST7: Invalid host name, EADDRNOTAVAIL Expect Error*/
+ /*Assigning invalid host name*/
+ bind_addr.sin_addr.s_addr = inet_addr(SCTP_INV_LOOPBACK);
+ error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
+ if (error != -1 || errno != EADDRNOTAVAIL)
+ tst_brkm(TBROK, tst_exit, "bind() with invalid local "
+ "address error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with invalid local address - EADDRNOTAVAIL");
+
+ /*bind() TEST8: Bind on a socket that has already called bind
+ EINAVL, Expected error*/
+ bind_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ /*Calling bind first time, it should pass*/
+ test_bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
+
+ error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
+ if (error != -1 || errno != EINVAL)
+ tst_brkm(TBROK, tst_exit, "bind() on an already bound socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() on an already bound socket - EINVAL");
+
+ /*Closing the socket which succeed in bind() */
+ close(sk);
+
+ /*Opening the socket again for further test*/
+ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*bind() TEST9: Bind on reserved ports EACCES, Expected error*/
+ /*Assigning a reserved port*/
+ uid = getuid();
+ if (uid != 0) {
+ bind_addr.sin_port = htons(SCTP_RESERVED_PORT);
+ error = bind(sk, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr));
+ if (error != -1 || errno != EACCES)
+ tst_brkm(TBROK, tst_exit, "bind() on reserverd port "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() on reserved port - EACCESS");
+ }
+
+ /*bind() TEST10: INADDR_ANY address and non-zero port, bind() should
+ succeed*/
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ bind_addr.sin_port = htons(SCTP_TESTPORT_1);
+ error = bind(sk, (struct sockaddr *) &bind_addr,sizeof(bind_addr));
+ if ( error < 0 )
+ tst_brkm(TBROK, tst_exit, "bind() with INADDR_ANY address and "
+ "non-zero port error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with INADDR_ANY address and non-zero port - "
+ "SUCCESS");
+
+ /*Closing the socket which succeed in bind() */
+ close(sk);
+
+ /*Opening the socket again for further test*/
+ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*bind() TEST11: INADDR_ANY address and zero port, bind() should
+ succeed*/
+ bind_addr.sin_port = 0;
+ error = bind(sk, (struct sockaddr *) &bind_addr,sizeof(bind_addr));
+ if ( error < 0 )
+ tst_brkm(TBROK, tst_exit, "bind() with INADDR_ANY address and "
+ "zero port error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with INADDR_ANY address and zero port - "
+ "SUCCESS");
+
+ /*Closing the socket which succeed in bind() */
+ close(sk);
+
+ /*Opening the socket again for further test*/
+ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*bind() TEST12: local address and zero port, bind() should
+ succeed*/
+ bind_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ bind_addr.sin_port = 0;
+ error = bind(sk, (struct sockaddr *) &bind_addr,sizeof(bind_addr));
+ if ( error < 0 )
+ tst_brkm(TBROK, tst_exit, "bind() with local address and "
+ "zero port error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "bind() with local address and zero port - "
+ "SUCCESS");
+
+ /*listen() TEST13: Bad socket descriptor EBADF, Expected error*/
+ error = listen(-1, 3);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "listen() with bad socket descriptor "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "listen() with bad socket descriptor - EBADF");
+
+ /*listen() TEST14: Invalid socket ENOTSOCK, Expected error*/
+ error = listen(0, 3);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "listen() with invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "listen() with invalid socket - ENOTSOCK");
+
+ /*listen() TEST15:listen on a bound socket, should succeed*/
+ error = listen(sk, 3);
+ if ( error < 0 )
+ tst_brkm(TBROK, tst_exit, "listen() on a bound socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "listen() on a bound socket - SUCCESS");
+
+ close(sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_sockopt.c b/utils/sctp/func_tests/test_1_to_1_sockopt.c
new file mode 100644
index 000000000..e2229913a
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_sockopt.c
@@ -0,0 +1,414 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file has test cases to test negative scenarios for getsockopt ()
+ * setsockopt () call for 1-1 style sockets
+ *
+ * setsockopt () Tests:
+ * -------------------
+ * TEST1: setsockopt: Bad socket descriptor
+ * TEST2: setsockopt: Invalid socket
+ * TEST3: setsockopt: Invalid level
+ * TEST4: setsockopt: Invalid option buffer
+ * TEST5: setsockopt: Invalid option name
+ * TEST6: getsockopt: Bad socket descriptor
+ * TEST7: getsockopt: Invalid socket
+ * TEST8: getsockopt: Invalid option buffer
+ * TEST9: getsockopt: Invalid option name
+ *
+ * TEST10: getsockopt: SCTP_INITMSG
+ * TEST11: setsockopt: SCTP_INITMSG
+ * TEST12: setsockopt: SO_LINGER
+ * TEST13: getsockopt: SO_LINGER
+ * TEST14: getsockopt: SO_RCVBUF
+ * TEST15: getsockopt: SCTP_STATUS
+ * TEST16: setsockopt: SO_RCVBUF
+ * TEST17: setsockopt: SO_SNDBUF
+ * TEST18: getsockopt: SO_SNDBUF
+ * TEST19: getsockopt: SCTP_PRIMARY_ADDR
+ * TEST20: setsockopt: SCTP_PRIMARY_ADDR
+ * TEST21: getsockopt: SCTP_ASSOCINFO
+ * TEST22: setsockopt: SCTP_ASSOCINFO
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 22;
+int TST_CNT = 0;
+
+int
+main(void)
+{
+ int error;
+ socklen_t len;
+ int sk, sk1, sk2, acpt_sk, pf_class;
+ struct sctp_rtoinfo grtinfo;
+ struct sockaddr_in lstn_addr, conn_addr;
+ struct sctp_initmsg ginmsg; /*get the value for SCTP_INITMSG*/
+ struct sctp_initmsg sinmsg; /*set the value for SCTP_INITMSG*/
+ struct linger slinger; /*SO_LINGER structure*/
+ struct linger glinger; /*SO_LINGER structure*/
+ struct sockaddr_in addr;
+ struct sockaddr_in *gaddr;
+ struct sctp_status gstatus; /*SCTP_STATUS option*/
+ int rcvbuf_val_get, rcvbuf_val_set; /*get and set var for SO_RCVBUF*/
+ int sndbuf_val_get, sndbuf_val_set;/*get and set var for SO_SNDBUF*/
+ struct sctp_prim gprimaddr;/*SCTP_PRIMARY_ADDR get*/
+ struct sctp_prim sprimaddr;/*SCTP_PRIMARY_ADDR set*/
+ struct sctp_assocparams sassocparams; /* SCTP_ASSOCPARAMS set */
+ struct sctp_assocparams gassocparams; /* SCTP_ASSOCPARAMS get */
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ pf_class = PF_INET;
+
+ sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /*setsockopt() TEST1: Bad socket descriptor EBADF, Expected error*/
+ error = setsockopt(-1, IPPROTO_SCTP, 0, 0, 0);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "setsockopt with a bad socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() with a bad socket descriptor - EBADF");
+
+ /*setsockopt() TEST2: Invalid socket ENOTSOCK, Expected error*/
+ error = setsockopt(0, IPPROTO_SCTP, 0, 0, 0);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "setsockopt with an invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() with an invalid socket - ENOTSOCK");
+
+ /*setsockopt() TEST3: Invalid level ENOPROTOOPT, Expected error*/
+ error = setsockopt(sk, -1, SCTP_RTOINFO, 0, 0);
+ if (error != -1 || errno != ENOPROTOOPT)
+ tst_brkm(TBROK, tst_exit, "setsockopt with invalid level "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() with an invalid level - ENOPROTOOPT");
+
+ /*setsockopt() TEST4: Invalid option buffer EFAULT, Expected error*/
+ error = setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO,
+ (const struct sctp_rtoinfo *)-1, sizeof(struct sctp_rtoinfo));
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "setsockopt with invalid option "
+ "buffer error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() with invalid option buffer - EFAULT");
+
+ /*setsockopt() TEST5: Invalid option Name EOPNOTSUPP, Expected error*/
+ error = setsockopt(sk, IPPROTO_SCTP, SCTP_AUTOCLOSE, 0, 0);
+ if (error != -1 || errno != EOPNOTSUPP)
+ tst_brkm(TBROK, tst_exit, "setsockopt with invalid option "
+ "name error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() with invalid option name - EOPNOTSUPP");
+
+ /*getsockopt() TEST6: Bad socket descriptor EBADF, Expected error*/
+ error = getsockopt(-1, IPPROTO_SCTP, 0, 0, 0);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "getsockopt with a bad socket "
+ "descriptor error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() with a bad socket descriptor - EBADF");
+
+ /*getsockopt() TEST7: Invalid socket ENOTSOCK, Expected error*/
+ error = getsockopt(0, IPPROTO_SCTP, 0, 0, 0);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "getsockopt with an invalid socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() with an invalid socket - ENOTSOCK");
+#if 0
+ /*getsockopt() TEST3: Invalid level ENOPROTOOPT, Expected error*/
+ /*I have commented this test case because it is returning EOPNOTSUPP.
+ When I checked the code there also it is returning EOPNOTSUPP. As this
+ is not specific to TCP style, I do not want to do the code change*/
+
+ error = getsockopt(sk, -1, SCTP_RTOINFO, 0, 0);
+ if (error != -1 || errno != ENOPROTOOPT)
+ tst_brkm(TBROK, tst_exit, "getsockopt with invalid level "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() with an invalid level - ENOPROTOOPT");
+#endif
+ len = sizeof(struct sctp_rtoinfo);
+
+ /*getsockopt() TEST8: Invalid option buffer EFAULT, Expected error*/
+ error = getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO,
+ (struct sctp_rtoinfo *)-1, &len);
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "getsockopt with invalid option "
+ "buffer error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() with invalid option buffer - EFAULT");
+
+ /*getsockopt() TEST9: Invalid option Name EOPNOTSUPP, Expected error*/
+ error = getsockopt(sk, IPPROTO_SCTP, SCTP_AUTOCLOSE, &grtinfo, &len);
+ if (error != -1 || errno != EOPNOTSUPP)
+ tst_brkm(TBROK, tst_exit, "getsockopt with invalid option "
+ "name error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() with invalid option name - EOPNOTSUPP");
+
+ close(sk);
+
+ sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ len = sizeof(struct sctp_initmsg);
+
+ /* TEST10: Test cases for getsockopt SCTP_INITMSG */
+ test_getsockopt(sk1, SCTP_INITMSG, &ginmsg, &len);
+
+ tst_resm(TPASS, "getsockopt() SCTP_INITMSG - SUCCESS");
+
+ sinmsg.sinit_num_ostreams = 5;
+ sinmsg.sinit_max_instreams = 5;
+ sinmsg.sinit_max_attempts = 3;
+ sinmsg.sinit_max_init_timeo = 30;
+ /* TEST11: Test case for setsockopt SCTP_INITMSG */
+ test_setsockopt(sk1, SCTP_INITMSG, &sinmsg, sizeof(sinmsg));
+
+ test_getsockopt(sk1, SCTP_INITMSG, &ginmsg, &len);
+
+ if (sinmsg.sinit_num_ostreams != ginmsg.sinit_num_ostreams &&
+ sinmsg.sinit_max_instreams != ginmsg.sinit_max_instreams &&
+ sinmsg.sinit_max_attempts != ginmsg.sinit_max_attempts &&
+ sinmsg.sinit_max_init_timeo != ginmsg.sinit_max_init_timeo)
+ tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_INITMSG "
+ "compare failed");
+
+ tst_resm(TPASS, "setsockopt() SCTP_INITMSG - SUCCESS");
+
+ /*Now get the values on different endpoint*/
+ test_getsockopt(sk2, SCTP_INITMSG, &ginmsg, &len);
+
+ /*Comparison should not succeed here*/
+ if (sinmsg.sinit_num_ostreams == ginmsg.sinit_num_ostreams &&
+ sinmsg.sinit_max_instreams == ginmsg.sinit_max_instreams &&
+ sinmsg.sinit_max_attempts == ginmsg.sinit_max_attempts &&
+ sinmsg.sinit_max_init_timeo == ginmsg.sinit_max_init_timeo)
+ tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_INITMSG "
+ "unexpected compare success");
+
+ /* SO_LINGER Test with l_onff = 0 and l_linger = 0 */
+ slinger.l_onoff = 0;
+ slinger.l_linger = 0;
+ test_bind(sk1, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
+ test_listen(sk1, 10 );
+ len = sizeof(struct sockaddr_in);
+ test_connect(sk2, (struct sockaddr *) &conn_addr, len);
+
+ acpt_sk = test_accept(sk1, (struct sockaddr *)&addr, &len);
+
+ len = sizeof(struct linger);
+ /* TEST12: Test case for setsockopt SO_LINGER */
+ error = setsockopt(sk2, SOL_SOCKET, SO_LINGER, &slinger, len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "setsockopt SO_LINGER "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() SO_LINGER - SUCCESS");
+
+ /* TEST13: Test case for getsockopt SO_LINGER */
+ error = getsockopt(sk2, SOL_SOCKET, SO_LINGER, &glinger, &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SO_LINGER "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() SO_LINGER - SUCCESS");
+
+ if (slinger.l_onoff != glinger.l_onoff ||
+ slinger.l_linger != glinger.l_linger)
+ tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SO_LINGER "
+ "compare failed");
+
+ /*First gets the default SO_RCVBUF value and comapres with the
+ value obtained from SCTP_STATUS*/
+ len = sizeof(int);
+ /* TEST14: Test case for getsockopt SO_RCVBUF */
+ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_get, &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SO_RCVBUF "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() SO_RCVBUF - SUCCESS");
+
+ len = sizeof(struct sctp_status);
+ /* TEST15: Test case for getsockopt SCTP_STATUS */
+ error = getsockopt(sk2, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_STATUS "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() SCTP_STATUS - SUCCESS");
+
+ /* Reducing the SO_RCVBUF value using setsockopt() */
+ /* Upstream has changed the MIN_RCVBUF (2048 + sizeof(struct sk_buff)) */
+ len = sizeof(int);
+ rcvbuf_val_set = 2048;
+ /* TEST16: Test case for setsockopt SO_RCVBUF */
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_set, len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "setsockopt SO_RCVBUF "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() SO_RCVBUF - SUCCESS");
+
+ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_get, &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SO_RCVBUF "
+ "error:%d, errno:%d", error, errno);
+
+ if ((2 * rcvbuf_val_set) != rcvbuf_val_get)
+ tst_brkm(TBROK, tst_exit, "Comparison failed:Set value and "
+ "got value differs Set Value=%d Get Value=%d",
+ (2*rcvbuf_val_set), rcvbuf_val_get);
+
+ sndbuf_val_set = 2048;
+ /* TEST17: Test case for setsockopt SO_SNDBUF */
+ error = setsockopt(sk2, SOL_SOCKET, SO_SNDBUF, &sndbuf_val_set, len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "setsockopt SO_SNDBUF "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() SO_SNDBUF - SUCCESS");
+
+ /* TEST18: Test case for getsockopt SO_SNDBUF */
+ error = getsockopt(sk2, SOL_SOCKET, SO_SNDBUF, &sndbuf_val_get, &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SO_SNDBUF "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() SO_SNDBUF - SUCCESS");
+
+ if ((2 * sndbuf_val_set) != sndbuf_val_get)
+ tst_brkm(TBROK, tst_exit, "Comparison failed:Set value and "
+ "got value differs Set Value=%d Get Value=%d\n",
+ (2*sndbuf_val_set), sndbuf_val_get);
+
+
+ /* Getting the primary address using SCTP_PRIMARY_ADDR */
+ len = sizeof(struct sctp_prim);
+ /* TEST19: Test case for getsockopt SCTP_PRIMARY_ADDR */
+ error = getsockopt(sk2,IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &gprimaddr,
+ &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_PRIMARY_ADDR "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() SCTP_PRIMARY_ADDR - SUCCESS");
+
+ gaddr = (struct sockaddr_in *) &gprimaddr.ssp_addr;
+ if(htons(gaddr->sin_port) != lstn_addr.sin_port &&
+ gaddr->sin_family != lstn_addr.sin_family &&
+ gaddr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_PRIMARY_ADDR value "
+ "mismatch");
+
+ memcpy(&sprimaddr, &gprimaddr, sizeof(struct sctp_prim));
+
+ /* TEST20: Test case for setsockopt SCTP_PRIMARY_ADDR */
+ error = setsockopt(sk2,IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &sprimaddr,
+ len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "setsockopt SCTP_PRIMARY_ADDR "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt() SCTP_PRIMARY_ADDR - SUCCESS");
+
+ /* TEST21: Test case for getsockopt SCTP_PRIMARY_ADDR */
+ /* Getting the association info using SCTP_ASSOCINFO */
+ len = sizeof(struct sctp_assocparams);
+ error = getsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &gassocparams,
+ &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt() SCTP_ASSOCINFO - SUCCESS");
+
+ /* TEST21: Test case for setsockopt SCTP_ASSOCINFO */
+ memcpy(&sassocparams, &gassocparams, sizeof(struct sctp_assocparams));
+ sassocparams.sasoc_asocmaxrxt += 5;
+ sassocparams.sasoc_cookie_life += 10;
+
+ error = setsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &sassocparams,
+ len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "setsockopt SCTP_ASSOCINFO "
+ "error:%d, errno:%d", error, errno);
+
+ error = getsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &gassocparams,
+ &len);
+ if (error < 0)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO "
+ "error:%d, errno:%d", error, errno);
+
+ if (sassocparams.sasoc_asocmaxrxt != gassocparams.sasoc_asocmaxrxt ||
+ sassocparams.sasoc_cookie_life != gassocparams.sasoc_cookie_life)
+ tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO value "
+ "mismatch");
+ tst_resm(TPASS, "setsockopt() SCTP_ASSOCINFO - SUCCESS");
+
+ close(sk2);
+ close(sk1);
+ close(acpt_sk);
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_1_to_1_threads.c b/utils/sctp/func_tests/test_1_to_1_threads.c
new file mode 100644
index 000000000..e2a7eeeed
--- /dev/null
+++ b/utils/sctp/func_tests/test_1_to_1_threads.c
@@ -0,0 +1,196 @@
+/* SCTP kernel Implementation
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
+ * (C) Copyright IBM Corp. 2004
+ *
+ * This file does send and receive for 500 threads on a unique association for
+ * THREAD_SND_RCV_LOOPS = 10 many times. To change the number of threads
+ * change the THREADS valuen and loop change the THREAD_SND_RCV_LOOPS.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release
+ *
+ */
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sys/uio.h>
+#include <linux/socket.h>
+#include <sctputil.h>
+
+#define THREADS 10 /* FIXME should be 500 instead of 10 */
+#define THREAD_SND_RCV_LOOPS 10
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+int client_sk;
+int server_sk;
+int acpt_sk;
+struct sockaddr_in conn_addr;
+char *message = "hello, world!\n";
+
+void
+t_recv(void) {
+ int cnt;
+ struct msghdr inmessage;
+ struct iovec iov;
+ char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ char * buffer;
+
+ memset(&inmessage, 0, sizeof(inmessage));
+ buffer = malloc(100);
+
+ iov.iov_base = buffer;
+ iov.iov_len = 100;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ cnt = test_recvmsg(acpt_sk,&inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, cnt, strlen(message) + 1, MSG_EOR,
+ 0, 0);
+}
+
+void
+t_send(void) {
+ struct msghdr outmessage;
+ struct sctp_sndrcvinfo *sinfo;
+ struct cmsghdr *cmsg;
+ struct iovec out_iov;
+ char outcmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &conn_addr;
+ outmessage.msg_namelen = sizeof(conn_addr);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = (strlen(message) + 1);
+
+ test_sendmsg(client_sk, &outmessage, 0, strlen(message)+1);
+}
+
+void *relay(void *arg)
+{
+ int id = *(int *) arg;
+
+ if (id == 0) {
+ t_send();
+ } else {
+ t_recv();
+ t_send();
+ }
+
+ pthread_exit(NULL);
+}
+
+int
+main(void)
+{
+
+ int cnt,i;
+ int pth[THREADS];
+ pthread_t thread[THREADS];
+ int status;
+ int exit_status;
+ void * result;
+ pthread_attr_t attr;
+ struct sockaddr_in lstn_addr;
+ socklen_t len = sizeof(struct sockaddr_in);
+ struct sockaddr_in svr_addr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ server_sk = test_socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
+ client_sk = test_socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
+
+ lstn_addr.sin_family = AF_INET;
+ lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ conn_addr.sin_family = AF_INET;
+ conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ conn_addr.sin_port = htons(SCTP_TESTPORT_1);
+
+ test_bind(server_sk, (struct sockaddr *)&lstn_addr,
+ sizeof(struct sockaddr_in));
+
+ test_listen(server_sk,10);
+
+ test_connect(client_sk,(struct sockaddr *)&conn_addr,len);
+
+ acpt_sk = test_accept(server_sk, (struct sockaddr *)&svr_addr, &len);
+
+ for ( i = 0; i < THREAD_SND_RCV_LOOPS; i++ ) {
+ for (cnt = 0; cnt < THREADS; cnt++) {
+ pth[cnt] = cnt;
+ status = pthread_create(&thread[cnt], &attr, relay, &pth[cnt]);
+ if (status)
+ tst_brkm(TBROK, tst_exit, "pthread_create "
+ "failed status:%d, errno:%d", status,
+ errno);
+ }
+
+ pthread_attr_destroy(&attr);
+ for (cnt = 0; cnt < THREADS ; cnt++) {
+ exit_status = pthread_join (thread[cnt], &result);
+ if (exit_status == -1)
+ tst_brkm(TBROK, tst_exit, "pthread_join "
+ "Thread #%d exited with status:%d",
+ cnt, exit_status);
+ }
+ }
+
+ tst_resm(TPASS, "send and receive data across multiple threads - "
+ "SUCCESS");
+
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_assoc_abort.c b/utils/sctp/func_tests/test_assoc_abort.c
new file mode 100644
index 000000000..7e9a0b509
--- /dev/null
+++ b/utils/sctp/func_tests/test_assoc_abort.c
@@ -0,0 +1,244 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Ardelle Fan <ardelle.fan@intle.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a functional test to verify the ungraceful abort of an
+ * association.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+#define MAX_CLIENTS 10
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk[MAX_CLIENTS];
+ sockaddr_storage_t svr_loop, clt_loop[MAX_CLIENTS];
+ sctp_assoc_t svr_associd[MAX_CLIENTS];
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ int error;
+ uint32_t ppid;
+ uint32_t stream;
+ struct sctp_assoc_change *sac;
+ char *big_buffer;
+ int i;
+ char *message = "hello, world!\n";
+ struct sctp_status status;
+ socklen_t status_len;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ svr_loop.v4.sin_family = AF_INET;
+ svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+ test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(svr_sk);
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 1);
+
+ /* Create and bind all the client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clt_sk[i] = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ clt_loop[i].v4.sin_family = AF_INET;
+ clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i);
+ test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i]));
+
+ test_enable_assoc_change(clt_sk[i]);
+ }
+
+ /* Build up a msghdr structure we can use for all sending. */
+ outmessage.msg_name = &svr_loop;
+ outmessage.msg_namelen = sizeof(svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ out_iov.iov_base = message;
+ out_iov.iov_len = strlen(message) + 1;
+
+ /* Send the first message from all the clients to the server. This
+ * will create the associations.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++)
+ test_sendmsg(clt_sk[i], &outmessage, 0, strlen(message) + 1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on all client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ }
+
+ /* Get the communication up message and the data message on the
+ * server sockets for all the clients.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd[i] = sac->sac_assoc_id;
+ }
+
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ outmessage.msg_iov = NULL;
+ outmessage.msg_iovlen = 0;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_flags |= SCTP_ABORT;
+
+ /* Shutdown all the associations of the server socket in a loop. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ sinfo->sinfo_assoc_id = svr_associd[i];
+
+ /* Verify that the association is present. */
+ memset(&status, 0, sizeof(struct sctp_status));
+ status.sstat_assoc_id = sinfo->sinfo_assoc_id;
+ status_len = sizeof(struct sctp_status);
+ error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS,
+ &status, &status_len);
+ if (error)
+ tst_brkm(TBROK, tst_exit,
+ "getsockopt(SCTP_STATUS): %s",
+ strerror(errno));
+
+ /* Call sendmsg() to abort the association. */
+ test_sendmsg(svr_sk, &outmessage, 0, 0);
+
+ /* Verify that the association is no longer present. */
+ memset(&status, 0, sizeof(struct sctp_status));
+ status.sstat_assoc_id = sinfo->sinfo_assoc_id;
+ status_len = sizeof(struct sctp_status);
+ error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS,
+ &status, &status_len);
+ if ((error != -1) && (errno != EINVAL))
+ tst_brkm(TBROK, tst_exit,
+ "getsockopt(SCTP_STATUS) "
+ "error:%d errno:%d", error, errno);
+ }
+
+ close(svr_sk);
+
+ /* Get the COMM_LOST notification. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change)+4,
+ SCTP_ASSOC_CHANGE, SCTP_COMM_LOST);
+
+ close(clt_sk[i]);
+ }
+
+ tst_resm(TPASS, "ABORT an association using SCTP_ABORT");
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_assoc_shutdown.c b/utils/sctp/func_tests/test_assoc_shutdown.c
new file mode 100644
index 000000000..dcdb37794
--- /dev/null
+++ b/utils/sctp/func_tests/test_assoc_shutdown.c
@@ -0,0 +1,246 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a functional test to verify the graceful shutdown of an
+ * association.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+#define MAX_CLIENTS 10
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk[MAX_CLIENTS];
+ sctp_assoc_t svr_associd[MAX_CLIENTS];
+ sockaddr_storage_t svr_loop, clt_loop[MAX_CLIENTS];
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ int error;
+ uint32_t ppid;
+ uint32_t stream;
+ struct sctp_assoc_change *sac;
+ char *big_buffer;
+ int i;
+ char *message = "hello, world!\n";
+ struct sctp_status status;
+ socklen_t status_len;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ svr_loop.v4.sin_family = AF_INET;
+ svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+ test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(svr_sk);
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 1);
+
+ /* Create and bind all the client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clt_sk[i] = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ clt_loop[i].v4.sin_family = AF_INET;
+ clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i);
+ test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i]));
+
+ test_enable_assoc_change(clt_sk[i]);
+ }
+
+ /* Build up a msghdr structure we can use for all sending. */
+ outmessage.msg_name = &svr_loop;
+ outmessage.msg_namelen = sizeof(svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ out_iov.iov_base = message;
+ out_iov.iov_len = strlen(message) + 1;
+
+ /* Send the first message from all the clients to the server. This
+ * will create the associations.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++)
+ test_sendmsg(clt_sk[i], &outmessage, 0, strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on all client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ }
+
+ /* Get the communication up message and the data message on the
+ * server sockets for all the clients.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message)+1,
+ MSG_EOR, stream, ppid);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd[i] = sac->sac_assoc_id;
+ }
+
+ /* Build up a msghdr structure we can use for all sending. */
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ outmessage.msg_iov = NULL;
+ outmessage.msg_iovlen = 0;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_flags |= SCTP_EOF;
+
+ /* Shutdown all the associations of the server socket in a loop. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ sinfo->sinfo_assoc_id = svr_associd[i];
+
+ /* Verify that the association is present. */
+ memset(&status, 0, sizeof(struct sctp_status));
+ status.sstat_assoc_id = sinfo->sinfo_assoc_id;
+ status_len = sizeof(struct sctp_status);
+ error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS,
+ &status, &status_len);
+ if (error)
+ tst_brkm(TBROK, tst_exit,
+ "getsockopt(SCTP_STATUS): %s",
+ strerror(errno));
+
+ /* Call sendmsg() to shutdown the association. */
+ test_sendmsg(svr_sk, &outmessage, 0, 0);
+
+ /* Verify that the association is no longer present. */
+ memset(&status, 0, sizeof(struct sctp_status));
+ status.sstat_assoc_id = sinfo->sinfo_assoc_id;
+ status_len = sizeof(struct sctp_status);
+ error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS,
+ &status, &status_len);
+ if ((error != -1) && (errno != EINVAL))
+ tst_brkm(TBROK, tst_exit,
+ "getsockopt(SCTP_STATUS) "
+ "error:%d errno:%d", error, errno);
+ }
+
+ close(svr_sk);
+
+ /* Get the shutdown complete notification. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE,
+ SCTP_SHUTDOWN_COMP);
+
+ close(clt_sk[i]);
+ }
+
+ tst_resm(TPASS, "Graceful shutdown of associations using SCTP_EOF");
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_autoclose.c b/utils/sctp/func_tests/test_autoclose.c
new file mode 100644
index 000000000..b5368e70a
--- /dev/null
+++ b/utils/sctp/func_tests/test_autoclose.c
@@ -0,0 +1,168 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a Functional Test to verify autoclose functionality and the
+ * socket option SCTP_AUTOCLOSE that can be used to specify the duration in
+ * which an idle association is automatically closed.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1, loop2;
+ struct msghdr inmessage, outmessage;
+ struct iovec iov, out_iov;
+ int error;
+ char *big_buffer;
+ char *message = "hello, world!\n";
+ uint32_t autoclose;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(sk1);
+ test_enable_assoc_change(sk2);
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ /* Mark sk2 as being able to accept new associations. */
+ test_listen(sk2, 1);
+
+ /* Set the autoclose duration for the associations created on sk1
+ * and sk2 to be 5 seconds.
+ */
+ autoclose = 5;
+ test_setsockopt(sk1, SCTP_AUTOCLOSE, &autoclose, sizeof(autoclose));
+ test_setsockopt(sk2, SCTP_AUTOCLOSE, &autoclose, sizeof(autoclose));
+
+ /* Send the first message. This will create the association. */
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &loop2;
+ outmessage.msg_namelen = sizeof(loop2);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+
+ test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = NULL;
+
+ /* Get the communication up message on sk2. */
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ /* Get the communication up message on sk1. */
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ /* Get the first message which was sent. */
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR|MSG_CTRUNC, 0, 0);
+
+ tst_resm(TINFO, "Waiting for the associations to close automatically "
+ "in 5 secs");
+
+ /* Get the shutdown complete notification from sk1. */
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ /* Get the shutdown complete notification from sk2. */
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ tst_resm(TPASS, "Autoclose of associations");
+
+ /* Shut down the link. */
+ close(sk1);
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_basic.c b/utils/sctp/func_tests/test_basic.c
new file mode 100644
index 000000000..b8d4eaea1
--- /dev/null
+++ b/utils/sctp/func_tests/test_basic.c
@@ -0,0 +1,456 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Hui Huang <hui.huang@nokia.com>
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <samudrala@us.ibm.com>
+ */
+
+/* This is a basic functional test for the SCTP kernel
+ * implementation state machine.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 15;
+int TST_CNT = 0;
+
+int main(void)
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1;
+ sockaddr_storage_t loop2;
+ sockaddr_storage_t msgname;
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ char *message = "hello, world!\n";
+ char *telephone = "Watson, come here! I need you!\n";
+ char *telephone_resp = "I already brought your coffee...\n";
+ int error, bytes_sent;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ sctp_assoc_t associd1, associd2;
+ struct sctp_assoc_change *sac;
+ char *big_buffer;
+ struct sockaddr *laddrs, *paddrs;
+ int n_laddrs, n_paddrs, i;
+ struct sockaddr *sa_addr;
+ struct sockaddr_in *in_addr;
+ struct sockaddr_in6 *in6_addr;
+ void *addr_buf;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ loop1.v6.sin6_family = AF_INET6;
+ loop1.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_ANY_INIT;
+ loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v6.sin6_family = AF_INET6;
+ loop2.v6.sin6_addr = in6addr_loopback;
+ loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
+#else
+ pf_class = PF_INET;
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = INADDR_ANY;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ tst_resm(TPASS, "socket");
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ tst_resm(TPASS, "bind");
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(sk1);
+ test_enable_assoc_change(sk2);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_name = &msgname;
+
+ /* Try to read on socket 2. This should fail since we are
+ * neither listening, nor established.
+ */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = recvmsg(sk2, &inmessage, MSG_WAITALL);
+ if (error > 0)
+ tst_brkm(TBROK, tst_exit, "recvmsg on a socket neither"
+ "listening nor established error: %d", error);
+
+ tst_resm(TPASS, "recvmsg on a socket neither listening nor "
+ "established");
+
+ /* Mark sk2 as being able to accept new associations. */
+ error = test_listen(sk2, 1);
+
+ tst_resm(TPASS, "listen");
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &loop2;
+ outmessage.msg_namelen = sizeof(loop2);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
+
+ tst_resm(TPASS, "sendmsg with a valid msg_name");
+
+ /* Get the communication up message on sk2. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ inmessage.msg_namelen = sizeof(msgname);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if TEST_V6
+
+ if (inmessage.msg_namelen != sizeof(struct sockaddr_in6)) {
+ DUMP_CORE;
+ }
+ if (msgname.v6.sin6_port != htons(SCTP_TESTPORT_1)) {
+ DUMP_CORE;
+ }
+
+ if (msgname.v6.sin6_family != AF_INET6) {
+ DUMP_CORE;
+ }
+
+ if (memcmp(&msgname.v6.sin6_addr, &in6addr_loopback,
+ sizeof(msgname.v6.sin6_addr))) {
+ DUMP_CORE;
+ }
+#else
+ if (inmessage.msg_namelen != sizeof(struct sockaddr_in)) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_port != htons(SCTP_TESTPORT_1)) {
+ DUMP_CORE;
+ }
+
+ if (msgname.v4.sin_family != AF_INET) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_addr.s_addr != SCTP_IP_LOOPBACK) {
+ DUMP_CORE;
+ }
+#endif
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd2 = sac->sac_assoc_id;
+
+ /* Get the communication up message on sk1. */
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd1 = sac->sac_assoc_id;
+
+ tst_resm(TPASS, "recvmsg COMM_UP notifications");
+
+ /* Get the first message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ inmessage.msg_namelen = sizeof(msgname);
+ memset(&msgname, 0, sizeof(msgname));
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+#if TEST_V6
+
+ if (inmessage.msg_namelen != sizeof(struct sockaddr_in6)) {
+ DUMP_CORE;
+ }
+ if (msgname.v6.sin6_port != htons(SCTP_TESTPORT_1)) {
+ DUMP_CORE;
+ }
+
+ if (msgname.v6.sin6_family != AF_INET6) {
+ DUMP_CORE;
+ }
+
+ if (memcmp(&msgname.v6.sin6_addr, &in6addr_loopback,
+ sizeof(msgname.v6.sin6_addr))) {
+ DUMP_CORE;
+ }
+#else
+ if (inmessage.msg_namelen != sizeof(struct sockaddr_in)) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_port != htons(SCTP_TESTPORT_1)) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_family != AF_INET) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_addr.s_addr != SCTP_IP_LOOPBACK) {
+ DUMP_CORE;
+ }
+#endif
+
+ /* Try to send a message with NULL msg_name and associd, should fail */
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid++;
+ stream++;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = telephone;
+ outmessage.msg_iov->iov_len = strlen(telephone) + 1;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ bytes_sent = sendmsg(sk1, &outmessage, MSG_NOSIGNAL);
+ if ((bytes_sent > 0) || (EPIPE != errno))
+ tst_brkm(TBROK, tst_exit, "sendmsg with NULL associd and "
+ "NULL msg_name error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "sendmsg with NULL associd and NULL msg_name");
+
+ /* Fill in a incorrect assoc_id, which should cause an error. */
+ sinfo->sinfo_assoc_id = associd2;
+ bytes_sent = sendmsg(sk1, &outmessage, MSG_NOSIGNAL);
+ if ((bytes_sent > 0) || (EPIPE != errno))
+ tst_brkm(TBROK, tst_exit, "sendmsg with incorrect associd "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "sendmsg with incorrect associd");
+
+ /* Fill in a correct assoc_id and get back to the normal testing. */
+ sinfo->sinfo_assoc_id = associd1;
+ /* Send two more messages, to cause a second SACK. */
+ test_sendmsg(sk1, &outmessage, 0, strlen(telephone)+1);
+
+ outmessage.msg_name = &loop2;
+ outmessage.msg_namelen = sizeof(loop2);
+ outmessage.msg_iov->iov_base = telephone_resp;
+ outmessage.msg_iov->iov_len = strlen(telephone_resp) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(telephone_resp)+1);
+
+ tst_resm(TPASS, "sendmsg with valid associd");
+
+ /* Get those two messages. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(telephone) + 1,
+ MSG_EOR, stream, ppid);
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(telephone_resp) + 1,
+ MSG_EOR, stream, ppid);
+
+ tst_resm(TPASS, "recvmsg");
+
+ n_laddrs = sctp_getladdrs(sk1, associd1, &laddrs);
+ if (n_laddrs <= 0)
+ tst_brkm(TBROK, tst_exit, "sctp_getladdrs: %s",
+ strerror(errno));
+
+ tst_resm(TPASS, "sctp_getladdrs");
+
+ addr_buf = (void *)laddrs;
+ for (i = 0; i < n_laddrs; i++) {
+ sa_addr = (struct sockaddr *)addr_buf;
+ if (AF_INET == sa_addr->sa_family) {
+ in_addr = (struct sockaddr_in *)sa_addr;
+ tst_resm(TINFO, "LOCAL ADDR %d.%d.%d.%d PORT %d",
+ NIPQUAD(in_addr->sin_addr),
+ ntohs(in_addr->sin_port));
+ addr_buf += sizeof(struct sockaddr_in);
+ } else {
+ in6_addr = (struct sockaddr_in6 *)sa_addr;
+ tst_resm(TINFO,
+ "LOCAL ADDR %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x PORT %d",
+ NIP6(in6_addr->sin6_addr),
+ ntohs(in6_addr->sin6_port));
+ addr_buf += sizeof(struct sockaddr_in6);
+ }
+ }
+
+ sctp_freeladdrs(laddrs);
+
+ tst_resm(TPASS, "sctp_freeladdrs");
+
+ n_paddrs = sctp_getpaddrs(sk1, associd1, &paddrs);
+ if (n_paddrs <= 0)
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s",
+ strerror(errno));
+
+ tst_resm(TPASS, "sctp_getpaddrs");
+
+ addr_buf = (void *)paddrs;
+ for (i = 0; i < n_paddrs; i++) {
+ sa_addr = (struct sockaddr *)addr_buf;
+ if (AF_INET == sa_addr->sa_family) {
+ in_addr = (struct sockaddr_in *)sa_addr;
+ tst_resm(TINFO, "PEER ADDR %d.%d.%d.%d PORT %d",
+ NIPQUAD(in_addr->sin_addr),
+ ntohs(in_addr->sin_port));
+ addr_buf += sizeof(struct sockaddr_in);
+ } else {
+ in6_addr = (struct sockaddr_in6 *)sa_addr;
+ tst_resm(TINFO,
+ "PEER ADDR %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x PORT %d",
+ NIP6(in6_addr->sin6_addr),
+ ntohs(in6_addr->sin6_port));
+ addr_buf += sizeof(struct sockaddr_in6);
+ }
+ }
+
+ sctp_freepaddrs(paddrs);
+
+ tst_resm(TPASS, "sctp_freepaddrs");
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ inmessage.msg_namelen = sizeof(msgname);
+ memset(&msgname, 0, sizeof(msgname));
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+#if TEST_V6
+
+ if (inmessage.msg_namelen != sizeof(struct sockaddr_in6)) {
+ DUMP_CORE;
+ }
+ if (msgname.v6.sin6_port != htons(SCTP_TESTPORT_1)) {
+ DUMP_CORE;
+ }
+
+ if (msgname.v6.sin6_family != AF_INET6) {
+ DUMP_CORE;
+ }
+
+ if (memcmp(&msgname.v6.sin6_addr, &in6addr_loopback,
+ sizeof(msgname.v6.sin6_addr))) {
+ DUMP_CORE;
+ }
+#else
+ if (inmessage.msg_namelen != sizeof(struct sockaddr_in)) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_port != htons(SCTP_TESTPORT_1)) {
+ DUMP_CORE;
+ }
+
+ if (msgname.v4.sin_family != AF_INET) {
+ DUMP_CORE;
+ }
+ if (msgname.v4.sin_addr.s_addr != SCTP_IP_LOOPBACK) {
+ DUMP_CORE;
+ }
+#endif
+
+ tst_resm(TPASS, "recvmsg SHUTDOWN_COMP notification");
+
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_connect.c b/utils/sctp/func_tests/test_connect.c
new file mode 100644
index 000000000..333c283ed
--- /dev/null
+++ b/utils/sctp/func_tests/test_connect.c
@@ -0,0 +1,219 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2002, 2003
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a kernel test to verify the one-to-many style connect() in blocking
+ * and non-blocking modes.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 5;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk1, clt_sk2, peeloff_sk;
+ sctp_assoc_t svr_associd1;
+ sockaddr_storage_t svr_loop, clt_loop1, clt_loop2, clt_loop3;
+ struct sctp_assoc_change *sac;
+ struct iovec iov;
+ struct msghdr inmessage;
+ int error;
+ char *big_buffer;
+ int flags;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Initialize the server and client addresses. */
+ svr_loop.v4.sin_family = AF_INET;
+ svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+ clt_loop1.v4.sin_family = AF_INET;
+ clt_loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop1.v4.sin_port = htons(SCTP_TESTPORT_2);
+ clt_loop2.v4.sin_family = AF_INET;
+ clt_loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop2.v4.sin_port = htons(SCTP_TESTPORT_2+1);
+ clt_loop3.v4.sin_family = AF_INET;
+ clt_loop3.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop3.v4.sin_port = htons(SCTP_TESTPORT_2+2);
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 1);
+
+ /* Create and bind the client sockets. */
+ clt_sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(clt_sk1, &clt_loop1.sa, sizeof(clt_loop1));
+ clt_sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(clt_sk2, &clt_loop2.sa, sizeof(clt_loop2));
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(svr_sk);
+ test_enable_assoc_change(clt_sk1);
+ test_enable_assoc_change(clt_sk2);
+
+ /* Set clt_sk1 as non-blocking. */
+ flags = fcntl(clt_sk1, F_GETFL, 0);
+ if (flags < 0)
+ tst_brkm(TBROK, tst_exit, "fcntl F_GETFL: %s", strerror(errno));
+ if (fcntl(clt_sk1, F_SETFL, flags | O_NONBLOCK) < 0)
+ tst_brkm(TBROK, tst_exit, "fcntl F_SETFL: %s", strerror(errno));
+
+ /* Do a non-blocking connect from clt_sk1 to svr_sk */
+ error = connect(clt_sk1, &svr_loop.sa, sizeof(svr_loop));
+ /* Non-blocking connect should return immediately with EINPROGRESS. */
+ if ((error != -1) || (EINPROGRESS != errno))
+ tst_brkm(TBROK, tst_exit, "non-blocking connect error: %d"
+ "errno:%d", error, errno);
+
+ tst_resm(TPASS, "non-blocking connect");
+
+ /* Doing a connect on a socket to create an association that is
+ * is already established should return EISCONN.
+ */
+ error = connect(clt_sk1, &svr_loop.sa, sizeof(svr_loop));
+ if ((error != -1) || (EISCONN != errno))
+ tst_brkm(TBROK, tst_exit, "connect on a socket to create an "
+ "assoc that is already established error:%d errno:%d",
+ error, errno);
+
+ tst_resm(TPASS, "connect on a socket to create an assoc that is "
+ "already established");
+
+ /* Initialize inmessage for all receives. */
+ memset(&inmessage, 0, sizeof(inmessage));
+ big_buffer = test_malloc(REALLY_BIG);
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = NULL;
+
+ /* Get COMM_UP on clt_sk1 */
+ error = test_recvmsg(clt_sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ clt_associd1 = sac->sac_assoc_id;
+#endif
+
+ /* Get COMM_UP on svr_sk */
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd1 = sac->sac_assoc_id;
+
+ /* Do a blocking connect from clt_sk2 to svr_sk.
+ * Blocking connect should block until the association is established
+ * and return success.
+ */
+ test_connect(clt_sk2, &svr_loop.sa, sizeof(svr_loop));
+
+ /* Get COMM_UP on clt_sk2 */
+ error = test_recvmsg(clt_sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ clt_associd2 = sac->sac_assoc_id;
+#endif
+
+ /* Get COMM_UP on svr_sk */
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd2 = sac->sac_assoc_id;
+#endif
+
+ tst_resm(TPASS, "blocking connect");
+
+ peeloff_sk = test_sctp_peeloff(svr_sk, svr_associd1);
+
+ /* Doing a connect on a peeled off socket should fail. */
+ error = connect(peeloff_sk, &clt_loop3.sa, sizeof(clt_loop3));
+ if ((error != -1) || (EISCONN != errno))
+ tst_brkm(TBROK, tst_exit, "connect on a peeled off socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect on a peeled off socket");
+
+ /* Trying to create an association on a socket that matches an
+ * existing peeled-off association should fail.
+ */
+ error = connect(svr_sk, &clt_loop1.sa, sizeof(clt_loop1));
+ if ((error != -1) || (EADDRNOTAVAIL != errno))
+ tst_brkm(TBROK, tst_exit, "connect to create an assoc that "
+ "matches a peeled off assoc error:%d errno:%d",
+ error, errno);
+
+ tst_resm(TPASS, "connect to create an assoc that matches a peeled off "
+ "assoc");
+
+ close(svr_sk);
+ close(clt_sk1);
+ close(clt_sk2);
+ close(peeloff_sk);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_connectx.c b/utils/sctp/func_tests/test_connectx.c
new file mode 100644
index 000000000..24772417c
--- /dev/null
+++ b/utils/sctp/func_tests/test_connectx.c
@@ -0,0 +1,270 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2002, 2003
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a kernel test to verify the one-to-many style sctp_connectx()
+ * in blocking and non-blocking modes.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 9;
+int TST_CNT = 0;
+
+#define NUMADDR 6
+#define SCTP_IP_LOOPBACK_I(I) htonl(0x7f000001 + I)
+
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk1, clt_sk2, peeloff_sk;
+ sctp_assoc_t associd, svr_associd1, svr_associd2, clt_associd1, clt_associd2;
+ struct iovec iov;
+ struct msghdr inmessage;
+ int error, i;
+ struct sctp_assoc_change *sac;
+ char *big_buffer;
+ int flags;
+ struct sockaddr_in svr_loop[NUMADDR];
+ struct sockaddr_in svr_try[NUMADDR];
+ struct sockaddr_in clt_loop1[NUMADDR];
+ struct sockaddr_in clt_loop2[NUMADDR];
+ struct sockaddr_in clt_loop3[NUMADDR];
+ sockaddr_storage_t svr_test[NUMADDR], clt_test1[NUMADDR], clt_test2[NUMADDR];
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ for (i = 0; i < NUMADDR; i++) {
+ /* Initialize the server and client addresses. */
+ svr_loop[i].sin_family = AF_INET;
+ svr_loop[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i);
+ svr_loop[i].sin_port = htons(SCTP_TESTPORT_1);
+ svr_test[i].v4.sin_family = AF_INET;
+ svr_test[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i);
+ svr_test[i].v4.sin_port = htons(SCTP_TESTPORT_1);
+ svr_try[i].sin_family = AF_INET;
+ if (i < (NUMADDR-1)) {
+ svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i);
+ } else {
+ /* Make last address invalid. */
+ svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x400);
+ }
+ svr_try[i].sin_port = htons(SCTP_TESTPORT_1);
+ clt_loop1[i].sin_family = AF_INET;
+ clt_loop1[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100);
+ clt_loop1[i].sin_port = htons(SCTP_TESTPORT_2);
+ clt_test1[i].v4.sin_family = AF_INET;
+ clt_test1[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100);
+ clt_test1[i].v4.sin_port = htons(SCTP_TESTPORT_2);
+ clt_loop2[i].sin_family = AF_INET;
+ clt_loop2[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200);
+ clt_loop2[i].sin_port = htons(SCTP_TESTPORT_2+1);
+ clt_test2[i].v4.sin_family = AF_INET;
+ clt_test2[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200);
+ clt_test2[i].v4.sin_port = htons(SCTP_TESTPORT_2+1);
+ clt_loop3[i].sin_family = AF_INET;
+ clt_loop3[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x300);
+ clt_loop3[i].sin_port = htons(SCTP_TESTPORT_2+2);
+ }
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(svr_sk, (struct sockaddr *)&svr_loop[0], sizeof(svr_loop[0]));
+ test_bindx_add(svr_sk, (struct sockaddr *)&svr_loop[1], NUMADDR-1);
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 1);
+
+ /* Create and bind the client sockets. */
+ clt_sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(clt_sk1, (struct sockaddr *)&clt_loop1[0], sizeof(clt_loop1));
+ test_bindx_add(clt_sk1, (struct sockaddr *)&clt_loop1[1], NUMADDR-1);
+ clt_sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(clt_sk2, (struct sockaddr *)&clt_loop2[0], sizeof(clt_loop2));
+ test_bindx_add(clt_sk2, (struct sockaddr *)&clt_loop2[1], NUMADDR-1);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(svr_sk);
+ test_enable_assoc_change(clt_sk1);
+ test_enable_assoc_change(clt_sk2);
+
+ /* Set clt_sk1 as non-blocking. */
+ flags = fcntl(clt_sk1, F_GETFL, 0);
+ if (flags < 0)
+ tst_brkm(TBROK, tst_exit, "fcntl F_GETFL: %s", strerror(errno));
+ if (fcntl(clt_sk1, F_SETFL, flags | O_NONBLOCK) < 0)
+ tst_brkm(TBROK, tst_exit, "fcntl F_SETFL: %s", strerror(errno));
+
+ /* Do a non-blocking connectx from clt_sk1 to svr_sk */
+ error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR,
+ &associd);
+ /* Non-blocking connectx should return immediately with EINPROGRESS. */
+ if ((error != -1) || (EINPROGRESS != errno))
+ tst_brkm(TBROK, tst_exit, "non-blocking connectx error: %d"
+ "errno:%d", error, errno);
+
+ tst_resm(TPASS, "non-blocking connectx");
+
+ /* Doing a connectx on a socket to create an association that is
+ * is already established should return EISCONN.
+ */
+ error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR,
+ NULL);
+ if ((error != -1) || (EISCONN != errno))
+ tst_brkm(TBROK, tst_exit, "connectx on a socket to create an "
+ "assoc that is already established error:%d errno:%d",
+ error, errno);
+
+ tst_resm(TPASS, "connectx on a socket to create an assoc that is "
+ "already established");
+
+ /* Initialize inmessage for all receives. */
+ memset(&inmessage, 0, sizeof(inmessage));
+ big_buffer = test_malloc(REALLY_BIG);
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = NULL;
+
+ /* Get COMM_UP on clt_sk1 */
+ error = test_recvmsg(clt_sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ clt_associd1 = sac->sac_assoc_id;
+
+ if (associd) {
+ if (associd != clt_associd1)
+ tst_brkm(TBROK, tst_exit, "Association id mismatch: "
+ "connectx returned %d, notification returned:%d",
+ associd, clt_associd1);
+ tst_resm(TPASS, "Association id match between sctp_connectx()"
+ " and notification.");
+ }
+
+ /* Get COMM_UP on svr_sk */
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd1 = sac->sac_assoc_id;
+
+ /* Do a blocking connectx from clt_sk2 to svr_sk.
+ * Blocking connectx should block until the association is established
+ * and return success.
+ */
+ test_connectx(clt_sk2, (struct sockaddr *)svr_try, NUMADDR);
+
+ /* Get COMM_UP on clt_sk2 */
+ error = test_recvmsg(clt_sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ clt_associd2 = sac->sac_assoc_id;
+
+ /* Get COMM_UP on svr_sk */
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd2 = sac->sac_assoc_id;
+
+ tst_resm(TPASS, "blocking connectx");
+
+ peeloff_sk = test_sctp_peeloff(svr_sk, svr_associd1);
+
+ /* Doing a connectx on a peeled off socket should fail. */
+ error = sctp_connectx(peeloff_sk, (struct sockaddr *)clt_loop3, NUMADDR,
+ NULL);
+ if ((error != -1) || (EISCONN != errno))
+ tst_brkm(TBROK, tst_exit, "connectx on a peeled off socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connectx on a peeled off socket");
+
+ /* Trying to create an association on a socket that matches an
+ * existing peeled-off association should fail.
+ */
+ error = sctp_connectx(svr_sk, (struct sockaddr *)clt_loop1, NUMADDR,
+ NULL);
+ if ((error != -1) || (EADDRNOTAVAIL != errno))
+ tst_brkm(TBROK, tst_exit, "connectx to create an assoc that "
+ "matches a peeled off assoc error:%d errno:%d",
+ error, errno);
+
+ tst_resm(TPASS, "connectx to create an assoc that matches a peeled off "
+ "assoc");
+
+ test_peer_addr(peeloff_sk, svr_associd1, clt_test1, NUMADDR);
+ tst_resm(TPASS, "server association 1 peers ok");
+ test_peer_addr(svr_sk, svr_associd2, clt_test2, NUMADDR);
+ tst_resm(TPASS, "server association 2 peers ok");
+ test_peer_addr(clt_sk1, clt_associd1, svr_test, NUMADDR);
+ tst_resm(TPASS, "client association 1 peers ok");
+ test_peer_addr(clt_sk2, clt_associd2, svr_test, NUMADDR);
+ tst_resm(TPASS, "client association 2 peers ok");
+ close(svr_sk);
+ close(clt_sk1);
+ close(clt_sk2);
+ close(peeloff_sk);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_fragments.c b/utils/sctp/func_tests/test_fragments.c
new file mode 100644
index 000000000..86262ce1e
--- /dev/null
+++ b/utils/sctp/func_tests/test_fragments.c
@@ -0,0 +1,298 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Hui Huang <hui.huang@nokia.com>
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a functional test to verify the data fragmentation, reassembly
+ * support and SCTP_DISABLE_FRAGMENTS socket option.
+ * The following tests are done in sequence.
+ * - Verify SCTP_DISABLE_FRAGMENTS socket option by doing a setsockopt()
+ * followed by a getsockopt().
+ * - Verify that a message size exceeding the association fragmentation
+ * point cannot be sent when fragmentation is disabled.
+ * - Send and receive a set of messages that are bigger than the path mtu.
+ * The different message sizes to be tested are specified in the array
+ * msg_sizes[].
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 4;
+int TST_CNT = 0;
+
+int msg_sizes[] = {1353, 2000, 5000, 10000, 20000, 32768};
+
+int
+main(int argc, char *argv[])
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1;
+ sockaddr_storage_t loop2;
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ int error, bytes_sent;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ char *big_buffer;
+ int msg_len, msg_cnt, i;
+ void *msg_buf;
+ int disable_frag;
+ socklen_t optlen;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ loop1.v6.sin6_family = AF_INET6;
+ loop1.v6.sin6_addr = in6addr_loopback;
+ loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v6.sin6_family = AF_INET6;
+ loop2.v6.sin6_addr = in6addr_loopback;
+ loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
+#else
+ pf_class = PF_INET;
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(sk1);
+ test_enable_assoc_change(sk2);
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ /* Mark sk2 as being able to accept new associations. */
+ test_listen(sk2, 1);
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &loop2;
+ outmessage.msg_namelen = sizeof(loop2);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ msg_len = 10;
+ msg_buf = test_build_msg(10);
+ outmessage.msg_iov->iov_base = msg_buf;
+ outmessage.msg_iov->iov_len = msg_len;
+ test_sendmsg(sk1, &outmessage, 0, msg_len);
+
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on sk2. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd2 = sac->sac_assoc_id;
+#endif
+ /* Get the communication up message on sk1. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd1 = sac->sac_assoc_id;
+#endif
+ /* Get the first message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, msg_len, MSG_EOR, stream, ppid);
+
+ free(msg_buf);
+
+ /* Disable fragmentation. */
+ disable_frag = 1;
+ test_setsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag,
+ sizeof(disable_frag));
+
+ tst_resm(TPASS, "setsockopt(SCTP_DISABLE_FRAGMENTS)");
+
+ /* Do a getsockopt() and verify that fragmentation is disabled. */
+ disable_frag = 0;
+ optlen = sizeof(disable_frag);
+ error = test_getsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag,
+ &optlen);
+ if ((error != 0) && (disable_frag != 1))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DISABLE_FRAGMENTS) "
+ "error:%d errno:%d disable_frag:%d",
+ error, errno, disable_frag);
+
+ tst_resm(TPASS, "getsockopt(SCTP_DISABLE_FRAGMENTS)");
+
+ /* Try to send a messsage that exceeds association fragmentation point
+ * and verify that it fails.
+ */
+ msg_len = 100000;
+ msg_buf = test_build_msg(msg_len);
+ outmessage.msg_iov->iov_base = msg_buf;
+ outmessage.msg_iov->iov_len = msg_len;
+ error = sendmsg(sk1, &outmessage, 0);
+ if ((error != -1) || (errno != EMSGSIZE))
+ tst_brkm(TBROK, tst_exit, "Send a message that exceeds "
+ "assoc frag point error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "Send a message that exceeds assoc frag point");
+
+ /* Enable Fragmentation. */
+ disable_frag = 0;
+ test_setsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag,
+ sizeof(disable_frag));
+
+ msg_cnt = sizeof(msg_sizes) / sizeof(int);
+
+ /* Send and receive the messages of different sizes specified in the
+ * msg_sizes array in a loop.
+ */
+ for (i = 0; i < msg_cnt; i++) {
+
+ msg_len = msg_sizes[i];
+ msg_buf = test_build_msg(msg_len);
+ outmessage.msg_iov->iov_base = msg_buf;
+ outmessage.msg_iov->iov_len = msg_len;
+ bytes_sent = test_sendmsg(sk1, &outmessage, 0, msg_len);
+
+ tst_resm(TINFO, "Sent %d byte message", bytes_sent);
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ /* Handle Partial Reads. */
+ if (inmessage.msg_flags & MSG_EOR) {
+ test_check_msg_data(&inmessage, error, bytes_sent,
+ MSG_EOR, stream, ppid);
+ tst_resm(TINFO, "Received %d byte message", error);
+ } else {
+ int remain;
+
+ test_check_msg_data(&inmessage, error, error, 0,
+ stream, ppid);
+ tst_resm(TINFO, "Received %d byte message", error);
+
+ /* Read the remaining message. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ remain = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, remain,
+ bytes_sent - error,
+ MSG_EOR, stream, ppid);
+ tst_resm(TINFO, "Received %d byte message", error);
+ }
+
+ free(msg_buf);
+ }
+
+ tst_resm(TPASS, "Send/Receive fragmented messages");
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_getname.c b/utils/sctp/func_tests/test_getname.c
new file mode 100644
index 000000000..d7011f69b
--- /dev/null
+++ b/utils/sctp/func_tests/test_getname.c
@@ -0,0 +1,258 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2004
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a kernel test to verify getsockname() and getpeername() interfaces
+ * for single-homed one-to-one style sockets.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 13;
+int TST_CNT = 0;
+
+#define MAX_CLIENTS 10
+
+int
+main(int argc, char *argv[])
+{
+ int clt_sk, svr_sk, accept_sk;
+ sockaddr_storage_t svr_loop, accept_loop;
+ sockaddr_storage_t svr_local_addr, svr_peer_addr;
+ sockaddr_storage_t clt_local_addr, clt_peer_addr;
+ socklen_t len;
+ int error;
+ int pf_class;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Initialize the server and client addresses. */
+#if TEST_V6
+ pf_class = PF_INET6;
+ svr_loop.v6.sin6_family = AF_INET6;
+ svr_loop.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_ANY_INIT;
+ svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1);
+#else
+ pf_class = PF_INET;
+ svr_loop.v4.sin_family = AF_INET;
+ svr_loop.v4.sin_addr.s_addr = INADDR_ANY;
+ svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+#endif
+
+ /* Create and bind the listening server socket. */
+ svr_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ bzero(&svr_local_addr, sizeof(svr_local_addr));
+ len = sizeof(svr_local_addr);
+ /* Verify that getsockname() on an unconnected socket works fine. */
+ error = getsockname(svr_sk, (struct sockaddr *)&svr_local_addr, &len);
+ if (0 != error)
+ tst_brkm(TBROK, tst_exit, "getsockname: %s", strerror(errno));
+
+ tst_resm(TPASS, "getsockname on an unconnected socket");
+
+ bzero(&svr_peer_addr, sizeof(svr_peer_addr));
+ len = sizeof(svr_peer_addr);
+ /* Verify that getpeername() on an unconnected socket fails. */
+ error = getpeername(svr_sk, (struct sockaddr *)&svr_peer_addr, &len);
+ if ((-1 != error) || (ENOTCONN != errno))
+ tst_brkm(TBROK, tst_exit, "getpeername on an unconnected "
+ "socket error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "getpeername on an unconnected socket");
+
+ /* Mark svr_sk as being able to accept new associations. */
+ test_listen(svr_sk, 5);
+
+ /* Create the client socket. */
+ clt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /* Do a blocking connect from clt_sk to svr_sk */
+#if TEST_V6
+ svr_loop.v6.sin6_addr = in6addr_loopback;
+#else
+ svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+#endif
+ test_connect(clt_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ bzero(&clt_local_addr, sizeof(clt_local_addr));
+ len = sizeof(clt_local_addr);
+ /* Get the client's local address. */
+ error = getsockname(clt_sk, (struct sockaddr *)&clt_local_addr, &len);
+ if (0 != error)
+ tst_brkm(TBROK, tst_exit, "getsockname on a connected client "
+ "socket: %s", strerror(errno));
+
+ tst_resm(TPASS, "getsockname on a connected client socket");
+
+ bzero(&clt_peer_addr, sizeof(clt_peer_addr));
+ len = sizeof(clt_peer_addr);
+ /* Get the client's peer address. */
+ error = getpeername(clt_sk, (struct sockaddr *)&clt_peer_addr, &len);
+ if (0 != error)
+ tst_brkm(TBROK, tst_exit, "getpeername on a connected client "
+ "socket: %s", strerror(errno));
+
+ tst_resm(TPASS, "getpeername on a connected client socket");
+
+ /* Extract the association on the listening socket as a new socket. */
+ len = sizeof(accept_loop);
+ accept_sk = test_accept(svr_sk, &accept_loop.sa, &len);
+
+ bzero(&svr_local_addr, sizeof(svr_local_addr));
+ len = sizeof(svr_local_addr);
+ /* Get the server's local address. */
+ error = getsockname(accept_sk, (struct sockaddr *)&svr_local_addr,
+ &len);
+ if (0 != error)
+ tst_brkm(TBROK, tst_exit, "getsockname on a connected server "
+ "socket: %s", strerror(errno));
+
+ tst_resm(TPASS, "getsockname on a connected server socket");
+
+ bzero(&svr_peer_addr, sizeof(svr_peer_addr));
+ len = sizeof(svr_peer_addr);
+ /* Get the server's peer address. */
+ error = getpeername(accept_sk, (struct sockaddr *)&svr_peer_addr,
+ &len);
+ if (0 != error)
+ tst_brkm(TBROK, tst_exit, "getpeername on a connected server "
+ "socket: %s", strerror(errno));
+
+ tst_resm(TPASS, "getpeername on a connected server socket");
+
+ if (svr_local_addr.v4.sin_port != clt_peer_addr.v4.sin_port)
+ tst_brkm(TBROK, tst_exit, "Server's local port(%d) doesn't "
+ "match Client's peer port(%d)\n",
+ svr_local_addr.v4.sin_port, clt_peer_addr.v4.sin_port);
+
+ if (svr_peer_addr.v4.sin_port != clt_local_addr.v4.sin_port)
+ tst_brkm(TBROK, tst_exit, "Server's peer port(%d) doesn't "
+ "match Client's local port(%d)\n",
+ svr_peer_addr.v4.sin_port, clt_local_addr.v4.sin_port);
+#if TEST_V6
+ if (memcmp(&svr_local_addr, &clt_peer_addr, len) != 0)
+ tst_brkm(TBROK, tst_exit, "Server's local address and client's "
+ "peer addresses do not match\n");
+
+ if (memcmp(&svr_peer_addr, &clt_local_addr, len) != 0)
+ tst_brkm(TBROK, tst_exit, "Server's peer address and client's "
+ "local addresses do not match\n");
+#else
+ if (svr_local_addr.v4.sin_addr.s_addr !=
+ clt_peer_addr.v4.sin_addr.s_addr)
+ tst_brkm(TBROK, tst_exit, "Server's local address and client's "
+ "peer addresses do not match\n");
+ if (svr_peer_addr.v4.sin_addr.s_addr !=
+ clt_local_addr.v4.sin_addr.s_addr)
+ tst_brkm(TBROK, tst_exit, "Server's peer address and client's "
+ "local addresses do not match\n");
+#endif
+ tst_resm(TPASS, "getsockname/getpeername server/client match");
+
+ bzero(&clt_local_addr, sizeof(clt_local_addr));
+ len = sizeof(clt_local_addr);
+ /*getsockname(): Bad socket descriptor, EBADF expected error*/
+ error = getsockname(-1, (struct sockaddr *)&clt_local_addr, &len);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "getsockname on a bad socket "
+ "descriptor. error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockname on a bad socket descriptor - EBADF");
+
+ /*getsockname(): Invalid socket, ENOTSOCK expected error*/
+ error = getsockname(0, (struct sockaddr *)&clt_local_addr, &len);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "getsockname on an invalid socket "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockname on an invalid socket - ENOTSOCK");
+
+ /*getsockname(): Invalid structure, EFAULT expected error*/
+ error = getsockname(clt_sk, (struct sockaddr *)-1, &len);
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "getsockname with invalid buffer "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockname with invalid buffer - EFAULT");
+
+ bzero(&clt_peer_addr, sizeof(clt_peer_addr));
+ len = sizeof(clt_peer_addr);
+ /*getpeername(): Bad socket descriptor, EBADF expected error*/
+ error = getpeername(-1, (struct sockaddr *)&clt_local_addr, &len);
+ if (error != -1 || errno != EBADF)
+ tst_brkm(TBROK, tst_exit, "getpeername on a bad socket "
+ "descriptor. error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getpeername on a bad socket descriptor - EBADF");
+
+ /*getpeername(): Invalid socket, ENOTSOCK expected error*/
+ error = getpeername(0, (struct sockaddr *)&clt_local_addr, &len);
+ if (error != -1 || errno != ENOTSOCK)
+ tst_brkm(TBROK, tst_exit, "getpeername on an invalid socket "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getpeername on an invalid socket - ENOTSOCK");
+
+ /*getpeername(): Invalid structure, EFAULT expected error*/
+ error = getpeername(clt_sk, (struct sockaddr *)-1, &len);
+ if (error != -1 || errno != EFAULT)
+ tst_brkm(TBROK, tst_exit, "getpeername with invalid buffer "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getpeername with invalid buffer - EFAULT");
+
+ close(clt_sk);
+ close(svr_sk);
+ close(accept_sk);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_inaddr_any.c b/utils/sctp/func_tests/test_inaddr_any.c
new file mode 100644
index 000000000..722a7025f
--- /dev/null
+++ b/utils/sctp/func_tests/test_inaddr_any.c
@@ -0,0 +1,251 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2002, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ * Copyright (c) 2001 La Monte H.P. Yarroll
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ * Daisy Chang <daisyc@us.ibm.com>
+ */
+
+/* This is a functional test to verify binding a socket with INADDRY_ANY
+ * address and send messages.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 2;
+int TST_CNT = 0;
+
+int
+main(void)
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop;
+ sockaddr_storage_t anyaddr;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ struct iovec iov;
+ struct msghdr inmessage;
+ char *message = "hello, world!\n";
+ char *telephone = "Watson, come here! I need you!\n";
+ char *telephone_resp = "I already brought your coffee...\n";
+ int error;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ socklen_t namelen;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ loop.v6.sin6_family = AF_INET6;
+ loop.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_LOOPBACK_INIT;
+ loop.v6.sin6_port = 0;
+
+ anyaddr.v6.sin6_family = AF_INET6;
+ anyaddr.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_ANY_INIT;
+ anyaddr.v6.sin6_port = 0;
+#else
+ pf_class = PF_INET;
+
+ loop.v4.sin_family = AF_INET;
+ loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop.v4.sin_port = 0;
+
+ anyaddr.v4.sin_family = AF_INET;
+ anyaddr.v4.sin_addr.s_addr = INADDR_ANY;
+ anyaddr.v4.sin_port = 0;
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(sk1);
+ test_enable_assoc_change(sk2);
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop.sa, sizeof(loop));
+ test_bind(sk2, &anyaddr.sa, sizeof(anyaddr));
+
+ tst_resm(TPASS, "bind INADDR_ANY address");
+
+ /* Mark sk2 as being able to accept new associations */
+ test_listen(sk2, 1);
+
+ /* Now use getsockaname() to retrieve the ephmeral ports. */
+ namelen = sizeof(loop);
+ error = getsockname(sk1, &loop.sa, &namelen);
+ if (error != 0)
+ tst_brkm(TBROK, tst_exit, "getsockname: %s", strerror(errno));
+
+ namelen = sizeof(anyaddr);
+ error = getsockname(sk2, &anyaddr.sa, &namelen);
+ if (error != 0)
+ tst_brkm(TBROK, tst_exit, "getsockname: %s", strerror(errno));
+
+#if TEST_V6
+ loop.v6.sin6_port = anyaddr.v6.sin6_port;
+#else
+ loop.v4.sin_port = anyaddr.v4.sin_port;
+#endif
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &loop;
+ outmessage.msg_namelen = sizeof(loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = test_malloc(REALLY_BIG);
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on sk2. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ /* Get the communication up message on sk1. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ /* Get the first message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+
+ /* Send 2 messages. */
+ outmessage.msg_name = &loop;
+ outmessage.msg_namelen = sizeof(loop);
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid++;
+ stream++;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = telephone;
+ outmessage.msg_iov->iov_len = strlen(telephone) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(telephone)+1);
+
+ outmessage.msg_iov->iov_base = telephone_resp;
+ outmessage.msg_iov->iov_len = strlen(telephone_resp) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(telephone_resp)+1);
+
+ /* Get those two messages. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(telephone) + 1,
+ MSG_EOR, stream, ppid);
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(telephone_resp) + 1,
+ MSG_EOR, stream, ppid);
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ close(sk2);
+
+ tst_resm(TPASS, "send msgs from a socket with INADDR_ANY bind address");
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_peeloff.c b/utils/sctp/func_tests/test_peeloff.c
new file mode 100644
index 000000000..8fb7a00ea
--- /dev/null
+++ b/utils/sctp/func_tests/test_peeloff.c
@@ -0,0 +1,299 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a Functional test to verify the new SCTP interface sctp_peeloff()
+ * that can be used to branch off an association into a separate socket.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 6;
+int TST_CNT = 0;
+
+#define MAX_CLIENTS 10
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk[MAX_CLIENTS], peeloff_sk[MAX_CLIENTS];
+ sctp_assoc_t svr_associd[MAX_CLIENTS];
+ sockaddr_storage_t svr_loop, clt_loop[MAX_CLIENTS];
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ int error;
+ uint32_t ppid;
+ uint32_t stream;
+ struct sctp_assoc_change *sac;
+ char *big_buffer;
+ int i;
+ char *message = "hello, world!\n";
+ int pf_class;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+#if TEST_V6
+ pf_class = PF_INET6;
+ svr_loop.v6.sin6_family = AF_INET6;
+ svr_loop.v6.sin6_addr = in6addr_loopback;
+ svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1);
+#else
+ pf_class = PF_INET;
+ svr_loop.v4.sin_family = AF_INET;
+ svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+#endif
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(svr_sk);
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 1);
+
+ /* Create and bind all the client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clt_sk[i] = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+#if TEST_V6
+ clt_loop[i].v6.sin6_family = AF_INET6;
+ clt_loop[i].v6.sin6_addr = in6addr_loopback;
+ clt_loop[i].v6.sin6_port = htons(SCTP_TESTPORT_2 + i);
+#else
+ clt_loop[i].v4.sin_family = AF_INET;
+ clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i);
+#endif
+ test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i]));
+
+ test_enable_assoc_change(clt_sk[i]);
+ }
+
+ /* Send the first message from all the clients to the server. This
+ * will create the associations.
+ */
+ outmessage.msg_name = &svr_loop;
+ outmessage.msg_namelen = sizeof(svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ for (i = 0; i < MAX_CLIENTS; i++)
+ test_sendmsg(clt_sk[i], &outmessage, 0,
+ strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on all client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ clt_associd[i] = sac->sac_assoc_id;
+#endif
+ }
+
+ /* Get the communication up message and the data message on the
+ * server sockets for all the clients.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ svr_associd[i] = sac->sac_assoc_id;
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+ }
+
+ /* Branch off all the associations on the server socket to separate
+ * individual sockets.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++)
+ peeloff_sk[i] = test_sctp_peeloff(svr_sk, svr_associd[i]);
+
+ tst_resm(TPASS, "sctp_peeloff");
+
+ errno = 0;
+ /* Verify that a peeled off socket is not allowed to do a listen(). */
+ error = listen(peeloff_sk[0], 1);
+ if (error != -1)
+ tst_brkm(TBROK, tst_exit, "listen on a peeled off socket "
+ "error: %d, errno: %d", error, errno);
+
+ tst_resm(TPASS, "listen on a peeled off socket");
+
+ errno = 0;
+ /* Verify that an association cannot be branched off an already
+ * peeled-off socket.
+ */
+ if ((-1 != sctp_peeloff(peeloff_sk[0], svr_associd[0])) ||
+ (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "sctp_peeloff on a peeled off "
+ "socket error:%d, errno:%d",
+ error, errno);
+
+ tst_resm(TPASS, "sctp_peeloff on a peeled off socket");
+
+ /* Send a message from all the client sockets to the server socket. */
+ for (i = 0; i < MAX_CLIENTS; i++)
+ test_sendmsg(clt_sk[i], &outmessage, 0, strlen(message)+1);
+
+ /* Receive the sent messages on the peeled off server sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(peeloff_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+ }
+
+ tst_resm(TPASS, "Receive msgs on peeled off sockets");
+
+ /* Send a message from all the peeled off server sockets to the client
+ * sockets.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ outmessage.msg_name = &clt_loop[i];
+ outmessage.msg_namelen = sizeof(clt_loop[i]);
+ test_sendmsg(peeloff_sk[i], &outmessage, 0, strlen(message)+1);
+ }
+
+ /* Receive the messages sent from the peeled of server sockets on
+ * the client sockets.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+ }
+
+ tst_resm(TPASS, "Send msgs on peeled off sockets");
+
+ errno = 0;
+ /* Verify that a peeled-off socket cannot initialize a new
+ * association by trying to send a message to a client that is not
+ * associated with the peeled-off socket.
+ * The message is sent to the client that is associated with the
+ * socket.
+ */
+ outmessage.msg_name = &clt_loop[1];
+ outmessage.msg_namelen = sizeof(clt_loop[1]);
+ test_sendmsg(peeloff_sk[0], &outmessage, 0, strlen(message)+1);
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[0], &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+
+ tst_resm(TPASS, "peeled off socket cannot initialize a new assoc");
+
+ close(svr_sk);
+
+ /* Close all the peeled off server sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++)
+ close(peeloff_sk[i]);
+
+ /* Get the shutdown complete notification from all the client
+ * sockets.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE,
+ SCTP_SHUTDOWN_COMP);
+
+ close(clt_sk[i]);
+ }
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_recvmsg.c b/utils/sctp/func_tests/test_recvmsg.c
new file mode 100644
index 000000000..b16cceb41
--- /dev/null
+++ b/utils/sctp/func_tests/test_recvmsg.c
@@ -0,0 +1,160 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2002, 2003
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ *
+ * This file is part of the SCTP kernel Implementation
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ */
+
+/* This is a kernel test to verify
+ * 1. MSG_EOR flag is set correctly when a single message is read using multiple
+ * recvmsg() calls.
+ * 2. MSG_PEEK support.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 2;
+int TST_CNT = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int svr_sk, clt_sk;
+ struct sockaddr_in svr_loop, clt_loop;
+ struct iovec iov, out_iov;
+ struct msghdr inmessage, outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ int error, msglen, i;
+ char *big_buffer;
+ void *msg_buf;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Initialize the server and client addresses. */
+ svr_loop.sin_family = AF_INET;
+ svr_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.sin_port = htons(SCTP_TESTPORT_1);
+ clt_loop.sin_family = AF_INET;
+ clt_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop.sin_port = htons(SCTP_TESTPORT_2);
+
+ /* Create and bind the server socket. */
+ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(svr_sk, (struct sockaddr *)&svr_loop, sizeof(svr_loop));
+
+ /* Mark server socket as being able to accept new associations. */
+ test_listen(svr_sk, 1);
+
+ /* Create and bind the client sockets. */
+ clt_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ test_bind(clt_sk, (struct sockaddr *)&clt_loop, sizeof(clt_loop));
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(svr_sk);
+ test_enable_assoc_change(clt_sk);
+
+ /* Send a message. This will create the association. */
+ memset(&outmessage, 0, sizeof(outmessage));
+ outmessage.msg_name = &svr_loop;
+ outmessage.msg_namelen = sizeof(svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ msg_buf = test_build_msg(30000);
+ outmessage.msg_iov->iov_base = msg_buf;
+ outmessage.msg_iov->iov_len = 30000;
+ test_sendmsg(clt_sk, &outmessage, 0, 30000);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = 2000;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Receive COMM_UP on clt_sk. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(clt_sk, &inmessage, 0);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ /* Receive COMM_UP on svr_sk. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ /* Read the 30000 byte message using multiple recvmsg() calls in a
+ * loop with 2000 bytes per read.
+ */
+ for (i = 0, msglen = 30000; i < 15; i++, msglen-=2000) {
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_PEEK);
+ test_check_msg_data(&inmessage, error, msglen,
+ MSG_EOR, 0, 0);
+
+ iov.iov_len = 2000;
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, 2000,
+ ((i==14)?MSG_EOR:0), 0, 0);
+ }
+
+ tst_resm(TPASS, "recvmsg with MSG_PEEK flag");
+ tst_resm(TPASS, "MSG_EOR in msg_flags set correctly");
+
+ close(svr_sk);
+ close(clt_sk);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_sctp_sendrecvmsg.c b/utils/sctp/func_tests/test_sctp_sendrecvmsg.c
new file mode 100644
index 000000000..21ba86712
--- /dev/null
+++ b/utils/sctp/func_tests/test_sctp_sendrecvmsg.c
@@ -0,0 +1,380 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2003
+ * Copyright (c) 2003 Intel Corp.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * To compile the v6 version, set the symbol TEST_V6 to 1.
+ *
+ * Written or modified by:
+ * Ardelle Fan <ardelle.fan@intel.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a basic functional test for the SCTP new library APIs
+ * sctp_sendmsg() and sctp_recvmsg(). test_timetolive.c is rewritten using
+ * these new APIs.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT = 0;
+
+/* RCVBUF value, and indirectly RWND*2 */
+#define SMALL_RCVBUF 3000
+#define SMALL_MAXSEG 100
+/* This is extra data length to ensure rwnd closes */
+#define RWND_SLOP 100
+static char *fillmsg = NULL;
+static char *ttlmsg = "This should time out!\n";
+static char *nottlmsg = "This should NOT time out!\n";
+static char ttlfrag[SMALL_MAXSEG*3] = {0};
+static char *message = "Hello world\n";
+
+int main(int argc, char *argv[])
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1;
+ sockaddr_storage_t loop2;
+ sockaddr_storage_t msgname;
+ int error;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ struct sctp_event_subscribe subscribe;
+ char *big_buffer;
+ int offset, msg_flags;
+ socklen_t msgname_len;
+ size_t buflen;
+ struct sctp_send_failed *ssf;
+ struct sctp_sndrcvinfo sinfo;
+ struct sctp_sndrcvinfo snd_sinfo;
+ sctp_assoc_t associd1;
+ socklen_t len, oldlen;
+ struct sctp_status gstatus;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ loop1.v6.sin6_family = AF_INET6;
+ loop1.v6.sin6_addr = in6addr_loopback;
+ loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v6.sin6_family = AF_INET6;
+ loop2.v6.sin6_addr = in6addr_loopback;
+ loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
+#else
+ pf_class = PF_INET;
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Set the MAXSEG to something smallish. */
+ {
+ int val = SMALL_MAXSEG;
+ test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
+ }
+
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ subscribe.sctp_send_failure_event = 1;
+ test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+ test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ /*
+ * Set the RWND small so we can fill it up easily.
+ * then reset RCVBUF to avoid frame droppage
+ */
+ len = sizeof(int);
+ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen, &len);
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
+ strerror(errno));
+
+ len = SMALL_RCVBUF; /* Really becomes 2xlen when set. */
+
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Mark sk2 as being able to accept new associations. */
+ test_listen(sk2, 1);
+
+ /* Send the first message. This will create the association. */
+ ppid = rand();
+ stream = 1;
+ test_sctp_sendmsg(sk1, message, strlen(message) + 1,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 0, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg");
+
+ /* Get the communication up message on sk2. */
+ buflen = REALLY_BIG;
+ big_buffer = test_malloc(buflen);
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+#if 0
+ associd2 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
+#endif
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+
+ /* restore the rcvbuffer size for the receiving socket */
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen,
+ sizeof(oldlen));
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Get the communication up message on sk1. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk1, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ associd1 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ tst_resm(TPASS, "sctp_recvmsg SCTP_COMM_UP notification");
+
+ /* Get the first message which was sent. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
+ strlen(message) + 1, MSG_EOR, stream, ppid);
+
+ tst_resm(TPASS, "sctp_recvmsg data");
+
+ /* Figure out how big to make our fillmsg */
+ len = sizeof(struct sctp_status);
+ memset(&gstatus,0,sizeof(struct sctp_status));
+ gstatus.sstat_assoc_id = associd1;
+ error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
+ strerror(errno));
+ tst_resm(TINFO, "creating a fillmsg of size %d",
+ gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
+
+ /* Send a fillmsg */
+ memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
+ ppid++;
+ stream++;
+ test_sctp_sendmsg(sk1, fillmsg, gstatus.sstat_rwnd+RWND_SLOP,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 0, 0);
+
+ /* Now send a message that will timeout. */
+ test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 2000, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg with ttl");
+
+ /* Next send a message that won't time out. */
+ test_sctp_sendmsg(sk1, nottlmsg, strlen(nottlmsg) + 1,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 0, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg with zero ttl");
+
+ /* And finally a fragmented message that will time out. */
+ memset(ttlfrag, '0', sizeof(ttlfrag));
+ ttlfrag[sizeof(ttlfrag)-1] = '\0';
+ test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 2000, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
+
+ /* Sleep waiting for the message to time out. */
+ tst_resm(TINFO, "** SLEEPING for 3 seconds **");
+ sleep(3);
+
+ /* Get the fillmsg. */
+ do {
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ } while (!(msg_flags & MSG_EOR));
+
+ /* Get the message that did NOT time out. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
+ strlen(nottlmsg) + 1, MSG_EOR, stream, ppid);
+ if (0 != strncmp(big_buffer, nottlmsg, strlen(nottlmsg)))
+ tst_brkm(TBROK, tst_exit, "sctp_recvmsg: Wrong Message !!!");
+
+ tst_resm(TPASS, "sctp_recvmsg msg with zero ttl");
+
+ /* Get the SEND_FAILED notification for the message that DID
+ * time out.
+ */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk1, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_send_failed) +
+ strlen(ttlmsg) + 1,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)big_buffer;
+ if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+
+ tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for message with ttl");
+
+ offset = 0;
+
+ /* Get the SEND_FAILED notifications for the fragmented message that
+ * timed out.
+ */
+ do {
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk1, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_send_failed) +
+ SMALL_MAXSEG,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)big_buffer;
+ if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
+ SMALL_MAXSEG))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+ offset += SMALL_MAXSEG;
+ } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST FRAG */
+
+ tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for fragmented message with "
+ "ttl");
+
+ snd_sinfo.sinfo_ppid = rand();
+ snd_sinfo.sinfo_flags = 0;
+ snd_sinfo.sinfo_stream = 2;
+ snd_sinfo.sinfo_timetolive = 0;
+ snd_sinfo.sinfo_assoc_id = associd1;
+ test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
+ MSG_NOSIGNAL);
+
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
+ strlen(message) + 1, MSG_EOR, snd_sinfo.sinfo_stream,
+ snd_sinfo.sinfo_ppid);
+
+ tst_resm(TPASS, "sctp_send");
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_sockopt.c b/utils/sctp/func_tests/test_sockopt.c
new file mode 100644
index 000000000..a31c5d3ab
--- /dev/null
+++ b/utils/sctp/func_tests/test_sockopt.c
@@ -0,0 +1,1147 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Hui Huang <hui.huang@nokia.com>
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <samudrala@us.ibm.com>
+ */
+
+/* This is a functional test to verify the various SCTP level socket
+ * options that can be used to get information about existing SCTP
+ * associations and to configure certain parameters.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 29;
+int TST_CNT = 0;
+
+int
+main(void)
+{
+ int udp_svr_sk, udp_clt_sk, tcp_svr_sk, tcp_clt_sk;
+ int accept_sk, peeloff_sk;
+ sockaddr_storage_t udp_svr_loop, udp_clt_loop;
+ sockaddr_storage_t tcp_svr_loop, tcp_clt_loop;
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ char *message = "hello, world!\n";
+ int error;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ sctp_assoc_t udp_svr_associd, udp_clt_associd;
+ struct sctp_assoc_change *sac;
+ char *big_buffer;
+ struct sctp_event_subscribe subscribe;
+ struct sctp_initmsg initmsg;
+ struct sctp_paddrparams paddrparams;
+ struct sctp_sndrcvinfo set_udp_sk_dflt_param, get_udp_sk_dflt_param;
+ struct sctp_sndrcvinfo set_tcp_sk_dflt_param, get_tcp_sk_dflt_param;
+ struct sctp_sndrcvinfo set_udp_assoc_dflt_param;
+ struct sctp_sndrcvinfo get_udp_assoc_dflt_param;
+ struct sctp_sndrcvinfo set_tcp_assoc_dflt_param;
+ struct sctp_sndrcvinfo get_tcp_assoc_dflt_param;
+ struct sctp_sndrcvinfo get_peeloff_assoc_dflt_param;
+ struct sctp_sndrcvinfo get_accept_assoc_dflt_param;
+ struct sctp_paddrinfo pinfo;
+ int dflt_pathmaxrxt;
+ socklen_t optlen, addrlen;
+ struct sctp_status status;
+ struct sctp_assoc_value value;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ udp_svr_loop.v6.sin6_family = AF_INET6;
+ udp_svr_loop.v6.sin6_addr = in6addr_loopback;
+ udp_svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ udp_clt_loop.v6.sin6_family = AF_INET6;
+ udp_clt_loop.v6.sin6_addr = in6addr_loopback;
+ udp_clt_loop.v6.sin6_port = htons(SCTP_TESTPORT_1+1);
+
+ tcp_svr_loop.v6.sin6_family = AF_INET6;
+ tcp_svr_loop.v6.sin6_addr = in6addr_loopback;
+ tcp_svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1+2);
+
+ tcp_clt_loop.v6.sin6_family = AF_INET6;
+ tcp_clt_loop.v6.sin6_addr = in6addr_loopback;
+ tcp_clt_loop.v6.sin6_port = htons(SCTP_TESTPORT_1+3);
+#else
+ pf_class = PF_INET;
+
+ udp_svr_loop.v4.sin_family = AF_INET;
+ udp_svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ udp_svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ udp_clt_loop.v4.sin_family = AF_INET;
+ udp_clt_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ udp_clt_loop.v4.sin_port = htons(SCTP_TESTPORT_1+1);
+
+ tcp_svr_loop.v4.sin_family = AF_INET;
+ tcp_svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ tcp_svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1+2);
+
+ tcp_clt_loop.v4.sin_family = AF_INET;
+ tcp_clt_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ tcp_clt_loop.v4.sin_port = htons(SCTP_TESTPORT_2+3);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(udp_svr_sk);
+ test_enable_assoc_change(udp_clt_sk);
+
+ /* Bind these sockets to the test ports. */
+ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+ test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop));
+
+ /* Mark udp_svr_sk as being able to accept new associations. */
+ test_listen(udp_svr_sk, 1);
+
+ /* TEST #1: SCTP_STATUS socket option. */
+ /* Make sure that SCTP_STATUS getsockopt on a socket with no
+ * association fails.
+ */
+ optlen = sizeof(struct sctp_status);
+ memset(&status, 0, optlen);
+ error = getsockopt(udp_svr_sk, SOL_SCTP, SCTP_STATUS, &status,
+ &optlen);
+ if ((error != -1) && (errno != EINVAL))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) on a "
+ "socket with no assoc error:%d errno:%d",
+ error, errno);
+
+ tst_resm(TPASS, "getsockopt(SCTP_STATUS) on a socket with no assoc");
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &udp_svr_loop;
+ outmessage.msg_namelen = sizeof(udp_svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(udp_clt_sk, &outmessage, 0, strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on udp_svr_sk. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ udp_svr_associd = sac->sac_assoc_id;
+
+ /* Get the communication up message on udp_clt_sk. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_clt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ udp_clt_associd = sac->sac_assoc_id;
+
+ /* Get the first message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+
+ /* Get SCTP_STATUS for udp_clt_sk's given association. */
+ optlen = sizeof(struct sctp_status);
+ memset(&status, 0, optlen);
+ status.sstat_assoc_id = udp_clt_associd;
+ test_getsockopt(udp_clt_sk, SCTP_STATUS, &status, &optlen);
+
+ tst_resm(TPASS, "getsockopt(SCTP_STATUS)");
+
+ /* Make sure that SCTP_STATUS getsockopt with invalid associd fails. */
+ optlen = sizeof(struct sctp_status);
+ memset(&status, 0, optlen);
+ status.sstat_assoc_id = udp_svr_associd;
+ error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_STATUS, &status,
+ &optlen);
+ if ((error != -1) && (errno != EINVAL))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) with "
+ "associd error: %d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt(SCTP_STATUS) with invalid associd");
+
+ /* Make sure that SCTP_STATUS getsockopt with NULL associd fails. */
+ optlen = sizeof(struct sctp_status);
+ memset(&status, 0, optlen);
+ status.sstat_assoc_id = 0;
+ error = getsockopt(udp_svr_sk, SOL_SCTP, SCTP_STATUS, &status,
+ &optlen);
+ if ((error != -1) && (errno != EINVAL))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) with "
+ "NULL associd error: %d errno:%d", error, errno);
+
+ tst_resm(TPASS, "getsockopt(SCTP_STATUS) with NULL associd");
+
+ /* Shut down the link. */
+ close(udp_clt_sk);
+
+ /* Get the shutdown complete notification. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ error = 0;
+ close(udp_svr_sk);
+
+ /* TEST #2: SCTP_EVENTS socket option and SCTP_SHUTDOWN_EVENT
+ * notification.
+ */
+ /* Create the two endpoints which will talk to each other. */
+ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(udp_svr_sk);
+ test_enable_assoc_change(udp_clt_sk);
+
+ /* Bind these sockets to the test ports. */
+ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+ test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop));
+
+ /* Mark udp_svr_sk as being able to accept new associations. */
+ test_listen(udp_svr_sk, 1);
+
+ /* Get the default events that are enabled on udp_svr_sk. */
+ optlen = sizeof(subscribe);
+ test_getsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe, &optlen);
+
+ /* Get the default events that are enabled on udp_clt_sk. */
+ optlen = sizeof(subscribe);
+ test_getsockopt(udp_clt_sk, SCTP_EVENTS, &subscribe, &optlen);
+
+ tst_resm(TPASS, "getsockopt(SCTP_EVENTS)");
+
+ /* Disable all the events on udp_svr_sk and udp_clt_sk. */
+ memset(&subscribe, 0, sizeof(struct sctp_event_subscribe));
+ test_setsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe,
+ sizeof(subscribe));
+ test_setsockopt(udp_clt_sk, SCTP_EVENTS, &subscribe,
+ sizeof(subscribe));
+
+ tst_resm(TPASS, "setsockopt(SCTP_EVENTS)");
+
+ /* Get the updated list of enabled events on udp_svr_sk and
+ * udp_clt_sk.
+ */
+ optlen = sizeof(subscribe);
+ test_getsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe, &optlen);
+ optlen = sizeof(subscribe);
+ test_getsockopt(udp_clt_sk, SCTP_EVENTS, &subscribe, &optlen);
+
+ /* Send a message. This will create the association. */
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(udp_clt_sk, &outmessage, 0, strlen(message)+1);
+
+ /* Get the message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, 0, 0);
+ /* Verify that we received the msg without any ancillary data. */
+ if (inmessage.msg_controllen != 0)
+ tst_brkm(TBROK, tst_exit, "Receive unexpected ancillary"
+ "data");
+
+ /* Enable SCTP_SHUTDOWN_EVENTs on udp_svr_sk. */
+ memset(&subscribe, 0, sizeof(struct sctp_event_subscribe));
+ subscribe.sctp_shutdown_event = 1;
+ test_setsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe,
+ sizeof(subscribe));
+
+ error = 0;
+ /* Shut down the link. */
+ close(udp_clt_sk);
+
+ /* Get the SHUTDOWN_EVENT notification on udp_svr_sk. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_shutdown_event),
+ SCTP_SHUTDOWN_EVENT, 0);
+
+ tst_resm(TPASS, "setsockopt(SCTP_EVENTS) - SCTP_SHUTDOWN_EVENT");
+
+ close(udp_svr_sk);
+
+ /* TEST #3: whether sctp_opt_info equals */
+ /* Create the two endpoints which will talk to each other. */
+ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(udp_svr_sk);
+ test_enable_assoc_change(udp_clt_sk);
+
+ /* Bind these sockets to the test ports. */
+ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+ test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop));
+
+ /* Mark udp_svr_sk as being able to accept new associations. */
+ test_listen(udp_svr_sk, 1);
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &udp_svr_loop;
+ outmessage.msg_namelen = sizeof(udp_svr_loop);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(udp_clt_sk, &outmessage, 0, strlen(message)+1);
+
+ /* Get the communication up message on udp_clt_sk. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_clt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ udp_clt_associd = sac->sac_assoc_id;
+
+ /* Compare the SCTP_STATUS result between sctp_opt_info and
+ * getsockopt
+ */
+ {
+ struct sctp_status status1, status2;
+
+ memset(&status1, 0, sizeof(status1));
+ memset(&status2, 0, sizeof(status2));
+ optlen = sizeof(struct sctp_status);
+
+ /* Test SCTP_STATUS for udp_clt_sk's given association. */
+ error = sctp_opt_info(udp_clt_sk,udp_clt_associd,SCTP_STATUS,
+ (char *)&status1, &optlen);
+ if (error != 0)
+ tst_brkm(TBROK, tst_exit,
+ "sctp_opt_info(SCTP_STATUS): %s",
+ strerror(errno));
+
+ status2.sstat_assoc_id = udp_clt_associd;
+ error = getsockopt(udp_clt_sk, IPPROTO_SCTP, SCTP_STATUS,
+ (char *)&status2, &optlen);
+ if (error != 0)
+ tst_brkm(TBROK, tst_exit,
+ "getsockopt(SCTP_STATUS): %s",
+ strerror(errno));
+ if (strncmp((char *)&status1, (char *)&status2, optlen))
+ tst_brkm(TBROK, tst_exit, "sctp_opt_info(SCTP_STAUS)"
+ "doesn't match getsockopt(SCTP_STATUS)");
+
+ tst_resm(TPASS, "sctp_opt_info(SCTP_STATUS)");
+ }
+ error = 0;
+ /* Shut down the link. */
+ close(udp_svr_sk);
+ close(udp_clt_sk);
+
+ /* TEST #4: SCTP_INITMSG socket option. */
+ /* Create a socket. */
+ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Bind this socket to the test port. */
+ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(udp_svr_sk);
+
+ /* Get the default parameters for association initialization. */
+ optlen = sizeof(initmsg);
+ test_getsockopt(udp_svr_sk, SCTP_INITMSG, &initmsg, &optlen);
+
+ tst_resm(TPASS, "getsockopt(SCTP_INITMSG)");
+
+ /* Change the parameters for association initialization. */
+ initmsg.sinit_num_ostreams = 5;
+ initmsg.sinit_max_instreams = 5;
+ initmsg.sinit_max_attempts = 3;
+ initmsg.sinit_max_init_timeo = 30;
+ test_setsockopt(udp_svr_sk, SCTP_INITMSG, &initmsg, sizeof(initmsg));
+
+ tst_resm(TPASS, "setsockopt(SCTP_INITMSG)");
+
+ /* Get the updated parameters for association initialization. */
+ optlen = sizeof(initmsg);
+ test_getsockopt(udp_svr_sk, SCTP_INITMSG, &initmsg, &optlen);
+
+ close(udp_svr_sk);
+
+ /* TEST #5: SCTP_PEER_ADDR_PARAMS socket option. */
+ /* Create a socket. */
+ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Get the default parameters for this endpoint */
+ optlen = sizeof(paddrparams);
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_address.ss_family = AF_INET;
+ test_getsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams,
+ &optlen);
+
+ dflt_pathmaxrxt = paddrparams.spp_pathmaxrxt;
+ tst_resm(TPASS, "getsockopt(SCTP_PEER_ADDR_PARAMS)");
+
+ /* Change the default parameters for this endpoint (socket) */
+ paddrparams.spp_hbinterval = 1000;
+ paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1;
+ paddrparams.spp_sackdelay = 100;
+ test_setsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams,
+ sizeof(paddrparams));
+
+ paddrparams.spp_pathmaxrxt = 0;
+
+ /* Get the updated default parameters for this endpoint. */
+ optlen = sizeof(paddrparams);
+ test_getsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams,
+ &optlen);
+ if (paddrparams.spp_pathmaxrxt != dflt_pathmaxrxt+1)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "mismatch");
+
+ value.assoc_id = 0;
+ optlen = sizeof(value);
+ test_getsockopt(udp_svr_sk, SCTP_DELAYED_ACK_TIME, &value,
+ &optlen);
+ if (value.assoc_value != 100)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DELAYED_ACK_TIME) "
+ "mismatch");
+
+ value.assoc_id = 0;
+ value.assoc_value = 250;
+ test_setsockopt(udp_svr_sk, SCTP_DELAYED_ACK_TIME, &value,
+ sizeof(value));
+ optlen = sizeof(paddrparams);
+ test_getsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams,
+ &optlen);
+ if (paddrparams.spp_sackdelay != 250)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DELAYED_ACK_TIME) "
+ "mismatch");
+
+ tst_resm(TPASS, "setsockopt(SCTP_DELAYED_ACK_TIME)");
+
+
+ /* Ensure that prior defaults are preserved for a new endpoint */
+ udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ optlen = sizeof(paddrparams);
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_address.ss_family = AF_INET;
+ test_getsockopt(udp_clt_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams,
+ &optlen);
+ if (paddrparams.spp_pathmaxrxt != dflt_pathmaxrxt)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "mismatch");
+
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS)");
+
+ /* Invalid assoc id */
+ paddrparams.spp_assoc_id = 1234;
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid associd error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid associd");
+
+ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+ test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop));
+
+ test_listen(udp_svr_sk, 5);
+
+ test_enable_assoc_change(udp_svr_sk);
+ test_enable_assoc_change(udp_clt_sk);
+
+ /* Do a connect on a UDP-style socket and establish an association. */
+ test_connect(udp_clt_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+
+ /* Receive the COMM_UP notifications and get the associd's */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_hbinterval = 1000;
+ paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1;
+ test_setsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams,
+ sizeof(paddrparams));
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) - "
+ "one-to-many style valid associd valid address");
+
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_svr_loop, sizeof(udp_svr_loop));
+ paddrparams.spp_hbinterval = 1000;
+ paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid transport error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid transport");
+
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_hbinterval = 1000;
+ paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams) - 1);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid parameter length error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid parameter length");
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_DELAYED_ACK_TIME,
+ &value,
+ sizeof(value) - 1);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DELAYED_ACK_TIME) "
+ "invalid parameter length error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_DELAYED_ACK_TIME) "
+ "- one-to-many style invalid parameter length");
+
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_sackdelay = 501;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid sack delay error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid sack delay");
+
+ value.assoc_id = sac->sac_assoc_id;
+ value.assoc_value = 501;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_DELAYED_ACK_TIME,
+ &value,
+ sizeof(value));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DELAYED_ACK_TIME) "
+ "invalid sack delay error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_DELAYED_ACK_TIME) "
+ "- one-to-many style invalid sack delay");
+
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_pathmtu = 511;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid path MTU error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid path MTU");
+
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_flags = SPP_HB_ENABLE | SPP_HB_DISABLE;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid hb enable flags error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid hb enable flags");
+
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_flags = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid PMTU discovery enable flags error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid PMTU discovery enable flags");
+
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_assoc_id = sac->sac_assoc_id;
+ memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ paddrparams.spp_flags = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid sack delay enable flags error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid sack delay enable flags");
+
+ memset(&paddrparams, 0, sizeof(paddrparams));
+ paddrparams.spp_flags = SPP_HB_DEMAND;
+
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS,
+ &paddrparams,
+ sizeof(paddrparams));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "invalid hb demand error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) "
+ "- one-to-many style invalid hb demand");
+
+ close(udp_svr_sk);
+ close(udp_clt_sk);
+
+
+ /* TEST #6: SCTP_DEFAULT_SEND_PARAM socket option. */
+ /* Create and bind 2 UDP-style sockets(udp_svr_sk, udp_clt_sk) and
+ * 2 TCP-style sockets. (tcp_svr_sk, tcp_clt_sk)
+ */
+ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ tcp_svr_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ tcp_clt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(udp_svr_sk);
+ test_enable_assoc_change(udp_clt_sk);
+ test_enable_assoc_change(tcp_svr_sk);
+ test_enable_assoc_change(tcp_clt_sk);
+
+ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+ test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop));
+ test_bind(tcp_svr_sk, &tcp_svr_loop.sa, sizeof(tcp_svr_loop));
+ test_bind(tcp_clt_sk, &tcp_clt_loop.sa, sizeof(tcp_clt_loop));
+
+ /* Mark udp_svr_sk and tcp_svr_sk as being able to accept new
+ * associations.
+ */
+ test_listen(udp_svr_sk, 5);
+ test_listen(tcp_svr_sk, 5);
+
+ /* Set default send parameters on the unconnected UDP-style sockets. */
+ memset(&set_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_udp_sk_dflt_param.sinfo_ppid = 1000;
+ test_setsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &set_udp_sk_dflt_param, sizeof(set_udp_sk_dflt_param));
+ memset(&set_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_udp_sk_dflt_param.sinfo_ppid = 1000;
+ test_setsockopt(udp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &set_udp_sk_dflt_param, sizeof(set_udp_sk_dflt_param));
+
+ tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style socket");
+
+ /* Get default send parameters on the unconnected UDP-style socket. */
+ memset(&get_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_udp_sk_dflt_param);
+ test_getsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_udp_sk_dflt_param, &optlen);
+
+ /* Verify that the get param matches set param. */
+ if (set_udp_sk_dflt_param.sinfo_ppid !=
+ get_udp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ /* Get default send parameters on the unconnected UDP-style socket. */
+ memset(&get_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_udp_sk_dflt_param);
+ test_getsockopt(udp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_udp_sk_dflt_param, &optlen);
+
+ /* Verify that the get param matches set param. */
+ if (set_udp_sk_dflt_param.sinfo_ppid !=
+ get_udp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style socket");
+
+ /* Verify that trying to set send params with an invalid assoc id
+ * on an UDP-style socket fails.
+ */
+ memset(&set_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_udp_sk_dflt_param.sinfo_ppid = 1000;
+ /* Invalid assoc id */
+ set_udp_sk_dflt_param.sinfo_assoc_id = 1234;
+ error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_DEFAULT_SEND_PARAM,
+ &set_udp_sk_dflt_param,
+ sizeof(set_udp_sk_dflt_param));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "invalid associd error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "- one-to-many style invalid associd");
+
+ /* Do a connect on a UDP-style socket and establish an association. */
+ test_connect(udp_clt_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop));
+
+ /* Receive the COMM_UP notifications and get the associd's */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ udp_svr_associd = sac->sac_assoc_id;
+
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(udp_clt_sk, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ udp_clt_associd = sac->sac_assoc_id;
+
+ /* Verify that trying to set send params with an assoc id not
+ * belonging to the socket on an UDP-style socket fails.
+ */
+ memset(&set_udp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_udp_assoc_dflt_param.sinfo_ppid = 3000;
+ set_udp_assoc_dflt_param.sinfo_assoc_id = udp_clt_associd;
+ error = setsockopt(udp_svr_sk, SOL_SCTP, SCTP_DEFAULT_SEND_PARAM,
+ &set_udp_assoc_dflt_param,
+ sizeof(set_udp_assoc_dflt_param));
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "associd belonging to another socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style associd belonging to another socket");
+
+ /* Set default send parameters of an association on the listening
+ * UDP-style socket with a valid associd.
+ */
+ memset(&set_udp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_udp_assoc_dflt_param.sinfo_ppid = 3000;
+ set_udp_assoc_dflt_param.sinfo_assoc_id = udp_svr_associd;
+ test_setsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &set_udp_assoc_dflt_param,
+ sizeof(set_udp_assoc_dflt_param));
+
+ tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style valid associd");
+
+ /* Get default send parameters of an association on the listening
+ * UDP-style socket with a valid associd.
+ */
+ memset(&get_udp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ get_udp_assoc_dflt_param.sinfo_assoc_id = udp_svr_associd ;
+ optlen = sizeof(get_udp_assoc_dflt_param);
+ test_getsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_udp_assoc_dflt_param, &optlen);
+
+ /* Verify that the get param matches the set param. */
+ if (get_udp_assoc_dflt_param.sinfo_ppid !=
+ set_udp_assoc_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style valid associd");
+
+ /* Get default send parameters of an association on the connected
+ * UDP-style socket with zero associd. This should return the
+ * socket wide default parameters.
+ */
+ memset(&get_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ get_udp_sk_dflt_param.sinfo_assoc_id = 0 ;
+ optlen = sizeof(get_udp_sk_dflt_param);
+ test_getsockopt(udp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_udp_sk_dflt_param, &optlen);
+
+ /* Verify that the get param matches the socket-wide set param. */
+ if (get_udp_sk_dflt_param.sinfo_ppid !=
+ set_udp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style zero associd");
+
+ peeloff_sk = test_sctp_peeloff(udp_svr_sk, udp_svr_associd);
+
+ /* Get default send parameters of an association on the peeled off
+ * UDP-style socket. This should return the association's default
+ * parameters.
+ */
+ memset(&get_peeloff_assoc_dflt_param, 0,
+ sizeof(struct sctp_sndrcvinfo));
+ get_peeloff_assoc_dflt_param.sinfo_assoc_id = 0 ;
+ optlen = sizeof(get_peeloff_assoc_dflt_param);
+ test_getsockopt(peeloff_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_peeloff_assoc_dflt_param, &optlen);
+
+ /* Verify that the get param matches the association's set param. */
+ if (get_peeloff_assoc_dflt_param.sinfo_ppid !=
+ set_udp_assoc_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-many style peeled off socket");
+
+ /* Set default send parameters on the unconnected TCP-style sockets. */
+ memset(&set_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_tcp_sk_dflt_param.sinfo_ppid = 2000;
+ /* Invalid assoc id, ignored on a TCP-style socket. */
+ set_tcp_sk_dflt_param.sinfo_assoc_id = 1234;
+ test_setsockopt(tcp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &set_tcp_sk_dflt_param,
+ sizeof(set_tcp_sk_dflt_param));
+
+ /* Set default send parameters on the unconnected TCP-style sockets. */
+ memset(&set_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_tcp_sk_dflt_param.sinfo_ppid = 2000;
+ /* Invalid assoc id, ignored on a TCP-style socket. */
+ set_tcp_sk_dflt_param.sinfo_assoc_id = 1234;
+ test_setsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &set_tcp_sk_dflt_param,
+ sizeof(set_tcp_sk_dflt_param));
+
+ tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-one style socket");
+
+ /* Get default send parameters on the unconnected TCP-style socket. */
+ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_tcp_sk_dflt_param);
+ test_getsockopt(tcp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_tcp_sk_dflt_param, &optlen);
+
+ /* Verify that the get param matches set param. */
+ if (set_tcp_sk_dflt_param.sinfo_ppid !=
+ get_tcp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ /* Get default send parameters on the unconnected TCP-style socket. */
+ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_tcp_sk_dflt_param);
+ test_getsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_tcp_sk_dflt_param, &optlen);
+
+ /* Verify that the get param matches set param. */
+ if (set_tcp_sk_dflt_param.sinfo_ppid !=
+ get_tcp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-one style socket");
+
+ /* Do a connect on a TCP-style socket and establish an association. */
+ test_connect(tcp_clt_sk, &tcp_svr_loop.sa, sizeof(tcp_svr_loop));
+
+ /* Set default send parameters of an association on the connected
+ * TCP-style socket.
+ */
+ memset(&set_tcp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ set_tcp_assoc_dflt_param.sinfo_ppid = 4000;
+ set_tcp_assoc_dflt_param.sinfo_assoc_id = 0;
+ test_setsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &set_tcp_assoc_dflt_param,
+ sizeof(set_tcp_assoc_dflt_param));
+
+ tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-one style assoc");
+
+ /* Get default send parameters of an association on the connected
+ * TCP-style socket.
+ */
+ memset(&get_tcp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_tcp_assoc_dflt_param);
+ test_getsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_tcp_assoc_dflt_param, &optlen);
+
+ if (set_tcp_assoc_dflt_param.sinfo_ppid !=
+ get_tcp_assoc_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ /* Get default send parameters on the connected TCP-style socket. */
+ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_tcp_sk_dflt_param);
+ test_getsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_tcp_sk_dflt_param, &optlen);
+
+ /* Verify that the get parameters returned matches the set param
+ * set for the association, not the socket-wide param.
+ */
+ if ((get_tcp_sk_dflt_param.sinfo_ppid ==
+ set_tcp_sk_dflt_param.sinfo_ppid) ||
+ (get_tcp_sk_dflt_param.sinfo_ppid !=
+ set_tcp_assoc_dflt_param.sinfo_ppid))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ /* Get default send parameters on the listening TCP-style socket. */
+ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_tcp_sk_dflt_param);
+ test_getsockopt(tcp_svr_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_tcp_sk_dflt_param, &optlen);
+
+ /* Verify that the get parameters returned matches the socket-wide
+ * set param.
+ */
+ if (get_tcp_sk_dflt_param.sinfo_ppid !=
+ set_tcp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-one style assoc");
+
+ accept_sk = test_accept(tcp_svr_sk, NULL, &addrlen);
+
+ /* Get default send parameters of an association on the accepted
+ * TCP-style socket.
+ */
+ memset(&get_accept_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo));
+ optlen = sizeof(get_accept_assoc_dflt_param);
+ test_getsockopt(accept_sk, SCTP_DEFAULT_SEND_PARAM,
+ &get_accept_assoc_dflt_param, &optlen);
+
+ error = 0;
+
+ /* Verify that the get parameters returned matches the socket-wide
+ * set param.
+ */
+ if (get_tcp_sk_dflt_param.sinfo_ppid !=
+ set_tcp_sk_dflt_param.sinfo_ppid)
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) "
+ "mismatch.");
+
+ tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - "
+ "one-to-one style accepted socket");
+
+ /* TEST #7: SCTP_GET_PEER_ADDR_INFO socket option. */
+ /* Try 0 associd and 0 addr */
+ memset(&pinfo, 0, sizeof(pinfo));
+ optlen = sizeof(pinfo);
+ error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO,
+ &pinfo, &optlen);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_GET_PEER_ADDR_INFO) "
+ "null associd, null addr error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - "
+ "null associd and null addr");
+
+ /* Try valid associd, but 0 addr */
+ memset(&pinfo, 0, sizeof(pinfo));
+ optlen = sizeof(pinfo);
+ pinfo.spinfo_assoc_id = udp_clt_associd;
+ error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO,
+ &pinfo, &optlen);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_GET_PEER_ADDR_INFO) "
+ "valid associd, null addr error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - "
+ "valid associd and null addr");
+
+ /* Try valid associd, invalid addr */
+ memset(&pinfo, 0, sizeof(pinfo));
+ optlen = sizeof(pinfo);
+ pinfo.spinfo_assoc_id = udp_clt_associd;
+ memcpy(&pinfo.spinfo_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO,
+ &pinfo, &optlen);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_GET_PEER_ADDR_INFO) "
+ "valid associd, invalid addr error:%d, errno:%d\n",
+ error, errno);
+
+ tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - "
+ "valid associd and invalid addr");
+
+ /* Try valid associd, valid addr */
+ memset(&pinfo, 0, sizeof(pinfo));
+ optlen = sizeof(pinfo);
+ pinfo.spinfo_assoc_id = udp_clt_associd;
+ memcpy(&pinfo.spinfo_address, &udp_svr_loop, sizeof(udp_svr_loop));
+ test_getsockopt(udp_clt_sk, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen);
+
+ tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - "
+ "valid associd and valid addr");
+
+ /* Try valid addr, peeled off socket */
+ memset(&pinfo, 0, sizeof(pinfo));
+ optlen = sizeof(pinfo);
+ pinfo.spinfo_assoc_id = 0;
+ memcpy(&pinfo.spinfo_address, &udp_clt_loop, sizeof(udp_clt_loop));
+ test_getsockopt(peeloff_sk, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen);
+
+ tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - "
+ "valid associd and valid addr peeled off socket");
+
+ /* Try valid addr, TCP-style accept socket */
+ memset(&pinfo, 0, sizeof(pinfo));
+ optlen = sizeof(pinfo);
+ pinfo.spinfo_assoc_id = 0;
+ memcpy(&pinfo.spinfo_address, &tcp_clt_loop, sizeof(tcp_clt_loop));
+ error = test_getsockopt(accept_sk, SCTP_GET_PEER_ADDR_INFO, &pinfo,
+ &optlen);
+
+ tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - "
+ "valid associd and valid addr accepted socket");
+
+ close(udp_svr_sk);
+ close(udp_clt_sk);
+ close(tcp_svr_sk);
+ close(tcp_clt_sk);
+ close(accept_sk);
+ close(peeloff_sk);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_tcp_style.c b/utils/sctp/func_tests/test_tcp_style.c
new file mode 100644
index 000000000..f4f835a7b
--- /dev/null
+++ b/utils/sctp/func_tests/test_tcp_style.c
@@ -0,0 +1,463 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2003
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ *
+ * This file is part of the SCTP kernel Implementation
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a kernel test to verify the TCP-style socket interfaces. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 22;
+int TST_CNT = 0;
+
+#define MAX_CLIENTS 10
+
+int
+main(int argc, char *argv[])
+{
+ int clt_sk[MAX_CLIENTS], accept_sk[MAX_CLIENTS];
+ int listen_sk, clt2_sk, accept2_sk;
+ sockaddr_storage_t clt_loop[MAX_CLIENTS];
+ sockaddr_storage_t svr_loop, accept_loop, clt2_loop;
+ socklen_t addrlen;
+ int error, i;
+ char *message = "hello, world!\n";
+ char msgbuf[100];
+ int pf_class;
+ struct pollfd poll_fd;
+ fd_set set;
+ struct msghdr outmessage;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct iovec out_iov;
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct msghdr inmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char *big_buffer;
+ struct iovec iov;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Initialize the server and client addresses. */
+#if TEST_V6
+ pf_class = PF_INET6;
+ svr_loop.v6.sin6_family = AF_INET6;
+ svr_loop.v6.sin6_addr = in6addr_loopback;
+ svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1);
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clt_loop[i].v6.sin6_family = AF_INET6;
+ clt_loop[i].v6.sin6_addr = in6addr_loopback;
+ clt_loop[i].v6.sin6_port = htons(SCTP_TESTPORT_2 + i);
+ }
+ clt2_loop.v6.sin6_family = AF_INET6;
+ clt2_loop.v6.sin6_addr = in6addr_loopback;
+ clt2_loop.v6.sin6_port = htons(SCTP_TESTPORT_2 + i);
+#else
+ pf_class = PF_INET;
+ svr_loop.v4.sin_family = AF_INET;
+ svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1);
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clt_loop[i].v4.sin_family = AF_INET;
+ clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i);
+ }
+ clt2_loop.v4.sin_family = AF_INET;
+ clt2_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ clt2_loop.v4.sin_port = htons(SCTP_TESTPORT_2 + i);
+#endif
+
+ /* Create and bind the listening server socket. */
+ listen_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ test_bind(listen_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ /* Mark listen_sk as being able to accept new associations. */
+ test_listen(listen_sk, MAX_CLIENTS-1);
+
+ /* Create and bind the client sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i]));
+ }
+ clt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ test_bind(clt2_sk, &clt2_loop.sa, sizeof(clt2_loop));
+
+ addrlen = sizeof(accept_loop);
+ /* Try to do accept on a non-listening socket. It should fail. */
+ error = accept(clt_sk[0], &accept_loop.sa, &addrlen);
+ if ((-1 != error) && (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "accept on non-listening socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept on non-listening socket");
+
+ /* Try to do a connect from a listening socket. It should fail. */
+ error = connect(listen_sk, (struct sockaddr *)&clt_loop[0],
+ sizeof(clt_loop[0]));
+ if ((-1 != error) && (EISCONN != errno))
+ tst_brkm(TBROK, tst_exit, "connect to non-listening socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect to non-listening socket");
+
+ /* Do a blocking connect from clt_sk's to listen_sk */
+ for (i = 0; i < MAX_CLIENTS; i++)
+ test_connect(clt_sk[i], &svr_loop.sa, sizeof(svr_loop));
+
+ tst_resm(TPASS, "connect to listening socket");
+
+ /* Verify that no more connect's can be done after the acceptq
+ * backlog has reached the max value.
+ */
+ error = connect(clt2_sk, &svr_loop.sa, sizeof(svr_loop));
+ if ((-1 != error) && (ECONNREFUSED != errno))
+ tst_brkm(TBROK, tst_exit, "connect after max backlog "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect after max backlog");
+
+ /* Extract the associations on the listening socket as new sockets. */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ poll_fd.fd = listen_sk;
+ poll_fd.events = POLLIN;
+ poll_fd.revents = 0;
+ error = poll(&poll_fd, 1, -1);
+ if ((1 != error) && (1 != poll_fd.revents))
+ tst_brkm(TBROK, tst_exit, "Unexpected return value "
+ "with poll, error:%d errno:%d, revents:%d",
+ error, errno, poll_fd.revents);
+
+ addrlen = sizeof(accept_loop);
+ accept_sk[i] = test_accept(listen_sk, &accept_loop.sa,
+ &addrlen);
+ }
+
+ tst_resm(TPASS, "accept from listening socket");
+
+ /* Try to do a connect on an established socket. It should fail. */
+ error = connect(accept_sk[0], &clt_loop[0].sa, sizeof(clt_loop[0]));
+ if ((-1 != error) || (EISCONN != errno))
+ tst_brkm(TBROK, tst_exit, "connect on an established socket "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "connect on an established socket");
+
+ /* Try to do accept on an established socket. It should fail. */
+ error = accept(accept_sk[0], &accept_loop.sa, &addrlen);
+ if ((-1 != error) && (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "accept on an established socket "
+ "error:%d errno:%d", error, errno);
+
+ error = accept(clt_sk[0], &accept_loop.sa, &addrlen);
+ if ((-1 != error) && (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "accept on an established socket "
+ "failure: error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "accept on an established socket");
+
+ /* Send and receive a message from the client sockets to the accepted
+ * sockets.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ test_send(clt_sk[i], message, strlen(message), 0);
+ test_recv(accept_sk[i], msgbuf, 100, 0);
+ }
+
+ tst_resm(TPASS, "client sockets -> accepted sockets");
+
+ /* Send and receive a message from the accepted sockets to the client
+ * sockets.
+ */
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ test_send(accept_sk[i], message, strlen(message), 0);
+ test_recv(clt_sk[i], msgbuf, 100, 0);
+ }
+
+ tst_resm(TPASS, "accepted sockets -> client sockets");
+
+ /* Sending a message on a listening socket should fail. */
+ error = send(listen_sk, message, strlen(message), MSG_NOSIGNAL);
+ if ((-1 != error) || (EPIPE != errno))
+ tst_brkm(TBROK, tst_exit, "send on a listening socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "send on a listening socket");
+
+ /* Trying to receive a message on a listening socket should fail. */
+ error = recv(listen_sk, msgbuf, 100, 0);
+ if ((-1 != error) || (ENOTCONN != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a listening socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "recv on a listening socket");
+
+ /* TESTCASES for shutdown() */
+ errno = 0;
+ test_send(accept_sk[0], message, strlen(message), 0);
+
+ /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+ test_enable_assoc_change(clt_sk[0]);
+
+ /* Do a SHUT_WR on clt_sk[0] to disable any new sends. */
+ test_shutdown(clt_sk[0], SHUT_WR);
+
+ /* Reading on a socket that has received SHUTDOWN should return 0
+ * indicating EOF.
+ */
+ error = recv(accept_sk[0], msgbuf, 100, 0);
+ if ((0 != error) || (0 != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN received socket "
+ "error:%d errno:%d", error, errno);
+
+ tst_resm(TPASS, "recv on a SHUTDOWN received socket");
+
+ /* Read the pending message on clt_sk[0] that was received before
+ * SHUTDOWN call.
+ */
+ test_recv(clt_sk[0], msgbuf, 100, 0);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+ inmessage.msg_controllen = sizeof(incmsg);
+
+ /* Receive the SHUTDOWN_COMP notification as they are enabled. */
+ error = test_recvmsg(clt_sk[0], &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ tst_resm(TPASS, "recv SHUTDOWN_COMP notification on a SHUT_WR socket");
+
+ /* No more messages and the association is SHUTDOWN, should fail. */
+ error = recv(clt_sk[0], msgbuf, 100, 0);
+ if ((-1 != error) || (ENOTCONN != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN sent socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "recv on a SHUTDOWN sent socket");
+
+ errno = 0;
+
+ /* Do a SHUT_RD on clt_sk[1] to disable any new receives. */
+ test_shutdown(clt_sk[1], SHUT_RD);
+
+ error = recv(clt_sk[1], msgbuf, 100, 0);
+ if ((0 != error) || (0 != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket "
+ "error:%d, errno:%d", error, errno);
+
+ /* Sending a message on SHUT_RD socket. */
+ test_send(clt_sk[1], message, strlen(message), 0);
+
+ /* Receive the message sent on SHUT_RD socket. */
+ test_recv(accept_sk[1], msgbuf, 100, 0);
+
+ /* Send a message to the SHUT_RD socket. */
+ test_send(accept_sk[1], message, strlen(message), 0);
+
+ /* We should not receive the message as the socket is SHUT_RD */
+ error = recv(clt_sk[1], msgbuf, 100, 0);
+ if ((0 != error) || (0 != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "recv on a SHUT_RD socket");
+
+ /* Do a SHUT_RDWR on clt_sk[2] to disable any new sends/receives. */
+ test_shutdown(clt_sk[2], SHUT_RDWR);
+
+ error = recv(accept_sk[2], msgbuf, 100, 0);
+ if ((0 != error) || (0 != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RDWR socket "
+ "error:%d, errno:%d", error, errno);
+
+ error = recv(clt_sk[2], msgbuf, 100, 0);
+ if ((0 != error) || (0 != errno))
+ tst_brkm(TBROK, tst_exit, "recv on a SHUT_RDWR socket "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "recv on a SHUT_RDWR socket");
+
+ error = 0;
+
+ for (i = 0; i < MAX_CLIENTS; i++)
+ close(clt_sk[i]);
+ for (i = 0; i < MAX_CLIENTS; i++)
+ close(accept_sk[i]);
+
+ /* Test case to verify accept of a CLOSED association. */
+ /* Do a connect, send and a close to ESTABLISH and CLOSE an
+ * association on the listening socket.
+ */
+ test_connect(clt2_sk, &svr_loop.sa, sizeof(svr_loop));
+
+ test_send(clt2_sk, message, strlen(message), 0);
+
+ close(clt2_sk);
+
+ FD_ZERO(&set);
+ FD_SET(listen_sk, &set);
+
+ error = select(listen_sk + 1, &set, NULL, NULL, NULL);
+ if (1 != error)
+ tst_brkm(TBROK, tst_exit, "select error:%d, "
+ "errno: %d", error, errno);
+
+ /* Now accept the CLOSED association waiting on the listening
+ * socket.
+ */
+ accept2_sk = test_accept(listen_sk, &accept_loop.sa, &addrlen);
+
+ /* Receive the message sent before doing a close. */
+ test_recv(accept2_sk, msgbuf, 100, 0);
+
+ /* Receive EOF indication as there are no more messages and the
+ * socket is SHUTDOWN.
+ */
+ error = recv(accept2_sk, msgbuf, 100, 0);
+ if ((0 != error) || (0 != errno))
+ tst_brkm(TBROK, tst_exit, "Unexpected error return on "
+ "recv(error:%d, errno:%d)", error, errno);
+
+ tst_resm(TPASS, "accept of a CLOSED association");
+
+ /* Trying to send a message over the CLOSED association should
+ * generate EPIPE.
+ */
+ error = send(accept2_sk, message, strlen(message), MSG_NOSIGNAL);
+ if ((-1 != error) || (EPIPE != errno))
+ tst_brkm(TBROK, tst_exit, "send to a CLOSED association "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "send to a CLOSED association");
+
+ error = 0;
+ close(accept2_sk);
+
+ /* Verify that auto-connect can be done on a TCP-style socket using
+ * sendto/sendmsg.
+ */
+ clt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
+ test_bind(clt2_sk, &clt2_loop.sa, sizeof(clt2_loop));
+
+ /* Do a sendto() without a connect() */
+ test_sendto(clt2_sk, message, strlen(message), 0, &svr_loop.sa,
+ sizeof(svr_loop));
+
+ accept2_sk = test_accept(listen_sk, &accept_loop.sa, &addrlen);
+
+ test_recv(accept2_sk, msgbuf, 100, 0);
+
+ tst_resm(TPASS, "auto-connect using sendto");
+
+ outmessage.msg_name = &svr_loop;
+ outmessage.msg_namelen = sizeof(svr_loop);
+ outmessage.msg_iov = NULL;
+ outmessage.msg_iovlen = 0;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ /* Verify that SCTP_EOF cannot be used to shutdown an association
+ * on a TCP-style socket.
+ */
+ sinfo->sinfo_flags |= SCTP_EOF;
+ error = sendmsg(clt2_sk, &outmessage, 0);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_EOF flag "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sendmsg with SCTP_EOF flag");
+
+ /* Verify that SCTP_ABORT cannot be used to abort an association
+ * on a TCP-style socket.
+ */
+ sinfo->sinfo_flags |= SCTP_ABORT;
+ error = sendmsg(clt2_sk, &outmessage, 0);
+ if ((-1 != error) || (EINVAL != errno))
+ tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_ABORT flag "
+ "error:%d, errno:%d", error, errno);
+
+ tst_resm(TPASS, "sendmsg with SCTP_ABORT flag");
+
+ /* Verify that a normal message can be sent using sendmsg. */
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ out_iov.iov_base = message;
+ out_iov.iov_len = strlen(message) + 1;
+ sinfo->sinfo_flags = 0;
+ test_sendmsg(clt2_sk, &outmessage, 0, strlen(message)+1);
+
+ test_recv(accept2_sk, msgbuf, 100, 0);
+
+ tst_resm(TPASS, "sendmsg with no flags");
+
+ close(clt2_sk);
+ close(accept2_sk);
+ close(listen_sk);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/func_tests/test_timetolive.c b/utils/sctp/func_tests/test_timetolive.c
new file mode 100644
index 000000000..d13168e4b
--- /dev/null
+++ b/utils/sctp/func_tests/test_timetolive.c
@@ -0,0 +1,406 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/*
+ * This is a basic functional test for the SCTP kernel
+ * implementation of sndrcvinfo.sinfo_timetolive.
+ *
+ * 1) Create two sockets, the listening socket sets its RECVBUF small
+ * 2) Create a connection. Send enough data to the non-reading listener
+ * to fill the RCVBUF.
+ * 5) Set sinfo_timetolive on a message and send.
+ * 6) Disable sinfo_timetolive on a message and send.
+ * 7) Wait sinfo_timetolive.
+ * 8) Read out all the data at the receiver.
+ * 9) Make sure timed out message did not make it.
+ * 10) Make sure that the message with no timeout makes it to the receiver.
+ *
+ * Also test with SEND_FAILED notifications. Also, use a fragmented
+ * message so as to also exercise the SEND_FAILED of fragmentation
+ * code.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 6;
+int TST_CNT = 0;
+
+/* This is the size of our RCVBUF */
+#define SMALL_RCVBUF 3000
+
+/* MAX segment size */
+#define SMALL_MAXSEG 100
+
+/* RWND_SLOP is the extra data that fills up the rwnd */
+#define RWND_SLOP 100
+static char *fillmsg = NULL;
+static char *ttlmsg = "This should time out!\n";
+static char *nottlmsg = "This should NOT time out!\n";
+static char ttlfrag[SMALL_MAXSEG*3] = {0};
+static char *message = "Hello world\n";
+
+int main(int argc, char *argv[])
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1;
+ sockaddr_storage_t loop2;
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ int error;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ sctp_assoc_t associd1;
+ struct sctp_assoc_change *sac;
+ struct sctp_event_subscribe subscribe;
+ char *big_buffer;
+ int offset;
+ struct sctp_send_failed *ssf;
+ socklen_t len; /* Really becomes 2xlen when set. */
+ int orig_len;
+ struct sctp_status gstatus;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ loop1.v6.sin6_family = AF_INET6;
+ loop1.v6.sin6_addr = in6addr_loopback;
+ loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v6.sin6_family = AF_INET6;
+ loop2.v6.sin6_addr = in6addr_loopback;
+ loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
+#else
+ pf_class = PF_INET;
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ len = sizeof(int);
+ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
+ &len);
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
+ strerror(errno));
+ /* Set the MAXSEG to something smallish. */
+ {
+ int val = SMALL_MAXSEG;
+ test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
+ }
+
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ subscribe.sctp_send_failure_event = 1;
+ test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+ test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ /*
+ * This code sets the associations RWND very small so we can
+ * fill it. It does this by manipulating the rcvbuf as follows:
+ * 1) Reduce the rcvbuf size on the socket
+ * 2) create an association so that we advertize rcvbuf/2 as
+ * our initial rwnd
+ * 3) raise the rcvbuf value so that we don't drop data wile
+ * receiving later data
+ */
+ len = SMALL_RCVBUF;
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len,
+ sizeof(len));
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Mark sk2 as being able to accept new associations. */
+ test_listen(sk2, 1);
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &loop2;
+ outmessage.msg_namelen = sizeof(loop2);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on sk2. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+#if 0
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd2 = sac->sac_assoc_id;
+#endif
+
+ /* Get the communication up message on sk1. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd1 = sac->sac_assoc_id;
+
+ /* restore the rcvbuffer size for the receiving socket */
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
+ sizeof(orig_len));
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Get the first data message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+
+ /* Figure out how big to make our fillmsg */
+ len = sizeof(struct sctp_status);
+ memset(&gstatus,0,sizeof(struct sctp_status));
+ gstatus.sstat_assoc_id = associd1;
+ error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
+ strerror(errno));
+ tst_resm(TINFO, "Creating fillmsg of size %d",
+ gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
+
+ /* Send a fillmsg */
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid++;
+ stream++;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
+ outmessage.msg_iov->iov_base = fillmsg;
+ outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_timetolive = 0;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
+ gstatus.sstat_rwnd+RWND_SLOP);
+
+ /* Now send the message with timeout. */
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = ttlmsg;
+ outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_timetolive = 2000;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
+
+ tst_resm(TPASS, "Send a message with timeout");
+
+ /* Next send a message with no timeout. */
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = nottlmsg;
+ outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_timetolive = 0;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
+
+ tst_resm(TPASS, "Send a message with no timeout");
+
+ /* And finally a fragmented message that will time out. */
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ memset(ttlfrag, '0', sizeof(ttlfrag));
+ ttlfrag[sizeof(ttlfrag)-1] = '\0';
+ outmessage.msg_iov->iov_base = ttlfrag;
+ outmessage.msg_iov->iov_len = sizeof(ttlfrag);
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_timetolive = 2000;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
+
+ tst_resm(TPASS, "Send a fragmented message with timeout");
+
+ /* Sleep waiting for the message to time out. */
+ tst_resm(TINFO, " ** SLEEPING for 3 seconds **");
+ sleep(3);
+
+ /* Read the fillmsg snuck in between the ttl'd messages. */
+ do {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ } while (!(inmessage.msg_flags & MSG_EOR));
+
+ /* Now get the message that did NOT time out. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1,
+ MSG_EOR, stream, ppid);
+ if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1))
+ tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!");
+
+ tst_resm(TPASS, "Receive message with no timeout");
+
+ /* Get the SEND_FAILED notification for the message that DID
+ * time out.
+ */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_send_failed) +
+ strlen(ttlmsg) + 1,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)iov.iov_base;
+ if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+
+ tst_resm(TPASS, "Receive SEND_FAILED for message with timeout");
+
+ /* Get the SEND_FAILED notification for the fragmented message that
+ * DID time out.
+ */
+ offset = 0;
+ do {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_send_failed) +
+ SMALL_MAXSEG,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)iov.iov_base;
+ if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
+ SMALL_MAXSEG))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+ offset += SMALL_MAXSEG;
+ } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */
+
+ tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with "
+ "timeout");
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/utils/sctp/include/netinet/sctp.h b/utils/sctp/include/netinet/sctp.h
new file mode 100644
index 000000000..51f5bfb84
--- /dev/null
+++ b/utils/sctp/include/netinet/sctp.h
@@ -0,0 +1,867 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * sctp.h
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * Linux Kernel SCTP Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with SCTP in kernel.
+ *
+ * This header represents the structures and constants needed to support
+ * the SCTP Extension to the Sockets API.
+ *
+ * (C) Copyright IBM Corp. 2001, 2004
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * R. Stewart <randall@sctp.chicago.il.us>
+ * K. Morneau <kmorneau@cisco.com>
+ * Q. Xie <qxie1@email.mot.com>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Jon Grimm <jgrimm@austin.ibm.com>
+ * Daisy Chang <daisyc@us.ibm.com>
+ * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ * Vlad Yasevich <vladislav.yasevich@hp.com>
+ */
+
+#ifndef __linux_sctp_h__
+#define __linux_sctp_h__
+
+#include <stdint.h>
+#include <linux/types.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+typedef __s32 sctp_assoc_t;
+
+/* Socket option layer for SCTP */
+#ifndef SOL_SCTP
+#define SOL_SCTP 132
+#endif
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+/* 9. Preprocessor constants */
+#define HAVE_SCTP
+#define HAVE_KERNEL_SCTP
+#define HAVE_SCTP_MULTIBUF
+#define HAVE_SCTP_NOCONNECT
+#define HAVE_SCTP_PRSCTP
+#define HAVE_SCTP_ADDIP
+#define HAVE_SCTP_CANSET_PRIMARY
+
+/* The following symbols come from the Sockets API Extensions for
+ * SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>.
+ */
+#define SCTP_RTOINFO 0
+#define SCTP_ASSOCINFO 1
+#define SCTP_INITMSG 2
+#define SCTP_NODELAY 3 /* Get/set nodelay option. */
+#define SCTP_AUTOCLOSE 4
+#define SCTP_SET_PEER_PRIMARY_ADDR 5
+#define SCTP_PRIMARY_ADDR 6
+#define SCTP_ADAPTATION_LAYER 7
+#define SCTP_DISABLE_FRAGMENTS 8
+#define SCTP_PEER_ADDR_PARAMS 9
+#define SCTP_DEFAULT_SEND_PARAM 10
+#define SCTP_EVENTS 11
+#define SCTP_I_WANT_MAPPED_V4_ADDR 12 /* Turn on/off mapped v4 addresses */
+#define SCTP_MAXSEG 13 /* Get/set maximum fragment. */
+#define SCTP_STATUS 14
+#define SCTP_GET_PEER_ADDR_INFO 15
+#define SCTP_DELAYED_ACK_TIME 16
+#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME
+#define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME
+#define SCTP_CONTEXT 17
+#define SCTP_FRAGMENT_INTERLEAVE 18
+#define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */
+#define SCTP_MAX_BURST 20 /* Set/Get max burst */
+#define SCTP_AUTH_CHUNK 21 /* Set only: add a chunk type to authenticate */
+#define SCTP_HMAC_IDENT 22
+#define SCTP_AUTH_KEY 23
+#define SCTP_AUTH_ACTIVE_KEY 24
+#define SCTP_AUTH_DELETE_KEY 25
+#define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */
+#define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */
+#define SCTP_GET_ASSOC_NUMBER 28 /* Read only */
+
+/* Internal Socket Options. Some of the sctp library functions are
+ * implemented using these socket options.
+ */
+#define SCTP_SOCKOPT_BINDX_ADD 100 /* BINDX requests for adding addrs */
+#define SCTP_SOCKOPT_BINDX_REM 101 /* BINDX requests for removing addrs. */
+#define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */
+/* Options 104-106 are deprecated and removed. Do not use this space */
+#define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */
+#define SCTP_GET_PEER_ADDRS 108 /* Get all peer addresss. */
+#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local addresss. */
+#define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */
+#define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */
+
+/* SCTP socket option used to read per endpoint association statistics. */
+#define SCTP_GET_ASSOC_STATS 112 /* Read only */
+
+/*
+ * 5.2.1 SCTP Initiation Structure (SCTP_INIT)
+ *
+ * This cmsghdr structure provides information for initializing new
+ * SCTP associations with sendmsg(). The SCTP_INITMSG socket option
+ * uses this same data structure. This structure is not used for
+ * recvmsg().
+ *
+ * cmsg_level cmsg_type cmsg_data[]
+ * ------------ ------------ ----------------------
+ * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg
+ *
+ */
+struct sctp_initmsg {
+ __u16 sinit_num_ostreams;
+ __u16 sinit_max_instreams;
+ __u16 sinit_max_attempts;
+ __u16 sinit_max_init_timeo;
+};
+
+/*
+ * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
+ *
+ * This cmsghdr structure specifies SCTP options for sendmsg() and
+ * describes SCTP header information about a received message through
+ * recvmsg().
+ *
+ * cmsg_level cmsg_type cmsg_data[]
+ * ------------ ------------ ----------------------
+ * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo
+ *
+ */
+struct sctp_sndrcvinfo {
+ __u16 sinfo_stream;
+ __u16 sinfo_ssn;
+ __u16 sinfo_flags;
+ __u32 sinfo_ppid;
+ __u32 sinfo_context;
+ __u32 sinfo_timetolive;
+ __u32 sinfo_tsn;
+ __u32 sinfo_cumtsn;
+ sctp_assoc_t sinfo_assoc_id;
+};
+
+/*
+ * sinfo_flags: 16 bits (unsigned integer)
+ *
+ * This field may contain any of the following flags and is composed of
+ * a bitwise OR of these values.
+ */
+
+enum sctp_sinfo_flags {
+ SCTP_UNORDERED = 1, /* Send/receive message unordered. */
+ SCTP_ADDR_OVER = 2, /* Override the primary destination. */
+ SCTP_ABORT=4, /* Send an ABORT message to the peer. */
+ SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */
+ SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+};
+
+
+typedef union {
+ __u8 raw;
+ struct sctp_initmsg init;
+ struct sctp_sndrcvinfo sndrcv;
+} sctp_cmsg_data_t;
+
+/* These are cmsg_types. */
+typedef enum sctp_cmsg_type {
+ SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */
+#define SCTP_INIT SCTP_INIT
+ SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */
+#define SCTP_SNDRCV SCTP_SNDRCV
+} sctp_cmsg_t;
+
+
+/*
+ * 5.3.1.1 SCTP_ASSOC_CHANGE
+ *
+ * Communication notifications inform the ULP that an SCTP association
+ * has either begun or ended. The identifier for a new association is
+ * provided by this notificaion. The notification information has the
+ * following format:
+ *
+ */
+struct sctp_assoc_change {
+ __u16 sac_type;
+ __u16 sac_flags;
+ __u32 sac_length;
+ __u16 sac_state;
+ __u16 sac_error;
+ __u16 sac_outbound_streams;
+ __u16 sac_inbound_streams;
+ sctp_assoc_t sac_assoc_id;
+ __u8 sac_info[0];
+};
+
+/*
+ * sac_state: 32 bits (signed integer)
+ *
+ * This field holds one of a number of values that communicate the
+ * event that happened to the association. They include:
+ *
+ * Note: The following state names deviate from the API draft as
+ * the names clash too easily with other kernel symbols.
+ */
+enum sctp_sac_state {
+ SCTP_COMM_UP,
+ SCTP_COMM_LOST,
+ SCTP_RESTART,
+ SCTP_SHUTDOWN_COMP,
+ SCTP_CANT_STR_ASSOC,
+};
+
+/*
+ * 5.3.1.2 SCTP_PEER_ADDR_CHANGE
+ *
+ * When a destination address on a multi-homed peer encounters a change
+ * an interface details event is sent. The information has the
+ * following structure:
+ */
+struct sctp_paddr_change {
+ __u16 spc_type;
+ __u16 spc_flags;
+ __u32 spc_length;
+ struct sockaddr_storage spc_aaddr;
+ int spc_state;
+ int spc_error;
+ sctp_assoc_t spc_assoc_id;
+} __attribute__((packed, aligned(4)));
+
+/*
+ * spc_state: 32 bits (signed integer)
+ *
+ * This field holds one of a number of values that communicate the
+ * event that happened to the address. They include:
+ */
+enum sctp_spc_state {
+ SCTP_ADDR_AVAILABLE,
+ SCTP_ADDR_UNREACHABLE,
+ SCTP_ADDR_REMOVED,
+ SCTP_ADDR_ADDED,
+ SCTP_ADDR_MADE_PRIM,
+ SCTP_ADDR_CONFIRMED,
+};
+
+
+/*
+ * 5.3.1.3 SCTP_REMOTE_ERROR
+ *
+ * A remote peer may send an Operational Error message to its peer.
+ * This message indicates a variety of error conditions on an
+ * association. The entire error TLV as it appears on the wire is
+ * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP
+ * specification [SCTP] and any extensions for a list of possible
+ * error formats. SCTP error TLVs have the format:
+ */
+struct sctp_remote_error {
+ __u16 sre_type;
+ __u16 sre_flags;
+ __u32 sre_length;
+ __u16 sre_error;
+ sctp_assoc_t sre_assoc_id;
+ __u8 sre_data[0];
+};
+
+
+/*
+ * 5.3.1.4 SCTP_SEND_FAILED
+ *
+ * If SCTP cannot deliver a message it may return the message as a
+ * notification.
+ */
+struct sctp_send_failed {
+ __u16 ssf_type;
+ __u16 ssf_flags;
+ __u32 ssf_length;
+ __u32 ssf_error;
+ struct sctp_sndrcvinfo ssf_info;
+ sctp_assoc_t ssf_assoc_id;
+ __u8 ssf_data[0];
+};
+
+/*
+ * ssf_flags: 16 bits (unsigned integer)
+ *
+ * The flag value will take one of the following values
+ *
+ * SCTP_DATA_UNSENT - Indicates that the data was never put on
+ * the wire.
+ *
+ * SCTP_DATA_SENT - Indicates that the data was put on the wire.
+ * Note that this does not necessarily mean that the
+ * data was (or was not) successfully delivered.
+ */
+enum sctp_ssf_flags {
+ SCTP_DATA_UNSENT,
+ SCTP_DATA_SENT,
+};
+
+/*
+ * 5.3.1.5 SCTP_SHUTDOWN_EVENT
+ *
+ * When a peer sends a SHUTDOWN, SCTP delivers this notification to
+ * inform the application that it should cease sending data.
+ */
+struct sctp_shutdown_event {
+ __u16 sse_type;
+ __u16 sse_flags;
+ __u32 sse_length;
+ sctp_assoc_t sse_assoc_id;
+};
+
+/*
+ * 5.3.1.6 SCTP_ADAPTATION_INDICATION
+ *
+ * When a peer sends a Adaptation Layer Indication parameter , SCTP
+ * delivers this notification to inform the application
+ * that of the peers requested adaptation layer.
+ */
+struct sctp_adaptation_event {
+ __u16 sai_type;
+ __u16 sai_flags;
+ __u32 sai_length;
+ __u32 sai_adaptation_ind;
+ sctp_assoc_t sai_assoc_id;
+};
+
+/*
+ * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
+ *
+ * When a receiver is engaged in a partial delivery of a
+ * message this notification will be used to indicate
+ * various events.
+ */
+struct sctp_pdapi_event {
+ __u16 pdapi_type;
+ __u16 pdapi_flags;
+ __u32 pdapi_length;
+ __u32 pdapi_indication;
+ sctp_assoc_t pdapi_assoc_id;
+};
+
+enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, };
+
+/*
+* 5.3.1.8. SCTP_AUTHENTICATION_EVENT
+*
+* When a receiver is using authentication this message will provide
+* notifications regarding new keys being made active as well as errors.
+*/
+
+struct sctp_authkey_event {
+ __u16 auth_type;
+ __u16 auth_flags;
+ __u32 auth_length;
+ __u16 auth_keynumber;
+ __u16 auth_altkeynumber;
+ __u32 auth_indication;
+ sctp_assoc_t auth_assoc_id;
+};
+
+enum { SCTP_AUTH_NEWKEY = 0, };
+
+struct sctp_sender_dry_event {
+ __u16 sender_dry_type;
+ __u16 sender_dry_flags;
+ __u32 sender_dry_length;
+ sctp_assoc_t sender_dry_assoc_id;
+};
+
+/*
+ * Described in Section 7.3
+ * Ancillary Data and Notification Interest Options
+ */
+struct sctp_event_subscribe {
+ __u8 sctp_data_io_event;
+ __u8 sctp_association_event;
+ __u8 sctp_address_event;
+ __u8 sctp_send_failure_event;
+ __u8 sctp_peer_error_event;
+ __u8 sctp_shutdown_event;
+ __u8 sctp_partial_delivery_event;
+ __u8 sctp_adaptation_layer_event;
+ __u8 sctp_authentication_event;
+ __u8 sctp_sender_dry_event;
+};
+
+/*
+ * 5.3.1 SCTP Notification Structure
+ *
+ * The notification structure is defined as the union of all
+ * notification types.
+ *
+ */
+union sctp_notification {
+ struct {
+ __u16 sn_type; /* Notification type. */
+ __u16 sn_flags;
+ __u32 sn_length;
+ } sn_header;
+ struct sctp_assoc_change sn_assoc_change;
+ struct sctp_paddr_change sn_paddr_change;
+ struct sctp_remote_error sn_remote_error;
+ struct sctp_send_failed sn_send_failed;
+ struct sctp_shutdown_event sn_shutdown_event;
+ struct sctp_adaptation_event sn_adaptation_event;
+ struct sctp_pdapi_event sn_pdapi_event;
+ struct sctp_authkey_event sn_authkey_event;
+ struct sctp_sender_dry_event sn_sender_dry_event;
+};
+
+/* Section 5.3.1
+ * All standard values for sn_type flags are greater than 2^15.
+ * Values from 2^15 and down are reserved.
+ */
+
+enum sctp_sn_type {
+ SCTP_SN_TYPE_BASE = (1<<15),
+ SCTP_ASSOC_CHANGE,
+#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE
+ SCTP_PEER_ADDR_CHANGE,
+#define SCTP_PEER_ADDR_CHANGE SCTP_PEER_ADDR_CHANGE
+ SCTP_SEND_FAILED,
+#define SCTP_SEND_FAILED SCTP_SEND_FAILED
+ SCTP_REMOTE_ERROR,
+#define SCTP_REMOTE_ERROR SCTP_REMOTE_ERROR
+ SCTP_SHUTDOWN_EVENT,
+#define SCTP_SHUTDOWN_EVENT SCTP_SHUTDOWN_EVENT
+ SCTP_PARTIAL_DELIVERY_EVENT,
+#define SCTP_PARTIAL_DELIVERY_EVENT SCTP_PARTIAL_DELIVERY_EVENT
+ SCTP_ADAPTATION_INDICATION,
+#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTATION_INDICATION
+ SCTP_AUTHENTICATION_INDICATION,
+#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_INDICATION
+ SCTP_SENDER_DRY_EVENT,
+#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT
+};
+
+/* Notification error codes used to fill up the error fields in some
+ * notifications.
+ * SCTP_PEER_ADDRESS_CHAGE : spc_error
+ * SCTP_ASSOC_CHANGE : sac_error
+ * These names should be potentially included in the draft 04 of the SCTP
+ * sockets API specification.
+ */
+typedef enum sctp_sn_error {
+ SCTP_FAILED_THRESHOLD,
+ SCTP_RECEIVED_SACK,
+ SCTP_HEARTBEAT_SUCCESS,
+ SCTP_RESPONSE_TO_USER_REQ,
+ SCTP_INTERNAL_ERROR,
+ SCTP_SHUTDOWN_GUARD_EXPIRES,
+ SCTP_PEER_FAULTY,
+} sctp_sn_error_t;
+
+/*
+ * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO)
+ *
+ * The protocol parameters used to initialize and bound retransmission
+ * timeout (RTO) are tunable. See [SCTP] for more information on how
+ * these parameters are used in RTO calculation.
+ */
+struct sctp_rtoinfo {
+ sctp_assoc_t srto_assoc_id;
+ __u32 srto_initial;
+ __u32 srto_max;
+ __u32 srto_min;
+};
+
+/*
+ * 7.1.2 Association Parameters (SCTP_ASSOCINFO)
+ *
+ * This option is used to both examine and set various association and
+ * endpoint parameters.
+ */
+struct sctp_assocparams {
+ sctp_assoc_t sasoc_assoc_id;
+ __u16 sasoc_asocmaxrxt;
+ __u16 sasoc_number_peer_destinations;
+ __u32 sasoc_peer_rwnd;
+ __u32 sasoc_local_rwnd;
+ __u32 sasoc_cookie_life;
+};
+
+/*
+ * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
+ *
+ * Requests that the peer mark the enclosed address as the association
+ * primary. The enclosed address must be one of the association's
+ * locally bound addresses. The following structure is used to make a
+ * set primary request:
+ */
+struct sctp_setpeerprim {
+ sctp_assoc_t sspp_assoc_id;
+ struct sockaddr_storage sspp_addr;
+} __attribute__((packed, aligned(4)));
+
+/*
+ * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
+ *
+ * Requests that the local SCTP stack use the enclosed peer address as
+ * the association primary. The enclosed address must be one of the
+ * association peer's addresses. The following structure is used to
+ * make a set peer primary request:
+ */
+struct sctp_setprim {
+ sctp_assoc_t ssp_assoc_id;
+ struct sockaddr_storage ssp_addr;
+} __attribute__((packed, aligned(4)));
+
+/* For backward compatibility use, define the old name too */
+#define sctp_prim sctp_setprim
+
+/*
+ * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
+ *
+ * Requests that the local endpoint set the specified Adaptation Layer
+ * Indication parameter for all future INIT and INIT-ACK exchanges.
+ */
+struct sctp_setadaptation {
+ __u32 ssb_adaptation_ind;
+};
+
+/*
+ * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS)
+ *
+ * Applications can enable or disable heartbeats for any peer address
+ * of an association, modify an address's heartbeat interval, force a
+ * heartbeat to be sent immediately, and adjust the address's maximum
+ * number of retransmissions sent before an address is considered
+ * unreachable. The following structure is used to access and modify an
+ * address's parameters:
+ */
+enum sctp_spp_flags {
+ SPP_HB_ENABLE = 1<<0, /*Enable heartbeats*/
+ SPP_HB_DISABLE = 1<<1, /*Disable heartbeats*/
+ SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE,
+ SPP_HB_DEMAND = 1<<2, /*Send heartbeat immediately*/
+ SPP_PMTUD_ENABLE = 1<<3, /*Enable PMTU discovery*/
+ SPP_PMTUD_DISABLE = 1<<4, /*Disable PMTU discovery*/
+ SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE,
+ SPP_SACKDELAY_ENABLE = 1<<5, /*Enable SACK*/
+ SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/
+ SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE,
+ SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */
+};
+
+struct sctp_paddrparams {
+ sctp_assoc_t spp_assoc_id;
+ struct sockaddr_storage spp_address;
+ __u32 spp_hbinterval;
+ __u16 spp_pathmaxrxt;
+ __u32 spp_pathmtu;
+ __u32 spp_sackdelay;
+ __u32 spp_flags;
+} __attribute__((packed, aligned(4)));
+
+/*
+ * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK)
+ *
+ * This set option adds a chunk type that the user is requesting to be
+ * received only in an authenticated way. Changes to the list of chunks
+ * will only effect future associations on the socket.
+ */
+struct sctp_authchunk {
+ __u8 sauth_chunk;
+};
+
+/*
+ * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT)
+ *
+ * This option gets or sets the list of HMAC algorithms that the local
+ * endpoint requires the peer to use.
+*/
+
+enum {
+ SCTP_AUTH_HMAC_ID_SHA1 = 1,
+ SCTP_AUTH_HMAC_ID_SHA256 = 3,
+};
+
+struct sctp_hmacalgo {
+ __u32 shmac_number_of_idents;
+ __u16 shmac_idents[];
+};
+
+/*
+ * 7.1.20. Set a shared key (SCTP_AUTH_KEY)
+ *
+ * This option will set a shared secret key which is used to build an
+ * association shared key.
+ */
+struct sctp_authkey {
+ sctp_assoc_t sca_assoc_id;
+ __u16 sca_keynumber;
+ __u16 sca_keylength;
+ __u8 sca_key[];
+};
+
+/*
+ * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY)
+ *
+ * This option will get or set the active shared key to be used to build
+ * the association shared key.
+ */
+
+struct sctp_authkeyid {
+ sctp_assoc_t scact_assoc_id;
+ __u16 scact_keynumber;
+};
+
+
+/*
+ * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed. This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds. It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm. If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values. If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model). Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ */
+struct sctp_sack_info {
+ sctp_assoc_t sack_assoc_id;
+ uint32_t sack_delay;
+ uint32_t sack_freq;
+};
+
+struct sctp_assoc_value {
+ sctp_assoc_t assoc_id;
+ uint32_t assoc_value;
+};
+
+/*
+ * 7.2.2 Peer Address Information
+ *
+ * Applications can retrieve information about a specific peer address
+ * of an association, including its reachability state, congestion
+ * window, and retransmission timer values. This information is
+ * read-only. The following structure is used to access this
+ * information:
+ */
+struct sctp_paddrinfo {
+ sctp_assoc_t spinfo_assoc_id;
+ struct sockaddr_storage spinfo_address;
+ __s32 spinfo_state;
+ __u32 spinfo_cwnd;
+ __u32 spinfo_srtt;
+ __u32 spinfo_rto;
+ __u32 spinfo_mtu;
+} __attribute__((packed, aligned(4)));
+
+/* Peer addresses's state. */
+/* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x]
+ * calls.
+ * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters.
+ * Not yet confirmed by a heartbeat and not available for data
+ * transfers.
+ * ACTIVE : Peer address confirmed, active and available for data transfers.
+ * INACTIVE: Peer address inactive and not available for data transfers.
+ */
+enum sctp_spinfo_state {
+ SCTP_INACTIVE,
+ SCTP_PF,
+ SCTP_ACTIVE,
+ SCTP_UNCONFIRMED,
+ SCTP_UNKNOWN = 0xffff
+};
+
+/*
+ * 7.2.1 Association Status (SCTP_STATUS)
+ *
+ * Applications can retrieve current status information about an
+ * association, including association state, peer receiver window size,
+ * number of unacked data chunks, and number of data chunks pending
+ * receipt. This information is read-only. The following structure is
+ * used to access this information:
+ */
+struct sctp_status {
+ sctp_assoc_t sstat_assoc_id;
+ __s32 sstat_state;
+ __u32 sstat_rwnd;
+ __u16 sstat_unackdata;
+ __u16 sstat_penddata;
+ __u16 sstat_instrms;
+ __u16 sstat_outstrms;
+ __u32 sstat_fragmentation_point;
+ struct sctp_paddrinfo sstat_primary;
+};
+
+/*
+ * 7.2.3. Get the list of chunks the peer requires to be authenticated
+ * (SCTP_PEER_AUTH_CHUNKS)
+ *
+ * This option gets a list of chunks for a specified association that
+ * the peer requires to be received authenticated only.
+ */
+struct sctp_authchunks {
+ sctp_assoc_t gauth_assoc_id;
+ __u32 gauth_number_of_chunks;
+ uint8_t gauth_chunks[];
+};
+/* The broken spelling has been released already,
+ * so don't break anyone, now that it's fixed.
+ */
+#define guth_number_of_chunks gauth_number_of_chunks
+
+/* Association states. */
+enum sctp_sstat_state {
+ SCTP_EMPTY = 0,
+ SCTP_CLOSED = 1,
+ SCTP_COOKIE_WAIT = 2,
+ SCTP_COOKIE_ECHOED = 3,
+ SCTP_ESTABLISHED = 4,
+ SCTP_SHUTDOWN_PENDING = 5,
+ SCTP_SHUTDOWN_SENT = 6,
+ SCTP_SHUTDOWN_RECEIVED = 7,
+ SCTP_SHUTDOWN_ACK_SENT = 8,
+};
+
+/*
+ * 8.3, 8.5 get all peer/local addresses in an association.
+ * This parameter struct is used by SCTP_GET_PEER_ADDRS and
+ * SCTP_GET_LOCAL_ADDRS socket options used internally to implement
+ * sctp_getpaddrs() and sctp_getladdrs() API.
+ */
+struct sctp_getaddrs_old {
+ sctp_assoc_t assoc_id;
+ int addr_num;
+ struct sockaddr *addrs;
+};
+struct sctp_getaddrs {
+ sctp_assoc_t assoc_id; /*input*/
+ __u32 addr_num; /*output*/
+ __u8 addrs[0]; /*output, variable size*/
+};
+
+/* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves
+ * association stats. All stats are counts except sas_maxrto and
+ * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since
+ * the last call. Will return 0 when did not change since last call
+ */
+struct sctp_assoc_stats {
+ sctp_assoc_t sas_assoc_id; /* Input */
+ /* Transport of the observed max RTO spike */
+ struct sockaddr_storage sas_obs_rto_ipaddr;
+ __u64 sas_maxrto; /* Maximum Observed RTO for period */
+ __u64 sas_isacks; /* SACKs received */
+ __u64 sas_osacks; /* SACKs sent */
+ __u64 sas_opackets; /* Packets sent */
+ __u64 sas_ipackets; /* Packets received */
+ __u64 sas_rtxchunks; /* Retransmitted Chunks */
+ __u64 sas_outofseqtsns;/* TSN received > next expected */
+ __u64 sas_idupchunks; /* Dups received (ordered+unordered) */
+ __u64 sas_gapcnt; /* Gap Acknowledgements Received */
+ __u64 sas_ouodchunks; /* Unordered data chunks sent */
+ __u64 sas_iuodchunks; /* Unordered data chunks received */
+ __u64 sas_oodchunks; /* Ordered data chunks sent */
+ __u64 sas_iodchunks; /* Ordered data chunks received */
+ __u64 sas_octrlchunks; /* Control chunks sent */
+ __u64 sas_ictrlchunks; /* Control chunks received */
+};
+
+/* These are bit fields for msghdr->msg_flags. See section 5.1. */
+/* On user space Linux, these live in <bits/socket.h> as an enum. */
+enum sctp_msg_flags {
+ MSG_NOTIFICATION = 0x8000,
+#define MSG_NOTIFICATION MSG_NOTIFICATION
+};
+
+/*
+ * 8.1 sctp_bindx()
+ *
+ * The flags parameter is formed from the bitwise OR of zero or more of the
+ * following currently defined flags:
+ */
+#define SCTP_BINDX_ADD_ADDR 0x01
+#define SCTP_BINDX_REM_ADDR 0x02
+
+/* This is the structure that is passed as an argument(optval) to
+ * getsockopt(SCTP_SOCKOPT_PEELOFF).
+ */
+typedef struct {
+ sctp_assoc_t associd;
+ int sd;
+} sctp_peeloff_arg_t;
+
+
+int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags);
+
+int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
+ sctp_assoc_t *id);
+
+int sctp_peeloff(int sd, sctp_assoc_t assoc_id);
+
+/* Prototype for the library function sctp_opt_info defined in
+ * API 7. Socket Options.
+ */
+int sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size);
+
+/* Get all peer address on a socket. This is a new SCTP API
+ * described in the section 8.3 of the Sockets API Extensions for SCTP.
+ * This is implemented using the getsockopt() interface.
+ */
+int sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs);
+
+/* Frees all resources allocated by sctp_getpaddrs(). This is a new SCTP API
+ * described in the section 8.4 of the Sockets API Extensions for SCTP.
+ */
+int sctp_freepaddrs(struct sockaddr *addrs);
+
+/* Get all locally bound address on a socket. This is a new SCTP API
+ * described in the section 8.5 of the Sockets API Extensions for SCTP.
+ * This is implemented using the getsockopt() interface.
+ */
+int sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs);
+
+/* Frees all resources allocated by sctp_getladdrs(). This is a new SCTP API
+ * described in the section 8.6 of the Sockets API Extensions for SCTP.
+ */
+int sctp_freeladdrs(struct sockaddr *addrs);
+
+/* This library function assists the user with the advanced features
+ * of SCTP. This is a new SCTP API described in the section 8.7 of the
+ * Sockets API Extensions for SCTP. This is implemented using the
+ * sendmsg() interface.
+ */
+int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
+ socklen_t tolen, uint32_t ppid, uint32_t flags,
+ uint16_t stream_no, uint32_t timetolive, uint32_t context);
+
+/* This library function assist the user with sending a message without
+ * dealing directly with the CMSG header.
+ */
+int sctp_send(int s, const void *msg, size_t len,
+ const struct sctp_sndrcvinfo *sinfo, int flags);
+
+/* This library function assists the user with the advanced features
+ * of SCTP. This is a new SCTP API described in the section 8.8 of the
+ * Sockets API Extensions for SCTP. This is implemented using the
+ * recvmsg() interface.
+ */
+int sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from,
+ socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo,
+ int *msg_flags);
+
+/* Return the address length for an address family. */
+int sctp_getaddrlen(sa_family_t family);
+
+__END_DECLS
+
+#endif /* __linux_sctp_h__ */
diff --git a/utils/sctp/lib/Makefile b/utils/sctp/lib/Makefile
new file mode 100644
index 000000000..810bbb690
--- /dev/null
+++ b/utils/sctp/lib/Makefile
@@ -0,0 +1,31 @@
+#
+# testcases/network/sctp/lib Makefile.
+#
+# Copyright (C) 2009, Cisco Systems Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Garrett Cooper, July 2009
+#
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+CPPFLAGS += -I$(abs_srcdir)/../include
+
+LIB := libsctp.a
+
+include $(top_srcdir)/include/mk/lib.mk
diff --git a/utils/sctp/lib/addrs.c b/utils/sctp/lib/addrs.c
new file mode 100644
index 000000000..65f522225
--- /dev/null
+++ b/utils/sctp/lib/addrs.c
@@ -0,0 +1,155 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * addrs.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
+ *
+ * (C) Copyright IBM Corp. 2003
+ * Copyright (c) 2001-2002 Intel Corp.
+ *
+ * Written or modified by:
+ * Ardelle Fan <ardelle.fan@intel.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ * Ivan Skytte Jørgensen <isj-sctp@i1.dk>
+ */
+
+#include <malloc.h>
+#include <netinet/in.h>
+#include <netinet/sctp.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * Common getsockopt() layer
+ * If the NEW getsockopt() API fails this function will fall back to using
+ * the old API
+ */
+static int
+sctp_getaddrs(int sd, sctp_assoc_t id, int optname_new,
+ struct sockaddr **addrs)
+{
+ int cnt, err;
+ socklen_t len;
+ size_t bufsize = 4096; /*enough for most cases*/
+
+ struct sctp_getaddrs *getaddrs = (struct sctp_getaddrs*)malloc(bufsize);
+ if(!getaddrs)
+ return -1;
+
+ for(;;) {
+ char *new_buf;
+
+ len = bufsize;
+ getaddrs->assoc_id = id;
+ err = getsockopt(sd, SOL_SCTP, optname_new, getaddrs, &len);
+ if (err == 0) {
+ /*got it*/
+ break;
+ }
+ if (errno != ENOMEM ) {
+ /*unknown error*/
+ free(getaddrs);
+ return -1;
+ }
+ /*expand buffer*/
+ if (bufsize > 128*1024) {
+ /*this is getting ridiculous*/
+ free(getaddrs);
+ errno = ENOBUFS;
+ return -1;
+ }
+ new_buf = realloc(getaddrs, bufsize+4096);
+ if (!new_buf) {
+ free(getaddrs);
+ return -1;
+ }
+ bufsize += 4096;
+ getaddrs = (struct sctp_getaddrs*)new_buf;
+ }
+
+ /* we skip traversing the list, allocating a new buffer etc. and enjoy
+ * a simple hack*/
+ cnt = getaddrs->addr_num;
+ memmove(getaddrs, getaddrs + 1, len);
+ *addrs = (struct sockaddr*)getaddrs;
+
+ return cnt;
+} /* sctp_getaddrs() */
+
+/* Get all peer address on a socket. This is a new SCTP API
+ * described in the section 8.3 of the Sockets API Extensions for SCTP.
+ * This is implemented using the getsockopt() interface.
+ */
+int
+sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs)
+{
+ return sctp_getaddrs(sd, id,
+ SCTP_GET_PEER_ADDRS,
+ addrs);
+} /* sctp_getpaddrs() */
+
+/* Frees all resources allocated by sctp_getpaddrs(). This is a new SCTP API
+ * described in the section 8.4 of the Sockets API Extensions for SCTP.
+ */
+int
+sctp_freepaddrs(struct sockaddr *addrs)
+{
+ free(addrs);
+ return 0;
+
+} /* sctp_freepaddrs() */
+
+/* Get all locally bound address on a socket. This is a new SCTP API
+ * described in the section 8.5 of the Sockets API Extensions for SCTP.
+ * This is implemented using the getsockopt() interface.
+ */
+int
+sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs)
+{
+ return sctp_getaddrs(sd, id,
+ SCTP_GET_LOCAL_ADDRS,
+ addrs);
+} /* sctp_getladdrs() */
+
+/* Frees all resources allocated by sctp_getladdrs(). This is a new SCTP API
+ * described in the section 8.6 of the Sockets API Extensions for SCTP.
+ */
+int
+sctp_freeladdrs(struct sockaddr *addrs)
+{
+ free(addrs);
+ return 0;
+
+} /* sctp_freeladdrs() */
+
+int
+sctp_getaddrlen(sa_family_t family)
+{
+ /* We could call into the kernel to see what it thinks the size should
+ * be, but hardcoding the address families here is: (a) faster,
+ * (b) easier, and (c) probably good enough for forseeable future.
+ */
+ switch(family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ default:
+ /* Currently there is no defined error handling in
+ * draft-ietf-tsvwg-sctpsocket-13.txt.
+ * -1 might cause the application to overwrite buffer
+ * or misinterpret data. 0 is more likely to cause
+ * an endless loop.
+ */
+ return 0;
+ }
+}
diff --git a/utils/sctp/lib/bindx.c b/utils/sctp/lib/bindx.c
new file mode 100644
index 000000000..8e0b464af
--- /dev/null
+++ b/utils/sctp/lib/bindx.c
@@ -0,0 +1,78 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * bindx.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
+ *
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 2002 Intel Corporation.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Daisy Chang <daisyc@us.ibm.com>
+ * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */
+#include <netinet/in.h>
+#include <netinet/sctp.h> /* SCTP_SOCKOPT_BINDX_* */
+#include <errno.h>
+
+/* Support the sctp_bindx() interface.
+ *
+ * See Sockets API Extensions for SCTP. Section 8.1.
+ *
+ * Instead of implementing through a socket call in sys_socketcall(),
+ * tunnel the request through setsockopt().
+ */
+int
+sctp_bindx(int fd, struct sockaddr *addrs, int addrcnt, int flags)
+{
+ int setsock_option = 0;
+ void *addrbuf;
+ struct sockaddr *sa_addr;
+ socklen_t addrs_size = 0;
+ int i;
+
+ switch (flags) {
+ case SCTP_BINDX_ADD_ADDR:
+ setsock_option = SCTP_SOCKOPT_BINDX_ADD;
+ break;
+ case SCTP_BINDX_REM_ADDR:
+ setsock_option = SCTP_SOCKOPT_BINDX_REM;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ addrbuf = addrs;
+ for (i = 0; i < addrcnt; i++) {
+ sa_addr = (struct sockaddr *)addrbuf;
+ switch (sa_addr->sa_family) {
+ case AF_INET:
+ addrs_size += sizeof(struct sockaddr_in);
+ addrbuf += sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ addrs_size += sizeof(struct sockaddr_in6);
+ addrbuf += sizeof(struct sockaddr_in6);
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ return setsockopt(fd, SOL_SCTP, setsock_option, addrs, addrs_size);
+}
diff --git a/utils/sctp/lib/connectx.c b/utils/sctp/lib/connectx.c
new file mode 100644
index 000000000..50cf4c8ac
--- /dev/null
+++ b/utils/sctp/lib/connectx.c
@@ -0,0 +1,185 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * connectx.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt.
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
+ *
+ * (C) Copyright IBM Corp. 2001, 2005
+ *
+ * Written or modified by:
+ * Frank Filz <ffilz@us.ibm.com>
+ */
+
+#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */
+#include <netinet/in.h>
+#include <netinet/sctp.h> /* SCTP_SOCKOPT_CONNECTX_* */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+/* Support the sctp_connectx() interface.
+ *
+ * See Sockets API Extensions for SCTP. Section 8.1.
+ *
+ * Instead of implementing through a socket call in sys_socketcall(),
+ * tunnel the request through setsockopt().
+ */
+static int __connectx_addrsize(const struct sockaddr *addrs,
+ const int addrcnt)
+{
+ const void *addrbuf;
+ const struct sockaddr *sa_addr;
+ int addrs_size = 0;
+ int i;
+
+ addrbuf = addrs;
+ for (i = 0; i < addrcnt; i++) {
+ sa_addr = (const struct sockaddr *)addrbuf;
+ switch (sa_addr->sa_family) {
+ case AF_INET:
+ addrs_size += sizeof(struct sockaddr_in);
+ addrbuf += sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ addrs_size += sizeof(struct sockaddr_in6);
+ addrbuf += sizeof(struct sockaddr_in6);
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ return addrs_size;
+}
+
+
+int __sctp_connectx(int fd, struct sockaddr *addrs, int addrcnt)
+{
+ socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt);
+
+ if (addrs_size < 0)
+ return addrs_size;
+
+ return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, addrs,
+ addrs_size);
+}
+
+extern int sctp_connectx_orig (int)
+ __attribute ((alias ("__sctp_connectx")));
+
+
+static int __connectx(int fd, struct sockaddr *addrs, socklen_t addrs_size,
+ sctp_assoc_t *id)
+{
+ int status;
+
+ if (id)
+ *id = 0;
+
+ status = setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX, addrs,
+ addrs_size);
+
+ /* Normalize status and set association id */
+ if (status > 0) {
+ if (id)
+ *id = status;
+ return 0;
+ }
+
+ /* The error is something other then "Option not supported" */
+ if (status < 0 && errno != ENOPROTOOPT)
+ return status;
+
+ /* At this point, if the application wanted the id, we can't
+ * really provide it, so we can return ENOPROTOOPT.
+ */
+ if (id) {
+ errno = ENOPROTOOPT;
+ return -1;
+ }
+
+ /* Finally, try the old API */
+ return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD,
+ addrs, addrs_size);
+}
+
+int sctp_connectx2(int fd, struct sockaddr *addrs, int addrcnt,
+ sctp_assoc_t *id)
+{
+ socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt);
+
+ if (addrs_size < 0)
+ return addrs_size;
+
+ return __connectx(fd, addrs, addrs_size, id);
+}
+
+int sctp_connectx3(int fd, struct sockaddr *addrs, int addrcnt,
+ sctp_assoc_t *id)
+{
+ socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt);
+ int status;
+ struct sctp_getaddrs_old param;
+ socklen_t opt_len = sizeof(param);
+
+ if (addrs_size < 0)
+ return addrs_size;
+
+ /* First try the new socket api
+ * Because the id is returned in the option buffer we have prepend
+ * 32bit to it for the returned association id
+ */
+ param.assoc_id = 0;
+ param.addr_num = addrs_size;
+ param.addrs = addrs;
+ status = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX3,
+ &param, &opt_len);
+ if (status == 0 || errno == EINPROGRESS) {
+ /* Succeeded immediately, or initiated on non-blocking
+ * socket.
+ */
+ if (id)
+ *id = param.assoc_id;
+ }
+
+ if (errno != ENOPROTOOPT) {
+ /* No point in trying the fallbacks*/
+ return status;
+ }
+
+ /* The first incarnation of updated connectx api didn't work for
+ * non-blocking sockets. So if the application wants the association
+ * id and the socket is non-blocking, we can't really do anything.
+ */
+ if (id) {
+ /* Program wants the association-id returned. We can only do
+ * that if the socket is blocking */
+ status = fcntl(fd, F_GETFL);
+ if (status < 0)
+ return status;
+
+ if (status & O_NONBLOCK) {
+ /* Socket is non-blocking. Fail */
+ errno = ENOPROTOOPT;
+ return -1;
+ }
+ }
+
+ return __connectx(fd, addrs, addrs_size, id);
+}
+
+__asm__(".symver __sctp_connectx, sctp_connectx@");
+__asm__(".symver sctp_connectx_orig, sctp_connectx@VERS_1");
+__asm__(".symver sctp_connectx2, sctp_connectx@VERS_2");
+__asm__(".symver sctp_connectx3, sctp_connectx@@VERS_3");
diff --git a/utils/sctp/lib/opt_info.c b/utils/sctp/lib/opt_info.c
new file mode 100644
index 000000000..21c830705
--- /dev/null
+++ b/utils/sctp/lib/opt_info.c
@@ -0,0 +1,62 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * opt_info.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code if to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
+ *
+ * (C) Copyright IBM Corp. 2003
+ * Copyright (c) 2002 Intel Corporation.
+ *
+ * Written or modified by:
+ * Ardelle Fan <ardelle.fan@intel.com>
+ */
+
+#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */
+#include <netinet/sctp.h> /* SCTP_SOCKOPT_BINDX_* */
+#include <errno.h>
+
+/* Support the sctp_opt_info() interface.
+ *
+ * See Sockets API Extensions for SCTP. Section 7.
+ *
+ * Pass sctp option information pass both in to and out of the SCTP stack.
+ * This is a new SCTP API described in the section 7 of the Sockets API
+ * Extensions for SCTP. This is implemented using the getsockopt() interface.
+ */
+int
+sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
+{
+ switch (opt) {
+ case SCTP_RTOINFO:
+ case SCTP_ASSOCINFO:
+ case SCTP_INITMSG:
+ case SCTP_NODELAY:
+ case SCTP_AUTOCLOSE:
+ case SCTP_PRIMARY_ADDR:
+ case SCTP_DISABLE_FRAGMENTS:
+ case SCTP_PEER_ADDR_PARAMS:
+ case SCTP_DEFAULT_SEND_PARAM:
+ case SCTP_EVENTS:
+ case SCTP_I_WANT_MAPPED_V4_ADDR:
+ case SCTP_MAXSEG:
+ case SCTP_STATUS:
+ case SCTP_GET_PEER_ADDR_INFO:
+ case SCTP_AUTH_ACTIVE_KEY:
+ case SCTP_PEER_AUTH_CHUNKS:
+ case SCTP_LOCAL_AUTH_CHUNKS:
+ *(sctp_assoc_t *)arg = id;
+ return getsockopt(sd, IPPROTO_SCTP, opt, arg, size);
+ default:
+ return ENOTSUP;
+ }
+
+} /* sctp_opt_info() */
diff --git a/utils/sctp/lib/peeloff.c b/utils/sctp/lib/peeloff.c
new file mode 100644
index 000000000..a870050c6
--- /dev/null
+++ b/utils/sctp/lib/peeloff.c
@@ -0,0 +1,47 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * peeloff.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
+ *
+ * (C) Copyright IBM Corp. 2001, 2003
+ *
+ * Written or modified by:
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */
+#include <netinet/sctp.h> /* SCTP_SOCKOPT_BINDX_* */
+#include <errno.h>
+
+/* Branch off an association into a seperate socket. This is a new SCTP API
+ * described in the section 8.2 of the Sockets API Extensions for SCTP.
+ * This is implemented using the getsockopt() interface.
+ */
+int
+sctp_peeloff(int fd, sctp_assoc_t associd)
+{
+ sctp_peeloff_arg_t peeloff;
+ socklen_t peeloff_size = sizeof(peeloff);
+ int err;
+
+ peeloff.associd = associd;
+ peeloff.sd = 0;
+ err = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_PEELOFF, &peeloff,
+ &peeloff_size);
+ if (err < 0) {
+ return err;
+ }
+
+ return peeloff.sd;
+
+} /* sctp_peeloff() */
diff --git a/utils/sctp/lib/recvmsg.c b/utils/sctp/lib/recvmsg.c
new file mode 100644
index 000000000..457578837
--- /dev/null
+++ b/utils/sctp/lib/recvmsg.c
@@ -0,0 +1,101 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * sctp_recvmsg.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt>
+ *
+ * Copyright (c) 2003 International Business Machines, Corp.
+ *
+ * Written or modified by:
+ * Ryan Layer <rmlayer@us.ibm.com>
+ *
+ * An implementation may provide a library function (or possibly system
+ * call) to assist the user with the advanced features of SCTP. Note
+ * that in order for the sctp_sndrcvinfo structure to be filled in by
+ * sctp_recvmsg() the caller must enable the sctp_data_io_events with
+ * the SCTP_EVENTS option.
+ *
+ * sctp_recvmsg(). Its syntax is,
+ *
+ * int sctp_recvmsg(int s,
+ * void *msg,
+ * size_t len,
+ * struct sockaddr *from,
+ * socklen_t *fromlen,
+ * struct sctp_sndrcvinfo *sinfo,
+ * int *msg_flags)
+ *
+ *
+ * s - is the socket descriptor
+ * msg - is a message buffer to be filled.
+ * len - is the length of the message buffer.
+ * from - is a pointer to a address to be filled with
+ * the sender of this messages address.
+ * fromlen - is the from length.
+ * sinfo - A pointer to a sctp_sndrcvinfo structure
+ * to be filled upon receipt of the message.
+ * msg_flags - A pointer to a integer to be filled with
+ * any message flags (e.g. MSG_NOTIFICATION).
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */
+#include <netinet/sctp.h>
+
+int sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from,
+ socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo,
+ int *msg_flags)
+{
+ int error;
+ struct iovec iov;
+ struct msghdr inmsg;
+ char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg = NULL;
+
+ memset(&inmsg, 0, sizeof (inmsg));
+
+ iov.iov_base = msg;
+ iov.iov_len = len;
+
+ inmsg.msg_name = from;
+ inmsg.msg_namelen = fromlen ? *fromlen : 0;
+ inmsg.msg_iov = &iov;
+ inmsg.msg_iovlen = 1;
+ inmsg.msg_control = incmsg;
+ inmsg.msg_controllen = sizeof(incmsg);
+
+ error = recvmsg(s, &inmsg, msg_flags ? *msg_flags : 0);
+ if (error < 0)
+ return error;
+
+ if (fromlen)
+ *fromlen = inmsg.msg_namelen;
+ if (msg_flags)
+ *msg_flags = inmsg.msg_flags;
+
+ if (!sinfo)
+ return error;
+
+ for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&inmsg, cmsg)){
+ if ((IPPROTO_SCTP == cmsg->cmsg_level) &&
+ (SCTP_SNDRCV == cmsg->cmsg_type))
+ break;
+ }
+
+ /* Copy sinfo. */
+ if (cmsg)
+ memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo));
+
+ return (error);
+}
diff --git a/utils/sctp/lib/sendmsg.c b/utils/sctp/lib/sendmsg.c
new file mode 100644
index 000000000..90461748e
--- /dev/null
+++ b/utils/sctp/lib/sendmsg.c
@@ -0,0 +1,106 @@
+/* SCTP kernel Implementation: User API extensions.
+ *
+ * sendmsg.c
+ *
+ * Distributed under the terms of the LGPL v2.1 as described in
+ * http://www.gnu.org/copyleft/lesser.txt
+ *
+ * This file is part of the user library that offers support for the
+ * SCTP kernel Implementation. The main purpose of this
+ * code is to provide the SCTP Socket API mappings for user
+ * application to interface with the SCTP in kernel.
+ *
+ * This implementation is based on the Socket API Extensions for SCTP
+ * defined in <draft-ietf-tsvwg-sctpsocket-10.txt>
+ *
+ * Copyright (c) 2003 Intel Corp.
+ *
+ * Written or modified by:
+ * Ardelle Fan <ardelle.fan@intel.com>
+ */
+
+#include <string.h>
+#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */
+#include <netinet/sctp.h>
+
+/* This library function assists the user with the advanced features
+ * of SCTP. This is a new SCTP API described in the section 8.7 of the
+ * Sockets API Extensions for SCTP. This is implemented using the
+ * sendmsg() interface.
+ */
+int
+sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
+ socklen_t tolen, uint32_t ppid, uint32_t flags,
+ uint16_t stream_no, uint32_t timetolive, uint32_t context)
+{
+ struct msghdr outmsg;
+ struct iovec iov;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+
+ outmsg.msg_name = to;
+ outmsg.msg_namelen = tolen;
+ outmsg.msg_iov = &iov;
+ iov.iov_base = (void *)msg;
+ iov.iov_len = len;
+ outmsg.msg_iovlen = 1;
+
+ outmsg.msg_control = outcmsg;
+ outmsg.msg_controllen = sizeof(outcmsg);
+ outmsg.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmsg);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+
+ outmsg.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_flags = flags;
+ sinfo->sinfo_stream = stream_no;
+ sinfo->sinfo_timetolive = timetolive;
+ sinfo->sinfo_context = context;
+
+ return sendmsg(s, &outmsg, 0);
+}
+
+/* This library function assist the user with sending a message without
+ * dealing directly with the CMSG header.
+ */
+int
+sctp_send(int s, const void *msg, size_t len,
+ const struct sctp_sndrcvinfo *sinfo, int flags)
+{
+ struct msghdr outmsg;
+ struct iovec iov;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+
+ outmsg.msg_name = NULL;
+ outmsg.msg_namelen = 0;
+ outmsg.msg_iov = &iov;
+ iov.iov_base = (void *)msg;
+ iov.iov_len = len;
+ outmsg.msg_iovlen = 1;
+ outmsg.msg_controllen = 0;
+
+ if (sinfo) {
+ struct cmsghdr *cmsg;
+
+ outmsg.msg_control = outcmsg;
+ outmsg.msg_controllen = sizeof(outcmsg);
+ outmsg.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&outmsg);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+
+ outmsg.msg_controllen = cmsg->cmsg_len;
+ memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo));
+ }
+
+ return sendmsg(s, &outmsg, flags);
+}
diff --git a/utils/sctp/testlib/Makefile b/utils/sctp/testlib/Makefile
new file mode 100644
index 000000000..e7b5a51a2
--- /dev/null
+++ b/utils/sctp/testlib/Makefile
@@ -0,0 +1,41 @@
+#
+# testcases/network/sctp/testlib Makefile.
+#
+# Copyright (C) 2009, Cisco Systems Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Garrett Cooper, July 2009
+#
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+CPPFLAGS += -DLTP -I$(abs_srcdir)/../include
+
+LDLIBS += -lltp -lsctp
+
+LIB := libsctputil.a
+
+#
+#DEPLIBDIR := ../lib
+
+include $(top_srcdir)/include/mk/lib.mk
+
+#$(MAKE_TARGETS): | libsctp.a
+
+#$()/libsctp.a:
+# $(MAKE) -C $(builddir)/../lib all
diff --git a/utils/sctp/testlib/sctputil.c b/utils/sctp/testlib/sctputil.c
new file mode 100644
index 000000000..c670af679
--- /dev/null
+++ b/utils/sctp/testlib/sctputil.c
@@ -0,0 +1,418 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (C) 1999 Cisco
+ * Copyright (C) 1999-2000 Motorola
+ # Copyright (C) 2001 Nokia
+ * Copyright (C) 2001 La Monte H.P. Yarroll
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Narasimha Budihal <narsi@refcode.org>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Daisy Chang <daisyc@us.ibm.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <malloc.h>
+#include "netinet/sctp.h"
+#include "sctputil.h"
+
+/* This function prints the cmsg data. */
+void
+test_print_cmsg(sctp_cmsg_t type, sctp_cmsg_data_t *data)
+{
+ switch(type) {
+ case SCTP_INIT:
+ printf("INIT\n");
+ printf(" sinit_num_ostreams %d\n",
+ data->init.sinit_num_ostreams);
+ printf(" sinit_max_instreams %d\n",
+ data->init.sinit_max_instreams);
+ printf(" sinit_max_attempts %d\n",
+ data->init.sinit_max_attempts);
+ printf(" sinit_max_init_timeo %d\n",
+ data->init.sinit_max_init_timeo);
+
+ break;
+ case SCTP_SNDRCV:
+ printf("SNDRCV\n");
+ printf(" sinfo_stream %u\n", data->sndrcv.sinfo_stream);
+ printf(" sinfo_ssn %u\n", data->sndrcv.sinfo_ssn);
+ printf(" sinfo_flags 0x%x\n", data->sndrcv.sinfo_flags);
+ printf(" sinfo_ppid %u\n", data->sndrcv.sinfo_ppid);
+ printf(" sinfo_context %x\n", data->sndrcv.sinfo_context);
+ printf(" sinfo_tsn %u\n", data->sndrcv.sinfo_tsn);
+ printf(" sinfo_cumtsn %u\n", data->sndrcv.sinfo_cumtsn);
+ printf(" sinfo_assoc_id %u\n", data->sndrcv.sinfo_assoc_id);
+
+ break;
+
+ default:
+ printf("UNKNOWN CMSG: %d\n", type);
+ break;
+ }
+}
+
+/* This function prints the message. */
+void
+test_print_message(int sk, struct msghdr *msg, size_t msg_len)
+{
+ sctp_cmsg_data_t *data;
+ struct cmsghdr *cmsg;
+ int i;
+ int done = 0;
+ char save;
+ union sctp_notification *sn;
+
+ for (cmsg = CMSG_FIRSTHDR(msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ data = (sctp_cmsg_data_t *)CMSG_DATA(cmsg);
+ test_print_cmsg(cmsg->cmsg_type, data);
+ }
+
+ if (!(MSG_NOTIFICATION & msg->msg_flags)) {
+ int index = 0;
+ /* Make sure that everything is printable and that we
+ * are NUL terminated...
+ */
+ printf("DATA(%d): ", msg_len);
+ while ( msg_len > 0 ) {
+ char *text;
+ int len;
+
+ text = msg->msg_iov[index].iov_base;
+ len = msg->msg_iov[index].iov_len;
+
+ save = text[msg_len-1];
+ if ( len > msg_len ) {
+ text[(len = msg_len) - 1] = '\0';
+ }
+
+ if ( (msg_len -= len) > 0 ) { index++; }
+
+ for (i = 0; i < len - 1; ++i) {
+ if (!isprint(text[i])) text[i] = '.';
+ }
+
+ printf("%s", text);
+ text[msg_len-1] = save;
+
+ if ( (done = !strcmp(text, "exit")) ) { break; }
+ }
+ } else {
+ printf("NOTIFICATION: ");
+ sn = (union sctp_notification *)msg->msg_iov[0].iov_base;
+ switch (sn->sn_header.sn_type) {
+ case SCTP_ASSOC_CHANGE:
+ switch (sn->sn_assoc_change.sac_state) {
+ case SCTP_COMM_UP:
+ printf("ASSOC_CHANGE - COMM_UP");
+ break;
+ case SCTP_COMM_LOST:
+ printf("ASSOC_CHANGE - COMM_LOST");
+ break;
+ case SCTP_RESTART:
+ printf("ASSOC_CHANGE - RESTART");
+ break;
+ case SCTP_SHUTDOWN_COMP:
+ printf("ASSOC_CHANGE - SHUTDOWN_COMP");
+ break;
+ case SCTP_CANT_STR_ASSOC:
+ printf("ASSOC_CHANGE - CANT_STR_ASSOC");
+ break;
+ default:
+ printf("ASSOC_CHANGE - UNEXPECTED(%d)",
+ sn->sn_assoc_change.sac_state);
+ break;
+ }
+ break;
+ default:
+ printf("%d", sn->sn_header.sn_type);
+ break;
+ }
+ }
+
+ printf("\n");
+}
+
+/* Check if a buf/msg_flags matches a notification, its type, and possibly an
+ * additional field in the corresponding notification structure.
+ */
+void
+test_check_buf_notification(void *buf, int datalen, int msg_flags,
+ int expected_datalen, uint16_t expected_sn_type,
+ uint32_t expected_additional)
+{
+ union sctp_notification *sn;
+
+ if (!(msg_flags & MSG_NOTIFICATION))
+ tst_brkm(TBROK, tst_exit, "Got a datamsg, expecting "
+ "notification");
+
+ if (expected_datalen <= 0)
+ return;
+
+ if (datalen != expected_datalen)
+ tst_brkm(TBROK, tst_exit, "Got a notification of unexpected "
+ "length:%d, expected length:%d", datalen,
+ expected_datalen);
+
+ sn = (union sctp_notification *)buf;
+ if (sn->sn_header.sn_type != expected_sn_type)
+ tst_brkm(TBROK, tst_exit, "Unexpected notification:%d"
+ "expected:%d", sn->sn_header.sn_type,
+ expected_sn_type);
+
+ switch(sn->sn_header.sn_type){
+ case SCTP_ASSOC_CHANGE:
+ if (sn->sn_assoc_change.sac_state != expected_additional)
+ tst_brkm(TBROK, tst_exit, "Unexpected sac_state:%d "
+ "expected:%d", sn->sn_assoc_change.sac_state,
+ expected_additional);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Check if a message matches a notification, its type, and possibly an
+ * additional field in the corresponding notification structure.
+ */
+void
+test_check_msg_notification(struct msghdr *msg, int datalen,
+ int expected_datalen, uint16_t expected_sn_type,
+ uint32_t expected_additional)
+{
+ test_check_buf_notification(msg->msg_iov[0].iov_base, datalen,
+ msg->msg_flags, expected_datalen,
+ expected_sn_type, expected_additional);
+}
+
+/* Check if a buf/msg_flags/sinfo corresponds to data, its length, msg_flags,
+ * stream and ppid.
+ */
+void
+test_check_buf_data(void *buf, int datalen, int msg_flags,
+ struct sctp_sndrcvinfo *sinfo, int expected_datalen,
+ int expected_msg_flags, uint16_t expected_stream,
+ uint32_t expected_ppid)
+{
+ if (msg_flags & MSG_NOTIFICATION)
+ tst_brkm(TBROK, tst_exit, "Got a notification, expecting a"
+ "datamsg");
+
+ if (expected_datalen <= 0)
+ return;
+
+ if (datalen != expected_datalen)
+ tst_brkm(TBROK, tst_exit, "Got a datamsg of unexpected "
+ "length:%d, expected length:%d", datalen,
+ expected_datalen);
+
+ if ((msg_flags & ~0x80000000) != expected_msg_flags)
+ tst_brkm(TBROK, tst_exit, "Unexpected msg_flags:0x%x "
+ "expecting:0x%x", msg_flags, expected_msg_flags);
+
+ if ((0 == expected_stream) && (0 == expected_ppid))
+ return;
+
+ if (!sinfo)
+ tst_brkm(TBROK, tst_exit, "Null sinfo, but expected "
+ "stream:%d expected ppid:%d", expected_stream,
+ expected_ppid);
+
+ if (sinfo->sinfo_stream != expected_stream)
+ tst_brkm(TBROK, tst_exit, "stream mismatch: expected:%x "
+ "got:%x", expected_stream, sinfo->sinfo_stream);
+ if (sinfo->sinfo_ppid != expected_ppid)
+ tst_brkm(TBROK, tst_exit, "ppid mismatch: expected:%x "
+ "got:%x\n", expected_ppid, sinfo->sinfo_ppid);
+}
+
+/* Check if a message corresponds to data, its length, msg_flags, stream and
+ * ppid.
+ */
+void
+test_check_msg_data(struct msghdr *msg, int datalen, int expected_datalen,
+ int expected_msg_flags, uint16_t expected_stream,
+ uint32_t expected_ppid)
+{
+ struct cmsghdr *cmsg = NULL;
+ struct sctp_sndrcvinfo *sinfo = NULL;
+
+ /* Receive auxiliary data in msgh. */
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msg, cmsg)){
+ if (IPPROTO_SCTP == cmsg->cmsg_level &&
+ SCTP_SNDRCV == cmsg->cmsg_type)
+ break;
+ } /* for( all cmsgs) */
+
+ if ((!cmsg) ||
+ (cmsg->cmsg_len < CMSG_LEN(sizeof(struct sctp_sndrcvinfo))))
+ sinfo = NULL;
+ else
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+
+ test_check_buf_data(msg->msg_iov[0].iov_base, datalen, msg->msg_flags,
+ sinfo, expected_datalen, expected_msg_flags,
+ expected_stream, expected_ppid);
+
+}
+
+
+/* Allocate a buffer of requested len and fill in with data. */
+void *
+test_build_msg(int len)
+{
+ int i = len - 1;
+ int n;
+ unsigned char msg[] =
+ "012345678901234567890123456789012345678901234567890";
+ char *msg_buf, *p;
+
+ msg_buf = (char *)malloc(len);
+ if (!msg_buf)
+ tst_brkm(TBROK, tst_exit, "malloc failed");
+
+ p = msg_buf;
+
+ do {
+ n = ((i > 50)?50:i);
+ memcpy(p, msg, ((i > 50)?50:i));
+ p += n;
+ i -= n;
+ } while (i > 0);
+
+ msg_buf[len-1] = '\0';
+
+ return(msg_buf);
+}
+
+/* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+void test_enable_assoc_change(int fd)
+{
+ struct sctp_event_subscribe subscribe;
+
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ test_setsockopt(fd, SCTP_EVENTS, (char *)&subscribe,
+ sizeof(subscribe));
+}
+
+static int cmp_addr(sockaddr_storage_t *addr1, sockaddr_storage_t *addr2)
+{
+ if (addr1->sa.sa_family != addr2->sa.sa_family)
+ return 0;
+ switch (addr1->sa.sa_family) {
+ case AF_INET6:
+ if (addr1->v6.sin6_port != addr2->v6.sin6_port)
+ return -1;
+ return memcmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr,
+ sizeof(addr1->v6.sin6_addr));
+ case AF_INET:
+ if (addr1->v4.sin_port != addr2->v4.sin_port)
+ return 0;
+ return memcmp(&addr1->v4.sin_addr, &addr2->v4.sin_addr,
+ sizeof(addr1->v4.sin_addr));
+ default:
+ tst_brkm(TBROK, tst_exit, "invalid address type %d",
+ addr1->sa.sa_family);
+ return -1;
+ }
+}
+
+/* Test peer addresses for association. */
+int test_peer_addr(int sk, sctp_assoc_t asoc, sockaddr_storage_t *peers, int count)
+{
+ struct sockaddr *addrs;
+ int error, i, j;
+ struct sockaddr *sa_addr;
+ socklen_t addrs_size = 0;
+ void *addrbuf;
+ char *found = (char *) malloc(count);
+ memset(found, 0, count);
+
+ error = sctp_getpaddrs(sk, asoc, &addrs);
+ if (-1 == error) {
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno));
+ return error;
+ }
+ if (error != count) {
+ sctp_freepaddrs(addrs);
+ tst_brkm(TBROK, tst_exit, "peer count %d mismatch, expected %d",
+ error, count);
+ }
+ addrbuf = addrs;
+ for (i = 0; i < count; i++) {
+ sa_addr = (struct sockaddr *)addrbuf;
+ switch (sa_addr->sa_family) {
+ case AF_INET:
+ addrs_size += sizeof(struct sockaddr_in);
+ addrbuf += sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ addrs_size += sizeof(struct sockaddr_in6);
+ addrbuf += sizeof(struct sockaddr_in6);
+ break;
+ default:
+ errno = EINVAL;
+ sctp_freepaddrs(addrs);
+ tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno));
+ return -1;
+ }
+ for (j = 0; j < count; j++) {
+ if (cmp_addr((sockaddr_storage_t *)sa_addr,
+ &peers[j]) == 0) {
+ found[j] = 1;
+ }
+ }
+ }
+ for (j = 0; j < count; j++) {
+ if (found[j] == 0) {
+ tst_brkm(TBROK, tst_exit, "peer address %d not found", j);
+ }
+ }
+ sctp_freepaddrs(addrs);
+ return 0;
+}
diff --git a/utils/sctp/testlib/sctputil.h b/utils/sctp/testlib/sctputil.h
new file mode 100644
index 000000000..347c91bde
--- /dev/null
+++ b/utils/sctp/testlib/sctputil.h
@@ -0,0 +1,324 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ * Copyright (c) 2001 La Monte H.P. Yarroll
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * La Monte H.P. Yarroll <piggy@acm.org>
+ * Karl Knutson <karl@athena.chicago.il.us>
+ * Randall Stewart <randall@stewart.chicago.il.us>
+ * Ken Morneau <kmorneau@cisco.com>
+ * Qiaobing Xie <qxie1@motorola.com>
+ * Daisy Chang <daisyc@us.ibm.com>
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <samudrala@us.ibm.com>
+ * Hui Huang <hui.huang@nokia.com>
+ */
+
+#ifndef __sctputil_h__
+#define __sctputil_h__
+
+#ifdef LTP
+#include <test.h>
+#include <usctest.h>
+#endif
+
+#include <string.h>
+
+typedef union {
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ struct sockaddr sa;
+} sockaddr_storage_t;
+
+
+#define REALLY_BIG 65536
+
+/* Literal defines. */
+#ifdef PROT_SOCK
+#define SCTP_TESTPORT_1 PROT_SOCK
+#else
+#define SCTP_TESTPORT_1 1024
+#endif
+#define SCTP_TESTPORT_2 (SCTP_TESTPORT_1+1)
+
+#define SCTP_IP_BCAST htonl(0xffffffff)
+#define SCTP_IP_LOOPBACK htonl(0x7f000001)
+
+/* These are stolen from <netinet/in.h>. */
+#define SCTP_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#define SCTP_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+
+/* Display an IPv4 address in readable format. */
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+
+/* Display an IPv6 address in readable format. */
+#define NIP6(addr) \
+ ntohs((addr).s6_addr16[0]), \
+ ntohs((addr).s6_addr16[1]), \
+ ntohs((addr).s6_addr16[2]), \
+ ntohs((addr).s6_addr16[3]), \
+ ntohs((addr).s6_addr16[4]), \
+ ntohs((addr).s6_addr16[5]), \
+ ntohs((addr).s6_addr16[6]), \
+ ntohs((addr).s6_addr16[7])
+
+#define DUMP_CORE { \
+ char *diediedie = 0; \
+ printf("DUMP_CORE %s: %d\n", __FILE__, __LINE__);\
+ *diediedie = 0; \
+}
+
+#ifndef LTP
+enum {
+ TPASS,
+ TINFO,
+};
+
+extern char *TCID;
+extern int TST_TOTAL;
+extern int TST_CNT;
+
+#define tst_brkm(a1, a2, whatever...) \
+ { \
+ printf("%s %2d BROK : ", TCID, ++TST_CNT); \
+ printf(whatever); \
+ printf("\n"); \
+ DUMP_CORE \
+ }
+#define tst_resm(a1, whatever...) \
+ { \
+ printf("%s %2d %s : ", TCID, \
+ (a1 == TPASS)?++TST_CNT:0, \
+ (a1 == TPASS)?"PASS":"INFO"); \
+ printf(whatever); \
+ printf("\n"); \
+ }
+#endif
+
+static inline int test_socket(int domain, int type, int protocol)
+{
+ int sk = socket(domain, type, protocol);
+ if (-1 == sk)
+ tst_brkm(TBROK, tst_exit, "socket: %s", strerror(errno));
+ return sk;
+}
+
+static inline int test_bind(int sk, struct sockaddr *addr, socklen_t addrlen)
+{
+ int error = bind(sk, addr, addrlen);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "bind: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_bindx_add(int sk, struct sockaddr *addr, int count)
+{
+ int error = sctp_bindx(sk, addr, count, SCTP_BINDX_ADD_ADDR);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "bindx (add): %s", strerror(errno));
+ return error;
+}
+
+static inline int test_listen(int sk, int backlog)
+{
+ int error = listen(sk, backlog);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "listen: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_connect(int sk, struct sockaddr *addr, socklen_t addrlen)
+{
+ int error = connect(sk, addr, addrlen);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "connect: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_connectx(int sk, struct sockaddr *addr, int count)
+{
+ int error = sctp_connectx(sk, addr, count, NULL);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "connectx: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_accept(int sk, struct sockaddr *addr, socklen_t *addrlen)
+{
+ int error = accept(sk, addr, addrlen);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "accept: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_send(int sk, const void *msg, size_t len, int flags)
+{
+ int error = send(sk, msg, len, flags);
+ if (len != error)
+ tst_brkm(TBROK, tst_exit, "send: error:%d errno:%d",
+ error, errno);
+ return error;
+}
+
+static inline int test_sendto(int sk, const void *msg, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen)
+{
+ int error = sendto(sk, msg, len, flags, to, tolen);
+ if (len != error)
+ tst_brkm(TBROK, tst_exit, "sendto: error:%d errno:%d",
+ error, errno);
+ return error;
+}
+
+static inline int test_sendmsg(int sk, const struct msghdr *msg, int flags,
+ int msglen)
+{
+ int error = sendmsg(sk, msg, flags);
+ if (msglen != error)
+ tst_brkm(TBROK, tst_exit, "sendmsg: error:%d errno:%d",
+ error, errno);
+ return error;
+}
+
+static inline int test_recv(int sk, void *buf, size_t len, int flags)
+{
+ int error = recv(sk, buf, len, flags);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "recv: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_recvmsg(int sk, struct msghdr *msg, int flags)
+{
+ int error = recvmsg(sk, msg, flags);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "recvmsg: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_shutdown(int sk, int how)
+{
+ int error = shutdown(sk, how);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "shutdown: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_getsockopt(int sk, int optname, void *optval,
+ socklen_t *optlen)
+{
+ int error = getsockopt(sk, SOL_SCTP, optname, optval, optlen);
+ if (error)
+ tst_brkm(TBROK, tst_exit, "getsockopt(%d): %s", optname,
+ strerror(errno));
+ return error;
+}
+
+static inline int test_setsockopt(int sk, int optname, const void *optval,
+ socklen_t optlen)
+{
+ int error = setsockopt(sk, SOL_SCTP, optname, optval, optlen);
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(%d): %s", optname,
+ strerror(errno));
+ return error;
+}
+
+static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
+{
+ int error = sctp_peeloff(sk, assoc_id);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "sctp_peeloff: %s", strerror(errno));
+ return error;
+}
+
+static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
+ struct sockaddr *to, socklen_t tolen,
+ uint32_t ppid, uint32_t flags,
+ uint16_t stream_no, uint32_t timetolive,
+ uint32_t context)
+{
+ int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
+ timetolive, context);
+ if (len != error)
+ tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
+ error, errno);
+ return error;
+}
+
+static inline int test_sctp_send(int s, const void *msg, size_t len,
+ const struct sctp_sndrcvinfo *sinfo,
+ int flags)
+{
+ int error = sctp_send(s, msg, len, sinfo, flags);
+ if (len != error)
+ tst_brkm(TBROK, tst_exit, "sctp_send: error:%d errno:%d",
+ error, errno);
+ return error;
+}
+
+static inline int test_sctp_recvmsg(int sk, void *msg, size_t len,
+ struct sockaddr *from, socklen_t *fromlen,
+ struct sctp_sndrcvinfo *sinfo,
+ int *msg_flags)
+{
+ int error = sctp_recvmsg(sk, msg, len, from, fromlen, sinfo, msg_flags);
+ if (-1 == error)
+ tst_brkm(TBROK, tst_exit, "sctp_recvmsg: %s", strerror(errno));
+ return error;
+}
+
+static inline void *test_malloc(size_t size)
+{
+ void *buf = malloc(size);
+ if (NULL == buf)
+ tst_brkm(TBROK, tst_exit, "malloc failed");
+ return buf;
+}
+
+void test_check_msg_notification(struct msghdr *, int, int, uint16_t, uint32_t);
+void test_check_buf_notification(void *, int, int, int, uint16_t, uint32_t);
+void test_check_msg_data(struct msghdr *, int, int, int, uint16_t, uint32_t);
+void test_check_buf_data(void *, int, int, struct sctp_sndrcvinfo *, int, int,
+ uint16_t, uint32_t);
+void *test_build_msg(int);
+void test_enable_assoc_change(int);
+void test_print_message(int sk, struct msghdr *msg, size_t msg_len);
+int test_peer_addr(int sk, sctp_assoc_t asoc, sockaddr_storage_t *peers, int count);
+
+#endif /* __sctputil_h__ */