diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f71833..1ebfcb3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,102 +29,62 @@
 # SUCH DAMAGE.
 #
 
-cmake_minimum_required(VERSION 2.6)
 project(usrsctplib)
+cmake_minimum_required(VERSION 3.0)
 
 # Debug build type as default
 if (NOT CMAKE_BUILD_TYPE)
-    message(STATUS "No build type selected, using DEBUG")
-    set(CMAKE_BUILD_TYPE "DEBUG")
+	message(STATUS "No build type selected, using DEBUG")
+	set(CMAKE_BUILD_TYPE "DEBUG")
 endif ()
 
 include(CheckStructHasMember)
 include(CheckIncludeFile)
 include(CheckIncludeFiles)
-
+include(CheckCCompilerFlag)
 
 #################################################
 # CHECK OPTIONS
 #################################################
 
-option(INVARIANTS "Add runtime checks" 0)
-if (INVARIANTS)
-    add_definitions(-DINVARIANTS)
+option(sctp_invariants "Add runtime checks" 0)
+if (sctp_invariants)
+	add_definitions(-DINVARIANTS)
 endif ()
 
-option(SCTP_DEBUG "Provide debug information" 1)
-if (SCTP_DEBUG)
-    add_definitions(-DSCTP_DEBUG)
+option(sctp_debug "Provide debug information" 1)
+if (sctp_debug)
+	add_definitions(-DSCTP_DEBUG)
 endif ()
 
-option(INET "Support IPv4" 1)
-if (INET)
-    add_definitions(-DINET)
+option(sctp_inet "Support IPv4" 1)
+if (sctp_inet)
+	add_definitions(-DINET)
 endif ()
 
-option(INET6 "Support IPv6" 1)
-if (INET6)
-    add_definitions(-DINET6)
+option(sctp_inet6 "Support IPv6" 1)
+if (sctp_inet6)
+	add_definitions(-DINET6)
 endif ()
 
-option(SCTP_SIMPLE_ALLOCATOR " " 1)
-if (SCTP_SIMPLE_ALLOCATOR)
-    add_definitions(-DSCTP_SIMPLE_ALLOCATOR)
+option(sctp_werror "Thread warning as error" 1)
+
+option(sctp_link_programs_static "Link example programs static" 0)
+
+option(sctp_build_programs "Build example programs" 1)
+
+option(sctp_sanitizer_address "Compile with address sanitizer" 0)
+
+option(sctp_sanitizer_memory "Compile with memory sanitizer" 0)
+
+if (sctp_sanitizer_address AND sctp_sanitizer_memory)
+	message(FATAL_ERROR "Can not compile with both sanitizer options")
 endif ()
 
-option(SCTP_PROCESS_LEVEL_LOCKS " " 1)
-if (SCTP_PROCESS_LEVEL_LOCKS)
-    add_definitions(-DSCTP_PROCESS_LEVEL_LOCKS)
-endif ()
-
-option(SCTP_WITH_NO_CSUM "Disable SCTP checksum" 0)
-if (SCTP_WITH_NO_CSUM)
-    add_definitions(-DSCTP_WITH_NO_CSUM)
-endif ()
-
-option(SCTP_MBUF_LOGGING " " 0)
-if (SCTP_MBUF_LOGGING)
-    add_definitions(-DSCTP_MBUF_LOGGING)
-endif ()
-
-option(SCTP_PACKET_LOGGING " " 0)
-if (SCTP_PACKET_LOGGING)
-    add_definitions(-DSCTP_PACKET_LOGGING)
-endif ()
-
-option(SCTP_SO_LOCK_TESTING " " 0)
-if (SCTP_SO_LOCK_TESTING)
-    add_definitions(-DSCTP_SO_LOCK_TESTING)
-endif ()
-
-option(SCTP_EMBEDDED_V6_SCOPE " " 0)
-if (SCTP_EMBEDDED_V6_SCOPE)
-    add_definitions(-DSCTP_EMBEDDED_V6_SCOPE)
-endif ()
-
-option(SCTP_KAME " " 0)
-if (SCTP_KAME)
-    add_definitions(-DSCTP_KAME)
-endif ()
-
-option(WERROR "Warning as error" 1)
-
-option(LINK_PROGRAMS_STATIC "Link example programs static" 0)
-
-option(BUILD_PROGRAMS "Build example programs" 1)
-
-option(SANITIZER_ADDRESS "Compile with address sanitizer" 0)
-
-option(SANITIZER_MEMORY "Compile with memory sanitizer" 0)
-
-if (SANITIZER_ADDRESS AND SANITIZER_MEMORY)
-    message(FATAL_ERROR "Can not compile with both sanitizer options")
-endif ()
-
-if (LINK_PROGRAMS_STATIC OR WIN32)
-    set(PROGRAMS_LINK_LIBRARY "usrsctp-static")
+if (sctp_link_programs_static OR WIN32)
+	set(programs_link_library "usrsctp-static")
 else ()
-    set(PROGRAMS_LINK_LIBRARY "usrsctp")
+	set(programs_link_library "usrsctp")
 endif ()
 
 
@@ -132,29 +92,29 @@
 # CHECK FOR TYPES AND FUNCTIONS
 #################################################
 
-check_include_files("sys/queue.h" HAVE_SYS_QUEUE_H)
-if (HAVE_SYS_QUEUE_H)
-    add_definitions(-DHAVE_SYS_QUEUE_H)
+check_include_files("sys/queue.h" have_sys_queue_h)
+if (have_sys_queue_h)
+	add_definitions(-DHAVE_SYS_QUEUE_H)
 endif ()
 
-check_include_files("sys/socket.h;linux/if_addr.h" HAVE_LINUX_IF_ADDR_H)
-if (HAVE_LINUX_IF_ADDR_H)
-    add_definitions(-DHAVE_LINUX_IF_ADDR_H)
+check_include_files("sys/socket.h;linux/if_addr.h" have_linux_if_addr_h)
+if (have_linux_if_addr_h)
+	add_definitions(-DHAVE_LINUX_IF_ADDR_H)
 endif ()
 
-check_include_files("sys/socket.h;linux/rtnetlink.h" HAVE_LINUX_RTNETLINK_H)
-if (HAVE_LINUX_RTNETLINK_H)
-    add_definitions(-DHAVE_LINUX_RTNETLINK_H)
+check_include_files("sys/socket.h;linux/rtnetlink.h" have_linux_rtnetlink_h)
+if (have_linux_rtnetlink_h)
+	add_definitions(-DHAVE_LINUX_RTNETLINK_H)
 endif ()
 
-check_include_files("sys/types.h;netinet/in.h;netinet/ip.h;netinet/ip_icmp.h" HAVE_NETINET_IP_ICMP_H)
-if (HAVE_NETINET_IP_ICMP_H)
-    add_definitions(-DHAVE_NETINET_IP_ICMP_H)
+check_include_files("sys/types.h;netinet/in.h;netinet/ip.h;netinet/ip_icmp.h" have_netinet_ip_icmp_h)
+if (have_netinet_ip_icmp_h)
+	add_definitions(-DHAVE_NETINET_IP_ICMP_H)
 endif ()
 
-check_include_files("stdatomic.h" HAVE_STDATOMIC_H)
-if (HAVE_STDATOMIC_H)
-    add_definitions(-DHAVE_STDATOMIC_H)
+check_include_files("stdatomic.h" have_stdatomic_h)
+if (have_stdatomic_h)
+	add_definitions(-DHAVE_STDATOMIC_H)
 endif ()
 
 
@@ -162,34 +122,35 @@
 # CHECK STRUCT MEMBERS
 #################################################
 
-set (CMAKE_REQUIRED_INCLUDES "${CMAKE_SOURCE_DIR}/usrsctplib")
-check_include_file(usrsctp.h HAVE_USRSCTP_H)
-if (NOT HAVE_USRSCTP_H)
-    message(FATAL_ERROR "usrsctp.h not found")
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_SOURCE_DIR}/usrsctplib")
+
+check_include_file(usrsctp.h have_usrsctp_h)
+if (NOT have_usrsctp_h)
+	message(FATAL_ERROR "usrsctp.h not found")
 endif ()
 
-check_struct_has_member("struct sockaddr" "sa_len" "sys/types.h;sys/socket.h" HAVE_SA_LEN)
-if (HAVE_SA_LEN)
-    message(STATUS "HAVE_SA_LEN")
-    add_definitions(-DHAVE_SA_LEN)
+check_struct_has_member("struct sockaddr" "sa_len" "sys/types.h;sys/socket.h" have_sa_len)
+if (have_sa_len)
+	message(STATUS "have_sa_len")
+	add_definitions(-DHAVE_SA_LEN)
 endif ()
 
-check_struct_has_member("struct sockaddr_in" "sin_len" "sys/types.h;netinet/in.h" HAVE_SIN_LEN)
-if (HAVE_SIN_LEN)
-    message(STATUS "HAVE_SIN_LEN")
-    add_definitions(-DHAVE_SIN_LEN)
+check_struct_has_member("struct sockaddr_in" "sin_len" "sys/types.h;netinet/in.h" have_sin_len)
+if (have_sin_len)
+	message(STATUS "have_sin_len")
+	add_definitions(-DHAVE_SIN_LEN)
 endif ()
 
-check_struct_has_member("struct sockaddr_in6" "sin6_len" "sys/types.h;netinet/in.h" HAVE_SIN6_LEN)
-if (HAVE_SIN6_LEN)
-    message(STATUS "HAVE_SIN6_LEN")
-    add_definitions(-DHAVE_SIN6_LEN)
+check_struct_has_member("struct sockaddr_in6" "sin6_len" "sys/types.h;netinet/in.h" have_sin6_len)
+if (have_sin6_len)
+	message(STATUS "have_sin6_len")
+	add_definitions(-DHAVE_SIN6_LEN)
 endif ()
 
-check_struct_has_member("struct sockaddr_conn" "sconn_len" "usrsctp.h" HAVE_SCONN_LEN)
-if (HAVE_SCONN_LEN)
-    message(STATUS "HAVE_SCONN_LEN")
-    add_definitions(-DHAVE_SCONN_LEN)
+check_struct_has_member("struct sockaddr_conn" "sconn_len" "usrsctp.h" have_sconn_len)
+if (have_sconn_len)
+	message(STATUS "HAVE_SCONN_LEN")
+	add_definitions(-DHAVE_SCONN_LEN)
 endif ()
 
 
@@ -198,38 +159,85 @@
 #################################################
 
 # SETTINGS FOR UNIX COMPILER
-if ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang" OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xGNU")
-    set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -std=c99 -pedantic -Wall -Wextra -Wfloat-equal -Wshadow -Wpointer-arith -Winit-self -Wno-unused-function -Wno-unused-parameter")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c99 -pedantic -Wall -Wextra -Wfloat-equal -Wshadow -Wpointer-arith -Winit-self -Wno-unused-function -Wno-unused-parameter")
+if ("${CMAKE_C_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang" OR "${CMAKE_C_COMPILER_ID}" MATCHES "GNU")
+	set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -std=c99 -pedantic -Wall -Wextra")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c99 -pedantic -Wall -Wextra")
 
-    if (WERROR)
-        set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Werror")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
-    endif ()
+	check_c_compiler_flag(-Wfloat-equal has_wfloat_equal)
+	if (has_wfloat_equal)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wfloat-equal")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wfloat-equal")
+	endif ()
 
-    if (SANITIZER_ADDRESS)
-        set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fsanitize=address -O1 -fno-omit-frame-pointer -g -Wno-address-of-packed-member")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer -g -Wno-address-of-packed-member")
-    endif ()
+	check_c_compiler_flag(-Wshadow has_wshadow)
+	if (has_wshadow)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wshadow")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
+	endif ()
 
-    if (SANITIZER_MEMORY)
-        # maybe add "-fPIE -pie" here
-        set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fsanitize=memory -fno-omit-frame-pointer -g -Wno-address-of-packed-member -fsanitize-memory-track-origins")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -g -Wno-address-of-packed-member -fsanitize-memory-track-origins")
-    endif ()
+	check_c_compiler_flag(-Wpointer-arith has_wpointer_aritih)
+	if (has_wpointer_aritih)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wpointer-arith")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith")
+	endif ()
+
+	check_c_compiler_flag(-Wunreachable-code has_wunreachable_code)
+	if (has_wunreachable_code)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wunreachable-code")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunreachable-code")
+	endif ()
+
+	check_c_compiler_flag(-Winit-self has_winit_self)
+	if (has_winit_self)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Winit-self")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self")
+	endif ()
+
+	check_c_compiler_flag(-Wno-unused-function has_wno_unused_function)
+	if (has_wno_unused_function)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wno-unused-function")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
+	endif ()
+
+	check_c_compiler_flag(-Wno-unused-parameter has_wno_unused_parameter)
+	if (has_wno_unused_parameter)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wno-unused-parameter")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
+	endif ()
+
+	check_c_compiler_flag(-Wno-unreachable-code has_wno_unreachable_code)
+	if (has_wno_unreachable_code)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wno-unreachable-code")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unreachable-code")
+	endif ()
+
+	if (sctp_werror)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Werror")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+	endif ()
+
+	if (sctp_sanitizer_address)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fsanitize=address -fno-omit-frame-pointer -g")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g")
+	endif ()
+
+	if (sctp_sanitizer_memory)
+		set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fsanitize=memory -fno-omit-frame-pointer -g -fsanitize-memory-track-origins")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -g -fsanitize-memory-track-origins")
+	endif ()
 endif ()
 
 # SETTINGS FOR VISUAL STUDIO COMPILER
 if ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
-    if (CMAKE_C_FLAGS MATCHES "/W[0-4]")
-        string(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
-    else ()
-        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3")
-    endif ()
+	if (CMAKE_C_FLAGS MATCHES "/W[0-4]")
+		string(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+	else ()
+		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3")
+	endif ()
 
-    if (WERROR)
-        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
-    endif ()
+	if (WERROR)
+		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
+	endif ()
 endif ()
 
 
@@ -239,6 +247,6 @@
 
 add_subdirectory(usrsctplib)
 
-if (BUILD_PROGRAMS)
-    add_subdirectory(programs)
+if (sctp_build_programs)
+	add_subdirectory(programs)
 endif ()
diff --git a/README.md b/README.md
index 6fc164c..0f0f8b1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
 # usrsctp
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/13430/badge.svg)](https://scan.coverity.com/projects/usrsctp)
 
 This is a userland SCTP stack supporting FreeBSD, Linux, Mac OS X and Windows.
 
diff --git a/configure.ac b/configure.ac
index 2339ea7..a6bfbd9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,7 +45,7 @@
 
 case $host_os in
 darwin*)
-  CFLAGS="$CFLAGS -std=c99 -Wno-deprecated-declarations -Wno-address-of-packed-member -D__APPLE_USE_RFC_2292"
+  CFLAGS="$CFLAGS -std=c99 -Wno-deprecated-declarations -D__APPLE_USE_RFC_2292"
   LIBCFLAGS="$LIBCFLAGS -U__APPLE__ -D__Userspace_os_Darwin"
   ;;
 dragonfly*)
@@ -55,7 +55,7 @@
 freebsd*)
   CFLAGS="$CFLAGS -std=c99 -pthread"
   if $CC --version | grep -q clang; then
-    CFLAGS="$CFLAGS -Wno-unknown-warning-option -Wno-address-of-packed-member"
+    CFLAGS="$CFLAGS -Wno-unknown-warning-option"
     LDFLAGS="$LDFLAGS -Qunused-arguments"
   fi
   LIBCFLAGS="$LIBCFLAGS -U__FreeBSD__ -D__Userspace_os_FreeBSD"
diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt
index 3026ddc..ab4c7fd 100644
--- a/programs/CMakeLists.txt
+++ b/programs/CMakeLists.txt
@@ -49,11 +49,11 @@
 #################################################
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    add_definitions(-D_GNU_SOURCE)
+	add_definitions(-D_GNU_SOURCE)
 endif ()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-    add_definitions(-D__APPLE_USE_RFC_2292)
+	add_definitions(-D__APPLE_USE_RFC_2292)
 endif ()
 
 
@@ -68,32 +68,32 @@
 # PROGRAMS
 #################################################
 
-set(CHECK_PROGRAMS
-    client.c
-    daytime_server.c
-    discard_server.c
-    echo_server.c
-    ekr_client.c
-    ekr_loop_offload.c
-    ekr_loop.c
-    ekr_peer.c
-    ekr_server.c
-    http_client.c
-    rtcweb.c
-    test_libmgmt.c
-    test_timer.c
-    tsctp.c
+set(check_programs
+	client.c
+	daytime_server.c
+	discard_server.c
+	echo_server.c
+	ekr_client.c
+	ekr_loop_offload.c
+	ekr_loop.c
+	ekr_peer.c
+	ekr_server.c
+	http_client.c
+	rtcweb.c
+	test_libmgmt.c
+	test_timer.c
+	tsctp.c
 )
 
-foreach (SOURCE_FILE ${CHECK_PROGRAMS})
-    get_filename_component(SOURCE_FILE_WE ${SOURCE_FILE} NAME_WE)
-    add_executable(
-        ${SOURCE_FILE_WE}
-        ${SOURCE_FILE}
-    )
+foreach (source_file ${check_programs})
+	get_filename_component(source_file_we ${source_file} NAME_WE)
+	add_executable(
+		${source_file_we}
+		${source_file}
+	)
 
-    target_link_libraries(${SOURCE_FILE_WE}
-        ${PROGRAMS_LINK_LIBRARY}
-        ${CMAKE_THREAD_LIBS_INIT}
-    )
+	target_link_libraries(${source_file_we}
+		${programs_link_library}
+		${CMAKE_THREAD_LIBS_INIT}
+	)
 endforeach ()
diff --git a/programs/client.c b/programs/client.c
index 8dcad6f..1fe7579 100644
--- a/programs/client.c
+++ b/programs/client.c
@@ -32,6 +32,9 @@
  * Usage: client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port]
  */
 
+#ifdef _WIN32
+#define _CRT_SECURE_NO_WARNINGS
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -55,6 +58,206 @@
 typedef char* caddr_t;
 #endif
 
+static void
+handle_association_change_event(struct sctp_assoc_change *sac)
+{
+	unsigned int i, n;
+
+	printf("Association change ");
+	switch (sac->sac_state) {
+	case SCTP_COMM_UP:
+		printf("SCTP_COMM_UP");
+		break;
+	case SCTP_COMM_LOST:
+		printf("SCTP_COMM_LOST");
+		break;
+	case SCTP_RESTART:
+		printf("SCTP_RESTART");
+		break;
+	case SCTP_SHUTDOWN_COMP:
+		printf("SCTP_SHUTDOWN_COMP");
+		break;
+	case SCTP_CANT_STR_ASSOC:
+		printf("SCTP_CANT_STR_ASSOC");
+		break;
+	default:
+		printf("UNKNOWN");
+		break;
+	}
+	printf(", streams (in/out) = (%u/%u)",
+	       sac->sac_inbound_streams, sac->sac_outbound_streams);
+	n = sac->sac_length - sizeof(struct sctp_assoc_change);
+	if (((sac->sac_state == SCTP_COMM_UP) ||
+	     (sac->sac_state == SCTP_RESTART)) && (n > 0)) {
+		printf(", supports");
+		for (i = 0; i < n; i++) {
+			switch (sac->sac_info[i]) {
+			case SCTP_ASSOC_SUPPORTS_PR:
+				printf(" PR");
+				break;
+			case SCTP_ASSOC_SUPPORTS_AUTH:
+				printf(" AUTH");
+				break;
+			case SCTP_ASSOC_SUPPORTS_ASCONF:
+				printf(" ASCONF");
+				break;
+			case SCTP_ASSOC_SUPPORTS_MULTIBUF:
+				printf(" MULTIBUF");
+				break;
+			case SCTP_ASSOC_SUPPORTS_RE_CONFIG:
+				printf(" RE-CONFIG");
+				break;
+			default:
+				printf(" UNKNOWN(0x%02x)", sac->sac_info[i]);
+				break;
+			}
+		}
+	} else if (((sac->sac_state == SCTP_COMM_LOST) ||
+	            (sac->sac_state == SCTP_CANT_STR_ASSOC)) && (n > 0)) {
+		printf(", ABORT =");
+		for (i = 0; i < n; i++) {
+			printf(" 0x%02x", sac->sac_info[i]);
+		}
+	}
+	printf(".\n");
+	if ((sac->sac_state == SCTP_CANT_STR_ASSOC) ||
+	    (sac->sac_state == SCTP_SHUTDOWN_COMP) ||
+	    (sac->sac_state == SCTP_COMM_LOST)) {
+		exit(0);
+	}
+	return;
+}
+
+static void
+handle_peer_address_change_event(struct sctp_paddr_change *spc)
+{
+	char addr_buf[INET6_ADDRSTRLEN];
+	const char *addr;
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_conn *sconn;
+
+	switch (spc->spc_aaddr.ss_family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *)&spc->spc_aaddr;
+		addr = inet_ntop(AF_INET, &sin->sin_addr, addr_buf, INET_ADDRSTRLEN);
+		break;
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
+		addr = inet_ntop(AF_INET6, &sin6->sin6_addr, addr_buf, INET6_ADDRSTRLEN);
+		break;
+	case AF_CONN:
+		sconn = (struct sockaddr_conn *)&spc->spc_aaddr;
+#ifdef _WIN32
+		_snprintf(addr_buf, INET6_ADDRSTRLEN, "%p", sconn->sconn_addr);
+#else
+		snprintf(addr_buf, INET6_ADDRSTRLEN, "%p", sconn->sconn_addr);
+#endif
+		addr = addr_buf;
+		break;
+	default:
+#ifdef _WIN32
+		_snprintf(addr_buf, INET6_ADDRSTRLEN, "Unknown family %d", spc->spc_aaddr.ss_family);
+#else
+		snprintf(addr_buf, INET6_ADDRSTRLEN, "Unknown family %d", spc->spc_aaddr.ss_family);
+#endif
+		addr = addr_buf;
+		break;
+	}
+	printf("Peer address %s is now ", addr);
+	switch (spc->spc_state) {
+	case SCTP_ADDR_AVAILABLE:
+		printf("SCTP_ADDR_AVAILABLE");
+		break;
+	case SCTP_ADDR_UNREACHABLE:
+		printf("SCTP_ADDR_UNREACHABLE");
+		break;
+	case SCTP_ADDR_REMOVED:
+		printf("SCTP_ADDR_REMOVED");
+		break;
+	case SCTP_ADDR_ADDED:
+		printf("SCTP_ADDR_ADDED");
+		break;
+	case SCTP_ADDR_MADE_PRIM:
+		printf("SCTP_ADDR_MADE_PRIM");
+		break;
+	case SCTP_ADDR_CONFIRMED:
+		printf("SCTP_ADDR_CONFIRMED");
+		break;
+	default:
+		printf("UNKNOWN");
+		break;
+	}
+	printf(" (error = 0x%08x).\n", spc->spc_error);
+	return;
+}
+
+static void
+handle_send_failed_event(struct sctp_send_failed_event *ssfe)
+{
+	size_t i, n;
+
+	if (ssfe->ssfe_flags & SCTP_DATA_UNSENT) {
+		printf("Unsent ");
+	}
+	if (ssfe->ssfe_flags & SCTP_DATA_SENT) {
+		printf("Sent ");
+	}
+	if (ssfe->ssfe_flags & ~(SCTP_DATA_SENT | SCTP_DATA_UNSENT)) {
+		printf("(flags = %x) ", ssfe->ssfe_flags);
+	}
+	printf("message with PPID = %u, SID = %u, flags: 0x%04x due to error = 0x%08x",
+	       ntohl(ssfe->ssfe_info.snd_ppid), ssfe->ssfe_info.snd_sid,
+	       ssfe->ssfe_info.snd_flags, ssfe->ssfe_error);
+	n = ssfe->ssfe_length - sizeof(struct sctp_send_failed_event);
+	for (i = 0; i < n; i++) {
+		printf(" 0x%02x", ssfe->ssfe_data[i]);
+	}
+	printf(".\n");
+	return;
+}
+
+static void
+handle_notification(union sctp_notification *notif, size_t n)
+{
+	if (notif->sn_header.sn_length != (uint32_t)n) {
+		return;
+	}
+	switch (notif->sn_header.sn_type) {
+	case SCTP_ASSOC_CHANGE:
+		handle_association_change_event(&(notif->sn_assoc_change));
+		break;
+	case SCTP_PEER_ADDR_CHANGE:
+		handle_peer_address_change_event(&(notif->sn_paddr_change));
+		break;
+	case SCTP_REMOTE_ERROR:
+		break;
+	case SCTP_SHUTDOWN_EVENT:
+		break;
+	case SCTP_ADAPTATION_INDICATION:
+		break;
+	case SCTP_PARTIAL_DELIVERY_EVENT:
+		break;
+	case SCTP_AUTHENTICATION_EVENT:
+		break;
+	case SCTP_SENDER_DRY_EVENT:
+		break;
+	case SCTP_NOTIFICATIONS_STOPPED_EVENT:
+		break;
+	case SCTP_SEND_FAILED_EVENT:
+		handle_send_failed_event(&(notif->sn_send_failed_event));
+		break;
+	case SCTP_STREAM_RESET_EVENT:
+		break;
+	case SCTP_ASSOC_RESET_EVENT:
+		break;
+	case SCTP_STREAM_CHANGE_EVENT:
+		break;
+	default:
+		break;
+	}
+}
+
 static int
 receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
            size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
@@ -63,13 +266,17 @@
 		done = 1;
 		usrsctp_close(sock);
 	} else {
+		if (flags & MSG_NOTIFICATION) {
+			handle_notification((union sctp_notification *)data, datalen);
+		} else {
 #ifdef _WIN32
-		_write(_fileno(stdout), data, (unsigned int)datalen);
+			_write(_fileno(stdout), data, (unsigned int)datalen);
 #else
-		if (write(fileno(stdout), data, datalen) < 0) {
-			perror("write");
-		}
+			if (write(fileno(stdout), data, datalen) < 0) {
+				perror("write");
+			}
 #endif
+		}
 		free(data);
 	}
 	return (1);
@@ -94,8 +301,13 @@
 	struct sockaddr_in6 addr6;
 	struct sctp_udpencaps encaps;
 	struct sctpstat stat;
+	struct sctp_event event;
+	uint16_t event_types[] = {SCTP_ASSOC_CHANGE,
+	                          SCTP_PEER_ADDR_CHANGE,
+	                          SCTP_SEND_FAILED_EVENT};
 	char buffer[80];
-	int i, n;
+	unsigned int i;
+	int n;
 
 	if (argc < 3) {
 		printf("%s", "Usage: client remote_addr remote_port local_port local_encaps_port remote_encaps_port\n");
@@ -113,6 +325,15 @@
 	if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) {
 		perror("usrsctp_socket");
 	}
+	memset(&event, 0, sizeof(event));
+	event.se_assoc_id = SCTP_ALL_ASSOC;
+	event.se_on = 1;
+	for (i = 0; i < sizeof(event_types)/sizeof(uint16_t); i++) {
+		event.se_type = event_types[i];
+		if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) {
+			perror("setsockopt SCTP_EVENT");
+		}
+	}
 	if (argc > 3) {
 		memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
 #ifdef HAVE_SIN6_LEN
@@ -161,7 +382,7 @@
 	} else {
 		addr = addrs;
 		printf("Local addresses: ");
-		for (i = 0; i < n; i++) {
+		for (i = 0; i < (unsigned int)n; i++) {
 			if (i > 0) {
 				printf("%s", ", ");
 			}
@@ -209,7 +430,7 @@
 	} else {
 		addr = addrs;
 		printf("Peer addresses: ");
-		for (i = 0; i < n; i++) {
+		for (i = 0; i < (unsigned int)n; i++) {
 			if (i > 0) {
 				printf("%s", ", ");
 			}
@@ -262,7 +483,7 @@
 	}
 	while (!done) {
 #ifdef _WIN32
-		Sleep(1*1000);
+		Sleep(1 * 1000);
 #else
 		sleep(1);
 #endif
@@ -272,7 +493,7 @@
 	       stat.sctps_outpackets, stat.sctps_inpackets);
 	while (usrsctp_finish() != 0) {
 #ifdef _WIN32
-		Sleep(1000);
+		Sleep(1 * 1000);
 #else
 		sleep(1);
 #endif
diff --git a/programs/daytime_server.c b/programs/daytime_server.c
index 18a0fcb..35cadf5 100644
--- a/programs/daytime_server.c
+++ b/programs/daytime_server.c
@@ -30,6 +30,10 @@
 
 /*
  * Usage: daytime_server [local_encaps_port] [remote_encaps_port]
+ * 
+ * Example
+ * Server: $ ./daytime_server 11111 22222
+ * Client: $ ./client 127.0.0.1 13 0 22222 11111
  */
 
 #ifdef _WIN32
@@ -49,6 +53,10 @@
 #endif
 #include <usrsctp.h>
 
+#define PORT 13
+#define DAYTIME_PPID 40
+#define SLEEP 1
+
 void
 debug_printf(const char *format, ...)
 {
@@ -59,7 +67,6 @@
 	va_end(ap);
 }
 
-#define DAYTIME_PPID 40
 int
 main(int argc, char *argv[])
 {
@@ -97,7 +104,7 @@
 	addr.sin_len = sizeof(struct sockaddr_in);
 #endif
 	addr.sin_family = AF_INET;
-	addr.sin_port = htons(13);
+	addr.sin_port = htons(PORT);
 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
 	if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
 		perror("usrsctp_bind");
@@ -121,16 +128,18 @@
 		sndinfo.snd_ppid = htonl(DAYTIME_PPID);
 		sndinfo.snd_context = 0;
 		sndinfo.snd_assoc_id = 0;
-		usrsctp_sendv(conn_sock, buffer, strlen(buffer), NULL, 0, (void *)&sndinfo,
-		              (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0);
+		if (usrsctp_sendv(conn_sock, buffer, strlen(buffer), NULL, 0, (void *)&sndinfo,
+		                  (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
+			perror("usrsctp_sendv");
+		}
 		usrsctp_close(conn_sock);
 	}
 	usrsctp_close(sock);
 	while (usrsctp_finish() != 0) {
 #ifdef _WIN32
-		Sleep(1000);
+		Sleep(SLEEP * 1000);
 #else
-		sleep(1);
+		sleep(SLEEP);
 #endif
 	}
 	return (0);
diff --git a/programs/discard_server.c b/programs/discard_server.c
index bc67cd5..39846dd 100644
--- a/programs/discard_server.c
+++ b/programs/discard_server.c
@@ -30,6 +30,10 @@
 
 /*
  * Usage: discard_server [local_encaps_port] [remote_encaps_port]
+ * 
+ * Example
+ * Server: $ ./discard_server 11111 22222
+ * Client: $ ./client 127.0.0.1 9 0 22222 11111
  */
 
 #ifdef _WIN32
@@ -48,7 +52,9 @@
 #endif
 #include <usrsctp.h>
 
+#define PORT 9
 #define BUFFER_SIZE 10240
+#define SLEEP 1
 
 const int use_cb = 0;
 
@@ -189,7 +195,7 @@
 	addr.sin6_len = sizeof(struct sockaddr_in6);
 #endif
 	addr.sin6_family = AF_INET6;
-	addr.sin6_port = htons(9);
+	addr.sin6_port = htons(PORT);
 	addr.sin6_addr = in6addr_any;
 	if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) {
 		perror("usrsctp_bind");
@@ -200,9 +206,9 @@
 	while (1) {
 		if (use_cb) {
 #ifdef _WIN32
-			Sleep(1*1000);
+			Sleep(SLEEP * 1000);
 #else
-			sleep(1);
+			sleep(SLEEP);
 #endif
 		} else {
 			from_len = (socklen_t)sizeof(struct sockaddr_in6);
@@ -239,9 +245,9 @@
 	usrsctp_close(sock);
 	while (usrsctp_finish() != 0) {
 #ifdef _WIN32
-		Sleep(1000);
+		Sleep(SLEEP * 1000);
 #else
-		sleep(1);
+		sleep(SLEEP);
 #endif
 	}
 	return (0);
diff --git a/programs/echo_server.c b/programs/echo_server.c
index 1eab193..64f12c5 100644
--- a/programs/echo_server.c
+++ b/programs/echo_server.c
@@ -29,7 +29,11 @@
  */
 
 /*
- * Usage: discard_server [local_encaps_port] [remote_encaps_port]
+ * Usage: echo_server [local_encaps_port] [remote_encaps_port]
+ * 
+ * Example
+ * Server: $ ./echo_server 11111 22222
+ * Client: $ ./client 127.0.0.1 7 0 22222 11111
  */
 
 #ifdef _WIN32
@@ -48,7 +52,9 @@
 #endif
 #include <usrsctp.h>
 
+#define PORT 7
 #define BUFFER_SIZE 10240
+#define SLEEP 1
 
 const int use_cb = 0;
 
@@ -204,7 +210,7 @@
 	addr.sin6_len = sizeof(struct sockaddr_in6);
 #endif
 	addr.sin6_family = AF_INET6;
-	addr.sin6_port = htons(7);
+	addr.sin6_port = htons(PORT);
 	addr.sin6_addr = in6addr_any;
 	if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) {
 		perror("usrsctp_bind");
@@ -215,9 +221,9 @@
 	while (1) {
 		if (use_cb) {
 #ifdef _WIN32
-			Sleep(1*1000);
+		Sleep(SLEEP * 1000);
 #else
-			sleep(1);
+		sleep(SLEEP);
 #endif
 		} else {
 			from_len = (socklen_t)sizeof(struct sockaddr_in6);
@@ -269,9 +275,9 @@
 	usrsctp_close(sock);
 	while (usrsctp_finish() != 0) {
 #ifdef _WIN32
-		Sleep(1000);
+		Sleep(SLEEP * 1000);
 #else
-		sleep(1);
+		sleep(SLEEP);
 #endif
 	}
 	return (0);
diff --git a/programs/ekr_client.c b/programs/ekr_client.c
index 5cef40c..1e5e7e3 100644
--- a/programs/ekr_client.c
+++ b/programs/ekr_client.c
@@ -200,10 +200,12 @@
 #ifdef _WIN32
 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
 		printf("socket() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 		perror("socket");
+		exit(EXIT_FAILURE);
 	}
 #endif
 	memset(&sin, 0, sizeof(struct sockaddr_in));
@@ -214,15 +216,17 @@
 	sin.sin_port = htons(atoi(argv[2]));
 	if (!inet_pton(AF_INET, argv[1], &sin.sin_addr.s_addr)){
 		printf("error: invalid address\n");
-		exit(1);
+		exit(EXIT_FAILURE);
 	}
 #ifdef _WIN32
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
 		printf("bind() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
 		perror("bind");
+		exit(EXIT_FAILURE);
 	}
 #endif
 	memset(&sin, 0, sizeof(struct sockaddr_in));
@@ -233,15 +237,17 @@
 	sin.sin_port = htons(atoi(argv[4]));
 	if (!inet_pton(AF_INET, argv[3], &sin.sin_addr.s_addr)){
 		printf("error: invalid address\n");
-		exit(1);
+		exit(EXIT_FAILURE);
 	}
 #ifdef _WIN32
 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
 		printf("connect() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
 		perror("connect");
+		exit(EXIT_FAILURE);
 	}
 #endif
 #ifdef SCTP_DEBUG
diff --git a/programs/ekr_loop.c b/programs/ekr_loop.c
index 798e899..77e72c5 100644
--- a/programs/ekr_loop.c
+++ b/programs/ekr_loop.c
@@ -383,7 +383,7 @@
 	};
 #endif
 #ifdef SCTP_DEBUG
-	usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
+	usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE);
 #endif
 	usrsctp_sysctl_set_sctp_ecn_enable(0);
 	usrsctp_register_address((void *)&fd_c);
@@ -399,7 +399,7 @@
 		exit(EXIT_FAILURE);
 	}
 	printf("Change send socket buffer size from %d ", cur_buf_size);
-	snd_buf_size = 1<<20; /* 1 MB */
+	snd_buf_size = 1<<22; /* 4 MB */
 	if (usrsctp_setsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &snd_buf_size, sizeof(int)) < 0) {
 		perror("usrsctp_setsockopt");
 		exit(EXIT_FAILURE);
@@ -489,7 +489,13 @@
 	sndinfo.snd_ppid = htonl(DISCARD_PPID);
 	sndinfo.snd_context = 0;
 	sndinfo.snd_assoc_id = 0;
-	/* Send a 1 MB message */
+	/* Send a 1 MB ordered message */
+	if (usrsctp_sendv(s_c, line, LINE_LENGTH, NULL, 0, (void *)&sndinfo,
+	                 (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
+		perror("usrsctp_sendv");
+		exit(EXIT_FAILURE);
+	}
+	/* Send a 1 MB ordered message */
 	if (usrsctp_sendv(s_c, line, LINE_LENGTH, NULL, 0, (void *)&sndinfo,
 	                 (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
 		perror("usrsctp_sendv");
diff --git a/programs/ekr_peer.c b/programs/ekr_peer.c
index b3cfe62..ca0c64d 100644
--- a/programs/ekr_peer.c
+++ b/programs/ekr_peer.c
@@ -387,7 +387,7 @@
 #ifdef _WIN32
 	if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
 		printf("WSAStartup failed\n");
-		exit (EXIT_FAILURE);
+		exit(EXIT_FAILURE);
 	}
 #endif
 	usrsctp_init(0, conn_output, debug_printf);
@@ -395,10 +395,12 @@
 #ifdef _WIN32
 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
 		printf("socket() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 		perror("socket");
+		exit(EXIT_FAILURE);
 	}
 #endif
 	memset(&sin, 0, sizeof(struct sockaddr_in));
@@ -409,15 +411,17 @@
 	sin.sin_port = htons(atoi(argv[2]));
 	if (!inet_pton(AF_INET, argv[1], &sin.sin_addr.s_addr)){
 		printf("error: invalid address\n");
-		exit(1);
+		exit(EXIT_FAILURE);
 	}
 #ifdef _WIN32
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
 		printf("bind() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
 		perror("bind");
+		exit(EXIT_FAILURE);
 	}
 #endif
 	memset(&sin, 0, sizeof(struct sockaddr_in));
@@ -428,15 +432,17 @@
 	sin.sin_port = htons(atoi(argv[4]));
 	if (!inet_pton(AF_INET, argv[3], &sin.sin_addr.s_addr)){
 		printf("error: invalid address\n");
-		exit(1);
+		exit(EXIT_FAILURE);
 	}
 #ifdef _WIN32
 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
 		printf("connect() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
 		perror("connect");
+		exit(EXIT_FAILURE);
 	}
 #endif
 #ifdef _WIN32
diff --git a/programs/ekr_server.c b/programs/ekr_server.c
index 02f02b1..5545abb 100644
--- a/programs/ekr_server.c
+++ b/programs/ekr_server.c
@@ -50,7 +50,9 @@
 #endif
 #include <usrsctp.h>
 
+#define PORT 5001
 #define MAX_PACKET_SIZE (1<<16)
+#define SLEEP 1
 
 #ifdef _WIN32
 static DWORD WINAPI
@@ -196,10 +198,12 @@
 #ifdef _WIN32
 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
 		printf("socket() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 		perror("socket");
+		exit(EXIT_FAILURE);
 	}
 #endif
 	memset(&sin, 0, sizeof(struct sockaddr_in));
@@ -210,15 +214,17 @@
 	sin.sin_port = htons(atoi(argv[2]));
 	if (!inet_pton(AF_INET, argv[1], &sin.sin_addr.s_addr)){
 		printf("error: invalid address\n");
-		exit(1);
+		exit(EXIT_FAILURE);
 	}
 #ifdef _WIN32
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
 		printf("bind() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
 		perror("bind");
+		exit(EXIT_FAILURE);
 	}
 #endif
 	memset(&sin, 0, sizeof(struct sockaddr_in));
@@ -229,15 +235,17 @@
 	sin.sin_port = htons(atoi(argv[4]));
 	if (!inet_pton(AF_INET, argv[3], &sin.sin_addr.s_addr)){
 		printf("error: invalid address\n");
-		exit(1);
+		exit(EXIT_FAILURE);
 	}
 #ifdef _WIN32
 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
 		printf("connect() failed with error: %d\n", WSAGetLastError());
+		exit(EXIT_FAILURE);
 	}
 #else
 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
 		perror("connect");
+		exit(EXIT_FAILURE);
 	}
 #endif
 #ifdef SCTP_DEBUG
@@ -258,7 +266,7 @@
 #ifdef HAVE_SCONN_LEN
 	sconn.sconn_len = sizeof(struct sockaddr_conn);
 #endif
-	sconn.sconn_port = htons(5001);
+	sconn.sconn_port = htons(PORT);
 	sconn.sconn_addr = (void *)&fd;
 	if (usrsctp_bind(s, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
 		perror("usrsctp_bind");
@@ -275,9 +283,9 @@
 	usrsctp_deregister_address((void *)&fd);
 	while (usrsctp_finish() != 0) {
 #ifdef _WIN32
-		Sleep(1000);
+		Sleep(SLEEP * 1000);
 #else
-		sleep(1);
+		sleep(SLEEP);
 #endif
 	}
 #ifdef _WIN32
diff --git a/programs/http_client.c b/programs/http_client.c
index 6dfd1ee..607ee26 100644
--- a/programs/http_client.c
+++ b/programs/http_client.c
@@ -30,6 +30,9 @@
 
 /*
  * Usage: http_client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]
+ * 
+ * Example
+ * Client: $ ./http_client 212.201.121.100 80 0 9899 9899 /cgi-bin/he
  */
 
 #ifdef _WIN32
diff --git a/programs/rtcweb.c b/programs/rtcweb.c
index 1e0b734..5c5908d 100644
--- a/programs/rtcweb.c
+++ b/programs/rtcweb.c
@@ -146,11 +146,23 @@
 #undef SCTP_PACKED
 
 static void
+lock_peer_connection(struct peer_connection *);
+
+static void
+unlock_peer_connection(struct peer_connection *);
+
+static void
 init_peer_connection(struct peer_connection *pc)
 {
 	uint32_t i;
 	struct channel *channel;
 
+#ifdef _WIN32
+	InitializeCriticalSection(&(pc->mutex));
+#else
+	pthread_mutex_init(&pc->mutex, NULL);
+#endif
+	lock_peer_connection(pc);
 	for (i = 0; i < NUMBER_OF_CHANNELS; i++) {
 		channel = &(pc->channels[i]);
 		channel->id = i;
@@ -169,11 +181,7 @@
 	}
 	pc->o_stream_buffer_counter = 0;
 	pc->sock = NULL;
-#ifdef _WIN32
-	InitializeCriticalSection(&(pc->mutex));
-#else
-	pthread_mutex_init(&pc->mutex, NULL);
-#endif
+	unlock_peer_connection(pc);
 }
 
 static void
diff --git a/programs/test_timer.c b/programs/test_timer.c
index ba2cb50..90a93c8 100644
--- a/programs/test_timer.c
+++ b/programs/test_timer.c
@@ -39,18 +39,13 @@
 int
 main(void) 
 {
-	int i;
-	void *p;
+	unsigned int i;
 
 	usrsctp_init(0, NULL, NULL);
-#ifdef SCTP_DEBUG
-	usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
-#endif
 	printf("Entering the loop\n");
-	p = &i;
-	for (i = 0; i < 100000; i++) {
-		usrsctp_register_address(p);
-		usrsctp_deregister_address(p);
+	for (i = 0; i < 1000000; i++) {
+		usrsctp_register_address(NULL);
+		usrsctp_deregister_address(NULL);
 	}
 	printf("Exited the loop\n");
 	while (usrsctp_finish() != 0) {
diff --git a/programs/tsctp.c b/programs/tsctp.c
index 89811c1..c85da22 100644
--- a/programs/tsctp.c
+++ b/programs/tsctp.c
@@ -414,7 +414,9 @@
 				fragpoint = atoi(optarg);
 				break;
 			case 'L':
-				inet_pton(AF_INET, optarg, &srcAddr);
+				if (inet_pton(AF_INET, optarg, &srcAddr) != 1) {
+					printf("Can't parse %s\n", optarg);
+				}
 				break;
 			case 'R':
 				rcvbufsize = atoi(optarg);
diff --git a/usrsctplib/CMakeLists.txt b/usrsctplib/CMakeLists.txt
index 942e01a..c5b7229 100644
--- a/usrsctplib/CMakeLists.txt
+++ b/usrsctplib/CMakeLists.txt
@@ -36,15 +36,17 @@
 
 set(VERSION "1.0.0")
 
-set(prefix ${CMAKE_INSTALL_PREFIX})
-set(exec_prefix "\${prefix}")
-set(libdir "\${exec_prefix}/lib")
-set(includedir "\${prefix}/include/usrsctp")
+set(prefix 					${CMAKE_INSTALL_PREFIX})
+set(exec_prefix 			${prefix})
+set(libdir 					${exec_prefix}/lib)
+set(includedir 				${prefix}/include/usrsctp)
 set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
-set(CMAKE_MACOSX_RPATH 1)
+set(CMAKE_MACOSX_RPATH 		1)
 
 add_definitions(-D__Userspace__)
 add_definitions(-D__Userspace_os_${CMAKE_SYSTEM_NAME})
+add_definitions(-DSCTP_SIMPLE_ALLOCATOR)
+add_definitions(-DSCTP_PROCESS_LEVEL_LOCKS)
 
 
 #################################################
@@ -52,34 +54,32 @@
 #################################################
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    add_definitions(-D_GNU_SOURCE)
-    #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wno-address-of-packed-member")
-    #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-address-of-packed-member")
+	add_definitions(-D_GNU_SOURCE)
 endif ()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
-    add_definitions(-U__FreeBSD__)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wno-address-of-packed-member -Wno-unknown-warning-option")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-address-of-packed-member -Wno-unknown-warning-option")
+	add_definitions(-U__FreeBSD__)
+	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wno-address-of-packed-member")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-address-of-packed-member")
 endif ()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-    add_definitions(-U__APPLE__)
-    add_definitions(-D__APPLE_USE_RFC_2292)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wno-address-of-packed-member -Wno-deprecated-declarations")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-address-of-packed-member -Wno-deprecated-declarations")
+	add_definitions(-U__APPLE__)
+	add_definitions(-D__APPLE_USE_RFC_2292)
+	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wno-address-of-packed-member -Wno-deprecated-declarations")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-address-of-packed-member -Wno-deprecated-declarations")
 endif ()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "DragonFly")
-    add_definitions(-U__DragonFly__)
+	add_definitions(-U__DragonFly__)
 endif ()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
-    add_definitions(-U__NetBSD__)
+	add_definitions(-U__NetBSD__)
 endif ()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
-    add_definitions(-U__OpenBSD__)
+	add_definitions(-U__OpenBSD__)
 endif ()
 
 
@@ -89,92 +89,92 @@
 
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 
-list(APPEND usrsctp_root_HEADERS
-    user_atomic.h
-    user_environment.h
-    user_inpcb.h
-    user_ip_icmp.h
-    user_ip6_var.h
-    user_malloc.h
-    user_mbuf.h
-    user_queue.h
-    user_recv_thread.h
-    user_route.h
-    user_socketvar.h
-    user_uma.h
-    usrsctp.h
+list(APPEND usrsctp_root_headers
+	user_atomic.h
+	user_environment.h
+	user_inpcb.h
+	user_ip_icmp.h
+	user_ip6_var.h
+	user_malloc.h
+	user_mbuf.h
+	user_queue.h
+	user_recv_thread.h
+	user_route.h
+	user_socketvar.h
+	user_uma.h
+	usrsctp.h
 )
 
-list(APPEND usrsctp_netinet_HEADERS
-    netinet/sctp_asconf.h
-    netinet/sctp_auth.h
-    netinet/sctp_bsd_addr.h
-    netinet/sctp_callout.h
-    netinet/sctp_constants.h
-    netinet/sctp_crc32.h
-    netinet/sctp_header.h
-    netinet/sctp_indata.h
-    netinet/sctp_input.h
-    netinet/sctp_lock_userspace.h
-    netinet/sctp_os_userspace.h
-    netinet/sctp_os.h
-    netinet/sctp_output.h
-    netinet/sctp_pcb.h
-    netinet/sctp_peeloff.h
-    netinet/sctp_process_lock.h
-    netinet/sctp_sha1.h
-    netinet/sctp_structs.h
-    netinet/sctp_sysctl.h
-    netinet/sctp_timer.h
-    netinet/sctp_uio.h
-    netinet/sctp_var.h
-    netinet/sctputil.h
-    netinet/sctp.h
+list(APPEND usrsctp_netinet_headers
+	netinet/sctp_asconf.h
+	netinet/sctp_auth.h
+	netinet/sctp_bsd_addr.h
+	netinet/sctp_callout.h
+	netinet/sctp_constants.h
+	netinet/sctp_crc32.h
+	netinet/sctp_header.h
+	netinet/sctp_indata.h
+	netinet/sctp_input.h
+	netinet/sctp_lock_userspace.h
+	netinet/sctp_os_userspace.h
+	netinet/sctp_os.h
+	netinet/sctp_output.h
+	netinet/sctp_pcb.h
+	netinet/sctp_peeloff.h
+	netinet/sctp_process_lock.h
+	netinet/sctp_sha1.h
+	netinet/sctp_structs.h
+	netinet/sctp_sysctl.h
+	netinet/sctp_timer.h
+	netinet/sctp_uio.h
+	netinet/sctp_var.h
+	netinet/sctputil.h
+	netinet/sctp.h
 )
 
-list(APPEND usrsctp_netinet6_HEADERS
-    netinet6/sctp6_var.h
+list(APPEND usrsctp_netinet6_headers
+	netinet6/sctp6_var.h
 )
 
-list(APPEND usrsctp_HEADERS
-    ${usrsctp_root_HEADERS}
-    ${usrsctp_netinet_HEADERS}
-    ${usrsctp_netinet6_HEADERS}
+list(APPEND usrsctp_headers
+	${usrsctp_root_headers}
+	${usrsctp_netinet_headers}
+	${usrsctp_netinet6_headers}
 )
 
-list(APPEND usrsctp_SOURCES
-    netinet/sctp_asconf.c
-    netinet/sctp_auth.c
-    netinet/sctp_bsd_addr.c
-    netinet/sctp_callout.c
-    netinet/sctp_cc_functions.c
-    netinet/sctp_crc32.c
-    netinet/sctp_indata.c
-    netinet/sctp_input.c
-    netinet/sctp_output.c
-    netinet/sctp_pcb.c
-    netinet/sctp_peeloff.c
-    netinet/sctp_sha1.c
-    netinet/sctp_ss_functions.c
-    netinet/sctp_sysctl.c
-    netinet/sctp_timer.c
-    netinet/sctp_userspace.c
-    netinet/sctp_usrreq.c
-    netinet/sctputil.c
-    netinet6/sctp6_usrreq.c
-    user_environment.c
-    user_mbuf.c
-    user_recv_thread.c
-    user_socket.c
+list(APPEND usrsctp_sources
+	netinet/sctp_asconf.c
+	netinet/sctp_auth.c
+	netinet/sctp_bsd_addr.c
+	netinet/sctp_callout.c
+	netinet/sctp_cc_functions.c
+	netinet/sctp_crc32.c
+	netinet/sctp_indata.c
+	netinet/sctp_input.c
+	netinet/sctp_output.c
+	netinet/sctp_pcb.c
+	netinet/sctp_peeloff.c
+	netinet/sctp_sha1.c
+	netinet/sctp_ss_functions.c
+	netinet/sctp_sysctl.c
+	netinet/sctp_timer.c
+	netinet/sctp_userspace.c
+	netinet/sctp_usrreq.c
+	netinet/sctputil.c
+	netinet6/sctp6_usrreq.c
+	user_environment.c
+	user_mbuf.c
+	user_recv_thread.c
+	user_socket.c
 )
 
-add_library(usrsctp SHARED ${usrsctp_SOURCES} ${usrsctp_HEADERS})
-add_library(usrsctp-static STATIC ${usrsctp_SOURCES} ${usrsctp_HEADERS})
+add_library(usrsctp SHARED ${usrsctp_sources} ${usrsctp_headers})
+add_library(usrsctp-static STATIC ${usrsctp_sources} ${usrsctp_headers})
 
 if (WIN32)
-    message(STATUS "link library: ws2_32")
-    target_link_libraries(usrsctp ws2_32)
-    target_link_libraries(usrsctp-static ws2_32)
+	message(STATUS "link library: ws2_32")
+	target_link_libraries(usrsctp ws2_32)
+	target_link_libraries(usrsctp-static ws2_32)
 endif ()
 
 set_target_properties(usrsctp-static PROPERTIES OUTPUT_NAME "usrsctp")
@@ -182,7 +182,7 @@
 set_target_properties(usrsctp PROPERTIES SOVERSION 1 VERSION 1.0.0)
 
 if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
-    SET(CMAKE_INSTALL_LIBDIR lib)
+	SET(CMAKE_INSTALL_LIBDIR lib)
 endif ()
 
 
diff --git a/usrsctplib/netinet/sctp.h b/usrsctplib/netinet/sctp.h
index 0e38054..f5b1d82 100755
--- a/usrsctplib/netinet/sctp.h
+++ b/usrsctplib/netinet/sctp.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 297662 2016-04-07 09:10:34Z rrs $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 323657 2017-09-16 21:26:06Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_H_
@@ -569,7 +571,6 @@
 #define SCTP_PCB_FLAGS_INTERLEAVE_STRMS  0x0000000000000010
 #define SCTP_PCB_FLAGS_DO_ASCONF         0x0000000000000020
 #define SCTP_PCB_FLAGS_AUTO_ASCONF       0x0000000000000040
-#define SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE  0x0000000000000080
 /* socket options */
 #define SCTP_PCB_FLAGS_NODELAY           0x0000000000000100
 #define SCTP_PCB_FLAGS_AUTOCLOSE         0x0000000000000200
diff --git a/usrsctplib/netinet/sctp_asconf.c b/usrsctplib/netinet/sctp_asconf.c
index 0234810..704dfde 100755
--- a/usrsctplib/netinet/sctp_asconf.c
+++ b/usrsctplib/netinet/sctp_asconf.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 324056 2017-09-27 13:05:23Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -2341,39 +2343,6 @@
 	return (0);
 }
 
-void
-sctp_set_primary_ip_address(struct sctp_ifa *ifa)
-{
-	struct sctp_inpcb *inp;
-
-	/* go through all our PCB's */
-	LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) {
-		struct sctp_tcb *stcb;
-
-		/* process for all associations for this endpoint */
-		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
-			/* queue an ASCONF:SET_PRIM_ADDR to be sent */
-			if (!sctp_asconf_queue_add(stcb, ifa,
-						   SCTP_SET_PRIM_ADDR)) {
-				/* set primary queuing succeeded */
-				SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ",
-					(void *)stcb);
-				SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa);
-				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
-				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
-#ifdef SCTP_TIMER_BASED_ASCONF
-					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
-							 stcb->sctp_ep, stcb,
-							 stcb->asoc.primary_destination);
-#else
-					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
-#endif
-				}
-			}
-		} /* for each stcb */
-	} /* for each inp */
-}
-
 int
 sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa)
 {
diff --git a/usrsctplib/netinet/sctp_asconf.h b/usrsctplib/netinet/sctp_asconf.h
index 69accd2..28130f3 100755
--- a/usrsctplib/netinet/sctp_asconf.h
+++ b/usrsctplib/netinet/sctp_asconf.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.h 309607 2016-12-06 10:21:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.h 324056 2017-09-27 13:05:23Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_ASCONF_H_
@@ -73,9 +75,6 @@
     struct sockaddr *);
 
 extern void
-sctp_set_primary_ip_address(struct sctp_ifa *ifa);
-
-extern void
 sctp_check_address_list(struct sctp_tcb *, struct mbuf *, int, int,
     struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t);
 
diff --git a/usrsctplib/netinet/sctp_auth.c b/usrsctplib/netinet/sctp_auth.c
index d03ace5..e1163eb 100755
--- a/usrsctplib/netinet/sctp_auth.c
+++ b/usrsctplib/netinet/sctp_auth.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 324971 2017-10-25 09:12:22Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -1633,9 +1635,9 @@
 	/* now use the rest of the mbuf chain */
 	while ((m_tmp != NULL) && (size > 0)) {
 		data = mtod(m_tmp, uint8_t *) + m_offset;
-		if (size > (uint32_t) SCTP_BUF_LEN(m_tmp)) {
-			memset(data, 0, SCTP_BUF_LEN(m_tmp));
-			size -= SCTP_BUF_LEN(m_tmp);
+		if (size > (uint32_t)(SCTP_BUF_LEN(m_tmp) - m_offset)) {
+			memset(data, 0, SCTP_BUF_LEN(m_tmp) - m_offset);
+			size -= SCTP_BUF_LEN(m_tmp) - m_offset;
 		} else {
 			memset(data, 0, size);
 			size = 0;
diff --git a/usrsctplib/netinet/sctp_auth.h b/usrsctplib/netinet/sctp_auth.h
index b24f514..c1f82d8 100755
--- a/usrsctplib/netinet/sctp_auth.h
+++ b/usrsctplib/netinet/sctp_auth.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_bsd_addr.c b/usrsctplib/netinet/sctp_bsd_addr.c
index 805fdb8..e886e6c 100755
--- a/usrsctplib/netinet/sctp_bsd_addr.c
+++ b/usrsctplib/netinet/sctp_bsd_addr.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -824,10 +826,6 @@
 
 	if ((int)space_needed > (((mbuf_threshold - 1) * MLEN) + MHLEN)) {
 		MCLGET(m, how);
-		if (m == NULL) {
-			return (NULL);
-		}
-
 		if (SCTP_BUF_IS_EXTENDED(m) == 0) {
 			sctp_m_freem(m);
 			return (NULL);
diff --git a/usrsctplib/netinet/sctp_bsd_addr.h b/usrsctplib/netinet/sctp_bsd_addr.h
index e0483a4..a83c0ec 100755
--- a/usrsctplib/netinet/sctp_bsd_addr.h
+++ b/usrsctplib/netinet/sctp_bsd_addr.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_callout.c b/usrsctplib/netinet/sctp_callout.c
index c55f1b4..30bfa0d 100755
--- a/usrsctplib/netinet/sctp_callout.c
+++ b/usrsctplib/netinet/sctp_callout.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_callout.h b/usrsctplib/netinet/sctp_callout.h
index 4d764c9..765f966 100755
--- a/usrsctplib/netinet/sctp_callout.h
+++ b/usrsctplib/netinet/sctp_callout.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_cc_functions.c b/usrsctplib/netinet/sctp_cc_functions.c
index ace7464..e53e4d7 100755
--- a/usrsctplib/netinet/sctp_cc_functions.c
+++ b/usrsctplib/netinet/sctp_cc_functions.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_constants.h b/usrsctplib/netinet/sctp_constants.h
index 9afc9bd..525c958 100755
--- a/usrsctplib/netinet/sctp_constants.h
+++ b/usrsctplib/netinet/sctp_constants.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_constants.h 320263 2017-06-23 09:27:31Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_constants.h 324615 2017-10-14 10:02:59Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_CONSTANTS_H_
@@ -102,10 +104,6 @@
  */
 #define SCTP_DEFAULT_VRF_SIZE 4
 
-/* constants for rto calc */
-#define sctp_align_safe_nocopy 0
-#define sctp_align_unsafe_makecopy 1
-
 /* JRS - Values defined for the HTCP algorithm */
 #define ALPHA_BASE	(1<<7)  /* 1.0 with shift << 7 */
 #define BETA_MIN	(1<<6)  /* 0.5 with shift << 7 */
@@ -563,11 +561,9 @@
 #define SCTP_TIMER_TYPE_INPKILL         15
 #define SCTP_TIMER_TYPE_ASOCKILL        16
 #define SCTP_TIMER_TYPE_ADDR_WQ         17
-#define SCTP_TIMER_TYPE_ZERO_COPY       18
-#define SCTP_TIMER_TYPE_ZCOPY_SENDQ     19
-#define SCTP_TIMER_TYPE_PRIM_DELETED    20
+#define SCTP_TIMER_TYPE_PRIM_DELETED    18
 /* add new timers here - and increment LAST */
-#define SCTP_TIMER_TYPE_LAST            21
+#define SCTP_TIMER_TYPE_LAST            19
 
 #define SCTP_IS_TIMER_TYPE_VALID(t)	(((t) > SCTP_TIMER_TYPE_NONE) && \
 					 ((t) < SCTP_TIMER_TYPE_LAST))
@@ -996,9 +992,6 @@
 #define SCTP_SO_NOT_LOCKED	0
 
 
-#define SCTP_HOLDS_LOCK 1
-#define SCTP_NOT_LOCKED 0
-
 /*-
  * For address locks, do we hold the lock?
  */
diff --git a/usrsctplib/netinet/sctp_crc32.c b/usrsctplib/netinet/sctp_crc32.c
index 27536f1..16ce971 100755
--- a/usrsctplib/netinet/sctp_crc32.c
+++ b/usrsctplib/netinet/sctp_crc32.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_crc32.h b/usrsctplib/netinet/sctp_crc32.h
index 0b1cbbb..ee1161a 100755
--- a/usrsctplib/netinet/sctp_crc32.h
+++ b/usrsctplib/netinet/sctp_crc32.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_header.h b/usrsctplib/netinet/sctp_header.h
index 20031e9..6035d9c 100755
--- a/usrsctplib/netinet/sctp_header.h
+++ b/usrsctplib/netinet/sctp_header.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_indata.c b/usrsctplib/netinet/sctp_indata.c
index 211c05a..9a1dfcb 100755
--- a/usrsctplib/netinet/sctp_indata.c
+++ b/usrsctplib/netinet/sctp_indata.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 321463 2017-07-25 11:05:53Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 325434 2017-11-05 11:59:33Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -95,12 +97,14 @@
 		return (calc);
 	}
 
+	KASSERT(asoc->cnt_on_reasm_queue > 0 || asoc->size_on_reasm_queue == 0,
+	        ("size_on_reasm_queue is %u", asoc->size_on_reasm_queue));
+	KASSERT(asoc->cnt_on_all_streams > 0 || asoc->size_on_all_streams == 0,
+	        ("size_on_all_streams is %u", asoc->size_on_all_streams));
 	if (stcb->asoc.sb_cc == 0 &&
-	    asoc->size_on_reasm_queue == 0 &&
-	    asoc->size_on_all_streams == 0) {
+	    asoc->cnt_on_reasm_queue == 0 &&
+	    asoc->cnt_on_all_streams == 0) {
 		/* Full rwnd granted */
-		KASSERT(asoc->cnt_on_reasm_queue == 0, ("cnt_on_reasm_queue is %u", asoc->cnt_on_reasm_queue));
-		KASSERT(asoc->cnt_on_all_streams == 0, ("cnt_on_all_streams is %u", asoc->cnt_on_all_streams));
 		calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
 		return (calc);
 	}
@@ -1245,6 +1249,19 @@
 			}
 			done = (control->end_added) && (control->last_frag_seen);
 			if (control->on_read_q == 0) {
+				if (!done) {
+					if (asoc->size_on_all_streams >= control->length) {
+						asoc->size_on_all_streams -= control->length;
+					} else {
+#ifdef INVARIANTS
+						panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+						asoc->size_on_all_streams = 0;
+#endif
+					}
+					strm->pd_api_started = 1;
+					control->pdapi_started = 1;
+				}
 				sctp_add_to_readq(stcb->sctp_ep, stcb,
 						  control,
 						  &stcb->sctp_socket->so_rcv, control->end_added,
@@ -1254,10 +1271,6 @@
 			if (done) {
 				control = nctl;
 				goto deliver_more;
-			} else {
-				/* We are now doing PD API */
-				strm->pd_api_started = 1;
-				control->pdapi_started = 1;
 			}
 		}
 	}
@@ -1318,15 +1331,10 @@
 			} else if (control->on_strm_q == SCTP_ON_ORDERED) {
 				/* Ordered */
 				TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
-				if (asoc->size_on_all_streams >= control->length) {
-					asoc->size_on_all_streams -= control->length;
-				} else {
-#ifdef INVARIANTS
-					panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
-#else
-					asoc->size_on_all_streams = 0;
-#endif
-				}
+				/*
+				 * Don't need to decrement size_on_all_streams,
+				 * since control is on the read queue.
+				 */
 				sctp_ucount_decr(asoc->cnt_on_all_streams);
 				control->on_strm_q = 0;
 #ifdef INVARIANTS
@@ -1381,10 +1389,10 @@
 		}
 		if (sctp_place_control_in_stream(strm, asoc, control)) {
 			/* Duplicate SSN? */
-			sctp_clean_up_control(stcb, control);
 			sctp_abort_in_reasm(stcb, control, chk,
 					    abort_flag,
 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
+			sctp_clean_up_control(stcb, control);
 			return;
 		}
 		if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) {
@@ -1583,9 +1591,16 @@
 					next_fsn, control->fsn_included);
 				TAILQ_REMOVE(&control->reasm, at, sctp_next);
 				lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
-				asoc->size_on_all_streams += lenadded;
 				if (control->on_read_q) {
 					do_wakeup = 1;
+				} else {
+					/*
+					 * We only add to the size-on-all-streams
+					 * if its not on the read q. The read q
+					 * flag will cause a sballoc so its accounted
+					 * for there.
+					 */
+					asoc->size_on_all_streams += lenadded;
 				}
 				next_fsn++;
 				if (control->end_added && control->pdapi_started) {
@@ -1598,7 +1613,6 @@
 								  control,
 								  &stcb->sctp_socket->so_rcv, control->end_added,
 								  SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
-						do_wakeup = 1;
 					}
 					break;
 				}
@@ -2623,10 +2637,11 @@
 	struct sctp_association *asoc;
 	int num_chunks = 0;	/* number of control chunks processed */
 	int stop_proc = 0;
-	int chk_length, break_flag, last_chunk;
+	int break_flag, last_chunk;
 	int abort_flag = 0, was_a_gap;
 	struct mbuf *m;
 	uint32_t highest_tsn;
+	uint16_t chk_length;
 
 	/* set the rwnd */
 	sctp_set_rwnd(stcb, &stcb->asoc);
@@ -2679,7 +2694,8 @@
 #endif
 	/* get pointer to the first chunk header */
 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
-						     sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf);
+	                                           sizeof(struct sctp_chunkhdr),
+	                                           (uint8_t *)&chunk_buf);
 	if (ch == NULL) {
 		return (1);
 	}
@@ -2721,7 +2737,7 @@
 		}
 		if ((ch->chunk_type == SCTP_DATA) ||
 		    (ch->chunk_type == SCTP_IDATA)) {
-			int clen;
+			uint16_t clen;
 
 			if (ch->chunk_type == SCTP_DATA) {
 				clen = sizeof(struct sctp_data_chunk);
@@ -2736,7 +2752,8 @@
 				struct mbuf *op_err;
 				char msg[SCTP_DIAG_INFO_LEN];
 
-				snprintf(msg, sizeof(msg), "DATA chunk of length %d",
+				snprintf(msg, sizeof(msg), "%s chunk of length %u",
+				         ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA",
 				         chk_length);
 				op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20;
@@ -2811,7 +2828,25 @@
 				return (2);
 			}
 			default:
-				/* unknown chunk type, use bit rules */
+				/*
+				 * Unknown chunk type: use bit rules after
+				 * checking length
+				 */
+				if (chk_length < sizeof(struct sctp_chunkhdr)) {
+					/*
+					 * Need to send an abort since we had a
+					 * invalid chunk.
+					 */
+					struct mbuf *op_err;
+					char msg[SCTP_DIAG_INFO_LEN];
+
+					snprintf(msg, sizeof(msg), "Chunk of length %u",
+						 chk_length);
+					op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20;
+					sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+					return (2);
+				}
 				if (ch->chunk_type & 0x40) {
 					/* Add a error report to the queue */
 					struct mbuf *op_err;
@@ -2847,7 +2882,8 @@
 			continue;
 		}
 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
-							     sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf);
+		                                           sizeof(struct sctp_chunkhdr),
+		                                           (uint8_t *)&chunk_buf);
 		if (ch == NULL) {
 			*offset = length;
 			stop_proc = 1;
@@ -3039,7 +3075,6 @@
 												   &stcb->asoc,
 												   tp1->whoTo,
 												   &tp1->sent_rcv_time,
-												   sctp_align_safe_nocopy,
 												   SCTP_RTT_FROM_DATA);
 									*rto_ok = 0;
 								}
@@ -3998,7 +4033,6 @@
 									sctp_calculate_rto(stcb,
 											   asoc, tp1->whoTo,
 											   &tp1->sent_rcv_time,
-											   sctp_align_safe_nocopy,
 											   SCTP_RTT_FROM_DATA);
 								rto_ok = 0;
 							}
@@ -4204,7 +4238,6 @@
 again:
 	j = 0;
 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
-		int to_ticks;
 		if (win_probe_recovery && (net->window_probe)) {
 			win_probe_recovered = 1;
 			/*
@@ -4220,15 +4253,9 @@
 				}
 			}
 		}
-		if (net->RTO == 0) {
-			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
-		} else {
-			to_ticks = MSEC_TO_TICKS(net->RTO);
-		}
 		if (net->flight_size) {
 			j++;
-			(void)SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks,
-						  sctp_timeout_handler, &net->rxt_timer);
+			sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net);
 			if (net->window_probe) {
 				net->window_probe = 0;
 			}
@@ -4237,8 +4264,7 @@
 				/* In window probes we must assure a timer is still running there */
 				net->window_probe = 0;
 				if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
-					SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks,
-					                    sctp_timeout_handler, &net->rxt_timer);
+					sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net);
 				}
 			} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
@@ -4633,7 +4659,6 @@
 									sctp_calculate_rto(stcb,
 											   asoc, tp1->whoTo,
 											   &tp1->sent_rcv_time,
-											   sctp_align_safe_nocopy,
 											   SCTP_RTT_FROM_DATA);
 								rto_ok = 0;
 							}
diff --git a/usrsctplib/netinet/sctp_indata.h b/usrsctplib/netinet/sctp_indata.h
index 625dd62..bdba114 100755
--- a/usrsctplib/netinet/sctp_indata.h
+++ b/usrsctplib/netinet/sctp_indata.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c
index 0649ec2..d2ceb75 100755
--- a/usrsctplib/netinet/sctp_input.c
+++ b/usrsctplib/netinet/sctp_input.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 320653 2017-07-04 18:24:50Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 325864 2017-11-15 22:13:10Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -224,8 +226,7 @@
 #if defined(__FreeBSD__)
 		                       mflowtype, mflowid,
 #endif
-		                       vrf_id, port,
-		                       ((stcb == NULL) ? SCTP_HOLDS_LOCK : SCTP_NOT_LOCKED));
+		                       vrf_id, port);
 	}
  outnow:
 	if (stcb == NULL) {
@@ -549,8 +550,8 @@
 	    asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
 
 	/* calculate the RTO */
-	net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, sctp_align_safe_nocopy,
-				      SCTP_RTT_FROM_NON_DATA);
+	net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered,
+	                              SCTP_RTT_FROM_NON_DATA);
 #if defined(__Userspace__)
 	if (stcb->sctp_ep->recv_callback) {
 		if (stcb->sctp_socket) {
@@ -711,14 +712,22 @@
 		                r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_4);
 		sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net);
 	}
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
+		sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+			       stcb->asoc.overall_error_count,
+			       0,
+			       SCTP_FROM_SCTP_INPUT,
+			       __LINE__);
+	}
+	stcb->asoc.overall_error_count = 0;
 	old_error_counter = r_net->error_count;
 	r_net->error_count = 0;
 	r_net->hb_responded = 1;
 	tv.tv_sec = cp->heartbeat.hb_info.time_value_1;
 	tv.tv_usec = cp->heartbeat.hb_info.time_value_2;
 	/* Now lets do a RTO with this */
-	r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy,
-					SCTP_RTT_FROM_NON_DATA);
+	r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv,
+	                                SCTP_RTT_FROM_NON_DATA);
 	if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) {
 		r_net->dest_state |= SCTP_ADDR_REACHABLE;
 		sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
@@ -776,6 +785,14 @@
 	*/
 	struct sctpasochead *head;
 
+	if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) ||
+	    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+		atomic_add_int(&stcb->asoc.refcnt, 1);
+		SCTP_TCB_UNLOCK(stcb);
+		SCTP_INP_INFO_WLOCK();
+		SCTP_TCB_LOCK(stcb);
+		atomic_subtract_int(&stcb->asoc.refcnt, 1);
+	}
 	if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
 		/* generate a new vtag and send init */
 		LIST_REMOVE(stcb, sctp_asocs);
@@ -784,6 +801,7 @@
 		/* put it in the bucket in the vtag hash of assoc's for the system */
 		LIST_INSERT_HEAD(head, stcb, sctp_asocs);
 		sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
+		SCTP_INP_INFO_WUNLOCK();
 		return (1);
 	}
 	if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
@@ -803,6 +821,7 @@
 		/* put it in the bucket in the vtag hash of assoc's for the system */
 		LIST_INSERT_HEAD(head, stcb, sctp_asocs);
 		sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
+		SCTP_INP_INFO_WUNLOCK();
 		return (1);
 	}
 	return (0);
@@ -824,7 +843,8 @@
 }
 
 
-static void
+/* Returns 1 if the stcb was aborted, 0 otherwise */
+static int
 sctp_handle_abort(struct sctp_abort_chunk *abort,
     struct sctp_tcb *stcb, struct sctp_nets *net)
 {
@@ -836,29 +856,29 @@
 
 	SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: handling ABORT\n");
 	if (stcb == NULL)
-		return;
+		return (0);
 
 	len = ntohs(abort->ch.chunk_length);
-	if (len > sizeof (struct sctp_chunkhdr)) {
+	if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause)) {
 		/* Need to check the cause codes for our
 		 * two magic nat aborts which don't kill the assoc
 		 * necessarily.
 		 */
-		struct sctp_gen_error_cause *cause;
+		struct sctp_error_cause *cause;
 
-		cause = (struct sctp_gen_error_cause *)(abort + 1);
+		cause = (struct sctp_error_cause *)(abort + 1);
 		error = ntohs(cause->code);
 		if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) {
 			SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
 			                           abort->ch.chunk_flags);
 			if (sctp_handle_nat_colliding_state(stcb)) {
-				return;
+				return (0);
 			}
 		} else if (error == SCTP_CAUSE_NAT_MISSING_STATE) {
 			SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n",
 			                           abort->ch.chunk_flags);
 			if (sctp_handle_nat_missing_state(stcb, net)) {
-				return;
+				return (0);
 			}
 		}
 	} else {
@@ -893,6 +913,7 @@
 	SCTP_SOCKET_UNLOCK(so, 1);
 #endif
 	SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n");
+	return (1);
 }
 
 static void
@@ -1148,19 +1169,11 @@
 #endif
 }
 
-/*
- * Skip past the param header and then we will find the chunk that caused the
- * problem. There are two possibilities ASCONF or FWD-TSN other than that and
- * our peer must be broken.
- */
 static void
-sctp_process_unrecog_chunk(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr,
+sctp_process_unrecog_chunk(struct sctp_tcb *stcb, uint8_t chunk_type,
     struct sctp_nets *net)
 {
-	struct sctp_chunkhdr *chk;
-
-	chk = (struct sctp_chunkhdr *)((caddr_t)phdr + sizeof(*phdr));
-	switch (chk->chunk_type) {
+	switch (chunk_type) {
 	case SCTP_ASCONF_ACK:
 	case SCTP_ASCONF:
 		sctp_asconf_cleanup(stcb, net);
@@ -1171,8 +1184,8 @@
 		break;
 	default:
 		SCTPDBG(SCTP_DEBUG_INPUT2,
-			"Peer does not support chunk type %d(%x)??\n",
-			chk->chunk_type, (uint32_t) chk->chunk_type);
+			"Peer does not support chunk type %d (0x%x).\n",
+			chunk_type, chunk_type);
 		break;
 	}
 }
@@ -1184,12 +1197,9 @@
  * XXX: Is this the right thing to do?
  */
 static void
-sctp_process_unrecog_param(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr)
+sctp_process_unrecog_param(struct sctp_tcb *stcb, uint16_t parameter_type)
 {
-	struct sctp_paramhdr *pbad;
-
-	pbad = phdr + 1;
-	switch (ntohs(pbad->param_type)) {
+	switch (parameter_type) {
 		/* pr-sctp draft */
 	case SCTP_PRSCTP_SUPPORTED:
 		stcb->asoc.prsctp_supported = 0;
@@ -1214,66 +1224,72 @@
 		break;
 	default:
 		SCTPDBG(SCTP_DEBUG_INPUT2,
-			"Peer does not support param type %d(%x)??\n",
-			pbad->param_type, (uint32_t) pbad->param_type);
+			"Peer does not support param type %d (0x%x)??\n",
+			parameter_type, parameter_type);
 		break;
 	}
 }
 
 static int
 sctp_handle_error(struct sctp_chunkhdr *ch,
-    struct sctp_tcb *stcb, struct sctp_nets *net)
+                  struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t limit)
 {
-	int chklen;
-	struct sctp_paramhdr *phdr;
-	uint16_t error, error_type;
-	uint16_t error_len;
+	struct sctp_error_cause *cause;
 	struct sctp_association *asoc;
-	int adjust;
+	uint32_t remaining_length, adjust;
+	uint16_t code, cause_code, cause_length;
 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
 	struct socket *so;
 #endif
 
 	/* parse through all of the errors and process */
 	asoc = &stcb->asoc;
-	phdr = (struct sctp_paramhdr *)((caddr_t)ch +
+	cause = (struct sctp_error_cause *)((caddr_t)ch +
 	    sizeof(struct sctp_chunkhdr));
-	chklen = ntohs(ch->chunk_length) - sizeof(struct sctp_chunkhdr);
-	error = 0;
-	while ((size_t)chklen >= sizeof(struct sctp_paramhdr)) {
+	remaining_length = ntohs(ch->chunk_length);
+	if (remaining_length > limit) {
+		remaining_length = limit;
+	}
+	if (remaining_length >= sizeof(struct sctp_chunkhdr)) {
+		remaining_length -= sizeof(struct sctp_chunkhdr);
+	} else {
+		remaining_length = 0;
+	}
+	code = 0;
+	while (remaining_length >= sizeof(struct sctp_error_cause)) {
 		/* Process an Error Cause */
-		error_type = ntohs(phdr->param_type);
-		error_len = ntohs(phdr->param_length);
-		if ((error_len > chklen) || (error_len == 0)) {
-			/* invalid param length for this param */
-			SCTPDBG(SCTP_DEBUG_INPUT1, "Bogus length in error param- chunk left:%d errorlen:%d\n",
-				chklen, error_len);
+		cause_code = ntohs(cause->code);
+		cause_length = ntohs(cause->length);
+		if ((cause_length > remaining_length) || (cause_length == 0)) {
+			/* Invalid cause length, possibly due to truncation. */
+			SCTPDBG(SCTP_DEBUG_INPUT1, "Bogus length in cause - bytes left: %u cause length: %u\n",
+				remaining_length, cause_length);
 			return (0);
 		}
-		if (error == 0) {
+		if (code == 0) {
 			/* report the first error cause */
-			error = error_type;
+			code = cause_code;
 		}
-		switch (error_type) {
+		switch (cause_code) {
 		case SCTP_CAUSE_INVALID_STREAM:
 		case SCTP_CAUSE_MISSING_PARAM:
 		case SCTP_CAUSE_INVALID_PARAM:
 		case SCTP_CAUSE_NO_USER_DATA:
-			SCTPDBG(SCTP_DEBUG_INPUT1, "Software error we got a %d back? We have a bug :/ (or do they?)\n",
-				error_type);
+			SCTPDBG(SCTP_DEBUG_INPUT1, "Software error we got a %u back? We have a bug :/ (or do they?)\n",
+				cause_code);
 			break;
 		case SCTP_CAUSE_NAT_COLLIDING_STATE:
-		        SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
+		        SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags: %x\n",
 				ch->chunk_flags);
 			if (sctp_handle_nat_colliding_state(stcb)) {
-			  return (0);
+				return (0);
 			}
 			break;
 		case SCTP_CAUSE_NAT_MISSING_STATE:
-			SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n",
+			SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags: %x\n",
 			                           ch->chunk_flags);
 			if (sctp_handle_nat_missing_state(stcb, net)) {
-			  return (0);
+				return (0);
 			}
 			break;
 		case SCTP_CAUSE_STALE_COOKIE:
@@ -1281,12 +1297,18 @@
 			 * We only act if we have echoed a cookie and are
 			 * waiting.
 			 */
-			if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) {
-				int *p;
+			if ((cause_length >= sizeof(struct sctp_error_stale_cookie)) &&
+			    (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+				struct sctp_error_stale_cookie *stale_cookie;
 
-				p = (int *)((caddr_t)phdr + sizeof(*phdr));
-				/* Save the time doubled */
-				asoc->cookie_preserve_req = ntohl(*p) << 1;
+				stale_cookie = (struct sctp_error_stale_cookie *)cause;
+				asoc->cookie_preserve_req = ntohl(stale_cookie->stale_time);
+				/* Double it to be more robust on RTX */
+				if (asoc->cookie_preserve_req <= UINT32_MAX / 2) {
+					asoc->cookie_preserve_req *= 2;
+				} else {
+					asoc->cookie_preserve_req = UINT32_MAX;
+				}
 				asoc->stale_cookie_count++;
 				if (asoc->stale_cookie_count >
 				    asoc->max_init_times) {
@@ -1329,10 +1351,21 @@
 			 */
 			break;
 		case SCTP_CAUSE_UNRECOG_CHUNK:
-			sctp_process_unrecog_chunk(stcb, phdr, net);
+			if (cause_length >= sizeof(struct sctp_error_unrecognized_chunk)) {
+				struct sctp_error_unrecognized_chunk *unrec_chunk;
+
+				unrec_chunk = (struct sctp_error_unrecognized_chunk *)cause;
+				sctp_process_unrecog_chunk(stcb, unrec_chunk->ch.chunk_type, net);
+			}
 			break;
 		case SCTP_CAUSE_UNRECOG_PARAM:
-			sctp_process_unrecog_param(stcb, phdr);
+			/* XXX: We only consider the first parameter */
+			if (cause_length >= sizeof(struct sctp_error_cause) + sizeof(struct sctp_paramhdr)) {
+				struct sctp_paramhdr *unrec_parameter;
+
+				unrec_parameter = (struct sctp_paramhdr *)(cause + 1);
+				sctp_process_unrecog_param(stcb, ntohs(unrec_parameter->param_type));
+			}
 			break;
 		case SCTP_CAUSE_COOKIE_IN_SHUTDOWN:
 			/*
@@ -1349,8 +1382,8 @@
 			 * We should NOT get these here, but in a
 			 * ASCONF-ACK.
 			 */
-			SCTPDBG(SCTP_DEBUG_INPUT2, "Peer sends ASCONF errors in a Operational Error?<%d>?\n",
-				error_type);
+			SCTPDBG(SCTP_DEBUG_INPUT2, "Peer sends ASCONF errors in a error cause with code %u.\n",
+				cause_code);
 			break;
 		case SCTP_CAUSE_OUT_OF_RESC:
 			/*
@@ -1362,15 +1395,19 @@
 			 */
 			break;
 		default:
-			SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_handle_error: unknown error type = 0x%xh\n",
-				error_type);
+			SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_handle_error: unknown code 0x%x\n",
+				cause_code);
 			break;
 		}
-		adjust = SCTP_SIZE32(error_len);
-		chklen -= adjust;
-		phdr = (struct sctp_paramhdr *)((caddr_t)phdr + adjust);
+		adjust = SCTP_SIZE32(cause_length);
+		if (remaining_length >= adjust) {
+			remaining_length -= adjust;
+		} else {
+			remaining_length = 0;
+		}
+		cause = (struct sctp_error_cause *)((caddr_t)cause + adjust);
 	}
-	sctp_ulp_notify(SCTP_NOTIFY_REMOTE_ERROR, stcb, error, ch, SCTP_SO_NOT_LOCKED);
+	sctp_ulp_notify(SCTP_NOTIFY_REMOTE_ERROR, stcb, code, ch, SCTP_SO_NOT_LOCKED);
 	return (0);
 }
 
@@ -1565,6 +1602,7 @@
 	struct sctp_init_ack_chunk *initack_cp, initack_buf;
 	struct sctp_nets *net;
 	struct mbuf *op_err;
+	struct timeval old;
 	int init_offset, initack_offset, i;
 	int retval;
 	int spec_flag = 0;
@@ -1727,11 +1765,12 @@
 				 * since we did not send a HB make sure we
 				 * don't double things
 				 */
+				old.tv_sec = cookie->time_entered.tv_sec;
+				old.tv_usec = cookie->time_entered.tv_usec;
 				net->hb_responded = 1;
 				net->RTO = sctp_calculate_rto(stcb, asoc, net,
-							      &cookie->time_entered,
-							      sctp_align_unsafe_makecopy,
-							      SCTP_RTT_FROM_NON_DATA);
+				                              &old,
+				                              SCTP_RTT_FROM_NON_DATA);
 
 				if (stcb->asoc.sctp_autoclose_ticks &&
 				    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))) {
@@ -2480,10 +2519,13 @@
 	}
 	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
 	if ((netp != NULL) && (*netp != NULL)) {
+		struct timeval old;
+
 		/* calculate the RTT and set the encaps port */
+		old.tv_sec = cookie->time_entered.tv_sec;
+		old.tv_usec = cookie->time_entered.tv_usec;
 		(*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp,
-						  &cookie->time_entered, sctp_align_unsafe_makecopy,
-						  SCTP_RTT_FROM_NON_DATA);
+		                                  &old, SCTP_RTT_FROM_NON_DATA);
 	}
 	/* respond with a COOKIE-ACK */
 	sctp_send_cookie_ack(stcb);
@@ -2681,9 +2723,6 @@
 	/* Expire time is in Ticks, so we convert to seconds */
 	time_expires.tv_sec = cookie->time_entered.tv_sec + TICKS_TO_SEC(cookie->cookie_life);
 	time_expires.tv_usec = cookie->time_entered.tv_usec;
-        /* TODO sctp_constants.h needs alternative time macros when
-         *  _KERNEL is undefined.
-         */
 #ifndef __FreeBSD__
 	if (timercmp(&now, &time_expires, >))
 #else
@@ -2693,9 +2732,11 @@
 		/* cookie is stale! */
 		struct mbuf *op_err;
 		struct sctp_error_stale_cookie *cause;
-		uint32_t tim;
+		struct timeval diff;
+		uint32_t staleness;
+
 		op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_stale_cookie),
-					       0, M_NOWAIT, 1, MT_DATA);
+		                               0, M_NOWAIT, 1, MT_DATA);
 		if (op_err == NULL) {
 			/* FOOBAR */
 			return (NULL);
@@ -2706,12 +2747,23 @@
 		cause->cause.code = htons(SCTP_CAUSE_STALE_COOKIE);
 		cause->cause.length = htons((sizeof(struct sctp_paramhdr) +
 		    (sizeof(uint32_t))));
-		/* seconds to usec */
-		tim = (now.tv_sec - time_expires.tv_sec) * 1000000;
-		/* add in usec */
-		if (tim == 0)
-			tim = now.tv_usec - cookie->time_entered.tv_usec;
-		cause->stale_time = htonl(tim);
+#ifndef __FreeBSD__
+		timersub(&now, &time_expires, &diff);
+#else
+		diff = now;
+		timevalsub(&diff, &time_expires);
+#endif
+		if (diff.tv_sec > UINT32_MAX / 1000000) {
+			staleness = UINT32_MAX;
+		} else {
+			staleness = diff.tv_sec * 1000000;
+		}
+		if (UINT32_MAX - staleness >= (uint32_t)diff.tv_usec) {
+			staleness += diff.tv_usec;
+		} else {
+			staleness = UINT32_MAX;
+		}
+		cause->stale_time = htonl(staleness);
 		sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err,
 #if defined(__FreeBSD__)
 		                   mflowtype, mflowid, l_inp->fibnum,
@@ -3092,7 +3144,14 @@
 	}
 
 	asoc = &stcb->asoc;
-
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
+		sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+			       asoc->overall_error_count,
+			       0,
+			       SCTP_FROM_SCTP_INPUT,
+			       __LINE__);
+	}
+	asoc->overall_error_count = 0;
 	sctp_stop_all_cookie_timers(stcb);
 	/* process according to association state */
 	if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) {
@@ -3110,8 +3169,8 @@
 		SCTP_STAT_INCR_GAUGE32(sctps_currestab);
 		if (asoc->overall_error_count == 0) {
 			net->RTO = sctp_calculate_rto(stcb, asoc, net,
-					             &asoc->time_entered, sctp_align_safe_nocopy,
-						      SCTP_RTT_FROM_NON_DATA);
+			                              &asoc->time_entered,
+			                              SCTP_RTT_FROM_NON_DATA);
 		}
 		(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
 		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_UP, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
@@ -3316,14 +3375,14 @@
 	 * make sure that we have a covered ECNE in the control chunk part.
 	 * If so remove it.
 	 */
-	struct sctp_tmit_chunk *chk;
+	struct sctp_tmit_chunk *chk, *nchk;
 	struct sctp_ecne_chunk *ecne;
 	int override;
 	uint32_t cwr_tsn;
 
 	cwr_tsn = ntohl(cp->tsn);
 	override = cp->ch.chunk_flags & SCTP_CWR_REDUCE_OVERRIDE;
-	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
+	TAILQ_FOREACH_SAFE(chk, &stcb->asoc.control_send_queue, sctp_next, nchk) {
 		if (chk->rec.chunk_id.id != SCTP_ECN_ECHO) {
 			continue;
 		}
@@ -4673,7 +4732,7 @@
 	char msg[SCTP_DIAG_INFO_LEN];
 	uint32_t vtag_in;
 	int num_chunks = 0;	/* number of control chunks processed */
-	uint32_t chk_length;
+	uint32_t chk_length, contiguous;
 	int ret;
 	int abort_no_unlock = 0;
 	int ecne_seen = 0;
@@ -4683,7 +4742,6 @@
 	 * until we get into jumbo grams and such..
 	 */
 	uint8_t chunk_buf[SCTP_CHUNK_BUFFER_SIZE];
-	struct sctp_tcb *locked_tcb = stcb;
 	int got_auth = 0;
 	uint32_t auth_offset = 0, auth_len = 0;
 	int auth_skipped = 0;
@@ -4695,31 +4753,29 @@
 	SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_control: iphlen=%u, offset=%u, length=%u stcb:%p\n",
 		iphlen, *offset, length, (void *)stcb);
 
+	if (stcb) {
+		SCTP_TCB_LOCK_ASSERT(stcb);
+	}
 	/* validate chunk header length... */
 	if (ntohs(ch->chunk_length) < sizeof(*ch)) {
 		SCTPDBG(SCTP_DEBUG_INPUT1, "Invalid header length %d\n",
 			ntohs(ch->chunk_length));
-		if (locked_tcb) {
-			SCTP_TCB_UNLOCK(locked_tcb);
-		}
-		return (NULL);
+		*offset = length;
+		return (stcb);
 	}
 	/*
 	 * validate the verification tag
 	 */
 	vtag_in = ntohl(sh->v_tag);
 
-	if (locked_tcb) {
-		SCTP_TCB_LOCK_ASSERT(locked_tcb);
-	}
 	if (ch->chunk_type == SCTP_INITIATION) {
 		SCTPDBG(SCTP_DEBUG_INPUT1, "Its an INIT of len:%d vtag:%x\n",
 			ntohs(ch->chunk_length), vtag_in);
 		if (vtag_in != 0) {
 			/* protocol error- silently discard... */
 			SCTP_STAT_INCR(sctps_badvtag);
-			if (locked_tcb) {
-				SCTP_TCB_UNLOCK(locked_tcb);
+			if (stcb != NULL) {
+				SCTP_TCB_UNLOCK(stcb);
 			}
 			return (NULL);
 		}
@@ -4742,9 +4798,6 @@
 			if (*offset >= length) {
 				/* no more data left in the mbuf chain */
 				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				return (NULL);
 			}
 			ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
@@ -4753,10 +4806,7 @@
 		if (ch == NULL) {
 			/* Help */
 			*offset = length;
-			if (locked_tcb) {
-				SCTP_TCB_UNLOCK(locked_tcb);
-			}
-			return (NULL);
+			return (stcb);
 		}
 		if (ch->chunk_type == SCTP_COOKIE_ECHO) {
 			goto process_control_chunks;
@@ -4793,8 +4843,6 @@
 				 * sctp_findassociation_ep_asconf().
 				 */
 				SCTP_INP_DECR_REF(inp);
-			} else {
-				locked_tcb = stcb;
 			}
 
 			/* now go back and verify any auth chunk to be sure */
@@ -4810,10 +4858,7 @@
 								       auth_offset)) {
 					/* auth HMAC failed so dump it */
 					*offset = length;
-					if (locked_tcb) {
-						SCTP_TCB_UNLOCK(locked_tcb);
-					}
-					return (NULL);
+					return (stcb);
 				} else {
 					/* remaining chunks are HMAC checked */
 					stcb->asoc.authenticated = 1;
@@ -4831,9 +4876,6 @@
 #endif
 					 vrf_id, port);
 			*offset = length;
-			if (locked_tcb) {
-				SCTP_TCB_UNLOCK(locked_tcb);
-			}
 			return (NULL);
 		}
 		asoc = &stcb->asoc;
@@ -4845,13 +4887,14 @@
 			if ((((ch->chunk_flags & SCTP_HAD_NO_TCB) == 0) &&
 			     (vtag_in == asoc->my_vtag)) ||
 			    (((ch->chunk_flags & SCTP_HAD_NO_TCB) == SCTP_HAD_NO_TCB) &&
+			     (asoc->peer_vtag != htonl(0)) &&
 			     (vtag_in == asoc->peer_vtag))) {
 				/* this is valid */
 			} else {
 				/* drop this packet... */
 				SCTP_STAT_INCR(sctps_badvtag);
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
+				if (stcb != NULL) {
+					SCTP_TCB_UNLOCK(stcb);
 				}
 				return (NULL);
 			}
@@ -4864,8 +4907,8 @@
 				 * but it won't complete until the shutdown
 				 * is completed
 				 */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
+				if (stcb != NULL) {
+					SCTP_TCB_UNLOCK(stcb);
 				}
 				snprintf(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
 				op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
@@ -4886,8 +4929,8 @@
 					"invalid vtag: %xh, expect %xh\n",
 					vtag_in, asoc->my_vtag);
 				SCTP_STAT_INCR(sctps_badvtag);
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
+				if (stcb != NULL) {
+					SCTP_TCB_UNLOCK(stcb);
 				}
 				*offset = length;
 				return (NULL);
@@ -4902,14 +4945,6 @@
 	     (ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) &&
 	    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
 		/* implied cookie-ack.. we must have lost the ack */
-		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-			sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-				       stcb->asoc.overall_error_count,
-				       0,
-				       SCTP_FROM_SCTP_INPUT,
-				       __LINE__);
-		}
-		stcb->asoc.overall_error_count = 0;
 		sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb,
 				       *netp);
 	}
@@ -4924,66 +4959,36 @@
 		if (chk_length < sizeof(*ch) ||
 		    (*offset + (int)chk_length) > length) {
 			*offset = length;
-			if (locked_tcb) {
-				SCTP_TCB_UNLOCK(locked_tcb);
-			}
-			return (NULL);
+			return (stcb);
 		}
 		SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks);
 		/*
-		 * INIT-ACK only gets the init ack "header" portion only
-		 * because we don't have to process the peer's COOKIE. All
-		 * others get a complete chunk.
+		 * INIT and INIT-ACK only gets the init ack "header" portion
+		 * only because we don't have to process the peer's COOKIE.
+		 * All others get a complete chunk.
 		 */
-		if ((ch->chunk_type == SCTP_INITIATION_ACK) ||
-		    (ch->chunk_type == SCTP_INITIATION)) {
-			/* get an init-ack chunk */
-			ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
-								   sizeof(struct sctp_init_ack_chunk), chunk_buf);
-			if (ch == NULL) {
-				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
-				return (NULL);
-			}
-		} else {
-			/* For cookies and all other chunks. */
-			if (chk_length > sizeof(chunk_buf)) {
-				/*
-				 * use just the size of the chunk buffer
-				 * so the front part of our chunks fit in
-				 * contiguous space up to the chunk buffer
-				 * size (508 bytes).
-				 * For chunks that need to get more than that
-				 * they must use the sctp_m_getptr() function
-				 * or other means (e.g. know how to parse mbuf
-				 * chains). Cookies do this already.
-				 */
-				ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
-									   (sizeof(chunk_buf) - 4),
-									   chunk_buf);
-				if (ch == NULL) {
-					*offset = length;
-					if (locked_tcb) {
-						SCTP_TCB_UNLOCK(locked_tcb);
-					}
-					return (NULL);
-				}
-			} else {
-				/* We can fit it all */
-				ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
-								   chk_length, chunk_buf);
-				if (ch == NULL) {
-					SCTP_PRINTF("sctp_process_control: Can't get the all data....\n");
-					*offset = length;
-					if (locked_tcb) {
-						SCTP_TCB_UNLOCK(locked_tcb);
-					}
-					return (NULL);
-				}
-			}
+		switch (ch->chunk_type) {
+		case SCTP_INITIATION:
+			contiguous = sizeof(struct sctp_init_chunk);
+			break;
+		case SCTP_INITIATION_ACK:
+			contiguous = sizeof(struct sctp_init_ack_chunk);
+			break;
+		default:
+			contiguous = min(chk_length, sizeof(chunk_buf));
+			break;
 		}
+		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
+		                                           contiguous,
+		                                           chunk_buf);
+		if (ch == NULL) {
+			*offset = length;
+			if (stcb != NULL) {
+				SCTP_TCB_UNLOCK(stcb);
+			}
+			return (NULL);
+		}
+
 		num_chunks++;
 		/* Save off the last place we got a control from */
 		if (stcb != NULL) {
@@ -5018,8 +5023,8 @@
 			    (length - *offset > (int)SCTP_SIZE32(chk_length))) {
 				/* RFC 4960 requires that no ABORT is sent */
 				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
+				if (stcb != NULL) {
+					SCTP_TCB_UNLOCK(stcb);
 				}
 				return (NULL);
 			}
@@ -5043,26 +5048,22 @@
 #endif
 			                 vrf_id, port);
 			*offset = length;
-			if ((!abort_no_unlock) && (locked_tcb)) {
-				SCTP_TCB_UNLOCK(locked_tcb);
+			if ((!abort_no_unlock) && (stcb != NULL)) {
+				SCTP_TCB_UNLOCK(stcb);
 			}
 			return (NULL);
 			break;
 		case SCTP_PAD_CHUNK:
 			break;
 		case SCTP_INITIATION_ACK:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_INIT-ACK\n");
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_INIT_ACK\n");
 			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
 				/* We are not interested anymore */
-				if ((stcb) && (stcb->asoc.total_output_queue_size)) {
+				if ((stcb != NULL) && (stcb->asoc.total_output_queue_size)) {
 					;
 				} else {
-					if ((locked_tcb != NULL) && (locked_tcb != stcb)) {
-						/* Very unlikely */
-						SCTP_TCB_UNLOCK(locked_tcb);
-					}
 					*offset = length;
-					if (stcb) {
+					if (stcb != NULL) {
 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
 						so = SCTP_INP_SO(inp);
 						atomic_add_int(&stcb->asoc.refcnt, 1);
@@ -5084,12 +5085,9 @@
 			if ((num_chunks > 1) ||
 			    (length - *offset > (int)SCTP_SIZE32(chk_length))) {
 				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
-				return (NULL);
+				return (stcb);
 			}
-			if ((netp) && (*netp)) {
+			if ((netp != NULL) && (*netp != NULL)) {
 				ret = sctp_handle_init_ack(m, iphlen, *offset,
 				                           src, dst, sh,
 				                           (struct sctp_init_ack_chunk *)ch,
@@ -5113,44 +5111,57 @@
 			if ((stcb != NULL) && (ret == 0)) {
 				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
 			}
-			if (locked_tcb) {
-				SCTP_TCB_UNLOCK(locked_tcb);
-			}
-			return (NULL);
+			return (stcb);
 			break;
 		case SCTP_SELECTIVE_ACK:
-			{
-				struct sctp_sack_chunk *sack;
-				int abort_now = 0;
-				uint32_t a_rwnd, cum_ack;
-				uint16_t num_seg, num_dup;
-				uint8_t flags;
-				int offset_seg, offset_dup;
+		case SCTP_NR_SELECTIVE_ACK:
+		{
+			int abort_now = 0;
+			uint32_t a_rwnd, cum_ack;
+			uint16_t num_seg, num_nr_seg, num_dup;
+			uint8_t flags;
+			int offset_seg, offset_dup;
 
-				SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SACK\n");
-				SCTP_STAT_INCR(sctps_recvsacks);
-				if (stcb == NULL) {
-					SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing SACK chunk\n");
-					break;
-				}
+			SCTPDBG(SCTP_DEBUG_INPUT3, "%s\n",
+				ch->chunk_type == SCTP_SELECTIVE_ACK ? "SCTP_SACK" : "SCTP_NR_SACK");
+			SCTP_STAT_INCR(sctps_recvsacks);
+			if (stcb == NULL) {
+				SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing %s chunk\n",
+				        (ch->chunk_type == SCTP_SELECTIVE_ACK) ? "SCTP_SACK" : "SCTP_NR_SACK");
+				break;
+			}
+			if (ch->chunk_type == SCTP_SELECTIVE_ACK) {
 				if (chk_length < sizeof(struct sctp_sack_chunk)) {
 					SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on SACK chunk, too small\n");
 					break;
 				}
-				if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
-					/*-
-					 * If we have sent a shutdown-ack, we will pay no
-					 * attention to a sack sent in to us since
-					 * we don't care anymore.
-					 */
+			} else {
+				if (stcb->asoc.nrsack_supported == 0) {
+					goto unknown_chunk;
+				}
+				if (chk_length < sizeof(struct sctp_nr_sack_chunk)) {
+					SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on NR_SACK chunk, too small\n");
 					break;
 				}
+			}
+			if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
+				/*-
+				 * If we have sent a shutdown-ack, we will pay no
+				 * attention to a sack sent in to us since
+				 * we don't care anymore.
+				 */
+				break;
+			}
+			flags = ch->chunk_flags;
+			if (ch->chunk_type == SCTP_SELECTIVE_ACK) {
+				struct sctp_sack_chunk *sack;
+
 				sack = (struct sctp_sack_chunk *)ch;
-				flags = ch->chunk_flags;
 				cum_ack = ntohl(sack->sack.cum_tsn_ack);
 				num_seg = ntohs(sack->sack.num_gap_ack_blks);
+				num_nr_seg = 0;
 				num_dup = ntohs(sack->sack.num_dup_tsns);
-				a_rwnd = (uint32_t) ntohl(sack->sack.a_rwnd);
+				a_rwnd = ntohl(sack->sack.a_rwnd);
 				if (sizeof(struct sctp_sack_chunk) +
 				    num_seg * sizeof(struct sctp_gap_ack_block) +
 				    num_dup * sizeof(uint32_t) != chk_length) {
@@ -5159,78 +5170,15 @@
 				}
 				offset_seg = *offset + sizeof(struct sctp_sack_chunk);
 				offset_dup = offset_seg + num_seg * sizeof(struct sctp_gap_ack_block);
-				SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SACK process cum_ack:%x num_seg:%d a_rwnd:%d\n",
-				        cum_ack, num_seg, a_rwnd);
-				stcb->asoc.seen_a_sack_this_pkt = 1;
-				if ((stcb->asoc.pr_sctp_cnt == 0) &&
-				    (num_seg == 0) &&
-				    SCTP_TSN_GE(cum_ack, stcb->asoc.last_acked_seq) &&
-				    (stcb->asoc.saw_sack_with_frags == 0) &&
-				    (stcb->asoc.saw_sack_with_nr_frags == 0) &&
-				    (!TAILQ_EMPTY(&stcb->asoc.sent_queue))
-					) {
-					/* We have a SIMPLE sack having no prior segments and
-					 * data on sent queue to be acked.. Use the faster
-					 * path sack processing. We also allow window update
-					 * sacks with no missing segments to go this way too.
-					 */
-					sctp_express_handle_sack(stcb, cum_ack, a_rwnd, &abort_now, ecne_seen);
-				} else {
-					if (netp && *netp)
-						sctp_handle_sack(m, offset_seg, offset_dup, stcb,
-								 num_seg, 0, num_dup, &abort_now, flags,
-								 cum_ack, a_rwnd, ecne_seen);
-				}
-				if (abort_now) {
-					/* ABORT signal from sack processing */
-					*offset = length;
-					return (NULL);
-				}
-				if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
-				    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
-				    (stcb->asoc.stream_queue_cnt == 0)) {
-					sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb,  0, NULL, SCTP_SO_NOT_LOCKED);
-				}
-			}
-			break;
-		/* EY - nr_sack:  If the received chunk is an nr_sack chunk */
-		case SCTP_NR_SELECTIVE_ACK:
-			{
+			} else {
 				struct sctp_nr_sack_chunk *nr_sack;
-				int abort_now = 0;
-				uint32_t a_rwnd, cum_ack;
-				uint16_t num_seg, num_nr_seg, num_dup;
-				uint8_t flags;
-				int offset_seg, offset_dup;
 
-				SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK\n");
-				SCTP_STAT_INCR(sctps_recvsacks);
-				if (stcb == NULL) {
-					SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing NR-SACK chunk\n");
-					break;
-				}
-				if (stcb->asoc.nrsack_supported == 0) {
-					goto unknown_chunk;
-				}
-				if (chk_length < sizeof(struct sctp_nr_sack_chunk)) {
-					SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on NR-SACK chunk, too small\n");
-					break;
-				}
-				if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
-					/*-
-					 * If we have sent a shutdown-ack, we will pay no
-					 * attention to a sack sent in to us since
-					 * we don't care anymore.
-					 */
-					break;
-				}
 				nr_sack = (struct sctp_nr_sack_chunk *)ch;
-				flags = ch->chunk_flags;
 				cum_ack = ntohl(nr_sack->nr_sack.cum_tsn_ack);
 				num_seg = ntohs(nr_sack->nr_sack.num_gap_ack_blks);
 				num_nr_seg = ntohs(nr_sack->nr_sack.num_nr_gap_ack_blks);
 				num_dup = ntohs(nr_sack->nr_sack.num_dup_tsns);
-				a_rwnd = (uint32_t) ntohl(nr_sack->nr_sack.a_rwnd);
+				a_rwnd = ntohl(nr_sack->nr_sack.a_rwnd);
 				if (sizeof(struct sctp_nr_sack_chunk) +
 				    (num_seg + num_nr_seg) * sizeof(struct sctp_gap_ack_block) +
 				    num_dup * sizeof(uint32_t) != chk_length) {
@@ -5238,108 +5186,91 @@
 					break;
 				}
 				offset_seg = *offset + sizeof(struct sctp_nr_sack_chunk);
-				offset_dup = offset_seg + num_seg * sizeof(struct sctp_gap_ack_block);
-				SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK process cum_ack:%x num_seg:%d a_rwnd:%d\n",
-				        cum_ack, num_seg, a_rwnd);
-				stcb->asoc.seen_a_sack_this_pkt = 1;
-				if ((stcb->asoc.pr_sctp_cnt == 0) &&
-				    (num_seg == 0) && (num_nr_seg == 0) &&
-				    SCTP_TSN_GE(cum_ack, stcb->asoc.last_acked_seq) &&
-				    (stcb->asoc.saw_sack_with_frags == 0) &&
-				    (stcb->asoc.saw_sack_with_nr_frags == 0) &&
-				    (!TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
-					/*
-					 * We have a SIMPLE sack having no
-					 * prior segments and data on sent
-					 * queue to be acked. Use the
-					 * faster path sack processing. We
-					 * also allow window update sacks
-					 * with no missing segments to go
-					 * this way too.
-					 */
-					sctp_express_handle_sack(stcb, cum_ack, a_rwnd,
-					                         &abort_now, ecne_seen);
-				} else {
-					if (netp && *netp)
-						sctp_handle_sack(m, offset_seg, offset_dup, stcb,
-						                 num_seg, num_nr_seg, num_dup, &abort_now, flags,
-						                 cum_ack, a_rwnd, ecne_seen);
-				}
-				if (abort_now) {
-					/* ABORT signal from sack processing */
-					*offset = length;
-					return (NULL);
-				}
-				if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
-				    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
-				    (stcb->asoc.stream_queue_cnt == 0)) {
-					sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb,  0, NULL, SCTP_SO_NOT_LOCKED);
+				offset_dup = offset_seg + (num_seg + num_nr_seg) * sizeof(struct sctp_gap_ack_block);
+			}
+			SCTPDBG(SCTP_DEBUG_INPUT3, "%s process cum_ack:%x num_seg:%d a_rwnd:%d\n",
+				(ch->chunk_type == SCTP_SELECTIVE_ACK) ? "SCTP_SACK" : "SCTP_NR_SACK",
+			        cum_ack, num_seg, a_rwnd);
+			stcb->asoc.seen_a_sack_this_pkt = 1;
+			if ((stcb->asoc.pr_sctp_cnt == 0) &&
+			    (num_seg == 0) && (num_nr_seg == 0) &&
+			    SCTP_TSN_GE(cum_ack, stcb->asoc.last_acked_seq) &&
+			    (stcb->asoc.saw_sack_with_frags == 0) &&
+			    (stcb->asoc.saw_sack_with_nr_frags == 0) &&
+			    (!TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
+				/*
+				 * We have a SIMPLE sack having no
+				 * prior segments and data on sent
+				 * queue to be acked. Use the
+				 * faster path sack processing. We
+				 * also allow window update sacks
+				 * with no missing segments to go
+				 * this way too.
+				 */
+				sctp_express_handle_sack(stcb, cum_ack, a_rwnd,
+				                         &abort_now, ecne_seen);
+			} else {
+				if ((netp != NULL) && (*netp != NULL)) {
+					sctp_handle_sack(m, offset_seg, offset_dup, stcb,
+					                 num_seg, num_nr_seg, num_dup, &abort_now, flags,
+					                 cum_ack, a_rwnd, ecne_seen);
 				}
 			}
+			if (abort_now) {
+				/* ABORT signal from sack processing */
+				*offset = length;
+				return (NULL);
+			}
+			if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
+			    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
+			    (stcb->asoc.stream_queue_cnt == 0)) {
+				sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb,  0, NULL, SCTP_SO_NOT_LOCKED);
+			}
 			break;
-
+		}
 		case SCTP_HEARTBEAT_REQUEST:
 			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT\n");
-			if ((stcb) && netp && *netp) {
+			if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
 				SCTP_STAT_INCR(sctps_recvheartbeat);
 				sctp_send_heartbeat_ack(stcb, m, *offset,
 							chk_length, *netp);
-
-				/* He's alive so give him credit */
-				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-					sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-						       stcb->asoc.overall_error_count,
-						       0,
-						       SCTP_FROM_SCTP_INPUT,
-						       __LINE__);
-				}
-				stcb->asoc.overall_error_count = 0;
 			}
 			break;
 		case SCTP_HEARTBEAT_ACK:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT-ACK\n");
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT_ACK\n");
 			if ((stcb == NULL) || (chk_length != sizeof(struct sctp_heartbeat_chunk))) {
 				/* Its not ours */
 				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
-				return (NULL);
+				return (stcb);
 			}
-			/* He's alive so give him credit */
-			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-				sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-					       stcb->asoc.overall_error_count,
-					       0,
-					       SCTP_FROM_SCTP_INPUT,
-					       __LINE__);
-			}
-			stcb->asoc.overall_error_count = 0;
 			SCTP_STAT_INCR(sctps_recvheartbeatack);
-			if (netp && *netp)
+			if ((netp != NULL) && (*netp != NULL)) {
 				sctp_handle_heartbeat_ack((struct sctp_heartbeat_chunk *)ch,
 							  stcb, *netp);
+			}
 			break;
 		case SCTP_ABORT_ASSOCIATION:
 			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ABORT, stcb %p\n",
 				(void *)stcb);
-			if ((stcb) && netp && *netp)
-				sctp_handle_abort((struct sctp_abort_chunk *)ch,
-						  stcb, *netp);
 			*offset = length;
-			return (NULL);
+			if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
+				if (sctp_handle_abort((struct sctp_abort_chunk *)ch, stcb, *netp)) {
+					return (NULL);
+				} else {
+					return (stcb);
+				}
+			} else {
+				return (NULL);
+			}
 			break;
 		case SCTP_SHUTDOWN:
 			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN, stcb %p\n",
 				(void *)stcb);
 			if ((stcb == NULL) || (chk_length != sizeof(struct sctp_shutdown_chunk))) {
 				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
-				return (NULL);
+				return (stcb);
 			}
-			if (netp && *netp) {
+			if ((netp != NULL) && (*netp != NULL)) {
 				int abort_flag = 0;
 
 				sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch,
@@ -5351,30 +5282,31 @@
 			}
 			break;
 		case SCTP_SHUTDOWN_ACK:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN-ACK, stcb %p\n", (void *)stcb);
-			if ((stcb) && (netp) && (*netp))
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN_ACK, stcb %p\n", (void *)stcb);
+			if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
 				sctp_handle_shutdown_ack((struct sctp_shutdown_ack_chunk *)ch, stcb, *netp);
+			}
 			*offset = length;
 			return (NULL);
 			break;
-
 		case SCTP_OPERATION_ERROR:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_OP-ERR\n");
-			if ((stcb) && netp && *netp && sctp_handle_error(ch, stcb, *netp) < 0) {
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_OP_ERR\n");
+			if ((stcb != NULL) && (netp != NULL) && (*netp != NULL) &&
+			    sctp_handle_error(ch, stcb, *netp, contiguous) < 0) {
 				*offset = length;
 				return (NULL);
 			}
 			break;
 		case SCTP_COOKIE_ECHO:
 			SCTPDBG(SCTP_DEBUG_INPUT3,
-				"SCTP_COOKIE-ECHO, stcb %p\n", (void *)stcb);
-			if ((stcb) && (stcb->asoc.total_output_queue_size)) {
+				"SCTP_COOKIE_ECHO, stcb %p\n", (void *)stcb);
+			if ((stcb != NULL) && (stcb->asoc.total_output_queue_size > 0)) {
 				;
 			} else {
 				if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
 					/* We are not interested anymore */
 				abend:
-					if (stcb) {
+					if (stcb != NULL) {
 						SCTP_TCB_UNLOCK(stcb);
 					}
 					*offset = length;
@@ -5427,7 +5359,7 @@
 					linp = inp;
 				}
 
-				if (linp) {
+				if (linp != NULL) {
 					SCTP_ASOC_CREATE_LOCK(linp);
 					if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
 					    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
@@ -5436,7 +5368,10 @@
 					}
 				}
 
-				if (netp) {
+				if (netp != NULL) {
+					struct sctp_tcb *locked_stcb;
+
+					locked_stcb = stcb;
 					ret_buf =
 						sctp_handle_cookie_echo(m, iphlen,
 						                        *offset,
@@ -5447,22 +5382,28 @@
 						                        auth_skipped,
 						                        auth_offset,
 						                        auth_len,
-						                        &locked_tcb,
+						                        &locked_stcb,
 #if defined(__FreeBSD__)
 						                        mflowtype,
 						                        mflowid,
 #endif
 						                        vrf_id,
 						                        port);
+					if ((locked_stcb != NULL) && (locked_stcb != stcb)) {
+						SCTP_TCB_UNLOCK(locked_stcb);
+					}
+					if (stcb != NULL) {
+						SCTP_TCB_LOCK_ASSERT(stcb);
+					}
 				} else {
 					ret_buf = NULL;
 				}
-				if (linp) {
+				if (linp != NULL) {
 					SCTP_ASOC_CREATE_UNLOCK(linp);
 				}
 				if (ret_buf == NULL) {
-					if (locked_tcb) {
-						SCTP_TCB_UNLOCK(locked_tcb);
+					if (stcb != NULL) {
+						SCTP_TCB_UNLOCK(stcb);
 					}
 					SCTPDBG(SCTP_DEBUG_INPUT3,
 						"GAK, null buffer\n");
@@ -5487,12 +5428,9 @@
 			}
 			break;
 		case SCTP_COOKIE_ACK:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_COOKIE-ACK, stcb %p\n", (void *)stcb);
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_COOKIE_ACK, stcb %p\n", (void *)stcb);
 			if ((stcb == NULL) || chk_length != sizeof(struct sctp_cookie_ack_chunk)) {
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
-				return (NULL);
+				return (stcb);
 			}
 			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
 				/* We are not interested anymore */
@@ -5516,85 +5454,43 @@
 					return (NULL);
 				}
 			}
-			/* He's alive so give him credit */
-			if ((stcb) && netp && *netp) {
-				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-					sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-						       stcb->asoc.overall_error_count,
-						       0,
-						       SCTP_FROM_SCTP_INPUT,
-						       __LINE__);
-				}
-				stcb->asoc.overall_error_count = 0;
-				sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch,stcb, *netp);
+			if ((netp != NULL) && (*netp != NULL)) {
+				sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, *netp);
 			}
 			break;
 		case SCTP_ECN_ECHO:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN-ECHO\n");
-			/* He's alive so give him credit */
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_ECHO\n");
 			if ((stcb == NULL) || (chk_length != sizeof(struct sctp_ecne_chunk))) {
 				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
-			if (stcb) {
-				if (stcb->asoc.ecn_supported == 0) {
-					goto unknown_chunk;
-				}
-				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-					sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-						       stcb->asoc.overall_error_count,
-						       0,
-						       SCTP_FROM_SCTP_INPUT,
-						       __LINE__);
-				}
-				stcb->asoc.overall_error_count = 0;
-				sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch,
-						     stcb);
-				ecne_seen = 1;
+			if (stcb->asoc.ecn_supported == 0) {
+				goto unknown_chunk;
 			}
+			sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch, stcb);
+			ecne_seen = 1;
 			break;
 		case SCTP_ECN_CWR:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN-CWR\n");
-			/* He's alive so give him credit */
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_CWR\n");
 			if ((stcb == NULL) || (chk_length != sizeof(struct sctp_cwr_chunk))) {
-				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
-			if (stcb) {
-				if (stcb->asoc.ecn_supported == 0) {
-					goto unknown_chunk;
-				}
-				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-					sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-						       stcb->asoc.overall_error_count,
-						       0,
-						       SCTP_FROM_SCTP_INPUT,
-						       __LINE__);
-				}
-				stcb->asoc.overall_error_count = 0;
-				sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb, *netp);
+			if (stcb->asoc.ecn_supported == 0) {
+				goto unknown_chunk;
 			}
+			sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb, *netp);
 			break;
 		case SCTP_SHUTDOWN_COMPLETE:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN-COMPLETE, stcb %p\n", (void *)stcb);
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN_COMPLETE, stcb %p\n", (void *)stcb);
 			/* must be first and only chunk */
 			if ((num_chunks > 1) ||
 			    (length - *offset > (int)SCTP_SIZE32(chk_length))) {
 				*offset = length;
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
-				return (NULL);
+				return (stcb);
 			}
-			if ((stcb) && netp && *netp) {
+			if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
 				sctp_handle_shutdown_complete((struct sctp_shutdown_complete_chunk *)ch,
 							      stcb, *netp);
 			}
@@ -5603,35 +5499,23 @@
 			break;
 		case SCTP_ASCONF:
 			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n");
-			/* He's alive so give him credit */
-			if (stcb) {
+			if (stcb != NULL) {
 				if (stcb->asoc.asconf_supported == 0) {
 					goto unknown_chunk;
 				}
-				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-					sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-						       stcb->asoc.overall_error_count,
-						       0,
-						       SCTP_FROM_SCTP_INPUT,
-						       __LINE__);
-				}
-				stcb->asoc.overall_error_count = 0;
 				sctp_handle_asconf(m, *offset, src,
 						   (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0);
 				asconf_cnt++;
 			}
 			break;
 		case SCTP_ASCONF_ACK:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF-ACK\n");
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF_ACK\n");
 			if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) {
 				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
-			if ((stcb) && netp && *netp) {
+			if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
 				if (stcb->asoc.asconf_supported == 0) {
 					goto unknown_chunk;
 				}
@@ -5652,31 +5536,19 @@
 			break;
 		case SCTP_FORWARD_CUM_TSN:
 		case SCTP_IFORWARD_CUM_TSN:
-			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_FWD-TSN\n");
+			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_FWD_TSN\n");
 			if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) {
 				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
 
-			/* He's alive so give him credit */
-			if (stcb) {
+			if (stcb != NULL) {
 				int abort_flag = 0;
 
 				if (stcb->asoc.prsctp_supported == 0) {
 					goto unknown_chunk;
 				}
-				stcb->asoc.overall_error_count = 0;
-				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-					sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-						       stcb->asoc.overall_error_count,
-						       0,
-						       SCTP_FROM_SCTP_INPUT,
-						       __LINE__);
-				}
 				*fwd_tsn_seen = 1;
 				if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
 					/* We are not interested anymore */
@@ -5706,28 +5578,15 @@
 				if (abort_flag) {
 					*offset = length;
 					return (NULL);
-				} else {
-					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-						sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-							       stcb->asoc.overall_error_count,
-							       0,
-							       SCTP_FROM_SCTP_INPUT,
-							       __LINE__);
-					}
-					stcb->asoc.overall_error_count = 0;
 				}
-
 			}
 			break;
 		case SCTP_STREAM_RESET:
 			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_STREAM_RESET\n");
 			if (((stcb == NULL) || (ch == NULL) || (chk_length < sizeof(struct sctp_stream_reset_tsn_req)))) {
 				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
 			if (stcb->asoc.reconfig_supported == 0) {
 				goto unknown_chunk;
@@ -5743,24 +5602,18 @@
 			/* re-get it all please */
 			if (chk_length < sizeof(struct sctp_pktdrop_chunk)) {
 				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
 
-
-			if (ch && (stcb) && netp && (*netp)) {
+			if ((ch != NULL) && (stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
 				if (stcb->asoc.pktdrop_supported == 0) {
 					goto unknown_chunk;
 				}
 				sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch,
 							   stcb, *netp,
-							   min(chk_length, (sizeof(chunk_buf) - 4)));
-
+							   min(chk_length, contiguous));
 			}
-
 			break;
 		case SCTP_AUTHENTICATION:
 			SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_AUTHENTICATION\n");
@@ -5781,11 +5634,8 @@
 			    (chk_length > (sizeof(struct sctp_auth_chunk) +
 					   SCTP_AUTH_DIGEST_LEN_MAX))) {
 				/* Its not ours */
-				if (locked_tcb) {
-					SCTP_TCB_UNLOCK(locked_tcb);
-				}
 				*offset = length;
-				return (NULL);
+				return (stcb);
 			}
 			if (got_auth == 1) {
 				/* skip this chunk... it's already auth'd */
@@ -5850,15 +5700,12 @@
 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
 							   sizeof(struct sctp_chunkhdr), chunk_buf);
 		if (ch == NULL) {
-			if (locked_tcb) {
-				SCTP_TCB_UNLOCK(locked_tcb);
-			}
 			*offset = length;
-			return (NULL);
+			return (stcb);
 		}
 	}			/* while */
 
-	if (asconf_cnt > 0 && stcb != NULL) {
+	if ((asconf_cnt > 0) && (stcb != NULL)) {
 		sctp_send_asconf_ack(stcb);
 	}
 	return (stcb);
@@ -6155,14 +6002,6 @@
 			 * shows us the cookie-ack was lost. Imply it was
 			 * there.
 			 */
-			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
-				sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
-					       stcb->asoc.overall_error_count,
-					       0,
-					       SCTP_FROM_SCTP_INPUT,
-					       __LINE__);
-			}
-			stcb->asoc.overall_error_count = 0;
 			sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, net);
 			break;
 		case SCTP_STATE_COOKIE_WAIT:
diff --git a/usrsctplib/netinet/sctp_input.h b/usrsctplib/netinet/sctp_input.h
index bc4cf42..c92c8bd 100755
--- a/usrsctplib/netinet/sctp_input.h
+++ b/usrsctplib/netinet/sctp_input.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_lock_userspace.h b/usrsctplib/netinet/sctp_lock_userspace.h
index 83a565c..7b8b0cb 100755
--- a/usrsctplib/netinet/sctp_lock_userspace.h
+++ b/usrsctplib/netinet/sctp_lock_userspace.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_os.h b/usrsctplib/netinet/sctp_os.h
index 4888381..b3746dd 100755
--- a/usrsctplib/netinet/sctp_os.h
+++ b/usrsctplib/netinet/sctp_os.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2006-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_os_userspace.h b/usrsctplib/netinet/sctp_os_userspace.h
index 50b7de2..8613301 100755
--- a/usrsctplib/netinet/sctp_os_userspace.h
+++ b/usrsctplib/netinet/sctp_os_userspace.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2006-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved.
@@ -45,8 +47,8 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #include <iphlpapi.h>
-#include <mswsock.h>
-#include <windows.h>
+#include <Mswsock.h>
+#include <Windows.h>
 #include "user_environment.h"
 typedef CRITICAL_SECTION userland_mutex_t;
 #if WINVER < 0x0600
@@ -216,6 +218,8 @@
 
 typedef char* caddr_t;
 
+#define bzero(buf, len) memset(buf, 0, len)
+#define bcopy(srcKey, dstKey, len) memcpy(dstKey, srcKey, len)
 #if _MSC_VER < 1900
 #define snprintf(data, size, format, ...) _snprintf_s(data, size, _TRUNCATE, format, __VA_ARGS__)
 #endif
@@ -272,7 +276,7 @@
 
 #else /* !defined(Userspace_os_Windows) */
 #include <sys/socket.h>
-#if defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_Linux) || defined(__Userspace_os_NetBSD) || defined(__Userspace_os_OpenBSD) || defined(__Userspace_os_NaCl)
+#if defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_Linux) || defined(__Userspace_os_NetBSD) || defined(__Userspace_os_OpenBSD) || defined(__Userspace_os_NaCl) || defined(__Userspace_os_Fuchsia)
 #include <pthread.h>
 #endif
 typedef pthread_mutex_t userland_mutex_t;
@@ -411,6 +415,8 @@
 #endif
 
 #if defined(__Userspace_os_Windows)
+int Win_getifaddrs(struct ifaddrs**);
+#define getifaddrs(interfaces)  (int)Win_getifaddrs(interfaces)
 int win_if_nametoindex(const char *);
 #define if_nametoindex(x) win_if_nametoindex(x)
 #endif
@@ -459,7 +465,7 @@
 #include <sys/priv.h>
 #endif
 /* #include <sys/random.h> */
-/* #include <sys/limits.h> */
+#include <limits.h>
 /* #include <machine/cpu.h> */
 
 #if defined(__Userspace_os_Darwin)
@@ -985,11 +991,6 @@
 #define SCTP_SB_LIMIT_RCV(so) so->so_rcv.sb_hiwat
 #define SCTP_SB_LIMIT_SND(so) so->so_snd.sb_hiwat
 
-/* Future zero copy wakeup/send  function */
-#define SCTP_ZERO_COPY_EVENT(inp, so)
-/* This is re-pulse ourselves for sendbuf */
-#define SCTP_ZERO_COPY_SENDQ_EVENT(inp, so)
-
 #define SCTP_READ_RANDOM(buf, len)	read_random(buf, len)
 
 #define SCTP_SHA1_CTX		struct sctp_sha1_context
diff --git a/usrsctplib/netinet/sctp_output.c b/usrsctplib/netinet/sctp_output.c
index 90b0bf3..6ac2059 100755
--- a/usrsctplib/netinet/sctp_output.c
+++ b/usrsctplib/netinet/sctp_output.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 325370 2017-11-03 20:46:12Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -3566,32 +3568,35 @@
 #else
 	struct cmsghdr cmh;
 #endif
-	int tlen, at, found;
 	struct sctp_sndinfo sndinfo;
 	struct sctp_prinfo prinfo;
 	struct sctp_authinfo authinfo;
+	int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off;
+	int found;
 
-	tlen = SCTP_BUF_LEN(control);
-	at = 0;
-	found = 0;
 	/*
 	 * Independent of how many mbufs, find the c_type inside the control
 	 * structure and copy out the data.
 	 */
-	while (at < tlen) {
-		if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+	found = 0;
+	tot_len = SCTP_BUF_LEN(control);
+	for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) {
+		rem_len = tot_len - off;
+		if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) {
 			/* There is not enough room for one more. */
 			return (found);
 		}
-		m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+		m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh);
 		if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) {
 			/* We dont't have a complete CMSG header. */
 			return (found);
 		}
-		if (((int)cmh.cmsg_len + at) > tlen) {
+		if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) {
 			/* We don't have the complete CMSG. */
 			return (found);
 		}
+		cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh));
+		cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh));
 		if ((cmh.cmsg_level == IPPROTO_SCTP) &&
 		    ((c_type == cmh.cmsg_type) ||
 		     ((c_type == SCTP_SNDRCV) &&
@@ -3599,11 +3604,14 @@
 		       (cmh.cmsg_type == SCTP_PRINFO) ||
 		       (cmh.cmsg_type == SCTP_AUTHINFO))))) {
 			if (c_type == cmh.cmsg_type) {
-				if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < cpsize) {
+				if (cpsize > INT_MAX) {
+					return (found);
+				}
+				if (cmsg_data_len < (int)cpsize) {
 					return (found);
 				}
 				/* It is exactly what we want. Copy it out. */
-				m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), (int)cpsize, (caddr_t)data);
+				m_copydata(control, cmsg_data_off, (int)cpsize, (caddr_t)data);
 				return (1);
 			} else {
 				struct sctp_sndrcvinfo *sndrcvinfo;
@@ -3617,10 +3625,10 @@
 				}
 				switch (cmh.cmsg_type) {
 				case SCTP_SNDINFO:
-					if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_sndinfo)) {
+					if (cmsg_data_len < (int)sizeof(struct sctp_sndinfo)) {
 						return (found);
 					}
-					m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo);
+					m_copydata(control, cmsg_data_off, sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo);
 					sndrcvinfo->sinfo_stream = sndinfo.snd_sid;
 					sndrcvinfo->sinfo_flags = sndinfo.snd_flags;
 					sndrcvinfo->sinfo_ppid = sndinfo.snd_ppid;
@@ -3628,10 +3636,10 @@
 					sndrcvinfo->sinfo_assoc_id = sndinfo.snd_assoc_id;
 					break;
 				case SCTP_PRINFO:
-					if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_prinfo)) {
+					if (cmsg_data_len < (int)sizeof(struct sctp_prinfo)) {
 						return (found);
 					}
-					m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_prinfo), (caddr_t)&prinfo);
+					m_copydata(control, cmsg_data_off, sizeof(struct sctp_prinfo), (caddr_t)&prinfo);
 					if (prinfo.pr_policy != SCTP_PR_SCTP_NONE) {
 						sndrcvinfo->sinfo_timetolive = prinfo.pr_value;
 					} else {
@@ -3640,10 +3648,10 @@
 					sndrcvinfo->sinfo_flags |= prinfo.pr_policy;
 					break;
 				case SCTP_AUTHINFO:
-					if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_authinfo)) {
+					if (cmsg_data_len < (int)sizeof(struct sctp_authinfo)) {
 						return (found);
 					}
-					m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_authinfo), (caddr_t)&authinfo);
+					m_copydata(control, cmsg_data_off, sizeof(struct sctp_authinfo), (caddr_t)&authinfo);
 					sndrcvinfo->sinfo_keynumber_valid = 1;
 					sndrcvinfo->sinfo_keynumber = authinfo.auth_keynumber;
 					break;
@@ -3653,7 +3661,6 @@
 				found = 1;
 			}
 		}
-		at += CMSG_ALIGN(cmh.cmsg_len);
 	}
 	return (found);
 }
@@ -4475,16 +4482,18 @@
 			}
 #endif
 		} else {
-			/* PMTU check versus smallest asoc MTU goes here */
-			if ((ro->ro_rt != NULL) &&
-			    (net->ro._s_addr)) {
+			if ((ro->ro_rt != NULL) && (net->ro._s_addr) &&
+			    ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) {
 				uint32_t mtu;
+
 				mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt);
-				if (net->port) {
-					mtu -= sizeof(struct udphdr);
-				}
-				if (mtu && (stcb->asoc.smallest_mtu > mtu)) {
-					sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+				if (mtu > 0) {
+					if (net->port) {
+						mtu -= sizeof(struct udphdr);
+					}
+					if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) {
+						sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+					}
 					net->mtu = mtu;
 				}
 			} else if (ro->ro_rt == NULL) {
@@ -4943,17 +4952,19 @@
 				}
 				net->src_addr_selected = 0;
 			}
-			if ((ro->ro_rt != NULL) &&
-			    (net->ro._s_addr)) {
+			if ((ro->ro_rt != NULL) && (net->ro._s_addr) &&
+			    ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) {
 				uint32_t mtu;
+
 				mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt);
-				if (mtu &&
-				    (stcb->asoc.smallest_mtu > mtu)) {
-					sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
-					net->mtu = mtu;
+				if (mtu > 0) {
 					if (net->port) {
-						net->mtu -= sizeof(struct udphdr);
+						mtu -= sizeof(struct udphdr);
 					}
+					if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) {
+						sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+					}
+					net->mtu = mtu;
 				}
 			}
 #if !defined(__Panda__) && !defined(__Userspace__)
@@ -5904,7 +5915,7 @@
 #if defined(__FreeBSD__)
 		       uint8_t mflowtype, uint32_t mflowid,
 #endif
-                       uint32_t vrf_id, uint16_t port, int hold_inp_lock)
+                       uint32_t vrf_id, uint16_t port)
 {
 	struct sctp_association *asoc;
 	struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err;
@@ -5914,6 +5925,7 @@
 	struct sctp_paramhdr *ph;
 	union sctp_sockstore *over_addr;
 	struct sctp_scoping scp;
+	struct timeval now;
 #ifdef INET
 	struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
 	struct sockaddr_in *src4 = (struct sockaddr_in *)src;
@@ -6024,7 +6036,9 @@
 	memset(&stc, 0, sizeof(struct sctp_state_cookie));
 
 	/* the time I built cookie */
-	(void)SCTP_GETTIME_TIMEVAL(&stc.time_entered);
+	(void)SCTP_GETTIME_TIMEVAL(&now);
+	stc.time_entered.tv_sec = now.tv_sec;
+	stc.time_entered.tv_usec = now.tv_usec;
 
 	/* populate any tie tags */
 	if (asoc != NULL) {
@@ -6317,10 +6331,7 @@
 		initack->init.initial_tsn = htonl(asoc->init_seq_number);
 	} else {
 		uint32_t vtag, itsn;
-		if (hold_inp_lock) {
-			SCTP_INP_INCR_REF(inp);
-			SCTP_INP_RUNLOCK(inp);
-		}
+
 		if (asoc) {
 			atomic_add_int(&asoc->refcnt, 1);
 			SCTP_TCB_UNLOCK(stcb);
@@ -6339,12 +6350,12 @@
 			SCTP_TCB_LOCK(stcb);
 			atomic_add_int(&asoc->refcnt, -1);
 		} else {
+			SCTP_INP_INCR_REF(inp);
+			SCTP_INP_RUNLOCK(inp);
 			vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1);
 			initack->init.initiate_tag = htonl(vtag);
 			/* get a TSN to use too */
 			initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep));
-		}
-		if (hold_inp_lock) {
 			SCTP_INP_RLOCK(inp);
 			SCTP_INP_DECR_REF(inp);
 		}
@@ -6737,7 +6748,15 @@
 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
 		ovh = SCTP_MIN_OVERHEAD;
 	} else {
+#if defined(__Userspace__)
+		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
+			ovh = sizeof(struct sctphdr);
+		} else {
+			ovh = SCTP_MIN_V4_OVERHEAD;
+		}
+#else
 		ovh = SCTP_MIN_V4_OVERHEAD;
+#endif
 	}
 	ovh += SCTP_DATA_CHUNK_OVERHEAD(stcb);
 	if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu)
@@ -8445,7 +8464,7 @@
 					sctp_log_cwnd(stcb, net, 1,
 						      SCTP_CWND_LOG_FILL_OUTQ_CALLED);
 				}
-			        continue;
+				continue;
 			}
 			if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) &&
 			    (net->flight_size == 0)) {
@@ -13317,10 +13336,9 @@
 	sp->sender_all_done = 0;
 	sp->some_taken = 0;
 	sp->put_last_out = 0;
-        resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb);
+	resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb);
 	sp->data = sp->tail_mbuf = NULL;
 	if (sp->length == 0) {
-		*error = 0;
 		goto skip_copy;
 	}
 	if (srcv->sinfo_keynumber_valid) {
@@ -13341,7 +13359,13 @@
 #endif
  skip_copy:
 	if (*error) {
+#if defined(__Userspace__)
+		SCTP_TCB_LOCK(stcb);
+#endif
 		sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED);
+#if defined(__Userspace__)
+		SCTP_TCB_UNLOCK(stcb);
+#endif
 		sp = NULL;
 	} else {
 		if (sp->sinfo_flags & SCTP_ADDR_OVER) {
@@ -14204,7 +14228,7 @@
 		if (strm->last_msg_incomplete == 0) {
 		do_a_copy_in:
 			sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error);
-			if ((sp == NULL) || (error)) {
+			if (error) {
 				goto out;
 			}
 			SCTP_TCB_SEND_LOCK(stcb);
diff --git a/usrsctplib/netinet/sctp_output.h b/usrsctplib/netinet/sctp_output.h
index dfae447..597ddc3 100755
--- a/usrsctplib/netinet/sctp_output.h
+++ b/usrsctplib/netinet/sctp_output.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 321034 2017-07-15 19:54:03Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 323861 2017-09-21 11:56:31Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_OUTPUT_H_
@@ -91,7 +93,7 @@
 #if defined(__FreeBSD__)
                        uint8_t, uint32_t,
 #endif
-                       uint32_t, uint16_t, int);
+                       uint32_t, uint16_t);
 
 struct mbuf *
 sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
diff --git a/usrsctplib/netinet/sctp_pcb.c b/usrsctplib/netinet/sctp_pcb.c
index 9e9fca0..2bde696 100755
--- a/usrsctplib/netinet/sctp_pcb.c
+++ b/usrsctplib/netinet/sctp_pcb.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 325370 2017-11-03 20:46:12Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -801,12 +803,11 @@
 
 		SCTP_WQ_ADDR_LOCK();
 		LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
-		SCTP_WQ_ADDR_UNLOCK();
-
 		sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
 				 (struct sctp_inpcb *)NULL,
 				 (struct sctp_tcb *)NULL,
 				 (struct sctp_nets *)NULL);
+		SCTP_WQ_ADDR_UNLOCK();
 	} else {
 		/* it's ready for use */
 		sctp_ifap->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
@@ -912,12 +913,11 @@
 		 * newest first :-0
 		 */
 		LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
-		SCTP_WQ_ADDR_UNLOCK();
-
 		sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
 				 (struct sctp_inpcb *)NULL,
 				 (struct sctp_tcb *)NULL,
 				 (struct sctp_nets *)NULL);
+		SCTP_WQ_ADDR_UNLOCK();
 	}
 	return;
 }
@@ -2877,16 +2877,16 @@
 		inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE |
 		    SCTP_PCB_FLAGS_UNBOUND);
 		/* Be sure we have blocking IO by default */
+		SOCK_LOCK(so);
 		SCTP_CLEAR_SO_NBIO(so);
+		SOCK_UNLOCK(so);
 #if defined(__Panda__)
 	} else if (SCTP_SO_TYPE(so) == SOCK_FASTSEQPACKET) {
 		inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
 		    SCTP_PCB_FLAGS_UNBOUND);
-		sctp_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE);
 	} else if (SCTP_SO_TYPE(so) == SOCK_FASTSTREAM) {
 		inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE |
 		    SCTP_PCB_FLAGS_UNBOUND);
-		sctp_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE);
 #endif
 	} else {
 		/*
@@ -3030,6 +3030,7 @@
 	/* number of streams to pre-open on a association */
 	m->pre_open_stream_count = SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default);
 
+	m->default_mtu = 0;
 	/* Add adaptation cookie */
 	m->adaptation_layer_indicator = 0;
 	m->adaptation_layer_indicator_provided = 0;
@@ -3445,7 +3446,7 @@
 		/* got to be root to get at low ports */
 #if !defined(__Windows__)
 		if (ntohs(lport) < IPPORT_RESERVED) {
-			if (p && (error =
+			if ((p != NULL) && ((error =
 #ifdef __FreeBSD__
 #if __FreeBSD_version > 602000
 				  priv_check(p, PRIV_NETINET_RESERVEDPORT)
@@ -3461,7 +3462,7 @@
 #else
 				  suser(p, 0)
 #endif
-				    )) {
+				    ) != 0)) {
 				SCTP_INP_DECR_REF(inp);
 				SCTP_INP_WUNLOCK(inp);
 				SCTP_INP_INFO_WUNLOCK();
@@ -4199,18 +4200,6 @@
 #endif
 #endif
 
-#if defined(__Panda__)
-	if (inp->pak_to_read) {
-		(void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.zero_copy_timer.timer);
-		SCTP_RELEASE_PKT(inp->pak_to_read);
-		inp->pak_to_read = NULL;
-	}
-	if (inp->pak_to_read_sendq) {
-		(void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.zero_copy_sendq_timer.timer);
-		SCTP_RELEASE_PKT(inp->pak_to_read_sendq);
-		inp->pak_to_read_sendq = NULL;
-	}
-#endif
 	if ((inp->sctp_asocidhash) != NULL) {
 		SCTP_HASH_FREE(inp->sctp_asocidhash, inp->hashasocidmark);
 		inp->sctp_asocidhash = NULL;
@@ -4656,7 +4645,33 @@
 		                                                net,
 		                                                0,
 		                                                stcb->asoc.vrf_id);
-		if (net->ro._s_addr != NULL) {
+		if (stcb->asoc.default_mtu > 0) {
+			net->mtu = stcb->asoc.default_mtu;
+			switch (net->ro._l_addr.sa.sa_family) {
+#ifdef INET
+			case AF_INET:
+				net->mtu += SCTP_MIN_V4_OVERHEAD;
+				break;
+#endif
+#ifdef INET6
+			case AF_INET6:
+				net->mtu += SCTP_MIN_OVERHEAD;
+				break;
+#endif
+#if defined(__Userspace__)
+			case AF_CONN:
+				net->mtu += sizeof(struct sctphdr);
+				break;
+#endif
+			default:
+				break;
+			}
+#if defined(INET) || defined(INET6)
+			if (net->port) {
+				net->mtu += (uint32_t)sizeof(struct udphdr);
+			}
+#endif
+		} else if (net->ro._s_addr != NULL) {
 			uint32_t imtu, rmtu, hcmtu;
 
 			net->src_addr_selected = 1;
@@ -4682,24 +4697,52 @@
 	}
 #endif
 	if (net->mtu == 0) {
-		switch (newaddr->sa_family) {
+		if (stcb->asoc.default_mtu > 0) {
+			net->mtu = stcb->asoc.default_mtu;
+			switch (net->ro._l_addr.sa.sa_family) {
 #ifdef INET
-		case AF_INET:
-			net->mtu = SCTP_DEFAULT_MTU;
-			break;
+			case AF_INET:
+				net->mtu += SCTP_MIN_V4_OVERHEAD;
+				break;
 #endif
 #ifdef INET6
-		case AF_INET6:
-			net->mtu = 1280;
-			break;
+			case AF_INET6:
+				net->mtu += SCTP_MIN_OVERHEAD;
+				break;
 #endif
 #if defined(__Userspace__)
-		case AF_CONN:
-			net->mtu = 1280;
-			break;
+			case AF_CONN:
+				net->mtu += sizeof(struct sctphdr);
+				break;
 #endif
-		default:
-			break;
+			default:
+				break;
+			}
+#if defined(INET) || defined(INET6)
+			if (net->port) {
+				net->mtu += (uint32_t)sizeof(struct udphdr);
+			}
+#endif
+		} else {
+			switch (newaddr->sa_family) {
+#ifdef INET
+			case AF_INET:
+				net->mtu = SCTP_DEFAULT_MTU;
+				break;
+#endif
+#ifdef INET6
+			case AF_INET6:
+				net->mtu = 1280;
+				break;
+#endif
+#if defined(__Userspace__)
+			case AF_CONN:
+				net->mtu = 1280;
+				break;
+#endif
+			default:
+				break;
+			}
 		}
 	}
 #if defined(INET) || defined(INET6)
diff --git a/usrsctplib/netinet/sctp_pcb.h b/usrsctplib/netinet/sctp_pcb.h
index b938625..47aaa24 100755
--- a/usrsctplib/netinet/sctp_pcb.h
+++ b/usrsctplib/netinet/sctp_pcb.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 310590 2016-12-26 11:06:41Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 325370 2017-11-03 20:46:12Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_PCB_H_
@@ -373,6 +375,7 @@
 	sctp_auth_chklist_t *local_auth_chunks;
 	sctp_hmaclist_t *local_hmacs;
 	uint16_t default_keyid;
+	uint32_t default_mtu;
 
 	/* various thresholds */
 	/* Max times I will init at a guy */
@@ -400,10 +403,6 @@
 	 */
 	struct sctp_timer signature_change;
 
-	/* Zero copy full buffer timer */
-	struct sctp_timer zero_copy_timer;
-        /* Zero copy app to transport (sendq) read repulse timer */
-	struct sctp_timer zero_copy_sendq_timer;
 	uint32_t def_cookie_life;
 	/* defaults to 0 */
 	int auto_close_time;
diff --git a/usrsctplib/netinet/sctp_peeloff.c b/usrsctplib/netinet/sctp_peeloff.c
index 7c55aa3..391b4f5 100755
--- a/usrsctplib/netinet/sctp_peeloff.c
+++ b/usrsctplib/netinet/sctp_peeloff.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -280,8 +282,10 @@
 				SCTP_FROM_SCTP_PEELOFF + SCTP_LOC_1);
 	}
 	/* Turn off any non-blocking semantic. */
+	SOCK_LOCK(newso);
 	SCTP_CLEAR_SO_NBIO(newso);
-        newso->so_state |= SS_ISCONNECTED;
+	newso->so_state |= SS_ISCONNECTED;
+	SOCK_UNLOCK(newso);
 	/* We remove it right away */
 
 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
@@ -294,7 +298,7 @@
 	head->so_qlen--;
 	SOCK_UNLOCK(head);
 #else
-        newso = TAILQ_FIRST(&head->so_q);
+	newso = TAILQ_FIRST(&head->so_q);
 	if (soqremque(newso, 1) == 0) {
 		SCTP_PRINTF("soremque failed, peeloff-fails (invarients would panic)\n");
 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
@@ -307,7 +311,7 @@
 	 * Now we must move it from one hash table to another and get the
 	 * stcb in the right place.
 	 */
-        sctp_move_pcb_and_assoc(inp, n_inp, stcb);
+	sctp_move_pcb_and_assoc(inp, n_inp, stcb);
 	atomic_add_int(&stcb->asoc.refcnt, 1);
 	SCTP_TCB_UNLOCK(stcb);
 	/*
diff --git a/usrsctplib/netinet/sctp_peeloff.h b/usrsctplib/netinet/sctp_peeloff.h
index 22375e3..adefcde 100755
--- a/usrsctplib/netinet/sctp_peeloff.h
+++ b/usrsctplib/netinet/sctp_peeloff.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_process_lock.h b/usrsctplib/netinet/sctp_process_lock.h
index 1d10985..ca66921 100755
--- a/usrsctplib/netinet/sctp_process_lock.h
+++ b/usrsctplib/netinet/sctp_process_lock.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved.
@@ -115,13 +117,13 @@
 
 #if defined(__Userspace_os_Windows)
 #define SCTP_WQ_ADDR_INIT() \
-        InitializeCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
+	InitializeCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
 #define SCTP_WQ_ADDR_DESTROY() \
 	DeleteCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
 #define SCTP_WQ_ADDR_LOCK() \
-        EnterCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
+	EnterCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
 #define SCTP_WQ_ADDR_UNLOCK() \
-        LeaveCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
+	LeaveCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx))
 
 
 #define SCTP_INP_INFO_LOCK_INIT() \
@@ -131,20 +133,20 @@
 #define SCTP_INP_INFO_RLOCK() \
 	EnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
 #define SCTP_INP_INFO_TRYLOCK()	\
-        TryEnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
+	TryEnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
 #define SCTP_INP_INFO_WLOCK() \
 	EnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
 #define SCTP_INP_INFO_RUNLOCK() \
- 	LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
+	LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
 #define SCTP_INP_INFO_WUNLOCK()	\
 	LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
 
 #define SCTP_IP_PKTLOG_INIT() \
-        InitializeCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx))
+	InitializeCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx))
 #define SCTP_IP_PKTLOG_DESTROY () \
 	DeleteCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx))
 #define SCTP_IP_PKTLOG_LOCK() \
-    	EnterCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx))
+	EnterCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx))
 #define SCTP_IP_PKTLOG_UNLOCK() \
 	LeaveCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx))
 
@@ -164,63 +166,51 @@
 
 #define SCTP_INP_LOCK_INIT(_inp) \
 	InitializeCriticalSection(&(_inp)->inp_mtx)
-
-#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \
-	InitializeCriticalSection(&(_inp)->inp_create_mtx)
-
 #define SCTP_INP_LOCK_DESTROY(_inp) \
 	DeleteCriticalSection(&(_inp)->inp_mtx)
-
-#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \
-	DeleteCriticalSection(&(_inp)->inp_create_mtx)
-
 #ifdef SCTP_LOCK_LOGGING
-#define SCTP_INP_RLOCK(_inp)	do { 					\
-	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\
-	EnterCriticalSection(&(_inp)->inp_mtx);			\
+#define SCTP_INP_RLOCK(_inp) do { 						\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP);			\
+		EnterCriticalSection(&(_inp)->inp_mtx);				\
 } while (0)
-
-#define SCTP_INP_WLOCK(_inp)	do { 					\
-	sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\
-	EnterCriticalSection(&(_inp)->inp_mtx);			\
+#define SCTP_INP_WLOCK(_inp) do { 						\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP);			\
+	EnterCriticalSection(&(_inp)->inp_mtx);					\
 } while (0)
 #else
-
-#define SCTP_INP_RLOCK(_inp)	do { 					\
-	EnterCriticalSection(&(_inp)->inp_mtx);			\
-} while (0)
-
-#define SCTP_INP_WLOCK(_inp)	do { 					\
-	EnterCriticalSection(&(_inp)->inp_mtx);			\
-} while (0)
+#define SCTP_INP_RLOCK(_inp) \
+	EnterCriticalSection(&(_inp)->inp_mtx)
+#define SCTP_INP_WLOCK(_inp) \
+	EnterCriticalSection(&(_inp)->inp_mtx)
 #endif
 
-
 #define SCTP_TCB_SEND_LOCK_INIT(_tcb) \
 	InitializeCriticalSection(&(_tcb)->tcb_send_mtx)
-
 #define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) \
 	DeleteCriticalSection(&(_tcb)->tcb_send_mtx)
-
-#define SCTP_TCB_SEND_LOCK(_tcb) do { \
-	EnterCriticalSection(&(_tcb)->tcb_send_mtx); \
-} while (0)
-
+#define SCTP_TCB_SEND_LOCK(_tcb) \
+	EnterCriticalSection(&(_tcb)->tcb_send_mtx)
 #define SCTP_TCB_SEND_UNLOCK(_tcb) \
 	LeaveCriticalSection(&(_tcb)->tcb_send_mtx)
 
 #define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1)
 #define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1)
 
+#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \
+	InitializeCriticalSection(&(_inp)->inp_create_mtx)
+#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \
+	DeleteCriticalSection(&(_inp)->inp_create_mtx)
 #ifdef SCTP_LOCK_LOGGING
-#define SCTP_ASOC_CREATE_LOCK(_inp) do {				\
-	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \
-	EnterCriticalSection(&(_inp)->inp_create_mtx);		\
+#define SCTP_ASOC_CREATE_LOCK(_inp) do {					\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE);		\
+	EnterCriticalSection(&(_inp)->inp_create_mtx);				\
 } while (0)
 #else
-#define SCTP_ASOC_CREATE_LOCK(_inp) do {				\
-	EnterCriticalSection(&(_inp)->inp_create_mtx);		\
-} while (0)
+#define SCTP_ASOC_CREATE_LOCK(_inp) \
+	EnterCriticalSection(&(_inp)->inp_create_mtx)
 #endif
 
 #define SCTP_INP_RUNLOCK(_inp) \
@@ -240,65 +230,81 @@
 
 #define SCTP_TCB_LOCK_INIT(_tcb) \
 	InitializeCriticalSection(&(_tcb)->tcb_mtx)
-
 #define SCTP_TCB_LOCK_DESTROY(_tcb) \
 	DeleteCriticalSection(&(_tcb)->tcb_mtx)
-
 #ifdef SCTP_LOCK_LOGGING
-#define SCTP_TCB_LOCK(_tcb)  do {					\
-	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB);		\
-	EnterCriticalSection(&(_tcb)->tcb_mtx);			\
+#define SCTP_TCB_LOCK(_tcb) do {						\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB);		\
+	EnterCriticalSection(&(_tcb)->tcb_mtx);					\
 } while (0)
-
 #else
-#define SCTP_TCB_LOCK(_tcb)  do {					\
-	EnterCriticalSection(&(_tcb)->tcb_mtx);			\
-} while (0)
+#define SCTP_TCB_LOCK(_tcb) \
+	EnterCriticalSection(&(_tcb)->tcb_mtx)
 #endif
-
 #define SCTP_TCB_TRYLOCK(_tcb) 	((TryEnterCriticalSection(&(_tcb)->tcb_mtx)))
-
-#define SCTP_TCB_UNLOCK(_tcb)	do {  \
-	LeaveCriticalSection(&(_tcb)->tcb_mtx);  \
-} while (0)
-
+#define SCTP_TCB_UNLOCK(_tcb) \
+	LeaveCriticalSection(&(_tcb)->tcb_mtx)
 #define SCTP_TCB_LOCK_ASSERT(_tcb)
 
 #else /* all Userspaces except Windows */
 #define SCTP_WQ_ADDR_INIT() \
-        (void)pthread_mutex_init(&SCTP_BASE_INFO(wq_addr_mtx), NULL)
+	(void)pthread_mutex_init(&SCTP_BASE_INFO(wq_addr_mtx), &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_WQ_ADDR_DESTROY() \
 	(void)pthread_mutex_destroy(&SCTP_BASE_INFO(wq_addr_mtx))
+#ifdef INVARIANTS
 #define SCTP_WQ_ADDR_LOCK() \
-        (void)pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx))
+	KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s: wq_addr_mtx already locked", __func__))
 #define SCTP_WQ_ADDR_UNLOCK() \
-        (void)pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx))
-
+	KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s: wq_addr_mtx not locked", __func__))
+#else
+#define SCTP_WQ_ADDR_LOCK() \
+	(void)pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx))
+#define SCTP_WQ_ADDR_UNLOCK() \
+	(void)pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx))
+#endif
 
 #define SCTP_INP_INFO_LOCK_INIT() \
-	(void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_ep_mtx), NULL)
+	(void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_ep_mtx), &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_INP_INFO_LOCK_DESTROY() \
 	(void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_ep_mtx))
+#ifdef INVARIANTS
+#define SCTP_INP_INFO_RLOCK() \
+	KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx already locked", __func__))
+#define SCTP_INP_INFO_WLOCK() \
+	KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx already locked", __func__))
+#define SCTP_INP_INFO_RUNLOCK() \
+	KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx not locked", __func__))
+#define SCTP_INP_INFO_WUNLOCK() \
+	KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx not locked", __func__))
+#else
 #define SCTP_INP_INFO_RLOCK() \
 	(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx))
-#define SCTP_INP_INFO_TRYLOCK()	\
-        (!(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_ep_mtx))))
 #define SCTP_INP_INFO_WLOCK() \
 	(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx))
-#define SCTP_INP_INFO_RUNLOCK()	\
+#define SCTP_INP_INFO_RUNLOCK() \
 	(void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx))
-#define SCTP_INP_INFO_WUNLOCK()	\
+#define SCTP_INP_INFO_WUNLOCK() \
 	(void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx))
+#endif
+#define SCTP_INP_INFO_TRYLOCK() \
+	(!(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_ep_mtx))))
 
 #define SCTP_IP_PKTLOG_INIT() \
-        (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), NULL)
+	(void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_IP_PKTLOG_DESTROY() \
 	(void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_pktlog_mtx))
+#ifdef INVARIANTS
 #define SCTP_IP_PKTLOG_LOCK() \
-        (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx))
-#define SCTP_IP_PKTLOG_UNLOCK()	\
-        (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx))
-
+	KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s: ipi_pktlog_mtx already locked", __func__))
+#define SCTP_IP_PKTLOG_UNLOCK() \
+	KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s: ipi_pktlog_mtx not locked", __func__))
+#else
+#define SCTP_IP_PKTLOG_LOCK() \
+	(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx))
+#define SCTP_IP_PKTLOG_UNLOCK() \
+	(void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx))
+#endif
 
 
 /*
@@ -307,88 +313,120 @@
  * or cookie secrets we lock the INP level.
  */
 #define SCTP_INP_READ_INIT(_inp) \
-	(void)pthread_mutex_init(&(_inp)->inp_rdata_mtx, NULL)
-
+	(void)pthread_mutex_init(&(_inp)->inp_rdata_mtx, &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_INP_READ_DESTROY(_inp) \
 	(void)pthread_mutex_destroy(&(_inp)->inp_rdata_mtx)
-
-#define SCTP_INP_READ_LOCK(_inp)	do { \
-	(void)pthread_mutex_lock(&(_inp)->inp_rdata_mtx);    \
-} while (0)
-
-
+#ifdef INVARIANTS
+#define SCTP_INP_READ_LOCK(_inp) \
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_rdata_mtx) == 0, ("%s: inp_rdata_mtx already locked", __func__))
+#define SCTP_INP_READ_UNLOCK(_inp) \
+	KASSERT(pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) == 0, ("%s: inp_rdata_mtx not locked", __func__))
+#else
+#define SCTP_INP_READ_LOCK(_inp) \
+	(void)pthread_mutex_lock(&(_inp)->inp_rdata_mtx)
 #define SCTP_INP_READ_UNLOCK(_inp) \
 	(void)pthread_mutex_unlock(&(_inp)->inp_rdata_mtx)
+#endif
 
 #define SCTP_INP_LOCK_INIT(_inp) \
-	(void)pthread_mutex_init(&(_inp)->inp_mtx, NULL)
-
-#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \
-	(void)pthread_mutex_init(&(_inp)->inp_create_mtx, NULL)
-
+	(void)pthread_mutex_init(&(_inp)->inp_mtx, &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_INP_LOCK_DESTROY(_inp) \
 	(void)pthread_mutex_destroy(&(_inp)->inp_mtx)
-
-#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \
-	(void)pthread_mutex_destroy(&(_inp)->inp_create_mtx)
-
+#ifdef INVARIANTS
 #ifdef SCTP_LOCK_LOGGING
-#define SCTP_INP_RLOCK(_inp)	do { 					\
-	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\
-	(void)pthread_mutex_lock(&(_inp)->inp_mtx);			\
+#define SCTP_INP_RLOCK(_inp) do {									\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)				\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP);						\
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__))	\
 } while (0)
-
-#define SCTP_INP_WLOCK(_inp)	do { 					\
-	sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\
-	(void)pthread_mutex_lock(&(_inp)->inp_mtx);			\
-} while (0)
-
-#else
-
-#define SCTP_INP_RLOCK(_inp)	do { 					\
-	(void)pthread_mutex_lock(&(_inp)->inp_mtx);			\
-} while (0)
-
-#define SCTP_INP_WLOCK(_inp)	do { 					\
-	(void)pthread_mutex_lock(&(_inp)->inp_mtx);			\
-} while (0)
-#endif
-
-
-#define SCTP_TCB_SEND_LOCK_INIT(_tcb) \
-	(void)pthread_mutex_init(&(_tcb)->tcb_send_mtx, NULL)
-
-#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) \
-	(void)pthread_mutex_destroy(&(_tcb)->tcb_send_mtx)
-
-#define SCTP_TCB_SEND_LOCK(_tcb) do { \
-	(void)pthread_mutex_lock(&(_tcb)->tcb_send_mtx); \
-} while (0)
-
-#define SCTP_TCB_SEND_UNLOCK(_tcb) \
-	(void)pthread_mutex_unlock(&(_tcb)->tcb_send_mtx)
-
-#define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1)
-#define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1)
-
-#ifdef SCTP_LOCK_LOGGING
-#define SCTP_ASOC_CREATE_LOCK(_inp) do {				\
-	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \
-	(void)pthread_mutex_lock(&(_inp)->inp_create_mtx);		\
+#define SCTP_INP_WLOCK(_inp) do {									\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)				\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP);						\
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__))
 } while (0)
 #else
-#define SCTP_ASOC_CREATE_LOCK(_inp) do {				\
-	(void)pthread_mutex_lock(&(_inp)->inp_create_mtx);		\
-} while (0)
+#define SCTP_INP_RLOCK(_inp) \
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__))
+#define SCTP_INP_WLOCK(_inp) \
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__))
 #endif
-
+#define SCTP_INP_RUNLOCK(_inp) \
+	KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx not locked", __func__))
+#define SCTP_INP_WUNLOCK(_inp) \
+	KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx not locked", __func__))
+#else
+#ifdef SCTP_LOCK_LOGGING
+#define SCTP_INP_RLOCK(_inp) do {						\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP);			\
+	(void)pthread_mutex_lock(&(_inp)->inp_mtx);				\
+} while (0)
+#define SCTP_INP_WLOCK(_inp) do {						\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP);			\
+	(void)pthread_mutex_lock(&(_inp)->inp_mtx);				\
+} while (0)
+#else
+#define SCTP_INP_RLOCK(_inp) \
+	(void)pthread_mutex_lock(&(_inp)->inp_mtx)
+#define SCTP_INP_WLOCK(_inp) \
+	(void)pthread_mutex_lock(&(_inp)->inp_mtx)
+#endif
 #define SCTP_INP_RUNLOCK(_inp) \
 	(void)pthread_mutex_unlock(&(_inp)->inp_mtx)
 #define SCTP_INP_WUNLOCK(_inp) \
 	(void)pthread_mutex_unlock(&(_inp)->inp_mtx)
+#endif
+#define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1)
+#define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1)
+
+#define SCTP_TCB_SEND_LOCK_INIT(_tcb) \
+	(void)pthread_mutex_init(&(_tcb)->tcb_send_mtx, &SCTP_BASE_VAR(mtx_attr))
+#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) \
+	(void)pthread_mutex_destroy(&(_tcb)->tcb_send_mtx)
+#ifdef INVARIANTS
+#define SCTP_TCB_SEND_LOCK(_tcb) \
+	KASSERT(pthread_mutex_lock(&(_tcb)->tcb_send_mtx) == 0, ("%s: tcb_send_mtx already locked", __func__))
+#define SCTP_TCB_SEND_UNLOCK(_tcb) \
+	KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_send_mtx) == 0, ("%s: tcb_send_mtx not locked", __func__))
+#else
+#define SCTP_TCB_SEND_LOCK(_tcb) \
+	(void)pthread_mutex_lock(&(_tcb)->tcb_send_mtx)
+#define SCTP_TCB_SEND_UNLOCK(_tcb) \
+	(void)pthread_mutex_unlock(&(_tcb)->tcb_send_mtx)
+#endif
+
+#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \
+	(void)pthread_mutex_init(&(_inp)->inp_create_mtx, &SCTP_BASE_VAR(mtx_attr))
+#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \
+	(void)pthread_mutex_destroy(&(_inp)->inp_create_mtx)
+#ifdef INVARIANTS
+#ifdef SCTP_LOCK_LOGGING
+#define SCTP_ASOC_CREATE_LOCK(_inp) do {										\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)						\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE);							\
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx already locked", __func__))	\
+} while (0)
+#else
+#define SCTP_ASOC_CREATE_LOCK(_inp) \
+	KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx already locked", __func__))
+#endif
+#define SCTP_ASOC_CREATE_UNLOCK(_inp) \
+	KASSERT(pthread_mutex_unlock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx not locked", __func__))
+#else
+#ifdef SCTP_LOCK_LOGGING
+#define SCTP_ASOC_CREATE_LOCK(_inp) do {					\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)	\
+		sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE);		\
+	(void)pthread_mutex_lock(&(_inp)->inp_create_mtx);			\
+} while (0)
+#else
+#define SCTP_ASOC_CREATE_LOCK(_inp) \
+	(void)pthread_mutex_lock(&(_inp)->inp_create_mtx)
+#endif
 #define SCTP_ASOC_CREATE_UNLOCK(_inp) \
 	(void)pthread_mutex_unlock(&(_inp)->inp_create_mtx)
-
+#endif
 /*
  * For the majority of things (once we have found the association) we will
  * lock the actual association mutex. This will protect all the assoiciation
@@ -398,28 +436,38 @@
  */
 
 #define SCTP_TCB_LOCK_INIT(_tcb) \
-	(void)pthread_mutex_init(&(_tcb)->tcb_mtx, NULL)
-
+	(void)pthread_mutex_init(&(_tcb)->tcb_mtx, &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_TCB_LOCK_DESTROY(_tcb) \
 	(void)pthread_mutex_destroy(&(_tcb)->tcb_mtx)
-
+#ifdef INVARIANTS
 #ifdef SCTP_LOCK_LOGGING
-#define SCTP_TCB_LOCK(_tcb)  do {					\
-	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB);		\
-	(void)pthread_mutex_lock(&(_tcb)->tcb_mtx);			\
+#define SCTP_TCB_LOCK(_tcb) do {									\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) 				\
+		sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB);					\
+	KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__))	\
 } while (0)
-
 #else
-#define SCTP_TCB_LOCK(_tcb)  do {					\
-	(void)pthread_mutex_lock(&(_tcb)->tcb_mtx);			\
-} while (0)
+#define SCTP_TCB_LOCK(_tcb) \
+	KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__))
 #endif
-
-#define SCTP_TCB_TRYLOCK(_tcb) 	(!(pthread_mutex_trylock(&(_tcb)->tcb_mtx)))
-
-#define SCTP_TCB_UNLOCK(_tcb)	(void)pthread_mutex_unlock(&(_tcb)->tcb_mtx)
-
-#define SCTP_TCB_LOCK_ASSERT(_tcb)
+#define SCTP_TCB_UNLOCK(_tcb) \
+	KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx not locked", __func__))
+#else
+#ifdef SCTP_LOCK_LOGGING
+#define SCTP_TCB_LOCK(_tcb) do {						\
+	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) 	\
+		sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB);		\
+	(void)pthread_mutex_lock(&(_tcb)->tcb_mtx);				\
+} while (0)
+#else
+#define SCTP_TCB_LOCK(_tcb) \
+	(void)pthread_mutex_lock(&(_tcb)->tcb_mtx)
+#endif
+#define SCTP_TCB_UNLOCK(_tcb) (void)pthread_mutex_unlock(&(_tcb)->tcb_mtx)
+#endif
+#define SCTP_TCB_LOCK_ASSERT(_tcb) \
+	KASSERT(pthread_mutex_trylock(&(_tcb)->tcb_mtx) == EBUSY, ("%s: tcb_mtx not locked", __func__))
+#define SCTP_TCB_TRYLOCK(_tcb) (!(pthread_mutex_trylock(&(_tcb)->tcb_mtx)))
 #endif
 
 #endif /* SCTP_PER_SOCKET_LOCKING */
@@ -434,29 +482,36 @@
 #define SCTP_INP_READ_CONTENDED(_inp) (0) /* Don't know if this is possible */
 #define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */
 
-
 /* socket locks */
 
-#if defined(__Userspace__)
 #if defined(__Userspace_os_Windows)
 #define SOCKBUF_LOCK_ASSERT(_so_buf)
-#define SOCKBUF_LOCK(_so_buf) EnterCriticalSection(&(_so_buf)->sb_mtx)
-#define SOCKBUF_UNLOCK(_so_buf) LeaveCriticalSection(&(_so_buf)->sb_mtx)
-#define SOCK_LOCK(_so)  SOCKBUF_LOCK(&(_so)->so_rcv)
-#define SOCK_UNLOCK(_so)  SOCKBUF_UNLOCK(&(_so)->so_rcv)
+#define SOCKBUF_LOCK(_so_buf) \
+	EnterCriticalSection(&(_so_buf)->sb_mtx)
+#define SOCKBUF_UNLOCK(_so_buf) \
+	LeaveCriticalSection(&(_so_buf)->sb_mtx)
+#define SOCK_LOCK(_so) \
+	SOCKBUF_LOCK(&(_so)->so_rcv)
+#define SOCK_UNLOCK(_so) \
+	SOCKBUF_UNLOCK(&(_so)->so_rcv)
 #else
-#define SOCKBUF_LOCK_ASSERT(_so_buf) KASSERT(pthread_mutex_trylock(SOCKBUF_MTX(_so_buf)) == EBUSY, ("%s: socket buffer not locked", __func__))
-#define SOCKBUF_LOCK(_so_buf)   pthread_mutex_lock(SOCKBUF_MTX(_so_buf))
-#define SOCKBUF_UNLOCK(_so_buf) pthread_mutex_unlock(SOCKBUF_MTX(_so_buf))
-#define	SOCK_LOCK(_so)		SOCKBUF_LOCK(&(_so)->so_rcv)
-#define	SOCK_UNLOCK(_so)	SOCKBUF_UNLOCK(&(_so)->so_rcv)
+#define SOCKBUF_LOCK_ASSERT(_so_buf) \
+	KASSERT(pthread_mutex_trylock(SOCKBUF_MTX(_so_buf)) == EBUSY, ("%s: socket buffer not locked", __func__))
+#ifdef INVARIANTS
+#define SOCKBUF_LOCK(_so_buf) \
+	KASSERT(pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) == 0, ("%s: sockbuf_mtx already locked", __func__))
+#define SOCKBUF_UNLOCK(_so_buf) \
+	KASSERT(pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) == 0, ("%s: sockbuf_mtx not locked", __func__))
+#else
+#define SOCKBUF_LOCK(_so_buf) \
+	pthread_mutex_lock(SOCKBUF_MTX(_so_buf))
+#define SOCKBUF_UNLOCK(_so_buf) \
+	pthread_mutex_unlock(SOCKBUF_MTX(_so_buf))
 #endif
-#else
-#define SOCK_LOCK(_so)
-#define SOCK_UNLOCK(_so)
-#define SOCKBUF_LOCK(_so_buf)
-#define SOCKBUF_UNLOCK(_so_buf)
-#define SOCKBUF_LOCK_ASSERT(_so_buf)
+#define SOCK_LOCK(_so) \
+	SOCKBUF_LOCK(&(_so)->so_rcv)
+#define SOCK_UNLOCK(_so) \
+	SOCKBUF_UNLOCK(&(_so)->so_rcv)
 #endif
 
 #define SCTP_STATLOG_INIT_LOCK()
@@ -470,18 +525,12 @@
 	InitializeCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx))
 #define SCTP_IPI_ADDR_DESTROY() \
 	DeleteCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx))
-
-#define SCTP_IPI_ADDR_RLOCK() 						\
-	do { 								\
-		EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx));	\
-	} while (0)
+#define SCTP_IPI_ADDR_RLOCK() \
+	EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx))
 #define SCTP_IPI_ADDR_RUNLOCK() \
 	LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx))
-
-#define SCTP_IPI_ADDR_WLOCK() 						\
-	do { 								\
-		EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx));	\
-	} while (0)
+#define SCTP_IPI_ADDR_WLOCK() \
+	EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx))
 #define SCTP_IPI_ADDR_WUNLOCK() \
 	LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx))
 
@@ -489,154 +538,122 @@
 /* iterator locks */
 #define SCTP_ITERATOR_LOCK_INIT() \
 	InitializeCriticalSection(&sctp_it_ctl.it_mtx)
-
-#define SCTP_ITERATOR_LOCK() 						\
-	do {								\
-		EnterCriticalSection(&sctp_it_ctl.it_mtx);		\
-	} while (0)
-
+#define SCTP_ITERATOR_LOCK_DESTROY() \
+	DeleteCriticalSection(&sctp_it_ctl.it_mtx)
+#define SCTP_ITERATOR_LOCK() \
+		EnterCriticalSection(&sctp_it_ctl.it_mtx)
 #define SCTP_ITERATOR_UNLOCK() \
 	LeaveCriticalSection(&sctp_it_ctl.it_mtx)
 
-#define SCTP_ITERATOR_LOCK_DESTROY() \
-	DeleteCriticalSection(&sctp_it_ctl.it_mtx)
-
-
 #define SCTP_IPI_ITERATOR_WQ_INIT() \
 	InitializeCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx)
-
 #define SCTP_IPI_ITERATOR_WQ_DESTROY() \
 	DeleteCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx)
-
 #define SCTP_IPI_ITERATOR_WQ_LOCK() \
-	do { \
-		EnterCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx); \
-	} while (0)
-
+	EnterCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx)
 #define SCTP_IPI_ITERATOR_WQ_UNLOCK() \
 	LeaveCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx)
 
 #else /* end of __Userspace_os_Windows */
 /* address list locks */
 #define SCTP_IPI_ADDR_INIT() \
-	(void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_addr_mtx), NULL)
+	(void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_addr_mtx), &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_IPI_ADDR_DESTROY() \
 	(void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_addr_mtx))
-
-#define SCTP_IPI_ADDR_RLOCK() 						\
-	do { 								\
-		(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx));	\
-	} while (0)
+#ifdef INVARIANTS
+#define SCTP_IPI_ADDR_RLOCK() \
+	KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx already locked", __func__))
+#define SCTP_IPI_ADDR_RUNLOCK() \
+	KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx not locked", __func__))
+#define SCTP_IPI_ADDR_WLOCK() \
+	KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx already locked", __func__))
+#define SCTP_IPI_ADDR_WUNLOCK() \
+	KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx not locked", __func__))
+#else
+#define SCTP_IPI_ADDR_RLOCK() \
+	(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx))
 #define SCTP_IPI_ADDR_RUNLOCK() \
 	(void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx))
-
-#define SCTP_IPI_ADDR_WLOCK() 						\
-	do { 								\
-		(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx));	\
-	} while (0)
+#define SCTP_IPI_ADDR_WLOCK() \
+	(void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx))
 #define SCTP_IPI_ADDR_WUNLOCK() \
 	(void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx))
-
+#endif
 
 /* iterator locks */
 #define SCTP_ITERATOR_LOCK_INIT() \
-	(void)pthread_mutex_init(&sctp_it_ctl.it_mtx, NULL)
-
-#define SCTP_ITERATOR_LOCK() 						\
-	do {								\
-		(void)pthread_mutex_lock(&sctp_it_ctl.it_mtx);		\
-	} while (0)
-
-#define SCTP_ITERATOR_UNLOCK() \
-	(void)pthread_mutex_unlock(&sctp_it_ctl.it_mtx)
-
+	(void)pthread_mutex_init(&sctp_it_ctl.it_mtx, &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_ITERATOR_LOCK_DESTROY() \
 	(void)pthread_mutex_destroy(&sctp_it_ctl.it_mtx)
-
+#ifdef INVARIANTS
+#define SCTP_ITERATOR_LOCK() \
+	KASSERT(pthread_mutex_lock(&sctp_it_ctl.it_mtx) == 0, ("%s: it_mtx already locked", __func__))
+#define SCTP_ITERATOR_UNLOCK() \
+	KASSERT(pthread_mutex_unlock(&sctp_it_ctl.it_mtx) == 0, ("%s: it_mtx not locked", __func__))
+#else
+#define SCTP_ITERATOR_LOCK() \
+	(void)pthread_mutex_lock(&sctp_it_ctl.it_mtx)
+#define SCTP_ITERATOR_UNLOCK() \
+	(void)pthread_mutex_unlock(&sctp_it_ctl.it_mtx)
+#endif
 
 #define SCTP_IPI_ITERATOR_WQ_INIT() \
-	(void)pthread_mutex_init(&sctp_it_ctl.ipi_iterator_wq_mtx, NULL)
-
+	(void)pthread_mutex_init(&sctp_it_ctl.ipi_iterator_wq_mtx, &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_IPI_ITERATOR_WQ_DESTROY() \
 	(void)pthread_mutex_destroy(&sctp_it_ctl.ipi_iterator_wq_mtx)
-
+#ifdef INVARIANTS
 #define SCTP_IPI_ITERATOR_WQ_LOCK() \
-	do { \
-		(void)pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx); \
-	} while (0)
-
+	KASSERT(pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s: ipi_iterator_wq_mtx already locked", __func__))
+#define SCTP_IPI_ITERATOR_WQ_UNLOCK() \
+	KASSERT(pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s: ipi_iterator_wq_mtx not locked", __func__))
+#else
+#define SCTP_IPI_ITERATOR_WQ_LOCK() \
+	(void)pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx)
 #define SCTP_IPI_ITERATOR_WQ_UNLOCK() \
 	(void)pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx)
 #endif
+#endif
 
 #define SCTP_INCR_EP_COUNT() \
-	do { \
-		atomic_add_int(&SCTP_BASE_INFO(ipi_count_ep), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_ep), 1)
 
 #define SCTP_DECR_EP_COUNT() \
-	do { \
-	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_ep), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_ep), 1)
 
 #define SCTP_INCR_ASOC_COUNT() \
-	do { \
-	       atomic_add_int(&SCTP_BASE_INFO(ipi_count_asoc), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_asoc), 1)
 
 #define SCTP_DECR_ASOC_COUNT() \
-	do { \
-	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_asoc), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_asoc), 1)
 
 #define SCTP_INCR_LADDR_COUNT() \
-	do { \
-	       atomic_add_int(&SCTP_BASE_INFO(ipi_count_laddr), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_laddr), 1)
 
 #define SCTP_DECR_LADDR_COUNT() \
-	do { \
-	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_laddr), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_laddr), 1)
 
 #define SCTP_INCR_RADDR_COUNT() \
-	do { \
- 	       atomic_add_int(&SCTP_BASE_INFO(ipi_count_raddr), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_raddr), 1)
 
 #define SCTP_DECR_RADDR_COUNT() \
-	do { \
- 	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_raddr), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_raddr), 1)
 
 #define SCTP_INCR_CHK_COUNT() \
-	do { \
-  	       atomic_add_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_chunk), 1)
 
 #define SCTP_DECR_CHK_COUNT() \
-	do { \
-  	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1)
 
 #define SCTP_INCR_READQ_COUNT() \
-	do { \
-	       atomic_add_int(&SCTP_BASE_INFO(ipi_count_readq), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_readq), 1)
 
 #define SCTP_DECR_READQ_COUNT() \
-	do { \
-	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_readq), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_readq), 1)
 
 #define SCTP_INCR_STRMOQ_COUNT() \
-	do { \
-	       atomic_add_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1); \
-	} while (0)
+	atomic_add_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1)
 
 #define SCTP_DECR_STRMOQ_COUNT() \
-	do { \
-	       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1); \
-	} while (0)
+	atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1)
 
 #endif
diff --git a/usrsctplib/netinet/sctp_sha1.c b/usrsctplib/netinet/sctp_sha1.c
index c86517f..aba6160 100755
--- a/usrsctplib/netinet/sctp_sha1.c
+++ b/usrsctplib/netinet/sctp_sha1.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2013, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_sha1.h b/usrsctplib/netinet/sctp_sha1.h
index 01e3c2e..6d6a05c 100755
--- a/usrsctplib/netinet/sctp_sha1.h
+++ b/usrsctplib/netinet/sctp_sha1.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_ss_functions.c b/usrsctplib/netinet/sctp_ss_functions.c
index b609ca5..f198257 100755
--- a/usrsctplib/netinet/sctp_ss_functions.c
+++ b/usrsctplib/netinet/sctp_ss_functions.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved.
  * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2010-2012, by Robin Seggelmann. All rights reserved.
@@ -28,7 +30,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 321289 2017-07-20 11:09:33Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 326180 2017-11-24 19:38:59Z tuexen $");
 #endif
 
 #include <netinet/sctp_pcb.h>
diff --git a/usrsctplib/netinet/sctp_structs.h b/usrsctplib/netinet/sctp_structs.h
index b5f3ef2..543d386 100755
--- a/usrsctplib/netinet/sctp_structs.h
+++ b/usrsctplib/netinet/sctp_structs.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 310590 2016-12-26 11:06:41Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 325370 2017-11-03 20:46:12Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_STRUCTS_H_
@@ -1155,6 +1157,7 @@
 	uint32_t chunks_on_out_queue;	/* total chunks floating around,
 					 * locked by send socket buffer */
 	uint32_t peers_adaptation;
+	uint32_t default_mtu;
 	uint16_t peer_hmac_id;	/* peer HMAC id to send */
 
 	/*
diff --git a/usrsctplib/netinet/sctp_sysctl.c b/usrsctplib/netinet/sctp_sysctl.c
index 1846475..59b22e4 100755
--- a/usrsctplib/netinet/sctp_sysctl.c
+++ b/usrsctplib/netinet/sctp_sysctl.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 318958 2017-05-26 16:29:00Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 323505 2017-09-12 21:08:50Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -629,11 +631,27 @@
 				xraddr.rtt = net->rtt / 1000;
 				xraddr.heartbeat_interval = net->heart_beat_delay;
 				xraddr.ssthresh = net->ssthresh;
+				xraddr.encaps_port = net->port;
+				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
+					xraddr.state = SCTP_UNCONFIRMED;
+				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
+					xraddr.state = SCTP_ACTIVE;
+				} else {
+					xraddr.state = SCTP_INACTIVE;
+				}
 #endif
 #else
 				xraddr.rtt = net->rtt / 1000;
 				xraddr.heartbeat_interval = net->heart_beat_delay;
 				xraddr.ssthresh = net->ssthresh;
+				xraddr.encaps_port = net->port;
+				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
+					xraddr.state = SCTP_UNCONFIRMED;
+				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
+					xraddr.state = SCTP_ACTIVE;
+				} else {
+					xraddr.state = SCTP_INACTIVE;
+				}
 #endif
 				xraddr.start_time.tv_sec = (uint32_t)net->start_time.tv_sec;
 				xraddr.start_time.tv_usec = (uint32_t)net->start_time.tv_usec;
diff --git a/usrsctplib/netinet/sctp_sysctl.h b/usrsctplib/netinet/sctp_sysctl.h
index cbd29e3..22ae57e 100755
--- a/usrsctplib/netinet/sctp_sysctl.h
+++ b/usrsctplib/netinet/sctp_sysctl.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_timer.c b/usrsctplib/netinet/sctp_timer.c
index 9507c71..426ba44 100755
--- a/usrsctplib/netinet/sctp_timer.c
+++ b/usrsctplib/netinet/sctp_timer.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_timer.h b/usrsctplib/netinet/sctp_timer.h
index a519bb6..822d5b4 100755
--- a/usrsctplib/netinet/sctp_timer.h
+++ b/usrsctplib/netinet/sctp_timer.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctp_uio.h b/usrsctplib/netinet/sctp_uio.h
index c46989b..956d754 100755
--- a/usrsctplib/netinet/sctp_uio.h
+++ b/usrsctplib/netinet/sctp_uio.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_uio.h 309607 2016-12-06 10:21:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_uio.h 323505 2017-09-12 21:08:50Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_UIO_H_
@@ -1306,13 +1308,17 @@
 	uint32_t rtt;
 	uint32_t heartbeat_interval;
 	uint32_t ssthresh;
-	uint32_t extra_padding[30];              /* future */
+	uint16_t encaps_port;
+	uint16_t state;
+	uint32_t extra_padding[29];              /* future */
 #endif
 #else
 	uint32_t rtt;
 	uint32_t heartbeat_interval;
 	uint32_t ssthresh;
-	uint32_t extra_padding[30];              /* future */
+	uint16_t encaps_port;
+	uint16_t state;
+	uint32_t extra_padding[29];              /* future */
 #endif
 };
 
diff --git a/usrsctplib/netinet/sctp_usrreq.c b/usrsctplib/netinet/sctp_usrreq.c
index 619eee5..0325571 100755
--- a/usrsctplib/netinet/sctp_usrreq.c
+++ b/usrsctplib/netinet/sctp_usrreq.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 325370 2017-11-03 20:46:12Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -170,7 +172,7 @@
 static void
 sctp_finish(void *unused __unused)
 {
-         sctp_pcb_finish();
+	sctp_pcb_finish();
 }
 VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL);
 #endif
@@ -356,6 +358,10 @@
 #endif
 		/* no need to unlock here, since the TCB is gone */
 	} else if (icmp_code == ICMP_UNREACH_NEEDFRAG) {
+		if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) {
+			SCTP_TCB_UNLOCK(stcb);
+			return;
+		}
 		/* Find the next (smaller) MTU */
 		if (next_mtu == 0) {
 			/*
@@ -1253,7 +1259,7 @@
 int
 sctp_flush(struct socket *so, int how)
 {
-        /*
+	/*
 	 * We will just clear out the values and let
 	 * subsequent close clear out the data, if any.
 	 * Note if the user did a shutdown(SHUT_RD) they
@@ -1274,7 +1280,7 @@
 		return (0);
 	}
 	SCTP_INP_RUNLOCK(inp);
-        if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
+	if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
 		/* First make sure the sb will be happy, we don't
 		 * use these except maybe the count
 		 */
@@ -1287,7 +1293,7 @@
 		so->so_rcv.sb_mbcnt = 0;
 		so->so_rcv.sb_mb = NULL;
 	}
-        if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
+	if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
 		/* First make sure the sb will be happy, we don't
 		 * use these except maybe the count
 		 */
@@ -1320,7 +1326,9 @@
 		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
 		SOCKBUF_UNLOCK(&so->so_rcv);
 #else
+		SOCK_LOCK(so);
 		so->so_state &= ~SS_CANTRCVMORE;
+		SOCK_UNLOCK(so);
 #endif
 		/* This proc will wakeup for read and do nothing (I hope) */
 		SCTP_INP_RUNLOCK(inp);
@@ -2557,6 +2565,7 @@
 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
 		} else {
 			id->assoc_value = stcb->asoc.vrf_id;
+			SCTP_TCB_UNLOCK(stcb);
 			*optsize = sizeof(struct sctp_assoc_value);
 		}
 		break;
@@ -3060,7 +3069,12 @@
 #endif
 #ifdef INET6
 				case AF_INET6:
-					paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
+					paddrp->spp_pathmtu -= SCTP_MIN_OVERHEAD;
+					break;
+#endif
+#if defined(__Userspace__)
+				case AF_CONN:
+					paddrp->spp_pathmtu -= sizeof(struct sctphdr);
 					break;
 #endif
 				default:
@@ -3095,7 +3109,7 @@
 				 * value
 				 */
 				paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
-				paddrp->spp_pathmtu = 0;
+				paddrp->spp_pathmtu = stcb->asoc.default_mtu;
 				if (stcb->asoc.default_dscp & 0x01) {
 					paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
 					paddrp->spp_flags |= SPP_DSCP;
@@ -3142,8 +3156,7 @@
 					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
 				}
 #endif
-				/* can't return this */
-				paddrp->spp_pathmtu = 0;
+				paddrp->spp_pathmtu = inp->sctp_ep.default_mtu;
 
 				if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
 					paddrp->spp_flags |= SPP_HB_ENABLE;
@@ -3237,6 +3250,11 @@
 				paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD;
 				break;
 #endif
+#if defined(__Userspace__)
+			case AF_CONN:
+				paddri->spinfo_mtu -= sizeof(struct sctphdr);
+				break;
+#endif
 			default:
 				break;
 			}
@@ -3246,7 +3264,7 @@
 			if (stcb != NULL) {
 				SCTP_TCB_UNLOCK(stcb);
 			}
-		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
+			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
 			error = ENOENT;
 		}
 		break;
@@ -3334,6 +3352,11 @@
 			sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD;
 			break;
 #endif
+#if defined(__Userspace__)
+		case AF_CONN:
+			sstat->sstat_primary.spinfo_mtu -= sizeof(struct sctphdr);
+			break;
+#endif
 		default:
 			break;
 		}
@@ -3740,7 +3763,6 @@
 		if (event_type > 0) {
 			if (stcb) {
 				event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
-				SCTP_TCB_UNLOCK(stcb);
 			} else {
 				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
 				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
@@ -3754,6 +3776,9 @@
 				}
 			}
 		}
+		if (stcb != NULL) {
+			SCTP_TCB_UNLOCK(stcb);
+		}
 		if (error == 0) {
 			*optsize = sizeof(struct sctp_event);
 		}
@@ -4346,12 +4371,16 @@
 			sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
 			sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
 #endif
-			SCTP_TCB_UNLOCK(stcb);
-			*optsize = sizeof(struct sctp_prstatus);
 		} else {
 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 			error = EINVAL;
 		}
+		if (stcb != NULL) {
+			SCTP_TCB_UNLOCK(stcb);
+		}
+		if (error == 0) {
+			*optsize = sizeof(struct sctp_prstatus);
+		}
 		break;
 	}
 	case SCTP_PR_ASSOC_STATUS:
@@ -4374,12 +4403,16 @@
 				sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy];
 				sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy];
 			}
-			SCTP_TCB_UNLOCK(stcb);
-			*optsize = sizeof(struct sctp_prstatus);
 		} else {
 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 			error = EINVAL;
 		}
+		if (stcb != NULL) {
+			SCTP_TCB_UNLOCK(stcb);
+		}
+		if (error == 0) {
+			*optsize = sizeof(struct sctp_prstatus);
+		}
 		break;
 	}
 	case SCTP_MAX_CWND:
@@ -6130,6 +6163,11 @@
 						net->mtu += SCTP_MIN_OVERHEAD;
 						break;
 #endif
+#if defined(__Userspace__)
+					case AF_CONN:
+						net->mtu += sizeof(struct sctphdr);
+						break;
+#endif
 					default:
 						break;
 					}
@@ -6273,6 +6311,11 @@
 							net->mtu += SCTP_MIN_OVERHEAD;
 							break;
 #endif
+#if defined(__Userspace__)
+						case AF_CONN:
+							net->mtu += sizeof(struct sctphdr);
+							break;
+#endif
 						default:
 							break;
 						}
@@ -6280,6 +6323,7 @@
 							sctp_pathmtu_adjustment(stcb, net->mtu);
 						}
 					}
+					stcb->asoc.default_mtu = paddrp->spp_pathmtu;
 					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
 				}
 				if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
@@ -6289,6 +6333,7 @@
 						}
 						net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
 					}
+					stcb->asoc.default_mtu = 0;
 					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
 				}
 				if (paddrp->spp_flags & SPP_DSCP) {
@@ -6346,8 +6391,12 @@
 					sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
 				}
 				if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
+					inp->sctp_ep.default_mtu = 0;
 					sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
 				} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
+					if (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU) {
+						inp->sctp_ep.default_mtu = paddrp->spp_pathmtu;
+					}
 					sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
 				}
 				if (paddrp->spp_flags & SPP_DSCP) {
@@ -6595,9 +6644,9 @@
 #else
 		error = suser(p, 0);
 #endif
-#endif
 		if (error)
 			break;
+#endif
 
 		SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
 		/* SUPER USER CHECK? */
@@ -7835,7 +7884,7 @@
 	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
 		/* Should I really unlock ? */
 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
-	        error = EFAULT;
+		error = EFAULT;
 		goto out_now;
 	}
 #ifdef INET6
@@ -8256,8 +8305,8 @@
 		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
 	}
 #endif
-	SOCK_LOCK(so);
 #if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Userspace__)
+	SOCK_LOCK(so);
 	error = solisten_proto_check(so);
 	SOCK_UNLOCK(so);
 	if (error) {
diff --git a/usrsctplib/netinet/sctp_var.h b/usrsctplib/netinet/sctp_var.h
index 9922685..860eceb 100755
--- a/usrsctplib/netinet/sctp_var.h
+++ b/usrsctplib/netinet/sctp_var.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/netinet/sctputil.c b/usrsctplib/netinet/sctputil.c
index 88cc6d4..2e404eb 100755
--- a/usrsctplib/netinet/sctputil.c
+++ b/usrsctplib/netinet/sctputil.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 326163 2017-11-24 12:18:48Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -1110,6 +1112,7 @@
 	asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
 	asoc->initial_rto = inp->sctp_ep.initial_rto;
 
+	asoc->default_mtu = inp->sctp_ep.default_mtu;
 	asoc->max_init_times = inp->sctp_ep.max_init_times;
 	asoc->max_send_times = inp->sctp_ep.max_send_times;
 	asoc->def_net_failure = inp->sctp_ep.def_net_failure;
@@ -1558,13 +1561,11 @@
 	LIST_INIT(&asc->list_of_work);
 	asc->cnt = 0;
 
-	SCTP_WQ_ADDR_LOCK();
 	LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
 		LIST_REMOVE(wi, sctp_nxt_addr);
 		LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
 		asc->cnt++;
 	}
-	SCTP_WQ_ADDR_UNLOCK();
 
 	if (asc->cnt == 0) {
 		SCTP_FREE(asc, SCTP_M_ASC_IT);
@@ -1585,11 +1586,9 @@
 			if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
 				sctp_asconf_iterator_end(asc, 0);
 			} else {
-				SCTP_WQ_ADDR_LOCK();
 				LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
 					LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
 				}
-				SCTP_WQ_ADDR_UNLOCK();
 				SCTP_FREE(asc, SCTP_M_ASC_IT);
 			}
 		}
@@ -1666,8 +1665,7 @@
 		     (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) &&
 		     (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) &&
 		     (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) &&
-		     (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))
-			) {
+		     (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))) {
 			SCTP_INP_DECR_REF(inp);
 #if defined(__FreeBSD__) && __FreeBSD_version >= 801000
 			CURVNET_RESTORE();
@@ -1721,6 +1719,12 @@
 #endif
 			return;
 		}
+	} else if (inp != NULL) {
+		if (type != SCTP_TIMER_TYPE_INPKILL) {
+			SCTP_INP_WLOCK(inp);
+		}
+	} else {
+		SCTP_WQ_ADDR_LOCK();
 	}
 	/* record in stopped what t-o occurred */
 	tmr->stopped_from = type;
@@ -1742,22 +1746,6 @@
 
 	/* call the handler for the appropriate timer type */
 	switch (type) {
-	case SCTP_TIMER_TYPE_ZERO_COPY:
-		if (inp == NULL) {
-			break;
-		}
-		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
-			SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
-		}
-		break;
-	case SCTP_TIMER_TYPE_ZCOPY_SENDQ:
-		if (inp == NULL) {
-			break;
-		}
-		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
-		    SCTP_ZERO_COPY_SENDQ_EVENT(inp, inp->sctp_socket);
-		}
-                break;
 	case SCTP_TIMER_TYPE_ADDR_WQ:
 		sctp_handle_addr_wq();
 		break;
@@ -1884,7 +1872,6 @@
 			}
 			SCTP_STAT_INCR(sctps_timosecret);
 			(void)SCTP_GETTIME_TIMEVAL(&tv);
-			SCTP_INP_WLOCK(inp);
 			inp->sctp_ep.time_of_secret_change = tv.tv_sec;
 			inp->sctp_ep.last_secret_number =
 			    inp->sctp_ep.current_secret_number;
@@ -1898,7 +1885,6 @@
 				inp->sctp_ep.secret_key[secret][i] =
 				    sctp_select_initial_TSN(&inp->sctp_ep);
 			}
-			SCTP_INP_WUNLOCK(inp);
 			sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net);
 		}
 		did_output = 0;
@@ -2052,6 +2038,10 @@
 get_out:
 	if (stcb) {
 		SCTP_TCB_UNLOCK(stcb);
+	} else if (inp != NULL) {
+		SCTP_INP_WUNLOCK(inp);
+	} else {
+		SCTP_WQ_ADDR_UNLOCK();
 	}
 
 out_decr:
@@ -2081,14 +2071,6 @@
 		SCTP_TCB_LOCK_ASSERT(stcb);
 	}
 	switch (t_type) {
-	case SCTP_TIMER_TYPE_ZERO_COPY:
-		tmr = &inp->sctp_ep.zero_copy_timer;
-		to_ticks = SCTP_ZERO_COPY_TICK_DELAY;
-		break;
-	case SCTP_TIMER_TYPE_ZCOPY_SENDQ:
-		tmr = &inp->sctp_ep.zero_copy_sendq_timer;
-		to_ticks = SCTP_ZERO_COPY_SENDQ_TICK_DELAY;
-		break;
 	case SCTP_TIMER_TYPE_ADDR_WQ:
 		/* Only 1 tick away :-) */
 		tmr = &SCTP_BASE_INFO(addr_wq_timer);
@@ -2374,12 +2356,6 @@
 		SCTP_TCB_LOCK_ASSERT(stcb);
 	}
 	switch (t_type) {
-	case SCTP_TIMER_TYPE_ZERO_COPY:
-		tmr = &inp->sctp_ep.zero_copy_timer;
-		break;
-	case SCTP_TIMER_TYPE_ZCOPY_SENDQ:
-		tmr = &inp->sctp_ep.zero_copy_sendq_timer;
-		break;
 	case SCTP_TIMER_TYPE_ADDR_WQ:
 		tmr = &SCTP_BASE_INFO(addr_wq_timer);
 		break;
@@ -2571,8 +2547,8 @@
 sctp_calculate_rto(struct sctp_tcb *stcb,
 		   struct sctp_association *asoc,
 		   struct sctp_nets *net,
-		   struct timeval *told,
-		   int safe, int rtt_from_sack)
+		   struct timeval *old,
+		   int rtt_from_sack)
 {
 	/*-
 	 * given an association and the starting time of the current RTT
@@ -2581,19 +2557,8 @@
 	int32_t rtt; /* RTT in ms */
 	uint32_t new_rto;
 	int first_measure = 0;
-	struct timeval now, then, *old;
+	struct timeval now;
 
-	/* Copy it out for sparc64 */
-	if (safe == sctp_align_unsafe_makecopy) {
-		old = &then;
-		memcpy(&then, told, sizeof(struct timeval));
-	} else if (safe == sctp_align_safe_nocopy) {
-		old = told;
-	} else {
-		/* error */
-		SCTP_PRINTF("Huh, bad rto calc call\n");
-		return (0);
-	}
 	/************************/
 	/* 1. calculate new RTT */
 	/************************/
@@ -4675,17 +4640,18 @@
 	struct sctp_queued_to_read *control, *nctl;
 	struct sctp_readhead tmp_queue;
 	struct mbuf *m;
+#if defined(__FreeBSD__) || defined(__APPLE__)
 	int error = 0;
+#endif
 
 	old_so = old_inp->sctp_socket;
 	new_so = new_inp->sctp_socket;
 	TAILQ_INIT(&tmp_queue);
+#if defined(__FreeBSD__) || defined(__APPLE__)
 #if defined(__FreeBSD__) && __FreeBSD_version < 700000
 	SOCKBUF_LOCK(&(old_so->so_rcv));
 #endif
-#if defined(__FreeBSD__) || defined(__APPLE__)
 	error = sblock(&old_so->so_rcv, waitflags);
-#endif
 #if defined(__FreeBSD__) && __FreeBSD_version < 700000
 	SOCKBUF_UNLOCK(&(old_so->so_rcv));
 #endif
@@ -4702,6 +4668,7 @@
 		 */
 		return;
 	}
+#endif
 	/* lock the socket buffers */
 	SCTP_INP_READ_LOCK(old_inp);
 	TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) {
@@ -4767,36 +4734,32 @@
 )
 {
 	if ((inp != NULL) && (inp->sctp_socket != NULL)) {
-		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
-			SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
-		} else {
 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-			struct socket *so;
+		struct socket *so;
 
-			so = SCTP_INP_SO(inp);
-			if (!so_locked) {
-				if (stcb) {
-					atomic_add_int(&stcb->asoc.refcnt, 1);
-					SCTP_TCB_UNLOCK(stcb);
-				}
-				SCTP_SOCKET_LOCK(so, 1);
-				if (stcb) {
-					SCTP_TCB_LOCK(stcb);
-					atomic_subtract_int(&stcb->asoc.refcnt, 1);
-				}
-				if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
-					SCTP_SOCKET_UNLOCK(so, 1);
-					return;
-				}
+		so = SCTP_INP_SO(inp);
+		if (!so_locked) {
+			if (stcb) {
+				atomic_add_int(&stcb->asoc.refcnt, 1);
+				SCTP_TCB_UNLOCK(stcb);
 			}
-#endif
-			sctp_sorwakeup(inp, inp->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-			if (!so_locked) {
+			SCTP_SOCKET_LOCK(so, 1);
+			if (stcb) {
+				SCTP_TCB_LOCK(stcb);
+				atomic_subtract_int(&stcb->asoc.refcnt, 1);
+			}
+			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
 				SCTP_SOCKET_UNLOCK(so, 1);
+				return;
 			}
-#endif
 		}
+#endif
+		sctp_sorwakeup(inp, inp->sctp_socket);
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+		if (!so_locked) {
+			SCTP_SOCKET_UNLOCK(so, 1);
+		}
+#endif
 	}
 }
 #if defined(__Userspace__)
@@ -5128,14 +5091,14 @@
 		stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
 		stcb->asoc.strmout[sid].abandoned_sent[0]++;
 #if defined(SCTP_DETAILED_STR_STATS)
-		stcb->asoc.strmout[stream].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
+		stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
 #endif
 	} else {
 		stcb->asoc.abandoned_unsent[0]++;
 		stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
 		stcb->asoc.strmout[sid].abandoned_unsent[0]++;
 #if defined(SCTP_DETAILED_STR_STATS)
-		stcb->asoc.strmout[stream].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
+		stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
 #endif
 	}
 	do {
@@ -6775,11 +6738,11 @@
 	 * newest first :-0
 	 */
 	LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
-	SCTP_WQ_ADDR_UNLOCK();
 	sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
 			 (struct sctp_inpcb *)NULL,
 			 (struct sctp_tcb *)NULL,
 			 (struct sctp_nets *)NULL);
+	SCTP_WQ_ADDR_UNLOCK();
 	return (0);
 }
 
diff --git a/usrsctplib/netinet/sctputil.h b/usrsctplib/netinet/sctputil.h
index 59dd364..69fe484 100755
--- a/usrsctplib/netinet/sctputil.h
+++ b/usrsctplib/netinet/sctputil.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 320260 2017-06-23 08:34:01Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 324615 2017-10-14 10:02:59Z tuexen $");
 #endif
 
 #ifndef _NETINET_SCTP_UTIL_H_
@@ -144,7 +146,7 @@
 
 uint32_t
 sctp_calculate_rto(struct sctp_tcb *, struct sctp_association *,
-    struct sctp_nets *, struct timeval *, int, int);
+    struct sctp_nets *, struct timeval *, int);
 
 uint32_t sctp_calculate_len(struct mbuf *);
 
diff --git a/usrsctplib/netinet6/sctp6_usrreq.c b/usrsctplib/netinet6/sctp6_usrreq.c
index 1c9bbd9..752f52b 100644
--- a/usrsctplib/netinet6/sctp6_usrreq.c
+++ b/usrsctplib/netinet6/sctp6_usrreq.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
@@ -32,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 321204 2017-07-19 14:28:58Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 325370 2017-11-03 20:46:12Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
@@ -396,6 +398,10 @@
 		}
 		break;
 	case ICMP6_PACKET_TOO_BIG:
+		if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) {
+			SCTP_TCB_UNLOCK(stcb);
+			break;
+		}
 		if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
 			timer_stopped = 1;
 			sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
@@ -1247,7 +1253,7 @@
 	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
 		if (stcb) {
-			SCTP_TCB_UNLOCK(stcb);
+			SCTP_TCB_LOCK(stcb);
 		}
 		SCTP_INP_RUNLOCK(inp);
 	} else {
diff --git a/usrsctplib/netinet6/sctp6_var.h b/usrsctplib/netinet6/sctp6_var.h
index 2dca684..a962b12 100755
--- a/usrsctplib/netinet6/sctp6_var.h
+++ b/usrsctplib/netinet6/sctp6_var.h
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
diff --git a/usrsctplib/user_environment.c b/usrsctplib/user_environment.c
index 6830a23..767c4ba 100755
--- a/usrsctplib/user_environment.c
+++ b/usrsctplib/user_environment.c
@@ -60,22 +60,20 @@
  */
 userland_mutex_t atomic_mtx;
 
-/* Source: /usr/src/sys/dev/random/harvest.c */
-static int read_random_phony(void *, int);
-
-static int (*read_func)(void *, int) = read_random_phony;
-
-/* Userland-visible version of read_random */
-int
-read_random(void *buf, int count)
-{
-	return ((*read_func)(buf, count));
-}
-
 /* If the entropy device is not loaded, make a token effort to
  * provide _some_ kind of randomness. This should only be used
  * inside other RNG's, like arc4random(9).
  */
+#if defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_Darwin)
+static int
+read_random_phony(void *buf, int count)
+{
+	if (count >= 0) {
+		arc4random_buf(buf, count);
+	}
+	return (count);
+}
+#else
 static int
 read_random_phony(void *buf, int count)
 {
@@ -93,4 +91,14 @@
 
 	return (count);
 }
+#endif
+
+static int (*read_func)(void *, int) = read_random_phony;
+
+/* Userland-visible version of read_random */
+int
+read_random(void *buf, int count)
+{
+	return ((*read_func)(buf, count));
+}
 
diff --git a/usrsctplib/user_environment.h b/usrsctplib/user_environment.h
index 306ff6b..6e37d07 100755
--- a/usrsctplib/user_environment.h
+++ b/usrsctplib/user_environment.h
@@ -94,17 +94,18 @@
 	abort();
 }
 
-#define panic(...)                       \
-	do {                             \
-		SCTP_PRINTF(__VA_ARGS__);\
-		SCTP_PRINTF("\n");       \
-		terminate_non_graceful();\
+#define panic(...)                                  \
+	do {                                        \
+		SCTP_PRINTF("%s(): ", __FUNCTION__);\
+		SCTP_PRINTF(__VA_ARGS__);           \
+		SCTP_PRINTF("\n");                  \
+		terminate_non_graceful();           \
 } while (0)
 
 #define KASSERT(cond, args)          \
 	do {                         \
 		if (!(cond)) {       \
-			panic args ;\
+			panic args ; \
 		}                    \
 	} while (0)
 #else
diff --git a/usrsctplib/user_mbuf.c b/usrsctplib/user_mbuf.c
index 7a1aaba..ec83931 100755
--- a/usrsctplib/user_mbuf.c
+++ b/usrsctplib/user_mbuf.c
@@ -204,41 +204,41 @@
 }
 
 
-static int clust_constructor_dup(caddr_t m_clust, struct mbuf* m)
+static void
+clust_constructor_dup(caddr_t m_clust, struct mbuf* m)
 {
 	u_int *refcnt;
 	int type, size;
 
+	if (m == NULL) {
+		return;
+	}
 	/* Assigning cluster of MCLBYTES. TODO: Add jumbo frame functionality */
 	type = EXT_CLUSTER;
 	size = MCLBYTES;
 
 	refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int);
 	/*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/
-	if (refcnt == NULL) {
 #if !defined(SCTP_SIMPLE_ALLOCATOR)
+	if (refcnt == NULL) {
 		umem_reap();
-#endif
 		refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int);
 		/*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/
 	}
+#endif
 	*refcnt = 1;
-	if (m != NULL) {
-		m->m_ext.ext_buf = (caddr_t)m_clust;
-		m->m_data = m->m_ext.ext_buf;
-		m->m_flags |= M_EXT;
-		m->m_ext.ext_free = NULL;
-		m->m_ext.ext_args = NULL;
-		m->m_ext.ext_size = size;
-		m->m_ext.ext_type = type;
-		m->m_ext.ref_cnt = refcnt;
-	}
-
-	return (0);
+	m->m_ext.ext_buf = (caddr_t)m_clust;
+	m->m_data = m->m_ext.ext_buf;
+	m->m_flags |= M_EXT;
+	m->m_ext.ext_free = NULL;
+	m->m_ext.ext_args = NULL;
+	m->m_ext.ext_size = size;
+	m->m_ext.ext_type = type;
+	m->m_ext.ref_cnt = refcnt;
+	return;
 }
 
 
-
 /* __Userspace__ */
 void
 m_clget(struct mbuf *m, int how)
diff --git a/usrsctplib/user_recv_thread.c b/usrsctplib/user_recv_thread.c
index b1a9d01..b7cb06a 100755
--- a/usrsctplib/user_recv_thread.c
+++ b/usrsctplib/user_recv_thread.c
@@ -361,13 +361,13 @@
 			i = 0;
 			SCTP_BUF_LEN(recvmbuf[0]) = iovlen;
 
-			ncounter -= iovlen;
+			ncounter -= min(ncounter, iovlen);
 			(to_fill)++;
 			do {
 				recvmbuf[i]->m_next = recvmbuf[i+1];
 				SCTP_BUF_LEN(recvmbuf[i]->m_next) = min(ncounter, iovlen);
 				i++;
-				ncounter -= iovlen;
+				ncounter -= min(ncounter, iovlen);
 				(to_fill)++;
 			} while (ncounter > 0);
 		}
@@ -564,13 +564,13 @@
 			i = 0;
 			SCTP_BUF_LEN(recvmbuf6[0]) = iovlen;
 
-			ncounter -= iovlen;
+			ncounter -= min(ncounter, iovlen);
 			(to_fill)++;
 			do {
 				recvmbuf6[i]->m_next = recvmbuf6[i+1];
 				SCTP_BUF_LEN(recvmbuf6[i]->m_next) = min(ncounter, iovlen);
 				i++;
-				ncounter -= iovlen;
+				ncounter -= min(ncounter, iovlen);
 				(to_fill)++;
 			} while (ncounter > 0);
 		}
@@ -764,13 +764,13 @@
 			i = 0;
 			SCTP_BUF_LEN(udprecvmbuf[0]) = iovlen;
 
-			ncounter -= iovlen;
+			ncounter -= min(ncounter, iovlen);
 			(to_fill)++;
 			do {
 				udprecvmbuf[i]->m_next = udprecvmbuf[i+1];
 				SCTP_BUF_LEN(udprecvmbuf[i]->m_next) = min(ncounter, iovlen);
 				i++;
-				ncounter -= iovlen;
+				ncounter -= min(ncounter, iovlen);
 				(to_fill)++;
 			} while (ncounter > 0);
 		}
@@ -978,13 +978,13 @@
 			i = 0;
 			SCTP_BUF_LEN(udprecvmbuf6[0]) = iovlen;
 
-			ncounter -= iovlen;
+			ncounter -= min(ncounter, iovlen);
 			(to_fill)++;
 			do {
 				udprecvmbuf6[i]->m_next = udprecvmbuf6[i+1];
 				SCTP_BUF_LEN(udprecvmbuf6[i]->m_next) = min(ncounter, iovlen);
 				i++;
-				ncounter -= iovlen;
+				ncounter -= min(ncounter, iovlen);
 				(to_fill)++;
 			} while (ncounter > 0);
 		}
diff --git a/usrsctplib/user_socket.c b/usrsctplib/user_socket.c
index 1f5f77f..8122e58 100755
--- a/usrsctplib/user_socket.c
+++ b/usrsctplib/user_socket.c
@@ -2436,6 +2436,121 @@
 }
 
 int
+usrsctp_opt_info(struct socket *so, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
+{
+	if (arg == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if ((id == SCTP_CURRENT_ASSOC) ||
+	    (id == SCTP_ALL_ASSOC)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	switch (opt) {
+	case SCTP_RTOINFO:
+		((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
+		break;
+	case SCTP_ASSOCINFO:
+		((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
+		break;
+	case SCTP_DEFAULT_SEND_PARAM:
+		((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
+		break;
+	case SCTP_PRIMARY_ADDR:
+		((struct sctp_setprim *)arg)->ssp_assoc_id = id;
+		break;
+	case SCTP_PEER_ADDR_PARAMS:
+		((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
+		break;
+	case SCTP_MAXSEG:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_AUTH_KEY:
+		((struct sctp_authkey *)arg)->sca_assoc_id = id;
+		break;
+	case SCTP_AUTH_ACTIVE_KEY:
+		((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
+		break;
+	case SCTP_DELAYED_SACK:
+		((struct sctp_sack_info *)arg)->sack_assoc_id = id;
+		break;
+	case SCTP_CONTEXT:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_STATUS:
+		((struct sctp_status *)arg)->sstat_assoc_id = id;
+		break;
+	case SCTP_GET_PEER_ADDR_INFO:
+		((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
+		break;
+	case SCTP_PEER_AUTH_CHUNKS:
+		((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
+		break;
+	case SCTP_LOCAL_AUTH_CHUNKS:
+		((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
+		break;
+	case SCTP_TIMEOUTS:
+		((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
+		break;
+	case SCTP_EVENT:
+		((struct sctp_event *)arg)->se_assoc_id = id;
+		break;
+	case SCTP_DEFAULT_SNDINFO:
+		((struct sctp_sndinfo *)arg)->snd_assoc_id = id;
+		break;
+	case SCTP_DEFAULT_PRINFO:
+		((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
+		break;
+	case SCTP_PEER_ADDR_THLDS:
+		((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
+		break;
+	case SCTP_REMOTE_UDP_ENCAPS_PORT:
+		((struct sctp_udpencaps *)arg)->sue_assoc_id = id;
+		break;
+	case SCTP_ECN_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_PR_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_AUTH_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_ASCONF_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_RECONFIG_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_NRSACK_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_PKTDROP_SUPPORTED:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_MAX_BURST:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_ENABLE_STREAM_RESET:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	case SCTP_PR_STREAM_STATUS:
+		((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
+		break;
+	case SCTP_PR_ASSOC_STATUS:
+		((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
+		break;
+	case SCTP_MAX_CWND:
+		((struct sctp_assoc_value *)arg)->assoc_id = id;
+		break;
+	default:
+		break;
+	}
+	return (usrsctp_getsockopt(so, IPPROTO_SCTP, opt, arg, size));
+}
+
+int
 usrsctp_set_ulpinfo(struct socket *so, void *ulp_info)
 {
 	return (register_ulp_info(so, ulp_info));
@@ -2657,9 +2772,13 @@
 				return (-1);
 			}
 #endif
+			len += sizeof(struct sockaddr_in);
+			if (len > SCTP_STACK_BUF_SIZE) {
+				errno = ENOMEM;
+				return (-1);
+			}
 			memcpy(cpto, at, sizeof(struct sockaddr_in));
 			cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
-			len += sizeof(struct sockaddr_in);
 			at = (struct sockaddr *)((caddr_t)at + sizeof(struct sockaddr_in));
 			break;
 #endif
@@ -2673,18 +2792,30 @@
 #endif
 #ifdef INET
 			if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) {
+				len += sizeof(struct sockaddr_in);
+				if (len > SCTP_STACK_BUF_SIZE) {
+					errno = ENOMEM;
+					return (-1);
+				}
 				in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at);
 				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
-				len += sizeof(struct sockaddr_in);
 			} else {
+				len += sizeof(struct sockaddr_in6);
+				if (len > SCTP_STACK_BUF_SIZE) {
+					errno = ENOMEM;
+					return (-1);
+				}
 				memcpy(cpto, at, sizeof(struct sockaddr_in6));
 				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6));
-				len += sizeof(struct sockaddr_in6);
 			}
 #else
+			len += sizeof(struct sockaddr_in6);
+			if (len > SCTP_STACK_BUF_SIZE) {
+				errno = ENOMEM;
+				return (-1);
+			}
 			memcpy(cpto, at, sizeof(struct sockaddr_in6));
 			cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6));
-			len += sizeof(struct sockaddr_in6);
 #endif
 			at = (struct sockaddr *)((caddr_t)at + sizeof(struct sockaddr_in6));
 			break;
@@ -2693,18 +2824,8 @@
 			errno = EINVAL;
 			return (-1);
 		}
-		if (len > (sizeof(buf) - sizeof(int))) {
-			/* Never enough memory */
-			errno = E2BIG;
-			return (-1);
-		}
 		cnt++;
 	}
-	/* do we have any? */
-	if (cnt == 0) {
-		errno = EINVAL;
-		return (-1);
-	}
 	aa = (int *)buf;
 	*aa = cnt;
 	ret = usrsctp_setsockopt(so, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, (socklen_t)len);
diff --git a/usrsctplib/usrsctp.h b/usrsctplib/usrsctp.h
index 6c98033..70b719a 100644
--- a/usrsctplib/usrsctp.h
+++ b/usrsctplib/usrsctp.h
@@ -898,6 +898,13 @@
                    socklen_t *option_len);
 
 int
+usrsctp_opt_info(struct socket *so,
+                 sctp_assoc_t id,
+                 int opt,
+                 void *arg,
+                 socklen_t *size);
+
+int
 usrsctp_getpaddrs(struct socket *so,
                   sctp_assoc_t id,
                   struct sockaddr **raddrs);