diff options
Diffstat (limited to 'utils/sctp')
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, + ¶m, &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__ */ |