Squashed 'third_party/lksctp-tools/' content from commit 200eca7f1

Change-Id: I8f7575513f114b205178cac5c6b3706f3d725cb5
git-subtree-dir: third_party/lksctp-tools
git-subtree-split: 200eca7f1419b1ae53958b51e8551f7e7f6cd467
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..c5b8fa6
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,8 @@
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+
+SUBDIRS = apps include lib testlib withsctp
+
+if BUILD_TESTS
+SUBDIRS += func_tests
+endif
diff --git a/src/apps/.gitignore b/src/apps/.gitignore
new file mode 100644
index 0000000..a7ba019
--- /dev/null
+++ b/src/apps/.gitignore
@@ -0,0 +1,10 @@
+bindx_test
+myftp
+nagle_rcv
+nagle_snd
+peel_client
+peel_server
+sctp_darn
+sctp_status
+sctp_test
+sctp_xconnect
diff --git a/src/apps/Makefile.am b/src/apps/Makefile.am
new file mode 100644
index 0000000..7e32306
--- /dev/null
+++ b/src/apps/Makefile.am
@@ -0,0 +1,42 @@
+# Include these two in all the Makefile.am's!!!
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+include $(top_srcdir)/Makefile.dirs
+
+# General compilation flags
+AM_CPPFLAGS = -I. -I$(top_builddir)/src/include -I$(top_srcdir)/src/testlib \
+              -g -O2 -fno-strict-aliasing -Wall -Wstrict-prototypes \
+              -Wimplicit-function-declaration
+
+AM_LDFLAGS = 
+
+LDADD = $(top_builddir)/src/testlib/libsctputil.la \
+	$(top_builddir)/src/lib/libsctp.la
+
+# programs to be installed with the distriubution
+bin_PROGRAMS = sctp_darn sctp_test sctp_status
+
+# Test programs and libraries to build
+noinst_PROGRAMS = bindx_test nagle_snd nagle_rcv myftp sctp_xconnect \
+	peel_server peel_client sctp_test sctp_status
+
+$(top_builddir)/src/lib/libsctp.la:
+	$(MAKE) -C $(top_builddir)/src/lib libsctp.la
+
+$(top_builddir)/src/testlib/libsctputil.la:
+	$(MAKE) -C $(top_builddir)/src/testlib libsctputil.la
+
+# Specifying the sources
+bindx_test_SOURCES = bindx_test.c
+sctp_darn_SOURCES = sctp_darn.c sctp_darn.h
+sctp_test_SOURCES = sctp_test.c
+sctp_status_SOURCES = sctp_status.c
+nagle_rcv_SOURCES = nagle_rcv.c 
+nagle_snd_SOURCES = nagle_snd.c 
+myftp_SOURCES = myftp.c
+sctp_xconnect_SOURCES = sctp_xconnect.c
+peel_server_SOURCES = peel_server.c
+peel_client_SOURCES = peel_client.c
+
+# Tutorials
+pkgdoc_DATA = sctp_darn.c sctp_darn.h sctp_test.c sctp_status.c
diff --git a/src/apps/bindx_test.c b/src/apps/bindx_test.c
new file mode 100644
index 0000000..ff3de86
--- /dev/null
+++ b/src/apps/bindx_test.c
@@ -0,0 +1,134 @@
+  /* -*-c-*-
+  **
+  ** sctp-tools: Another bindx test.
+  ** 
+  ** $Id: bindx_test.c,v 1.1.1.1 2002/08/06 22:31:05 inaky Exp $
+  **
+  ** Distributed under the terms of the GPL v2.0 as described in
+  ** $top_srcdir/COPYING. 
+  **
+  ** (C) Copyright IBM Corp. 2003
+  ** (C) 2002 Intel Corporation
+  **    Iñaky Pérez-González <inaky.perez-gonzalez@intel.com>:
+  **    Sridhar Samudrala <sri@us.ibm.com>
+  */
+
+#define _GNU_SOURCE /* GNU extensions */
+
+#include <stdlib.h>     /* malloc() */
+#include <arpa/inet.h>  /* inet_pton() */
+#include <errno.h>
+#include <sys/socket.h> /* socket() */
+#include <stdio.h>      /* fprintf */
+#include <netinet/in.h> /* sockaddr_in */
+#include <unistd.h>     /* close() */
+#include <string.h>     /* strchr() */
+#include <netinet/sctp.h>   /* bindx() */
+
+  /* Global stuff */
+
+#ifndef IPPROTO_SCTP 
+#define IPPROTO_SCTP 132
+#endif
+
+  /*! Main function: initialize, setup, run the main loop
+  **
+  **
+  */
+
+int main (int argc, char **argv)
+{
+	void *addr_buf, *buf_ptr;
+	void *addr_buf_size = 0;
+	size_t addrs, cnt;
+	int sd, result, port;
+	int domain = PF_INET6;
+
+	if (argc < 3) {
+		fprintf(stderr,
+			"Usage: bindx_test PORT IPADDR1 [IPADDR2 [...]]\n");
+		return 1;
+	}
+  
+	port = atoi(argv[1]);
+	printf("bindx_test: INFO: Port is %d\n", port);
+
+	/* Allocate the maximum space for the specified no. of  addresses.
+	 * Assume all of them are v6 addresses.
+	 */
+	addr_buf = malloc((argc -2) * sizeof(struct sockaddr_in6));
+	if (addr_buf == NULL) {
+		perror("bindx_test: ERROR: addr buf allocation failed");
+		return 1;
+	}
+  
+	/* Get the addresses from the cmd line */
+	addrs = 0;  /* healthy address iterator [and total counter] */
+	cnt = 2;    /* argument iterator */
+	buf_ptr = addr_buf;
+	while (cnt < argc) {
+		printf("bindx_test: INFO: Arg %zu: %s", cnt, argv[cnt]);
+		fflush(stderr);
+		if (strchr(argv[cnt], ':')) {
+			struct sockaddr_in6 *sa6; 
+
+			sa6 = (struct sockaddr_in6 *)buf_ptr;
+			printf(" IPv6 address number %zu", addrs);
+			sa6->sin6_family = AF_INET6;
+			sa6->sin6_port = port;
+			if (inet_pton(AF_INET6, argv[cnt], &sa6->sin6_addr)) {
+				addrs++;
+				addr_buf_size += sizeof(struct sockaddr_in6);
+				buf_ptr += sizeof(struct sockaddr_in6);
+			} else
+				printf(" error");
+		} else if (strchr(argv[cnt], '.')) {
+			struct sockaddr_in *sa; 
+
+			domain = PF_INET;
+			sa = (struct sockaddr_in *)buf_ptr;
+			printf (" IPv4 address number %zu", addrs);
+			sa->sin_family = AF_INET;
+			sa->sin_port = port;
+			if (inet_pton (AF_INET, argv[cnt], &sa->sin_addr)) {
+				addrs++;
+				addr_buf_size += sizeof(struct sockaddr_in);
+				buf_ptr += sizeof(struct sockaddr_in);
+			} else
+				printf (" error");
+		} else
+			printf (" Unknown");
+		putchar ('\n');
+		cnt++;
+	}
+
+	printf ("bindx_test: INFO: Got %zu addrs\n", addrs);
+  
+	/* Create the socket */
+	sd = socket(domain, SOCK_SEQPACKET, IPPROTO_SCTP);
+	if (sd == -1) {
+		perror("bindx_test: ERROR: Cannot open socket");
+		return 1;
+	}
+
+	/* add all */
+	result = sctp_bindx(sd, (struct sockaddr *)addr_buf, addrs,
+			    SCTP_BINDX_ADD_ADDR);
+	if (result == -1)
+		perror("bindx_test: ERROR: bindx addition error");
+	else {
+		printf("bindx_test: OK: bindx address addition\n");
+
+		/* remove all but the last */
+		result = sctp_bindx(sd, (struct sockaddr *)addr_buf, addrs-1,
+				     SCTP_BINDX_REM_ADDR);
+		if (result == -1)
+			perror("bindx_test: ERROR: bindx address removal");
+		else
+			printf("bindx_test: OK: bindx address removal\n");
+	}
+  
+	close(sd);
+	free(addr_buf);
+	return result;
+}
diff --git a/src/apps/myftp.c b/src/apps/myftp.c
new file mode 100644
index 0000000..64fa3f2
--- /dev/null
+++ b/src/apps/myftp.c
@@ -0,0 +1,413 @@
+/* myftp - simple file transfer over sctp testing tool. 
+ * Copyright (c) 2002 Intel Corp.
+ * 
+ * This file is part of the LKSCTP kernel Implementation.  This
+ * is a submission by Xingang Guo from the Intel Corporation while 
+ * participating on the LKSCTP project.  
+ * 
+ * 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 <sctp-developers-list@cig.mot.com>
+ * 
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
+ *
+ * Written or modified by: 
+ *    Xingang Guo           <xingang.guo@intel.com>
+ *    Jon Grimm             <jgrimm@us.ibm.com> 
+ * 
+ * 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 <stdlib.h>
+#include <string.h>
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <errno.h>
+#include <netinet/sctp.h>
+
+#define BUFSIZE 1024
+static char buffer[BUFSIZE];
+#define DUMP_CORE {  char *diediedie = 0; *diediedie = 0; }
+
+typedef enum { COMMAND_NONE, COMMAND_RECV, COMMAND_SEND } command_t;
+
+/* These are the global options.  */
+#define MAX_NUM_HOST	5
+static char *local_host[MAX_NUM_HOST];
+static int num_local_host = 0;
+static int local_port = 4444;
+
+static int buffer_size = BUFSIZE;
+static char *remote_host = NULL;
+static int remote_port = 4444;
+static command_t command = COMMAND_NONE;
+static char *filename = NULL;
+static int interactive = 0;
+static unsigned long delay = 0;	     
+static int verbose = 0;
+
+static void
+usage(char *argv0)
+{
+	fprintf(stderr, "Usage: %s [options]\n",argv0);
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "\t--local, -H <hostname>     Specify local interface\n");
+	fprintf(stderr, "\t--local-port, -P <port>    Specify local port (default 4444)\n");
+	fprintf(stderr, "\t--remote, -h <hostname>    Specify interface on remote host\n");
+	fprintf(stderr, "\t--remote-port, -p <port>   Specify remote port (default 4444)\n");
+	fprintf(stderr, "\t--listen, -l               Work in receiving mode\n");
+	fprintf(stderr, "\t--send, -s                 Work in sending mode\n");
+	fprintf(stderr, "\t--file, -f <filename>      File to read or write,\n");
+	fprintf(stderr, "\t--buffer, -b <size>        Buffer size. (default 1024 bytes)\n");
+	fprintf(stderr, "\t                           by default use standard input/output.\n");
+	fprintf(stderr, "\t--quick, -q                Send packets continueously,\n");
+	fprintf(stderr, "\t                           do not wait for <ENTER> key. Default wait.\n");
+	fprintf(stderr, "\t--delay, -d <usec>         Delay between consecutive sends (see --quick)\n");
+	fprintf(stderr, "\t--verbose, -v              In verbose mode, display the progress.\n");
+	fprintf(stderr, "\n\t--help,                    Print this message.\n\n");
+} /* usage() */
+
+static int parse_arguments(int argc, char *argv[])
+{
+	int option_index = 0;
+	int c;
+	static struct option long_options[] = {
+		{"local",	1, 0, 1},
+		{"local-port",	1, 0, 2},
+		{"remote",	1, 0, 3},
+		{"remote-port",	1, 0, 4},
+		{"file",	1, 0, 5},
+		{"delay",	1, 0, 6},
+		{"buffer",	1, 0, 7},
+		{"listen",	0, 0, 10},
+		{"send",	0, 0, 11},
+		{"quick",	0, 0, 12},
+		{"verbose",	0, 0, 13},
+		{"help",	0, 0, 99},
+		{0,		0, 0, 0}
+	};
+
+	/* Parse the arguments.  */
+	while (1) {
+		c = getopt_long(argc, argv, "H:P:h:p:f:d:b:qlsv",long_options,&option_index);
+		if (c == -1) break;
+
+		switch (c) {
+		case 0:
+			printf ("option %s", long_options[option_index].name);
+			if (optarg) printf (" with arg %s", optarg);
+			printf ("\n");
+			break;
+		case 1:		/* local host */
+		case 'H':
+			local_host[num_local_host++] = optarg;
+			break;
+		case 2:		/* local port */
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case 3:		/* remote host */
+		case 'h':
+			remote_host = optarg;
+			break;
+		case 4:		/* remote port */
+		case 'p':
+			remote_port = atoi(optarg);
+			break;
+		case 5:
+		case 'f':
+			filename = optarg;
+			break;
+
+		case 6:
+		case 'd':
+			delay = strtoul(optarg,NULL,10);
+			printf("delay is %ld usec\n",delay);
+			break;
+
+		case 7:
+		case 'b':
+			buffer_size = atoi(optarg);
+			if ( buffer_size > BUFSIZE ) {
+				buffer_size = BUFSIZE;
+				fprintf(stderr,"Warning, buffer size too large, set to %d\n",buffer_size);
+			}
+			break;
+
+		case 12:
+		case 'q':	interactive = 0; break;
+
+		case 13:
+		case 'v':	verbose = 1; break;
+			/* COMMANDS */
+		case 10:	/* listen */
+		case 'l':
+			if (command) {
+				fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]);
+				return 1;
+			}
+			else command = COMMAND_RECV;
+			break;
+
+		case 11:	/* send */
+		case 's':
+			if (command) {
+				fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]);
+				return 2;
+			} else command = COMMAND_SEND;
+			break;
+
+		case '?':
+		case 99:
+			usage(argv[0]);
+			return 3;
+			break;
+
+		default:
+			printf ("%s: unrecognized option 0%c\n", argv[0], c);
+			usage(argv[0]);
+			return 4;
+		}
+	}
+
+	if (optind < argc) {
+		fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]);
+		while (optind < argc) fprintf(stderr, "%s ", argv[optind++]);
+		fprintf(stderr, "\n");
+		usage(argv[0]);
+		return 5;
+	}
+
+
+	if (0 == num_local_host) {
+		fprintf(stderr, "%s: You MUST provide a local host.\n", argv[0]);
+		usage(argv[0]);
+		return 6;
+	}
+
+	if ( filename == NULL && command == COMMAND_SEND)
+		fprintf(stderr,"%s: Use standard input to send\n",argv[0]);
+
+	if ( filename == NULL && command == COMMAND_RECV )
+		fprintf(stderr,"%s: Use standard output to write\n",argv[0]);
+
+	return 0;
+} /* parse_arguments() */
+
+static void
+emsg(char *prog,char *s)
+{
+	if ( prog != NULL ) fprintf(stderr,"%s: ",prog);
+	perror(s);
+	fflush(stdout);
+	//DUMP_CORE;
+
+	exit(-1);
+}
+
+static int build_endpoint(char *argv0)
+{
+	int retval,i;
+
+	/* Create the local endpoint.  */
+	if ( (retval = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0 ) {
+		emsg(argv0,"socket");
+		exit(retval);
+	}
+
+	for ( i = 0;i < num_local_host;i++ ) {
+		struct hostent *hst;
+		struct sockaddr_in laddr;
+
+		memset(&laddr, 0, sizeof(laddr));
+		/* Get the transport address for the local host name.  */
+		fprintf(stderr,"Hostname %d is %s\n",i+1,local_host[i]);
+		if ( (hst = gethostbyname(local_host[i])) == NULL ) {
+			fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host[i]);
+			exit(1);
+		}
+		memcpy(&laddr.sin_addr, hst->h_addr_list[0],sizeof(laddr.sin_addr));
+		laddr.sin_port = htons(local_port);
+		laddr.sin_family = AF_INET;
+
+		/* Bind this socket to the test port.  */
+		if ( bind(retval, (struct sockaddr *)&laddr, sizeof(laddr)) ) {
+			emsg(argv0,"bind");
+			exit(-1);
+		}
+	}
+
+	fprintf(stderr,"Endpoint built.\n");
+
+	return retval;
+} /* build_endpoint() */
+
+/* Convenience structure to determine space needed for cmsg. */
+typedef union {
+	struct sctp_initmsg init;
+	struct sctp_sndrcvinfo sndrcvinfo;
+} _sctp_cmsg_data_t;
+
+
+/* Listen on the socket, printing out anything that arrives.  */
+static void
+command_recv(char *argv0, int sk)
+{
+	struct msghdr inmessage;
+	char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+	struct iovec iov;
+	int ret;
+	int fd;
+	int ct;
+
+	if (listen(sk, 1) == -1)
+		emsg(argv0, "listen");
+	/* Initialize inmessage with enough space for DATA... */
+	memset(&inmessage, 0, sizeof(inmessage));
+	iov.iov_base = buffer;
+	iov.iov_len = buffer_size;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+	/* creat a file */
+	if ( filename == NULL ) fd = 1;
+	else if ( (fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE)) == -1 )
+		emsg(argv0,"open");
+
+	fprintf(stderr,"%s Receiving...\n", argv0);
+	/* Get the messages sent */
+	ct = 0;
+	while ( (ret = recvmsg(sk, &inmessage, MSG_WAITALL)) >= 0 ) {
+		if ( verbose )
+			fprintf(stderr,"%s-%d received %d bytes\n",
+				argv0, ++ct, ret);
+		if ( !(inmessage.msg_flags & MSG_NOTIFICATION) ) {
+			//printf("%s write %d bytes\n",argv0,ret);
+			if ( write(fd,buffer,ret) != ret ) emsg(argv0,"write");
+		} else {
+			union sctp_notification *sn;
+			sn = (union sctp_notification *)iov.iov_base;
+			if ((sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) &&
+			    (sn->sn_assoc_change.sac_state 
+			     == SCTP_SHUTDOWN_COMP))
+				break;
+		}
+			
+	}
+
+	if ( ret < 0 ) emsg(argv0,"recvmsg");
+
+	close(fd);
+	close(sk);
+} /* command_recv() */
+
+/* Read lines from stdin and send them to the socket.  */
+static void
+command_send(char *argv0, int sk)
+{
+	struct msghdr outmsg;
+	struct iovec iov;
+	struct hostent *hst;
+	struct sockaddr_in remote_addr;
+	int fd;
+	int msglen;
+	int ct;
+
+	/* Set up the destination.  */
+	hst = gethostbyname(remote_host);
+	if (hst == NULL || hst->h_length < 1) {
+		fprintf(stderr, "%s: bad hostname: %s\n", argv0, remote_host);
+		exit(1);
+	}
+	memcpy(&remote_addr.sin_addr, hst->h_addr_list[0], sizeof(remote_addr.sin_addr));
+	remote_addr.sin_port = htons(remote_port);
+	remote_addr.sin_family = AF_INET;
+
+	/* Initialize the message struct we use to pass messages to
+	 * the remote socket.
+	 */
+	iov.iov_base = buffer;
+	iov.iov_len = buffer_size;
+	outmsg.msg_iov = &iov;
+	outmsg.msg_iovlen = 1;
+	outmsg.msg_control = NULL;
+	outmsg.msg_controllen = 0;
+	outmsg.msg_name = &remote_addr;
+	outmsg.msg_namelen = sizeof(remote_addr);
+
+	/* open the file */
+	if ( filename == NULL ) fd = 0;
+	else if ( (fd = open(filename,O_RDONLY)) == -1 ) emsg(argv0,"open");
+
+	fprintf(stderr,"%s ready to send...\n", argv0);
+	ct = 0;
+	while ( (msglen = read(fd,buffer,buffer_size)) > 0 ) {
+		/* Send to our neighbor.  */
+		iov.iov_len = msglen;
+		if ( sendmsg(sk, &outmsg, 0) != msglen ) emsg(argv0,"sendmsg");
+		if ( verbose ) fprintf(stderr,"%s-%d send %d bytes\n",argv0,++ct,msglen);
+		if ( interactive && fd != 1 ) 
+			getchar();
+			// no flow control? no problem, make it slow
+		else if ( delay > 0 ) 
+			usleep(delay);
+	}
+
+	close(fd);
+	close(sk);
+} /* command_send() */
+
+int main(int argc, char *argv[])
+{
+	int ret;
+
+	if (( ret = parse_arguments(argc, argv) )) return ret;
+
+	switch(command) {
+	case COMMAND_NONE:
+		fprintf(stderr, "%s: Please specify a command.\n", argv[0]);
+		break;
+	case COMMAND_RECV:
+		command_recv(argv[0],build_endpoint(argv[0]));
+		break;
+	case COMMAND_SEND:
+		command_send(argv[0],build_endpoint(argv[0]));
+		break;
+	default:
+		fprintf(stderr, "%s: illegal command %d\n", argv[0], command);
+	} /* switch(command) */
+
+	return 0;
+}
diff --git a/src/apps/nagle_rcv.c b/src/apps/nagle_rcv.c
new file mode 100644
index 0000000..18e0945
--- /dev/null
+++ b/src/apps/nagle_rcv.c
@@ -0,0 +1,243 @@
+/* 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.
+ *
+ * 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@intel.com>
+ *    Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a receiver for the performance test to verify Nagle's algorithm. 
+ * It creates a socket, binds to a address specified as a parameter and
+ * goes into a receive loop waiting for 1,000,000 packets. Then it calculates
+ * the packet receive rate, i.e. packets/second.
+ */
+
+#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>
+#include <getopt.h>
+#include <netdb.h>
+#include <time.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+void
+usage(char *progname)
+{
+	fprintf(stderr, "Usage: %s -H hostname [-P port]\n", progname);
+	fprintf(stderr, " -H, --local\t\t local hostname,\n");
+	fprintf(stderr, " -P, --local-port\t local port,\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+	int sk, i;
+	struct addrinfo *hst_res;
+	sockaddr_storage_t host;
+	sockaddr_storage_t msgname;
+	struct iovec iov;
+	struct msghdr inmessage;
+	char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+	int error, pf_class;
+	char *big_buffer;
+	char *local_host = NULL;
+	int local_port = SCTP_TESTPORT_1; 
+	char port_buffer[10];
+	int option_index = 0;
+	time_t from, to;
+	int bytes_received = 0; 
+	int c;
+	static struct option long_options[] = {
+		{"local",	1, 0, 1},
+		{"local-port",	1, 0, 2},
+		{0,		0, 0, 0}
+	};
+
+	/* Rather than fflush() throughout the code, set stdout to 
+	 * be unbuffered. 
+	 */
+	setvbuf(stdout, NULL, _IONBF, 0); 
+
+	/* Parse the arguments.  */
+	while (1) {
+		c = getopt_long (argc, argv, "H:P:",
+				 long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 0:
+			printf("option %s", long_options[option_index].name);
+			if (optarg) {
+				printf(" with arg %s", optarg);
+			}
+			printf("\n");
+			break;
+		case 1:		/* local host */
+		case 'H':
+			local_host = optarg;
+			break;
+		case 2:		/* local port */
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case '?':
+			usage(argv[0]);
+			exit(0);
+
+		default:
+			printf ("%s: unrecognized option 0%c\n", argv[0], c);
+			usage(argv[0]);
+			exit(1);
+		}
+	}
+
+	if (optind < argc)
+	{
+		fprintf(stderr, "%s: non-option arguments are illegal: ",
+			argv[0]);
+		while (optind < argc)
+			fprintf(stderr, "%s ", argv[optind++]);
+		fprintf (stderr, "\n");
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (!local_host) {
+		fprintf(stderr, "%s: : option -H, --local is required\n",
+			argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	/* Set some basic values which depend on the address family. */
+	if (!strcmp(local_host, "0"))
+		local_host = "0.0.0.0";
+
+	snprintf(port_buffer, 10, "%d", local_port);
+	error = getaddrinfo(local_host, port_buffer, NULL, &hst_res);
+	if (error) {
+		fprintf(stderr, "%s: getaddrinfo failed: %s\n", argv[0], local_host);
+		exit(1);
+	}
+
+	pf_class = hst_res->ai_family;
+	switch (pf_class) {
+	case AF_INET:
+	case AF_INET6:
+		memcpy(&host.sa, hst_res->ai_addr, hst_res->ai_addrlen);
+		break;
+	default:
+		fprintf(stderr, "Invalid address type.\n");
+		exit(1);
+		break;
+	}
+
+	freeaddrinfo(hst_res);
+
+	/* Create the endpoint which will talk to nagle_snd.  */
+	sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+	/* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+	test_enable_assoc_change(sk);
+
+	/* Bind the sockets to the test port.  */
+	test_bind(sk, &host.sa, sizeof(host));
+
+	/* Mark sk as being able to accept new associations.  */
+	test_listen(sk, 1);
+
+	printf("Listening on port:%d\n", local_port);
+
+	/* Initialize inmessage for 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 = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+	inmessage.msg_name = &msgname;
+	inmessage.msg_namelen = sizeof(msgname);
+	memset(&msgname, 0, sizeof(msgname));
+
+	/* Get the communication up message on sk.  */
+	error = test_recvmsg(sk, &inmessage, MSG_WAITALL);
+	test_check_msg_notification(&inmessage, error,
+				    sizeof(struct sctp_assoc_change),
+				    SCTP_ASSOC_CHANGE, SCTP_COMM_UP);	
+
+	printf("Established connection with "); 
+	if (AF_INET == msgname.sa.sa_family)
+		printf("%d.%d.%d.%d(%d)\n", NIPQUAD(msgname.v4.sin_addr),
+		       ntohs(msgname.v4.sin_port));
+	if (AF_INET6 == msgname.sa.sa_family)
+		printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)\n",
+		       NIP6(msgname.v6.sin6_addr), ntohs(msgname.v6.sin6_port));
+
+	time(&from);
+	for (i=0; i<1000000; i++) {
+		inmessage.msg_controllen = sizeof(incmsg);
+		inmessage.msg_namelen = sizeof(msgname);
+		error = test_recvmsg(sk, &inmessage, MSG_WAITALL);
+		if (inmessage.msg_flags & MSG_NOTIFICATION)
+			break;
+		printf("Received %d bytes of data\n", error);
+		bytes_received += error;
+	}
+	time(&to);
+
+	printf("\t%d messages(%d bytes) successfully received in %ld "
+	       "seconds.\n", i, bytes_received, to - from);
+	printf("The receive rate is %ld bytes/second\n",
+	       bytes_received/(to - from));
+
+	/* Shut down the link.	*/
+	error = 0;
+	close(sk);
+
+	return 0;
+}
diff --git a/src/apps/nagle_snd.c b/src/apps/nagle_snd.c
new file mode 100644
index 0000000..bc960cc
--- /dev/null
+++ b/src/apps/nagle_snd.c
@@ -0,0 +1,359 @@
+/* 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.
+ *
+ * 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@intel.com>
+ *    Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a receiver for the performance test to verify Nagle's algorithm. 
+ * It creates a socket, binds to a address specified as a parameter and
+ * sends 1,000,000 packets to a specified target.
+ */
+
+#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>
+#include <getopt.h>
+#include <netdb.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+void
+usage(char *argv0)
+{
+	fprintf(stderr, "Usage: %s -H localhost [-P localport] "
+		"-h remotehost [-p remoteport]\n"
+		"\t\t[-S msgsize] [-I interval] -N\n"
+		" -H, --local\t\tspecify one of the local addresses,\n"
+		" -P, --local-port\tspecify the port number for local addresses,\n"
+		" -h, --remote\t\tspecify one of the remote addresses,\n"
+		" -p, --remote-port\tspecify the port number for remote addresses,\n"
+		" -S, --size\t\tspecify the size(byte) of the sending message,\n"
+		" -I, --interval\t\tspecify the interval(second) that sending messages at,\n"
+		" -N, --nodelay\t\tspecify whether the SCTP allows Nagle's algorithm\n",
+		argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int sk, i;
+	struct addrinfo *hst_res, *tgt_res;
+	sockaddr_storage_t host, target;
+	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;
+	int error, pf_class;
+	sctp_assoc_t associd;
+	uint32_t ppid;
+	uint32_t stream;
+	char *remote_host = NULL;
+	int remote_port = SCTP_TESTPORT_1;
+	char *local_host = NULL;
+	int local_port = SCTP_TESTPORT_2;
+	int size = 1;
+	int interval = 0;
+	int nodelay = 0;
+	int option_index = 0;
+	char *big_buffer;
+	char port_buffer[10];
+	int c;
+	static struct option long_options[] = {
+		{"local",	 1, 0, 1},
+		{"local-port",	 1, 0, 2},
+		{"remote",	 1, 0, 3},
+		{"remote-port",  1, 0, 4},
+		{"size",	 1, 0, 5},
+		{"interval",	 1, 0, 6},
+		{"nodelay",	 0, 0, 10},
+		{0,		 0, 0, 0}
+	};
+
+	/* Rather than fflush() throughout the code, set stdout to 
+	 * be unbuffered. 
+	 */
+	setvbuf(stdout, NULL, _IONBF, 0); 
+
+	/* Parse the arguments.  */
+	while (1) {
+		c = getopt_long (argc, argv, "H:P:h:p:S:I:N",
+				 long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 0:
+			printf("option %s", long_options[option_index].name);
+			if (optarg) {
+				printf(" with arg %s", optarg);
+			}
+			printf("\n");
+			break;
+		case 1:		/* local host */
+		case 'H':
+			local_host = optarg;
+			break;
+		case 2:		/* local port */
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case 3:		/* remote host */
+		case 'h':
+			remote_host = optarg;
+			break;
+		case 4:		/* remote port */
+		case 'p':
+			remote_port = atoi(optarg);
+			break;
+		case 5:		/* size */
+		case 'S':
+			size = atoi(optarg);
+			break;
+		case 6:		/* interval */
+		case 'I':
+			interval = atoi(optarg);
+			break;
+		case 10:	 /* nodelay */
+		case 'N':
+			nodelay = 1;
+			break;
+		case '?':
+			usage(argv[0]);
+			exit(0);
+
+		default:
+			printf ("%s: unrecognized option 0%c\n",
+				argv[0], c);
+			usage(argv[0]);
+			exit(1);
+		}
+	}
+
+	if (optind < argc)
+	{
+		fprintf(stderr, "%s: non-option arguments are illegal: ",
+			argv[0]);
+		while (optind < argc)
+			fprintf(stderr, "%s ", argv[optind++]);
+		fprintf (stderr, "\n");
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (!local_host || !remote_host) {
+		fprintf(stderr, "%s: : option --local and --remote are required\n",
+			argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	/* Set some basic values which depend on the address family. */
+	if (!strcmp(local_host, "0"))
+		local_host = "0.0.0.0";
+
+	snprintf(port_buffer, 10, "%d", local_port);
+	error = getaddrinfo(local_host, port_buffer, NULL, &hst_res);
+	if (error) {
+		fprintf(stderr, "%s: getaddrinfo failed: %s\n", argv[0], local_host);
+		exit(1);
+	}
+
+	snprintf(port_buffer, 10, "%d", remote_port);
+	error = getaddrinfo(remote_host, port_buffer, NULL, &tgt_res);
+	if (error) {
+		fprintf(stderr, "%s: getaddrinfo failed: %s\n", argv[0], remote_host);
+		exit(1);
+	}
+
+	if ( hst_res->ai_family != tgt_res->ai_family) {
+		fprintf(stderr, "local and reomte hosts should be the " 
+			"same address family\n");
+		exit(1);
+	}
+
+	pf_class = hst_res->ai_family;
+	switch (pf_class) {
+	case AF_INET:
+	case AF_INET6:
+		memcpy(&host.sa, hst_res->ai_addr, hst_res->ai_addrlen);
+		memcpy(&target.sa, tgt_res->ai_addr, tgt_res->ai_addrlen);
+		break;
+	default:
+		fprintf(stderr, "Invalid address type.\n");
+		exit(1);
+		break;
+	}
+
+	freeaddrinfo(hst_res);
+	freeaddrinfo(tgt_res);
+
+	sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+	/* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
+	test_enable_assoc_change(sk);
+
+	test_setsockopt(sk, SCTP_NODELAY, &nodelay, sizeof(int));
+
+	/* Bind the sockets to the test port.  */
+	test_bind(sk, &host.sa, sizeof(host));
+
+	/* Mark sk as being able to accept new associations.  */
+	test_listen(sk, 1);
+
+	/* Build up a msghdr structure we can use for all sending.  */
+	outmessage.msg_name = &target;
+	outmessage.msg_namelen = sizeof(target);
+	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;
+
+	message = test_malloc((size + 1) * sizeof(u_int8_t));
+
+	for(i=0; i + 10 < size; i+= 10)
+		memcpy(message+i, "1234567890", 10);
+	strncpy(message+i, "1234567890", size-i);
+	*(message+size) = 0;
+
+	outmessage.msg_iov->iov_base = message;
+	outmessage.msg_iov->iov_len = size + 1;
+
+	printf("Initiating connection with %s:%d...\n", remote_host,
+	       remote_port);
+
+	/* Send the first message.  This will create the association.  */
+	test_sendmsg(sk, &outmessage, 0, size+1);
+
+	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 = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+	inmessage.msg_name = &msgname;
+	inmessage.msg_namelen = sizeof(msgname);
+	memset(&msgname, 0, sizeof(msgname));
+
+	/* Get the communication up message on sk.  */
+	error = test_recvmsg(sk, &inmessage, MSG_WAITALL);
+	test_check_msg_notification(&inmessage, error,
+				    sizeof(struct sctp_assoc_change),
+				    SCTP_ASSOC_CHANGE, SCTP_COMM_UP);	
+	associd = ((struct sctp_assoc_change *)iov.iov_base)->sac_assoc_id;
+
+	printf("Established connection with ");	
+	if (AF_INET == msgname.sa.sa_family)
+		printf("%d.%d.%d.%d(%d)\n", NIPQUAD(msgname.v4.sin_addr),
+		       ntohs(msgname.v4.sin_port));
+	if (AF_INET6 == msgname.sa.sa_family)
+		printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)\n",
+		       NIP6(msgname.v6.sin6_addr), ntohs(msgname.v6.sin6_port));
+
+	printf("Sending data to receiver...\n");
+
+	for (i=1; i<1000000; i++) {
+
+		if (interval)
+			sleep(interval);
+
+		outmessage.msg_name = &target;
+		outmessage.msg_namelen = sizeof(target);
+		outmessage.msg_iov = &out_iov;
+		outmessage.msg_iovlen = 1;
+		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++;
+
+		sinfo->sinfo_ppid = ppid;
+		sinfo->sinfo_stream = stream;
+		sinfo->sinfo_assoc_id = associd;
+
+		outmessage.msg_iov->iov_base = message;
+		outmessage.msg_iov->iov_len = size + 1;
+
+		test_sendmsg(sk, &outmessage, 0, size+1);
+	}
+
+	printf("\n\n\t\tComplete all the data sendings to receiver...\n\n\n");
+
+	error = 0;
+	close(sk);
+
+	free(message);
+
+	/* Indicate successful completion.  */
+	return 0;
+
+}
diff --git a/src/apps/peel_client.c b/src/apps/peel_client.c
new file mode 100644
index 0000000..5c195d3
--- /dev/null
+++ b/src/apps/peel_client.c
@@ -0,0 +1,672 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2003
+ *
+ * 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.
+ *
+ * In addition:
+ *
+ * Copyright (c) 2003 Cisco
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * a) Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * b) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * c) Neither the name of Cisco Systems, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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:
+ *    Randall Stewart   <rrs@cisco.com>
+ *    Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+#include <ctype.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/uio.h>
+#include <netdb.h>
+
+#include <netinet/sctp.h>
+#ifdef __NetBSD__
+#include <sys/inttypes.h>
+#endif
+
+#define SCTP_CRC32C_POLY 0x1EDC6F41
+#define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF])
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Copyright 2001, D. Otis.  Use this program, code or tables    */
+/* extracted from it, as desired without restriction.            */
+/*                                                               */
+/* 32 Bit Reflected CRC table generation for SCTP.               */
+/* To accommodate serial byte data being shifted out least       */
+/* significant bit first, the table's 32 bit words are reflected */
+/* which flips both byte and bit MS and LS positions.  The CRC   */
+/* is calculated MS bits first from the perspective of the serial*/
+/* stream.  The x^32 term is implied and the x^0 term may also   */
+/* be shown as +1.  The polynomial code used is 0x1EDC6F41.      */
+/* Castagnoli93                                                  */
+/* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+  */
+/* x^11+x^10+x^9+x^8+x^6+x^0                                     */
+/* Guy Castagnoli Stefan Braeuer and Martin Herrman              */
+/* "Optimization of Cyclic Redundancy-Check Codes                */
+/* with 24 and 32 Parity Bits",                                  */
+/* IEEE Transactions on Communications, Vol.41, No.6, June 1993  */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static unsigned char buffer1[4100];
+static unsigned char buffer2[4100];
+static unsigned char buffer3[4100];
+static unsigned char buffer4[4100];
+static struct sockaddr_in bindto,got,to;
+static socklen_t len;
+
+unsigned long  sctp_crc_c[256] = {
+	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
+};
+
+u_int32_t
+update_crc32(u_int32_t crc32,
+	     unsigned char *buffer,
+	     unsigned int length)
+{
+	int i;
+	for (i = 0; i < length; i++) {
+		SCTP_CRC32C(crc32, buffer[i]);
+	}
+	return (crc32);
+}
+
+u_int32_t
+sctp_csum_finalize(u_int32_t crc32)
+{
+	u_int32_t result;
+#if BYTE_ORDER == BIG_ENDIAN
+	u_int8_t byte0, byte1, byte2, byte3;
+#endif
+	/* Complement the result */
+	result = ~crc32;
+#if BYTE_ORDER == BIG_ENDIAN
+	/*
+	 * For BIG-ENDIAN.. aka Motorola byte order the result is in
+	 * little-endian form. So we must manually swap the bytes. Then
+	 * we can call htonl() which does nothing...
+	 */
+	byte0 = result & 0x000000ff;
+	byte1 = (result >> 8) & 0x000000ff;
+	byte2 = (result >> 16) & 0x000000ff;
+	byte3 = (result >> 24) & 0x000000ff;
+	result = ((byte0 << 24) |
+		  (byte1 << 16) |
+		  (byte2 << 8) |
+		  byte3);
+	crc32 = htonl(result);
+#else
+	/*
+	 * For INTEL platforms the result comes out in network order.
+	 * No htonl is required or the swap above. So we optimize out
+	 * both the htonl and the manual swap above.
+	 */
+	crc32 = result;
+#endif
+	return (crc32);
+}
+
+static u_int32_t at = 468700;
+
+void
+prepare_buffers(void)
+{
+        /* Prepare buffers */
+	u_int32_t temp,*p;
+	int i;
+
+	p = (u_int32_t *)buffer1;
+	for(i=0;i<(sizeof(buffer1)/4);i++){
+		*p = at;
+		at++;
+		p++;
+	}
+	/* backup over the last int */
+	p--;
+	*p = 0;
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer1,(sizeof(buffer1)-4));
+	*p = sctp_csum_finalize(temp);
+
+	p = (u_int32_t *)buffer2;
+	for(i=0;i<(sizeof(buffer2)/4);i++){
+		*p = at;
+		at++;
+		p++;
+	}
+	p--;
+	*p = 0;
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer2,(sizeof(buffer2)-4));
+	*p = sctp_csum_finalize(temp);
+
+	p = (u_int32_t *)buffer3;
+	for(i=0;i<(sizeof(buffer3)/4);i++){
+		*p = at;
+		at++;
+		p++;
+	}
+	p--;
+	*p = 0;
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer3,(sizeof(buffer3)-4));
+	*p = sctp_csum_finalize(temp);
+
+	p = (u_int32_t *)buffer4;
+	for(i=0;i<(sizeof(buffer4)/4);i++){
+		*p = at;
+		at++;
+		p++;
+	}
+	p--;
+	*p = 0;
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer4,(sizeof(buffer4)-4));
+	*p = sctp_csum_finalize(temp);
+}
+
+static int
+my_handle_notification(int fd,char *notify_buf) {
+	union sctp_notification *snp;
+	struct sctp_assoc_change *sac;
+	struct sctp_paddr_change *spc;
+	struct sctp_remote_error *sre;
+	struct sctp_send_failed *ssf;
+	struct sctp_shutdown_event *sse;
+	int asocDown;
+	char *str;
+	char buf[256];
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
+
+	asocDown = 0;
+	snp = (union sctp_notification *)notify_buf;
+	switch(snp->sn_header.sn_type) {
+	case SCTP_ASSOC_CHANGE:
+		sac = &snp->sn_assoc_change;
+		switch(sac->sac_state) {
+
+		case SCTP_COMM_UP:
+			str = "COMMUNICATION UP";
+			break;
+		case SCTP_COMM_LOST:
+			str = "COMMUNICATION LOST";
+			asocDown = 1;
+			break;
+		case SCTP_RESTART:
+		        str = "RESTART";
+			break;
+		case SCTP_SHUTDOWN_COMP:
+			str = "SHUTDOWN COMPLETE";
+			asocDown = 1;
+			break;
+		case SCTP_CANT_STR_ASSOC:
+			str = "CANT START ASSOC";
+			printf("EXIT:SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str,
+			       (uint32_t)sac->sac_assoc_id);
+			exit(0);
+			break;
+		default:
+			str = "UNKNOWN";
+		} /* end switch(sac->sac_state) */
+		printf("SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str,
+		       (uint32_t)sac->sac_assoc_id);
+		break;
+	case SCTP_PEER_ADDR_CHANGE:
+		spc = &snp->sn_paddr_change;
+		switch(spc->spc_state) {
+		case SCTP_ADDR_AVAILABLE:
+			str = "ADDRESS AVAILABLE";
+			break;
+		case SCTP_ADDR_UNREACHABLE:
+			str = "ADDRESS UNAVAILABLE";
+			break;
+		case SCTP_ADDR_REMOVED:
+			str = "ADDRESS REMOVED";
+			break;
+		case SCTP_ADDR_ADDED:
+			str = "ADDRESS ADDED";
+			break;
+		case SCTP_ADDR_MADE_PRIM:
+			str = "ADDRESS MADE PRIMARY";
+			break;
+		default:
+			str = "UNKNOWN";
+		} /* end switch */
+		sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
+		if (sin6->sin6_family == AF_INET6) {
+			inet_ntop(AF_INET6, (char*)&sin6->sin6_addr, buf, sizeof(buf));
+		} else {
+			sin = (struct sockaddr_in *)&spc->spc_aaddr;
+			inet_ntop(AF_INET, (char*)&sin->sin_addr, buf, sizeof(buf));
+		}
+		printf("SCTP_PEER_ADDR_CHANGE: %s, addr=%s, assoc=%xh\n", str,
+		       buf, (uint32_t)spc->spc_assoc_id);
+		break;
+	case SCTP_REMOTE_ERROR:
+		sre = &snp->sn_remote_error;
+		printf("SCTP_REMOTE_ERROR: assoc=%xh\n",
+		       (uint32_t)sre->sre_assoc_id);
+		break;
+	case SCTP_SEND_FAILED:
+		ssf = &snp->sn_send_failed;
+		printf("SCTP_SEND_FAILED: assoc=%xh\n",
+		       (uint32_t)ssf->ssf_assoc_id);
+		break;
+	case SCTP_ADAPTATION_INDICATION:
+	  {
+	    struct sctp_adaptation_event *ae;
+	    ae = &snp->sn_adaptation_event;
+	    printf("\nSCTP_adaptation_indication bits:0x%x\n",
+		   (u_int)ae->sai_adaptation_ind);
+	  }
+	  break;
+	case SCTP_PARTIAL_DELIVERY_EVENT:
+	  {
+	    struct sctp_pdapi_event *pdapi;
+	    pdapi = &snp->sn_pdapi_event;
+	    printf("SCTP_PD-API event:%u\n",
+		   pdapi->pdapi_indication);
+	    if(pdapi->pdapi_indication == 0){
+		    printf("PDI- Aborted\n");
+	    }
+	  }
+	  break;
+
+	case SCTP_SHUTDOWN_EVENT:
+                sse = &snp->sn_shutdown_event;
+		printf("SCTP_SHUTDOWN_EVENT: assoc=%xh\n",
+		       (uint32_t)sse->sse_assoc_id);
+		break;
+	default:
+		printf("Unknown notification event type=%xh\n", 
+		       snp->sn_header.sn_type);
+	} /* end switch(snp->sn_type) */
+	if(asocDown){
+		printf("Bring association back up\n");
+		len = sizeof(to);
+		if(connect(fd,(struct sockaddr *)&to,len) == -1){
+			printf("Sorry connect fails %d\n",errno);
+		}
+		return(1);
+	}
+	return(0);
+}
+
+
+	
+int
+my_sctpReadInput(int fd)
+{
+	/* receive some number of datagrams and
+	 * act on them.
+	 */
+	int sz;
+	struct msghdr msg;
+	struct iovec iov[2];
+	unsigned char from[200];
+	char readBuffer[65535];
+	char controlVector[65535];
+  
+	iov[0].iov_base = readBuffer;
+	iov[0].iov_len = sizeof(readBuffer);
+	iov[1].iov_base = NULL;
+	iov[1].iov_len = 0;
+	msg.msg_name = (caddr_t)from;
+	msg.msg_namelen = sizeof(from);
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = (caddr_t)controlVector;
+	msg.msg_controllen = sizeof(controlVector);
+	msg.msg_flags = 0;
+	errno = 0;
+	sz = recvmsg(fd,&msg,0);
+	if(sz <= 0){
+		printf("Read returns %d errno:%d control len is %zu msgflg:%x\n",
+		       sz,errno,
+		       msg.msg_controllen,msg.msg_flags);
+	}
+	if (msg.msg_flags & MSG_NOTIFICATION) {
+		return(my_handle_notification(fd,readBuffer));
+	}else{
+		printf("Huh, I got data?.. ignored (%d bytes)\n",sz);
+		return(0);
+	}
+}
+
+
+int
+clear_fds(int fd,int fd1)
+{
+	int felldown;
+	int max,notdone;
+	fd_set readfds,writefds,exceptfds;
+	struct timeval tv;
+	memset(&tv,0,sizeof(tv));
+	FD_ZERO(&readfds);
+	FD_ZERO(&writefds);
+	FD_ZERO(&exceptfds);
+	felldown = 0;
+	FD_SET(fd,&readfds);
+	FD_SET(fd1,&readfds);
+	if(fd > fd1){
+		max = fd + 1;
+	}else{
+		max = fd1 + 1;
+	}
+	notdone = 1;
+	while(notdone){
+		if (select(max, &readfds, &writefds, &exceptfds, &tv) == -1)
+			break;
+		notdone = 0;
+		if(FD_ISSET(fd,&readfds)){
+			notdone++;
+			printf("clearing fd:%d\n",fd);
+			felldown += my_sctpReadInput(fd);
+			notdone = 1;
+		}
+		if(FD_ISSET(fd1,&readfds)){
+			notdone++;
+			printf("clearing fd1:%d\n",fd1);
+			felldown += my_sctpReadInput(fd1);
+		}
+	}
+	return(felldown);
+}
+
+void
+process_out_data(int fd,int fd1)
+{
+	int notdone,x,ret;
+	while(1){
+		/* Prepare the buffers */
+		prepare_buffers();
+		/* send out the 4 buffers */
+		ret = sendto(fd,buffer1,sizeof(buffer1),0,
+			     (struct sockaddr *)&to,sizeof(to));
+		if(ret < sizeof(buffer1)){
+			printf("Gak1, error:%d ret:%d\n",errno,ret);
+		}
+
+		ret = sendto(fd1,buffer2,sizeof(buffer1),0,
+			     (struct sockaddr *)&to,sizeof(to));
+		if(ret < sizeof(buffer2)){
+			printf("Gak2, error:%d ret:%d\n",errno,ret);
+		}
+
+
+		ret = sendto(fd,buffer3,sizeof(buffer1),0,
+			     (struct sockaddr *)&to,sizeof(to));
+		if(ret < sizeof(buffer3)){
+			printf("Gak3, error:%d ret:%d\n",errno,ret);
+		}
+
+
+		ret = sendto(fd1,buffer4,sizeof(buffer1),0,
+			     (struct sockaddr *)&to,sizeof(to));
+		if(ret < sizeof(buffer4)){
+			printf("Gak4, error:%d ret:%d\n",errno,ret);
+		}
+
+		/*  now wait until we get a assoc failing */
+		notdone = 1;
+		while(notdone){
+			x = clear_fds(fd,fd1);
+			if(x){
+				notdone = 0;
+			}
+			sleep(1);
+		}
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int i,fd,fd1;
+	char *addr=NULL;
+	uint16_t port=0;
+	int protocol_touse = IPPROTO_SCTP;
+	struct sctp_event_subscribe event = {0};
+
+	while((i= getopt(argc,argv,"p:h:")) != EOF){
+		switch(i){
+		case 'h':
+			addr = optarg;
+			break;
+		case 'p':
+			port = (uint16_t)strtol(optarg,NULL,0);
+			break;
+		};
+	}
+	memset(&to,0,sizeof(to));
+	if((addr == NULL) || (port == 0)){
+		printf("Usage: %s -h addr -p port\n", argv[0]);
+		return(-1);
+	}
+	if(inet_pton(AF_INET, addr, (void *) &to.sin_addr)){
+		//to.sin_len = sizeof(to);
+		to.sin_family = AF_INET;
+		printf("port selected is %d\n",port);
+		printf("addr %x\n",(u_int)ntohl(to.sin_addr.s_addr));
+		to.sin_port = htons(port);
+	}else{
+		printf("Can't translate the address\n");
+		return(-1);
+	}
+	/**********************socket 1 *******************/
+      	fd = socket(AF_INET, SOCK_SEQPACKET, protocol_touse);
+	if(fd == -1){
+		printf("can't open socket:%d\n",errno);
+		return(-1);
+	}
+	memset(&bindto,0,sizeof(bindto));
+	//len = bindto.sin_len = sizeof(bindto);
+	len = sizeof(bindto);
+	bindto.sin_family = AF_INET;
+	bindto.sin_port = 0;
+	if(bind(fd,(struct sockaddr *)&bindto, len) < 0){
+		printf("can't bind a socket:%d\n",errno);
+		close(fd);
+		return(-1);
+	}
+	if(getsockname(fd,(struct sockaddr *)&got,&len) < 0){
+		printf("get sockname failed err:%d\n",errno);
+		close(fd);
+		return(-1);
+	}	
+	printf("fd uses port %d\n",ntohs(got.sin_port));
+
+	/**********************socket 2 *******************/
+      	fd1 = socket(AF_INET, SOCK_SEQPACKET, protocol_touse);
+	if(fd1 == -1){
+		printf("can't open socket:%d\n",errno);
+		close(fd);
+		return(-1);
+	}
+	memset(&bindto,0,sizeof(bindto));
+	//len = bindto.sin_len = sizeof(bindto);
+	len = sizeof(bindto);
+	bindto.sin_family = AF_INET;
+	bindto.sin_port = 0;
+	if(bind(fd1,(struct sockaddr *)&bindto, len) < 0){
+		printf("can't bind a socket:%d\n",errno);
+		close(fd);
+		close(fd1);
+		return(-1);
+	}
+	if(getsockname(fd1,(struct sockaddr *)&got,&len) < 0){
+		printf("get sockname failed err:%d\n",errno);
+		close(fd);
+		close(fd1);
+		return(-1);
+	}	
+	printf("fd1 uses port %d\n",ntohs(got.sin_port));
+
+	/* enable all event notifications */
+	event.sctp_data_io_event = 1;
+	event.sctp_association_event = 1;
+	event.sctp_address_event = 1;
+	event.sctp_send_failure_event = 1;
+	event.sctp_peer_error_event = 1;
+	event.sctp_shutdown_event = 1;
+	event.sctp_partial_delivery_event = 1;
+	event.sctp_adaptation_layer_event = 1;
+	if (setsockopt(fd, IPPROTO_SCTP, 
+		       SCTP_EVENTS, &event, 
+		       sizeof(event)) != 0) {
+		printf("Gak, can't set events errno:%d\n",errno);
+		exit(0);
+	}
+	if (setsockopt(fd1, IPPROTO_SCTP, 
+		       SCTP_EVENTS, &event, 
+		       sizeof(event)) != 0) {
+		printf("Gak, can't set events errno:%d\n",errno);
+		exit(0);
+	}
+
+	if(connect(fd,(struct sockaddr *)&to,len) == -1){
+		printf("Sorry connect fails %d\n",errno);
+		close(fd);
+		return(-1);
+	}
+	if(connect(fd1,(struct sockaddr *)&to,len) == -1){
+		printf("Sorry connect fails %d\n",errno);
+		close(fd);
+		return(-1);
+	}
+	printf("Connected\n");
+	clear_fds(fd,fd1);
+	process_out_data(fd,fd1);
+
+	return(0);
+}
+
diff --git a/src/apps/peel_server.c b/src/apps/peel_server.c
new file mode 100644
index 0000000..24a1ef8
--- /dev/null
+++ b/src/apps/peel_server.c
@@ -0,0 +1,667 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2003
+ * Copyright (c) 2003 Cisco
+ *
+ * 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.
+ *
+ * In addition:
+ *
+ * Copyright (c) 2003 Cisco
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * a) Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * b) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * c) Neither the name of Cisco Systems, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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:
+ *    Randall Stewart   <rrs@cisco.com>
+ *    Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+#include <ctype.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/uio.h>
+#include <netdb.h>
+
+#include <netinet/sctp.h>
+#ifdef __NetBSD__
+#include <sys/inttypes.h>
+#endif
+
+#define SCTP_CRC32C_POLY 0x1EDC6F41
+#define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF])
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Copyright 2001, D. Otis.  Use this program, code or tables    */
+/* extracted from it, as desired without restriction.            */
+/*                                                               */
+/* 32 Bit Reflected CRC table generation for SCTP.               */
+/* To accommodate serial byte data being shifted out least       */
+/* significant bit first, the table's 32 bit words are reflected */
+/* which flips both byte and bit MS and LS positions.  The CRC   */
+/* is calculated MS bits first from the perspective of the serial*/
+/* stream.  The x^32 term is implied and the x^0 term may also   */
+/* be shown as +1.  The polynomial code used is 0x1EDC6F41.      */
+/* Castagnoli93                                                  */
+/* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+  */
+/* x^11+x^10+x^9+x^8+x^6+x^0                                     */
+/* Guy Castagnoli Stefan Braeuer and Martin Herrman              */
+/* "Optimization of Cyclic Redundancy-Check Codes                */
+/* with 24 and 32 Parity Bits",                                  */
+/* IEEE Transactions on Communications, Vol.41, No.6, June 1993  */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static unsigned char buffer1[4100];
+static unsigned char buffer2[4100];
+static unsigned char buffer3[4100];
+static unsigned char buffer4[4100];
+static struct sockaddr_in bindto,got;
+static socklen_t len;
+
+unsigned long  sctp_crc_c[256] = {
+	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
+};
+
+u_int32_t
+update_crc32(u_int32_t crc32,
+	     unsigned char *buffer,
+	     unsigned int length)
+{
+	int i;
+	for (i = 0; i < length; i++) {
+		SCTP_CRC32C(crc32, buffer[i]);
+	}
+	return (crc32);
+}
+
+u_int32_t
+sctp_csum_finalize(u_int32_t crc32)
+{
+	u_int32_t result;
+#if BYTE_ORDER == BIG_ENDIAN
+	u_int8_t byte0, byte1, byte2, byte3;
+#endif
+	/* Complement the result */
+	result = ~crc32;
+#if BYTE_ORDER == BIG_ENDIAN
+	/*
+	 * For BIG-ENDIAN.. aka Motorola byte order the result is in
+	 * little-endian form. So we must manually swap the bytes. Then
+	 * we can call htonl() which does nothing...
+	 */
+	byte0 = result & 0x000000ff;
+	byte1 = (result >> 8) & 0x000000ff;
+	byte2 = (result >> 16) & 0x000000ff;
+	byte3 = (result >> 24) & 0x000000ff;
+	result = ((byte0 << 24) |
+		  (byte1 << 16) |
+		  (byte2 << 8) |
+		  byte3);
+	crc32 = htonl(result);
+#else
+	/*
+	 * For INTEL platforms the result comes out in network order.
+	 * No htonl is required or the swap above. So we optimize out
+	 * both the htonl and the manual swap above.
+	 */
+	crc32 = result;
+#endif
+	return (crc32);
+}
+
+int
+check_buffers(void)
+{
+        /* Prepare buffers */
+	u_int32_t temp,*csum;
+	int ret=0;
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer1,(sizeof(buffer1)-4));
+	temp = sctp_csum_finalize(temp);
+	csum = (u_int32_t *)(buffer1+(sizeof(buffer1)-4));
+	if(*csum != temp){
+		printf("Buffer1: Found csum:%x calculated:%x\n",
+		       *csum,temp);
+		ret++;
+	}
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer2,(sizeof(buffer2)-4));
+	temp = sctp_csum_finalize(temp);
+	csum = (u_int32_t *)(buffer2+(sizeof(buffer2)-4));
+	if(*csum != temp){
+		printf("Buffer2: Found csum:%x calculated:%x\n",
+		       *csum,temp);
+		ret++;
+	}
+
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer3,(sizeof(buffer3)-4));
+	temp = sctp_csum_finalize(temp);
+	csum = (u_int32_t *)(buffer3+(sizeof(buffer3)-4));
+	if(*csum != temp){
+		printf("Buffer3: Found csum:%x calculated:%x\n",
+		       *csum,temp);
+		ret++;
+	}
+
+	temp = 0xffffffff;
+	temp = update_crc32(temp,buffer4,(sizeof(buffer4)-4));
+	temp = sctp_csum_finalize(temp);
+	csum = (u_int32_t *)(buffer4+(sizeof(buffer4)-4));
+	if(*csum != temp){
+		printf("Buffer4: Found csum:%x calculated:%x\n",
+		       *csum,temp);
+		ret++;
+	}
+	return(ret);
+}
+
+static int
+my_handle_notification(int fd,char *notify_buf) {
+	union sctp_notification *snp;
+	struct sctp_assoc_change *sac;
+	struct sctp_paddr_change *spc;
+	struct sctp_remote_error *sre;
+	struct sctp_send_failed *ssf;
+	struct sctp_shutdown_event *sse;
+	int asocUp;
+	char *str;
+	char buf[256];
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
+
+	snp = (union sctp_notification *)notify_buf;
+	asocUp = 0;
+	switch(snp->sn_header.sn_type) {
+	case SCTP_ASSOC_CHANGE:
+		sac = &snp->sn_assoc_change;
+		switch(sac->sac_state) {
+
+		case SCTP_COMM_UP:
+			str = "COMMUNICATION UP";
+			asocUp++;
+			break;
+		case SCTP_COMM_LOST:
+			str = "COMMUNICATION LOST";
+			break;
+		case SCTP_RESTART:
+		        str = "RESTART";
+			asocUp++;
+			break;
+		case SCTP_SHUTDOWN_COMP:
+			str = "SHUTDOWN COMPLETE";
+			break;
+		case SCTP_CANT_STR_ASSOC:
+			str = "CANT START ASSOC";
+			printf("EXIT:SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str,
+			       (uint32_t)sac->sac_assoc_id);
+			exit(0);
+			break;
+		default:
+			str = "UNKNOWN";
+		} /* end switch(sac->sac_state) */
+		printf("SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str,
+		       (uint32_t)sac->sac_assoc_id);
+		break;
+	case SCTP_PEER_ADDR_CHANGE:
+		spc = &snp->sn_paddr_change;
+		switch(spc->spc_state) {
+		case SCTP_ADDR_AVAILABLE:
+			str = "ADDRESS AVAILABLE";
+			break;
+		case SCTP_ADDR_UNREACHABLE:
+			str = "ADDRESS UNAVAILABLE";
+			break;
+		case SCTP_ADDR_REMOVED:
+			str = "ADDRESS REMOVED";
+			break;
+		case SCTP_ADDR_ADDED:
+			str = "ADDRESS ADDED";
+			break;
+		case SCTP_ADDR_MADE_PRIM:
+			str = "ADDRESS MADE PRIMARY";
+			break;
+		default:
+			str = "UNKNOWN";
+		} /* end switch */
+		sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
+		if (sin6->sin6_family == AF_INET6) {
+			inet_ntop(AF_INET6, (char*)&sin6->sin6_addr, buf, sizeof(buf));
+		} else {
+			sin = (struct sockaddr_in *)&spc->spc_aaddr;
+			inet_ntop(AF_INET, (char*)&sin->sin_addr, buf, sizeof(buf));
+		}
+		printf("SCTP_PEER_ADDR_CHANGE: %s, addr=%s, assoc=%xh\n", str,
+		       buf, (uint32_t)spc->spc_assoc_id);
+		break;
+	case SCTP_REMOTE_ERROR:
+		sre = &snp->sn_remote_error;
+		printf("SCTP_REMOTE_ERROR: assoc=%xh\n",
+		       (uint32_t)sre->sre_assoc_id);
+		break;
+	case SCTP_SEND_FAILED:
+		ssf = &snp->sn_send_failed;
+		printf("SCTP_SEND_FAILED: assoc=%xh\n",
+		       (uint32_t)ssf->ssf_assoc_id);
+		break;
+	case SCTP_ADAPTATION_INDICATION:
+	  {
+	    struct sctp_adaptation_event *ae;
+	    ae = &snp->sn_adaptation_event;
+	    printf("\nSCTP_adaptation_indication bits:0x%x\n",
+		   (u_int)ae->sai_adaptation_ind);
+	  }
+	  break;
+	case SCTP_PARTIAL_DELIVERY_EVENT:
+	  {
+	    struct sctp_pdapi_event *pdapi;
+	    pdapi = &snp->sn_pdapi_event;
+	    printf("SCTP_PD-API event:%u\n",
+		   pdapi->pdapi_indication);
+	    if(pdapi->pdapi_indication == 0){
+		    printf("PDI- Aborted\n");
+	    }
+	  }
+	  break;
+
+	case SCTP_SHUTDOWN_EVENT:
+                sse = &snp->sn_shutdown_event;
+		printf("SCTP_SHUTDOWN_EVENT: assoc=%xh\n",
+		       (uint32_t)sse->sse_assoc_id);
+		break;
+	default:
+		printf("Unknown notification event type=%xh\n", 
+		       snp->sn_header.sn_type);
+	} /* end switch(snp->sn_type) */
+	return(asocUp);
+}
+
+
+static char readBuffer[65535];	
+static int sz=0;
+static char controlVector[65535];
+static struct msghdr msg;
+int
+my_sctpReadInput(int fd,int maxread)
+{
+	/* receive some number of datagrams and
+	 * act on them.
+	 */
+	struct iovec iov[2];
+	unsigned char from[200];
+
+	memset(&msg,0,sizeof(msg));
+	memset(controlVector,0,sizeof(controlVector));
+	memset(readBuffer,0,sizeof(readBuffer));
+
+	iov[0].iov_base = readBuffer;
+	iov[0].iov_len = maxread;
+	iov[1].iov_base = NULL;
+	iov[1].iov_len = 0;
+	msg.msg_name = (caddr_t)from;
+	msg.msg_namelen = sizeof(from);
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = (caddr_t)controlVector;
+	msg.msg_controllen = sizeof(controlVector);
+	errno = 0;
+	sz = recvmsg(fd,&msg,0);
+	printf("Read fd:%d returns %d errno:%d control len is %zu msgflg:%x\n",
+	       fd,
+	       sz,errno,
+	       msg.msg_controllen,
+	       msg.msg_flags);
+
+	if (msg.msg_flags & MSG_NOTIFICATION) {
+		printf("Got a notification\n");
+		return(my_handle_notification(fd,readBuffer));
+	}else{
+		printf("Got data\n");
+		return(-1);
+	}
+}
+
+
+int
+poll_fd(int fd)
+{
+	int cameup;
+	int max;
+	fd_set readfds,writefds,exceptfds;
+	struct timeval tv;
+
+	memset(&tv,0,sizeof(tv));
+	FD_ZERO(&readfds);
+	FD_ZERO(&writefds);
+	FD_ZERO(&exceptfds);
+	cameup = 0;
+	max = fd + 1;
+
+	printf("poll_fd\n");
+	FD_SET(fd,&readfds);
+
+	if (select(max, &readfds, &writefds, &exceptfds, NULL) == -1)
+		return(cameup);
+	if(FD_ISSET(fd,&readfds)){
+		printf("Read please\n");
+		cameup += my_sctpReadInput(fd,4100);
+	}
+
+	return(cameup);
+}
+
+static sctp_assoc_t
+dig_out_asocid(void)
+{
+	struct sctp_sndrcvinfo *s_info;
+	struct cmsghdr *cmsg;
+	s_info = NULL;
+	if(msg.msg_controllen){
+		/* parse through and see if we find
+		 * the sctp_sndrcvinfo
+		 */
+		cmsg = (struct cmsghdr *)controlVector;
+		while(cmsg){
+			if(cmsg->cmsg_level == IPPROTO_SCTP){
+				if(cmsg->cmsg_type == SCTP_SNDRCV){
+					/* Got it */
+					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+					break;
+				}
+			}
+			cmsg = CMSG_NXTHDR(&msg,cmsg);
+		}
+	}else{
+		printf("No CMSG?\n");
+		exit(0);
+	}
+	if(s_info == NULL){
+		printf("No sinfo?\n");
+		exit(0);
+	}
+	return(s_info->sinfo_assoc_id);
+}
+
+
+void
+process(int fd,int magic)
+{
+	int fd1,num_asoc,ret,i;
+	sctp_assoc_t asoc;
+	struct timespec ts;
+	num_asoc = 0;
+	i = 1;
+	ts.tv_sec = 0;
+	ts.tv_nsec = 10000;
+
+	while(i < 4099){
+		printf("pass %d\n",i);
+		while(num_asoc < 2){
+			ret = poll_fd(fd);
+			if(ret >0 ){
+				num_asoc += ret;
+			}else if(ret == 0){
+				sleep(1);
+			}else if(ret < 0){
+				printf("Got data? %d\n",sz);
+				sleep(1);
+			}
+			printf("asoc count is %d\n",num_asoc);
+		}
+	again:
+		printf("Reading for %d bytes from fd:%d\n",
+		       i,fd);
+		my_sctpReadInput(fd,i);
+		if(sz == i){
+			memcpy(buffer1,readBuffer,i);
+		}else{
+			printf("Huh I am messed up read %d wanted %d\n",
+			       sz,i);
+			goto again;
+		}
+		if(msg.msg_flags & MSG_EOR){
+			printf("Huh got EOR on paritial read?\n");
+			exit(0);
+		}
+		asoc = dig_out_asocid();
+		nanosleep(&ts,NULL);
+
+		fd1 = sctp_peeloff(fd,asoc);
+		if(fd1 == -1){
+			printf("peeloff failed %d/err:%d\n",
+			       fd1,errno);
+			exit(0);
+		}
+		my_sctpReadInput(fd1,(4100-i));
+		if(sz > 0){
+			memcpy(&buffer1[i],readBuffer,sz);
+			printf("Copied %d bytes\n",sz);
+		}else{
+			printf("Huh only read %d\n",sz);
+		}
+		if(magic >= i){
+			printf("magic engaged\n");
+			my_sctpReadInput(fd,i);
+		}else{
+			my_sctpReadInput(fd,4100);
+		}
+		if(sz > 0){
+			memcpy(buffer2,readBuffer,sz);
+			printf("copied %d bytes\n",sz);
+		}else{
+			printf("Huh only read %d\n",sz);
+		}
+		my_sctpReadInput(fd1,4100);
+		if(sz > 0){
+			memcpy(buffer3,readBuffer,sz);
+			printf("copied %d bytes\n",sz);
+		}else{
+			printf("Huh only read %d\n",sz);
+		}
+		my_sctpReadInput(fd,4100);
+		if(sz > 0){
+			memcpy(buffer4,readBuffer,sz);
+			printf("copied %d bytes\n",sz);
+		}else{
+			printf("Huh only read %d\n",sz);
+		}
+		if(check_buffers()){
+			exit(0);
+		}
+		close(fd1);
+		i++;
+		num_asoc--;
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int i,fd;
+	uint16_t myport=0;
+	int magic=0;
+	struct sctp_event_subscribe event = {0};
+	while((i= getopt(argc,argv,"m:M:")) != EOF){
+		switch(i){
+		case 'm':
+			myport = (uint16_t)strtol(optarg,NULL,0);
+			break;
+		case 'M':
+			magic = strtol(optarg,NULL,0);
+			break;
+		};
+	}
+	/**********************socket 1 *******************/
+      	fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+	if(fd == -1){
+		printf("can't open socket:%d\n",errno);
+		return(-1);
+	}
+	memset(&bindto,0,sizeof(bindto));
+	//len = bindto.sin_len = sizeof(bindto);
+	len = sizeof(bindto);
+	bindto.sin_family = AF_INET;
+	printf("bind port %d\n",myport);
+	bindto.sin_port = htons(myport);
+	if(bind(fd,(struct sockaddr *)&bindto, len) < 0){
+		printf("can't bind a socket:%d\n",errno);
+		close(fd);
+		return(-1);
+	}
+	if(getsockname(fd,(struct sockaddr *)&got,&len) < 0){
+		printf("get sockname failed err:%d\n",errno);
+		close(fd);
+		return(-1);
+	}	
+	printf("fd uses port %d\n",ntohs(got.sin_port));
+	if (listen(fd, 100) == -1) {
+		printf("listen err: %d\n", errno);
+		close(fd);
+		return(-1);
+	}
+	/* enable all event notifications */
+	event.sctp_data_io_event = 1;
+	event.sctp_association_event = 1;
+	event.sctp_address_event = 1;
+	event.sctp_send_failure_event = 1;
+	event.sctp_peer_error_event = 1;
+	event.sctp_shutdown_event = 1;
+	event.sctp_partial_delivery_event = 1;
+	event.sctp_adaptation_layer_event = 1;
+	if (setsockopt(fd, IPPROTO_SCTP, 
+		       SCTP_EVENTS, &event, 
+		       sizeof(event)) != 0) {
+		printf("Gak, can't set events errno:%d\n",errno);
+		exit(0);
+	}
+	printf("to process\n");
+	process(fd,magic);
+	return(0);
+}
+
diff --git a/src/apps/sctp_darn.c b/src/apps/sctp_darn.c
new file mode 100644
index 0000000..bcfb822
--- /dev/null
+++ b/src/apps/sctp_darn.c
@@ -0,0 +1,2414 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999 Cisco
+ * Copyright (c) 1999, 2000, 2001 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>
+ *    Karl Knutson <karl@athena.chicago.il.us>
+ *    Hui Huang <hui.huang@nokia.com>
+ *    Daisy Chang <daisyc@us.ibm.com>
+ *    Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a userspace test application for the SCTP kernel 
+ * implementation state machine.  It is vaguely inspired by Stevens'
+ * program "sock".
+ *
+ * It has the limited ability to send messages and to listen for messages
+ * sent via SCTP.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+//#define _GNU_SOURCE
+#include <getopt.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <sys/poll.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <net/if.h>
+#include <netinet/sctp.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include "sctp_darn.h"
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+#define GEN_DATA_FIRST	0x21
+#define GEN_DATA_LAST	0x7e
+
+/* 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])
+
+/* These are the global options.  */
+char *local_host = NULL;
+int local_port = 0;
+char *remote_host = NULL;
+int remote_port = 0;
+command_t command = COMMAND_NONE;
+struct sockaddr *bindx_add_addrs = NULL;
+int bindx_add_count = 0;
+struct sockaddr *bindx_rem_addrs = NULL;
+int bindx_rem_count = 0;
+struct sockaddr *connectx_addrs = NULL;
+int connectx_count = 0;
+int interactive_mode = 0;
+int poll_skn = 0;
+int nonblocking = 0;
+int opt_space = 0;
+char gen_data = GEN_DATA_FIRST;
+char *inter_outbuf = NULL;
+int inter_outlen = 0;
+int inter_sk = 0;
+int poll_snd_size = 0;
+int use_poll = 0;
+int socket_type = SOCK_SEQPACKET;
+sctp_assoc_t associd = 0;
+int echo = 0;
+char *interface = "eth0";
+int if_index = 0;
+sockaddr_storage_t remote_addr;
+sa_family_t ra_family;	/* What family is remote_addr? */
+int ra_len = 0;		/* How long is remote_addr? */
+void *ra_raw;		/* This is the addr part of remote_addr. */
+int new_connection = 1;
+
+enum inter_cmd_num {
+	INTER_SND = 0,
+	INTER_RCV,
+	INTER_SNDBUF,
+	INTER_RCVBUF,
+	INTER_BINDX_ADD,
+	INTER_BINDX_REM,
+	INTER_SET_PRIM,
+	INTER_SET_PEER_PRIM,
+	INTER_SHUTDOWN,
+	INTER_ABORT,
+	INTER_NODELAY,
+	INTER_MAXSEG,
+	INTER_HEARTBEAT,
+	INTER_GET_STATS
+};
+
+enum shutdown_type {
+	SHUTDOWN_ABORT = 0,
+	SHUTDOWN_SHUTDOWN
+};
+
+struct inter_entry {
+	char *cmd;
+	int cmd_num;
+};
+
+struct inter_entry inter_commands[] = {
+	{"snd", INTER_SND},
+	{"rcv",	INTER_RCV},
+	{"sndbuf", INTER_SNDBUF},
+	{"rcvbuf", INTER_RCVBUF},
+	{"bindx-add", INTER_BINDX_ADD},
+	{"bindx-rem", INTER_BINDX_REM},
+	{"primary", INTER_SET_PRIM},
+	{"peer_primary", INTER_SET_PEER_PRIM},
+	{"shutdown", INTER_SHUTDOWN},
+	{"abort", INTER_ABORT},
+	{"nodelay", INTER_NODELAY},
+	{"maxseg", INTER_MAXSEG},
+	{"heartbeat", INTER_HEARTBEAT},
+	{"stats", INTER_GET_STATS},
+	{NULL, -1},
+};
+
+#define POLL_SK_MAX 	256	/* The max number of sockets to select/poll. */
+int poll_sks[POLL_SK_MAX];		/* The array for using select(). */
+struct pollfd poll_fds[POLL_SK_MAX];	/* The array for using poll().  */
+#define POLL_SND_SIZE	16384	/* Default message size in the poll mode. */
+
+
+struct sockaddr *append_addr(const char *parm, struct sockaddr *addrs,
+			     int *ret_count) ;
+int build_endpoint(char *argv0, int portnum);
+static int parse_inter_commands(char *, char *, int);
+static void snd_func(char *);
+static void sndbuf_func(char *, int, int, int);
+static void rcvbuf_func(char *, int, int, int);
+static struct sockaddr *get_bindx_addr(char *, int *);
+static int bindx_func(char *, int, struct sockaddr *, int, int, int);
+static int connectx_func(char *, int, struct sockaddr *, int);
+static void  primary_func(char *, int, char *, int);
+static void  peer_primary_func(char *, int, char *, int);
+static void  spp_hb_demand_func(char *, int, char *, int);
+static int nodelay_func(char *, int, int val, int set);
+static int maxseg_func(char *, int, int val, int set);
+static int shutdown_func(char *argv0, int *skp, int shutdown_type);
+static int get_assocstats_func(int, sctp_assoc_t);
+static int test_sk_for_assoc(int sk, sctp_assoc_t assoc_id);
+static char * gen_message(int);
+static sctp_assoc_t test_recv_assoc_change(int);
+static sctp_assoc_t test_verify_assoc_change(struct msghdr *);
+void print_addr_buf(void * laddrs, int n_laddrs);
+int print_sockaddr(struct sockaddr *sa_addr);
+
+int
+main(int argc, char *argv[]) {
+	int sk = -1;
+	int error = 0;
+	int i;
+
+	signal(SIGPIPE, SIG_IGN);
+
+	parse_arguments(argc, argv);
+
+	switch(command) {
+	case COMMAND_NONE:
+		fprintf(stderr, "%s: Please specify a command.\n",
+			argv[0]);
+		exit(1);
+		break;
+	case COMMAND_LISTEN:
+		sk = build_endpoint(argv[0], local_port);
+		error = command_listen(argv[0], sk);
+		break;
+	case COMMAND_SEND:
+		sk = build_endpoint(argv[0], local_port);
+		error = command_send(argv[0], &sk);
+		break;
+	case COMMAND_POLL:
+		if (use_poll) {
+			for (i = 0; i < poll_skn; i++) {
+				poll_fds[i].fd = build_endpoint(argv[0],
+					local_port + i);
+			}
+		} else {
+			for (i = 0; i < poll_skn; i++) {
+				poll_sks[i] = build_endpoint(argv[0],
+					local_port + i);
+			}
+		}
+		error = command_poll(argv[0]);
+		break;
+	default:
+		fprintf(stderr, "%s: illegal command %d\n",
+			argv[0], command);
+		exit(1);
+	}
+
+	/* Shut down the link.  */
+	if (COMMAND_POLL != command) {
+		close(sk);
+	} else {
+		/* Shutdown all links.  */
+		if (use_poll) {
+			for (i = 0; i < poll_skn; i++) {
+				close(poll_fds[i].fd);
+			}
+		} else {
+			for (i = 0; i < poll_skn; i++) {
+				close(poll_sks[i]);
+			}
+		}
+	}
+
+	exit(error);
+}
+
+/********************************************************************
+ * 2nd Level Abstractions
+ ********************************************************************/
+
+void
+parse_arguments(int argc, char *argv[]) {
+	int option_index = 0;
+	int c;
+	struct sockaddr *tmp_addrs = NULL;
+
+	static struct option long_options[] = {
+		{"local",	1, 0, 1},
+		{"local-port",	1, 0, 2},
+		{"remote",	1, 0, 3},
+		{"remote-port",	1, 0, 4},
+		{"listen",	0, 0, 10},
+		{"send",	0, 0, 11},
+		{"bindx-add",	1, 0, 15},
+		{"bindx-rem",	1, 0, 16},
+		{"use-poll",	0, 0, 20},
+		{"echo",        0, 0, 'e'},
+		{"interface",   optional_argument, 0, 5,},
+		{"connectx",    1, 0, 17},
+		{0,		0, 0, 0}
+	};
+
+	/* Parse the arguments.  */
+	while (1) {
+		c = getopt_long (argc, argv, "B:H:IP:b:h:i:p:lm:nstz:ec:",
+				 long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 0:
+			printf("option %s", long_options[option_index].name);
+			if (optarg) {
+				printf(" with arg %s", optarg);
+			}
+			printf("\n");
+			break;
+		case 1:		/* local host */
+		case 'H':
+			local_host = optarg;
+			break;
+		case 2:		/* local port */
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case 3:		/* remote host */
+		case 'h':
+			remote_host = optarg;
+			break;
+		case 4:		/* remote port */
+		case 'p':
+			remote_port = atoi(optarg);
+			break;
+		case 5:  /* interface for sin6_scope_id */
+			if (optarg)
+				interface = optarg;
+			if_index = if_nametoindex(interface);
+			if (!if_index) {
+				printf("Interface %s unknown\n", interface);
+				exit(1);
+			}
+			break;
+			/* COMMANDS */
+		case 10:	/* listen */
+		case 'l':
+			if (command) {
+				fprintf(stderr,
+					"%s: pick ONE of listen or send\n",
+					argv[0]);
+				exit(1);
+			} else {
+				command = COMMAND_LISTEN;
+			}
+			break;
+
+		case 11:	/* send */
+		case 's':
+			if (command) {
+				fprintf(stderr,
+					"%s: pick ONE of listen or send\n",
+					argv[0]);
+				exit(1);
+			} else {
+				command = COMMAND_SEND;
+			}
+			break;
+
+		case 15:		/* bindx_add */
+		case 'B':
+			tmp_addrs =
+				append_addr(optarg, bindx_add_addrs,
+					    &bindx_add_count);
+			if (NULL == tmp_addrs) {
+				/* We have no memory, so keep fprintf()
+				 * from trying to allocate more.
+				 */
+				fprintf(stderr, "No memory to add ");
+				fprintf(stderr, "%s\n", optarg);
+				exit(2);
+			}
+			bindx_add_addrs = tmp_addrs;
+
+			break;
+
+		case 16:		/* bindx_rem */
+		case 'b':
+			tmp_addrs =
+				append_addr(optarg, bindx_rem_addrs,
+					    &bindx_rem_count);
+			if (NULL == tmp_addrs) {
+				/* We have no memory, so keep fprintf()
+				 * from trying to allocate more.
+				 */
+				fprintf(stderr, "No memory to add ");
+				fprintf(stderr, "%s\n", optarg);
+				exit(2);
+			}
+			bindx_rem_addrs = tmp_addrs;
+			break;
+		case 17:		/* connectx */
+		case 'c':
+			tmp_addrs =
+				append_addr(optarg, connectx_addrs,
+					    &connectx_count);
+			if (NULL == tmp_addrs) {
+				/* We have no memory, so keep fprintf()
+				 * from trying to allocate more.
+				 */
+				fprintf(stderr, "No memory to add ");
+				fprintf(stderr, "%s\n", optarg);
+				exit(2);
+			}
+			connectx_addrs = tmp_addrs;
+			break;
+		case 20:		/* use-poll */
+			use_poll = 1;
+			break;
+		case 'I':
+			interactive_mode = 1;
+			break;
+		case 'i':
+			command = COMMAND_POLL;
+			poll_skn = atoi(optarg);
+			if (poll_skn <= 0 || poll_skn > POLL_SK_MAX) {
+				fprintf(stderr, "Too many sockets for ");
+				fprintf(stderr, "for polling\n");
+				exit(2);
+			}
+			break;
+		case 'm':
+			opt_space = atoi(optarg);
+			break;
+		case 'n':
+			nonblocking = 1;
+			break;
+		case 't':
+			socket_type = SOCK_STREAM;
+			break;
+		case 'z':
+			poll_snd_size = atoi(optarg);
+			if (poll_snd_size <= 0) {
+				fprintf(stderr, "Bad message size.\n");
+				exit(2);
+			}
+			break;
+		case 'e':
+			echo = 1;
+			break;
+		case '?':
+			usage(argv[0]);
+			exit(1);
+
+		default:
+			printf ("%s: unrecognized option 0%c\n",
+				argv[0], c);
+			usage(argv[0]);
+			exit(1);
+		}
+	}
+
+	if (optind < argc)
+	{
+		fprintf(stderr, "%s: non-option arguments are illegal: ",
+			argv[0]);
+		while (optind < argc)
+			fprintf(stderr, "%s ", argv[optind++]);
+		fprintf (stderr, "\n");
+		usage(argv[0]);
+		exit(1);
+	}
+
+
+	if (NULL == local_host) {
+		fprintf(stderr, "%s: You MUST provide a local host.\n",
+			argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (command == COMMAND_SEND && NULL == remote_host
+	    && connectx_count == 0) {
+		fprintf(stderr, "%s: You MUST provide a remote host for sending.\n",
+			argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (remote_host != NULL && connectx_count != 0) {
+		fprintf(stderr, "%s: You can not provide both -h and -c options.\n",
+			argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+} /* parse_arguments() */
+
+/* Set up the local endpoint.  */
+int
+build_endpoint(char *argv0, int portnum)
+{
+	int retval;
+	struct hostent *hst;
+	sockaddr_storage_t local_addr;
+	sa_family_t la_family;	/* What family is local_addr? */
+	int la_len;		/* How long is local_addr? */
+	void *la_raw;		/* This is the addr part of local_addr. */
+	int error;
+	struct sctp_event_subscribe subscribe;
+
+	/* Get the transport address for the local host name.  */
+	hst = gethostbyname(local_host);
+	if (hst == NULL) {
+		hst = gethostbyname2(local_host, AF_INET6);
+	}
+
+	if (hst == NULL || hst->h_length < 1) {
+		fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host);
+		exit(1);
+	}
+
+	la_family = hst->h_addrtype;
+	switch (la_family) {
+	case AF_INET:
+		la_len = sizeof(local_addr.v4);
+		la_raw = &local_addr.v4.sin_addr;
+		local_addr.v4.sin_port = htons(portnum);
+		local_addr.v4.sin_family = AF_INET;
+		break;
+	case AF_INET6:
+		la_len = sizeof(local_addr.v6);
+		la_raw = &local_addr.v6.sin6_addr;
+		local_addr.v6.sin6_port = htons(portnum);
+		local_addr.v6.sin6_family = AF_INET6;
+		local_addr.v6.sin6_scope_id = if_index;
+		break;
+	default:
+		fprintf(stderr, "Invalid address type.\n");
+		exit(1);
+		break;
+	}
+	memcpy(la_raw, hst->h_addr_list[0], hst->h_length);
+
+	/* Create the local endpoint.  */
+	retval = socket(la_family, socket_type, IPPROTO_SCTP);
+	if (retval < 0) {
+		fprintf(stderr, "%s: failed to create socket:  %s.\n",
+			argv0, strerror(errno));
+		exit(1);
+	}
+
+	if (SOCK_SEQPACKET == socket_type) {
+		memset(&subscribe, 0, sizeof(subscribe));
+		subscribe.sctp_data_io_event = 1;
+		subscribe.sctp_association_event = 1;
+		error = setsockopt(retval, SOL_SCTP, SCTP_EVENTS,
+				   (char *)&subscribe, sizeof(subscribe));
+		if (error) {
+			fprintf(stderr, "SCTP_EVENTS: error: %d\n", error);
+			exit(1);
+		}
+	}
+
+	/* Bind this socket to the test port.  */
+	error = bind(retval, &local_addr.sa, la_len);
+	if (error != 0) {
+		fprintf(stderr, "%s: can not bind to %s:%d: %s.\n",
+			argv0, local_host, portnum,
+			strerror(errno));
+		exit(1);
+	}
+
+	/* Do we need to do bindx() to add any additional addresses? */
+	if (bindx_add_addrs) {
+		if (0 != bindx_func(argv0, retval, bindx_add_addrs,
+			bindx_add_count, SCTP_BINDX_ADD_ADDR, portnum)) {
+			fprintf(stderr, "bindx_func (add) failed.\n");
+			exit(1);
+		}
+	} /* if (bindx_add_addrs) */
+
+	/* Do we need to do bindx() to remove any bound addresses? */
+	if (bindx_rem_addrs) {
+		if (0 != bindx_func(argv0, retval, bindx_rem_addrs,
+			bindx_rem_count, SCTP_BINDX_REM_ADDR, portnum)) {
+			fprintf(stderr, "bindx_func (remove) failed.\n");
+			exit(1);
+		}
+	} /* if (bindx_rem_addrs) */
+
+	/* Do we want to run in the non-blocking mode? */
+	if (nonblocking) {
+		error = fcntl(retval, F_SETFL, O_NONBLOCK);
+		if (error != 0) {
+			fprintf(stderr, "%s: error fcntl: %s.\n",
+				argv0, strerror(errno));
+			exit(1);
+		}
+	}
+
+	if (opt_space) {
+		sndbuf_func(argv0, retval, opt_space, 1);
+		rcvbuf_func(argv0, retval, opt_space, 1);
+	}
+
+	return retval;
+
+} /* build_endpoint() */
+
+/* Convenience structure to determine space needed for cmsg. */
+typedef union {
+	struct sctp_initmsg init;
+	struct sctp_sndrcvinfo sndrcvinfo;
+} _sctp_cmsg_data_t;
+
+
+/* Listen on the socket, printing out anything that arrives.  */
+int
+command_listen(char *argv0, int sk)
+{
+	char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+	struct iovec iov;
+	struct msghdr inmessage;
+	sockaddr_storage_t msgname;
+	char message[REALLY_BIG];
+	int done = 0;
+	int error;
+	int c;
+	int recvsk = 0;
+
+ 	/* Mark sk as being able to accept new associations */
+	error = listen(sk, 5);
+	if (error != 0) {
+		printf("\n\n\t\tlisten Failure:  %s.\n\n\n",
+		       strerror(errno));
+		exit(1);
+	}
+
+	if (nonblocking) {
+		if (!interactive_mode) {
+			printf("Use -I for interactive mode with");
+		       printf("	-n nonblocking\n");
+		       exit(1);
+		 }
+	}
+
+	/* Initialize the global value for interactive mode functions.  */
+	if (interactive_mode) {
+		inter_sk = sk;
+	}
+
+	/* Initialize inmessage with enough space for DATA... */
+	memset(&inmessage, 0, sizeof(inmessage));
+	if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		printf("%s: Can't allocate memory.\n", argv0);
+		exit(1);
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+	inmessage.msg_name = &msgname;
+	inmessage.msg_namelen = sizeof(msgname);
+
+	printf("%s listening...\n", argv0);
+	/* Get the messages sent */
+	done = 0;
+	while (!done) {
+		if (interactive_mode) {
+			/* Read from the user.  */
+			if (remote_host) {
+				printf("%s:%d-%s:%d Interactive mode> ",
+					local_host, local_port, remote_host,
+					remote_port);
+			} else {
+				printf("%s:%d-", local_host, local_port);
+				if (associd) {
+					print_sockaddr(&remote_addr.sa);
+				} else {
+					printf("?:%d", remote_port);
+				}
+				printf(" Interactive mode> ");
+			}
+			fflush(stdout);
+			if (NULL == fgets(message, REALLY_BIG, stdin)) {
+				done = 1;
+				continue;
+			}
+
+			if (0 <= (c = parse_inter_commands(argv0, message,
+				0))) {
+				if (INTER_RCV != c) {
+					continue;
+				}
+			} else {
+				continue;
+			}
+		}
+
+		if (socket_type == SOCK_STREAM) {
+			socklen_t len = 0;
+
+			if (!recvsk) {
+				if ((recvsk = accept(sk, NULL, &len)) < 0) {
+					fprintf(stderr, "%s: error: %s.\n",
+						argv0, strerror(errno));
+					exit(1);
+				}
+			}
+
+		} else {
+			recvsk = sk;
+		}
+
+		error = recvmsg(recvsk, &inmessage, MSG_WAITALL);
+		if (error < 0) {
+			if (nonblocking && (EAGAIN == errno)) {
+				error = 0;
+				continue;
+			}
+
+			if (socket_type == SOCK_STREAM) {
+				if (ENOTCONN != errno)
+					break;
+				printf("No association is present now!!\n");
+				close(recvsk);
+				recvsk = 0;
+				continue;
+			}
+			break;
+		}
+
+		/* Update the associd when a notification is received on a
+		 * UDP-style socket.
+		 */
+		if (inmessage.msg_flags & MSG_NOTIFICATION)
+			associd = test_verify_assoc_change(&inmessage);
+
+		if (echo) {
+			if( !(MSG_NOTIFICATION & inmessage.msg_flags)) {
+				if (sendto(recvsk, inmessage.msg_iov->iov_base,
+					   error, 0,
+					   (struct sockaddr *)&msgname,
+					   sizeof(msgname)) == -1) {
+					fprintf(stderr, "%s: error: %s.\n",
+						argv0, strerror(errno));
+					exit(1);
+				}
+			}
+		}
+
+		test_print_message(sk, &inmessage, error);
+
+		inmessage.msg_control = incmsg;
+		inmessage.msg_controllen = sizeof(incmsg);
+		inmessage.msg_name = &msgname;
+		inmessage.msg_namelen = sizeof(msgname);
+		iov.iov_len = REALLY_BIG;
+
+		/* Verify that the association is no longer present.  */
+		if (0 != test_sk_for_assoc(recvsk, associd)) {
+			printf("No association is present now!!\n");
+			if (socket_type == SOCK_STREAM) {
+				close(recvsk);
+				recvsk = 0;
+			}
+		}
+	}
+
+	if (error < 0) {
+		fprintf(stderr, "%s: error: %s.\n",
+			argv0, strerror(errno));
+		exit(1);
+	}
+
+	return error;
+
+} /* command_listen() */
+
+/* Read lines from stdin and send them to the socket.  */
+int
+command_send(char *argv0, int *skp)
+{
+	struct msghdr outmsg;
+	struct iovec iov;
+	int done = 0;
+	char message[REALLY_BIG];
+	struct hostent *hst;
+	int c;
+	struct sockaddr *addrs;
+	int msglen;
+	int error = 0;
+	int sk = *skp;
+
+	/* Set up the destination.  */
+	if (remote_host != NULL) {
+		hst = gethostbyname(remote_host);
+		if (hst == NULL) {
+			hst = gethostbyname2(remote_host, AF_INET6);
+		}
+
+		if (hst == NULL || hst->h_length < 1) {
+			fprintf(stderr, "%s: bad hostname: %s\n",
+				argv0, remote_host);
+			exit(1);
+		}
+
+		ra_family = hst->h_addrtype;
+		switch (ra_family) {
+		case AF_INET:
+			ra_len = sizeof(remote_addr.v4);
+			ra_raw = &remote_addr.v4.sin_addr;
+			remote_addr.v4.sin_port = htons(remote_port);
+			remote_addr.v4.sin_family = AF_INET;
+			break;
+		case AF_INET6:
+			ra_len = sizeof(remote_addr.v6);
+			ra_raw = &remote_addr.v6.sin6_addr;
+			remote_addr.v6.sin6_port = htons(remote_port);
+			remote_addr.v6.sin6_family = AF_INET6;
+			remote_addr.v6.sin6_scope_id = if_index;
+			break;
+		default:
+			fprintf(stderr, "Invalid address type.\n");
+			exit(1);
+			break;
+		}
+		memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
+	}
+
+	/* Initialize the global value for interactive mode functions.  */
+	if (interactive_mode) {
+		inter_sk = sk;
+	}
+
+	printf("%s ready to send...\n", argv0);
+	while (!done) {
+		/* Read from the user.  */
+		if (remote_host) {
+			if (interactive_mode) {
+				printf("%s:%d-%s:%d Interactive mode> ",
+					local_host, local_port, remote_host,
+					remote_port);
+			} else {
+				printf("%s:%d-%s:%d> ",
+				       local_host, local_port,
+				       remote_host, remote_port);
+			}
+		} else {
+			printf("%s:%d-", local_host, local_port);
+			if (associd) {
+				print_sockaddr(&remote_addr.sa);
+			} else {
+				printf("XXXXXX:%d", remote_port);
+			}
+			if (interactive_mode) {
+				printf(" Interactive mode> ");
+			} else {
+				printf("> ");
+			}
+		}
+		fflush(stdout);
+		if (NULL == fgets(message, REALLY_BIG, stdin)) {
+			done = 1;
+			continue;
+		}
+
+		if (interactive_mode) {
+			/* This is the send only agent.  */
+			if (0 <= (c = parse_inter_commands(argv0, message,
+				1))) {
+				if (INTER_SND == c) {
+					iov.iov_base = inter_outbuf;
+					msglen = inter_outlen;
+					iov.iov_len = msglen;
+
+				} else {
+					continue;
+				}
+
+			} else {
+				continue;
+			}
+		} else {
+			/* Send to our neighbor.  */
+			msglen = strlen(message) + 1;
+			iov.iov_len = msglen;
+		}
+
+		/* For a UDP-style socket, verify if an existing association
+		 * has gone. If so, receive the pending SCTP_ASSOC_CHANGE
+		 * notification.
+		 */
+		if ((SOCK_SEQPACKET == socket_type) && associd &&
+		    (0 != test_sk_for_assoc(sk, associd))) {
+			associd = test_recv_assoc_change(sk);
+			printf("Old association gone, Starting a new one!\n");
+			new_connection = 1;
+		}
+
+		if (new_connection && connectx_count != 0) {
+			/* Do a sctp_connectx() to establish a connection. */
+			error = connectx_func(argv0, sk, connectx_addrs,
+					      connectx_count);
+			if (0 != error) {
+				if (error == -2) {
+					printf("Connection refused\n");
+					if (SOCK_SEQPACKET == socket_type) {
+						associd = test_recv_assoc_change(sk);
+					}
+					continue;
+				}
+				fprintf(stderr, "connectx failed.\n");
+				exit(1);
+			}
+			if (SOCK_SEQPACKET == socket_type) {
+				associd = test_recv_assoc_change(sk);
+			} else {
+				associd = 1;
+			}
+			int rc = sctp_getpaddrs(sk, associd, &addrs);
+			if (0 >= rc) {
+				if (rc == 0) {
+					fprintf(stderr, "sctp_getpaddrs failed, no peers.\n");
+				} else {
+					fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno);
+				}
+				exit(1);
+			}
+			printf("New connection, peer addresses\n");
+			print_addr_buf(addrs, rc);
+			ra_family = addrs[0].sa_family;
+			switch (ra_family) {
+			case AF_INET:
+				ra_len = sizeof(remote_addr.v4);
+				break;
+			case AF_INET6:
+				ra_len = sizeof(remote_addr.v6);
+				break;
+			default:
+				fprintf(stderr, "Invalid address type.\n");
+				exit(1);
+			}
+			memcpy(&remote_addr, &addrs[0], ra_len);
+			sctp_freepaddrs(addrs);
+			new_connection = 0;
+		}
+
+		do {
+			if (SOCK_SEQPACKET == socket_type ||
+			    (connectx_count == 0 && new_connection)) {
+				/* Initialize the message struct we use to pass
+				 * messages to the remote socket.
+				 */
+				if (!interactive_mode) {
+					iov.iov_base = message;
+					iov.iov_len = msglen;
+				}
+				outmsg.msg_iov = &iov;
+				outmsg.msg_iovlen = 1;
+				outmsg.msg_control = NULL;
+				outmsg.msg_controllen = 0;
+				outmsg.msg_name = &remote_addr;
+				outmsg.msg_namelen = ra_len;
+				outmsg.msg_flags = 0;
+
+				error = sendmsg(sk, &outmsg, 0);
+			} else {
+				error = send(sk, message, msglen, 0);
+				if (error == -1 && errno == EPIPE) {
+					error = close(sk);
+					if (error != 0) {
+						fprintf(stderr, "close failed %s\n", strerror(errno));
+						exit(1);
+					}
+					*skp = sk = build_endpoint(argv0, local_port);
+					break;
+				}
+			}
+
+			if (error != msglen) {
+				fprintf(stderr, "%s: error: %s.\n",
+					argv0, strerror(errno));
+				if (nonblocking && EAGAIN == errno) {
+					if (interactive_mode) {
+						break;
+					}
+					continue;
+				}
+				exit(1);
+			} else {
+				break;
+			}
+		} while (error != msglen);
+
+		/* If this is the first message sent over a UDP-style socket,
+		 * get the associd from the SCTP_ASSOC_CHANGE notification.
+		 */
+		if ((SOCK_SEQPACKET == socket_type) && (0 == associd))
+			associd = test_recv_assoc_change(sk);
+
+		/* Verify there is no association.  */
+		if (0 != test_sk_for_assoc(sk, associd)) {
+			printf("No association is present now!!\n");
+			new_connection = 1;
+		} else {
+			if (new_connection) {
+				int rc = sctp_getpaddrs(sk, associd, &addrs);
+				if (0 >= rc) {
+					if (rc == 0) {
+						fprintf(stderr, "sctp_getpaddrs failed, no peers.\n");
+					} else {
+						fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno);
+					}
+					exit(1);
+				}
+				printf("New connection, peer addresses\n");
+				print_addr_buf(addrs, rc);
+				sctp_freepaddrs(addrs);
+				new_connection = 0;
+			}
+		}
+
+		/* Clean up.  */
+		if (interactive_mode) {
+			free(inter_outbuf);
+			inter_outbuf = NULL;
+		}
+	} /* while(!done) */
+
+	return error;
+
+} /* command_send() */
+
+/* Listen on the array of sockets, printing out anything that arrives.  */
+int
+command_poll(char *argv0)
+{
+	char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+	struct iovec iov;
+	struct msghdr inmessage;
+	int done = 0;
+	int error = 0;
+	int max_fd, i, ret;
+	int size;
+	fd_set *ibitsp = NULL;
+	fd_set *obitsp = NULL;
+	fd_set *xbitsp = NULL;
+
+	struct msghdr outmsg;
+	struct hostent *hst;
+	int msglen;
+	int temp_fd, temp_set;
+
+
+
+	/* If a remote host is specified, initialize the destination. */
+	if (remote_host) {
+		/* Set up the destination.  */
+		hst = gethostbyname(remote_host);
+		if (hst == NULL) {
+			hst = gethostbyname2(remote_host, AF_INET6);
+		}
+
+		if (hst == NULL || hst->h_length < 1) {
+			fprintf(stderr, "%s: bad hostname: %s\n",
+				argv0, remote_host);
+			exit(1);
+		}
+
+		ra_family = hst->h_addrtype;
+		switch (ra_family) {
+		case AF_INET:
+			ra_len = sizeof(remote_addr.v4);
+			ra_raw = &remote_addr.v4.sin_addr;
+			remote_addr.v4.sin_port = htons(remote_port);
+			remote_addr.v4.sin_family = AF_INET;
+			break;
+		case AF_INET6:
+			ra_len = sizeof(remote_addr.v6);
+			ra_raw = &remote_addr.v6.sin6_addr;
+			remote_addr.v6.sin6_port = htons(remote_port);
+			remote_addr.v6.sin6_family = AF_INET6;
+			remote_addr.v6.sin6_scope_id = if_index;
+			break;
+		default:
+			fprintf(stderr, "Invalid address type.\n");
+			exit(1);
+			break;
+		}
+		memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
+
+		/* Initialize the message struct we use to pass messages to
+	 	 * the remote socket.
+	 	 */
+		outmsg.msg_iov = &iov;
+		outmsg.msg_iovlen = 1;
+		outmsg.msg_control = NULL;
+		outmsg.msg_controllen = 0;
+		outmsg.msg_name = &remote_addr;
+		outmsg.msg_namelen = ra_len;
+		outmsg.msg_flags = 0;
+	}
+
+
+	max_fd = -1;
+
+	/* Set all of the sockets to be ready for listening. */
+	if (use_poll) {
+		for (i = 0; i < poll_skn; i++) {
+			error = listen(poll_fds[i].fd, 1);
+			if (error != 0) {
+				printf("%s: Listen failed on socket number ",
+					argv0);
+				printf("%d: %s.\n", i, strerror(errno));
+				exit(1);
+			}
+		}
+		printf("%s listening...\n", argv0);
+	} else {
+		for (i = 0; i < poll_skn; i++) {
+			error = listen(poll_sks[i], 1);
+			if (error != 0) {
+				printf("%s: Listen failed on socket number ",
+					argv0);
+				printf("%d: %s.\n", i, strerror(errno));
+				exit(1);
+			}
+			if (poll_sks[i] > max_fd) {
+				max_fd = poll_sks[i];
+			}
+		}
+		printf("%s listening...\n", argv0);
+
+		size = howmany(max_fd + 1, NFDBITS) * sizeof(fd_mask);
+		if ((ibitsp = (fd_set *)malloc(size)) == NULL) {
+			printf("%s: Can't allocate memory.\n", argv0);
+			exit(1);
+		}
+		if ((obitsp = (fd_set *)malloc(size)) == NULL) {
+			printf("%s: Can't allocate memory.\n", argv0);
+			exit(1);
+		}
+		if ((xbitsp = (fd_set *)malloc(size)) == NULL) {
+			printf("%s: Can't allocate memory.\n", argv0);
+			exit(1);
+		}
+		memset(ibitsp, 0, size);
+		memset(obitsp, 0, size);
+		memset(xbitsp, 0, size);
+	}
+
+
+	/* Initialize inmessage with enough space for DATA... */
+	memset(&inmessage, 0, sizeof(inmessage));
+	if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		printf("%s: Can't allocate memory.\n", argv0);
+		exit(1);
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+
+	done = 0;
+	/* Set the default send message size.  */
+	if (!poll_snd_size) {
+		poll_snd_size = POLL_SND_SIZE;
+	}
+
+	while (!done) {
+
+		if (use_poll) {
+			for (i = 0; i < poll_skn; i++) {
+				poll_fds[i].events = POLLIN;
+			}
+			if (remote_host) {
+				/* Poll output on the first socket.  */
+				poll_fds[0].events |= POLLOUT;
+			}
+
+			if ((ret = poll(poll_fds, poll_skn, -1))) {
+				if (ret == -1) {
+					break;
+				}
+			}
+		} else {
+			for (i = 0; i < poll_skn; i++) {
+				FD_SET(poll_sks[i], ibitsp);
+				FD_SET(poll_sks[i], xbitsp);
+			}
+			if (remote_host) {
+				/* Only select output on the first socket.  */
+				FD_SET(poll_sks[0], obitsp);
+			}
+
+
+			if ((ret = select(max_fd + 1, ibitsp, obitsp, xbitsp,
+				(struct timeval *)0)) < 0) {
+				if (ret == -1) {
+					break;
+				}
+			}
+
+		}
+
+		if (remote_host) {
+			if (use_poll) {
+				temp_set = poll_fds[0].revents & POLLOUT;
+				temp_fd = poll_fds[0].fd;
+			} else {
+				temp_set = FD_ISSET(poll_sks[0], obitsp);
+				temp_fd = poll_sks[0];
+			}
+
+			if (temp_set) {
+				inter_outbuf = gen_message(poll_snd_size);
+				if (!inter_outbuf) {
+					fprintf(stderr,
+					"Cannot allocate out message.\n");
+					exit(1);
+				}
+				iov.iov_base = inter_outbuf;
+				msglen = poll_snd_size;
+				iov.iov_len = msglen;
+
+				error = sendmsg(temp_fd, &outmsg, 0);
+				fprintf(stderr,
+					"sent a message, msglen = %d\n",
+					msglen);
+
+				if (error != msglen) {
+					fprintf(stderr, "%s: error: %s.\n",
+						argv0, strerror(errno));
+					if ((!nonblocking) ||
+					    (EAGAIN != errno)) {
+						exit(1);
+					}
+				}
+
+				/* Clean up.  */
+				free(inter_outbuf);
+				inter_outbuf = NULL;
+			}
+
+		} /* while(!done) */
+
+		for (i = 0; !done && (i < poll_skn); i++) {
+			if (use_poll) {
+				temp_set = poll_fds[i].revents & POLLIN;
+				temp_fd = poll_fds[i].fd;
+			} else {
+				temp_set = FD_ISSET(poll_sks[i], ibitsp);
+				temp_fd = poll_sks[i];
+			}
+			if (temp_set) {
+				error = recvmsg(temp_fd, &inmessage,
+					MSG_WAITALL);
+				if (error < 0) {
+					if ((EAGAIN == errno)) {
+						error = 0;
+						continue;
+					}
+					else {
+						fprintf(stderr,
+							"%s: error: %s.\n",
+							argv0,
+							strerror(errno));
+						exit(1);
+					}
+				}
+				test_print_message(temp_fd, &inmessage, error);
+				inmessage.msg_control = incmsg;
+				inmessage.msg_controllen = sizeof(incmsg);
+				iov.iov_len = REALLY_BIG;
+			}
+
+			/* Update the associd when a notification is received
+			 * on a UDP-style socket.
+			 */
+			if (inmessage.msg_flags & MSG_NOTIFICATION)
+				associd = test_verify_assoc_change(&inmessage);
+
+			/* Verify there is no association. */
+			if (0 != test_sk_for_assoc(poll_sks[i], associd)) {
+				printf("No association is present in sk "
+				       "No.%d now!!\n",i);
+			}
+		}
+
+	}
+
+	if (!use_poll) {
+		free(ibitsp);
+		free(obitsp);
+		free(xbitsp);
+	}
+
+	return error;
+
+} /* command_poll() */
+
+/********************************************************************
+ * 3rd Level Abstractions
+ ********************************************************************/
+
+#define FPS(arg) fprintf(stderr, arg)
+
+void
+usage(char *argv0)
+{
+	/*
+	 * The bindx options, --bindx-add and --bindx-rem, are added to
+	 *
+	 * 1. provide first testcases for the new bindx system call
+	 *
+	 * 2. continue to grow sctp_darn with more functions and
+	 * features so it will be equivalent to the "sock" tool for
+	 * TCP as for SCTP.
+	 *
+	 * FIXME -
+	 *
+	 * It is not very effective to use these two options in the
+	 * current command line mode of sctp_darn. For example, the
+	 * --bindx-rem option can only be used in conjunction with the
+	 * --bindx-add simply to test the function in the kernel
+	 * path. Ideally, bindx needs to be tested by a tool which
+	 * provides an interactive mode for users to change parameters
+	 * and configuration dynamically with existing endpoints and
+	 * associations.
+	 */
+	fprintf(stderr, "Usage: %s -H <localhost> -P <localport> "
+		"[-h <remotehost>] [-p <remoteport>] -l|s\n"
+		" -H, --local\t\tspecify one of the local addresses,\n"
+		" -P, --local-port\tspecify the port number for local addresses,\n"
+		" -h, --remote\t\tspecify the peer address,\n"
+		" -p, --remote-port\tspecify the port number for the peer address,\n"
+		" -l, --listen\t\tprint messages received from the peer,\n"
+		" -s, --send\t\tsend messages to the peer,\n"
+		" -B, --bindx-add"
+		"\tadd the specified address(es) as additional bind\n"
+		"\t\t\taddresses to the local socket. Multiple addresses can\n"
+		"\t\t\tbe specified by using this argument multiple times.\n"
+		"\t\t\tFor example, '-B 10.0.0.1 -B 20.0.0.2'.\n"
+		" -b, --bindx-rem"
+		"\tremove the specified address(es) from the bind\n"
+		"\t\t\taddresses of the local socket. Multiple addresses can\n"
+		"\t\t\tbe specified by using this argument multiple times.\n"
+		"\t\t\tFor example, '-b 10.0.0.1 -b 20.0.0.2'.\n"
+		" -c, --connectx"
+		"\t\tuse the specified address(es) for connection to the\n"
+		"\t\t\tpeer socket. Multiple addresses can be specified by\n"
+		"\t\t\tusing this argument multiple times.\n"
+		"\t\t\tFor example, '-c 10.0.0.1 -c 20.0.0.2'.\n"
+		"\t\t\tThis option is incompatible with the -h option.\n"
+		" -I\t\t\tuse the interactive mode.\n"
+		" -i\t\t\tsetup the specified number of endpoints by using the\n"
+		"\t\t\tspecified local host (-H) and local port (-P). The port\n"
+        	"\t\t\tnumber will be incremented by one for each additional\n"
+        	"\t\t\tendpoint.  All of these endpoints will be listening.\n"
+		"\t\t\tIf a remote host (-h) and a remote port are also\n"
+		"\t\t\tspecified, the first endpoint will start sending fixed\n"
+		"\t\t\tsized messages to the remote host.\n"
+		" -m\t\t\tspecify the sockopt sndbuf/rcvbuf size.\n"
+		" -n\t\t\tset the socket(s) to be in the non-blocking mode.\n"
+		"\t\t\tcollect messages from stdin and deliver them to the\n"
+		"\t\t\tpeer,\n"
+		"--use-poll\t\tuse system call poll() for polling among the\n"
+		"\t\t\tnumber of endpoints specified by the -i option. Without\n"
+		"\t\t\tthis option, select() would be used as default.\n"
+		" -t\t\t\tuse SOCK_STREAM tcp-style sockets.\n"
+		" -z\t\t\tspecify the message size to be sent.  The default\n"
+		"\t\t\tmessage size generated would be 16K.\n"
+		" --interface=\"ifname\"\tselect interface for sin6_scope_id.\n",
+		argv0);
+}
+
+
+/* This function checks messages to see if they are of type 'event'
+ * and if they are well-formed.
+ */
+int
+user_test_check_message(struct msghdr *msg,
+                        int controllen,
+                        sctp_cmsg_t event)
+{
+
+
+	if (msg->msg_controllen != controllen) {
+		fprintf(stderr,
+			"Got control structure of length %zu, not %d\n",
+			msg->msg_controllen, controllen);
+		exit(1);
+	}
+	if (controllen > 0 && event != CMSG_FIRSTHDR(msg)->cmsg_type) {
+		fprintf(stderr, "Wrong kind of event: %d, not %d\n",
+			CMSG_FIRSTHDR(msg)->cmsg_type, event);
+		exit(1);
+	}
+
+	return 1;
+
+} /* user_test_check_message() */
+
+/* Add another address represented as the string 'parm' to the list
+ * addrs.  The argument count is the number of addrs on input and is
+ * adjusted for output.
+ */
+struct sockaddr *
+append_addr(const char *parm, struct sockaddr *addrs, int *ret_count)
+{
+	struct sockaddr *new_addrs = NULL;
+	void *aptr;
+	struct sockaddr *sa_addr;
+	struct sockaddr_in *b4ap;
+	struct sockaddr_in6 *b6ap;
+	struct hostent *hst4 = NULL;
+	struct hostent *hst6 = NULL;
+	int i4 = 0;
+	int i6 = 0;
+	int j;
+	int orig_count = *ret_count;
+	int count = orig_count;
+
+
+	if (!parm)
+		return NULL;
+	/* Get the entries for this host.  */
+	hst4 = gethostbyname(parm);
+	hst6 = gethostbyname2(parm, AF_INET6);
+
+	if ((NULL == hst4 || hst4->h_length < 1)
+	    && (NULL == hst6 || hst6->h_length < 1)) {
+		fprintf(stderr, "bad hostname: %s\n", parm);
+		goto finally;
+	}
+
+
+	/* Figure out the number of addresses.  */
+	if (NULL != hst4) {
+		for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) {
+			count++;
+		}
+	}
+	if (NULL != hst6) {
+		for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) {
+			count++;
+		}
+	}
+
+	/* Expand memory for the new addresses.  Assume all the addresses 
+	 * are v6 addresses.
+	 */
+	new_addrs = (struct sockaddr *)
+		realloc(addrs, sizeof(struct sockaddr_in6) * count);
+
+	if (NULL == new_addrs) {
+		count = *ret_count;
+		goto finally;
+	}
+
+	/* Skip the existing addresses. */
+	aptr = new_addrs; 
+	for (j = 0; j < orig_count; j++) {
+		sa_addr = (struct sockaddr *)aptr;
+		switch(sa_addr->sa_family) {
+		case AF_INET:
+			aptr += sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			aptr += sizeof(struct sockaddr_in6);
+			break;
+		default:
+			count = orig_count;
+			goto finally;
+		}
+	}	
+					
+	/* Put the new addresses away.  */
+	if (NULL != hst4) {
+		for (j = 0; j < i4; ++j) {
+			b4ap = (struct sockaddr_in *)aptr;
+			memset(b4ap, 0x00, sizeof(*b4ap));
+			b4ap->sin_family = AF_INET;
+			b4ap->sin_port = htons(local_port);
+			bcopy(hst4->h_addr_list[j], &b4ap->sin_addr,
+			      hst4->h_length);
+
+			aptr += sizeof(struct sockaddr_in);
+		} /* for (loop through the new v4 addresses) */
+	}
+
+	if (NULL != hst6) {
+		for (j = 0; j < i6; ++j) {
+			b6ap = (struct sockaddr_in6 *)aptr;
+			memset(b6ap, 0x00, sizeof(*b6ap));
+			b6ap->sin6_family = AF_INET6;
+			b6ap->sin6_port =  htons(local_port);
+			b6ap->sin6_scope_id = if_index;
+			bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr,
+			      hst6->h_length);
+
+			aptr += sizeof(struct sockaddr_in6);
+		} /* for (loop through the new v6 addresses) */
+	}
+
+ finally:
+
+	*ret_count = count;
+
+	return new_addrs;
+
+} /* append_addr() */
+
+static int
+parse_inter_commands(char *argv0, char *input, int snd_only)
+{
+	int i;
+	char *p;
+	int len;
+	int set = 0;
+	int val;
+	struct sockaddr *tmp_addrs = NULL;
+
+
+	p = input;
+	if (*p == '?' || *p == '\n') {
+		printf("Interactive commands:\n");
+		printf("snd=<int>        - Do a sendmsg with the specified");
+		printf(" length.\n");
+		printf("rcv=<int>        - Do a recvmsg.");
+		printf("The length is ignored for now.\n");
+		printf("bindx-add=<addr> - Add a local address");
+		printf(" with bindx. \n");
+		printf("bindx-rem=<addr> - Remove a local address");
+		printf(" with bindx. \n");
+		printf("rcvbuf=<int>     - Get/Set receive buffer size\n");
+		printf("sndbuf=<int>     - Get/Set send buffer size.\n");
+		printf("primary=<addr>   - Get/Set association's primary\n");
+		printf("peer_primary=addr- Set association's peer_primary\n");
+		printf("heartbeat=<addr> - Request a user initiated heartbeat\n");
+		printf("maxseg=<int>     - Get/Set Maximum fragment size.\n");
+		printf("nodelay=<0|1>    - Get/Set NODELAY option.\n");
+		printf("shutdown         - Shutdown the association.\n");
+		printf("abort            - Abort the association.\n");
+		printf("stats            - Print GET_ASSOC_STATS (if available in kernel).\n");
+		printf("?                - Help. Display this message.\n");
+		return -1;
+	}
+
+	for (i = 0; i < REALLY_BIG; i++) {
+		if (('=' == *p) ||
+		    ('?' == *p) ||
+		    ('\n' == *p)) {
+			if ('=' == *p) {
+				set = 1;
+			}
+			*p++ = '\0';
+			break;
+		}
+		p++;
+	}
+	if (i >= REALLY_BIG) {
+		printf("Invalid input.\n");
+		return -1;
+	}
+
+	i = 0;
+	while (NULL != inter_commands[i].cmd) {
+		if (!strcmp(input, inter_commands[i].cmd)) {
+			switch (i) {
+			case INTER_SND:
+				if (snd_only) {
+					if (*p < '0' || *p > '9') {
+						goto err_input;
+					}
+					snd_func(p);
+				} else {
+					goto err_input;
+				}
+				break;
+			case INTER_RCV:
+				if (snd_only) {
+					goto err_input;
+				}
+				break;
+			case INTER_SNDBUF:
+				if (set) {
+					if (*p < '0' || *p > '9') {
+						goto err_input;
+					}
+				}
+				len = (set) ? atoi(p) : 0;
+				sndbuf_func(argv0, inter_sk, len, set);
+				break;
+			case INTER_RCVBUF:
+				if (set) {
+					if (*p < '0' || *p > '9') {
+						goto err_input;
+					}
+				}
+				len = (set) ? atoi(p) : 0;
+				rcvbuf_func(argv0, inter_sk, len, set);
+				break;
+			case INTER_BINDX_ADD:
+				tmp_addrs = get_bindx_addr(p, &len);
+				bindx_func(argv0, inter_sk, tmp_addrs, len,
+					SCTP_BINDX_ADD_ADDR, local_port);
+				free(tmp_addrs);
+				break;
+			case INTER_BINDX_REM:
+				tmp_addrs = get_bindx_addr(p, &len);
+				bindx_func(argv0, inter_sk, tmp_addrs, len,
+					SCTP_BINDX_REM_ADDR, local_port);
+				free(tmp_addrs);
+				break;
+			case INTER_SET_PRIM:
+				primary_func(argv0, inter_sk, p, set);
+				break;
+			case INTER_SET_PEER_PRIM:
+				peer_primary_func(argv0, inter_sk, p, set);
+				break;
+			case INTER_HEARTBEAT:
+				spp_hb_demand_func(argv0, inter_sk, p, set);
+				break;
+			case INTER_SHUTDOWN:
+				shutdown_func(argv0, &inter_sk, SHUTDOWN_SHUTDOWN);
+				break;
+			case INTER_ABORT:
+				shutdown_func(argv0, &inter_sk, SHUTDOWN_ABORT);
+				break;
+			case INTER_NODELAY:
+				if (set) {
+					if (*p < '0' || *p > '9') {
+						goto err_input;
+					}
+				}
+				val = (set) ? atoi(p) : 0;
+				nodelay_func(argv0, inter_sk, val, set);
+				break;
+			case INTER_MAXSEG:
+				if (set) {
+					if (*p < '0' || *p > '9') {
+						goto err_input;
+					}
+				}
+				val = (set) ? atoi(p) : 0;
+				maxseg_func(argv0, inter_sk, val, set);
+				break;
+			case INTER_GET_STATS:
+				get_assocstats_func(inter_sk, associd);
+				break;
+			default:
+				goto err_input;
+				break;
+			}
+
+			return i;
+		}
+		i++;
+	}
+
+err_input:
+	printf("Invalid input.\n");
+	return -1;
+
+} /* parse_inter_commands() */
+
+static char *
+gen_message(int len)
+{
+
+	char *buf;
+	char *p;
+	int i;
+
+	buf = malloc(len);
+
+	if (NULL != buf) {
+		for (i = 0, p = buf; i < len; i++, p++) {
+			if (gen_data > GEN_DATA_LAST) {
+				gen_data = GEN_DATA_FIRST;
+			}
+			*p = gen_data++;
+		}
+	}
+
+	return(buf);
+
+} /* gen_message() */
+
+static void
+snd_func(char *input)
+{
+
+	int len;
+
+	len = atoi(input);
+	if (!(inter_outbuf = gen_message(len))) {
+		fprintf(stderr, "Cannot allocate out message.\n");
+		exit(1);
+	}
+	inter_outlen = len;
+
+} /* snd_func() */
+
+static void
+sndbuf_func(char *argv0, int sk, int len, int set)
+{
+	int error;
+	socklen_t optlen;
+
+	if (set) {
+		error = setsockopt(sk, SOL_SOCKET, SO_SNDBUF,
+			(char *)&len, sizeof(len));
+	} else {
+		optlen = sizeof(len);
+		error = getsockopt(sk, SOL_SOCKET, SO_SNDBUF,
+			(char *)&len, &optlen);
+	}
+	if (error != 0) {
+		fprintf(stderr, "%s: Error setting/getting sndbuf: %s.\n",
+			argv0, strerror(errno));
+		exit(1);
+	}
+
+	if (!set) {
+		printf("sndbuf is %d.\n", len);
+	}
+
+} /* sndbuf_func() */
+
+static void
+rcvbuf_func(char *argv0, int sk, int len, int set)
+{
+	int error;
+	socklen_t optlen;
+
+	if (set) {
+		error = setsockopt(sk, SOL_SOCKET, SO_RCVBUF,
+			(char *)&len, sizeof(len));
+	} else {
+		optlen = sizeof(len);
+		error = getsockopt(sk, SOL_SOCKET, SO_RCVBUF,
+			(char *)&len, &optlen);
+	}
+	if (error != 0) {
+		fprintf(stderr, "%s: Error setting/getting rcvbuf: %s.\n",
+			argv0, strerror(errno));
+		exit(1);
+	}
+
+	if (!set) {
+		printf("rcvbuf is %d.\n", len);
+	}
+
+} /* rcvbuf_func() */
+
+
+static struct sockaddr *
+get_bindx_addr(char *in, int *count)
+{
+
+	struct sockaddr *tmp_addrs = NULL;
+	char *p = in;
+
+	/* Set the buffer for address parsing.  */
+	while ('\n' != *p) {
+		p++;
+	}
+	*p = '\0';
+
+	*count = 0;
+
+	tmp_addrs = append_addr(in, tmp_addrs, count);
+	if (NULL == tmp_addrs) {
+		/* We have no memory, so keep fprintf()
+		 * from trying to allocate more.
+		 */
+		fprintf(stderr, "No memory to add ");
+		fprintf(stderr, "%s\n", in);
+		exit(2);
+	}
+	return tmp_addrs;
+
+} /* get_bindx_addr() */
+
+static int
+bindx_func(char *argv0, int sk, struct sockaddr *addrs, int count, int flag, int portnum)
+{
+
+	int error;
+	int i;
+	struct sockaddr *sa_addr;
+	void *aptr;
+
+
+	if (0 == portnum) {
+		fprintf(stderr, "%s: A non-0 local port number is ", argv0);
+		fprintf(stderr, "required for bindx to work!\n");
+		return -1 ;
+	}
+
+	/* Set the port in every address.  */
+	aptr = addrs;
+	for (i = 0; i < count; i++) {
+		sa_addr = (struct sockaddr *)aptr;
+
+		switch(sa_addr->sa_family) {
+		case AF_INET:
+			((struct sockaddr_in *)sa_addr)->sin_port =
+				htons(portnum);
+			aptr += sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			((struct sockaddr_in6 *)sa_addr)->sin6_port =
+				htons(portnum);
+			aptr += sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Invalid address family\n");
+			return -1;
+		}
+	}
+
+	error = sctp_bindx(sk, addrs, count, flag);
+
+	if (error != 0) {
+		if (flag == SCTP_BINDX_ADD_ADDR) {
+			fprintf(stderr, "%s: error adding addrs: %s.\n",
+				argv0, strerror(errno));
+			return -1;
+		} else {
+			fprintf(stderr, "%s: error removing addrs: %s.\n",
+				argv0, strerror(errno));
+			return -1;
+		}
+	}
+
+	return 0;
+
+} /* bindx_func() */
+
+static int
+connectx_func(char *argv0, int sk, struct sockaddr *addrs, int count)
+{
+
+	int error;
+	int i;
+	struct sockaddr *sa_addr;
+	void *aptr;
+
+
+	if (0 == remote_port) {
+		fprintf(stderr, "%s: A non-0 remote port number is ", argv0);
+		fprintf(stderr, "required for connectx to work!\n");
+		return -1 ;
+	}
+
+	/* Set the port in every address.  */
+	aptr = addrs;
+	for (i = 0; i < count; i++) {
+		sa_addr = (struct sockaddr *)aptr;
+
+		switch(sa_addr->sa_family) {
+		case AF_INET:
+			((struct sockaddr_in *)sa_addr)->sin_port =
+				htons(remote_port);
+			aptr += sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			((struct sockaddr_in6 *)sa_addr)->sin6_port =
+				htons(remote_port);
+			aptr += sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Invalid address family\n");
+			return -1;
+		}
+	}
+
+	error = sctp_connectx(sk, addrs, count, NULL);
+
+	if (error != 0) {
+		if (errno == ECONNREFUSED)
+			return -2;
+		fprintf(stderr, "%s: error connecting to addrs: %s.\n",
+			argv0, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+
+} /* connectx_func() */
+
+static void
+primary_func(char *argv0, int sk, char *cp, int set)
+{
+	struct sctp_prim prim;
+	struct sockaddr_in *in_addr;
+	struct sockaddr_in6 *in6_addr;
+	struct sockaddr *saddr;
+	socklen_t prim_len;
+	int ret;
+	char *p = cp;
+	char addr_buf[INET6_ADDRSTRLEN];
+	const char *ap = NULL;
+
+	prim_len = sizeof(struct sctp_prim);
+	if (!set) {
+		prim.ssp_assoc_id = associd;
+		ret = getsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
+				   &prim, &prim_len); 
+		if (ret < 0)
+			goto err;
+	
+		saddr = (struct sockaddr *)&prim.ssp_addr;	
+		if (AF_INET == saddr->sa_family) {
+			in_addr = (struct sockaddr_in *)&prim.ssp_addr;
+			ap = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf,
+				       INET6_ADDRSTRLEN);
+		} else if (AF_INET6 == saddr->sa_family) {
+			in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr;
+			ap = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf,
+				       INET6_ADDRSTRLEN);
+		}
+		if (!ap)
+			goto err;
+		printf("%s\n", ap);
+		return;
+	}
+
+	/* Set the buffer for address parsing.  */
+	while ('\n' != *p)
+		p++;
+	*p = '\0';
+
+	prim.ssp_assoc_id = associd;	
+	if (strchr(cp, '.')) {
+		in_addr = (struct sockaddr_in *)&prim.ssp_addr;
+		in_addr->sin_port = htons(remote_port);
+		in_addr->sin_family = AF_INET;
+		ret = inet_pton (AF_INET, cp, &in_addr->sin_addr);
+		if (ret <= 0)
+			goto err;		
+	} else if (strchr(cp, ':')) {
+		in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr;
+		in6_addr->sin6_port = htons(remote_port);
+		in6_addr->sin6_family = AF_INET6;
+		ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
+		if (ret <= 0)
+			goto err;		
+	} else
+		goto err;
+
+	ret = setsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
+			    &prim, sizeof(struct sctp_prim)); 
+	if (ret < 0)
+		goto err;
+
+	return;
+err:
+	if (!errno)
+		errno = EINVAL;
+	fprintf(stderr, "%s: error %s primary: %s.\n", argv0,
+	        (set)?"setting":"getting", strerror(errno));
+}
+
+static void
+peer_primary_func(char *argv0, int sk, char *cp, int set)
+{
+	struct sctp_setpeerprim setpeerprim;
+	struct sockaddr_in *in_addr;
+	struct sockaddr_in6 *in6_addr;
+	int ret;
+	char *p = cp;
+
+	if (!set) {
+		goto err;
+	}
+
+	/* Set the buffer for address parsing.  */
+	while ('\n' != *p)
+		p++;
+	*p = '\0';
+
+	setpeerprim.sspp_assoc_id = associd;	
+	if (strchr(cp, '.')) {
+		in_addr = (struct sockaddr_in *)&setpeerprim.sspp_addr;
+		in_addr->sin_port = htons(local_port);
+		in_addr->sin_family = AF_INET;
+		ret = inet_pton (AF_INET, cp, &in_addr->sin_addr);
+		if (ret <= 0)
+			goto err;		
+	} else if (strchr(cp, ':')) {
+		in6_addr = (struct sockaddr_in6 *)&setpeerprim.sspp_addr;
+		in6_addr->sin6_port = htons(local_port);
+		in6_addr->sin6_family = AF_INET6;
+		ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
+		if (ret <= 0)
+			goto err;		
+	} else
+		goto err;
+
+	ret = setsockopt(sk, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR,
+			    &setpeerprim, sizeof(struct sctp_setpeerprim)); 
+	if (ret < 0)
+		goto err;
+
+	return;
+err:
+	if (!errno)
+		errno = EINVAL;
+	fprintf(stderr, "%s: error %s peer_primary: %s.\n", argv0,
+	        (set)?"setting":"getting", strerror(errno));
+}
+
+static void
+spp_hb_demand_func(char *argv0, int sk, char *cp, int set)
+{
+	struct sctp_paddrparams params;
+	struct sockaddr_in *in_addr;
+	struct sockaddr_in6 *in6_addr;
+	int ret;
+	char *p = cp;
+
+	memset(&params, 0, sizeof(struct sctp_paddrparams));
+	params.spp_assoc_id = associd;
+	params.spp_flags = SPP_HB_DEMAND;
+
+	if (set) {
+		/* Set the buffer for address parsing.  */
+		while ('\n' != *p)
+			p++;
+		*p = '\0';
+
+		if (strchr(cp, '.')) {
+			in_addr = (struct sockaddr_in *)&params.spp_address;
+			in_addr->sin_port = htons(remote_port);
+			in_addr->sin_family = AF_INET;
+			ret = inet_pton(AF_INET, cp, &in_addr->sin_addr);
+			if (ret <= 0)
+				goto err;
+		} else if (strchr(cp, ':')) {
+			in6_addr = (struct sockaddr_in6 *)&params.spp_address;
+			in6_addr->sin6_port = htons(remote_port);
+			in6_addr->sin6_family = AF_INET6;
+			ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
+			if (ret <= 0)
+				goto err;
+		} else
+			goto err;
+	}
+
+	ret = setsockopt(sk, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
+			    &params, sizeof(struct sctp_paddrparams));
+	if (ret < 0)
+		goto err;
+
+	return;
+err:
+	if (!errno)
+		errno = EINVAL;
+	fprintf(stderr, "%s: error %s peer_addr_params: %s.\n", argv0,
+	        (set)?"setting":"getting", strerror(errno));
+}
+
+static int
+nodelay_func(char *argv0, int sk, int val, int set)
+{
+	socklen_t optlen;
+	int error;
+
+	if (set) {
+		error = setsockopt(sk, SOL_SCTP, SCTP_NODELAY,
+			(char *)&val, sizeof(val));
+	} else {
+		optlen = sizeof(val);
+		error = getsockopt(sk, SOL_SCTP, SCTP_NODELAY,
+			(char *)&val, &optlen);
+	}
+	if (error != 0) {
+		fprintf(stderr, "%s: Error setting/getting nodelay: %s.\n",
+			argv0, strerror(errno));
+		exit(1);
+	}
+
+	if (!set) {
+		printf("nodelay is %d.\n", val);
+	}
+
+	return error;
+}
+
+static int
+maxseg_func(char *argv0, int sk, int val, int set)
+{
+	socklen_t optlen;
+	int error;
+
+	if (set) {
+		error = setsockopt(sk, SOL_SCTP, SCTP_MAXSEG,
+			(char *)&val, sizeof(val));
+	} else {
+		optlen = sizeof(val);
+		error = getsockopt(sk, SOL_SCTP, SCTP_MAXSEG,
+			(char *)&val, &optlen);
+	}
+	if (error != 0) {
+		fprintf(stderr, "%s: Error setting/getting maxseg: %s.\n",
+			argv0, strerror(errno));
+		exit(1);
+	}
+
+	if (!set) {
+		printf("maxseg is %d.\n", val);
+	}
+
+	return error;
+}
+
+static int
+shutdown_func(char *argv0, int *skp, int shutdown_type)
+{
+	struct msghdr outmessage;
+	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct cmsghdr *cmsg;
+        int error=0, bytes_sent;
+	struct sctp_sndrcvinfo *sinfo;
+	struct hostent *hst;
+	char *sd_type;
+	int sk = *skp;
+
+	if (shutdown_type == SHUTDOWN_ABORT)
+		sd_type = "ABORT";
+	else
+		sd_type = "SHUTDOWN";
+
+	/* Verify that the association is present. */
+	error = test_sk_for_assoc(sk, associd);
+	if (error != 0) {
+		printf("The association isn't present yet! Cannot %s!\n", sd_type);
+		return -1;
+	}
+
+	if (socket_type == SOCK_SEQPACKET) {
+		/* Set up the destination.  */
+		if (remote_host) {
+			hst = gethostbyname(remote_host);
+			if (hst == NULL) {
+				hst = gethostbyname2(remote_host, AF_INET6);
+			}
+
+			if (hst == NULL || hst->h_length < 1) {
+				fprintf(stderr, "%s: bad hostname: %s\n",
+					argv0, remote_host);
+				exit(1);
+			}
+
+			ra_family = hst->h_addrtype;
+			switch (ra_family) {
+			case AF_INET:
+				ra_len = sizeof(remote_addr.v4);
+				ra_raw = &remote_addr.v4.sin_addr;
+				remote_addr.v4.sin_port = htons(remote_port);
+				remote_addr.v4.sin_family = AF_INET;
+				break;
+			case AF_INET6:
+				ra_len = sizeof(remote_addr.v6);
+				ra_raw = &remote_addr.v6.sin6_addr;
+				remote_addr.v6.sin6_port = htons(remote_port);
+				remote_addr.v6.sin6_family = AF_INET6;
+				break;
+			default:
+				fprintf(stderr, "Invalid address type.\n");
+				exit(1);
+				break;
+			}
+			memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
+		}
+
+		/* Initialize the message struct we use to pass messages to
+		 * the remote socket.
+		 */
+		outmessage.msg_name = &remote_addr;
+		outmessage.msg_namelen = ra_len;
+
+		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));
+		if (shutdown_type == SHUTDOWN_ABORT)
+			sinfo->sinfo_flags |= SCTP_ABORT;
+		else
+			sinfo->sinfo_flags |= SCTP_EOF;
+
+		sinfo->sinfo_assoc_id = associd;
+	
+		bytes_sent = sendmsg(sk, &outmessage, 0);
+		if (bytes_sent != 0) {
+			printf("Failure:  %s.\n", strerror(errno));
+			return -1;
+		}
+
+		/* Receive the COMM_LOST or SHUTDOWN_COMP event. */
+		test_recv_assoc_change(sk);
+	} else {
+		if (shutdown_type == SHUTDOWN_ABORT) {
+			struct  linger {
+				int  l_onoff; 
+				int  l_linger;
+			} data = {1, 0};
+			error = setsockopt(sk, SOL_SOCKET, SO_LINGER,
+					   (char *)&data, sizeof(data));
+			if (error != 0) {
+				printf("setsockopt failed %s\n", strerror(errno));
+				exit(1);
+			}
+		}
+		error = close(sk);
+		if (error != 0) {
+			printf("close failed %s\n", strerror(errno));
+			exit(1);
+		}
+		*skp = sk = build_endpoint(argv0, local_port);
+	}
+
+	/* Verify that the association is no longer present.  */
+	error = test_sk_for_assoc(sk, associd);
+	if (error != 0) {
+		printf("Successfully %s the original association\n", sd_type);
+		associd = 0;
+		new_connection = 1;
+	} else {
+		printf("%s failed\n", sd_type);
+		exit(1);
+	}
+
+	return 0;
+}
+
+static int
+get_assocstats_func(int sk, sctp_assoc_t assoc_id)
+{
+	int error = 0;
+	struct sctp_assoc_stats stats;
+	socklen_t len;
+
+	if (assoc_id == 0) {
+		printf("No association present yet\n");
+		return -1;
+	}
+
+	memset(&stats, 0, sizeof(struct sctp_assoc_stats));
+	stats.sas_assoc_id = assoc_id;
+	len = sizeof(struct sctp_assoc_stats);
+	error = getsockopt(sk, SOL_SCTP, SCTP_GET_ASSOC_STATS,
+			(char *)&stats, &len);
+	if (error != 0) {
+		printf("get_assoc_stats() failed %s\n", strerror(errno));
+		return error;
+	}
+
+	printf("Retransmitted Chunks: %" PRIu64 "\n", (uint64_t) stats.sas_rtxchunks);
+	printf("Gap Acknowledgements Received: %" PRIu64 "\n", (uint64_t) stats.sas_gapcnt);
+	printf("TSN received > next expected: %" PRIu64 "\n", (uint64_t) stats.sas_outofseqtsns);
+	printf("SACKs sent: %" PRIu64 "\n", (uint64_t) stats.sas_osacks);
+	printf("SACKs received: %" PRIu64 "\n", (uint64_t) stats.sas_isacks);
+	printf("Control chunks sent: %" PRIu64 "\n", (uint64_t) stats.sas_octrlchunks);
+	printf("Control chunks received: %" PRIu64 "\n", (uint64_t) stats.sas_ictrlchunks);
+	printf("Ordered data chunks sent: %" PRIu64 "\n", (uint64_t) stats.sas_oodchunks);
+	printf("Ordered data chunks received: %" PRIu64 "\n", (uint64_t) stats.sas_iodchunks);
+	printf("Unordered data chunks sent: %" PRIu64 "\n", (uint64_t) stats.sas_ouodchunks);
+	printf("Unordered data chunks received: %" PRIu64 "\n", (uint64_t) stats.sas_iuodchunks);
+	printf("Dups received (ordered+unordered): %" PRIu64 "\n", (uint64_t) stats.sas_idupchunks);
+	printf("Packets sent: %" PRIu64 "\n", (uint64_t) stats.sas_opackets);
+	printf("Packets received: %" PRIu64 "\n", (uint64_t) stats.sas_ipackets);
+	printf("Maximum Observed RTO this period: %" PRIu64 " - Transport: ", (uint64_t) stats.sas_maxrto);
+	print_sockaddr((struct sockaddr *)&stats.sas_obs_rto_ipaddr);
+	printf("\n");
+
+	return 0;
+}
+
+static int
+test_sk_for_assoc(int sk, sctp_assoc_t assoc_id)
+{
+	int error = 0;
+	struct sctp_status status;
+	socklen_t status_len;
+
+	memset(&status, 0, sizeof(status));
+	if (assoc_id)
+		status.sstat_assoc_id = assoc_id;
+	status_len = sizeof(struct sctp_status);
+	error = getsockopt(sk, SOL_SCTP, SCTP_STATUS,
+               		(char *)&status, &status_len);
+	return error;
+}
+
+/* Receive a notification and return the corresponding associd if the event is
+ * SCTP_COMM_UP. Return 0 for any other event.
+ */
+static sctp_assoc_t
+test_recv_assoc_change(int sk)
+{
+	struct msghdr inmessage;
+	struct iovec iov;
+	char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+	int error;
+
+	/* Initialize inmessage with enough space for DATA... */
+	memset(&inmessage, 0, sizeof(inmessage));
+	if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		printf("%s: Can't allocate memory.\n", __FUNCTION__);
+		exit(1);
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+	error = recvmsg(sk, &inmessage, MSG_WAITALL);
+	if (error < 0) {
+		printf("%s: recvmsg: %s\n", __FUNCTION__, strerror(errno));
+		exit(1);
+	}
+
+	return test_verify_assoc_change(&inmessage);
+}
+
+/* Verify a notification and return the corresponding associd if the event is
+ * SCTP_COMM_UP. Return 0 for any other event.
+ */
+static sctp_assoc_t
+test_verify_assoc_change(struct msghdr *msg)
+{
+	union sctp_notification *sn;
+
+	if (!(msg->msg_flags & MSG_NOTIFICATION)) {
+		fprintf(stderr, "%s: Received data when notification is expected\n",
+		       __FUNCTION__);
+		exit(1);
+	}
+
+	sn = (union sctp_notification *)msg->msg_iov->iov_base;
+	if (SCTP_ASSOC_CHANGE != sn->sn_header.sn_type) {
+		fprintf(stderr, "%s: Received unexpected notification: %d",
+			__FUNCTION__, sn->sn_header.sn_type);
+		exit(1);
+	}
+
+	switch(sn->sn_assoc_change.sac_state)
+	{
+	case SCTP_COMM_UP:
+		printf("Received SCTP_COMM_UP\n");
+		break;
+	case SCTP_COMM_LOST:
+		printf("Received SCTP_COMM_LOST\n");
+		break;
+	case SCTP_RESTART:
+		printf("Received SCTP_RESTART\n");
+		break;
+	case SCTP_SHUTDOWN_COMP:
+		printf("Received SCTP_SHUTDOWN_COMP\n");
+		break;
+	case SCTP_CANT_STR_ASSOC:
+		printf("Received SCTP_CANT_STR_ASSOC\n");
+		break;
+	}
+
+	if (SCTP_COMM_UP == sn->sn_assoc_change.sac_state)
+		return sn->sn_assoc_change.sac_assoc_id;
+	else
+		return 0;
+}
+
+void print_addr_buf(void * laddrs, int n_laddrs)
+{
+	void *addr_buf = laddrs;
+	int i;
+
+	for (i = 0; i < n_laddrs; i++) {
+		addr_buf += print_sockaddr((struct sockaddr *)addr_buf);
+		printf("\n");
+	}
+}
+
+int print_sockaddr(struct sockaddr *sa_addr)
+{
+	struct sockaddr_in *in_addr;
+	struct sockaddr_in6 *in6_addr;
+
+	if (AF_INET == sa_addr->sa_family) {
+		in_addr = (struct sockaddr_in *)sa_addr;
+		printf("%d.%d.%d.%d:%d",
+		       NIPQUAD(in_addr->sin_addr),
+		       ntohs(in_addr->sin_port));
+		return sizeof(struct sockaddr_in);
+	} else {
+		in6_addr = (struct sockaddr_in6 *)sa_addr;
+		printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%d",
+		       NIP6(in6_addr->sin6_addr),
+		       ntohs(in6_addr->sin6_port));
+		return sizeof(struct sockaddr_in6);
+	}
+}
diff --git a/src/apps/sctp_darn.h b/src/apps/sctp_darn.h
new file mode 100644
index 0000000..e2c1ef1
--- /dev/null
+++ b/src/apps/sctp_darn.h
@@ -0,0 +1,29 @@
+#ifndef __sctp_darn_h__
+#define __sctp_darn_h__
+
+#define REALLY_BIG 65536
+#define SCTP_TESTPORT_1 1
+#define SCTP_TESTPORT_2 2
+
+void parse_arguments(int argc, char *argv[]);
+void usage(char *argv0);
+int command_listen(char *arg0, int sk);
+int command_send(char *arg0,   int *skp);
+int command_poll(char *arg0);
+int test_print_message(int sk, struct msghdr *, size_t msg_len);
+
+typedef enum {
+	COMMAND_NONE = 0,
+	COMMAND_LISTEN,
+	COMMAND_SEND,
+	COMMAND_POLL,
+} command_t;
+
+typedef union {
+	struct sockaddr_storage ss;
+        struct sockaddr_in v4;
+        struct sockaddr_in6 v6;
+        struct sockaddr sa;
+} sockaddr_storage_t;
+
+#endif /* __sctp_darn_h__ */
diff --git a/src/apps/sctp_status.c b/src/apps/sctp_status.c
new file mode 100644
index 0000000..8563cbe6
--- /dev/null
+++ b/src/apps/sctp_status.c
@@ -0,0 +1,945 @@
+/* SCTP kernel reference Implementation
+ * (C) Copyright Fujitsu Ltd. 2008, 2009
+ *
+ * The SCTP reference 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 reference 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:
+ *    Wei Yongjun <yjwei@cn.fujitsu.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/sctp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+
+#define DEFAULT_SEC	0
+#define DEFAULT_USEC	5000
+
+#define REALLY_BIG 65536
+
+#define SERVER 		0
+#define CLIENT 		1
+#define NOT_DEFINED	666
+
+#define DEBUG_NONE	0
+#define DEBUG_MIN	1
+#define DEBUG_MAX	2
+
+#define ORDER_PATTERN_UNORDERED   0
+#define ORDER_PATTERN_ORDERED     1
+#define ORDER_PATTERN_ALTERNATE   2
+#define ORDER_PATTERN_RANDOM      3
+
+#define STREAM_PATTERN_SEQUENTIAL 0
+#define STREAM_PATTERN_RANDOM     1
+
+#define MAX_BIND_RETRYS 10
+#define BIG_REPEAT	1000000
+#define REPEAT 		10
+
+#define DEFAULT_MAX_WINDOW 32768
+#define DEFAULT_MIN_WINDOW 1500
+
+#define MSG_CNT		10
+
+#define DEBUG_PRINT(level, print_this...)	\
+{						\
+	if (debug_level >= level) { 		\
+		fprintf(stdout, print_this); 	\
+		fflush(stdout); 		\
+	}					\
+} /* DEBUG_PRINT */
+
+char *local_host = NULL;
+int local_port = 0;
+char *remote_host = NULL;
+int remote_port = 0;
+struct sockaddr_storage s_rem, s_loc;
+int r_len, l_len;
+int size_arg = 0;
+int debug_level = DEBUG_NONE;
+int order_pattern = ORDER_PATTERN_UNORDERED;
+int order_state = 0;
+int stream_pattern = STREAM_PATTERN_SEQUENTIAL;
+int stream_state = 0;
+int repeat = REPEAT;
+int repeat_count = 0;
+int max_msgsize = DEFAULT_MAX_WINDOW;
+int msg_cnt = MSG_CNT;
+int drain = 0;
+int max_stream = 0;
+int gsk = -1;
+int period = 1;
+char *statusfile = NULL;
+
+void printstatus(int sk);
+void sighandler(int signo);
+void settimerhandle(void);
+void usage(char *argv0);
+void start_test(int role);
+
+unsigned char msg[] = "012345678901234567890123456789012345678901234567890";
+
+/* Convenience structure to determine space needed for cmsg. */
+typedef union {
+	struct sctp_initmsg init;
+	struct sctp_sndrcvinfo sndrcvinfo;
+} _sctp_cmsg_data_t;
+
+int main(int argc, char *argv[]) {
+	int c, role = NOT_DEFINED;
+	char *interface = NULL;
+	struct sockaddr_in *t_addr;
+	struct sockaddr_in6 *t_addr6;
+
+	/* Parse the arguments.  */
+	while ((c = getopt(argc, argv, ":H:L:P:h:p:c:d:lm:sx:X:o:M:Di:I:f:")) >= 0 ) {
+		switch (c) {
+		case 'H':
+			local_host = optarg;
+			break;
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case 'h':
+			remote_host = optarg;
+			break;
+		case 'p':
+			remote_port = atoi(optarg);
+			break;
+		case 'l':
+			if (role != NOT_DEFINED) {
+				printf("%s: only -s or -l\n", argv[0]);
+				usage(argv[0]);
+				exit(1);
+			}
+			role = SERVER;
+			break;
+		case 's':
+			if (role != NOT_DEFINED) {
+				printf("%s: only -s or -l\n", argv[0]);
+				usage(argv[0]);
+				exit(1);
+			}
+			role = CLIENT;
+			break;
+		case 'D':
+			drain = 1;
+			break;
+		case 'd':
+			debug_level = atoi(optarg);
+			if (debug_level < DEBUG_NONE
+			    || debug_level > DEBUG_MAX) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'I':
+			period = atoi(optarg);
+			if (period < 0) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'x':
+			repeat = atoi(optarg);
+			if (!repeat) {
+				repeat = BIG_REPEAT;
+			}
+			break;
+		case 'X':
+			msg_cnt = atoi(optarg);
+			if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'c':
+			size_arg = atoi(optarg);
+			if (size_arg < 0) {
+				usage(argv[0]);
+				exit(1);
+			}
+
+			break;
+		case 'o':
+			order_pattern = atoi(optarg);
+			if (order_pattern <  ORDER_PATTERN_UNORDERED
+			    || order_pattern  > ORDER_PATTERN_RANDOM ) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'M':
+			max_stream = atoi(optarg);
+			if (max_stream <  0
+			    || max_stream >= (1<<16)) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'm':
+			max_msgsize = atoi(optarg);
+			break;
+		case 'i':
+			interface = optarg;
+			break;
+		case 'f':
+			statusfile = optarg;
+			break;
+		case '?':
+		default:
+			usage(argv[0]);
+			exit(0);
+		}
+	} /* while() */
+
+	if (NOT_DEFINED == role) {
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (SERVER == role && NULL == local_host && remote_host != NULL) {
+		fprintf(stderr, "%s: Server needs local address, "
+			 "not remote address\n", argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+	if (CLIENT == role && NULL == remote_host) {
+		fprintf(stderr, "%s: Client needs at least remote address "
+			 "& port\n", argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (optind < argc) {
+		fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]);
+		while (optind < argc)
+			fprintf(stderr, "%s ", argv[optind++]);
+		fprintf (stderr, "\n");
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (remote_host != NULL && remote_port != 0) {
+		struct addrinfo *res;
+		int error;
+		char *host_s, *serv_s;
+
+		if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+			fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
+			exit(1);
+		}
+		if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+			fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
+			exit(1);
+		}
+
+		error = getaddrinfo(remote_host, 0, NULL, &res);
+		if (error) {
+			printf("%s.\n", gai_strerror(error));
+			usage(argv[0]);
+			exit(1);
+		}
+
+		switch (res->ai_family) {
+			case AF_INET:
+				t_addr = (struct sockaddr_in *)&s_rem;
+
+				memcpy(t_addr, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr->sin_family = res->ai_family;
+				t_addr->sin_port = htons(remote_port);
+
+				r_len = res->ai_addrlen;
+#ifdef __FreeBSD__
+				t_addr->sin_len = r_len;
+#endif
+				break;
+			case AF_INET6:
+				t_addr6 = (struct sockaddr_in6 *)&s_rem;
+
+				memcpy(t_addr6, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr6->sin6_family = res->ai_family;
+				t_addr6->sin6_port = htons(remote_port);
+				if (interface)
+					t_addr6->sin6_scope_id = if_nametoindex(interface);
+
+				r_len = res->ai_addrlen;
+
+#ifdef __FreeBSD__
+				t_addr6->sin6_len = r_len;
+#endif
+				break;
+		}
+
+		getnameinfo((struct sockaddr *)&s_rem, r_len, host_s,
+			    NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
+
+		DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n",
+			    host_s, serv_s, res->ai_family);
+
+		freeaddrinfo(res);
+        }
+
+	if (local_host != NULL) {
+		struct addrinfo *res;
+		int error;
+		char *host_s, *serv_s;
+		struct sockaddr_in *t_addr;
+		struct sockaddr_in6 *t_addr6;
+
+		if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+			fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
+			exit(1);
+		}
+		if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+			fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
+			exit(1);
+		}
+
+		if (strcmp(local_host, "0") == 0)
+			local_host = "0.0.0.0";
+
+		error = getaddrinfo(local_host, 0, NULL, &res);
+		if (error) {
+			printf("%s.\n", gai_strerror(error));
+			usage(argv[0]);
+			exit(1);
+		}
+
+		switch (res->ai_family) {
+			case AF_INET:
+				t_addr = (struct sockaddr_in *)&s_loc;
+
+				memcpy(t_addr, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr->sin_family = res->ai_family;
+				t_addr->sin_port = htons(local_port);
+
+				l_len = res->ai_addrlen;
+#ifdef __FreeBSD__
+				t_addr->sin_len = l_len;
+#endif
+				break;
+			case AF_INET6:
+				t_addr6 = (struct sockaddr_in6 *)&s_loc;
+
+				memcpy(t_addr6, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr6->sin6_family = res->ai_family;
+				t_addr6->sin6_port = htons(local_port);
+				if (interface)
+					t_addr6->sin6_scope_id = if_nametoindex(interface);
+
+				l_len = res->ai_addrlen;
+
+#ifdef __FreeBSD__
+				t_addr6->sin6_len = l_len;
+#endif
+				break;
+		}
+
+		error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s,
+			    NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
+
+		if (error)
+			printf("%s..\n", gai_strerror(error));
+
+		DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n",
+			    host_s, serv_s, res->ai_family);
+
+		freeaddrinfo(res);
+        }
+
+	/* Let the testing begin. */
+	start_test(role);
+
+	return 0;
+}
+
+int bind_r(int sk, struct sockaddr_storage *saddr) {
+	int error = 0, i = 0;
+	char *host_s, *serv_s;
+
+	if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+		fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n");
+		exit(1);
+	}
+	if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+		fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n");
+		exit(1);
+	}
+
+	do {
+		if (i > 0) sleep(1); /* sleep a while before new try... */
+
+		error = getnameinfo((struct sockaddr *)saddr, l_len, host_s,
+				    NI_MAXHOST, serv_s, NI_MAXSERV,
+				    NI_NUMERICHOST);
+
+		if (error)
+			printf("%s\n", gai_strerror(error));
+
+		DEBUG_PRINT(DEBUG_MIN,
+			"\tbind(sk=%d, [a:%s,p:%s])  --  attempt %d/%d\n",
+			sk, host_s, serv_s, i+1, MAX_BIND_RETRYS);
+
+		error = bind(sk, (struct sockaddr *)saddr, l_len);
+
+		if (error != 0) {
+			if( errno != EADDRINUSE ) {
+				fprintf(stderr, "\n\n\t\t***bind: can "
+					"not bind to %s:%s: %s ****\n",
+					host_s, serv_s, strerror(errno));
+				exit(1);
+			}
+		}
+		i++;
+		if (i >= MAX_BIND_RETRYS) {
+			fprintf(stderr, "Maximum bind() attempts. "
+				"Die now...\n\n");
+			exit(1);
+		}
+	} while (error < 0 && i < MAX_BIND_RETRYS);
+
+	return 0;
+} /* bind_r() */
+
+int listen_r(int sk, int listen_count) {
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n",
+		sk, listen_count);
+
+	/* Mark sk as being able to accept new associations */
+	error = listen(sk, 1);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** listen:  %s ***\n\n\n", strerror(errno));
+		exit(1);
+	}
+
+	return 0;
+} /* listen_r() */
+
+int accept_r(int sk){
+	socklen_t len = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk);
+
+	gsk = accept(sk, NULL, &len);
+	if (gsk < 0) {
+		fprintf(stderr, "\n\n\t\t*** accept:  %s ***\n\n\n", strerror(errno));
+		exit(1);
+	}
+
+	return 0;
+} /* accept_r() */
+
+int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) {
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk);
+
+	/* Mark sk as being able to accept new associations */
+	error = connect(sk, serv_addr, addrlen);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** connect:  %s ***\n\n\n",
+			strerror(errno));
+		exit(1);
+	}
+
+	gsk = sk;
+
+	return 0;
+} /* connect_r() */
+
+int close_r(int sk) {
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk);
+
+	error = close(sk);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n",
+			strerror(errno));
+		exit(1);
+	}
+	fflush(stdout);
+	return 0;
+} /* close_r() */
+
+int receive_r(int sk)
+{
+	int error = 0;
+	char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+	struct iovec iov;
+	struct msghdr inmessage;
+
+	/* Initialize inmessage with enough space for DATA... */
+	memset(&inmessage, 0, sizeof(inmessage));
+	if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		exit(1);
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+	/* Get the messages sent */
+	while (1) {
+		DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk);
+
+		error = recvmsg(sk, &inmessage, MSG_WAITALL);
+		if (error < 0 && errno != EAGAIN) {
+			fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n",
+					strerror(errno));
+			fflush(stdout);
+			close(sk);
+			free(iov.iov_base);
+			exit(1);
+		} else if (error == 0) {
+			printf("\n\t\trecvmsg() returned 0 !!!!\n");
+			fflush(stdout);
+		}
+
+		if(MSG_NOTIFICATION & inmessage.msg_flags)
+			continue; /* got a notification... */
+
+		inmessage.msg_control = incmsg;
+		inmessage.msg_controllen = sizeof(incmsg);
+		iov.iov_len = REALLY_BIG;
+		break;
+	}
+
+	free(iov.iov_base);
+	return 0;
+} /* receive_r () */
+
+void server(int sk) {
+	int i;
+
+	if (max_msgsize > DEFAULT_MAX_WINDOW) {
+		if (setsockopt(sk, IPPROTO_SCTP, SO_RCVBUF, &max_msgsize,
+			       sizeof(max_msgsize)) < 0) {
+			perror("setsockopt(SO_RCVBUF)");
+			exit(1);
+		}
+	}
+
+	for (i = 0; i < msg_cnt; i++) {
+		receive_r(sk);
+		DEBUG_PRINT(DEBUG_MIN, "count %d\n", i+1);
+	}
+} /* server() */
+
+void * build_msg(int len) {
+	int i = len - 1;
+	int n;
+	char *msg_buf, *p;
+
+	msg_buf = malloc(len);
+	if (NULL == msg_buf) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		exit(1);
+	}
+	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);
+
+} /* build_msg() */
+
+int send_r(int sk, int stream, int order, int send_size, int assoc_i) {
+	int error = 0;
+	struct msghdr outmsg;
+	struct iovec iov;
+	char *message = NULL;
+	int msglen = 0;
+	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+
+	if (send_size > 0) {
+		message = build_msg(send_size);
+		msglen = strlen(message) + 1;
+		iov.iov_base = message;
+		iov.iov_len = msglen;
+	} else {
+			exit(1);
+	}
+
+	outmsg.msg_name = &s_rem;
+	outmsg.msg_namelen = sizeof(struct sockaddr_storage);
+	outmsg.msg_iov = &iov;
+	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 = rand();
+	sinfo->sinfo_stream = stream;
+	sinfo->sinfo_flags = 0;
+	if (!order)
+		sinfo->sinfo_flags = SCTP_UNORDERED;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n",
+		    sk, assoc_i, send_size);
+	DEBUG_PRINT(DEBUG_MAX, "\t  SNDRCV");
+	if (DEBUG_MAX == debug_level) {
+		printf("(stream=%u ", 	sinfo->sinfo_stream);
+		printf("flags=0x%x ",	sinfo->sinfo_flags);
+		printf("ppid=%u)\n",	sinfo->sinfo_ppid);
+	}
+
+	/* Send to our neighbor.  */
+	error = sendmsg(sk, &outmsg, MSG_WAITALL);
+	if (error != msglen) {
+		fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n",
+			strerror(errno));
+		fflush(stdout);
+		exit(1);
+	}
+
+	if (send_size > 0) free(message);
+	return 0;
+} /* send_r() */
+
+int next_order(int state, int pattern)
+{
+	switch (pattern){
+	case ORDER_PATTERN_UNORDERED:
+		state = 0;
+		break;
+	case ORDER_PATTERN_ORDERED:
+		state = 1;
+		break;
+	case ORDER_PATTERN_ALTERNATE:
+		state = state ? 0 : 1;
+		break;
+	case ORDER_PATTERN_RANDOM:
+		state = rand() % 2;
+		break;
+	}
+
+	return state;
+}
+
+int next_stream(int state, int pattern)
+{
+	switch (pattern){
+	case STREAM_PATTERN_RANDOM:
+		state = rand() % max_stream;
+		break;
+	case STREAM_PATTERN_SEQUENTIAL:
+		state = state + 1;
+		if (state >= max_stream)
+			state = 0;
+		break;
+	}
+
+	return state;
+}
+
+int next_msg_size(int msg_cnt)
+{
+	int msg_size;
+
+	if (size_arg) {
+		msg_size = size_arg;
+	} else {
+		msg_size = (rand() % max_msgsize) + 1;
+	}
+
+	return msg_size;
+
+} /* next_msg_size() */
+
+void client(int sk) {
+	int msg_size;
+	int i;
+
+	for (i = 0; i < msg_cnt; i++) {
+		msg_size = next_msg_size(i);
+		order_state = next_order(order_state, order_pattern);
+		stream_state = next_stream(stream_state, stream_pattern);
+
+		if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) {
+			close(sk);
+			break;
+		}
+
+		/* The sender is echoing so do discard the echoed data. */
+		if (drain && ((i + 1) % period == 0)) {
+			receive_r(sk);
+		}
+	}
+} /* client() */
+
+void start_test(int role) {
+	int sk, pid, ret;
+	int i = 0;
+
+	DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n");
+
+	repeat_count = repeat;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_STREAM, IPPROTO_SCTP)");
+
+	if ((sk = socket(s_loc.ss_family, SOCK_STREAM, IPPROTO_SCTP)) < 0 ) {
+		fprintf(stderr, "\n\n\t\t*** socket: failed to create"
+			" socket:  %s ***\n", strerror(errno));
+		exit(1);
+	}
+	DEBUG_PRINT(DEBUG_MIN, "  ->  sk=%d\n", sk);
+
+	bind_r(sk, &s_loc);
+
+	if (role == SERVER) {
+		listen_r(sk, 1);
+		accept_r(sk);
+	} else {
+		if (max_stream > 0) {
+			struct sctp_initmsg initmsg;
+
+			memset(&initmsg, 0, sizeof(initmsg));
+			initmsg.sinit_num_ostreams = max_stream;
+			initmsg.sinit_max_instreams = max_stream;
+			initmsg.sinit_max_attempts = 3;
+
+			ret = setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG,
+					 &initmsg, sizeof(initmsg));
+			if (ret < 0) {
+				perror("setsockopt(SCTP_INITMSG)");
+				exit(0);
+			}
+		}
+
+		connect_r(sk, (struct sockaddr *)&s_rem, r_len);
+	}
+
+	if ((pid = fork()) == 0) {
+		settimerhandle();
+		printstatus(gsk);
+		while(1);
+	} else {
+		if (!debug_level) {
+			printf("     ");
+		}
+
+		for(i = 0; i < repeat_count; i++) {
+
+			if (role == SERVER) {
+				DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.(%d/%d)\n",
+					i+1, repeat_count);
+				server(gsk);
+			} else {
+				DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n",
+					i+1, repeat_count);
+				client(sk);
+			}
+
+			fflush(stdout);
+		}
+
+		if (role == SERVER) close_r(gsk);
+		close_r(sk);
+	}
+} /* start_test() */
+
+void settimerhandle(void) {
+	struct sigaction act;
+	struct itimerval interval;
+
+	act.sa_handler = sighandler;
+	act.sa_flags = 0;
+	sigemptyset(&act.sa_mask);
+	sigaction(SIGPROF, &act, NULL);
+
+	interval.it_value.tv_sec = DEFAULT_SEC;
+	interval.it_value.tv_usec = DEFAULT_USEC;
+	interval.it_interval = interval.it_value;
+
+	setitimer(ITIMER_PROF, &interval, NULL);
+}
+
+void usage(char *argv0) {
+	fprintf(stderr, "\nusage:\n");
+	fprintf(stderr, "  server:\n");
+	fprintf(stderr, "  %8s -H local-addr -P local-port -l [-d level] [-x]\n"
+			"\t      [-L num-ports] [-S num-ports]\n"
+			"\t      [-a assoc-pattern]\n"
+			"\t      [-i interface]\n"
+			"\t      [-f status-file]\n",
+		argv0);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  client:\n");
+	fprintf(stderr, "  %8s -H local-addr -P local-port -h remote-addr\n"
+		"\t      -p remote-port -s [-c case ] [-d level]\n"
+		"\t      [-x repeat] [-o order-pattern] ream-pattern]\n"
+		"\t      [-M max-stream]\n"
+		"\t      [-m max-msgsize]\n"
+		"\t      [-L num-ports] [-S num-ports]\n"
+		"\t      [-i interface]\n"
+		"\t      [-f status-file]\n",
+		argv0);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "\t-c value = Packets of specifed size.\n");
+	fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n");
+	fprintf(stderr, "\t-x number of repeats\n");
+	fprintf(stderr, "\t-X number of messages\n");
+	fprintf(stderr, "\t-o order-pattern\n");
+	fprintf(stderr, "\t   0 = all unordered(default) \n");
+	fprintf(stderr, "\t   1 = all ordered \n");
+	fprintf(stderr, "\t   2 = alternating \n");
+	fprintf(stderr, "\t   3 = random\n");
+	fprintf(stderr, "\t-M max-stream (default value 0)\n");
+	fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n");
+	fprintf(stderr, "\t-I receive after <n> times of send, default value 1.\n");
+	fprintf(stderr, "\n");
+	fflush(stderr);
+
+} /* usage() */
+
+void sighandler(int signo) {
+	DEBUG_PRINT(DEBUG_MAX, "timeout sig\n");
+	printstatus(gsk);
+}
+
+char* get_sstat_state(int state) {
+	switch(state) {
+	case SCTP_EMPTY:
+		return "EMPTY";
+	case SCTP_CLOSED:
+		return "CLOSED";
+	case SCTP_COOKIE_WAIT:
+		return "COOKIE_WAIT";
+	case SCTP_COOKIE_ECHOED:
+		return "COOKIE_ECHOED";
+	case SCTP_ESTABLISHED:
+		return "ESTABLISHED";
+	case SCTP_SHUTDOWN_PENDING:
+		return "SHUTDOWN_PENDING";
+	case SCTP_SHUTDOWN_SENT:
+		return "SHUTDOWN_SENT";
+	case SCTP_SHUTDOWN_RECEIVED:
+		return "SHUTDOWN_RECEIVED";
+	case SCTP_SHUTDOWN_ACK_SENT:
+		return "SHUTDOWN_ACK_SENT";
+	default:
+		return "UNKNOW";
+	}
+}
+
+void printstatus(int sk) {
+	static int cwnd = 0;
+	static int count = 0;
+	struct sctp_status status;
+	socklen_t optlen;
+	FILE * fp;
+	const char *state_to_str[] = {
+		[SCTP_INACTIVE]		=	"INACTIVE",
+		[SCTP_PF]		=	"PF",
+		[SCTP_ACTIVE]		=	"ACTIVE",
+		[SCTP_UNCONFIRMED]	=	"UNCONFIRMED",
+	};
+
+	optlen = sizeof(struct sctp_status);
+	if(getsockopt(sk, IPPROTO_SCTP, SCTP_STATUS, &status, &optlen) < 0) {
+		fprintf(stderr, "Error getting status: %s.\n", strerror(errno));
+		exit(1);
+	}
+
+	if (statusfile != NULL) {
+		if (count == 0)
+			unlink(statusfile);
+
+		if((fp = fopen(statusfile, "a+")) == NULL) {
+			perror("fopen");
+			exit(1);
+		}
+	} else
+		fp = stdout;
+
+	if (count == 0)
+		fprintf(fp, "NO. ASSOC-ID STATE             RWND     UNACKDATA PENDDATA INSTRMS OUTSTRMS "
+				"FRAG-POINT SPINFO-STATE SPINFO-CWDN SPINFO-SRTT SPINFO-RTO SPINFO-MTU\n");
+
+	if (cwnd != status.sstat_primary.spinfo_cwnd) {
+		count++;
+
+		fprintf(fp, "%-3d %-8d %-17s %-8d %-9d %-8d %-7d %-8d %-10d %-12s %-11d %-11d %-10d %d\n", count,
+				status.sstat_assoc_id, get_sstat_state(status.sstat_state),
+				status.sstat_rwnd, status.sstat_unackdata, status.sstat_penddata,
+				status.sstat_instrms, status.sstat_outstrms, status.sstat_fragmentation_point,
+				state_to_str[status.sstat_primary.spinfo_state],
+				status.sstat_primary.spinfo_cwnd, status.sstat_primary.spinfo_srtt,
+				status.sstat_primary.spinfo_rto, status.sstat_primary.spinfo_mtu);
+	}
+
+	cwnd = status.sstat_primary.spinfo_cwnd;
+
+	fflush(fp);
+
+	if (fp != stdout)
+		fclose(fp);
+
+	if (status.sstat_primary.spinfo_state != SCTP_ACTIVE) {
+		close_r(sk);
+		exit(1);
+	}
+}
diff --git a/src/apps/sctp_test.c b/src/apps/sctp_test.c
new file mode 100644
index 0000000..cd7654b
--- /dev/null
+++ b/src/apps/sctp_test.c
@@ -0,0 +1,1852 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999 Cisco
+ * Copyright (c) 1999, 2000, 2001 Motorola
+ * Copyright (c) 2001-2002 Nokia
+ * Copyright (c) 2001 La Monte H.P. Yarroll
+ *
+ * This is a userspace test application for the SCTP kernel 
+ * implementation.
+ *
+ * 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, 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 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:
+ *   Hui Huang         <hui.huang@nokia.com>
+ *   Sridhar Samudrala <samudrala@us.ibm.com>
+ *   Jon Grimm         <jgrimm@us.ibm.com>
+ *   Daisy Chang       <daisyc@us.ibm.com>
+ *   Ryan Layer	       <rmlayer@us.ibm.com>
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.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 <string.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <net/if.h>
+
+#include <sys/resource.h>
+
+
+#define REALLY_BIG 65536
+
+#define SERVER 		0
+#define CLIENT 		1
+#define MIXED 		2
+#define NOT_DEFINED	666
+
+#define REPEAT 		10
+#define BIG_REPEAT	1000000
+#define MAX_BIND_RETRYS 10
+#define BODYSIZE	10
+#define MSG_CNT		10	/* If this is changed the msg_sizes array
+				   needs to be modified accordingly.  */
+
+#define DEFAULT_MAX_WINDOW 32768
+#define DEFAULT_MIN_WINDOW 1500
+
+#define DEBUG_NONE	0
+#define DEBUG_MIN	1
+#define DEBUG_MAX	2
+
+#define STREAM_PATTERN_SEQUENTIAL 0
+#define STREAM_PATTERN_RANDOM     1
+
+#define ORDER_PATTERN_UNORDERED   0
+#define ORDER_PATTERN_ORDERED     1
+#define ORDER_PATTERN_ALTERNATE   2
+#define ORDER_PATTERN_RANDOM      3
+
+#define ASSOC_PATTERN_SEQUENTIAL 0
+#define ASSOC_PATTERN_RANDOM     1
+
+#define NCASES 6
+#define MAX_POLL_SKS 256
+
+#define DEBUG_PRINT(level, print_this...)	\
+{						\
+	if (debug_level >= level) { 		\
+		fprintf(stdout, print_this); 	\
+		fflush(stdout); 		\
+	}					\
+} /* DEBUG_PRINT */
+
+/* Convenience structure to determine space needed for cmsg. */
+typedef union {
+        struct sctp_initmsg init;
+        struct sctp_sndrcvinfo sndrcvinfo;
+} _sctp_cmsg_data_t;
+
+#ifdef __FreeBSD__
+typedef union {
+        int                    raw;
+        struct sctp_initmsg     init;
+        struct sctp_sndrcvinfo  sndrcv;
+} sctp_cmsg_data_t;
+#endif
+
+#define CMSG_SPACE_INITMSG (CMSG_SPACE(sizeof(struct sctp_initmsg)))
+#define CMSG_SPACE_SNDRCV (CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)))
+
+typedef struct {
+	int rem_port;
+        int order_state;
+        int stream_state;
+	int msg_cnt;
+	int msg_sent;
+	int cycle;
+} _assoc_state;
+
+typedef struct {
+        int sk;
+        int assoc_i;
+	_assoc_state *assoc_state;
+} _poll_sks;
+
+char *local_host = NULL;
+int local_port = 0;
+char *remote_host = NULL;
+int remote_port = 0;
+/* struct sockaddr_in s_rem, s_loc; */
+struct sockaddr_storage s_rem, s_loc;
+int r_len, l_len;
+int test_case = 0;
+int size_arg = 0;
+int xflag = 0;
+int debug_level = DEBUG_MAX;
+int do_exit = 1;
+int stream_pattern = STREAM_PATTERN_SEQUENTIAL;
+int stream_state = 0;
+int order_pattern = ORDER_PATTERN_UNORDERED;
+int order_state = 0;
+int max_stream = 0;
+int seed = 0;
+int max_msgsize = DEFAULT_MAX_WINDOW;
+int timetolive = 0;
+int assoc_pattern = ASSOC_PATTERN_SEQUENTIAL;
+int socket_type = SOCK_SEQPACKET;
+int repeat_count = 0;
+int listeners = 0;
+int tosend = 0;
+_poll_sks poll_sks[MAX_POLL_SKS];
+int repeat = REPEAT;
+int msg_cnt = MSG_CNT;
+int drain = 0;
+int role = NOT_DEFINED;
+struct sockaddr *bindx_add_addrs = NULL;
+int bindx_add_count = 0;
+struct sockaddr *connectx_addrs = NULL;
+int connectx_count = 0;
+int if_index = 0;
+
+unsigned char msg[] = "012345678901234567890123456789012345678901234567890";
+
+static int msg_sizes[NCASES][MSG_CNT] =
+	{{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	 {1452, 2904, 4356, 1452, 2904, 4356, 1452, 2904, 4356, 1452},
+	 {1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453},
+	 {1, 1453, 32768, 1, 1453, 32768, 1, 1453, 32768, 1},
+	 {1, 1000, 2000, 3000, 5000, 10000, 15000, 20000, 25000, 32768},
+	 {32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768},
+	};
+
+static const char *sac_state_tbl[] = {
+	"COMMUNICATION_UP",
+	"COMMUNICATION_LOST",
+	"RESTART",
+	"SHUTDOWN_COMPLETE",
+	"CANT_START_ASSOCICATION"
+};
+
+void usage(char *argv0)
+{
+	fprintf(stderr, "\nusage:\n");
+	fprintf(stderr, "  server:\n");
+	fprintf(stderr, "  %8s -H local-addr -P local-port -l [-d level] [-x]\n"
+			"\t      [-L num-ports] [-S num-ports]\n"
+			"\t      [-a assoc-pattern]\n"
+			"\t      [-i interface]\n",
+		argv0);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  client:\n");
+	fprintf(stderr, "  %8s -H local-addr -P local-port -h remote-addr\n"
+		"\t      -p remote-port -s [-c case ] [-d level]\n"
+		"\t      [-x repeat] [-o order-pattern] [-t stream-pattern]\n"
+		"\t      [-M max-stream] [-r rand-seed]\n"
+		"\t      [-m max-msgsize]\n"
+		"\t      [-L num-ports] [-S num-ports]\n"
+		"\t      [-a assoc-pattern]\n"
+		"\t      [-i interface]\n",
+		argv0);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "\t-a assoc_pattern in the mixed mode\n");
+	fprintf(stderr, "\t   0 = sequential ascending(default)\n");
+	fprintf(stderr, "\t   1 = random\n");
+	fprintf(stderr, "\t-d debug\n");
+	fprintf(stderr, "\t   0 = none\n");
+	fprintf(stderr, "\t   1 = min(default)\n");
+	fprintf(stderr, "\t   2 = max\n");
+	fprintf(stderr, "\t-c testcase\n");
+	fprintf(stderr, "\t   0 = 1 byte packets.\n");
+	fprintf(stderr, "\t   1 = Sequence of multiples of 1452 byte packets.\n");
+	fprintf(stderr, "\t       (1452 is fragmentation point for an i/f with ");
+	fprintf(stderr, "1500 as mtu.)\n");
+	fprintf(stderr, "\t   2 = 1453 byte packets.\n");
+	fprintf(stderr, "\t       (min. size at which fragmentation occurs\n");
+	fprintf(stderr, "\t        for an i/f with 1500 as mtu.)\n");
+	fprintf(stderr, "\t   3 = Sequence of 1, 1453, 32768 byte packets.\n");
+	fprintf(stderr, "\t   4 = Sequence of following size packets.\n");
+	fprintf(stderr, "\t       (1, 1000, 2000, 3000, 5000, 10000,");
+	fprintf(stderr, "15000, 20000, 25000, 32768)\n");
+	fprintf(stderr, "\t   5 = 32768 byte packets.\n");
+	fprintf(stderr, "\t       (default max receive window size.)\n");
+	fprintf(stderr, "\t   6 = random size packets.\n");
+	fprintf(stderr, "\t   -ve value = Packets of specifed size.\n");
+	fprintf(stderr, "\t-m max msgsize for option -c 6 (1500-65515, default value 32768)\n");
+	fprintf(stderr, "\t-x number of repeats\n");
+	fprintf(stderr, "\t-o order-pattern\n");
+	fprintf(stderr, "\t   0 = all unordered(default) \n");
+	fprintf(stderr, "\t   1 = all ordered \n");
+	fprintf(stderr, "\t   2 = alternating \n");
+        fprintf(stderr, "\t   3 = random\n");
+	fprintf(stderr, "\t-t stream-pattern\n");
+	fprintf(stderr, "\t   0 = sequential ascending(default)\n");
+	fprintf(stderr, "\t   1 = random\n");
+	fprintf(stderr, "\t-M max-stream (default value 0)\n");
+	fprintf(stderr, "\t-r seed (default 0, use time())\n");
+	fprintf(stderr, "\t-L num-ports (default value 0). Run the mixed mode\n");
+	fprintf(stderr, "\t-S num-ports (default value 0). Run the mixed mode\n");
+	fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n");
+	fprintf(stderr, "\t-T use SOCK_STREAM tcp-style sockets.\n");
+	fprintf(stderr, "\t-B add the specified address(es) as additional bind\n");
+	fprintf(stderr, "\t   addresses of the local socket. Multiple addresses can\n");
+	fprintf(stderr, "\t   be specified by using this argument multiple times.\n");
+	fprintf(stderr, "\t   For example, '-B 10.0.0.1 -B 20.0.0.2'.\n");
+	fprintf(stderr, "\t   In case of IPv6 linklocal address, interface name can be set in following way \n");
+	fprintf(stderr, "\t   For example, '-B fe80::f8c3:b77f:698e:4506%%eth2'.\n");
+	fprintf(stderr, "\t-C use the specified address(es) for connection to the\n");
+	fprintf(stderr, "\t   peer socket. Multiple addresses can be specified by\n");
+	fprintf(stderr, "\t   using this argument multiple times.\n");
+	fprintf(stderr, "\t   For example, '-C 10.0.0.1 -C 20.0.0.2'.\n");
+	fprintf(stderr, "\t   This option is incompatible with the -h option.\n");
+	fprintf(stderr, "\t-O time to live (default value 0)\n");
+	fprintf(stderr, "\n");
+	fflush(stderr);
+
+} /* usage() */
+
+void *
+build_msg(int len)
+{
+	int i = len - 1;
+	int n;
+	char *msg_buf, *p;
+
+	msg_buf = malloc(len);
+	if (NULL == msg_buf) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		exit(1);
+	}
+	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);
+
+} /* build_msg() */
+
+static int
+print_cmsg(int type, sctp_cmsg_data_t *data)
+{
+        switch(type) {
+        case SCTP_INIT:
+		DEBUG_PRINT(DEBUG_MAX, "\tINIT\n");
+		if (DEBUG_MAX == debug_level) {
+			printf("\t\tsinit_num_ostreams=%d ",
+			       data->init.sinit_num_ostreams);
+                	printf("sinit_max_instreams=%d ",
+			       data->init.sinit_max_instreams);
+	                printf("sinit_max_attempts=%d ",
+			       data->init.sinit_max_attempts);
+        	        printf("sinit_max_init_timeo=%d\n",
+			       data->init.sinit_max_init_timeo);
+		}
+		break;
+        case SCTP_SNDRCV:
+		DEBUG_PRINT(DEBUG_MAX, "\t  SNDRCV");
+		if (DEBUG_MAX == debug_level) {
+        	        printf("(stream=%u ", 	data->sndrcv.sinfo_stream);
+                	printf("ssn=%u ", 	data->sndrcv.sinfo_ssn);
+			printf("tsn=%u ", 	data->sndrcv.sinfo_tsn);
+	                printf("flags=0x%x ",	data->sndrcv.sinfo_flags);
+        	        printf("ppid=%u\n",	data->sndrcv.sinfo_ppid);
+			printf("cumtsn=%u\n",   data->sndrcv.sinfo_cumtsn);
+                }
+		break;
+         default:
+		DEBUG_PRINT(DEBUG_MIN, "\tUnknown type: %d\n", type);
+                break;
+        }
+	fflush(stdout);
+        return 0;
+
+} /* print_cmsg() */
+
+/* This function prints the message. */
+static int
+print_message(const int sk, struct msghdr *msg, size_t msg_len) {
+	struct cmsghdr *scmsg;
+	sctp_cmsg_data_t *data;
+        int i;
+
+        if (!(MSG_NOTIFICATION & msg->msg_flags)) {
+                int index = 0;
+
+		DEBUG_PRINT(DEBUG_MIN, "Data %zu bytes.", msg_len);
+		DEBUG_PRINT(DEBUG_MAX, " First %zu bytes: ",
+				    (msg_len < BODYSIZE)?msg_len:BODYSIZE);
+                /* Make sure that everything is printable and that we
+                 * are NUL terminated...
+                 */
+		while ( msg_len > 0 ) {
+			char *text, tmptext[BODYSIZE];
+			int len;
+
+			memset(tmptext, 0x0, BODYSIZE);
+
+			text = msg->msg_iov[index].iov_base;
+			len = msg->msg_iov[index].iov_len;
+
+			if (msg_len == 1 && text[0] == 0) {
+				DEBUG_PRINT(DEBUG_MIN, "<empty> text[0]=%d",
+					    text[0]);
+				break;
+			}
+
+			if ( len > msg_len ) {
+				/* text[(len = msg_len) - 1] = '\0'; */
+				text[(len = msg_len)] = '\0';
+			}
+
+			if ( (msg_len -= len) > 0 ) { index++; }
+
+			for (i = 0; i < len - 1; ++i) {
+				if (!isprint(text[i])) text[i] = '.';
+			}
+
+ 			strncpy(tmptext, text, BODYSIZE);
+ 			tmptext[BODYSIZE-1] = '\0';
+
+			DEBUG_PRINT(DEBUG_MAX, "%s", tmptext);
+                }
+
+                DEBUG_PRINT(DEBUG_MIN, "\n");
+                fflush(stdout);
+        }  else { /* if(we have notification) */
+		struct sctp_assoc_change *sac;
+		struct sctp_send_failed *ssf;
+		struct sctp_paddr_change *spc;
+		struct sctp_remote_error *sre;
+		union sctp_notification *snp;
+		char addrbuf[INET6_ADDRSTRLEN];
+		const char *ap;
+		struct sockaddr_in *sin;
+		struct sockaddr_in6 *sin6;
+		int index = 0;
+
+		snp = (union sctp_notification *)msg->msg_iov[index].iov_base;
+
+		DEBUG_PRINT(DEBUG_MIN, "Notification:");
+        	
+		switch (snp->sn_header.sn_type) {
+			case SCTP_ASSOC_CHANGE:
+				sac = &snp->sn_assoc_change;
+				DEBUG_PRINT(DEBUG_MIN,
+					    " SCTP_ASSOC_CHANGE(%s)\n",
+					    sac_state_tbl[sac->sac_state]);
+				DEBUG_PRINT(DEBUG_MAX,
+					    "\t\t(assoc_change: state=%hu, "
+					    "error=%hu, instr=%hu "
+					    "outstr=%hu)\n",
+					    sac->sac_state, sac->sac_error,
+					    sac->sac_inbound_streams,
+					    sac->sac_outbound_streams);
+				break;
+			case SCTP_PEER_ADDR_CHANGE:
+				spc = &snp->sn_paddr_change;
+				DEBUG_PRINT(DEBUG_MIN,
+					    " SCTP_PEER_ADDR_CHANGE\n");
+				if (spc->spc_aaddr.ss_family == AF_INET) {
+					sin = (struct sockaddr_in *)
+					       &spc->spc_aaddr;
+					ap = inet_ntop(AF_INET, &sin->sin_addr,
+						       addrbuf,
+						       INET6_ADDRSTRLEN);
+				} else {
+					sin6 = (struct sockaddr_in6 *)
+						&spc->spc_aaddr;
+					ap = inet_ntop(AF_INET6,
+						       &sin6->sin6_addr,
+						       addrbuf,
+						       INET6_ADDRSTRLEN);
+				}
+				DEBUG_PRINT(DEBUG_MAX,
+					    "\t\t(peer_addr_change: %s "
+					    "state=%d, error=%d)\n",
+					    ap, spc->spc_state,
+					    spc->spc_error);
+				break;
+			case SCTP_SEND_FAILED:
+				ssf = &snp->sn_send_failed;
+				DEBUG_PRINT(DEBUG_MIN,
+					    " SCTP_SEND_FAILED\n");
+				DEBUG_PRINT(DEBUG_MAX,
+					    "\t\t(sendfailed: len=%hu "
+					    "err=%d)\n",
+					    ssf->ssf_length, ssf->ssf_error);
+				break;
+			case SCTP_REMOTE_ERROR:
+				sre = &snp->sn_remote_error;
+				DEBUG_PRINT(DEBUG_MIN,
+					    " SCTP_REMOTE_ERROR\n");
+				DEBUG_PRINT(DEBUG_MAX,
+					    "\t\t(remote_error: err=%hu)\n",
+					     ntohs(sre->sre_error));
+				break;
+			case SCTP_SHUTDOWN_EVENT:
+				DEBUG_PRINT(DEBUG_MIN,
+					    " SCTP_SHUTDOWN_EVENT\n");
+				break;
+			default:
+				DEBUG_PRINT(DEBUG_MIN,
+					    " Unknown type: %hu\n",
+					    snp->sn_header.sn_type);
+				break;
+		}
+
+		fflush(stdout);
+		return 1;
+
+        } /* notification received */
+
+        for (scmsg = CMSG_FIRSTHDR(msg);
+             scmsg != NULL;
+             scmsg = CMSG_NXTHDR(msg, scmsg)) {
+
+		data = (sctp_cmsg_data_t *)CMSG_DATA(scmsg);
+		if (debug_level) print_cmsg(scmsg->cmsg_type, data);
+	}
+
+
+	fflush(stdout);
+        return 0;
+
+} /* print_message() */
+
+struct sockaddr *
+append_addr(const char *parm, struct sockaddr *addrs, int *ret_count)
+{
+	struct sockaddr *new_addrs = NULL;
+	void *aptr;
+	struct sockaddr *sa_addr;
+	struct sockaddr_in *b4ap;
+	struct sockaddr_in6 *b6ap;
+	struct hostent *hst4 = NULL;
+	struct hostent *hst6 = NULL;
+	int i4 = 0;
+	int i6 = 0;
+	int j;
+	int orig_count = *ret_count;
+	int count = orig_count;
+	char *ipaddr = strdup(parm);
+	char *ifname;
+	int ifindex = 0;
+
+	/* check the interface. */
+	ifname = strchr(ipaddr,'%');
+	if (ifname) {
+		*ifname=0;
+		ifname++;
+		ifindex = if_nametoindex(ifname);
+		if (!ifindex) {
+			fprintf(stderr, "bad interface name: %s\n", ifname);
+			goto finally;
+		}
+	}
+
+	/* Get the entries for this host.  */
+	hst4 = gethostbyname(ipaddr);
+	hst6 = gethostbyname2(ipaddr, AF_INET6);
+
+	if ((NULL == hst4 || hst4->h_length < 1)
+	    && (NULL == hst6 || hst6->h_length < 1)) {
+		fprintf(stderr, "bad hostname: %s\n", ipaddr);
+		goto finally;
+	}
+
+	/* Figure out the number of addresses.  */
+	if (NULL != hst4) {
+		for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) {
+			count++;
+		}
+	}
+	if (NULL != hst6) {
+		for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) {
+			count++;
+		}
+	}
+
+	/* Expand memory for the new addresses.  Assume all the addresses
+	 * are v6 addresses.
+	 */
+	new_addrs = (struct sockaddr *)
+		realloc(addrs, sizeof(struct sockaddr_in6) * count);
+
+	if (NULL == new_addrs) {
+		count = *ret_count;
+		goto finally;
+	}
+
+	/* Skip the existing addresses. */
+	aptr = new_addrs;
+	for (j = 0; j < orig_count; j++) {
+		sa_addr = (struct sockaddr *)aptr;
+		switch(sa_addr->sa_family) {
+		case AF_INET:
+			aptr += sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			aptr += sizeof(struct sockaddr_in6);
+			break;
+		default:
+			count = orig_count;
+			goto finally;
+		}
+	}
+
+	/* Put the new addresses away.  */
+	if (NULL != hst4) {
+		for (j = 0; j < i4; ++j) {
+			b4ap = (struct sockaddr_in *)aptr;
+			memset(b4ap, 0x00, sizeof(*b4ap));
+			b4ap->sin_family = AF_INET;
+			b4ap->sin_port = htons(local_port);
+			bcopy(hst4->h_addr_list[j], &b4ap->sin_addr,
+			      hst4->h_length);
+
+			aptr += sizeof(struct sockaddr_in);
+		} /* for (loop through the new v4 addresses) */
+	}
+
+	if (NULL != hst6) {
+		for (j = 0; j < i6; ++j) {
+			b6ap = (struct sockaddr_in6 *)aptr;
+			memset(b6ap, 0x00, sizeof(*b6ap));
+			b6ap->sin6_family = AF_INET6;
+			b6ap->sin6_port =  htons(local_port);
+			b6ap->sin6_scope_id = if_index;
+			bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr,
+			      hst6->h_length);
+			if (!ifindex) {
+				b6ap->sin6_scope_id = ifindex;
+			}
+
+			aptr += sizeof(struct sockaddr_in6);
+		} /* for (loop through the new v6 addresses) */
+	}
+
+ finally:
+	free(ipaddr);
+	*ret_count = count;
+
+	return new_addrs;
+
+} /* append_addr() */
+
+int socket_r(void)
+{
+	struct sctp_event_subscribe subscribe;
+	int sk, error;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tsocket(%s, IPPROTO_SCTP)",
+		(socket_type == SOCK_SEQPACKET) ? "SOCK_SEQPACKET" : "SOCK_STREAM");
+
+	if ((sk = socket(s_loc.ss_family, socket_type, IPPROTO_SCTP)) < 0 ) {
+		if (do_exit) {
+			fprintf(stderr, "\n\n\t\t*** socket: failed to create"
+				" socket:  %s ***\n",
+        	       	        strerror(errno));
+			exit(1);
+		} else {
+			return -1;
+		}
+	}
+	DEBUG_PRINT(DEBUG_MIN, "  ->  sk=%d\n", sk);
+
+	memset(&subscribe, 0, sizeof(subscribe));
+	subscribe.sctp_data_io_event = 1;
+	subscribe.sctp_association_event = 1;
+	error = setsockopt(sk, SOL_SCTP, SCTP_EVENTS, (char *)&subscribe,
+			   sizeof(subscribe));
+	if (error) {
+		fprintf(stderr, "SCTP_EVENTS: error: %d\n", error);
+		exit(1);
+	}
+        if (max_stream > 0) {
+        	struct sctp_initmsg initmsg;
+        	memset(&initmsg, 0, sizeof(struct sctp_initmsg));
+        	initmsg.sinit_num_ostreams = max_stream;
+        	error = setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(struct sctp_initmsg));
+        	if (error) {
+        		fprintf(stderr, "SCTP_INITMSG: error: %d\n", error);
+        		exit(1);
+        	}
+        }
+	return sk;
+
+} /* socket_r() */
+
+int bind_r(int sk, struct sockaddr_storage *saddr)
+{
+        int error = 0, i = 0;
+	char *host_s, *serv_s;
+
+	if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+		fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n");
+		exit(1);
+	}
+	if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+		fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n");
+		exit(1);
+	}
+
+	do {
+		if (i > 0) sleep(1); /* sleep a while before new try... */
+
+		error = getnameinfo((struct sockaddr *)saddr, l_len, host_s,
+				    NI_MAXHOST, serv_s, NI_MAXSERV,
+				    NI_NUMERICHOST);
+
+		if (error)
+			printf("%s\n", gai_strerror(error));
+
+       		DEBUG_PRINT(DEBUG_MIN,
+			    "\tbind(sk=%d, [a:%s,p:%s])  --  attempt %d/%d\n",
+       			    sk, host_s, serv_s, i+1, MAX_BIND_RETRYS);
+
+       		error = bind(sk, (struct sockaddr *)saddr, l_len);
+
+	        if (error != 0) {
+	        	if( errno != EADDRINUSE ) {
+	        		if (do_exit) {
+	        		        fprintf(stderr, "\n\n\t\t***bind: can "
+						"not bind to %s:%s: %s ****\n",
+						host_s, serv_s,
+						strerror(errno));
+					exit(1);
+				} else {
+					return -1;
+				}
+			}
+		}
+		i++;
+		if (i >= MAX_BIND_RETRYS) {
+			fprintf(stderr, "Maximum bind() attempts. "
+				"Die now...\n\n");
+			exit(1);
+		}
+        } while (error < 0 && i < MAX_BIND_RETRYS);
+
+	free(host_s);
+	free(serv_s);
+	return 0;
+
+} /* bind_r() */
+
+int
+bindx_r(int sk, struct sockaddr *addrs, int count, int flag)
+{
+	int error;
+	int i;
+	struct sockaddr *sa_addr;
+	void *aptr;
+
+	/* Set the port in every address.  */
+	aptr = addrs;
+	for (i = 0; i < count; i++) {
+		sa_addr = (struct sockaddr *)aptr;
+
+		switch(sa_addr->sa_family) {
+		case AF_INET:
+			((struct sockaddr_in *)sa_addr)->sin_port =
+				htons(local_port);
+			aptr += sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			((struct sockaddr_in6 *)sa_addr)->sin6_port =
+				htons(local_port);
+			aptr += sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Invalid address family\n");
+			exit(1);
+		}
+	}
+
+	error = sctp_bindx(sk, addrs, count, flag);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t***bindx_r: error adding addrs:"
+			" %s. ***\n", strerror(errno));
+		exit(1);
+	}
+
+	return 0;
+
+} /* bindx_r() */
+
+int listen_r(int sk, int listen_count)
+{
+	int error = 0;
+	
+        DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n",
+		    sk, listen_count);
+
+ 	/* Mark sk as being able to accept new associations */
+        error = listen(sk, listen_count);
+        if (error != 0) {
+        	if (do_exit) {
+                	fprintf(stderr, "\n\n\t\t*** listen:  %s ***\n\n\n",
+                       		strerror(errno));
+			exit(1);
+		}
+		else return -1;
+        }
+        return 0;
+
+} /* listen_r() */
+
+int accept_r(int sk){
+	socklen_t len = 0;
+	int subsk;
+
+	DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk);
+
+	subsk = accept(sk, NULL, &len);
+	if (subsk < 0) {
+		fprintf(stderr, "\n\n\t\t*** accept:  %s ***\n\n\n", strerror(errno));
+		exit(1);
+	}
+
+	return subsk;
+} /* accept_r() */
+
+int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk);
+
+	/* Mark sk as being able to accept new associations */
+	error = connect(sk, serv_addr, addrlen);
+	if (error != 0) {
+		if (do_exit) {
+			fprintf(stderr, "\n\n\t\t*** connect:  %s ***\n\n\n",
+				strerror(errno));
+			exit(1);
+		}
+		else return -1;
+	}
+	return 0;
+
+} /* connect_r() */
+
+int connectx_r(int sk, struct sockaddr *addrs, int count)
+{
+	int error;
+	int i;
+	struct sockaddr *sa_addr;
+	void *aptr;
+
+	/* Set the port in every address.  */
+	aptr = addrs;
+	for (i = 0; i < count; i++) {
+		sa_addr = (struct sockaddr *)aptr;
+
+		switch(sa_addr->sa_family) {
+		case AF_INET:
+			((struct sockaddr_in *)sa_addr)->sin_port =
+				htons(remote_port);
+			aptr += sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			((struct sockaddr_in6 *)sa_addr)->sin6_port =
+				htons(remote_port);
+			aptr += sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Invalid address family\n");
+			exit(1);
+		}
+	}
+
+	error = sctp_connectx(sk, addrs, count, NULL);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** connectx_r: error connecting"
+			" to addrs: %s ***\n", strerror(errno));
+		exit(1);
+	}
+
+	return 0;
+
+} /* connectx_r() */
+
+int receive_r(int sk, int once)
+{
+	int recvsk = sk, i = 0, error = 0;
+        char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+        struct iovec iov;
+        struct msghdr inmessage;
+
+        /* Initialize inmessage with enough space for DATA... */
+        memset(&inmessage, 0, sizeof(inmessage));
+        if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		exit(1);
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+	/* Get the messages sent */
+	while (1) {
+
+		if (recvsk == sk && socket_type == SOCK_STREAM &&
+		    role == SERVER)
+			recvsk = accept_r(sk);
+
+		DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk);
+
+		error = recvmsg(recvsk, &inmessage, MSG_WAITALL);
+		if (error < 0 && errno != EAGAIN) {
+			if (errno == ENOTCONN && socket_type == SOCK_STREAM &&
+			    role == SERVER) {
+				printf("No association is present now!!\n");
+				close(recvsk);
+				recvsk = sk;
+				continue;
+			}
+
+			fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n",
+					strerror(errno));
+			fflush(stdout);
+			if (do_exit) exit(1);
+			else goto error_out;
+		}
+		else if (error == 0) {
+			if (socket_type == SOCK_STREAM && role == SERVER) {
+				printf("No association is present now!!\n");
+				close(recvsk);
+				recvsk = sk;
+				continue;
+			}
+			printf("\n\t\trecvmsg() returned 0 !!!!\n");
+			fflush(stdout);
+		}
+
+		if (print_message(recvsk, &inmessage, error) > 0)
+			continue; /* got a notification... */
+
+		inmessage.msg_control = incmsg;
+		inmessage.msg_controllen = sizeof(incmsg);
+		iov.iov_len = REALLY_BIG;
+		i++;
+		if (once)
+			break;
+	}
+
+	if (recvsk != sk)
+		close(recvsk);
+
+	free(iov.iov_base);
+	return 0;
+error_out:
+	close(sk);
+	free(iov.iov_base);
+	return -1;
+
+} /* receive_r () */
+
+int next_order(int state, int pattern)
+{
+	switch (pattern){
+	case ORDER_PATTERN_UNORDERED:
+		state = 0;
+		break;
+	case ORDER_PATTERN_ORDERED:
+		state = 1;
+		break;
+	case ORDER_PATTERN_ALTERNATE:
+		state = state ? 0 : 1;
+		break;
+	case ORDER_PATTERN_RANDOM:
+		state = rand() % 2;
+		break;
+	}
+
+	return state;
+}
+
+int next_stream(int state, int pattern)
+{
+	switch (pattern){
+	case STREAM_PATTERN_RANDOM:
+		state = rand() % (max_stream == 0 ? 1 : max_stream);
+		break;
+	case STREAM_PATTERN_SEQUENTIAL:
+		state = state + 1;
+		if (state >= max_stream)
+			state = 0;
+		break;
+	}
+
+	return state;
+}
+
+int next_msg_size(int msg_cnt)
+{
+	int msg_size;
+
+	if (size_arg) {
+		msg_size = size_arg;
+	} else if (test_case < NCASES) {
+		msg_size = msg_sizes[test_case][msg_cnt];
+	} else {
+		msg_size = (rand() % max_msgsize) + 1;
+	}
+
+	return msg_size;
+
+} /* next_msg_size() */
+
+int next_assoc(int i, int state, int pattern)
+{
+	int j;
+	int found = 0;
+	_assoc_state *as;
+
+
+	switch (pattern){
+	case ASSOC_PATTERN_RANDOM:
+		state = rand() % tosend;
+		break;
+	case ASSOC_PATTERN_SEQUENTIAL:
+		state = state + 1;
+		if (state >= tosend)
+			state = 0;
+		break;
+	}
+
+	as = poll_sks[i].assoc_state;
+	j = state;
+	do {
+		if (as[j].msg_sent < repeat_count) {
+			found = 1;
+			break;
+		}
+		if (++j >= tosend) {
+			j = 0;
+		}
+	} while (j != state);
+
+	if (found) {
+		return j;
+	} else {
+		return -1;
+	}
+	
+} /* next_assoc() */
+
+int send_r(int sk, int stream, int order, int send_size, int assoc_i)
+{
+	int error = 0;
+	struct msghdr outmsg;
+	struct iovec iov;
+	char *message = NULL;
+	int msglen = 0;
+	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+
+	if (send_size > 0) {
+		message = build_msg(send_size);
+		msglen = strlen(message) + 1;
+		iov.iov_base = message;
+		iov.iov_len = msglen;
+	}
+	else {
+		if (do_exit) {
+			exit(1);
+		} else {
+			goto error_out;
+		}
+	}
+
+	outmsg.msg_name = &s_rem;
+       	outmsg.msg_namelen = sizeof(struct sockaddr_storage);
+	outmsg.msg_iov = &iov;
+	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 = rand();
+	sinfo->sinfo_stream = stream;
+	sinfo->sinfo_flags = 0;
+	if (!order)
+		sinfo->sinfo_flags = SCTP_UNORDERED;
+	if (timetolive)
+		sinfo->sinfo_timetolive = timetolive;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n",
+		    sk, assoc_i, send_size);
+	DEBUG_PRINT(DEBUG_MAX, "\t  SNDRCV");
+	if (DEBUG_MAX == debug_level) {
+        	printf("(stream=%u ", 	sinfo->sinfo_stream);
+		printf("flags=0x%x ",	sinfo->sinfo_flags);
+		printf("ppid=%u\n",	sinfo->sinfo_ppid);
+	}
+
+	/* Send to our neighbor.  */
+	error = sendmsg(sk, &outmsg, MSG_WAITALL);
+	if (error != msglen) {
+		fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n",
+			strerror(errno));
+		fflush(stdout);
+	
+		if (do_exit) {
+			exit(1);
+		} else {
+			if (!drain)
+				goto error_out;
+		}
+	}
+
+	if (send_size > 0) free(message);
+	return 0;
+error_out:
+	if (send_size > 0) free(message);
+	return -1;
+
+} /* send_r() */
+
+int close_r(int sk)
+{
+	int error = 0;
+	
+	DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk);
+
+	error = close(sk);
+	if (error != 0) {
+		if (do_exit) {
+			fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n",
+				strerror(errno));
+			exit(1);
+		} else {
+			return -1;
+		}
+	}
+	fflush(stdout);
+	return 0;
+
+} /* close_r() */
+
+void
+server(int sk)
+{
+	if (max_msgsize > DEFAULT_MAX_WINDOW) {
+		if (setsockopt(sk, SOL_SOCKET, SO_RCVBUF, &max_msgsize,
+			       sizeof(max_msgsize)) < 0) {
+			perror("setsockopt(SO_RCVBUF)");
+			exit(1);
+		} 	
+	}
+
+	receive_r(sk, 0);
+
+} /* server() */
+
+void
+client(int sk)
+{
+	int msg_size;
+	int i;
+
+	for (i = 0; i < msg_cnt; i++) {
+
+		msg_size = next_msg_size(i);
+		order_state = next_order(order_state, order_pattern);
+		stream_state = next_stream(stream_state, stream_pattern);
+
+		if (send_r(sk, stream_state, order_state, msg_size, 0) < 0)
+			break;
+		/* The sender is echoing so do discard the echoed data. */
+		if (drain) {
+			receive_r(sk, 1);
+		}
+	}
+} /* client() */
+
+void
+mixed_mode_test(void)
+{
+	int error, i, j, max_fd, sks, size;
+	int assoc_i, n_msg_size, n_order, n_stream;
+	int done = 0;
+	fd_set *ibitsp = NULL, *obitsp = NULL, *xbitsp = NULL;
+        char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+        struct iovec iov;
+        struct msghdr inmessage;
+	_assoc_state *as;
+
+	
+	/* Set up the listeners.  If listeners is 0, set up one socket for
+	 * transmitting only.
+	 */
+	iov.iov_base = NULL;
+	max_fd = -1;
+	sks = (0 == listeners) ? 1 : listeners;
+	memset(poll_sks, 0, sks * sizeof(_poll_sks));
+
+	for (i = 0; i < sks; i++) {
+		poll_sks[i].sk = socket_r();
+
+		if (s_loc.ss_family == AF_INET6)
+			( (struct sockaddr_in6 *)&s_loc)->sin6_port =
+				htons(local_port + i);
+		else
+			( (struct sockaddr_in *)&s_loc)->sin_port =
+				htons(local_port + i);
+
+		bind_r(poll_sks[i].sk, &s_loc);
+		if (listeners) {
+			listen_r(poll_sks[i].sk, 100);
+		}
+		if (max_msgsize > DEFAULT_MAX_WINDOW) {
+			if (setsockopt(poll_sks[i].sk, SOL_SOCKET, SO_RCVBUF,
+				&max_msgsize, sizeof(max_msgsize)) < 0) {
+				perror("setsockopt(SO_RCVBUF)");
+				exit(1);
+			}
+		} 	
+
+		if (tosend) {
+			if ((poll_sks[i].assoc_state = (_assoc_state *)malloc(
+				sizeof(_assoc_state) * tosend)) == NULL) {
+				printf("Can't allocate memory.\n");
+				goto clean_up;
+			}
+			memset(poll_sks[i].assoc_state, 0,
+				sizeof(_assoc_state) * tosend);
+		}
+
+		if (poll_sks[i].sk > max_fd) {
+			max_fd = poll_sks[i].sk;
+		}
+	}
+
+	size = howmany(max_fd + 1, NFDBITS) * sizeof(fd_mask);
+	if ((ibitsp = (fd_set *)malloc(size)) == NULL) {
+		printf("Can't allocate memory.\n");
+		goto clean_up;
+	}
+	if ((obitsp = (fd_set *)malloc(size)) == NULL) {
+		printf("Can't allocate memory.\n");
+		goto clean_up;
+	}
+	if ((xbitsp = (fd_set *)malloc(size)) == NULL) {
+		printf("Can't allocate memory.\n");
+		goto clean_up;
+	}
+
+	memset(ibitsp, 0, size);
+	memset(obitsp, 0, size);
+	memset(xbitsp, 0, size);
+
+
+        /* Initialize inmessage with enough space for DATA... */
+        memset(&inmessage, 0, sizeof(inmessage));
+        if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		goto clean_up;
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+	/* Set up the remote port number per association for output.  */
+	for (i = 0; i < sks; i++) {
+		as = poll_sks[i].assoc_state;
+		for (j = 0; j < tosend; j++) {
+			as[j].rem_port = remote_port + j;
+		}
+	}
+
+	while (!done) {
+
+		for (i = 0; i < sks; i++) {
+			FD_SET(poll_sks[i].sk, ibitsp);
+			FD_SET(poll_sks[i].sk, obitsp);
+			FD_SET(poll_sks[i].sk, xbitsp);
+		}
+		if ((error = select(max_fd + 1, ibitsp, obitsp, xbitsp,
+			(struct timeval *)0)) < 0) {
+			fprintf(stderr, "\n\t\t*** select() failed ");
+			fprintf(stderr, "with error: %s\n\n",
+				strerror(errno));
+			fflush(stdout);
+			goto clean_up;
+		}
+		
+		for (i = 0; i < sks; i++) {
+			/* Is there anything to read from the socket?  */
+			if (listeners && FD_ISSET(poll_sks[i].sk, ibitsp)) {
+
+				FD_CLR(poll_sks[i].sk, ibitsp);
+				error = recvmsg(poll_sks[i].sk, &inmessage,
+					MSG_WAITALL);
+				if (error < 0) {
+					fprintf(stderr,
+						"\n\t\t*** recvmsg: %s ***\n\n",
+						strerror(errno));
+					fflush(stdout);
+					goto clean_up;
+				}
+				else if (error == 0) {
+					printf("\n\t\trecvmsg() returned ");
+				       	printf("0 !!!!\n");
+					fflush(stdout);
+				}
+
+				print_message(poll_sks[i].sk, &inmessage,
+					error);
+
+				inmessage.msg_control = incmsg;
+				inmessage.msg_controllen = sizeof(incmsg);
+				iov.iov_len = REALLY_BIG;
+			}
+			
+			/* Is this socket writeable?  */
+			if (tosend && FD_ISSET(poll_sks[i].sk, obitsp)) {
+
+				FD_CLR(poll_sks[i].sk, obitsp);
+
+				/* Pick an association.  */
+				assoc_i = next_assoc(i, poll_sks[i].assoc_i,
+						assoc_pattern);
+				if (assoc_i < 0) {
+					/* No work to do on any associations.
+					 * We are probably done. */
+					if (!listeners) {
+						done = 1;
+					}
+					continue;
+				}
+				poll_sks[i].assoc_i = assoc_i;
+
+				as = poll_sks[i].assoc_state;
+				n_msg_size = next_msg_size(as[assoc_i].msg_cnt);
+				n_order = as[assoc_i].order_state =
+					next_order(as[assoc_i].order_state,
+					order_pattern);
+				n_stream = as[assoc_i].stream_state =
+					next_stream(as[assoc_i].stream_state,
+					stream_pattern);
+
+				/* Set the destination port.  */
+				if (s_rem.ss_family == AF_INET6)
+					( (struct sockaddr_in6 *)&s_rem)->
+						sin6_port =
+						htons(as[assoc_i].rem_port);
+				else
+					( (struct sockaddr_in *)&s_rem)->
+						sin_port =
+						htons(as[assoc_i].rem_port);
+
+				/* Send a message thru the association.  */
+				if (send_r(poll_sks[i].sk, n_stream, n_order,
+					n_msg_size, assoc_i) < 0) {
+					/* Don't increment counter if there
+					 * is a problem of sending.
+					 */
+					continue;
+				}
+
+				/* Increment counters. */
+				if (++as[assoc_i].msg_cnt >= MSG_CNT) {
+					as[assoc_i].msg_cnt = 0;
+				}
+				if (++as[assoc_i].msg_sent >=
+					repeat_count) {
+					fprintf(stderr, "Association #%d in ",
+						assoc_i);
+					fprintf(stderr, "sk=%d has ",
+						poll_sks[i].sk);
+					fprintf(stderr, "completed %d msg as ",
+						as[assoc_i].msg_sent);
+					fprintf(stderr, "cycle %d.\n",
+						++as[assoc_i].cycle);
+
+					/* In the mixed mode, -x not only
+					 * specify the longer repeat cycle,
+					 * but it also mean to run the test
+					 * forever.
+					 */
+					if (xflag) {
+						as[assoc_i].msg_sent = 0;
+					}
+
+				}
+
+			}
+		}
+	}
+
+clean_up:
+	for (i = 0; i < sks; i++) {
+		close(poll_sks[i].sk);
+		if (poll_sks[i].assoc_state) {
+			free(poll_sks[i].assoc_state);
+		}
+	}
+
+	if (ibitsp) free(ibitsp);
+	if (obitsp) free(obitsp);
+	if (xbitsp) free(xbitsp);
+
+	if (iov.iov_base) free(iov.iov_base);
+
+} /* mixed_mode_test() */
+
+void start_test(int role)
+{
+	int sk;
+	int i = 0;
+	
+	DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n");
+
+	repeat_count = repeat;
+
+
+	if (MIXED == role) {
+		repeat_count = repeat_count * msg_cnt;  /* Repeat per assoc. */
+		mixed_mode_test();
+		return;
+	}
+
+	sk = socket_r();
+	if (sk < 0) {
+		DEBUG_PRINT(DEBUG_NONE, "\nSocket create err %d\n", errno);
+		return;
+	}
+
+	if (bind_r(sk, &s_loc) == -1) {
+		DEBUG_PRINT(DEBUG_NONE, "\nSocket bind err %d\n", errno);
+		return;
+	}
+
+	/* Do we need to do bindx() to add any additional addresses? */
+	if (bindx_add_addrs)
+		bindx_r(sk, bindx_add_addrs, bindx_add_count,
+			   SCTP_BINDX_ADD_ADDR);
+
+	if (role == SERVER) {
+		listen_r(sk, 100);
+	} else {
+		if (socket_type == SOCK_STREAM && connectx_count == 0)
+			connect_r(sk, (struct sockaddr *)&s_rem, r_len);
+
+		if (connectx_count != 0)
+			connectx_r(sk, connectx_addrs, connectx_count);
+	}
+
+	if (!debug_level) {
+		printf("     ");
+	}
+
+	for(i = 0; i < repeat_count; i++) {
+		
+		if (role == SERVER) {
+			DEBUG_PRINT(DEBUG_NONE,
+				    "Server: Receiving packets.\n");
+			server(sk);
+		} else {
+			DEBUG_PRINT(DEBUG_NONE,
+				    "Client: Sending packets.(%d/%d)\n",
+		    		    i+1, repeat_count);
+			client(sk);
+		}
+
+		fflush(stdout);
+	}
+
+	close_r(sk);
+
+} /* start_test() */
+
+int
+main(int argc, char *argv[])
+{
+	int c;
+	char *interface = NULL;
+	struct sockaddr_in *t_addr;
+	struct sockaddr_in6 *t_addr6;
+	struct sockaddr *tmp_addrs = NULL;
+	
+        /* Parse the arguments.  */
+        while ((c = getopt(argc, argv, ":H:L:P:S:a:h:p:c:d:lm:sx:X:o:t:M:r:w:Di:TB:C:O:")) >= 0 ) {
+
+                switch (c) {
+		case 'H':
+			local_host = optarg;
+			break;
+		case 'L':
+			role = MIXED;
+			listeners = atoi(optarg);
+			if (listeners > MAX_POLL_SKS) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case 'S':
+			role = MIXED;
+			tosend = atoi(optarg);
+			if (tosend > MAX_POLL_SKS) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'a':
+			assoc_pattern = atoi(optarg);
+			if (assoc_pattern <  ASSOC_PATTERN_SEQUENTIAL
+			    || assoc_pattern > ASSOC_PATTERN_RANDOM ) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'h':
+			remote_host = optarg;
+			break;
+		case 'D':
+			drain = 1;
+			do_exit = 0;
+			break;
+		case 'p':
+			remote_port = atoi(optarg);
+			break;
+		case 's':
+			if (role != NOT_DEFINED) {
+				printf("%s: only -s or -l\n", argv[0]);
+				usage(argv[0]);
+				exit(1);
+			}
+			role = CLIENT;
+			break;
+		case 'l':
+			if (role != NOT_DEFINED) {
+				printf("%s: only -s or -l\n", argv[0]);
+				usage(argv[0]);
+				exit(1);
+			}
+			role = SERVER;
+			break;
+		case 'd':
+			debug_level = atoi(optarg);
+			if (debug_level < DEBUG_NONE
+			    || debug_level > DEBUG_MAX) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'x':
+			repeat = atoi(optarg);
+			if (!repeat) {
+				xflag = 1;
+				repeat = BIG_REPEAT;
+			}
+			break;
+		case 'X':
+			msg_cnt = atoi(optarg);
+			if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'c':
+			test_case = atoi(optarg);
+			if (test_case > NCASES) {
+				usage(argv[0]);
+				exit(1);
+			}
+			if (test_case < 0) {
+				size_arg = -test_case;
+			}
+			
+			break;
+		case 'o':
+			order_pattern = atoi(optarg);
+			if (order_pattern <  ORDER_PATTERN_UNORDERED
+			    || order_pattern  > ORDER_PATTERN_RANDOM ) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'O':
+			timetolive = atoi(optarg);
+			if (timetolive < 0) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 't':
+			stream_pattern = atoi(optarg);
+			if (stream_pattern <  STREAM_PATTERN_SEQUENTIAL
+			    || stream_pattern > STREAM_PATTERN_RANDOM ) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'M':
+			max_stream = atoi(optarg);
+			if (max_stream <  0
+			    || max_stream >= (1<<16)) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'r':
+			seed = atoi(optarg);
+			break;
+		case 'm':
+			max_msgsize = atoi(optarg);
+#if 0
+			if ((max_msgsize < DEFAULT_MIN_WINDOW) ||
+			    (max_msgsize > 65515)) {
+				usage(argv[0]);
+				exit(1);
+			}
+#endif
+			break;
+		case 'i':
+			interface = optarg;
+			if_index = if_nametoindex(interface);
+			if (!if_index) {
+				printf("Interface %s unknown\n", interface);
+				exit(1);
+			}
+			break;
+		case 'T':
+			socket_type = SOCK_STREAM;
+			break;
+		case 'B':
+			tmp_addrs = append_addr(optarg, bindx_add_addrs,
+						&bindx_add_count);
+			if (NULL == tmp_addrs) {
+				fprintf(stderr, "No memory to add ");
+				fprintf(stderr, "%s\n", optarg);
+				exit(1);
+			}
+			bindx_add_addrs = tmp_addrs;
+			break;
+		case 'C':
+			tmp_addrs = append_addr(optarg, connectx_addrs,
+						&connectx_count);
+			if (NULL == tmp_addrs) {
+				fprintf(stderr, "No memory to add ");
+				fprintf(stderr, "%s\n", optarg);
+				exit(1);
+			}
+			connectx_addrs = tmp_addrs;
+			break;
+		case '?':
+		default:
+			usage(argv[0]);
+			exit(0);
+		}
+	} /* while() */
+
+	if (NOT_DEFINED == role) {
+		usage(argv[0]);
+		exit(1);
+	}
+
+
+	if (SERVER == role && NULL == local_host && remote_host != NULL) {
+		fprintf (stderr, "%s: Server needs local address, "
+			 "not remote address\n", argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+	if (CLIENT == role && NULL == remote_host && connectx_count == 0) {
+		fprintf (stderr, "%s: Client needs at least remote address "
+			 "& port\n", argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+	if (MIXED == role) {
+		if (listeners && NULL == local_host) {
+			fprintf (stderr, "%s: Servers need local address\n",
+				argv[0]);
+			usage(argv[0]);
+			exit(1);
+		}
+		if (tosend && NULL == remote_host) {
+			fprintf (stderr, "%s: Clients need remote address ",
+				argv[0]);
+			fprintf (stderr, "& port\n");
+			usage(argv[0]);
+			exit(1);
+		}
+	}
+
+	if (optind < argc) {
+                fprintf(stderr, "%s: non-option arguments are illegal: ",
+                        argv[0]);
+                while (optind < argc)
+                        fprintf(stderr, "%s ", argv[optind++]);
+                fprintf (stderr, "\n");
+                usage(argv[0]);
+                exit(1);
+	}
+
+	if (remote_host != NULL && connectx_count != 0) {
+		fprintf(stderr, "%s: You can not provide both -h and -C options.\n",
+			argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (remote_host != NULL && remote_port != 0) {
+		struct addrinfo *res;
+		int error;
+		char *host_s, *serv_s;
+
+		if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+			fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
+			exit(1);
+		}
+		if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+			fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
+			exit(1);
+		}
+
+		error = getaddrinfo(remote_host, 0, NULL, &res);
+		if (error) {
+			printf("%s.\n", gai_strerror(error));
+			usage(argv[0]);
+			exit(1);
+		}
+
+		switch (res->ai_family) {
+			case AF_INET:
+				t_addr = (struct sockaddr_in *)&s_rem;
+
+				memcpy(t_addr, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr->sin_family = res->ai_family;
+				t_addr->sin_port = htons(remote_port);
+
+				r_len = res->ai_addrlen;
+
+#ifdef __FreeBSD__
+				t_addr->sin_len = r_len;
+#endif
+				break;
+			case AF_INET6:
+
+				t_addr6 = (struct sockaddr_in6 *)&s_rem;
+				
+				memcpy(t_addr6, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr6->sin6_family = res->ai_family;
+				t_addr6->sin6_port = htons(remote_port);
+				if (interface)
+					t_addr6->sin6_scope_id =
+						if_nametoindex(interface);
+
+				r_len = res->ai_addrlen;
+
+#ifdef __FreeBSD__
+				t_addr6->sin6_len = r_len;
+#endif
+				break;
+		}
+
+		getnameinfo((struct sockaddr *)&s_rem, r_len, host_s,
+			    NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
+			
+		DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n",
+			    host_s, serv_s, res->ai_family);
+
+		freeaddrinfo(res);
+        }
+
+	if (connectx_count != 0) {
+		switch (connectx_addrs->sa_family) {
+		case AF_INET:
+			t_addr = (struct sockaddr_in *)&s_rem;
+			r_len = sizeof(struct sockaddr_in);
+			memcpy(t_addr, connectx_addrs, r_len);
+			t_addr->sin_port = htons(remote_port);
+			break;
+		case AF_INET6:
+			t_addr6 = (struct sockaddr_in6 *)&s_rem;
+			r_len = sizeof(struct sockaddr_in6);
+			memcpy(t_addr6, connectx_addrs, r_len);
+			t_addr6->sin6_port = htons(remote_port);
+			break;
+		}
+	}
+
+	if (local_host != NULL) {
+		struct addrinfo *res;
+		int error;
+		char *host_s, *serv_s;
+		struct sockaddr_in *t_addr;
+		struct sockaddr_in6 *t_addr6;
+
+		if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+			fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
+			exit(1);
+		}
+		if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+			fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
+			exit(1);
+		}
+
+		if (strcmp(local_host, "0") == 0)
+			local_host = "0.0.0.0";
+
+		error = getaddrinfo(local_host, 0, NULL, &res);
+		if (error) {
+			printf("%s.\n", gai_strerror(error));
+			usage(argv[0]);
+			exit(1);
+		}
+
+		switch (res->ai_family) {
+			case AF_INET:
+				t_addr = (struct sockaddr_in *)&s_loc;
+				memcpy(t_addr, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr->sin_family = res->ai_family;
+				t_addr->sin_port = htons(local_port);
+
+				l_len = res->ai_addrlen;
+
+#ifdef __FreeBSD__
+				t_addr->sin_len = l_len;
+#endif
+				break;
+			case AF_INET6:
+				t_addr6 = (struct sockaddr_in6 *)&s_loc;
+
+				memcpy(t_addr6, res->ai_addr,
+				       res->ai_addrlen);
+				t_addr6->sin6_family = res->ai_family;
+				t_addr6->sin6_port = htons(local_port);
+				if (interface)
+					t_addr6->sin6_scope_id =
+						if_nametoindex(interface);
+
+				l_len = res->ai_addrlen;
+
+#ifdef __FreeBSD__
+				t_addr6->sin6_len = l_len;
+#endif
+				break;
+		}
+
+		error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s,
+			    NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
+
+		if (error)
+			printf("%s..\n", gai_strerror(error));
+
+		DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n",
+			    host_s, serv_s, res->ai_family);
+
+		freeaddrinfo(res);
+        }
+
+
+	/* A half-hearted attempt to seed rand() */
+	if (seed == 0 ) {
+		seed = time(0);
+		DEBUG_PRINT(DEBUG_NONE, "seed = %d\n", seed);	
+	}
+	
+	srand(seed);
+
+	/* Let the testing begin. */
+	start_test(role);
+
+	return 0;
+
+} /*  main() */
diff --git a/src/apps/sctp_xconnect.c b/src/apps/sctp_xconnect.c
new file mode 100644
index 0000000..6759c0e
--- /dev/null
+++ b/src/apps/sctp_xconnect.c
@@ -0,0 +1,579 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2003
+ *
+ * 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:
+ *    Ryan Layer		<rmlayer@us.ibm.com>
+ */
+
+#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>
+#include <netdb.h>
+#include <getopt.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 1;
+int TST_CNT = 0;
+
+#define MAXHOSTNAME 64
+
+#define MAXCLIENTNUM 10000
+
+#define TRUE 1
+
+#define SERVER 1
+#define CLIENT 0
+#define NOT_DEFINED -1
+
+int mode = NOT_DEFINED;
+
+int	assoc_num,
+	remote_port,
+	local_port;
+int active = 0;
+
+char *local_host = NULL;
+char *remote_host = NULL;
+sockaddr_storage_t client_loop,
+		server_loop;
+struct hostent *hst;
+char big_buffer[REALLY_BIG];
+
+void usage(char *argv0);
+void parse_arguments(int argc, char*argv[]);
+void data_received(struct msghdr *inmessage, int len, int stream,
+                        int server_socket);
+int event_received(struct msghdr *inmessage, int assoc_num);
+void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds);
+void server_mode(void);
+void client_mode(void);
+
+/* Print the syntax/usage */
+void usage(char *argv0)
+{
+	printf("usage: %s -H localhost -P localport -l|c [-h remotehost]\n"
+	       "\t\t[-p remoteport] [-a] [-n <cnt>]\n" 
+	       " -H\t\tspecify a local address.\n"
+	       " -P\t\tspecify the local port number to be used\n"
+	       " -l\t\trun in server mode.\n"
+	       " -c\t\trun in client mode.\n"
+	       " -h\t\tspecify the peer address.\n"
+	       " -p\t\tspecify the port number for the peer address.\n"
+	       " -a\t\tactively generate traffic with the server.\n"
+	       " -n\t\tspecify the number of associations to create.\n",
+	       argv0);
+}
+
+/* Parse command line options */
+void parse_arguments(int argc, char*argv[]) {
+	int c;
+
+	while ((c = getopt(argc, argv, ":H:P:ach:ln:p:")) >= 0) {
+		switch (c) {
+			case 'H':
+				local_host = optarg;
+				break;
+			case 'P':
+				local_port = atoi(optarg);
+				break;
+			case 'c':
+			    if (mode == NOT_DEFINED)
+					mode = CLIENT;
+				else {
+					usage(argv[0]);
+					exit(0);
+				}
+				break;
+			case 'a':
+				active = 1;
+				break;
+			case 'h':
+				remote_host = optarg;
+				break;
+			case 'l':
+			    if (mode == NOT_DEFINED)
+					mode = SERVER;
+				else {
+					usage(argv[0]);
+					exit(0);
+				}
+				break;
+			case 'n':
+				assoc_num = atoi(optarg);
+				break;
+			case 'p':
+				remote_port = atoi(optarg);
+				break;
+			default:
+				usage(argv[0]);
+				exit(0);
+		}
+	} /* while() */
+
+	if (mode == CLIENT) {
+		if (assoc_num) {
+			if (assoc_num > MAXCLIENTNUM) {
+				printf("The number of associations indicated "
+					"is greater than the");
+				printf("max number of associations "
+					"allowed(%d).", MAXCLIENTNUM);
+				usage(argv[0]);
+				exit(0);
+			}
+		} else
+			assoc_num = 1;
+
+		if (remote_host && remote_port) {
+			hst = gethostbyname(remote_host);
+
+			memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0],
+				   sizeof(server_loop.v4.sin_addr));
+
+			server_loop.v4.sin_family = AF_INET;
+server_loop.v4.sin_port = htons(remote_port);
+		} else {
+			printf("Remote host and remote port must be defined "
+				"in client mode\n");
+			usage(argv[0]);
+			exit(0);
+		}
+
+		if (local_host) {
+			hst = gethostbyname(local_host);
+
+			memcpy(&client_loop.v4.sin_addr, hst->h_addr_list[0],
+				   sizeof(client_loop.v4.sin_addr));
+		} else
+			client_loop.v4.sin_addr.s_addr = INADDR_ANY;
+
+		if (local_port)
+			client_loop.v4.sin_port = htons(local_port);
+		else
+			client_loop.v4.sin_port = 0;
+
+		client_loop.v4.sin_family = AF_INET;
+	} else if (mode == SERVER) {
+		if (active) {
+			printf("This option if for client use only");
+			usage(argv[0]);
+			exit(0);
+		}
+
+		if (remote_host || remote_port) {
+			printf("Remote values not needed in server mode.\n");
+			usage(argv[0]);
+			exit(0);
+		}
+
+		if (local_host) {
+			hst = gethostbyname(local_host);
+
+			memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0],
+				   sizeof(server_loop.v4.sin_addr));
+		} else
+			server_loop.v4.sin_addr.s_addr = INADDR_ANY;
+
+		if (local_port)
+			server_loop.v4.sin_port = htons(local_port);
+		else {
+			printf("Specify a local port in server mode.\n");
+			usage(argv[0]);
+			exit(0);
+		}
+
+		server_loop.v4.sin_family = AF_INET;
+	} else {
+		printf("Must assisgn a client or server mode.\n");
+		usage(argv[0]);
+		exit(0);
+	}
+} /* parse_arguments() */
+
+/* Handle data received */
+void data_received(struct msghdr *inmessage, int len, int stream, int socket) {
+
+	int ppid, error;
+	char *ping = "PING";
+
+	if (mode == SERVER) {
+		ppid = rand();
+
+		error = sctp_sendmsg(socket,
+				inmessage->msg_iov->iov_base,
+				len,
+				(struct sockaddr *)inmessage->msg_name,
+				inmessage->msg_namelen,
+				ppid,
+				0,
+				stream,
+				0, 0);
+
+		if (error < 0) {
+			printf("Send Failure: %s.\n", strerror(errno));
+			DUMP_CORE;
+		}
+	} else {
+		ppid = rand();
+
+		printf("Data Received by socket #: %d.\n", socket);
+		printf("\tMessage = %s\n",
+			(char *)inmessage->msg_iov->iov_base);
+
+		if (active) {
+			error = sctp_sendmsg(socket, ping, strlen(ping) + 1,
+					     (struct sockaddr *)&server_loop,
+					     sizeof(server_loop), ppid, 0,
+					     stream, 0, 0);
+			if (error < 0) {
+				printf("Send Failure: %s.\n",
+				       strerror(errno));
+				DUMP_CORE;
+			}
+		}
+	}
+}
+
+/* This will print what type of SCTP_ASSOC_CHANGE state that was received */
+void print_sctp_sac_state(struct msghdr *msg) {
+
+	char *data;
+	union sctp_notification *sn;
+
+	if (msg->msg_flags & MSG_NOTIFICATION) {
+		data = (char *)msg->msg_iov[0].iov_base;
+
+		sn = (union sctp_notification *)data;
+
+		switch (sn->sn_assoc_change.sac_state) {
+				case SCTP_COMM_UP:
+						printf("SCTP_COMM_UP\n");
+						break;
+				case SCTP_COMM_LOST:
+						printf("SCTP_COMM_LOST\n");
+						break;
+				case SCTP_RESTART:
+						printf("SCTP_RESTART");
+						break;
+				case SCTP_SHUTDOWN_COMP:
+						printf("SCTP_SHUTDOWN_COMP\n");
+						break;
+				case SCTP_CANT_STR_ASSOC:
+						printf("SCTP_CANT_STR_ASSOC\n");
+						break;
+				default:
+						break;
+		}
+	}
+} /* void print_sctp_sac_state() */
+
+/* Tests what type of MSG_NOTIFICATION has been received.
+* For now this fucntion only works with SCTP_ASSOC_CHANGE 
+* types, but can be easily expanded.
+*
+* Will return...
+* -1 if the msg_flags is not MSG_NOTIFICATION
+*  0 if the MSG_NOTIFICATION type differs from the type
+*       passed into the additional variable
+*  1 if the MSG_NOTIFICATION type matches the type
+*       passed into the additional variable
+*/
+int test_check_notification_type(struct msghdr *msg,
+	uint16_t sn_type,
+	uint32_t additional) {
+
+	char *data;
+	union sctp_notification *sn;
+
+	if (!(msg->msg_flags & MSG_NOTIFICATION)) {
+		return -1;
+	} else {
+
+		/* Fixup for testframe. */
+		data = (char *)msg->msg_iov[0].iov_base;
+
+		sn = (union sctp_notification *)data;
+
+		if (sn->sn_header.sn_type != sn_type)
+			return 0;
+		else if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE)
+			if (sn->sn_assoc_change.sac_state == additional)
+				return 1;
+		return 0;
+	}
+}
+
+/* Determine the type of event and make correct adjustments to the
+* association count
+*/
+int event_received(struct msghdr *inmessage, int assoc_num) {
+
+	int error;
+
+	printf("Event Received\n");
+
+	print_sctp_sac_state(inmessage);
+
+	if (mode == SERVER) {
+		/* Test type of Event */
+		error = test_check_notification_type(inmessage,
+						SCTP_ASSOC_CHANGE,
+						SCTP_COMM_UP);
+		if (error > 0) {
+			assoc_num++;
+			printf("Assosiation Established: count = %d.\n",
+				assoc_num);
+		} else {
+			error = test_check_notification_type(inmessage,
+							SCTP_ASSOC_CHANGE,
+							SCTP_SHUTDOWN_COMP);
+
+			if (error > 0) {
+				assoc_num--;
+				printf("Assosiation Shutdown: count = %d.\n",
+					assoc_num);
+			}
+		}
+	}
+	return assoc_num;
+}
+
+void server_mode() {
+	sockaddr_storage_t msgname;
+	int server_socket,
+		error,
+		stream;
+	int assoc_num =0;
+	struct msghdr inmessage;
+	struct iovec iov;
+	char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+
+
+	printf("Running in Server Mode...\n");
+
+	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);
+	inmessage.msg_name = &msgname;
+	inmessage.msg_namelen = sizeof (msgname);
+
+	stream = 1;
+
+	server_socket = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+	if (server_socket < 0) {
+		printf("Socket Failure:  %s.\n", strerror(errno));
+		DUMP_CORE;
+	}
+
+	error = bind(server_socket, &server_loop.sa, sizeof(server_loop));
+	if (error != 0 ) {
+		printf("Bind Failure: %s.\n", strerror(errno));
+		DUMP_CORE;
+	}
+
+	error = listen(server_socket, 1);
+	if (error != 0) {
+		printf("Listen Failure: %s.\n", strerror(errno));
+		DUMP_CORE;
+	}
+	while (TRUE) {
+		error = recvmsg(server_socket, &inmessage, MSG_WAITALL);
+		if (error < 0) {
+			printf("Receive Failure: %s\n",
+			strerror(errno));
+		} else {
+		if (inmessage.msg_flags & MSG_NOTIFICATION)
+			assoc_num = event_received(&inmessage, assoc_num);
+		else
+			data_received(&inmessage, error, stream, server_socket);
+		}
+	}
+}
+
+void client_mode() {
+
+	int i, error, stream, max_socket = 0;
+	uint32_t ppid = 0;
+	int client_socket[assoc_num];
+	char *message = "Awake";
+	fd_set rfds;
+	struct timeval tv;
+
+        stream = 1;
+
+	printf("Running in Client Mode...\n");
+
+        /* Create the sockets */
+	for (i = 0; i < assoc_num; i++) {
+		client_socket[i] = socket(PF_INET, SOCK_SEQPACKET,
+					IPPROTO_SCTP);
+		if (client_socket[i] < 0 ){
+			printf("Socket Failure: %s.\n", strerror(errno));
+			DUMP_CORE;
+		}
+
+		if (local_port) {
+			error = bind(client_socket[i], &client_loop.sa,
+				sizeof(client_loop));
+			if (error < 0) {
+				printf("Bind Failure: %s\n", strerror(errno));
+				DUMP_CORE;
+			}
+		}
+
+		printf("Create Socket #: %d\n", client_socket[i]);
+
+		/* Connect to server and send initial message */
+		error = connect(client_socket[i], &server_loop.sa,
+						    sizeof(server_loop));
+		if (error < 0){
+			printf("Connect Failure: %s.\n", strerror(errno));
+			DUMP_CORE;
+		}
+
+		max_socket = client_socket[i];
+
+                ppid++;
+
+		/* Send initial message */
+		error = sctp_sendmsg(client_socket[i],
+				message,
+				strlen(message) + 1,
+				(struct sockaddr *)&server_loop,
+				sizeof(server_loop),
+				ppid,
+				0,
+				stream,
+				0, 0);
+		if (error < 0 ) {
+			printf("Send Failure: %s.\n", strerror(errno));
+			DUMP_CORE;
+		}
+	}
+
+	while (TRUE){
+
+		/* Clear the set for select() */
+		FD_ZERO(&rfds);
+
+		/* Set time out values for select() */
+		tv.tv_sec = 5;
+		tv.tv_usec = 0;
+
+		/* Add the sockets select() will examine */
+		for (i = 0; i < assoc_num; i++) {
+			FD_SET(client_socket[i], &rfds);
+		}
+
+		/* Wait until there is data to be read from one of the
+		 * sockets, or until the timer expires
+		 */
+		error = select(max_socket + 1, &rfds, NULL, NULL, &tv);
+
+		if (error < 0) {
+			printf("Select Failure: %s.\n", strerror(errno));
+			DUMP_CORE;
+		} else if (error) {
+			/* Loop through the array of sockets to find the ones
+			 *that have information to be read
+			 */
+			process_ready_sockets(client_socket, assoc_num, &rfds);
+		}
+	}
+}
+
+void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds) {
+
+        int i, stream, error;
+	struct msghdr inmessage;
+	struct iovec iov;
+	char incmsg[CMSG_SPACE(sizeof (sctp_cmsg_data_t))];
+	sockaddr_storage_t msgname;
+
+        /* Setup inmessage to be able to receive in incomming message */
+	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);
+	inmessage.msg_name = &msgname;
+	inmessage.msg_namelen = sizeof (msgname);
+
+	stream = 1;
+
+	for( i = 0; i < assoc_num; i++) {
+		if (FD_ISSET(client_socket[i], rfds)) {
+				error = recvmsg(client_socket[i], &inmessage,
+						MSG_WAITALL);
+				if (error < 0)
+						printf("Receive Failure: %s\n",
+							strerror(errno));
+				else {
+		/* Test to find the type of message that was read(event/data) */
+					if (inmessage.msg_flags &
+						MSG_NOTIFICATION)
+						 event_received(&inmessage,
+								0);
+
+					else
+						data_received(&inmessage, error,
+							stream,
+							client_socket[i]);
+			}
+		}
+	}
+}
+
+int main(int argc, char *argv[]) {
+
+	parse_arguments(argc, argv);
+
+	if (mode == SERVER) {
+		server_mode();
+	} else if (mode == CLIENT){
+		client_mode();
+	}
+	exit(1);
+}
+
diff --git a/src/func_tests/.gitignore b/src/func_tests/.gitignore
new file mode 100644
index 0000000..720db65
--- /dev/null
+++ b/src/func_tests/.gitignore
@@ -0,0 +1,41 @@
+test_1_to_1_accept_close
+test_1_to_1_addrs
+test_1_to_1_connect
+test_1_to_1_connectx
+test_1_to_1_events
+test_1_to_1_initmsg_connect
+test_1_to_1_nonblock
+test_1_to_1_recvfrom
+test_1_to_1_recvmsg
+test_1_to_1_rtoinfo
+test_1_to_1_send
+test_1_to_1_sendmsg
+test_1_to_1_sendto
+test_1_to_1_shutdown
+test_1_to_1_socket_bind_listen
+test_1_to_1_sockopt
+test_1_to_1_threads
+test_assoc_abort
+test_assoc_shutdown
+test_autoclose
+test_basic
+test_basic_v6
+test_connect
+test_connectx
+test_fragments
+test_fragments_v6
+test_getname
+test_getname_v6
+test_inaddr_any
+test_inaddr_any_v6
+test_peeloff
+test_peeloff_v6
+test_recvmsg
+test_sctp_sendrecvmsg
+test_sctp_sendrecvmsg_v6
+test_sockopt
+test_sockopt_v6
+test_tcp_style
+test_tcp_style_v6
+test_timetolive
+test_timetolive_v6
diff --git a/src/func_tests/Makefile.am b/src/func_tests/Makefile.am
new file mode 100644
index 0000000..e5bf454
--- /dev/null
+++ b/src/func_tests/Makefile.am
@@ -0,0 +1,179 @@
+# Include these two in all the Makefile.am's!!!
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+include $(top_srcdir)/Makefile.dirs
+
+# General compilation flags
+AM_CPPFLAGS = -I. -I$(top_builddir)/src/include -I$(top_srcdir)/src/testlib \
+              -g -O2 -fno-strict-aliasing -Wall -Wstrict-prototypes \
+              -Wimplicit-function-declaration
+
+AM_LDFLAGS = -lpthread
+
+LDADD = $(top_builddir)/src/testlib/libsctputil.la \
+	$(top_builddir)/src/lib/libsctp.la
+
+V6FLAGS = -DCONFIG_IPV6=1 -DTEST_V6=1 ${DEFS} ${INCLUDES} ${CFLAGS}
+
+# Test programs and libraries to build
+PASSING_KERN_TESTS = \
+	test_assoc_abort \
+	test_assoc_shutdown \
+	test_autoclose \
+	test_basic \
+	test_fragments \
+	test_inaddr_any \
+	test_peeloff \
+	test_sockopt \
+	test_connect \
+	test_connectx \
+	test_recvmsg \
+	test_timetolive \
+	test_sctp_sendrecvmsg \
+	test_getname \
+	test_tcp_style\
+	test_1_to_1_socket_bind_listen \
+	test_1_to_1_accept_close \
+	test_1_to_1_connect \
+	test_1_to_1_connectx \
+	test_1_to_1_send \
+	test_1_to_1_sendto \
+	test_1_to_1_sendmsg \
+	test_1_to_1_recvfrom \
+	test_1_to_1_recvmsg \
+	test_1_to_1_shutdown \
+	test_1_to_1_sockopt \
+	test_1_to_1_addrs \
+	test_1_to_1_nonblock \
+	test_1_to_1_rtoinfo \
+	test_1_to_1_events \
+	test_1_to_1_threads \
+	test_1_to_1_initmsg_connect
+
+PASSING_V6_KERN_TESTS = \
+	test_basic_v6 \
+	test_sockopt_v6 \
+	test_fragments_v6 \
+	test_inaddr_any_v6 \
+	test_peeloff_v6 \
+	test_timetolive_v6 \
+	test_sctp_sendrecvmsg_v6 \
+	test_getname_v6 \
+	test_tcp_style_v6
+
+if HAVE_SCTP_SENDV
+PASSING_KERN_TESTS += \
+	test_sctp_sendvrecvv
+PASSING_V6_KERN_TESTS += \
+	test_sctp_sendvrecvv_v6
+endif
+
+noinst_PROGRAMS = ${PASSING_KERN_TESTS} ${PASSING_V6_KERN_TESTS}
+
+$(top_builddir)/src/lib/libsctp.la:
+	$(MAKE) -C $(top_builddir)/src/lib libsctp.la
+
+$(top_builddir)/src/testlib/libsctputil.la:
+	$(MAKE) -C $(top_builddir)/src/testlib libsctputil.la
+
+# These are tests for live kernels which pass.
+v4test: ${PASSING_KERN_TESTS}
+	@for a in $^;				\
+	do 					\
+		echo "./$$a";			\
+		if ./$$a;			\
+		then				\
+			echo "$$a passes";	\
+			echo "";		\
+		else				\
+			echo "$$a fails";	\
+			exit 1;			\
+		fi;				\
+		sleep 1;			\
+	done
+	@echo "Hoody hoo!"
+
+# These are tests for live kernels which pass.
+v6test: ${PASSING_V6_KERN_TESTS}
+	@for a in $^;				\
+	do 					\
+		echo "./$$a";			\
+		if ./$$a;			\
+		then				\
+			echo "$$a passes";	\
+			echo "";		\
+		else				\
+			echo "$$a fails";	\
+			exit 1;			\
+		fi;				\
+		sleep 1;			\
+	done
+	@echo "Hoody hoo!"
+
+# Specifying the sources
+test_assoc_abort_SOURCES = test_assoc_abort.c 
+test_assoc_shutdown_SOURCES = test_assoc_shutdown.c 
+test_autoclose_SOURCES = test_autoclose.c 
+test_basic_SOURCES = test_basic.c 
+test_fragments_SOURCES = test_fragments.c 
+test_inaddr_any_SOURCES = test_inaddr_any.c 
+test_peeloff_SOURCES = test_peeloff.c 
+test_sockopt_SOURCES = test_sockopt.c 
+test_connect_SOURCES = test_connect.c 
+test_connectx_SOURCES = test_connectx.c 
+test_recvmsg_SOURCES = test_recvmsg.c 
+test_timetolive_SOURCES = test_timetolive.c
+test_sctp_sendrecvmsg_SOURCES = test_sctp_sendrecvmsg.c
+test_sctp_sendvrecvv_SOURCES = test_sctp_sendvrecvv.c
+test_getname_SOURCES = test_getname.c 
+test_tcp_style_SOURCES = test_tcp_style.c 
+
+test_1_to_1_socket_bind_listen_SOURCES = test_1_to_1_socket_bind_listen.c
+test_1_to_1_accept_close_SOURCES = test_1_to_1_accept_close.c
+test_1_to_1_connect_SOURCES = test_1_to_1_connect.c
+test_1_to_1_connectx_SOURCES = test_1_to_1_connectx.c
+test_1_to_1_send_SOURCES = test_1_to_1_send.c
+test_1_to_1_sendto_SOURCES = test_1_to_1_sendto.c
+test_1_to_1_sendmsg_SOURCES = test_1_to_1_sendmsg.c
+test_1_to_1_recvfrom_SOURCES = test_1_to_1_recvfrom.c
+test_1_to_1_recvmsg_SOURCES = test_1_to_1_recvmsg.c
+test_1_to_1_shutdown_SOURCES = test_1_to_1_shutdown.c
+test_1_to_1_sockopt_SOURCES = test_1_to_1_sockopt.c
+test_1_to_1_addrs_SOURCES = test_1_to_1_addrs.c
+test_1_to_1_nonblock_SOURCES = test_1_to_1_nonblock.c
+test_1_to_1_rtoinfo_SOURCES = test_1_to_1_rtoinfo.c
+test_1_to_1_events_SOURCES = test_1_to_1_events.c
+test_1_to_1_threads_SOURCES = test_1_to_1_threads.c
+test_1_to_1_initmsg_connect_SOURCES = test_1_to_1_initmsg_connect.c
+
+#
+# Specifying objects rules for "v6test"
+#
+test_basic_v6_SOURCES = test_basic.c
+test_basic_v6_CFLAGS = ${V6FLAGS}
+
+test_sockopt_v6_SOURCES = test_sockopt.c
+test_sockopt_v6_CFLAGS = ${V6FLAGS}
+
+test_fragments_v6_SOURCES = test_fragments.c
+test_fragments_v6_CFLAGS = ${V6FLAGS}
+
+test_inaddr_any_v6_SOURCES = test_inaddr_any.c
+test_inaddr_any_v6_CFLAGS = ${V6FLAGS}
+
+test_peeloff_v6_SOURCES = test_peeloff.c
+test_peeloff_v6_CFLAGS = ${V6FLAGS}
+
+test_timetolive_v6_SOURCES = test_timetolive.c
+test_timetolive_v6_CFLAGS = ${V6FLAGS}
+
+test_sctp_sendrecvmsg_v6_SOURCES = test_sctp_sendrecvmsg.c
+test_sctp_sendvrecvv_v6_SOURCES = test_sctp_sendvrecvv.c
+test_sctp_sendrecvmsg_v6_CFLAGS = ${V6FLAGS}
+test_sctp_sendvrecvv_v6_CFLAGS = ${V6FLAGS}
+
+test_getname_v6_SOURCES = test_getname.c
+test_getname_v6_CFLAGS = ${V6FLAGS}
+
+test_tcp_style_v6_SOURCES = test_tcp_style.c
+test_tcp_style_v6_CFLAGS = ${V6FLAGS}
diff --git a/src/func_tests/test_1_to_1_accept_close.c b/src/func_tests/test_1_to_1_accept_close.c
new file mode 100644
index 0000000..64162f8
--- /dev/null
+++ b/src/func_tests/test_1_to_1_accept_close.c
@@ -0,0 +1,246 @@
+/* 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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = accept(fd, (struct sockaddr *) &acpt_addr, &len);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "accept with invalid socket"
+                         "error:%d, errno:%d", error, err_no);
+
+	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 or EACCES when
+	 * SELinux set to enforcing, Expected error. */
+	error = accept(acpt_sk, (struct sockaddr *) &acpt_addr, &len);
+	if (error != -1 || (errno != EINVAL && errno != EACCES)) {
+		tst_brkm(TBROK, tst_exit, "accept on an established socket"
+			"error:%d, errno:%d", error, errno);
+	}
+
+	tst_resm(TPASS, "accept() on an established socket - %d", errno);
+
+	/*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/src/func_tests/test_1_to_1_addrs.c b/src/func_tests/test_1_to_1_addrs.c
new file mode 100644
index 0000000..5d56918
--- /dev/null
+++ b/src/func_tests/test_1_to_1_addrs.c
@@ -0,0 +1,289 @@
+/* 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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = sctp_getladdrs(fd, 0, &laddrs);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "sctp_getladdrs with invalid socket "
+			 "error:%d, errno:%d", error, err_no);
+
+	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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = sctp_getpaddrs(fd, 0, &paddrs);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with invalid socket "
+			 "error:%d, errno:%d", error, err_no);
+
+	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/src/func_tests/test_1_to_1_connect.c b/src/func_tests/test_1_to_1_connect.c
new file mode 100644
index 0000000..3ebc599
--- /dev/null
+++ b/src/func_tests/test_1_to_1_connect.c
@@ -0,0 +1,234 @@
+/* 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 <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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = connect(fd, (const struct sockaddr *) &conn_addr, len);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "connect with invalid socket "
+                         "error:%d, errno:%d", error, err_no);
+
+	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/src/func_tests/test_1_to_1_connectx.c b/src/func_tests/test_1_to_1_connectx.c
new file mode 100644
index 0000000..3cb18b3
--- /dev/null
+++ b/src/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 <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/src/func_tests/test_1_to_1_events.c b/src/func_tests/test_1_to_1_events.c
new file mode 100644
index 0000000..f758d6f
--- /dev/null
+++ b/src/func_tests/test_1_to_1_events.c
@@ -0,0 +1,205 @@
+/* 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);
+
+	memset(&event, 0, sizeof(event));
+	event.sctp_data_io_event = 1;
+	event.sctp_association_event = 1;
+	event.sctp_shutdown_event = 1;
+#ifdef HAVE_SCTP_AUTH_NO_AUTH
+	event.sctp_authentication_event = 1;
+#endif
+	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");
+
+#ifdef HAVE_SCTP_AUTH_NO_AUTH
+	error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL);
+	test_check_msg_notification(&inmessage,
+				    error,
+				    sizeof(struct sctp_authkey_event),
+				    SCTP_AUTHENTICATION_EVENT,
+				    SCTP_AUTH_NO_AUTH);
+
+	tst_resm(TPASS, "AUTH_NO_AUTH notification on server socket - SUCCESS");
+#endif
+
+	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/src/func_tests/test_1_to_1_initmsg_connect.c b/src/func_tests/test_1_to_1_initmsg_connect.c
new file mode 100644
index 0000000..8efb4f5
--- /dev/null
+++ b/src/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/src/func_tests/test_1_to_1_nonblock.c b/src/func_tests/test_1_to_1_nonblock.c
new file mode 100644
index 0000000..1179fb1
--- /dev/null
+++ b/src/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/src/func_tests/test_1_to_1_recvfrom.c b/src/func_tests/test_1_to_1_recvfrom.c
new file mode 100644
index 0000000..0ede562
--- /dev/null
+++ b/src/func_tests/test_1_to_1_recvfrom.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 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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	count = recvfrom(fd, message_rcv, msg_count, flag,
+			 (struct sockaddr *)&svr_addr, &len);
+	if (count == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (count != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "recvfrom with invalid socket "
+			 "count:%d, errno:%d", count, err_no);
+
+	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/src/func_tests/test_1_to_1_recvmsg.c b/src/func_tests/test_1_to_1_recvmsg.c
new file mode 100644
index 0000000..5f06bb6
--- /dev/null
+++ b/src/func_tests/test_1_to_1_recvmsg.c
@@ -0,0 +1,216 @@
+/* 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;
+	int fd, err_no = 0;
+	char filename[21];
+	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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	count = recvmsg(fd, &inmessage, flag);
+	if (count == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (count != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "recvmsg with invalid socket "
+			 "count:%d, errno:%d", count, err_no);
+
+	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/src/func_tests/test_1_to_1_rtoinfo.c b/src/func_tests/test_1_to_1_rtoinfo.c
new file mode 100644
index 0000000..1651df1
--- /dev/null
+++ b/src/func_tests/test_1_to_1_rtoinfo.c
@@ -0,0 +1,115 @@
+/* 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 <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;
+	srtoinfo.srto_assoc_id = 0;
+
+	/*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/src/func_tests/test_1_to_1_send.c b/src/func_tests/test_1_to_1_send.c
new file mode 100644
index 0000000..8d9516c
--- /dev/null
+++ b/src/func_tests/test_1_to_1_send.c
@@ -0,0 +1,241 @@
+/* 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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	count = send(fd, message, len_snd, flag);
+	if (count == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (count != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "send with invalid socket "
+			 "count:%d, errno:%d", count, err_no);
+
+	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/src/func_tests/test_1_to_1_sendmsg.c b/src/func_tests/test_1_to_1_sendmsg.c
new file mode 100644
index 0000000..13c920d
--- /dev/null
+++ b/src/func_tests/test_1_to_1_sendmsg.c
@@ -0,0 +1,377 @@
+/* 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))];
+	int fd, err_no = 0;
+	char filename[21];
+
+	/* 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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	count = sendmsg(fd, &outmessage, flag);
+	if (count == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (count != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "sendmsg with invalid socket "
+			 "count:%d, errno:%d", count, err_no);
+
+	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/src/func_tests/test_1_to_1_sendto.c b/src/func_tests/test_1_to_1_sendto.c
new file mode 100644
index 0000000..56b102a
--- /dev/null
+++ b/src/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(sk1, 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/src/func_tests/test_1_to_1_shutdown.c b/src/func_tests/test_1_to_1_shutdown.c
new file mode 100644
index 0000000..26c5b15
--- /dev/null
+++ b/src/func_tests/test_1_to_1_shutdown.c
@@ -0,0 +1,228 @@
+/* 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 <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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        /* 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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = shutdown(fd, SHUT_WR);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "shutdown with an invalid socket "
+			 "error:%d, errno:%d", error, err_no);
+
+	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/src/func_tests/test_1_to_1_socket_bind_listen.c b/src/func_tests/test_1_to_1_socket_bind_listen.c
new file mode 100644
index 0000000..06c6847
--- /dev/null
+++ b/src/func_tests/test_1_to_1_socket_bind_listen.c
@@ -0,0 +1,288 @@
+/* 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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = bind(fd, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "bind() with invalid socket "
+			 "descriptor error:%d, errno:%d", error, err_no);
+
+	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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = listen(fd, 3);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "listen() with invalid socket "
+			 "error:%d, errno:%d", error, err_no);
+
+	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/src/func_tests/test_1_to_1_sockopt.c b/src/func_tests/test_1_to_1_sockopt.c
new file mode 100644
index 0000000..49f4eaf
--- /dev/null
+++ b/src/func_tests/test_1_to_1_sockopt.c
@@ -0,0 +1,434 @@
+/* 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 */
+	int fd, err_no = 0;
+	char filename[21];
+
+	/* 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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = setsockopt(fd, IPPROTO_SCTP, 0, 0, 0);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "setsockopt with an invalid socket "
+			 "error:%d, errno:%d", error, err_no);
+
+	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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = getsockopt(fd, IPPROTO_SCTP, 0, 0, 0);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "getsockopt with an invalid socket "
+			 "error:%d, errno:%d", error, err_no);
+
+	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 = 2304;
+	/* 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/src/func_tests/test_1_to_1_threads.c b/src/func_tests/test_1_to_1_threads.c
new file mode 100644
index 0000000..e2a7eee
--- /dev/null
+++ b/src/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/src/func_tests/test_assoc_abort.c b/src/func_tests/test_assoc_abort.c
new file mode 100644
index 0000000..f8019c7
--- /dev/null
+++ b/src/func_tests/test_assoc_abort.c
@@ -0,0 +1,243 @@
+/* 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 <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/src/func_tests/test_assoc_shutdown.c b/src/func_tests/test_assoc_shutdown.c
new file mode 100644
index 0000000..a007117
--- /dev/null
+++ b/src/func_tests/test_assoc_shutdown.c
@@ -0,0 +1,245 @@
+/* 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 <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/src/func_tests/test_autoclose.c b/src/func_tests/test_autoclose.c
new file mode 100644
index 0000000..e65fac0
--- /dev/null
+++ b/src/func_tests/test_autoclose.c
@@ -0,0 +1,167 @@
+/* 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 <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/src/func_tests/test_basic.c b/src/func_tests/test_basic.c
new file mode 100644
index 0000000..92288b2
--- /dev/null
+++ b/src/func_tests/test_basic.c
@@ -0,0 +1,455 @@
+/* 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 <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/src/func_tests/test_connect.c b/src/func_tests/test_connect.c
new file mode 100644
index 0000000..333c283
--- /dev/null
+++ b/src/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/src/func_tests/test_connectx.c b/src/func_tests/test_connectx.c
new file mode 100644
index 0000000..2477241
--- /dev/null
+++ b/src/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/src/func_tests/test_fragments.c b/src/func_tests/test_fragments.c
new file mode 100644
index 0000000..7feb2b2
--- /dev/null
+++ b/src/func_tests/test_fragments.c
@@ -0,0 +1,297 @@
+/* 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 <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/src/func_tests/test_getname.c b/src/func_tests/test_getname.c
new file mode 100644
index 0000000..5fc4b3c
--- /dev/null
+++ b/src/func_tests/test_getname.c
@@ -0,0 +1,278 @@
+/* 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;
+	int fd, err_no = 0;
+	char filename[21];
+
+        /* 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));
+
+	memset(&svr_local_addr, 0x00, 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");
+
+	memset(&svr_peer_addr, 0x00, 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));
+
+	memset(&clt_local_addr, 0x00, 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");
+
+	memset(&clt_peer_addr, 0x00, 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); 
+
+	memset(&svr_local_addr, 0x00, 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");
+
+	memset(&svr_peer_addr, 0x00, 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");
+
+	memset(&clt_local_addr, 0x00, 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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = getsockname(fd, (struct sockaddr *)&clt_local_addr, &len);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "getsockname on an invalid socket "
+			 "error:%d errno:%d", error, err_no);
+
+	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");
+ 
+	memset(&clt_peer_addr, 0x00, 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*/
+	strcpy(filename, "/tmp/sctptest.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd == -1)
+		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
+				filename, strerror(errno));
+	error = getpeername(fd, (struct sockaddr *)&clt_local_addr, &len);
+	if (error == -1)
+		err_no = errno;
+	close(fd);
+	unlink(filename);
+	if (error != -1 || err_no != ENOTSOCK)
+		tst_brkm(TBROK, tst_exit, "getpeername on an invalid socket "
+			 "error:%d errno:%d", error, err_no);
+
+	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/src/func_tests/test_inaddr_any.c b/src/func_tests/test_inaddr_any.c
new file mode 100644
index 0000000..722a702
--- /dev/null
+++ b/src/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/src/func_tests/test_peeloff.c b/src/func_tests/test_peeloff.c
new file mode 100644
index 0000000..8fb7a00
--- /dev/null
+++ b/src/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/src/func_tests/test_recvmsg.c b/src/func_tests/test_recvmsg.c
new file mode 100644
index 0000000..b16cceb
--- /dev/null
+++ b/src/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/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
new file mode 100644
index 0000000..ceccd5a
--- /dev/null
+++ b/src/func_tests/test_sctp_sendrecvmsg.c
@@ -0,0 +1,370 @@
+/* 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 <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 500
+/* 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.
+	 */
+	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);
+
+
+	/* 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, 48, sizeof(ttlfrag)); /* 48 is the ascii of '0' */
+	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/src/func_tests/test_sctp_sendvrecvv.c b/src/func_tests/test_sctp_sendvrecvv.c
new file mode 100644
index 0000000..4991e79
--- /dev/null
+++ b/src/func_tests/test_sctp_sendvrecvv.c
@@ -0,0 +1,270 @@
+/* SCTP kernel Implementation
+ * (C) Copyright REDHAT Corp. 2018
+ *
+ * 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.
+ *
+ * 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:
+ *    Xin Long		<lucien.xin@gmail.com>
+ */
+
+/* This is a basic functional test for the SCTP new library APIs
+ * sctp_sendv() and sctp_recvv().
+ */
+
+#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 <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT;
+
+/* RCVBUF value, and indirectly RWND*2 */
+#define SMALL_RCVBUF 3000
+#define SMALL_MAXSEG 500
+/* This is extra data length to ensure rwnd closes */
+#define RWND_SLOP    100
+static char *message = "Hello world\n";
+
+int main(int argc, char *argv[])
+{
+	sockaddr_storage_t loop1, loop2, msgname;
+	int sk1, sk2, error, buflen, i, addrcnt;
+	socklen_t msgname_len, rn_len;
+	struct sctp_authinfo authinfo;
+	struct sctp_sndinfo sndinfo;
+	struct sockaddr *addr_list;
+	struct sctp_sendv_spa spa;
+	uint32_t infotype, stream;
+	struct iovec iov, iovx[3];
+	struct sctp_prinfo prinfo;
+	struct sctp_recvv_rn rn;
+	int pf_class, msg_flags;
+	socklen_t val = 1;
+	char addr_str[64];
+
+	/* Set some basic values which depend on the address family. */
+#if TEST_V6
+	struct sockaddr_in6 *v6addrs;
+
+	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);
+
+	addrcnt = 5;
+	v6addrs = test_malloc(sizeof(*v6addrs) * addrcnt);
+	v6addrs[0].sin6_family = PF_INET6;
+	v6addrs[0].sin6_addr = in6addr_loopback;
+	v6addrs[0].sin6_port = htons(SCTP_TESTPORT_2);
+	for (i = 1; i < addrcnt; i++) {
+		sprintf(addr_str, "2020::%d", i);
+		v6addrs[i].sin6_family = PF_INET6;
+		inet_pton(PF_INET6, addr_str, &v6addrs[i].sin6_addr);
+	}
+	addr_list = (struct sockaddr *)v6addrs;
+#else
+	struct sockaddr_in *v4addrs;
+
+	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);
+
+	addrcnt = 5;
+	v4addrs = test_malloc(sizeof(*v4addrs) * addrcnt);
+	v4addrs[0].sin_family = PF_INET;
+	v4addrs[0].sin_addr.s_addr = SCTP_IP_LOOPBACK;
+	v4addrs[0].sin_port = htons(SCTP_TESTPORT_2);
+	for (i = 1; i < addrcnt; i++) {
+		sprintf(addr_str, "172.16.1.%d", i);
+		v4addrs[i].sin_family = PF_INET;
+		v4addrs[i].sin_addr.s_addr = inet_addr(addr_str);
+	}
+	addr_list = (struct sockaddr *)v4addrs;
+#endif /* TEST_V6 */
+
+	setvbuf(stdout, NULL, _IONBF, 0);
+
+	/* 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);
+
+	/* 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);
+
+
+	/* Testing for sctp_sendv */
+	iov.iov_base = message;
+	iov.iov_len = strlen(message) + 1;
+	test_sctp_sendv(sk1, &iov, 1, addr_list, addrcnt, NULL, 0, 0, 0);
+	tst_resm(TPASS, "sctp_sendv addr info");
+
+	stream = 1;
+	memset(&sndinfo, 0, sizeof(sndinfo));
+	sndinfo.snd_flags = SCTP_UNORDERED;
+	sndinfo.snd_sid = stream;
+	test_sctp_sendv(sk1, &iov, 1, addr_list, addrcnt, &sndinfo,
+			sizeof(sndinfo), SCTP_SENDV_SNDINFO, 0);
+	tst_resm(TPASS, "sctp_sendv sndinfo with stream %d", stream);
+
+	iovx[0].iov_base = message;
+	iovx[0].iov_len = strlen(message) + 1;
+	iovx[1].iov_base = message;
+	iovx[1].iov_len = strlen(message) + 1;
+	iovx[2].iov_base = message;
+	iovx[2].iov_len = strlen(message) + 1;
+
+	stream = 2;
+	sndinfo.snd_sid = stream;
+	test_sctp_sendv(sk1, iovx, 3, addr_list, addrcnt, &sndinfo,
+			sizeof(sndinfo), SCTP_SENDV_SNDINFO, 0);
+	tst_resm(TPASS, "sctp_sendv sndinfo with stream %d", stream);
+
+	prinfo.pr_policy = SCTP_PR_SCTP_RTX;
+	prinfo.pr_value = 10;
+	test_sctp_sendv(sk1, iovx, 3, addr_list, addrcnt, &prinfo,
+			sizeof(prinfo), SCTP_SENDV_PRINFO, 0);
+	tst_resm(TPASS, "sctp_sendv prinfo");
+
+	authinfo.auth_keynumber = 0;
+	test_sctp_sendv(sk1, iovx, 3, addr_list, addrcnt, &authinfo,
+			sizeof(authinfo), SCTP_SENDV_AUTHINFO, 0);
+	tst_resm(TPASS, "sctp_sendv authinfo");
+
+
+	spa.sendv_sndinfo = sndinfo;
+	spa.sendv_prinfo = prinfo;
+	spa.sendv_authinfo = authinfo;
+
+	stream = 3;
+	spa.sendv_sndinfo.snd_sid = stream;
+	spa.sendv_flags = SCTP_SEND_SNDINFO_VALID | SCTP_SEND_PRINFO_VALID;
+	test_sctp_sendv(sk1, iovx, 3, addr_list, addrcnt, &spa,
+			sizeof(spa), SCTP_SENDV_SPA, 0);
+	tst_resm(TPASS, "sctp_sendv spa with stream %d", stream);
+
+	stream = 4;
+	spa.sendv_sndinfo.snd_sid = stream;
+	spa.sendv_flags = SCTP_SEND_SNDINFO_VALID | SCTP_SEND_PRINFO_VALID |
+			  SCTP_SEND_AUTHINFO_VALID;
+	test_sctp_sendv(sk1, iovx, 3, addr_list, addrcnt, &spa,
+			sizeof(spa), SCTP_SENDV_SPA, 0);
+	tst_resm(TPASS, "sctp_sendv spa with stream %d", stream);
+
+	/* Testing for sctp_recvv */
+	buflen = REALLY_BIG;
+	msgname_len = sizeof(msgname);
+	msg_flags = 0;
+	iov.iov_base = test_malloc(buflen);
+	iov.iov_len = buflen;
+	rn_len = sizeof(rn);
+
+	error = test_sctp_recvv(sk2, &iov, 1, (struct sockaddr *)&msgname,
+				&msgname_len, &rn, &rn_len, &infotype,
+				&msg_flags);
+	if (infotype != SCTP_RECVV_NOINFO)
+		tst_brkm(TBROK, tst_exit, "sctp_recvv infotype %d != %d",
+			 infotype, SCTP_RECVV_NOINFO);
+	tst_resm(TPASS, "sctp_recvv SCTP_RECVV_NOINFO");
+
+	error = setsockopt(sk2, SOL_SCTP, SCTP_RECVRCVINFO,
+			   &val, sizeof(val));
+	if (error)
+		tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_RECVRCVINFO): %s",
+			 strerror(errno));
+
+	error = test_sctp_recvv(sk2, &iov, 1, (struct sockaddr *)&msgname,
+				&msgname_len, &rn, &rn_len, &infotype,
+				&msg_flags);
+	if (infotype != SCTP_RECVV_RCVINFO ||
+	    rn.recvv_rcvinfo.rcv_sid != 1)
+		tst_brkm(TBROK, tst_exit, "sctp_recvv infotype %d != %d",
+			 infotype, SCTP_RECVV_NOINFO);
+	tst_resm(TPASS, "sctp_recvv SCTP_RECVV_RCVINFO");
+
+	error = setsockopt(sk2, SOL_SCTP, SCTP_RECVNXTINFO,
+			   &val, sizeof(val));
+	if (error)
+		tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_RECVNXTINFO): %s",
+			 strerror(errno));
+
+	rn_len = 1;
+	error = test_sctp_recvv(sk2, &iov, 1, (struct sockaddr *)&msgname,
+				&msgname_len, &rn, &rn_len, &infotype,
+				&msg_flags);
+	if (infotype != SCTP_RECVV_NOINFO)
+		tst_brkm(TBROK, tst_exit, "sctp_recvv infotype %d != %d",
+			 infotype, SCTP_RECVV_NOINFO);
+	tst_resm(TPASS, "sctp_recvv SCTP_RECVV_NOINFO due to small size");
+
+	rn_len = sizeof(struct sctp_nxtinfo);
+	error = test_sctp_recvv(sk2, &iov, 1, (struct sockaddr *)&msgname,
+				&msgname_len, &rn, &rn_len, &infotype,
+				&msg_flags);
+	if (infotype != SCTP_RECVV_NXTINFO)
+		tst_brkm(TBROK, tst_exit, "sctp_recvv infotype %d != %d",
+			 infotype, SCTP_RECVV_NXTINFO);
+	tst_resm(TPASS, "sctp_recvv SCTP_RECVV_NXTINFO due to small size");
+
+	rn_len = sizeof(rn);
+	error = test_sctp_recvv(sk2, &iov, 1, (struct sockaddr *)&msgname,
+				&msgname_len, &rn, &rn_len, &infotype,
+				&msg_flags);
+	if (infotype != SCTP_RECVV_RN ||
+	    rn.recvv_rcvinfo.rcv_sid != 0 || rn.recvv_nxtinfo.nxt_sid != 3)
+		tst_brkm(TBROK, tst_exit, "sctp_recvv infotype %d != %d",
+			 infotype, SCTP_RECVV_RN);
+	tst_resm(TPASS, "sctp_recvv SCTP_RECVV_RN");
+
+	close(sk1);
+	close(sk2);
+
+	return 0;
+}
diff --git a/src/func_tests/test_sockopt.c b/src/func_tests/test_sockopt.c
new file mode 100644
index 0000000..2bd1097
--- /dev/null
+++ b/src/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 <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/src/func_tests/test_tcp_style.c b/src/func_tests/test_tcp_style.c
new file mode 100644
index 0000000..f4f835a
--- /dev/null
+++ b/src/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/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
new file mode 100644
index 0000000..58d76f0
--- /dev/null
+++ b/src/func_tests/test_timetolive.c
@@ -0,0 +1,395 @@
+/* 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 <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 500
+
+/* 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 advertise rcvbuf/2 as
+	 *    our initial rwnd
+	 */
+	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;
+
+        /* 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, 48, sizeof(ttlfrag)); /* 48 is the ascii of '0' */
+	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/src/include/Makefile.am b/src/include/Makefile.am
new file mode 100644
index 0000000..38abaec
--- /dev/null
+++ b/src/include/Makefile.am
@@ -0,0 +1,5 @@
+
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+
+SUBDIRS = netinet
diff --git a/src/include/netinet/Makefile.am b/src/include/netinet/Makefile.am
new file mode 100644
index 0000000..965db8c
--- /dev/null
+++ b/src/include/netinet/Makefile.am
@@ -0,0 +1,14 @@
+
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+
+libcnetinetdir = $(includedir)/netinet
+
+
+## FIXME: Your stuff here
+
+# Supposing this is part of the development package, header for our
+# API.
+include_HEADERS =
+
+libcnetinet_HEADERS = sctp.h
diff --git a/src/include/netinet/sctp.h.in b/src/include/netinet/sctp.h.in
new file mode 100644
index 0000000..2009f1c
--- /dev/null
+++ b/src/include/netinet/sctp.h.in
@@ -0,0 +1,188 @@
+/* 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>
+#include <linux/sctp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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
+
+#undef HAVE_SCTP_STREAM_RESET_EVENT
+#undef HAVE_SCTP_STREAM_RECONFIG
+#undef HAVE_SCTP_PEELOFF_FLAGS
+#undef HAVE_SCTP_PDAPI_EVENT_PDAPI_STREAM
+#undef HAVE_SCTP_PDAPI_EVENT_PDAPI_SEQ
+#undef HAVE_SCTP_SENDV
+#undef HAVE_SCTP_AUTH_NO_AUTH
+#undef HAVE_SCTP_SPP_IPV6_FLOWLABEL
+#undef HAVE_SCTP_SPP_DSCP
+
+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);
+int sctp_peeloff_flags(int sd, sctp_assoc_t assoc_id, unsigned flags);
+
+/* 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);
+
+
+#ifdef HAVE_SCTP_SENDV
+/* sendv infotype */
+enum {
+	SCTP_SENDV_NOINFO,
+	SCTP_SENDV_SNDINFO,
+	SCTP_SENDV_PRINFO,
+	SCTP_SENDV_AUTHINFO,
+	SCTP_SENDV_SPA
+};
+
+/* sendv_flags */
+#define SCTP_SEND_SNDINFO_VALID		0x1
+#define SCTP_SEND_PRINFO_VALID		0x2
+#define SCTP_SEND_AUTHINFO_VALID	0x4
+#endif
+
+struct sctp_sendv_spa {
+	uint32_t sendv_flags;
+	struct sctp_sndinfo sendv_sndinfo;
+#ifdef HAVE_SCTP_SENDV
+	struct sctp_prinfo sendv_prinfo;
+	struct sctp_authinfo sendv_authinfo;
+#endif
+};
+
+#ifdef HAVE_SCTP_SENDV
+int sctp_sendv(int s, const struct iovec *iov, int iovcnt,
+	       struct sockaddr *addrs, int addrcnt, void *info,
+	       socklen_t infolen, unsigned int infotype, int flags);
+
+/* recvv infotype */
+enum {
+	SCTP_RECVV_NOINFO,
+	SCTP_RECVV_RCVINFO,
+	SCTP_RECVV_NXTINFO,
+	SCTP_RECVV_RN
+};
+
+struct sctp_recvv_rn {
+	struct sctp_rcvinfo recvv_rcvinfo;
+	struct sctp_nxtinfo recvv_nxtinfo;
+};
+
+int sctp_recvv(int s, const struct iovec *iov, int iovlen,
+	       struct sockaddr *from, socklen_t *fromlen, void *info,
+	       socklen_t *infolen, unsigned int *infotype, int *flags);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __linux_sctp_h__ */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644
index 0000000..1296caa
--- /dev/null
+++ b/src/lib/Makefile.am
@@ -0,0 +1,15 @@
+# Include these two in all the Makefile.am's!!!
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+include $(top_srcdir)/Makefile.dirs
+
+# General compilation flags
+AM_CPPFLAGS = -I$(top_builddir)/src/include
+
+lib_LTLIBRARIES = libsctp.la
+
+libsctp_la_SOURCES = bindx.c connectx.c peeloff.c opt_info.c \
+		addrs.c sendmsg.c recvmsg.c Versions.map
+libsctp_la_LDFLAGS = -version-info \
+		@LIBSCTP_CURRENT@:@LIBSCTP_REVISION@:@LIBSCTP_AGE@ \
+		-Wl,--version-script=$(srcdir)/Versions.map
diff --git a/src/lib/Versions.map b/src/lib/Versions.map
new file mode 100644
index 0000000..7faad5d
--- /dev/null
+++ b/src/lib/Versions.map
@@ -0,0 +1,28 @@
+VERS_1 {
+	global:
+		sctp_getpaddrs;
+		sctp_freepaddrs;
+		sctp_getladdrs;
+		sctp_freeladdrs;
+		sctp_getaddrlen;
+		sctp_bindx;
+		sctp_connectx;
+		sctp_opt_info;
+		sctp_peeloff;
+		sctp_recvmsg;
+		sctp_recvv;
+		sctp_sendmsg;
+		sctp_sendv;
+		sctp_send;
+
+	local:
+		*;
+};
+
+VERS_2 {
+	global:	sctp_connectx;
+} VERS_1;
+
+VERS_3 {
+	global:	sctp_connectx;
+} VERS_2;
diff --git a/src/lib/addrs.c b/src/lib/addrs.c
new file mode 100644
index 0000000..65f5222
--- /dev/null
+++ b/src/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/src/lib/bindx.c b/src/lib/bindx.c
new file mode 100644
index 0000000..5f44874
--- /dev/null
+++ b/src/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;
+	const char *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 = (char*)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/src/lib/connectx.c b/src/lib/connectx.c
new file mode 100644
index 0000000..5f4552b
--- /dev/null
+++ b/src/lib/connectx.c
@@ -0,0 +1,190 @@
+/* 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 char *addrbuf;
+	const struct sockaddr *sa_addr;
+	int addrs_size = 0;
+	int i;
+
+	addrbuf = (char *)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)
+{
+	int 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)
+{
+	int 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)
+{
+	int addrs_size = __connectx_addrsize(addrs, addrcnt);
+	int status;
+	struct sctp_getaddrs_old param;
+	socklen_t opt_len = sizeof(param);
+
+	if (addrs_size < 0)
+		return addrs_size;
+
+	/* First try the new socket api
+	 * Because the id is returned in the option buffer we have prepend
+	 * 32bit to it for the returned association id
+	 */
+	param.assoc_id = 0;
+	param.addr_num = addrs_size;
+	param.addrs = addrs;
+	status = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX3,
+		            &param, &opt_len);
+	if (status == 0 || errno == EINPROGRESS) {
+		/* Succeeded immediately, or initiated on non-blocking
+		 * socket.
+		 */
+		if (id)
+			*id = param.assoc_id;
+	}
+
+	if (errno != ENOPROTOOPT) {
+		/* No point in trying the fallbacks*/
+		return status;
+	}
+
+	/* The first incarnation of updated connectx api didn't work for
+	 * non-blocking sockets.  So if the application wants the association
+	 * id and the socket is non-blocking, we can't really do anything.
+	 */
+	if (id) {
+		/* Program wants the association-id returned. We can only do
+		 * that if the socket is blocking */
+		status = fcntl(fd, F_GETFL);
+		if (status < 0)
+			return status;
+
+		if (status & O_NONBLOCK) {
+			/* Socket is non-blocking. Fail */
+			errno = ENOPROTOOPT;
+			return -1;
+		}
+	}
+
+	return __connectx(fd, addrs, addrs_size, id);
+}
+
+#define __SYMPFX(pfx, sym) #pfx sym
+#define _SYMPFX(pfx, sym) __SYMPFX(pfx, sym)
+#define SYMPFX(sym) _SYMPFX(__USER_LABEL_PREFIX__, #sym)
+#define SYMVER(name, name2) __asm__(".symver " SYMPFX(name) "," SYMPFX(name2))
+
+SYMVER(__sctp_connectx, sctp_connectx@);
+SYMVER(sctp_connectx_orig, sctp_connectx@VERS_1);
+SYMVER(sctp_connectx2, sctp_connectx@VERS_2);
+SYMVER(sctp_connectx3, sctp_connectx@@VERS_3);
diff --git a/src/lib/opt_info.c b/src/lib/opt_info.c
new file mode 100644
index 0000000..21c8307
--- /dev/null
+++ b/src/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/src/lib/peeloff.c b/src/lib/peeloff.c
new file mode 100644
index 0000000..a4e1ed9
--- /dev/null
+++ b/src/lib/peeloff.c
@@ -0,0 +1,72 @@
+/* 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>
+
+#ifdef HAVE_SCTP_PEELOFF_FLAGS
+int
+sctp_peeloff_flags(int fd, sctp_assoc_t associd, unsigned flags)
+{
+	socklen_t peeloff_size = sizeof(sctp_peeloff_flags_arg_t);
+	sctp_peeloff_flags_arg_t peeloff;
+	int err;
+
+	if (!flags)
+		return sctp_peeloff(fd, associd);
+
+	peeloff.p_arg.associd = associd;
+	peeloff.p_arg.sd = 0;
+	peeloff.flags = flags;
+
+	err = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_PEELOFF_FLAGS, &peeloff,
+			 &peeloff_size);
+
+	if (err < 0)
+		return err;
+
+	return peeloff.p_arg.sd;
+}
+#endif
+
+/* 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)
+{
+	socklen_t peeloff_size = sizeof(sctp_peeloff_arg_t);
+	sctp_peeloff_arg_t 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;
+}
diff --git a/src/lib/recvmsg.c b/src/lib/recvmsg.c
new file mode 100644
index 0000000..88fe061
--- /dev/null
+++ b/src/lib/recvmsg.c
@@ -0,0 +1,191 @@
+/* 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);
+}
+
+#ifdef HAVE_SCTP_SENDV
+int sctp_recvv(int s, const struct iovec *iov, int iovlen,
+	       struct sockaddr *from, socklen_t *fromlen, void *info,
+	       socklen_t *infolen, unsigned int *infotype, int *flags)
+{
+	char incmsg[CMSG_SPACE(sizeof(struct sctp_rcvinfo) +
+			       sizeof(struct sctp_nxtinfo))];
+	int error, len, _infolen;
+	struct cmsghdr *cmsg;
+	struct msghdr inmsg;
+
+	memset(&inmsg, 0, sizeof(inmsg));
+
+	/* set from and iov */
+	inmsg.msg_name = from;
+	inmsg.msg_namelen = fromlen ? *fromlen : 0;
+	inmsg.msg_iov = (struct iovec *)iov;
+	inmsg.msg_iovlen = iovlen;
+	inmsg.msg_control = incmsg;
+	inmsg.msg_controllen = sizeof(incmsg);
+
+	error = recvmsg(s, &inmsg, flags ? *flags : 0);
+	if (error < 0)
+		return error;
+
+	/* set fromlen, frags */
+	if (fromlen)
+		*fromlen = inmsg.msg_namelen;
+
+	if (flags)
+		*flags = inmsg.msg_flags;
+
+	if (!info || !infotype || !infolen)
+		return error;
+
+	*infotype = SCTP_RECVV_NOINFO;
+	_infolen = *infolen;
+
+	/* set info and infotype */
+	for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL;
+				cmsg = CMSG_NXTHDR(&inmsg, cmsg)) {
+		if (cmsg->cmsg_level != IPPROTO_SCTP)
+			continue;
+
+		if (cmsg->cmsg_type == SCTP_RCVINFO) {
+			len = sizeof(struct sctp_rcvinfo);
+			if (*infotype == SCTP_RECVV_NOINFO) {
+				if (_infolen < len)
+					break;
+				memcpy(info, CMSG_DATA(cmsg), len);
+				*infotype = SCTP_RECVV_RCVINFO;
+				*infolen = len;
+			} else if (*infotype == SCTP_RECVV_NXTINFO) {
+				if (_infolen < len +
+					       sizeof(struct sctp_nxtinfo))
+					break;
+				memcpy(info + len, info,
+				       sizeof(struct sctp_nxtinfo));
+				memcpy(info, CMSG_DATA(cmsg), len);
+				*infotype = SCTP_RECVV_RN;
+				*infolen = len + sizeof(struct sctp_nxtinfo);
+			} else {
+				break;
+			}
+		} else if (cmsg->cmsg_type == SCTP_NXTINFO) {
+			len = sizeof(struct sctp_nxtinfo);
+			if (*infotype == SCTP_RECVV_NOINFO) {
+				if (_infolen < len)
+					break;
+				memcpy(info, CMSG_DATA(cmsg), len);
+				*infotype = SCTP_RECVV_NXTINFO;
+				*infolen = len;
+			} else if (*infotype == SCTP_RECVV_RCVINFO) {
+				if (_infolen < len +
+					       sizeof(struct sctp_rcvinfo))
+					break;
+				memcpy(info + sizeof(struct sctp_rcvinfo),
+				       CMSG_DATA(cmsg), len);
+				*infotype = SCTP_RECVV_RN;
+				*infolen = len + sizeof(struct sctp_rcvinfo);
+			} else {
+				break;
+			}
+		}
+	}
+
+	return error;
+}
+#endif
diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
new file mode 100644
index 0000000..4c90b07
--- /dev/null
+++ b/src/lib/sendmsg.c
@@ -0,0 +1,239 @@
+/* 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 <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.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_control = NULL;
+	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);
+}
+
+#ifdef HAVE_SCTP_SENDV
+static struct cmsghdr *sctp_sendv_store_cmsg(struct cmsghdr *cmsg, int *cmsglen,
+					     int type, int len, void *data)
+{
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = type;
+	cmsg->cmsg_len = CMSG_LEN(len);
+	memcpy(CMSG_DATA(cmsg), data, len);
+
+	*cmsglen += CMSG_SPACE(len);
+
+	return (struct cmsghdr *)((char *)cmsg + CMSG_SPACE(len));
+}
+
+int sctp_sendv(int s, const struct iovec *iov, int iovcnt,
+	       struct sockaddr *addrs, int addrcnt, void *info,
+	       socklen_t infolen, unsigned int infotype, int flags)
+{
+	char _cmsg[CMSG_SPACE(sizeof(struct sctp_sendv_spa))];
+	struct cmsghdr *cmsg = (struct cmsghdr *)_cmsg;
+	struct sockaddr *addr;
+	struct msghdr outmsg;
+	int len, cmsglen = 0;
+	int err, type, i;
+	char *addrbuf;
+
+	/* set msg_iov, msg_iovlen, msg_flags */
+	memset(&outmsg, 0x00, sizeof(outmsg));
+	outmsg.msg_iov = (struct iovec *)iov;
+	outmsg.msg_iovlen = iovcnt;
+	outmsg.msg_flags = flags;
+
+	/* set msg_name and msg_namelen */
+	if (addrs && addrcnt) {
+		outmsg.msg_name = addrs;
+		if (addrs->sa_family == AF_INET)
+			outmsg.msg_namelen = sizeof(struct sockaddr_in);
+		else if (addrs->sa_family == AF_INET6)
+			outmsg.msg_namelen = sizeof(struct sockaddr_in6);
+		else
+			return -EINVAL;
+		addrcnt -= 1;
+		addrbuf = (char *)addrs;
+		addrs = (struct sockaddr *)(addrbuf + outmsg.msg_namelen);
+	}
+
+	/* alloc memory only when it's multi-address */
+	if (addrcnt) {
+		len = CMSG_SPACE(sizeof(struct sockaddr_in6)) * addrcnt;
+		cmsg = malloc(sizeof(_cmsg) + len);
+		if (!cmsg)
+			return -ENOMEM;
+	}
+
+	outmsg.msg_control = cmsg;
+
+	/* add cmsg info for addr info */
+	for (i = 0, addrbuf = (char *)addrs; i < addrcnt; i++) {
+		void *ainfo;
+
+		addr = (struct sockaddr *)addrbuf;
+		if (addr->sa_family == AF_INET) {
+			struct sockaddr_in *a = (struct sockaddr_in *)addrbuf;
+
+			len = sizeof(struct in_addr);
+			type = SCTP_DSTADDRV4;
+			ainfo = &a->sin_addr;
+			addrbuf += sizeof(*a);
+		} else if (addr->sa_family == AF_INET6) {
+			struct sockaddr_in6 *a = (struct sockaddr_in6 *)addrbuf;
+
+			len = sizeof(struct in6_addr);
+			type = SCTP_DSTADDRV6;
+			ainfo = &a->sin6_addr;
+			addrbuf += sizeof(*a);
+		} else {
+			free(outmsg.msg_control);
+			return -EINVAL;
+		}
+
+		cmsg = sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len, ainfo);
+	}
+	/* add cmsg info for addr info for snd/pr/auth info */
+	if (infotype == SCTP_SENDV_SPA) {
+		struct sctp_sendv_spa *spa = info;
+
+		if (spa->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
+			type = SCTP_SNDINFO;
+			len = sizeof(struct sctp_sndinfo);
+			cmsg = sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len,
+						     &spa->sendv_sndinfo);
+		}
+		if (spa->sendv_flags & SCTP_SEND_PRINFO_VALID) {
+			type = SCTP_PRINFO;
+			len = sizeof(struct sctp_prinfo);
+			cmsg = sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len,
+						     &spa->sendv_prinfo);
+		}
+		if (spa->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
+			type = SCTP_AUTHINFO;
+			len = sizeof(struct sctp_authinfo);
+			sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len,
+					      &spa->sendv_authinfo);
+		}
+	} else if (infotype == SCTP_SENDV_SNDINFO) {
+		type = SCTP_SNDINFO;
+		len = sizeof(struct sctp_sndinfo);
+		sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len, info);
+	} else if (infotype == SCTP_SENDV_PRINFO) {
+		type = SCTP_PRINFO;
+		len = sizeof(struct sctp_prinfo);
+		sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len, info);
+	} else if (infotype == SCTP_SENDV_AUTHINFO) {
+		type = SCTP_AUTHINFO;
+		len = sizeof(struct sctp_authinfo);
+		sctp_sendv_store_cmsg(cmsg, &cmsglen, type, len, info);
+	}
+
+	outmsg.msg_controllen = cmsglen;
+
+	err = sendmsg(s, &outmsg, 0);
+
+	if (outmsg.msg_control != _cmsg)
+		free(outmsg.msg_control);
+
+	return err;
+}
+#endif
diff --git a/src/testlib/Makefile.am b/src/testlib/Makefile.am
new file mode 100644
index 0000000..b949611
--- /dev/null
+++ b/src/testlib/Makefile.am
@@ -0,0 +1,12 @@
+# Include these two in all the Makefile.am's!!!
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.rules
+
+include $(top_srcdir)/Makefile.dirs
+
+# General compilation flags
+AM_CPPFLAGS = -I$(top_builddir)/src/include
+
+noinst_LTLIBRARIES = libsctputil.la
+libsctputil_la_SOURCES = sctputil.c sctputil.h
+libsctputil_la_LDFLAGS =
diff --git a/src/testlib/sctputil.c b/src/testlib/sctputil.c
new file mode 100644
index 0000000..24f305a
--- /dev/null
+++ b/src/testlib/sctputil.c
@@ -0,0 +1,417 @@
+/* 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 <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.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(%lu):  ", 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);
+	free(found);
+	return 0;
+}
diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
new file mode 100644
index 0000000..9dbabd4
--- /dev/null
+++ b/src/testlib/sctputil.h
@@ -0,0 +1,358 @@
+/* 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;			
+}
+
+#ifdef HAVE_SCTP_SENDV
+static inline int test_sctp_sendv(int s, const struct iovec *iov, int iovcnt,
+				  struct sockaddr *addrs, int addrcnt,
+				  void *info, socklen_t infolen,
+				  unsigned int infotype, int flags)
+{
+	int error = sctp_sendv(s, iov, iovcnt, addrs, addrcnt, info, infolen,
+			       infotype, flags);
+	int i, tlen = 0;
+
+	for (i = 0; i < iovcnt; i++)
+		tlen += iov->iov_len;
+
+	if (tlen != error)
+		tst_brkm(TBROK, tst_exit, "sctp_sendv: error:%d errno:%d",
+			 error, errno);
+	return error;
+}
+#endif
+
+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;			
+}
+
+#ifdef HAVE_SCTP_SENDV
+static inline int test_sctp_recvv(int s, const struct iovec *iov, int iovlen,
+				  struct sockaddr *from, socklen_t *fromlen,
+				  void *info, socklen_t *infolen,
+				  unsigned int *infotype, int *flags)
+{
+	int error = sctp_recvv(s, iov, iovlen, from, fromlen, info, infolen,
+			       infotype, flags);
+	if (-1 == error)
+		tst_brkm(TBROK, tst_exit, "sctp_recvmsg: %s", strerror(errno));
+	return error;
+}
+#endif
+
+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__ */
diff --git a/src/withsctp/.gitignore b/src/withsctp/.gitignore
new file mode 100644
index 0000000..498e578
--- /dev/null
+++ b/src/withsctp/.gitignore
@@ -0,0 +1,2 @@
+checksctp
+withsctp
diff --git a/src/withsctp/Makefile.am b/src/withsctp/Makefile.am
new file mode 100644
index 0000000..3157588
--- /dev/null
+++ b/src/withsctp/Makefile.am
@@ -0,0 +1,28 @@
+# -*- Makefile -*-
+#
+# The author (La Monte H.P. Yarroll) disclaims copyright on this file.
+#
+
+include $(top_srcdir)/Makefile.vars
+include $(top_srcdir)/Makefile.dirs
+include $(top_srcdir)/Makefile.rules
+
+bin_PROGRAMS = checksctp
+bin_SCRIPTS = withsctp
+
+AM_CPPFLAGS=-I$(top_builddir)/src/include
+pkglib_LTLIBRARIES = libwithsctp.la
+libwithsctp_la_SOURCES = sctp_load_libs.c sctp_socket.c sctp_bind.c \
+	sctp_sockopt.c sctp_socket.h
+libwithsctp_la_LDFLAGS = -version-info \
+	@LIBWITHSCTP_CURRENT@:@LIBWITHSCTP_REVISION@:@LIBWITHSCTP_AGE@ -ldl
+
+pkgdoc_DATA = sctp_load_libs.c sctp_socket.c sctp_bind.c \
+	sctp_sockopt.c sctp_socket.h checksctp.c
+
+withsctp: withsctp.in
+	$(edit) $< >$@
+
+EXTRA_DIST += withsctp.in
+
+CLEANFILES += withsctp
diff --git a/src/withsctp/README b/src/withsctp/README
new file mode 100644
index 0000000..c7d8b97
--- /dev/null
+++ b/src/withsctp/README
@@ -0,0 +1,15 @@
+This is a package to let you use SCTP with your existing TCP-based binaries.
+
+usage:
+
+$ withsctp xinetd	# Start xinetd stream services on SCTP.
+$ withsctp telnet localhost	# Make a telnet over SCTP/IP connection.
+
+To install, edit the top of Makefile to set your install path(s) and then
+
+$ make all
+# make install
+
+This package originally written by La Monte H.P. Yarroll <piggy@acm.org>.
+To submit fixes or bug reports see lksctp.sourceforget.net.
+You can try the author or lksctp-developers@lists.sourceforget.net for support.
diff --git a/src/withsctp/checksctp.c b/src/withsctp/checksctp.c
new file mode 100644
index 0000000..bda9c1d
--- /dev/null
+++ b/src/withsctp/checksctp.c
@@ -0,0 +1,58 @@
+/* Does this host have SCTP?
+ *
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/* IPPROTO_SCTP SHOULD be defined in
+ * /usr/include/linux/in.h but probably isn't.
+ * It is an enum element, not a #define, so we can't easily check.
+ */
+#define SHOULD_IPPROTO_SCTP 132
+
+int main(void)
+{
+    int fd;
+
+    fd = socket(PF_INET, SOCK_STREAM, SHOULD_IPPROTO_SCTP);
+
+    if (fd <= 0) {
+	perror("checksctp");
+	exit(1);
+    } else {
+	fprintf(stderr, "SCTP supported\n");
+    }
+
+    close(fd);
+    return 0;
+}
diff --git a/src/withsctp/notes.txt b/src/withsctp/notes.txt
new file mode 100644
index 0000000..ef532ec
--- /dev/null
+++ b/src/withsctp/notes.txt
@@ -0,0 +1,6 @@
+Fri Dec 26 16:20:36 EST 2003
+
+It would be nice for withsctp to provide more facilities.
+
+Perhaps we could capture the bind call and allow substitution such as the
+arguments to sctp_darn.
diff --git a/src/withsctp/sctp_bind.c b/src/withsctp/sctp_bind.c
new file mode 100644
index 0000000..e744273
--- /dev/null
+++ b/src/withsctp/sctp_bind.c
@@ -0,0 +1,58 @@
+/* Wrap bind() to force the protocol for STREAM connections to SCTP.
+ * 
+ * Thanks to Midgard Security Services for
+ * http://www.securiteam.com/tools/3D5PTR5QAE.html
+ * from whence I cribbed the code to find the old bind().
+ * 
+ * gcc sctp_socket.c sctp_bind.c -o sctp_socket.so -ldl -shared -O2 -s
+ * export LD_PRELOAD=./sctp_socket.so
+ * 
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+#include <string.h> /* for strncmp() */
+#include <stdio.h>
+#include "sctp_socket.h"
+
+/* IPPROTO_SCTP SHOULD be defined in
+ * /usr/include/linux/in.h but probably isn't.
+ * It is an enum element, not a #define, so we can't easily check.
+ */
+#define SHOULD_IPPROTO_SCTP 132
+
+int
+bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+    _sctp_load_libs();
+
+    /* STUB.  The intent is to allow us to substitute an elaborate call to
+     * bindx() for the initial call to bind().  TBD.
+     */
+
+    return (real_bind)(sockfd, my_addr, addrlen);
+}
diff --git a/src/withsctp/sctp_load_libs.c b/src/withsctp/sctp_load_libs.c
new file mode 100644
index 0000000..d6a521f
--- /dev/null
+++ b/src/withsctp/sctp_load_libs.c
@@ -0,0 +1,67 @@
+/* Load the real underlying functions for withsctp and related scripts.
+ *
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "sctp_socket.h"
+
+int (*real_bind)(int  sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
+int (*real_socket)(int domain, int type, int protocol);
+int (*real_setsockopt)(int s, int level, int optname, const void *optval,
+		       socklen_t optlen);	
+static void *lib_handle = NULL;
+
+void
+_sctp_load_libs(void)
+{
+    if (NULL != lib_handle) return; /* Only init once.  */
+
+    if (!(lib_handle = dlopen("libc.so", RTLD_LAZY))) {
+	if (!(lib_handle = dlopen("libc.so.6", RTLD_LAZY))) {
+	    fprintf(stderr, "error loading libc!\n");
+	    exit (1);
+	}
+    }
+    
+    if (!(real_socket = dlsym(lib_handle, "socket"))) {
+	fprintf(stderr, "socket() not found in libc!\n");
+	exit (1);
+    }
+
+    if (!(real_bind = dlsym(lib_handle, "bind"))) {
+	fprintf(stderr, "bind() not found in libc!\n");
+	exit (1);
+    }
+
+    if (!(real_setsockopt = dlsym(lib_handle, "setsockopt"))) {
+	fprintf(stderr, "setsockopt() not found in libc!\n");
+	exit (1);
+    }
+}
diff --git a/src/withsctp/sctp_socket.c b/src/withsctp/sctp_socket.c
new file mode 100644
index 0000000..37d73af
--- /dev/null
+++ b/src/withsctp/sctp_socket.c
@@ -0,0 +1,59 @@
+/* Wrap socket() to force the protocol to SCTP for STREAM connections.
+ * 
+ * Thanks to Midgard Security Services for
+ * http://www.securiteam.com/tools/3D5PTR5QAE.html
+ * from whence I cribbed the code to find the old socket().
+ * 
+ * gcc sctp_socket.c -o sctp_socket.so -ldl -shared -O2 -s
+ * export LD_PRELOAD=./sctp_socket.so
+ * 
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+#include <string.h> /* for strncmp() */
+#include <stdio.h>
+#include "sctp_socket.h"
+
+/* IPPROTO_SCTP SHOULD be defined in
+ * /usr/include/linux/in.h but probably isn't.
+ * It is an enum element, not a #define, so we can't easily check.
+ */
+#define SHOULD_IPPROTO_SCTP 132
+
+int 
+socket(int domain, int type, int protocol)
+{
+    _sctp_load_libs();
+
+    if (((PF_INET == domain) || (PF_INET6 == domain))
+	&& (SOCK_STREAM == type)) {
+	protocol = SHOULD_IPPROTO_SCTP;
+    }
+
+    return (real_socket)(domain, type, protocol);
+}
diff --git a/src/withsctp/sctp_socket.h b/src/withsctp/sctp_socket.h
new file mode 100644
index 0000000..44c8226
--- /dev/null
+++ b/src/withsctp/sctp_socket.h
@@ -0,0 +1,69 @@
+/* Preprocessor definitions for withsctp and supporting scripts.
+ *
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+#include <dlfcn.h> /* for dlopen() and company */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/sctp.h>
+#include <netinet/tcp.h>
+
+extern int (*real_bind)(int  sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
+extern int (*real_socket)(int domain, int type, int protocol);
+extern int (*real_setsockopt)(int s, int level, int optname, const void *optval,
+			      socklen_t optlen);
+extern void _sctp_load_libs(void);
diff --git a/src/withsctp/sctp_sockopt.c b/src/withsctp/sctp_sockopt.c
new file mode 100644
index 0000000..01b8308
--- /dev/null
+++ b/src/withsctp/sctp_sockopt.c
@@ -0,0 +1,56 @@
+/* Wrap socket() to force the protocol to SCTP for STREAM connections.
+ * 
+ * Thanks to Midgard Security Services for
+ * http://www.securiteam.com/tools/3D5PTR5QAE.html
+ * from whence I cribbed the code to find the old socket().
+ * 
+ * Copyright 2003 La Monte HP Yarroll <piggy@acm.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 
+ *    2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *    3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+#include <string.h> /* for strncmp() */
+#include <stdio.h>
+#include "sctp_socket.h"
+
+/* IPPROTO_SCTP SHOULD be defined in
+ * /usr/include/linux/in.h but probably isn't.
+ * It is an enum element, not a #define, so we can't easily check.
+ */
+#define SHOULD_IPPROTO_SCTP 132
+
+int 
+setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
+{
+    _sctp_load_libs();
+
+    if ((IPPROTO_TCP == level) && (TCP_NODELAY == optname)) {
+	level = SHOULD_IPPROTO_SCTP;
+	optname = SCTP_NODELAY;
+    }
+
+    return (real_setsockopt)(s, level, optname, optval, optlen);
+}
diff --git a/src/withsctp/withsctp.in b/src/withsctp/withsctp.in
new file mode 100644
index 0000000..ef4f7bb
--- /dev/null
+++ b/src/withsctp/withsctp.in
@@ -0,0 +1,13 @@
+#!/bin/sh
+# -*- sh -*-
+LIBDIR=@libdir@/@PACKAGE@
+BINDIR=@bindir@
+LIBVER=@LIBWITHSCTP_CURRENT@.@LIBWITHSCTP_AGE@.@LIBWITHSCTP_REVISION@
+export LD_PRELOAD=${LIBDIR}/libwithsctp.so.${LIBVER}
+if ! ${BINDIR}/checksctp 2> /dev/null
+then
+    ${BINDIR}/checksctp;
+    exit 1;
+fi
+
+exec "$@"