summaryrefslogtreecommitdiff
path: root/netwerk
diff options
context:
space:
mode:
authorBasilisk-Dev <basiliskdev@protonmail.com>2023-08-26 21:58:02 -0400
committerBasilisk-Dev <basiliskdev@protonmail.com>2023-08-26 21:58:02 -0400
commit32ef10e763fec46aff31facdf915a0216afd45f9 (patch)
tree9d62cc75e193d0db6fc4431ac7572518ea0162ce /netwerk
parentac24db13efafdd2a973cd11e70f3ad7e2e93b233 (diff)
downloaduxp-32ef10e763fec46aff31facdf915a0216afd45f9.tar.gz
Issue #2058 - Initial update of usrsctp library
Diffstat (limited to 'netwerk')
-rw-r--r--netwerk/sctp/sctp_update.log1
-rw-r--r--netwerk/sctp/src/README.sctp11
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp.h54
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_asconf.c516
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_asconf.h17
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_auth.c263
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_auth.h11
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_bsd_addr.c314
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_bsd_addr.h11
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_callout.c87
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_callout.h34
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_cc_functions.c312
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_constants.h213
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_crc32.c159
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_crc32.h16
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_header.h164
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_indata.c4303
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_indata.h58
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_input.c2717
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_input.h18
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_lock_userspace.h22
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_os.h19
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_os_userspace.h248
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_output.c3500
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_output.h132
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_pcb.c1654
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_pcb.h186
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_peeloff.c57
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_peeloff.h10
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_process_lock.h559
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_sha1.c6
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_sha1.h15
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_ss_functions.c355
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_structs.h177
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_sysctl.c405
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_sysctl.h112
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_timer.c218
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_timer.h28
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_uio.h225
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_userspace.c231
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_usrreq.c2564
-rwxr-xr-xnetwerk/sctp/src/netinet/sctp_var.h137
-rwxr-xr-xnetwerk/sctp/src/netinet/sctputil.c3805
-rwxr-xr-xnetwerk/sctp/src/netinet/sctputil.h131
-rw-r--r--netwerk/sctp/src/netinet6/sctp6_usrreq.c917
-rwxr-xr-xnetwerk/sctp/src/netinet6/sctp6_var.h33
-rwxr-xr-xnetwerk/sctp/src/user_atomic.h33
-rwxr-xr-xnetwerk/sctp/src/user_environment.c336
-rwxr-xr-xnetwerk/sctp/src/user_environment.h45
-rwxr-xr-xnetwerk/sctp/src/user_inpcb.h23
-rwxr-xr-xnetwerk/sctp/src/user_ip6_var.h22
-rwxr-xr-xnetwerk/sctp/src/user_ip_icmp.h26
-rwxr-xr-xnetwerk/sctp/src/user_malloc.h71
-rwxr-xr-xnetwerk/sctp/src/user_mbuf.c285
-rwxr-xr-xnetwerk/sctp/src/user_mbuf.h65
-rwxr-xr-xnetwerk/sctp/src/user_queue.h6
-rwxr-xr-xnetwerk/sctp/src/user_recv_thread.c535
-rwxr-xr-xnetwerk/sctp/src/user_route.h2
-rwxr-xr-xnetwerk/sctp/src/user_socket.c1184
-rwxr-xr-xnetwerk/sctp/src/user_socketvar.h411
-rwxr-xr-xnetwerk/sctp/src/user_uma.h12
-rw-r--r--netwerk/sctp/src/usrsctp.h151
-rwxr-xr-xnetwerk/sctp/update_sctp.sh33
63 files changed, 15004 insertions, 13261 deletions
diff --git a/netwerk/sctp/sctp_update.log b/netwerk/sctp/sctp_update.log
index 229c7b9571..f994dcd7bd 100644
--- a/netwerk/sctp/sctp_update.log
+++ b/netwerk/sctp/sctp_update.log
@@ -16,3 +16,4 @@ sctp updated to version 8443 from SVN on Sun Mar 31 09:05:07 EDT 2013
sctp updated to version 8815 from SVN on Tue Mar 4 08:50:51 EST 2014
sctp updated to version 9168 from SVN on Tue Mar 3 12:11:40 EST 2015
sctp updated to version 9209 from SVN on Tue Mar 24 18:11:59 EDT 2015
+sctp updated to version 0.9.5.0 from https://github.com/sctplab/usrsctp/releases/tag/0.9.5.0 on Sat Aug 26 21:54:00 EDT 2023
diff --git a/netwerk/sctp/src/README.sctp b/netwerk/sctp/src/README.sctp
index 14fbb7c695..8e54cc03e5 100644
--- a/netwerk/sctp/src/README.sctp
+++ b/netwerk/sctp/src/README.sctp
@@ -1,12 +1,9 @@
-This code is imported from the usrsctp library via netwerk/sctp/update_sctp.sh.
+This code is imported from the usrsctp library. The current code is version
+0.9.5.0.
-The project is accessed via:
+The project is accessed on GitHub at the following location:
-svn co --username your.username https://sctp-refimpl.googlecode.com/svn/trunk sctpSVN
-
-If you just want a read-only copy use
-
-svn co http://sctp-refimpl.googlecode.com/svn/trunk sctpSVN
+https://github.com/sctplab/usrsctp
The usrsctp library is based on the FreeBSD kernel implementation, and the
userspace implementation was largely done my Michael Tuexen and Irene
diff --git a/netwerk/sctp/src/netinet/sctp.h b/netwerk/sctp/src/netinet/sctp.h
index 962ce1140b..f0dc35ad56 100755
--- a/netwerk/sctp/src/netinet/sctp.h
+++ b/netwerk/sctp/src/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.
@@ -30,22 +32,20 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 356270 2020-01-02 13:55:10Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 366750 2020-10-16 10:44:48Z tuexen $");
#endif
#ifndef _NETINET_SCTP_H_
#define _NETINET_SCTP_H_
-#if (defined(__APPLE__) || defined(__Userspace_os_Linux) || defined(__Userspace_os_Darwin))
+#if defined(__APPLE__) || defined(__linux__)
#include <stdint.h>
#endif
-
#include <sys/types.h>
-
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#define SCTP_PACKED __attribute__((packed))
#else
#pragma pack (push, 1)
@@ -189,7 +189,6 @@ struct sctp_paramhdr {
#define SCTP_STREAM_RESET_INCOMING 0x00000001
#define SCTP_STREAM_RESET_OUTGOING 0x00000002
-
/* here on down are more implementation specific */
#define SCTP_SET_DEBUG_LEVEL 0x00001005
#define SCTP_CLR_STAT_LOG 0x00001007
@@ -202,13 +201,15 @@ struct sctp_paramhdr {
#define SCTP_PLUGGABLE_SS 0x00001203
#define SCTP_SS_VALUE 0x00001204
#define SCTP_CC_OPTION 0x00001205 /* Options for CC modules */
+/* For I-DATA */
+#define SCTP_INTERLEAVING_SUPPORTED 0x00001206
+
/* read only */
#define SCTP_GET_SNDBUF_USE 0x00001101
#define SCTP_GET_STAT_LOG 0x00001103
#define SCTP_PCB_STATUS 0x00001104
#define SCTP_GET_NONCE_VALUES 0x00001105
-
/* Special hook for dynamically setting primary for all assoc's,
* this is a write only option that requires root privilege.
*/
@@ -281,11 +282,11 @@ struct sctp_paramhdr {
#define SCTP_PEELOFF 0x0000800a
/* the real worker for sctp_getaddrlen() */
#define SCTP_GET_ADDR_LEN 0x0000800b
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
/* temporary workaround for Apple listen() issue, no args used */
#define SCTP_LISTEN_FIX 0x0000800c
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
/* workaround for Cygwin on Windows: returns the SOCKET handle */
#define SCTP_GET_HANDLE 0x0000800d
#endif
@@ -331,7 +332,6 @@ struct sctp_paramhdr {
/* First-come, first-serve */
#define SCTP_SS_FIRST_COME 0x00000005
-
/* fragment interleave constants
* setting must be one of these or
* EINVAL returned.
@@ -402,33 +402,32 @@ struct sctp_error_cause {
} SCTP_PACKED;
struct sctp_error_invalid_stream {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_INVALID_STREAM */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_INVALID_STREAM */
uint16_t stream_id; /* stream id of the DATA in error */
uint16_t reserved;
} SCTP_PACKED;
struct sctp_error_missing_param {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_MISSING_PARAM */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_MISSING_PARAM */
uint32_t num_missing_params; /* number of missing parameters */
- /* uint16_t param_type's follow */
+ uint16_t type[];
} SCTP_PACKED;
struct sctp_error_stale_cookie {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_STALE_COOKIE */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_STALE_COOKIE */
uint32_t stale_time; /* time in usec of staleness */
} SCTP_PACKED;
struct sctp_error_out_of_resource {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_OUT_OF_RESOURCES */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_OUT_OF_RESOURCES */
} SCTP_PACKED;
struct sctp_error_unresolv_addr {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_UNRESOLVABLE_ADDR */
-
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRESOLVABLE_ADDR */
} SCTP_PACKED;
struct sctp_error_unrecognized_chunk {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_UNRECOG_CHUNK */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRECOG_CHUNK */
struct sctp_chunkhdr ch;/* header from chunk in error */
} SCTP_PACKED;
@@ -437,6 +436,11 @@ struct sctp_error_no_user_data {
uint32_t tsn; /* TSN of the empty data chunk */
} SCTP_PACKED;
+struct sctp_error_auth_invalid_hmac {
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNSUPPORTED_HMACID */
+ uint16_t hmac_id;
+} SCTP_PACKED;
+
/*
* Main SCTP chunk types we place these here so natd and f/w's in user land
* can find them.
@@ -462,6 +466,7 @@ struct sctp_error_no_user_data {
/* EY nr_sack chunk id*/
#define SCTP_NR_SELECTIVE_ACK 0x10
/************0x40 series ***********/
+#define SCTP_IDATA 0x40
/************0x80 series ***********/
/* RFC5061 */
#define SCTP_ASCONF_ACK 0x80
@@ -477,7 +482,7 @@ struct sctp_error_no_user_data {
#define SCTP_FORWARD_CUM_TSN 0xc0
/* RFC5061 */
#define SCTP_ASCONF 0xc1
-
+#define SCTP_IFORWARD_CUM_TSN 0xc2
/* ABORT and SHUTDOWN COMPLETE FLAG */
#define SCTP_HAD_NO_TCB 0x01
@@ -520,6 +525,7 @@ struct sctp_error_no_user_data {
#define SCTP_PCB_FLAGS_BOUNDALL 0x00000004
#define SCTP_PCB_FLAGS_ACCEPTING 0x00000008
#define SCTP_PCB_FLAGS_UNBOUND 0x00000010
+#define SCTP_PCB_FLAGS_SND_ITERATOR_UP 0x00000020
#define SCTP_PCB_FLAGS_CLOSE_IP 0x00040000
#define SCTP_PCB_FLAGS_WAS_CONNECTED 0x00080000
#define SCTP_PCB_FLAGS_WAS_ABORTED 0x00100000
@@ -561,7 +567,6 @@ struct sctp_error_no_user_data {
#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
@@ -597,14 +602,13 @@ struct sctp_error_no_user_data {
#define SCTP_MOBILITY_FASTHANDOFF 0x00000002
#define SCTP_MOBILITY_PRIM_DELETED 0x00000004
-
/* Smallest PMTU allowed when disabling PMTU discovery */
#define SCTP_SMALLEST_PMTU 512
/* Largest PMTU allowed when disabling PMTU discovery */
#define SCTP_LARGEST_PMTU 65536
-#if defined(__Userspace_os_Windows)
-#pragma pack()
+#if defined(_WIN32)
+#pragma pack(pop)
#endif
#undef SCTP_PACKED
@@ -622,9 +626,9 @@ struct sctp_error_no_user_data {
*/
#define SCTP_MAX_SACK_DELAY 500 /* per RFC4960 */
#define SCTP_MAX_HB_INTERVAL 14400000 /* 4 hours in ms */
+#define SCTP_MIN_COOKIE_LIFE 1000 /* 1 second in ms */
#define SCTP_MAX_COOKIE_LIFE 3600000 /* 1 hour in ms */
-
/* Types of logging/KTR tracing that can be enabled via the
* sysctl net.inet.sctp.sctp_logging. You must also enable
* SUBSYS tracing.
diff --git a/netwerk/sctp/src/netinet/sctp_asconf.c b/netwerk/sctp/src/netinet/sctp_asconf.c
index 438879885e..cd2944389f 100755
--- a/netwerk/sctp/src/netinet/sctp_asconf.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 277347 2015-01-18 20:53:20Z tuexen $");
+__FBSDID("$FreeBSD$");
#endif
#include <netinet/sctp_os.h>
@@ -51,10 +53,6 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 277347 2015-01-18 20:53:20Z t
* SCTP_DEBUG_ASCONF2: detailed info
*/
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 1
-#endif
-
/*
* RFC 5061
*
@@ -103,47 +101,52 @@ sctp_asconf_success_response(uint32_t id)
static struct mbuf *
sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv,
- uint16_t tlv_length)
+ uint16_t tlv_length)
{
struct mbuf *m_reply = NULL;
struct sctp_asconf_paramhdr *aph;
struct sctp_error_cause *error;
+ uint32_t buf_len;
+ uint16_t i, param_length, cause_length, padding_length;
uint8_t *tlv;
- m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) +
- tlv_length +
- sizeof(struct sctp_error_cause)),
- 0, M_NOWAIT, 1, MT_DATA);
+ if (error_tlv == NULL) {
+ tlv_length = 0;
+ }
+ cause_length = sizeof(struct sctp_error_cause) + tlv_length;
+ param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length;
+ padding_length = tlv_length % 4;
+ if (padding_length != 0) {
+ padding_length = 4 - padding_length;
+ }
+ buf_len = param_length + padding_length;
+ if (buf_len > MLEN) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1,
+ "asconf_error_response: tlv_length (%xh) too big\n",
+ tlv_length);
+ return (NULL);
+ }
+ m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_reply == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1,
"asconf_error_response: couldn't get mbuf!\n");
return (NULL);
}
aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
- error = (struct sctp_error_cause *)(aph + 1);
-
- aph->correlation_id = id;
aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
+ aph->ph.param_length = htons(param_length);
+ aph->correlation_id = id;
+ error = (struct sctp_error_cause *)(aph + 1);
error->code = htons(cause);
- error->length = tlv_length + sizeof(struct sctp_error_cause);
- aph->ph.param_length = error->length +
- sizeof(struct sctp_asconf_paramhdr);
-
- if (aph->ph.param_length > MLEN) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_error_response: tlv_length (%xh) too big\n",
- tlv_length);
- sctp_m_freem(m_reply); /* discard */
- return (NULL);
- }
+ error->length = htons(cause_length);
if (error_tlv != NULL) {
tlv = (uint8_t *) (error + 1);
memcpy(tlv, error_tlv, tlv_length);
+ for (i = 0; i < padding_length; i++) {
+ tlv[tlv_length + i] = 0;
+ }
}
- SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
- error->length = htons(error->length);
- aph->ph.param_length = htons(aph->ph.param_length);
-
+ SCTP_BUF_LEN(m_reply) = buf_len;
return (m_reply);
}
@@ -172,10 +175,16 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -187,7 +196,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
}
v4addr = (struct sctp_ipv4addr_param *)ph;
sin = &store.sin;
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin->sin_len = sizeof(struct sockaddr_in);
@@ -212,7 +221,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
}
v6addr = (struct sctp_ipv6addr_param *)ph;
sin6 = &store.sin6;
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
sin6->sin6_len = sizeof(struct sockaddr_in6);
@@ -243,30 +252,34 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
"process_asconf_add_ip: using source addr ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
}
+ net = NULL;
/* add the address */
if (bad_address) {
m_reply = sctp_asconf_error_response(aph->correlation_id,
SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
aparam_length);
- } else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE,
- SCTP_ADDR_DYNAMIC_ADDED) != 0) {
+ } else if (sctp_add_remote_addr(stcb, sa, &net, stcb->asoc.port,
+ SCTP_DONOT_SETSCOPE,
+ SCTP_ADDR_DYNAMIC_ADDED) != 0) {
SCTPDBG(SCTP_DEBUG_ASCONF1,
"process_asconf_add_ip: error adding address\n");
m_reply = sctp_asconf_error_response(aph->correlation_id,
SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph,
aparam_length);
} else {
- /* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
if (response_required) {
m_reply =
sctp_asconf_success_response(aph->correlation_id);
}
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
- stcb, net);
- if (send_hb) {
- sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
+ if (net != NULL) {
+ /* notify upper layer */
+ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
+ sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
+ sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
+ stcb, net);
+ if (send_hb) {
+ sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
+ }
}
}
return (m_reply);
@@ -275,7 +288,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
static int
sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
{
- struct sctp_nets *src_net, *net;
+ struct sctp_nets *src_net, *net, *nnet;
/* make sure the source address exists as a destination net */
src_net = sctp_findnet(stcb, src);
@@ -285,10 +298,9 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
}
/* delete all destination addresses except the source */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
if (net != src_net) {
/* delete this address */
- sctp_remove_net(stcb, net);
SCTPDBG(SCTP_DEBUG_ASCONF1,
"asconf_del_remote_addrs_except: deleting ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
@@ -296,6 +308,7 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
/* notify upper layer */
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
(struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
+ sctp_remove_net(stcb, net);
}
}
return (0);
@@ -326,10 +339,16 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -341,7 +360,7 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
}
v4addr = (struct sctp_ipv4addr_param *)ph;
sin = &store.sin;
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin->sin_len = sizeof(struct sockaddr_in);
@@ -363,7 +382,7 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
}
v6addr = (struct sctp_ipv6addr_param *)ph;
sin6 = &store.sin6;
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
sin6->sin6_len = sizeof(struct sockaddr_in6);
@@ -461,10 +480,16 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -476,7 +501,7 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
}
v4addr = (struct sctp_ipv4addr_param *)ph;
sin = &store.sin;
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin->sin_len = sizeof(struct sockaddr_in);
@@ -496,7 +521,7 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
}
v6addr = (struct sctp_ipv6addr_param *)ph;
sin6 = &store.sin6;
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
sin6->sin6_len = sizeof(struct sockaddr_in6);
@@ -559,8 +584,9 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
SCTP_MOBILITY_PRIM_DELETED) &&
(stcb->asoc.primary_destination->dest_state &
SCTP_ADDR_UNCONFIRMED) == 0) {
-
- sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER+SCTP_LOC_7);
+ sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED,
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
if (sctp_is_mobility_feature_on(stcb->sctp_ep,
SCTP_MOBILITY_FASTHANDOFF)) {
sctp_assoc_immediate_retrans(stcb,
@@ -571,8 +597,7 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
sctp_move_chunks_from_net(stcb,
stcb->asoc.deleted_primary);
}
- sctp_delete_prim_timer(stcb->sctp_ep, stcb,
- stcb->asoc.deleted_primary);
+ sctp_delete_prim_timer(stcb->sctp_ep, stcb);
}
} else {
/* couldn't set the requested primary address! */
@@ -682,10 +707,11 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
SCTPDBG(SCTP_DEBUG_ASCONF1,
"handle_asconf: couldn't get lookup addr!\n");
/* respond with a missing/invalid mandatory parameter error */
+ sctp_m_freem(m_ack);
return;
}
- /* param_length is already validated in process_control... */
- offset += ntohs(p_addr->ph.param_length); /* skip lookup addr */
+ /* skip lookup addr */
+ offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length));
/* get pointer to first asconf param in ASCONF */
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
if (aph == NULL) {
@@ -711,9 +737,10 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
sctp_m_freem(m_ack);
return;
}
- if (param_length <= sizeof(struct sctp_paramhdr)) {
+ if (param_length < sizeof(struct sctp_asconf_paramhdr)) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length);
sctp_m_freem(m_ack);
+ return;
}
/* get the entire parameter */
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
@@ -769,8 +796,6 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
if (m_result != NULL) {
SCTP_BUF_NEXT(m_tail) = m_result;
m_tail = m_result;
- /* update lengths, make sure it's aligned too */
- SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result));
ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
/* set flag to force success reports */
error = 1;
@@ -924,13 +949,13 @@ sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa)
* Cleanup for non-responded/OP ERR'd ASCONF
*/
void
-sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
+sctp_asconf_cleanup(struct sctp_tcb *stcb)
{
/*
* clear out any existing asconfs going out
*/
- sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_ASCONF+SCTP_LOC_2);
+ sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2);
stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out;
/* remove the old ASCONF on our outbound queue */
sctp_toss_old_asconf(stcb);
@@ -966,8 +991,12 @@ sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
((ifn == NULL) ||
(SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) {
/* clear any cached route */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(&net->ro);
+#else
RTFREE(net->ro.ro_rt);
net->ro.ro_rt = NULL;
+#endif
}
/* clear any cached source address */
if (net->src_addr_selected) {
@@ -978,7 +1007,6 @@ sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
}
}
-
void
sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
{
@@ -998,7 +1026,7 @@ sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa);
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb,
stcb->asoc.deleted_primary,
- SCTP_FROM_SCTP_TIMER+SCTP_LOC_8);
+ SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3);
stcb->asoc.num_send_timers_up--;
if (stcb->asoc.num_send_timers_up < 0) {
stcb->asoc.num_send_timers_up = 0;
@@ -1019,9 +1047,14 @@ sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
(stcb->asoc.sent_queue_cnt > 0)) {
struct sctp_tmit_chunk *chk;
- chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
- sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, chk->whoTo);
+ TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
+ if (chk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (chk != NULL) {
+ sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
+ }
}
}
return;
@@ -1038,7 +1071,7 @@ sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO);
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_TIMER+SCTP_LOC_5);
+ SCTP_FROM_SCTP_ASCONF + SCTP_LOC_4);
stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
net->error_count = 0;
TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
@@ -1076,10 +1109,14 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
if (addrnum == 1) {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
/* clear any cached route and source address */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(&net->ro);
+#else
if (net->ro.ro_rt) {
RTFREE(net->ro.ro_rt);
net->ro.ro_rt = NULL;
}
+#endif
if (net->src_addr_selected) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
@@ -1098,10 +1135,14 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
/* Multiple local addresses exsist in the association. */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
/* clear any cached route and source address */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(&net->ro);
+#else
if (net->ro.ro_rt) {
RTFREE(net->ro.ro_rt);
net->ro.ro_rt = NULL;
}
+#endif
if (net->src_addr_selected) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
@@ -1114,8 +1155,13 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
nexthop, the path will not be changed.
*/
SCTP_RTALLOC((sctp_route_t *)&net->ro,
- stcb->sctp_ep->def_vrf_id);
+ stcb->sctp_ep->def_vrf_id,
+ stcb->sctp_ep->fibnum);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (net->ro.ro_nh == NULL)
+#else
if (net->ro.ro_rt == NULL)
+#endif
continue;
changed = 0;
@@ -1155,7 +1201,7 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
}
}
}
-#endif /* __FreeBSD__ __APPLE__ __Userspace__ */
+#endif
/*
* process an ADD/DELETE IP ack from peer.
@@ -1187,7 +1233,7 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t
sctp_path_check_and_react(stcb, addr);
return;
}
-#endif /* __FreeBSD__ __APPLE__ __Userspace__ */
+#endif
/* clear any cached/topologically incorrect source addresses */
sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
}
@@ -1321,7 +1367,6 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
return (0);
}
-
/*
* add an asconf operation for the given ifa and type.
* type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
@@ -1334,6 +1379,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
{
uint32_t status;
int pending_delete_queued = 0;
+ int last;
/* see if peer supports ASCONF */
if (stcb->asoc.asconf_supported == 0) {
@@ -1344,15 +1390,21 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
* if this is deleting the last address from the assoc, mark it as
* pending.
*/
- if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending &&
- (sctp_local_addr_count(stcb) < 2)) {
- /* set the pending delete info only */
- stcb->asoc.asconf_del_pending = 1;
- stcb->asoc.asconf_addr_del_pending = ifa;
- atomic_add_int(&ifa->refcount, 1);
- SCTPDBG(SCTP_DEBUG_ASCONF2,
- "asconf_queue_add: mark delete last address pending\n");
- return (-1);
+ if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending) {
+ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ last = (sctp_local_addr_count(stcb) == 0);
+ } else {
+ last = (sctp_local_addr_count(stcb) == 1);
+ }
+ if (last) {
+ /* set the pending delete info only */
+ stcb->asoc.asconf_del_pending = 1;
+ stcb->asoc.asconf_addr_del_pending = ifa;
+ atomic_add_int(&ifa->refcount, 1);
+ SCTPDBG(SCTP_DEBUG_ASCONF2,
+ "asconf_queue_add: mark delete last address pending\n");
+ return (-1);
+ }
}
/* queue an asconf parameter */
@@ -1367,7 +1419,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
if (sctp_asconf_queue_mgmt(stcb,
stcb->asoc.asconf_addr_del_pending,
SCTP_DEL_IP_ADDRESS) == 0) {
- SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queing pending delete\n");
+ SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queuing pending delete\n");
pending_delete_queued = 1;
/* clear out the pending delete info */
stcb->asoc.asconf_del_pending = 0;
@@ -1637,7 +1689,7 @@ sctp_asconf_ack_clear(struct sctp_tcb *stcb SCTP_UNUSED)
{
/* assume peer doesn't really know how to do asconfs */
/* XXX we could free the pending queue here */
-
+
}
void
@@ -1680,8 +1732,13 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
* abort the asoc, since someone probably just hijacked us...
*/
if (serial_num == (asoc->asconf_seq_out + 1)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
- sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, SCTP_SO_NOT_LOCKED);
+ SCTP_SNPRINTF(msg, sizeof(msg), "Never sent serial number %8.8x", serial_num);
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_no_unlock = 1;
return;
}
@@ -1694,8 +1751,8 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
if (serial_num == asoc->asconf_seq_out - 1) {
/* stop our timer */
- sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_ASCONF+SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_ASCONF + SCTP_LOC_5);
}
/* process the ASCONF-ACK contents */
@@ -1720,7 +1777,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
sctp_asconf_ack_clear(stcb);
return;
}
- if (param_length < sizeof(struct sctp_paramhdr)) {
+ if (param_length < sizeof(struct sctp_asconf_paramhdr)) {
sctp_asconf_ack_clear(stcb);
return;
}
@@ -1768,9 +1825,9 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
} /* switch */
/* update remaining ASCONF-ACK message length to process */
- ack_length -= SCTP_SIZE32(param_length);
- if (ack_length <= 0) {
- /* no more data in the mbuf chain */
+ if (ack_length > SCTP_SIZE32(param_length)) {
+ ack_length -= SCTP_SIZE32(param_length);
+ } else {
break;
}
offset += SCTP_SIZE32(param_length);
@@ -1881,7 +1938,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
switch (ifa->address.sa.sa_family) {
#ifdef INET6
case AF_INET6:
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
&ifa->address.sin6.sin6_addr) != 0) {
return;
@@ -1891,7 +1948,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#endif
#ifdef INET
case AF_INET:
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
&ifa->address.sin.sin_addr) != 0) {
return;
@@ -1952,12 +2009,10 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case AF_INET:
{
struct sockaddr_in *sin;
- struct in6pcb *inp6;
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
/* invalid if we are a v6 only endpoint */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6))
+ SCTP_IPV6_V6ONLY(inp))
return;
sin = &ifa->address.sin;
@@ -1990,7 +2045,8 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* sent when the state goes open.
*/
if (status == 0 &&
- SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+ ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED))) {
#ifdef SCTP_TIMER_BASED_ASCONF
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
stcb, stcb->asoc.primary_destination);
@@ -2002,7 +2058,6 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
}
-
int
sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
{
@@ -2029,10 +2084,8 @@ sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNU
case AF_INET:
{
/* invalid if we are a v6 only endpoint */
- struct in6pcb *inp6;
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6)) {
+ SCTP_IPV6_V6ONLY(inp)) {
cnt_invalid++;
if (asc->cnt == cnt_invalid)
return (1);
@@ -2068,7 +2121,6 @@ sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP
laddr->action = 0;
break;
}
-
}
} else if (l->action == SCTP_DEL_IP_ADDRESS) {
LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
@@ -2123,7 +2175,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* we skip unspecifed addresses */
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -2145,13 +2197,11 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case AF_INET:
{
/* invalid if we are a v6 only endpoint */
- struct in6pcb *inp6;
struct sockaddr_in *sin;
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
/* invalid if we are a v6 only endpoint */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6))
+ SCTP_IPV6_V6ONLY(inp))
continue;
sin = &ifa->address.sin;
@@ -2159,7 +2209,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* we skip unspecifed addresses */
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -2170,7 +2220,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
continue;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6)) {
+ SCTP_IPV6_V6ONLY(inp)) {
cnt_invalid++;
if (asc->cnt == cnt_invalid)
return;
@@ -2196,18 +2246,19 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
} else if (type == SCTP_DEL_IP_ADDRESS) {
struct sctp_nets *net;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- sctp_rtentry_t *rt;
-
/* delete this address if cached */
if (net->ro._s_addr == ifa) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
- rt = net->ro.ro_rt;
- if (rt) {
- RTFREE(rt);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(&net->ro);
+#else
+ if (net->ro.ro_rt) {
+ RTFREE(net->ro.ro_rt);
net->ro.ro_rt = NULL;
}
+#endif
/*
* Now we deleted our src address,
* should we not also now reset the
@@ -2216,7 +2267,6 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
net->RTO = 0;
-
}
}
} else if (type == SCTP_SET_PRIM_ADDR) {
@@ -2242,7 +2292,8 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* count of queued params. If in the non-open state,
* these get sent when the assoc goes open.
*/
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
if (status >= 0) {
num_queued++;
}
@@ -2303,7 +2354,8 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
"set_primary_ip_address_sa: queued on tcb=%p, ",
(void *)stcb);
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
#ifdef SCTP_TIMER_BASED_ASCONF
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
stcb->sctp_ep, stcb,
@@ -2321,38 +2373,6 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
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) {
-#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)
{
@@ -2478,7 +2498,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
/* skip unspecifed addresses */
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -2512,7 +2532,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
/* we skip unspecifed addresses */
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -2601,21 +2621,21 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
if (m_asconf_chk == NULL) {
/* no mbuf's */
SCTPDBG(SCTP_DEBUG_ASCONF1,
- "compose_asconf: couldn't get chunk mbuf!\n");
+ "sctp_compose_asconf: couldn't get chunk mbuf!\n");
return (NULL);
}
m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (m_asconf == NULL) {
/* no mbuf's */
SCTPDBG(SCTP_DEBUG_ASCONF1,
- "compose_asconf: couldn't get mbuf!\n");
+ "sctp_compose_asconf: couldn't get mbuf!\n");
sctp_m_freem(m_asconf_chk);
return (NULL);
}
SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk);
SCTP_BUF_LEN(m_asconf) = 0;
acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
- bzero(acp, sizeof(struct sctp_asconf_chunk));
+ memset(acp, 0, sizeof(struct sctp_asconf_chunk));
/* save pointers to lookup address and asconf params */
lookup_ptr = (caddr_t)(acp + 1); /* after the header */
ptr = mtod(m_asconf, caddr_t); /* beginning of cluster */
@@ -2733,10 +2753,12 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
break;
#endif
default:
- p_size = 0;
- addr_size = 0;
- addr_ptr = NULL;
- break;
+ SCTPDBG(SCTP_DEBUG_ASCONF1,
+ "sctp_compose_asconf: no usable lookup addr (family = %d)!\n",
+ found_addr->sa_family);
+ sctp_m_freem(m_asconf_chk);
+ sctp_m_freem(m_asconf);
+ return (NULL);
}
lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
memcpy(lookup->addr, addr_ptr, addr_size);
@@ -2744,12 +2766,10 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
} else {
/* uh oh... don't have any address?? */
SCTPDBG(SCTP_DEBUG_ASCONF1,
- "compose_asconf: no lookup addr!\n");
- /* XXX for now, we send a IPv4 address of 0.0.0.0 */
- lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
- lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
- bzero(lookup->addr, sizeof(struct in_addr));
- SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
+ "sctp_compose_asconf: no lookup addr!\n");
+ sctp_m_freem(m_asconf_chk);
+ sctp_m_freem(m_asconf);
+ return (NULL);
}
}
/* chain it all together */
@@ -2870,8 +2890,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
* out the ASCONF.
*/
if (status == 0 &&
- SCTP_GET_STATE(&stcb->asoc) ==
- SCTP_STATE_OPEN) {
+ SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
#ifdef SCTP_TIMER_BASED_ASCONF
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
stcb->sctp_ep, stcb,
@@ -3046,10 +3065,6 @@ sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
"check_addr_list_ep: laddr->ifa is NULL");
continue;
}
- if (laddr->ifa == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "check_addr_list_ep: laddr->ifa->ifa_addr is NULL");
- continue;
- }
/* do i have it implicitly? */
if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) {
continue;
@@ -3111,7 +3126,7 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
#ifdef INET
case AF_INET:
sin = &sctp_ifa->address.sin;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -3127,7 +3142,7 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
#ifdef INET6
case AF_INET6:
sin6 = &sctp_ifa->address.sin6;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -3196,7 +3211,7 @@ sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
*/
uint32_t
sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
- uint32_t type, uint32_t vrf_id, struct sctp_ifa *sctp_ifap)
+ uint32_t type, uint32_t vrf_id)
{
struct sctp_ifa *ifa;
struct sctp_laddr *laddr, *nladdr;
@@ -3207,9 +3222,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
return (EINVAL);
}
#endif
- if (sctp_ifap) {
- ifa = sctp_ifap;
- } else if (type == SCTP_ADD_IP_ADDRESS) {
+ if (type == SCTP_ADD_IP_ADDRESS) {
/* For an add the address MUST be on the system */
ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
} else if (type == SCTP_DEL_IP_ADDRESS) {
@@ -3250,6 +3263,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
} else {
struct sctp_asconf_iterator *asc;
struct sctp_laddr *wi;
+ int ret;
SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
sizeof(struct sctp_asconf_iterator),
@@ -3271,7 +3285,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
wi->action = type;
atomic_add_int(&ifa->refcount, 1);
LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
- (void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
+ ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
sctp_asconf_iterator_stcb,
sctp_asconf_iterator_ep_end,
SCTP_PCB_ANY_FLAGS,
@@ -3279,6 +3293,12 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
SCTP_ASOC_ANY_STATE,
(void *)asc, 0,
sctp_asconf_iterator_end, inp, 0);
+ if (ret) {
+ SCTP_PRINTF("Failed to initiate iterator for addr_mgmt_ep_sa\n");
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EFAULT);
+ sctp_asconf_iterator_end(asc, 0);
+ return (EFAULT);
+ }
}
return (0);
} else {
@@ -3289,10 +3309,9 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
}
void
-sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
- struct sctp_nets *net)
+sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, struct sctp_nets *net)
{
- struct sctp_asconf_addr *aa;
+ struct sctp_asconf_addr *aa_vtag, *aa_add, *aa_del;
struct sctp_ifa *sctp_ifap;
struct sctp_asconf_tag_param *vtag;
#ifdef INET
@@ -3301,6 +3320,7 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
#ifdef INET6
struct sockaddr_in6 *to6;
#endif
+
if (net == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
return;
@@ -3309,108 +3329,84 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n");
return;
}
- /* Need to have in the asconf:
- * - vtagparam(my_vtag/peer_vtag)
- * - add(0.0.0.0)
- * - del(0.0.0.0)
- * - Any global addresses add(addr)
- */
- SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
- SCTP_M_ASC_ADDR);
- if (aa == NULL) {
- /* didn't get memory */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_send_nat_state_update: failed to get memory!\n");
+ /* Need to have in the ASCONF:
+ * - VTAG(my_vtag/peer_vtag)
+ * - ADD(wildcard)
+ * - DEL(wildcard)
+ * - ADD(Any global addresses)
+ */
+ SCTP_MALLOC(aa_vtag, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
+ SCTP_MALLOC(aa_add, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
+ SCTP_MALLOC(aa_del, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
+
+ if ((aa_vtag == NULL) || (aa_add == NULL) || (aa_del == NULL)) {
+ /* Didn't get memory */
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: failed to get memory!\n");
+out:
+ if (aa_vtag != NULL) {
+ SCTP_FREE(aa_vtag, SCTP_M_ASC_ADDR);
+ }
+ if (aa_add != NULL) {
+ SCTP_FREE(aa_add, SCTP_M_ASC_ADDR);
+ }
+ if (aa_del != NULL) {
+ SCTP_FREE(aa_del, SCTP_M_ASC_ADDR);
+ }
return;
}
- aa->special_del = 0;
- /* fill in asconf address parameter fields */
- /* top level elements are "networked" during send */
- aa->ifa = NULL;
- aa->sent = 0; /* clear sent flag */
- vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph;
+ memset(aa_vtag, 0, sizeof(struct sctp_asconf_addr));
+ aa_vtag->special_del = 0;
+ /* Fill in ASCONF address parameter fields. */
+ /* Top level elements are "networked" during send. */
+ aa_vtag->ifa = NULL;
+ aa_vtag->sent = 0; /* clear sent flag */
+ vtag = (struct sctp_asconf_tag_param *)&aa_vtag->ap.aph;
vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
vtag->local_vtag = htonl(stcb->asoc.my_vtag);
vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
- SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
- SCTP_M_ASC_ADDR);
- if (aa == NULL) {
- /* didn't get memory */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_send_nat_state_update: failed to get memory!\n");
- return;
- }
- memset(aa, 0, sizeof(struct sctp_asconf_addr));
- /* fill in asconf address parameter fields */
- /* ADD(0.0.0.0) */
+ memset(aa_add, 0, sizeof(struct sctp_asconf_addr));
+ memset(aa_del, 0, sizeof(struct sctp_asconf_addr));
switch (net->ro._l_addr.sa.sa_family) {
#ifdef INET
case AF_INET:
- aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
- aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
- aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
- /* No need to add an address, we are using 0.0.0.0 */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
+ aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
+ aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
+ aa_add->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
+ aa_add->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
+ /* No need to fill the address, we are using 0.0.0.0 */
+ aa_del->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
+ aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
+ aa_del->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
+ aa_del->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
+ /* No need to fill the address, we are using 0.0.0.0 */
break;
#endif
#ifdef INET6
case AF_INET6:
- aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
- aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
- aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
- /* No need to add an address, we are using 0.0.0.0 */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
+ aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
+ aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
+ aa_add->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
+ aa_add->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
+ /* No need to fill the address, we are using ::0 */
+ aa_del->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
+ aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
+ aa_del->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
+ aa_del->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
+ /* No need to fill the address, we are using ::0 */
break;
#endif
default:
SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_send_nat_state_update: unknown address family\n");
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- return;
- }
- SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
- SCTP_M_ASC_ADDR);
- if (aa == NULL) {
- /* didn't get memory */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_send_nat_state_update: failed to get memory!\n");
- return;
- }
- memset(aa, 0, sizeof(struct sctp_asconf_addr));
- /* fill in asconf address parameter fields */
- /* ADD(0.0.0.0) */
- switch (net->ro._l_addr.sa.sa_family) {
-#ifdef INET
- case AF_INET:
- aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
- aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
- aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
- /* No need to add an address, we are using 0.0.0.0 */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
- aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
- aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
- /* No need to add an address, we are using 0.0.0.0 */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
- break;
-#endif
- default:
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_send_nat_state_update: unknown address family\n");
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- return;
+ "sctp_asconf_send_nat_state_update: unknown address family %d\n",
+ net->ro._l_addr.sa.sa_family);
+ goto out;
}
+ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_vtag, next);
+ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_add, next);
+ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_del, next);
+
/* Now we must hunt the addresses and add all global addresses */
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
struct sctp_vrf *vrf = NULL;
@@ -3430,7 +3426,7 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
#ifdef INET
case AF_INET:
to = &sctp_ifap->address.sin;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
&to->sin_addr) != 0) {
continue;
@@ -3447,7 +3443,7 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
#ifdef INET6
case AF_INET6:
to6 = &sctp_ifap->address.sin6;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
&to6->sin6_addr) != 0) {
continue;
diff --git a/netwerk/sctp/src/netinet/sctp_asconf.h b/netwerk/sctp/src/netinet/sctp_asconf.h
index a3622e4128..3868949208 100755
--- a/netwerk/sctp/src/netinet/sctp_asconf.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.h 237715 2012-06-28 16:01:08Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_ASCONF_H_
@@ -43,7 +45,7 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.h 237715 2012-06-28 16:01:08Z t
/*
* function prototypes
*/
-extern void sctp_asconf_cleanup(struct sctp_tcb *, struct sctp_nets *);
+extern void sctp_asconf_cleanup(struct sctp_tcb *);
extern struct mbuf *sctp_compose_asconf(struct sctp_tcb *, int *, int);
@@ -56,9 +58,8 @@ sctp_handle_asconf_ack(struct mbuf *, int, struct sctp_asconf_ack_chunk *,
struct sctp_tcb *, struct sctp_nets *, int *);
extern uint32_t
-sctp_addr_mgmt_ep_sa(struct sctp_inpcb *, struct sockaddr *,
- uint32_t, uint32_t, struct sctp_ifa *);
-
+sctp_addr_mgmt_ep_sa(struct sctp_inpcb *, struct sockaddr *, uint32_t,
+ uint32_t);
extern int sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr,
uint32_t val);
@@ -67,15 +68,11 @@ extern void sctp_asconf_iterator_stcb(struct sctp_inpcb *inp,
void *ptr, uint32_t type);
extern void sctp_asconf_iterator_end(void *ptr, uint32_t val);
-
extern int32_t
sctp_set_primary_ip_address_sa(struct sctp_tcb *,
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/netwerk/sctp/src/netinet/sctp_auth.c b/netwerk/sctp/src/netinet/sctp_auth.c
index 4e9f7e4cda..9281e07803 100755
--- a/netwerk/sctp/src/netinet/sctp_auth.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 355931 2019-12-20 15:25:08Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 365071 2020-09-01 21:19:14Z mjg $");
#endif
#include <netinet/sctp_os.h>
@@ -51,11 +53,10 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 355931 2019-12-20 15:25:08Z tue
#define SCTP_AUTH_DEBUG2 (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH2)
#endif /* SCTP_DEBUG */
-
void
sctp_clear_chunklist(sctp_auth_chklist_t *chklist)
{
- bzero(chklist, sizeof(*chklist));
+ memset(chklist, 0, sizeof(*chklist));
/* chklist->num_chunks = 0; */
}
@@ -94,12 +95,11 @@ sctp_copy_chunklist(sctp_auth_chklist_t *list)
if (new_list == NULL)
return (NULL);
/* copy it */
- bcopy(list, new_list, sizeof(*new_list));
+ memcpy(new_list, list, sizeof(*new_list));
return (new_list);
}
-
/*
* add a chunk to the required chunks list
*/
@@ -239,7 +239,6 @@ sctp_unpack_auth_chunks(const uint8_t *ptr, uint8_t num_chunks,
return (size);
}
-
/*
* allocate structure space for a key of length keylen
*/
@@ -340,7 +339,7 @@ sctp_set_key(uint8_t *key, uint32_t keylen)
/* out of memory */
return (NULL);
}
- bcopy(key, new_key->key, keylen);
+ memcpy(new_key->key, key, keylen);
return (new_key);
}
@@ -429,34 +428,33 @@ sctp_compute_hashkey(sctp_key_t *key1, sctp_key_t *key2, sctp_key_t *shared)
if (sctp_compare_key(key1, key2) <= 0) {
/* key is shared + key1 + key2 */
if (sctp_get_keylen(shared)) {
- bcopy(shared->key, key_ptr, shared->keylen);
+ memcpy(key_ptr, shared->key, shared->keylen);
key_ptr += shared->keylen;
}
if (sctp_get_keylen(key1)) {
- bcopy(key1->key, key_ptr, key1->keylen);
+ memcpy(key_ptr, key1->key, key1->keylen);
key_ptr += key1->keylen;
}
if (sctp_get_keylen(key2)) {
- bcopy(key2->key, key_ptr, key2->keylen);
+ memcpy(key_ptr, key2->key, key2->keylen);
}
} else {
/* key is shared + key2 + key1 */
if (sctp_get_keylen(shared)) {
- bcopy(shared->key, key_ptr, shared->keylen);
+ memcpy(key_ptr, shared->key, shared->keylen);
key_ptr += shared->keylen;
}
if (sctp_get_keylen(key2)) {
- bcopy(key2->key, key_ptr, key2->keylen);
+ memcpy(key_ptr, key2->key, key2->keylen);
key_ptr += key2->keylen;
}
if (sctp_get_keylen(key1)) {
- bcopy(key1->key, key_ptr, key1->keylen);
+ memcpy(key_ptr, key1->key, key1->keylen);
}
}
return (new_key);
}
-
sctp_sharedkey_t *
sctp_alloc_sharedkey(void)
{
@@ -523,7 +521,7 @@ sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
} else if (new_skey->keyid == skey->keyid) {
/* replace the existing key */
/* verify this key *can* be replaced */
- if ((skey->deactivated) && (skey->refcount > 1)) {
+ if ((skey->deactivated) || (skey->refcount > 1)) {
SCTPDBG(SCTP_DEBUG_AUTH1,
"can't replace shared key id %u\n",
new_skey->keyid);
@@ -544,7 +542,7 @@ sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
}
}
/* shouldn't reach here */
- return (0);
+ return (EINVAL);
}
void
@@ -560,16 +558,12 @@ sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t key_id)
atomic_add_int(&skey->refcount, 1);
SCTPDBG(SCTP_DEBUG_AUTH2,
"%s: stcb %p key %u refcount acquire to %d\n",
- __FUNCTION__, (void *)stcb, key_id, skey->refcount);
+ __func__, (void *)stcb, key_id, skey->refcount);
}
}
void
-sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked)
{
sctp_sharedkey_t *skey;
@@ -578,20 +572,20 @@ sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked
/* decrement the ref count */
if (skey) {
- sctp_free_sharedkey(skey);
SCTPDBG(SCTP_DEBUG_AUTH2,
"%s: stcb %p key %u refcount release to %d\n",
- __FUNCTION__, (void *)stcb, key_id, skey->refcount);
+ __func__, (void *)stcb, key_id, skey->refcount);
/* see if a notification should be generated */
- if ((skey->refcount <= 1) && (skey->deactivated)) {
+ if ((skey->refcount <= 2) && (skey->deactivated)) {
/* notify ULP that key is no longer used */
sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb,
key_id, 0, so_locked);
SCTPDBG(SCTP_DEBUG_AUTH2,
"%s: stcb %p key %u no longer used, %d\n",
- __FUNCTION__, (void *)stcb, key_id, skey->refcount);
+ __func__, (void *)stcb, key_id, skey->refcount);
}
+ sctp_free_sharedkey(skey);
}
}
@@ -624,14 +618,16 @@ sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest)
LIST_FOREACH(skey, src, next) {
new_skey = sctp_copy_sharedkey(skey);
if (new_skey != NULL) {
- (void)sctp_insert_sharedkey(dest, new_skey);
- count++;
+ if (sctp_insert_sharedkey(dest, new_skey)) {
+ sctp_free_sharedkey(new_skey);
+ } else {
+ count++;
+ }
}
}
return (count);
}
-
sctp_hmaclist_t *
sctp_alloc_hmaclist(uint16_t num_hmacs)
{
@@ -655,7 +651,6 @@ sctp_free_hmaclist(sctp_hmaclist_t *list)
{
if (list != NULL) {
SCTP_FREE(list,SCTP_M_AUTH_HL);
- list = NULL;
}
}
@@ -772,7 +767,7 @@ sctp_serialize_hmaclist(sctp_hmaclist_t *list, uint8_t *ptr)
for (i = 0; i < list->num_algo; i++) {
hmac_id = htons(list->hmac[i]);
- bcopy(&hmac_id, ptr, sizeof(hmac_id));
+ memcpy(ptr, &hmac_id, sizeof(hmac_id));
ptr += sizeof(hmac_id);
}
return (list->num_algo * sizeof(hmac_id));
@@ -803,7 +798,7 @@ sctp_alloc_authinfo(void)
/* out of memory */
return (NULL);
}
- bzero(new_authinfo, sizeof(*new_authinfo));
+ memset(new_authinfo, 0, sizeof(*new_authinfo));
return (new_authinfo);
}
@@ -826,7 +821,6 @@ sctp_free_authinfo(sctp_authinfo_t *authinfo)
/* SCTP_FREE(authinfo, SCTP_M_AUTH_??); */
}
-
uint32_t
sctp_get_auth_chunk_len(uint16_t hmac_algo)
{
@@ -974,10 +968,10 @@ sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
key = temp;
}
/* initialize the inner/outer pads with the key and "append" zeroes */
- bzero(ipad, blocklen);
- bzero(opad, blocklen);
- bcopy(key, ipad, keylen);
- bcopy(key, opad, keylen);
+ memset(ipad, 0, blocklen);
+ memset(opad, 0, blocklen);
+ memcpy(ipad, key, keylen);
+ memcpy(opad, key, keylen);
/* XOR the key with ipad and opad values */
for (i = 0; i < blocklen; i++) {
@@ -1034,10 +1028,10 @@ sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
key = temp;
}
/* initialize the inner/outer pads with the key and "append" zeroes */
- bzero(ipad, blocklen);
- bzero(opad, blocklen);
- bcopy(key, ipad, keylen);
- bcopy(key, opad, keylen);
+ memset(ipad, 0, blocklen);
+ memset(opad, 0, blocklen);
+ memcpy(ipad, key, keylen);
+ memcpy(opad, key, keylen);
/* XOR the key with ipad and opad values */
for (i = 0; i < blocklen; i++) {
@@ -1079,40 +1073,6 @@ sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
return (digestlen);
}
-/*-
- * verify the HMAC digest using the desired hash key, text, and HMAC
- * algorithm.
- * Returns -1 on error, 0 on success.
- */
-int
-sctp_verify_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
- uint8_t *text, uint32_t textlen,
- uint8_t *digest, uint32_t digestlen)
-{
- uint32_t len;
- uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
-
- /* sanity check the material and length */
- if ((key == NULL) || (keylen == 0) ||
- (text == NULL) || (textlen == 0) || (digest == NULL)) {
- /* can't do HMAC with empty key or text or digest */
- return (-1);
- }
- len = sctp_get_hmac_digest_len(hmac_algo);
- if ((len == 0) || (digestlen != len))
- return (-1);
-
- /* compute the expected hash */
- if (sctp_hmac(hmac_algo, key, keylen, text, textlen, temp) != len)
- return (-1);
-
- if (memcmp(digest, temp, digestlen) != 0)
- return (-1);
- else
- return (0);
-}
-
-
/*
* computes the requested HMAC using a key struct (which may be modified if
* the keylen exceeds the HMAC block len).
@@ -1145,7 +1105,7 @@ sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key, uint8_t *text,
sctp_hmac_final(hmac_algo, &ctx, temp);
/* save the hashed key as the new key */
key->keylen = digestlen;
- bcopy(temp, key->key, key->keylen);
+ memcpy(key->key, temp, key->keylen);
}
return (sctp_hmac(hmac_algo, key->key, key->keylen, text, textlen,
digest));
@@ -1179,7 +1139,7 @@ sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t *key, struct mbuf *m,
sctp_hmac_final(hmac_algo, &ctx, temp);
/* save the hashed key as the new key */
key->keylen = digestlen;
- bcopy(temp, key->key, key->keylen);
+ memcpy(key->key, temp, key->keylen);
}
return (sctp_hmac_m(hmac_algo, key->key, key->keylen, m, m_offset, digest, 0));
}
@@ -1200,7 +1160,6 @@ sctp_auth_is_supported_hmac(sctp_hmaclist_t *list, uint16_t id)
return (0);
}
-
/*-
* clear any cached key(s) if they match the given key id on an association.
* the cached key(s) will be recomputed and re-cached at next use.
@@ -1458,7 +1417,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(random_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
+ (struct sctp_paramhdr *)random_store, plen);
if (phdr == NULL)
return;
/* save the random and length for the key */
@@ -1471,7 +1430,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(hmacs_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)hmacs_store, min(plen,sizeof(hmacs_store)));
+ (struct sctp_paramhdr *)hmacs_store, plen);
if (phdr == NULL)
return;
/* save the hmacs list and num for the key */
@@ -1493,7 +1452,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(chunks_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)chunks_store, min(plen,sizeof(chunks_store)));
+ (struct sctp_paramhdr *)chunks_store, plen);
if (phdr == NULL)
return;
chunks = (struct sctp_auth_chunk_list *)phdr;
@@ -1522,24 +1481,24 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
}
new_key = sctp_alloc_key(keylen);
if (new_key != NULL) {
- /* copy in the RANDOM */
- if (p_random != NULL) {
- keylen = sizeof(*p_random) + random_len;
- bcopy(p_random, new_key->key, keylen);
- } else {
- keylen = 0;
- }
- /* append in the AUTH chunks */
- if (chunks != NULL) {
- bcopy(chunks, new_key->key + keylen,
- sizeof(*chunks) + num_chunks);
- keylen += sizeof(*chunks) + num_chunks;
- }
- /* append in the HMACs */
- if (hmacs != NULL) {
- bcopy(hmacs, new_key->key + keylen,
- sizeof(*hmacs) + hmacs_len);
- }
+ /* copy in the RANDOM */
+ if (p_random != NULL) {
+ keylen = sizeof(*p_random) + random_len;
+ memcpy(new_key->key, p_random, keylen);
+ } else {
+ keylen = 0;
+ }
+ /* append in the AUTH chunks */
+ if (chunks != NULL) {
+ memcpy(new_key->key + keylen, chunks,
+ sizeof(*chunks) + num_chunks);
+ keylen += sizeof(*chunks) + num_chunks;
+ }
+ /* append in the HMACs */
+ if (hmacs != NULL) {
+ memcpy(new_key->key + keylen, hmacs,
+ sizeof(*hmacs) + hmacs_len);
+ }
}
if (stcb->asoc.authinfo.random != NULL)
sctp_free_key(stcb->asoc.authinfo.random);
@@ -1576,7 +1535,7 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
/* zero the digest + chunk padding */
digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id);
- bzero(auth->hmac, SCTP_SIZE32(digestlen));
+ memset(auth->hmac, 0, SCTP_SIZE32(digestlen));
/* is the desired key cached? */
if ((keyid != stcb->asoc.authinfo.assoc_keyid) ||
@@ -1613,9 +1572,8 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
m, auth_offset, auth->hmac);
}
-
static void
-sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
+sctp_zero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
{
struct mbuf *m_tmp;
uint8_t *data;
@@ -1633,11 +1591,11 @@ sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
/* 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)) {
- bzero(data, 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 {
- bzero(data, size);
+ memset(data, 0, size);
size = 0;
}
/* clear the offset since it's only for the first mbuf */
@@ -1679,10 +1637,13 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
"SCTP AUTH Chunk: shared key %u, HMAC id %u\n",
shared_key_id, hmac_id);
+#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+ return (0);
+#endif
/* is the indicated HMAC supported? */
if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) {
- struct mbuf *m_err;
- struct sctp_auth_invalid_hmac *err;
+ struct mbuf *op_err;
+ struct sctp_error_auth_invalid_hmac *cause;
SCTP_STAT_INCR(sctps_recvivalhmacid);
SCTPDBG(SCTP_DEBUG_AUTH1,
@@ -1692,20 +1653,19 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
* report this in an Error Chunk: Unsupported HMAC
* Identifier
*/
- m_err = sctp_get_mbuf_for_msg(sizeof(*err), 0, M_NOWAIT,
- 1, MT_HEADER);
- if (m_err != NULL) {
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_auth_invalid_hmac),
+ 0, M_NOWAIT, 1, MT_HEADER);
+ if (op_err != NULL) {
/* pre-reserve some space */
- SCTP_BUF_RESV_UF(m_err, sizeof(struct sctp_chunkhdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
/* fill in the error */
- err = mtod(m_err, struct sctp_auth_invalid_hmac *);
- bzero(err, sizeof(*err));
- err->ph.param_type = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
- err->ph.param_length = htons(sizeof(*err));
- err->hmac_id = ntohs(hmac_id);
- SCTP_BUF_LEN(m_err) = sizeof(*err);
+ cause = mtod(op_err, struct sctp_error_auth_invalid_hmac *);
+ cause->cause.code = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
+ cause->cause.length = htons(sizeof(struct sctp_error_auth_invalid_hmac));
+ cause->hmac_id = ntohs(hmac_id);
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_auth_invalid_hmac);
/* queue it */
- sctp_queue_op_err(stcb, m_err);
+ sctp_queue_op_err(stcb, op_err);
}
return (-1);
}
@@ -1755,13 +1715,13 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
return (-1);
}
/* save a copy of the digest, zero the pseudo header, and validate */
- bcopy(auth->hmac, digest, digestlen);
- sctp_bzero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen));
+ memcpy(digest, auth->hmac, digestlen);
+ sctp_zero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen));
(void)sctp_compute_hmac_m(hmac_id, stcb->asoc.authinfo.recv_key,
m, offset, computed_digest);
/* compare the computed digest with the one in the AUTH chunk */
- if (memcmp(digest, computed_digest, digestlen) != 0) {
+ if (timingsafe_bcmp(digest, computed_digest, digestlen) != 0) {
SCTP_STAT_INCR(sctps_recvauthfailed);
SCTPDBG(SCTP_DEBUG_AUTH1,
"SCTP Auth: HMAC digest check failed\n");
@@ -1775,11 +1735,7 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
*/
void
sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
- uint16_t keyid, uint16_t alt_keyid, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+ uint16_t keyid, uint16_t alt_keyid, int so_locked)
{
struct mbuf *m_notify;
struct sctp_authkey_event *auth;
@@ -1826,15 +1782,14 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
}
-
/*-
* validates the AUTHentication related parameters in an INIT/INIT-ACK
* Note: currently only used for INIT as INIT-ACK is handled inline
@@ -1843,7 +1798,7 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
int
sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
{
- struct sctp_paramhdr *phdr, parm_buf;
+ struct sctp_paramhdr *phdr, param_buf;
uint16_t ptype, plen;
int peer_supports_asconf = 0;
int peer_supports_auth = 0;
@@ -1852,7 +1807,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
uint8_t saw_asconf_ack = 0;
/* go through each of the params. */
- phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf, sizeof(param_buf));
while (phdr) {
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
@@ -1866,11 +1821,15 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
/* A supported extension chunk */
struct sctp_supported_chunk_types_param *pr_supported;
- uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
+ uint8_t local_store[SCTP_SMALL_CHUNK_STORE];
int num_ent, i;
+ if (plen > sizeof(local_store)) {
+ break;
+ }
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&local_store, min(plen,sizeof(local_store)));
+ (struct sctp_paramhdr *)&local_store,
+ plen);
if (phdr == NULL) {
return (-1);
}
@@ -1888,7 +1847,6 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
}
}
} else if (ptype == SCTP_RANDOM) {
- got_random = 1;
/* enforce the random length */
if (plen != (sizeof(struct sctp_auth_random) +
SCTP_AUTH_RANDOM_SIZE_REQUIRED)) {
@@ -1896,20 +1854,23 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
"SCTP: invalid RANDOM len\n");
return (-1);
}
+ got_random = 1;
} else if (ptype == SCTP_HMAC_LIST) {
- uint8_t store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_hmac_algo *hmacs;
+ uint8_t store[SCTP_PARAM_BUFFER_SIZE];
int num_hmacs;
- if (plen > sizeof(store))
+ if (plen > sizeof(store)) {
break;
+ }
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store, min(plen,sizeof(store)));
- if (phdr == NULL)
+ (struct sctp_paramhdr *)store,
+ plen);
+ if (phdr == NULL) {
return (-1);
+ }
hmacs = (struct sctp_auth_hmac_algo *)phdr;
- num_hmacs = (plen - sizeof(*hmacs)) /
- sizeof(hmacs->hmac_ids[0]);
+ num_hmacs = (plen - sizeof(*hmacs)) / sizeof(hmacs->hmac_ids[0]);
/* validate the hmac list */
if (sctp_verify_hmac_param(hmacs, num_hmacs)) {
SCTPDBG(SCTP_DEBUG_AUTH1,
@@ -1918,16 +1879,19 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
}
got_hmacs = 1;
} else if (ptype == SCTP_CHUNK_LIST) {
- int i, num_chunks;
+ struct sctp_auth_chunk_list *chunks;
uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE];
- /* did the peer send a non-empty chunk list? */
- struct sctp_auth_chunk_list *chunks = NULL;
+ int i, num_chunks;
+
+ if (plen > sizeof(chunks_store)) {
+ break;
+ }
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store,
- min(plen,sizeof(chunks_store)));
- if (phdr == NULL)
+ plen);
+ if (phdr == NULL) {
return (-1);
-
+ }
/*-
* Flip through the list and mark that the
* peer supports asconf/asconf_ack.
@@ -1940,7 +1904,6 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
saw_asconf = 1;
if (chunks->chunk_types[i] == SCTP_ASCONF_ACK)
saw_asconf_ack = 1;
-
}
if (num_chunks)
got_chklist = 1;
@@ -1950,8 +1913,8 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (offset >= limit) {
break;
}
- phdr = sctp_get_next_param(m, offset, &parm_buf,
- sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf,
+ sizeof(param_buf));
}
/* validate authentication required parameters */
if (got_random && got_hmacs) {
diff --git a/netwerk/sctp/src/netinet/sctp_auth.h b/netwerk/sctp/src/netinet/sctp_auth.h
index 997389363d..d43ada90da 100755
--- a/netwerk/sctp/src/netinet/sctp_auth.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.h 271673 2014-09-16 14:20:33Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_AUTH_H_
@@ -97,8 +99,6 @@ typedef struct sctp_authinformation {
uint16_t recv_keyid; /* last recv keyid (cached) */
} sctp_authinfo_t;
-
-
/*
* Macros
*/
@@ -147,7 +147,6 @@ extern void sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t keyid);
extern void sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t keyid,
int so_locked);
-
/* hmac list handling */
extern sctp_hmaclist_t *sctp_alloc_hmaclist(uint16_t num_hmacs);
extern void sctp_free_hmaclist(sctp_hmaclist_t *list);
@@ -168,8 +167,6 @@ extern uint32_t sctp_get_auth_chunk_len(uint16_t hmac_algo);
extern uint32_t sctp_get_hmac_digest_len(uint16_t hmac_algo);
extern uint32_t sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
uint8_t *text, uint32_t textlen, uint8_t *digest);
-extern int sctp_verify_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
- uint8_t *text, uint32_t textlen, uint8_t *digest, uint32_t digestlen);
extern uint32_t sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key,
uint8_t *text, uint32_t textlen, uint8_t *digest);
extern int sctp_auth_is_supported_hmac(sctp_hmaclist_t *list, uint16_t id);
diff --git a/netwerk/sctp/src/netinet/sctp_bsd_addr.c b/netwerk/sctp/src/netinet/sctp_bsd_addr.c
index f79b9ebb1a..fa7b87766b 100755
--- a/netwerk/sctp/src/netinet/sctp_bsd_addr.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 276914 2015-01-10 20:49:57Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 366426 2020-10-04 15:37:34Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -48,13 +50,11 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 276914 2015-01-10 20:49:57Z
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_indata.h>
-
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/unistd.h>
#endif
/* Declare all of our malloc named types */
-#ifndef __Panda__
MALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor");
MALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array");
MALLOC_DEFINE(SCTP_M_STRMO, "sctp_stro", "sctp stream out array");
@@ -75,12 +75,11 @@ MALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", "sctp mvrf pcb list");
MALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control");
MALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option");
MALLOC_DEFINE(SCTP_M_MCORE, "sctp_mcore", "sctp mcore queue");
-#endif
/* Global NON-VNET structure that controls the iterator */
struct iterator_control sctp_it_ctl;
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
-#if !defined(__FreeBSD__)
static void
sctp_cleanup_itqueue(void)
{
@@ -108,7 +107,7 @@ void
sctp_wakeup_iterator(void)
{
#if defined(SCTP_PROCESS_LEVEL_LOCKS)
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
WakeAllConditionVariable(&sctp_it_ctl.iterator_wakeup);
#else
pthread_cond_broadcast(&sctp_it_ctl.iterator_wakeup);
@@ -125,9 +124,12 @@ static void
#endif
sctp_iterator_thread(void *v SCTP_UNUSED)
{
+#if defined(__Userspace__)
+ sctp_userspace_set_threadname("SCTP iterator");
+#endif
SCTP_IPI_ITERATOR_WQ_LOCK();
/* In FreeBSD this thread never terminates. */
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
for (;;) {
#else
while ((sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) == 0) {
@@ -136,25 +138,25 @@ sctp_iterator_thread(void *v SCTP_UNUSED)
msleep(&sctp_it_ctl.iterator_running,
#if defined(__FreeBSD__)
&sctp_it_ctl.ipi_iterator_wq_mtx,
-#elif defined(__APPLE__) || defined(__Userspace_os_Darwin)
+#elif defined(__APPLE__)
sctp_it_ctl.ipi_iterator_wq_mtx,
#endif
0, "waiting_for_work", 0);
#else
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SleepConditionVariableCS(&sctp_it_ctl.iterator_wakeup, &sctp_it_ctl.ipi_iterator_wq_mtx, INFINITE);
#else
pthread_cond_wait(&sctp_it_ctl.iterator_wakeup, &sctp_it_ctl.ipi_iterator_wq_mtx);
#endif
#endif
-#if !defined(__FreeBSD__)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) {
break;
}
#endif
sctp_iterator_worker();
}
-#if !defined(__FreeBSD__)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
/* Now this thread needs to be terminated */
sctp_cleanup_itqueue();
sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_EXITED;
@@ -183,12 +185,14 @@ sctp_startup_iterator(void)
SCTP_ITERATOR_LOCK_INIT();
SCTP_IPI_ITERATOR_WQ_INIT();
TAILQ_INIT(&sctp_it_ctl.iteratorhead);
-#if defined(__FreeBSD__)
-#if __FreeBSD_version <= 701000
- kthread_create(sctp_iterator_thread,
-#else
+#if defined(__Userspace__)
+ if (sctp_userspace_thread_create(&sctp_it_ctl.thread_proc, &sctp_iterator_thread)) {
+ SCTP_PRINTF("ERROR: Creating sctp_iterator_thread failed.\n");
+ } else {
+ SCTP_BASE_VAR(iterator_thread_started) = 1;
+ }
+#elif defined(__FreeBSD__)
kproc_create(sctp_iterator_thread,
-#endif
(void *)NULL,
&sctp_it_ctl.thread_proc,
RFPROC,
@@ -196,14 +200,6 @@ sctp_startup_iterator(void)
SCTP_KTRHEAD_NAME);
#elif defined(__APPLE__)
kernel_thread_start((thread_continue_t)sctp_iterator_thread, NULL, &sctp_it_ctl.thread_proc);
-#elif defined(__Userspace__)
-#if defined(__Userspace_os_Windows)
- if ((sctp_it_ctl.thread_proc = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&sctp_iterator_thread, NULL, 0, NULL)) == NULL) {
-#else
- if (pthread_create(&sctp_it_ctl.thread_proc, NULL, &sctp_iterator_thread, NULL)) {
-#endif
- SCTP_PRINTF("ERROR: Creating sctp_iterator_thread failed.\n");
- }
#endif
}
@@ -248,7 +244,6 @@ sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa)
#endif /* __Userspace__ */
#endif /* INET6 */
-
#if !defined(__Userspace__)
static uint32_t
sctp_is_desired_interface_type(struct ifnet *ifn)
@@ -256,7 +251,7 @@ sctp_is_desired_interface_type(struct ifnet *ifn)
int result;
/* check the interface type to see if it's one we care about */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
switch(ifnet_type(ifn)) {
#else
switch (ifn->if_type) {
@@ -282,7 +277,7 @@ sctp_is_desired_interface_type(struct ifnet *ifn)
case IFT_GIF:
case IFT_L2VLAN:
case IFT_STF:
-#if !defined(__APPLE__)
+#if !(defined(__APPLE__) && !defined(__Userspace__))
case IFT_IP:
case IFT_IPOVERCDLC:
case IFT_IPOVERCLAW:
@@ -298,21 +293,29 @@ sctp_is_desired_interface_type(struct ifnet *ifn)
return (result);
}
#endif
+#if defined(__APPLE__) && !defined(__Userspace__)
-#if defined(__APPLE__)
int
sctp_is_vmware_interface(struct ifnet *ifn)
{
return (strncmp(ifnet_name(ifn), "vmnet", 5) == 0);
}
+
#endif
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32) && defined(__Userspace__)
+#ifdef MALLOC
+#undef MALLOC
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#endif
+#ifdef FREE
+#undef FREE
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+#endif
static void
sctp_init_ifns_for_vrf(int vrfid)
{
#if defined(INET) || defined(INET6)
- struct ifaddrs *ifa;
struct sctp_ifa *sctp_ifa;
DWORD Err, AdapterAddrsSize;
PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt;
@@ -338,6 +341,7 @@ sctp_init_ifns_for_vrf(int vrfid)
/* Get actual adapter information */
if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) {
SCTP_PRINTF("GetAdaptersV4Addresses() failed with error code %d\n", Err);
+ FREE(pAdapterAddrs);
return;
}
/* Enumerate through each returned adapter and save its information */
@@ -347,20 +351,14 @@ sctp_init_ifns_for_vrf(int vrfid)
if (IN4_ISLINKLOCAL_ADDRESS(&(((struct sockaddr_in *)(pUnicast->Address.lpSockaddr))->sin_addr))) {
continue;
}
- ifa = (struct ifaddrs*)malloc(sizeof(struct ifaddrs));
- ifa->ifa_name = _strdup(pAdapt->AdapterName);
- ifa->ifa_flags = pAdapt->Flags;
- ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in));
- memcpy(ifa->ifa_addr, pUnicast->Address.lpSockaddr, sizeof(struct sockaddr_in));
-
sctp_ifa = sctp_add_addr_to_vrf(0,
- ifa,
+ NULL,
pAdapt->IfIndex,
(pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType,
- ifa->ifa_name,
- (void *)ifa,
- ifa->ifa_addr,
- ifa->ifa_flags,
+ pAdapt->AdapterName,
+ NULL,
+ pUnicast->Address.lpSockaddr,
+ pAdapt->Flags,
0);
if (sctp_ifa) {
sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
@@ -368,8 +366,7 @@ sctp_init_ifns_for_vrf(int vrfid)
}
}
}
- if (pAdapterAddrs)
- GlobalFree(pAdapterAddrs);
+ FREE(pAdapterAddrs);
#endif
#ifdef INET6
AdapterAddrsSize = 0;
@@ -389,25 +386,21 @@ sctp_init_ifns_for_vrf(int vrfid)
/* Get actual adapter information */
if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) {
SCTP_PRINTF("GetAdaptersV6Addresses() failed with error code %d\n", Err);
+ FREE(pAdapterAddrs);
return;
}
/* Enumerate through each returned adapter and save its information */
for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) {
if (pAdapt->IfType == IF_TYPE_IEEE80211 || pAdapt->IfType == IF_TYPE_ETHERNET_CSMACD) {
for (pUnicast = pAdapt->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) {
- ifa = (struct ifaddrs*)malloc(sizeof(struct ifaddrs));
- ifa->ifa_name = _strdup(pAdapt->AdapterName);
- ifa->ifa_flags = pAdapt->Flags;
- ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in6));
- memcpy(ifa->ifa_addr, pUnicast->Address.lpSockaddr, sizeof(struct sockaddr_in6));
sctp_ifa = sctp_add_addr_to_vrf(0,
- ifa,
+ NULL,
pAdapt->Ipv6IfIndex,
(pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType,
- ifa->ifa_name,
- (void *)ifa,
- ifa->ifa_addr,
- ifa->ifa_flags,
+ pAdapt->AdapterName,
+ NULL,
+ pUnicast->Address.lpSockaddr,
+ pAdapt->Flags,
0);
if (sctp_ifa) {
sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
@@ -415,8 +408,7 @@ sctp_init_ifns_for_vrf(int vrfid)
}
}
}
- if (pAdapterAddrs)
- GlobalFree(pAdapterAddrs);
+ FREE(pAdapterAddrs);
#endif
}
#elif defined(__Userspace__)
@@ -425,15 +417,15 @@ sctp_init_ifns_for_vrf(int vrfid)
{
#if defined(INET) || defined(INET6)
int rc;
- struct ifaddrs *ifa = NULL;
+ struct ifaddrs *ifa, *ifas;
struct sctp_ifa *sctp_ifa;
uint32_t ifa_flags;
- rc = getifaddrs(&g_interfaces);
+ rc = getifaddrs(&ifas);
if (rc != 0) {
return;
}
- for (ifa = g_interfaces; ifa; ifa = ifa->ifa_next) {
+ for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) {
continue;
}
@@ -468,11 +460,11 @@ sctp_init_ifns_for_vrf(int vrfid)
#endif
ifa_flags = 0;
sctp_ifa = sctp_add_addr_to_vrf(vrfid,
- ifa,
+ NULL,
if_nametoindex(ifa->ifa_name),
0,
ifa->ifa_name,
- (void *)ifa,
+ NULL,
ifa->ifa_addr,
ifa_flags,
0);
@@ -480,11 +472,11 @@ sctp_init_ifns_for_vrf(int vrfid)
sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
}
}
+ freeifaddrs(ifas);
#endif
}
#endif
-
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static void
sctp_init_ifns_for_vrf(int vrfid)
{
@@ -543,13 +535,13 @@ sctp_init_ifns_for_vrf(int vrfid)
} else {
ifa_flags = 0;
}
- snprintf(name, SCTP_IFNAMSIZ, "%s%d", ifnet_name(ifn), ifnet_unit(ifn));
+ SCTP_SNPRINTF(name, SCTP_IFNAMSIZ, "%s%d", ifnet_name(ifn), ifnet_unit(ifn));
sctp_ifa = sctp_add_addr_to_vrf(vrfid,
- (void *)ifn,
+ (void *)ifn, /* XXX */
ifnet_index(ifn),
ifnet_type(ifn),
name,
- (void *)ifa,
+ (void *)ifa, /* XXX */
ifa->ifa_addr,
ifa_flags,
0);
@@ -562,8 +554,7 @@ sctp_init_ifns_for_vrf(int vrfid)
ifnet_list_free(ifnetlist);
}
#endif
-
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static void
sctp_init_ifns_for_vrf(int vrfid)
{
@@ -572,6 +563,7 @@ sctp_init_ifns_for_vrf(int vrfid)
* any IFA that exists as we float through the
* list of IFA's
*/
+ struct epoch_tracker et;
struct ifnet *ifn;
struct ifaddr *ifa;
struct sctp_ifa *sctp_ifa;
@@ -581,17 +573,13 @@ sctp_init_ifns_for_vrf(int vrfid)
#endif
IFNET_RLOCK();
- TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) {
+ NET_EPOCH_ENTER(et);
+ CK_STAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) {
if (sctp_is_desired_interface_type(ifn) == 0) {
/* non desired type */
continue;
}
-#if (__FreeBSD_version >= 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000
- IF_ADDR_RLOCK(ifn);
-#else
- IF_ADDR_LOCK(ifn);
-#endif
- TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
+ CK_STAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) {
if (ifa->ifa_addr == NULL) {
continue;
}
@@ -643,12 +631,8 @@ sctp_init_ifns_for_vrf(int vrfid)
sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
}
}
-#if (__FreeBSD_version >= 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000
- IF_ADDR_RUNLOCK(ifn);
-#else
- IF_ADDR_UNLOCK(ifn);
-#endif
}
+ NET_EPOCH_EXIT(et);
IFNET_RUNLOCK();
}
#endif
@@ -676,10 +660,14 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
return;
#else
uint32_t ifa_flags = 0;
+
+ if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
+ return;
+ }
/* BSD only has one VRF, if this changes
* we will need to hook in the right
* things here to get the id to pass to
- * the address managment routine.
+ * the address management routine.
*/
if (SCTP_BASE_VAR(first_time) == 0) {
/* Special test to see if my ::1 will showup with this */
@@ -722,16 +710,15 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
}
if (cmd == RTM_ADD) {
(void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp,
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
ifnet_index(ifa->ifa_ifp), ifnet_type(ifa->ifa_ifp), ifnet_name(ifa->ifa_ifp),
#else
ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname,
#endif
(void *)ifa, ifa->ifa_addr, ifa_flags, 1);
} else {
-
sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr,
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
ifnet_index(ifa->ifa_ifp),
ifnet_name(ifa->ifa_ifp));
#else
@@ -746,26 +733,13 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
#endif
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
void
-sctp_add_or_del_interfaces(int (*pred)(struct ifnet *), int add)
-{
- struct ifnet *ifn;
- struct ifaddr *ifa;
-
- IFNET_RLOCK();
- TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) {
- if (!(*pred)(ifn)) {
- continue;
- }
- TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
- sctp_addr_change(ifa, add ? RTM_ADD : RTM_DELETE);
- }
- }
- IFNET_RUNLOCK();
+sctp_addr_change_event_handler(void *arg __unused, struct ifaddr *ifa, int cmd) {
+ sctp_addr_change(ifa, cmd);
}
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
void
sctp_add_or_del_interfaces(int (*pred)(struct ifnet *), int add)
{
@@ -797,149 +771,52 @@ struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
int how, int allonebuf, int type)
{
- struct mbuf *m = NULL;
+ struct mbuf *m = NULL;
+#if defined(__FreeBSD__) || defined(__Userspace__)
#if defined(__Userspace__)
-
- /*
- * __Userspace__
- * Using m_clget, which creates and mbuf and a cluster and
- * hooks those together.
- * TODO: This does not yet have functionality for jumbo packets.
- *
- */
-
- int mbuf_threshold;
- if (want_header) {
- MGETHDR(m, how, type);
- } else {
- MGET(m, how, type);
- }
- if (m == NULL) {
- return (NULL);
- }
- if (allonebuf == 0)
- mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count);
- else
- mbuf_threshold = 1;
-
-
- 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);
- }
- }
- SCTP_BUF_LEN(m) = 0;
- SCTP_BUF_NEXT(m) = SCTP_BUF_NEXT_PKT(m) = NULL;
-
- /* __Userspace__
- * Check if anything need to be done to ensure logging works
- */
-#ifdef SCTP_MBUF_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- sctp_log_mb(m, SCTP_MBUF_IALLOC);
- }
-#endif
-#elif defined(__FreeBSD__) && __FreeBSD_version > 1100052
+ m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0, allonebuf);
+#else
m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
+#endif
if (m == NULL) {
/* bad, no memory */
return (m);
}
+#if !defined(__Userspace__)
if (allonebuf) {
if (SCTP_BUF_SIZE(m) < space_needed) {
m_freem(m);
return (NULL);
}
- }
- if (SCTP_BUF_NEXT(m)) {
- sctp_m_freem(SCTP_BUF_NEXT(m));
- SCTP_BUF_NEXT(m) = NULL;
- }
-#ifdef SCTP_MBUF_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- sctp_log_mb(m, SCTP_MBUF_IALLOC);
+ KASSERT(SCTP_BUF_NEXT(m) == NULL, ("%s: no chain allowed", __func__));
}
#endif
-#elif defined(__FreeBSD__) && __FreeBSD_version > 602000
- m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
- if (m == NULL) {
- /* bad, no memory */
- return (m);
- }
- if (allonebuf) {
- int siz;
- if (SCTP_BUF_IS_EXTENDED(m)) {
- siz = SCTP_BUF_EXTEND_SIZE(m);
- } else {
- if (want_header)
- siz = MHLEN;
- else
- siz = MLEN;
- }
- if (siz < space_needed) {
- m_freem(m);
- return (NULL);
- }
- }
- if (SCTP_BUF_NEXT(m)) {
- sctp_m_freem(SCTP_BUF_NEXT(m));
- SCTP_BUF_NEXT(m) = NULL;
- }
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
sctp_log_mb(m, SCTP_MBUF_IALLOC);
}
#endif
#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 601000
- int aloc_size;
- int index = 0;
-#endif
int mbuf_threshold;
+ unsigned int size;
+
if (want_header) {
MGETHDR(m, how, type);
+ size = MHLEN;
} else {
MGET(m, how, type);
+ size = MLEN;
}
if (m == NULL) {
return (NULL);
}
- if (allonebuf == 0)
+ if (allonebuf == 0) {
mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count);
- else
+ } else {
mbuf_threshold = 1;
+ }
-
- if (space_needed > (((mbuf_threshold - 1) * MLEN) + MHLEN)) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 601000
- try_again:
- index = 4;
- if (space_needed <= MCLBYTES) {
- aloc_size = MCLBYTES;
- } else {
- aloc_size = MJUMPAGESIZE;
- index = 5;
- }
- m_cljget(m, how, aloc_size);
- if (m == NULL) {
- return (NULL);
- }
- if (SCTP_BUF_IS_EXTENDED(m) == 0) {
- if ((aloc_size != MCLBYTES) &&
- (allonebuf == 0)) {
- aloc_size -= 10;
- goto try_again;
- }
- sctp_m_freem(m);
- return (NULL);
- }
-#else
+ if (space_needed > (unsigned int)(((mbuf_threshold - 1) * MLEN) + MHLEN)) {
MCLGET(m, how);
if (m == NULL) {
return (NULL);
@@ -948,7 +825,11 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
sctp_m_freem(m);
return (NULL);
}
-#endif
+ size = SCTP_BUF_EXTEND_SIZE(m);
+ }
+ if (allonebuf != 0 && size < space_needed) {
+ m_freem(m);
+ return (NULL);
}
SCTP_BUF_LEN(m) = 0;
SCTP_BUF_NEXT(m) = SCTP_BUF_NEXT_PKT(m) = NULL;
@@ -961,7 +842,6 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
return (m);
}
-
#ifdef SCTP_PACKET_LOGGING
void
sctp_packet_log(struct mbuf *m)
@@ -1037,7 +917,6 @@ sctp_packet_log(struct mbuf *m)
SCTP_BASE_VAR(packet_log_end));
SCTP_BASE_VAR(packet_log_end) = 0;
goto no_log;
-
}
lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisbegin];
*lenat = total_len;
@@ -1063,7 +942,6 @@ sctp_packet_log(struct mbuf *m)
atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), 1);
}
-
int
sctp_copy_out_packet_log(uint8_t *target, int length)
{
diff --git a/netwerk/sctp/src/netinet/sctp_bsd_addr.h b/netwerk/sctp/src/netinet/sctp_bsd_addr.h
index 8373b3b834..d6ab91b5b5 100755
--- a/netwerk/sctp/src/netinet/sctp_bsd_addr.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.h 237540 2012-06-24 21:25:54Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_BSD_ADDR_H_
@@ -47,7 +49,6 @@ void sctp_wakeup_iterator(void);
void sctp_startup_iterator(void);
-
#ifdef INET6
void sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa);
#endif
@@ -59,8 +60,10 @@ int sctp_copy_out_packet_log(uint8_t *target, int length);
#endif
-#if !defined(__Panda__)
void sctp_addr_change(struct ifaddr *ifa, int cmd);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+
+void sctp_addr_change_event_handler(void *, struct ifaddr *, int);
#endif
void sctp_add_or_del_interfaces(int (*pred)(struct ifnet *), int add);
diff --git a/netwerk/sctp/src/netinet/sctp_callout.c b/netwerk/sctp/src/netinet/sctp_callout.c
index 3174e3fd4b..4c9be7568b 100755
--- a/netwerk/sctp/src/netinet/sctp_callout.c
+++ b/netwerk/sctp/src/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.
@@ -32,18 +34,19 @@
#if defined(__Userspace__)
#include <sys/types.h>
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#endif
-#if defined(__Userspace_os_NaCl)
+#if defined(__native_client__)
#include <sys/select.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
+#include <user_atomic.h>
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_pcb.h>
#else
@@ -51,16 +54,26 @@
#include <netinet/sctp_callout.h>
#include <netinet/sctp_pcb.h>
#endif
+#include <netinet/sctputil.h>
/*
* Callout/Timer routines for OS that doesn't have them
*/
#if defined(__APPLE__) || defined(__Userspace__)
-int ticks = 0;
+static uint32_t ticks = 0;
#else
extern int ticks;
#endif
+uint32_t sctp_get_tick_count(void) {
+ uint32_t ret;
+
+ SCTP_TIMERQ_LOCK();
+ ret = ticks;
+ SCTP_TIMERQ_UNLOCK();
+ return ret;
+}
+
/*
* SCTP_TIMERQ_LOCK protects:
* - SCTP_BASE_INFO(callqueue)
@@ -71,20 +84,23 @@ static sctp_os_timer_t *sctp_os_timer_next = NULL;
void
sctp_os_timer_init(sctp_os_timer_t *c)
{
- bzero(c, sizeof(*c));
+ memset(c, 0, sizeof(*c));
}
-void
-sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
+int
+sctp_os_timer_start(sctp_os_timer_t *c, uint32_t to_ticks, void (*ftn) (void *),
void *arg)
{
+ int ret = 0;
+
/* paranoia */
if ((c == NULL) || (ftn == NULL))
- return;
+ return (ret);
SCTP_TIMERQ_LOCK();
/* check to see if we're rescheduling a timer */
if (c->c_flags & SCTP_CALLOUT_PENDING) {
+ ret = 1;
if (c == sctp_os_timer_next) {
sctp_os_timer_next = TAILQ_NEXT(c, tqe);
}
@@ -101,7 +117,7 @@ sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
* We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL,
* but there's no point since doing this setup doesn't take much time.
*/
- if (to_ticks <= 0)
+ if (to_ticks == 0)
to_ticks = 1;
c->c_arg = arg;
@@ -110,6 +126,7 @@ sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
c->c_time = ticks + to_ticks;
TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe);
SCTP_TIMERQ_UNLOCK();
+ return (ret);
}
int
@@ -133,8 +150,8 @@ sctp_os_timer_stop(sctp_os_timer_t *c)
return (1);
}
-static void
-sctp_handle_tick(int delta)
+void
+sctp_handle_tick(uint32_t elapsed_ticks)
{
sctp_os_timer_t *c;
void (*c_func)(void *);
@@ -142,10 +159,10 @@ sctp_handle_tick(int delta)
SCTP_TIMERQ_LOCK();
/* update our tick count */
- ticks += delta;
+ ticks += elapsed_ticks;
c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue));
while (c) {
- if (c->c_time <= ticks) {
+ if (SCTP_UINT32_GE(ticks, c->c_time)) {
sctp_os_timer_next = TAILQ_NEXT(c, tqe);
TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
c_func = c->c_func;
@@ -163,7 +180,7 @@ sctp_handle_tick(int delta)
SCTP_TIMERQ_UNLOCK();
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
void
sctp_timeout(void *arg SCTP_UNUSED)
{
@@ -178,43 +195,55 @@ sctp_timeout(void *arg SCTP_UNUSED)
void *
user_sctp_timer_iterate(void *arg)
{
+ sctp_userspace_set_threadname("SCTP timer");
for (;;) {
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
Sleep(TIMEOUT_INTERVAL);
#else
- struct timeval timeout;
+ struct timespec amount, remaining;
- timeout.tv_sec = 0;
- timeout.tv_usec = 1000 * TIMEOUT_INTERVAL;
- select(0, NULL, NULL, NULL, &timeout);
+ remaining.tv_sec = 0;
+ remaining.tv_nsec = TIMEOUT_INTERVAL * 1000 * 1000;
+ do {
+ amount = remaining;
+ } while (nanosleep(&amount, &remaining) == -1);
#endif
- if (SCTP_BASE_VAR(timer_thread_should_exit)) {
+ if (atomic_cmpset_int(&SCTP_BASE_VAR(timer_thread_should_exit), 1, 1)) {
break;
}
- sctp_handle_tick(MSEC_TO_TICKS(TIMEOUT_INTERVAL));
+ sctp_handle_tick(sctp_msecs_to_ticks(TIMEOUT_INTERVAL));
}
return (NULL);
}
void
-sctp_start_timer(void)
+sctp_start_timer_thread(void)
{
/*
* No need to do SCTP_TIMERQ_LOCK_INIT();
* here, it is being done in sctp_pcb_init()
*/
-#if defined (__Userspace_os_Windows)
- if ((SCTP_BASE_VAR(timer_thread) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)user_sctp_timer_iterate, NULL, 0, NULL)) == NULL) {
- SCTP_PRINTF("ERROR; Creating ithread failed\n");
- }
-#else
int rc;
- rc = pthread_create(&SCTP_BASE_VAR(timer_thread), NULL, user_sctp_timer_iterate, NULL);
+ rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(timer_thread), user_sctp_timer_iterate);
if (rc) {
- SCTP_PRINTF("ERROR; return code from pthread_create() is %d\n", rc);
+ SCTP_PRINTF("ERROR; return code from sctp_thread_create() is %d\n", rc);
+ } else {
+ SCTP_BASE_VAR(timer_thread_started) = 1;
}
-#endif
}
+void
+sctp_stop_timer_thread(void)
+{
+ atomic_cmpset_int(&SCTP_BASE_VAR(timer_thread_should_exit), 0, 1);
+ if (SCTP_BASE_VAR(timer_thread_started)) {
+#if defined(_WIN32)
+ WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE);
+ CloseHandle(SCTP_BASE_VAR(timer_thread));
+#else
+ pthread_join(SCTP_BASE_VAR(timer_thread), NULL);
+#endif
+ }
+}
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_callout.h b/netwerk/sctp/src/netinet/sctp_callout.h
index c53c5a4fc7..81fd8530d1 100755
--- a/netwerk/sctp/src/netinet/sctp_callout.h
+++ b/netwerk/sctp/src/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.
@@ -28,7 +30,7 @@
* SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#endif
@@ -51,26 +53,31 @@ __FBSDID("$FreeBSD$");
#define SCTP_TICKS_PER_FASTTIMO 20 /* called about every 20ms */
#if defined(__Userspace__)
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#define SCTP_TIMERQ_LOCK() EnterCriticalSection(&SCTP_BASE_VAR(timer_mtx))
#define SCTP_TIMERQ_UNLOCK() LeaveCriticalSection(&SCTP_BASE_VAR(timer_mtx))
#define SCTP_TIMERQ_LOCK_INIT() InitializeCriticalSection(&SCTP_BASE_VAR(timer_mtx))
#define SCTP_TIMERQ_LOCK_DESTROY() DeleteCriticalSection(&SCTP_BASE_VAR(timer_mtx))
#else
+#ifdef INVARIANTS
+#define SCTP_TIMERQ_LOCK() KASSERT(pthread_mutex_lock(&SCTP_BASE_VAR(timer_mtx)) == 0, ("%s: timer_mtx already locked", __func__))
+#define SCTP_TIMERQ_UNLOCK() KASSERT(pthread_mutex_unlock(&SCTP_BASE_VAR(timer_mtx)) == 0, ("%s: timer_mtx not locked", __func__))
+#else
#define SCTP_TIMERQ_LOCK() (void)pthread_mutex_lock(&SCTP_BASE_VAR(timer_mtx))
#define SCTP_TIMERQ_UNLOCK() (void)pthread_mutex_unlock(&SCTP_BASE_VAR(timer_mtx))
-#define SCTP_TIMERQ_LOCK_INIT() (void)pthread_mutex_init(&SCTP_BASE_VAR(timer_mtx), NULL)
+#endif
+#define SCTP_TIMERQ_LOCK_INIT() (void)pthread_mutex_init(&SCTP_BASE_VAR(timer_mtx), &SCTP_BASE_VAR(mtx_attr))
#define SCTP_TIMERQ_LOCK_DESTROY() (void)pthread_mutex_destroy(&SCTP_BASE_VAR(timer_mtx))
#endif
-
-extern int ticks;
#endif
+uint32_t sctp_get_tick_count(void);
+
TAILQ_HEAD(calloutlist, sctp_callout);
struct sctp_callout {
TAILQ_ENTRY(sctp_callout) tqe;
- int c_time; /* ticks to the event */
+ uint32_t c_time; /* ticks to the event */
void *c_arg; /* function argument */
void (*c_func)(void *); /* function to call */
int c_flags; /* state of this entry */
@@ -81,10 +88,18 @@ typedef struct sctp_callout sctp_os_timer_t;
#define SCTP_CALLOUT_PENDING 0x0004 /* callout is waiting for timeout */
void sctp_os_timer_init(sctp_os_timer_t *tmr);
-void sctp_os_timer_start(sctp_os_timer_t *, int, void (*)(void *), void *);
+/* Returns 1 if pending timer was rescheduled, 0 otherwise. */
+int sctp_os_timer_start(sctp_os_timer_t *, uint32_t, void (*)(void *), void *);
+/* Returns 1 if pending timer was stopped, 0 otherwise. */
int sctp_os_timer_stop(sctp_os_timer_t *);
+void sctp_handle_tick(uint32_t);
#define SCTP_OS_TIMER_INIT sctp_os_timer_init
+/*
+ * NOTE: The next two shouldn't be called directly outside of sctp_timer_start()
+ * and sctp_timer_stop(), since they don't handle incrementing/decrementing
+ * relevant reference counts.
+ */
#define SCTP_OS_TIMER_START sctp_os_timer_start
#define SCTP_OS_TIMER_STOP sctp_os_timer_stop
/* MT FIXME: Is the following correct? */
@@ -94,9 +109,10 @@ int sctp_os_timer_stop(sctp_os_timer_t *);
#define SCTP_OS_TIMER_DEACTIVATE(tmr) ((tmr)->c_flags &= ~SCTP_CALLOUT_ACTIVE)
#if defined(__Userspace__)
-void sctp_start_timer(void);
+void sctp_start_timer_thread(void);
+void sctp_stop_timer_thread(void);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
void sctp_timeout(void *);
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_cc_functions.c b/netwerk/sctp/src/netinet/sctp_cc_functions.c
index 0e01c9860d..57bcdaaa5a 100755
--- a/netwerk/sctp/src/netinet/sctp_cc_functions.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 279859 2015-03-10 19:49:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 366517 2020-10-07 15:22:48Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -48,8 +50,8 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 279859 2015-03-10 19:49
#include <netinet/sctp_timer.h>
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
-#include <netinet/sctp_dtrace_declare.h>
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <netinet/sctp_kdtrace.h>
#endif
#define SHIFT_MPTCP_MULTI_N 40
@@ -62,7 +64,7 @@ sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net)
if ((assoc->max_cwnd > 0) &&
(net->cwnd > assoc->max_cwnd) &&
(net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
- net->cwnd = assoc->max_cwnd ;
+ net->cwnd = assoc->max_cwnd;
if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
net->cwnd = net->mtu - sizeof(struct sctphdr);
}
@@ -99,8 +101,8 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
}
sctp_enforce_cwnd_limit(assoc, net);
net->ssthresh = assoc->peers_rwnd;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, init,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, init,
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
0, net->cwnd);
#endif
@@ -161,7 +163,6 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
(uint64_t)net->mtu *
(uint64_t)net->ssthresh) /
(uint64_t)t_ssthresh);
-
}
if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) {
uint32_t srtt;
@@ -194,8 +195,8 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
}
net->cwnd = net->ssthresh;
sctp_enforce_cwnd_limit(asoc, net);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, fr,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, fr,
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
old_cwnd, net->cwnd);
#endif
@@ -212,7 +213,7 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
/* Mark end of the window */
asoc->fast_recovery_tsn = asoc->sending_seq - 1;
} else {
- asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
+ asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
}
/*
@@ -225,11 +226,12 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
/* Mark end of the window */
net->fast_recovery_tsn = asoc->sending_seq - 1;
} else {
- net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
+ net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
}
sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA+SCTP_LOC_32 );
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1);
sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, net);
}
@@ -244,26 +246,25 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
}
/* Defines for instantaneous bw decisions */
-#define SCTP_INST_LOOSING 1 /* Loosing to other flows */
+#define SCTP_INST_LOOSING 1 /* Losing to other flows */
#define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */
#define SCTP_INST_GAINING 3 /* Gaining, step down possible */
-
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static int
cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw,
- uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind)
+ uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind)
#else
static int
cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nbw,
- uint64_t rtt_offset, uint8_t inst_ind)
+ uint64_t rtt_offset, uint8_t inst_ind)
#endif
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t oth, probepoint;
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
probepoint = (((uint64_t)net->cwnd) << 32);
#endif
if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
@@ -272,10 +273,10 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb
* we don't update bw.. so we don't
* update the rtt either.
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Probe point 5 */
probepoint |= ((5 << 16) | 1);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -292,13 +293,13 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb
((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
/* Try a step down */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
oth = net->cc_mod.rtcc.vol_reduce;
oth <<= 16;
oth |= net->cc_mod.rtcc.step_cnt;
oth <<= 16;
oth |= net->cc_mod.rtcc.last_step_state;
- SDT_PROBE(sctp, cwnd, net, rttstep,
+ SDT_PROBE5(sctp, cwnd, net, rttstep,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -321,10 +322,10 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb
* we update both the bw and the rtt here to
* lock this in as a good step down.
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Probe point 6 */
probepoint |= ((6 << 16) | 0);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -332,13 +333,13 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb
probepoint);
#endif
if (net->cc_mod.rtcc.steady_step) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
oth = net->cc_mod.rtcc.vol_reduce;
oth <<= 16;
oth |= net->cc_mod.rtcc.step_cnt;
oth <<= 16;
oth |= net->cc_mod.rtcc.last_step_state;
- SDT_PROBE(sctp, cwnd, net, rttstep,
+ SDT_PROBE5(sctp, cwnd, net, rttstep,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -367,10 +368,10 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb
}
/* Ok bw and rtt remained the same .. no update to any
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Probe point 7 */
probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -404,22 +405,22 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb
return ((int)net->cc_mod.rtcc.ret_from_eq);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static int
cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset,
- uint64_t vtag, uint8_t inst_ind)
+ uint64_t vtag, uint8_t inst_ind)
#else
static int
cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset,
- uint8_t inst_ind)
+ uint8_t inst_ind)
#endif
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t oth, probepoint;
#endif
/* Bandwidth decreased.*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
probepoint = (((uint64_t)net->cwnd) << 32);
#endif
if (net->rtt > net->cc_mod.rtcc.lbw_rtt+rtt_offset) {
@@ -428,10 +429,10 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) &&
(inst_ind != SCTP_INST_LOOSING)) {
/* We caused it maybe.. back off? */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* PROBE POINT 1 */
probepoint |= ((1 << 16) | 1);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -445,10 +446,10 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
}
return (1);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Probe point 2 */
probepoint |= ((2 << 16) | 0);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -457,13 +458,13 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
#endif
/* Someone else - fight for more? */
if (net->cc_mod.rtcc.steady_step) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
oth = net->cc_mod.rtcc.vol_reduce;
oth <<= 16;
oth |= net->cc_mod.rtcc.step_cnt;
oth <<= 16;
oth |= net->cc_mod.rtcc.last_step_state;
- SDT_PROBE(sctp, cwnd, net, rttstep,
+ SDT_PROBE5(sctp, cwnd, net, rttstep,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -485,10 +486,10 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
goto out_decision;
} else if (net->rtt < net->cc_mod.rtcc.lbw_rtt-rtt_offset) {
/* bw & rtt decreased */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Probe point 3 */
probepoint |= ((3 << 16) | 0);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -496,13 +497,13 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
probepoint);
#endif
if (net->cc_mod.rtcc.steady_step) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
oth = net->cc_mod.rtcc.vol_reduce;
oth <<= 16;
oth |= net->cc_mod.rtcc.step_cnt;
oth <<= 16;
oth |= net->cc_mod.rtcc.last_step_state;
- SDT_PROBE(sctp, cwnd, net, rttstep,
+ SDT_PROBE5(sctp, cwnd, net, rttstep,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -521,10 +522,10 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
goto out_decision;
}
/* The bw decreased but rtt stayed the same */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Probe point 4 */
probepoint |= ((4 << 16) | 0);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -532,13 +533,13 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
probepoint);
#endif
if (net->cc_mod.rtcc.steady_step) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
oth = net->cc_mod.rtcc.vol_reduce;
oth <<= 16;
oth |= net->cc_mod.rtcc.step_cnt;
oth <<= 16;
oth |= net->cc_mod.rtcc.last_step_state;
- SDT_PROBE(sctp, cwnd, net, rttstep,
+ SDT_PROBE5(sctp, cwnd, net, rttstep,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -565,7 +566,7 @@ out_decision:
}
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static int
cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag)
#else
@@ -573,7 +574,7 @@ static int
cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nbw)
#endif
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t oth, probepoint;
#endif
@@ -583,10 +584,10 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
* update. Note that we pay no attention to
* the inst_ind since our overall sum is increasing.
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* PROBE POINT 0 */
probepoint = (((uint64_t)net->cwnd) << 32);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -594,13 +595,13 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
probepoint);
#endif
if (net->cc_mod.rtcc.steady_step) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
oth = net->cc_mod.rtcc.vol_reduce;
oth <<= 16;
oth |= net->cc_mod.rtcc.step_cnt;
oth <<= 16;
oth |= net->cc_mod.rtcc.last_step_state;
- SDT_PROBE(sctp, cwnd, net, rttstep,
+ SDT_PROBE5(sctp, cwnd, net, rttstep,
vtag,
((net->cc_mod.rtcc.lbw << 32) | nbw),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -617,14 +618,14 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_
return (0);
}
-/* RTCC Algoritm to limit growth of cwnd, return
+/* RTCC Algorithm to limit growth of cwnd, return
* true if you want to NOT allow cwnd growth
*/
static int
cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
{
uint64_t bw_offset, rtt_offset;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t probepoint, rtt, vtag;
#endif
uint64_t bytes_for_this_rtt, inst_bw;
@@ -670,7 +671,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
* change within 1/32nd
*/
bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
rtt = stcb->asoc.my_vtag;
vtag = (rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport);
probepoint = (((uint64_t)net->cwnd) << 32);
@@ -691,12 +692,12 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
inst_ind = SCTP_INST_LOOSING;
else
inst_ind = SCTP_INST_NEUTRAL;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
probepoint |= ((0xb << 16) | inst_ind);
#endif
} else {
inst_ind = net->cc_mod.rtcc.last_inst_ind;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
inst_bw = bytes_for_this_rtt / (uint64_t)(net->rtt);
/* Can't determine do not change */
probepoint |= ((0xc << 16) | inst_ind);
@@ -704,14 +705,14 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
}
} else {
inst_ind = net->cc_mod.rtcc.last_inst_ind;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
inst_bw = bytes_for_this_rtt;
/* Can't determine do not change */
probepoint |= ((0xd << 16) | inst_ind);
#endif
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, rttvar,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((nbw << 32) | inst_bw),
((net->cc_mod.rtcc.lbw_rtt << 32) | rtt),
@@ -724,7 +725,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
}
bw_offset = net->cc_mod.rtcc.lbw >> bw_shift;
if (nbw > net->cc_mod.rtcc.lbw + bw_offset) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ret = cc_bw_increase(stcb, net, nbw, vtag);
#else
ret = cc_bw_increase(stcb, net, nbw);
@@ -733,7 +734,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
}
rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt);
if (nbw < net->cc_mod.rtcc.lbw - bw_offset) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind);
#else
ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, inst_ind);
@@ -744,7 +745,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
* we are in a situation where
* the bw stayed the same.
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind);
#else
ret = cc_bw_same(stcb, net, nbw, rtt_offset, inst_ind);
@@ -760,7 +761,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc)
{
struct sctp_nets *net;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int old_cwnd;
#endif
uint32_t t_ssthresh, t_cwnd, incr;
@@ -814,7 +815,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
/* update cwnd and Early FR */
/******************************/
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
-
#ifdef JANA_CMT_FAST_RECOVERY
/*
* CMT fast recovery code. Need to debug.
@@ -834,7 +834,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
continue;
}
#ifdef JANA_CMT_FAST_RECOVERY
- /* CMT fast recovery code
+ /* CMT fast recovery code
*/
/*
if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery && net->will_exit_fast_recovery == 0) {
@@ -876,7 +876,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
continue;
}
} else {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t vtag, probepoint;
probepoint = (((uint64_t)net->cwnd) << 32);
@@ -885,7 +885,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
(((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) |
(stcb->rport);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
nbw,
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -912,7 +912,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
if (net->flight_size + net->net_ack >= net->cwnd) {
uint32_t limit;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
old_cwnd = net->cwnd;
#endif
switch (asoc->sctp_cmt_on_off) {
@@ -984,8 +984,8 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
sctp_log_cwnd(stcb, net, incr,
SCTP_CWND_LOG_FROM_SS);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, ack,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, ack,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
@@ -1005,9 +1005,9 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
net->partial_bytes_acked += net->net_ack;
if ((net->flight_size + net->net_ack >= net->cwnd) &&
- (net->partial_bytes_acked >= net->cwnd)) {
+ (net->partial_bytes_acked >= net->cwnd)) {
net->partial_bytes_acked -= net->cwnd;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
old_cwnd = net->cwnd;
#endif
switch (asoc->sctp_cmt_on_off) {
@@ -1048,8 +1048,8 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
}
net->cwnd += incr;
sctp_enforce_cwnd_limit(asoc, net);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, ack,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, ack,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
@@ -1075,7 +1075,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
}
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static void
sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
#else
@@ -1083,14 +1083,14 @@ static void
sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net)
#endif
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int old_cwnd;
old_cwnd = net->cwnd;
#endif
net->cwnd = net->mtu;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, ack,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, ack,
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
old_cwnd, net->cwnd);
#endif
@@ -1098,7 +1098,6 @@ sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_n
(void *)net, net->cwnd);
}
-
static void
sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
{
@@ -1162,8 +1161,8 @@ sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
}
net->cwnd = net->mtu;
net->partial_bytes_acked = 0;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, to,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, to,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
@@ -1176,7 +1175,7 @@ sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
static void
sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net,
- int in_window, int num_pkt_lost, int use_rtcc)
+ int in_window, int num_pkt_lost, int use_rtcc)
{
int old_cwnd = net->cwnd;
if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) {
@@ -1198,16 +1197,15 @@ sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
}
} else {
- /* Further tuning down required over the drastic orginal cut */
+ /* Further tuning down required over the drastic original cut */
net->ssthresh -= (net->mtu * num_pkt_lost);
net->cwnd -= (net->mtu * num_pkt_lost);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
}
-
}
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
- } else {
+ } else {
if (in_window == 0) {
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
net->ssthresh = net->cwnd / 2;
@@ -1217,8 +1215,8 @@ sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *
net->RTO <<= 1;
}
net->cwnd = net->ssthresh;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, ecn,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, ecn,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
@@ -1338,8 +1336,8 @@ sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
sctp_enforce_cwnd_limit(&stcb->asoc, net);
if (net->cwnd - old_cwnd != 0) {
/* log only changes */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, pd,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, pd,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
@@ -1354,7 +1352,7 @@ sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
static void
sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
- struct sctp_nets *net, int burst_limit)
+ struct sctp_nets *net, int burst_limit)
{
int old_cwnd = net->cwnd;
@@ -1363,8 +1361,8 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
if (burst_limit) {
net->cwnd = (net->flight_size + (burst_limit * net->mtu));
sctp_enforce_cwnd_limit(&stcb->asoc, net);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
- SDT_PROBE(sctp, cwnd, net, bl,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SDT_PROBE5(sctp, cwnd, net, bl,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
@@ -1378,44 +1376,42 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
static void
sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- int accum_moved, int reneged_all, int will_exit)
+ struct sctp_association *asoc,
+ int accum_moved, int reneged_all, int will_exit)
{
- /* Passing a zero argument in last disables the rtcc algoritm */
+ /* Passing a zero argument in last disables the rtcc algorithm */
sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0);
}
static void
sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
- int in_window, int num_pkt_lost)
+ int in_window, int num_pkt_lost)
{
- /* Passing a zero argument in last disables the rtcc algoritm */
+ /* Passing a zero argument in last disables the rtcc algorithm */
sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0);
}
/* Here starts the RTCCVAR type CC invented by RRS which
* is a slight mod to RFC2581. We reuse a common routine or
- * two since these algoritms are so close and need to
+ * two since these algorithms are so close and need to
* remain the same.
*/
static void
sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
- int in_window, int num_pkt_lost)
+ int in_window, int num_pkt_lost)
{
sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1);
}
-
-static
-void sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
- struct sctp_tmit_chunk *tp1)
+static void sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
+ struct sctp_tmit_chunk *tp1)
{
net->cc_mod.rtcc.bw_bytes += tp1->send_size;
}
static void
sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED,
- struct sctp_nets *net)
+ struct sctp_nets *net)
{
if (net->cc_mod.rtcc.tls_needs_set > 0) {
/* We had a bw measurment going on */
@@ -1428,21 +1424,21 @@ sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED,
static void
sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
- struct sctp_nets *net)
+ struct sctp_nets *net)
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t vtag, probepoint;
#endif
if (net->cc_mod.rtcc.lbw) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Clear the old bw.. we went to 0 in-flight */
vtag = (net->rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) |
(stcb->rport);
probepoint = (((uint64_t)net->cwnd) << 32);
/* Probe point 8 */
probepoint |= ((8 << 16) | 0);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
((net->cc_mod.rtcc.lbw << 32) | 0),
((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
@@ -1489,21 +1485,21 @@ sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
static void
sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
- struct sctp_nets *net)
+ struct sctp_nets *net)
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint64_t vtag, probepoint;
#endif
sctp_set_initial_cc_param(stcb, net);
stcb->asoc.use_precise_time = 1;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
probepoint = (((uint64_t)net->cwnd) << 32);
probepoint |= ((9 << 16) | 0);
vtag = (net->rtt << 32) |
(((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) |
(stcb->rport);
- SDT_PROBE(sctp, cwnd, net, rttvar,
+ SDT_PROBE5(sctp, cwnd, net, rttvar,
vtag,
0,
0,
@@ -1524,15 +1520,14 @@ sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn);
net->cc_mod.rtcc.step_cnt = 0;
net->cc_mod.rtcc.last_step_state = 0;
-
-
}
static int
sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget,
- struct sctp_cc_option *cc_opt)
+ struct sctp_cc_option *cc_opt)
{
struct sctp_nets *net;
+
if (setorget == 1) {
/* a set */
if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
@@ -1597,10 +1592,10 @@ sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED,
static void
sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- int accum_moved, int reneged_all, int will_exit)
+ struct sctp_association *asoc,
+ int accum_moved, int reneged_all, int will_exit)
{
- /* Passing a one argument at the last enables the rtcc algoritm */
+ /* Passing a one argument at the last enables the rtcc algorithm */
sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1);
}
@@ -1616,13 +1611,13 @@ sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED,
struct sctp_hs_raise_drop {
int32_t cwnd;
- int32_t increase;
- int32_t drop_percent;
+ int8_t increase;
+ int8_t drop_percent;
};
#define SCTP_HS_TABLE_SIZE 73
-struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
+static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
{38, 1, 50}, /* 0 */
{118, 2, 44}, /* 1 */
{221, 3, 41}, /* 2 */
@@ -1722,7 +1717,7 @@ sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
}
}
net->last_hs_used = indx;
- incr = ((sctp_cwnd_adjust[indx].increase) << 10);
+ incr = (((int32_t)sctp_cwnd_adjust[indx].increase) << 10);
net->cwnd += incr;
}
sctp_enforce_cwnd_limit(&stcb->asoc, net);
@@ -1748,7 +1743,7 @@ sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
} else {
/* drop by the proper amount */
net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
- sctp_cwnd_adjust[net->last_hs_used].drop_percent);
+ (int32_t)sctp_cwnd_adjust[net->last_hs_used].drop_percent);
net->cwnd = net->ssthresh;
/* now where are we */
indx = net->last_hs_used;
@@ -1805,7 +1800,7 @@ sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
/* Mark end of the window */
asoc->fast_recovery_tsn = asoc->sending_seq - 1;
} else {
- asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
+ asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
}
/*
@@ -1818,11 +1813,12 @@ sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
/* Mark end of the window */
net->fast_recovery_tsn = asoc->sending_seq - 1;
} else {
- net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
+ net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
}
sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA+SCTP_LOC_32);
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2);
sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, net);
}
@@ -1838,15 +1834,14 @@ sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
static void
sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
+ struct sctp_association *asoc,
+ int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
{
struct sctp_nets *net;
/******************************/
/* update cwnd and Early FR */
/******************************/
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
-
#ifdef JANA_CMT_FAST_RECOVERY
/*
* CMT fast recovery code. Need to debug.
@@ -1866,7 +1861,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
continue;
}
#ifdef JANA_CMT_FAST_RECOVERY
- /* CMT fast recovery code
+ /* CMT fast recovery code
*/
/*
if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery && net->will_exit_fast_recovery == 0) {
@@ -1930,7 +1925,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
}
-
/*
* H-TCP congestion control. The algorithm is detailed in:
* R.N.Shorten, D.J.Leith:
@@ -1939,7 +1933,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
* http://www.hamilton.ie/net/htcp3.pdf
*/
-
static int use_rtt_scaling = 1;
static int use_bandwidth_switch = 1;
@@ -1958,7 +1951,7 @@ htcp_cong_time(struct htcp *ca)
static inline uint32_t
htcp_ccount(struct htcp *ca)
{
- return (htcp_cong_time(ca)/ca->minRTT);
+ return (ca->minRTT == 0 ? htcp_cong_time(ca) : htcp_cong_time(ca)/ca->minRTT);
}
static inline void
@@ -1996,7 +1989,7 @@ measure_rtt(struct sctp_nets *net)
if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) {
if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT)
net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT;
- if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT+MSEC_TO_TICKS(20))
+ if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT+sctp_msecs_to_ticks(20))
net->cc_mod.htcp_ca.maxRTT = srtt;
}
}
@@ -2056,7 +2049,7 @@ htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT)
}
}
- if (ca->modeswitch && minRTT > (uint32_t)MSEC_TO_TICKS(10) && maxRTT) {
+ if (ca->modeswitch && minRTT > sctp_msecs_to_ticks(10) && maxRTT) {
ca->beta = (minRTT<<7)/maxRTT;
if (ca->beta < BETA_MIN)
ca->beta = BETA_MIN;
@@ -2077,19 +2070,19 @@ htcp_alpha_update(struct htcp *ca)
if (diff > (uint32_t)hz) {
diff -= hz;
- factor = 1+ ( 10*diff + ((diff/2)*(diff/2)/hz))/hz;
+ factor = 1+ (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz;
}
if (use_rtt_scaling && minRTT) {
- uint32_t scale = (hz<<3)/(10*minRTT);
- scale = min(max(scale, 1U<<2), 10U<<3); /* clamping ratio to interval [0.5,10]<<3 */
- factor = (factor<<3)/scale;
- if (!factor)
+ uint32_t scale = (hz << 3) / (10 * minRTT);
+ scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to interval [0.5,10]<<3 */
+ factor = (factor << 3) / scale;
+ if (factor != 0)
factor = 1;
}
- ca->alpha = 2*factor*((1<<7)-ca->beta);
- if (!ca->alpha)
+ ca->alpha = 2 * factor * ((1 << 7) - ca->beta);
+ if (ca->alpha != 0)
ca->alpha = ALPHA_BASE;
}
@@ -2127,10 +2120,10 @@ htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
{
/*-
* How to handle these functions?
- * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question.
+ * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question.
* return;
*/
- if (net->cwnd <= net->ssthresh) {
+ if (net->cwnd <= net->ssthresh) {
/* We are in slow start */
if (net->flight_size + net->net_ack >= net->cwnd) {
if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) {
@@ -2146,7 +2139,6 @@ htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
sctp_log_cwnd(stcb, net, net->net_ack,
SCTP_CWND_LOG_FROM_SS);
}
-
}
sctp_enforce_cwnd_limit(&stcb->asoc, net);
} else {
@@ -2163,7 +2155,7 @@ htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
*/
/* What is snd_cwnd_cnt?? */
if (((net->partial_bytes_acked/net->mtu * net->cc_mod.htcp_ca.alpha) >> 7)*net->mtu >= net->cwnd) {
- /*-
+ /*-
* Does SCTP have a cwnd clamp?
* if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS).
*/
@@ -2234,7 +2226,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
/* update cwnd and Early FR */
/******************************/
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
-
#ifdef JANA_CMT_FAST_RECOVERY
/*
* CMT fast recovery code. Need to debug.
@@ -2254,7 +2245,7 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
continue;
}
#ifdef JANA_CMT_FAST_RECOVERY
- /* CMT fast recovery code
+ /* CMT fast recovery code
*/
/*
if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery && net->will_exit_fast_recovery == 0) {
@@ -2331,7 +2322,7 @@ sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
/* Mark end of the window */
asoc->fast_recovery_tsn = asoc->sending_seq - 1;
} else {
- asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
+ asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
}
/*
@@ -2344,11 +2335,12 @@ sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
/* Mark end of the window */
net->fast_recovery_tsn = asoc->sending_seq - 1;
} else {
- net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
+ net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
}
sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA+SCTP_LOC_32);
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, net);
}
@@ -2403,9 +2395,9 @@ sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
}
}
-struct sctp_cc_functions sctp_cc_functions[] = {
+const struct sctp_cc_functions sctp_cc_functions[] = {
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32) && !defined(__MINGW32__)
sctp_set_initial_cc_param,
sctp_cwnd_update_after_sack,
sctp_cwnd_update_exit_pf_common,
@@ -2426,7 +2418,7 @@ struct sctp_cc_functions sctp_cc_functions[] = {
#endif
},
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32) && !defined(__MINGW32__)
sctp_set_initial_cc_param,
sctp_hs_cwnd_update_after_sack,
sctp_cwnd_update_exit_pf_common,
@@ -2447,7 +2439,7 @@ struct sctp_cc_functions sctp_cc_functions[] = {
#endif
},
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32) && !defined(__MINGW32__)
sctp_htcp_set_initial_cc_param,
sctp_htcp_cwnd_update_after_sack,
sctp_cwnd_update_exit_pf_common,
@@ -2468,7 +2460,7 @@ struct sctp_cc_functions sctp_cc_functions[] = {
#endif
},
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32) && !defined(__MINGW32__)
sctp_set_rtcc_initial_cc_param,
sctp_cwnd_update_rtcc_after_sack,
sctp_cwnd_update_exit_pf_common,
diff --git a/netwerk/sctp/src/netinet/sctp_constants.h b/netwerk/sctp/src/netinet/sctp_constants.h
index ff4874d9df..b8e2f2d581 100755
--- a/netwerk/sctp/src/netinet/sctp_constants.h
+++ b/netwerk/sctp/src/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.
@@ -30,18 +32,18 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_constants.h 271204 2014-09-06 19:12:14Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_constants.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_CONSTANTS_H_
#define _NETINET_SCTP_CONSTANTS_H_
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32) && defined(__Userspace__)
extern void getwintimeofday(struct timeval *tv);
-#endif
+#endif
/* IANA assigned port number for SCTP over UDP encapsulation */
#define SCTP_OVER_UDP_TUNNELING_PORT 9899
@@ -71,6 +73,10 @@ extern void getwintimeofday(struct timeval *tv);
*/
#define SCTP_LARGEST_INIT_ACCEPTED (65535 - 2048)
+/* Largest length of a chunk */
+#define SCTP_MAX_CHUNK_LENGTH 0xffff
+/* Largest length of an error cause */
+#define SCTP_MAX_CAUSE_LENGTH 0xffff
/* Number of addresses where we just skip the counting */
#define SCTP_COUNT_LIMIT 40
@@ -86,22 +92,16 @@ extern void getwintimeofday(struct timeval *tv);
/* #define SCTP_AUDITING_ENABLED 1 used for debug/auditing */
#define SCTP_AUDIT_SIZE 256
-
#define SCTP_KTRHEAD_NAME "sctp_iterator"
#define SCTP_KTHREAD_PAGES 0
#define SCTP_MCORE_NAME "sctp_core_worker"
-
/* If you support Multi-VRF how big to
* make the initial array of VRF's to.
*/
#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 */
@@ -266,7 +266,6 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_LOCK_UNKNOWN 2
-
/* number of associations by default for zone allocation */
#define SCTP_MAX_NUM_OF_ASOC 40000
/* how many addresses per assoc remote and local */
@@ -276,7 +275,7 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_DEFAULT_MULTIPLE_ASCONFS 0
/*
- * Theshold for rwnd updates, we have to read (sb_hiwat >>
+ * Threshold for rwnd updates, we have to read (sb_hiwat >>
* SCTP_RWND_HIWAT_SHIFT) before we will look to see if we need to send a
* window update sack. When we look, we compare the last rwnd we sent vs the
* current rwnd. It too must be greater than this value. Using 3 divdes the
@@ -346,6 +345,7 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_RTT_FROM_NON_DATA 0
#define SCTP_RTT_FROM_DATA 1
+#define PR_SCTP_UNORDERED_FLAG 0x0001
/* IP hdr (20/40) + 12+2+2 (enet) + sctp common 12 */
#define SCTP_FIRST_MBUF_RESV 68
@@ -387,15 +387,14 @@ extern void getwintimeofday(struct timeval *tv);
/* align to 32-bit sizes */
#define SCTP_SIZE32(x) ((((x) + 3) >> 2) << 2)
-#define IS_SCTP_CONTROL(a) ((a)->chunk_type != SCTP_DATA)
-#define IS_SCTP_DATA(a) ((a)->chunk_type == SCTP_DATA)
-
+#define IS_SCTP_CONTROL(a) (((a)->chunk_type != SCTP_DATA) && ((a)->chunk_type != SCTP_IDATA))
+#define IS_SCTP_DATA(a) (((a)->chunk_type == SCTP_DATA) || ((a)->chunk_type == SCTP_IDATA))
/* SCTP parameter types */
/*************0x0000 series*************/
#define SCTP_HEARTBEAT_INFO 0x0001
#if defined(__Userspace__)
-#define SCTP_CONN_ADDRESS 0x0004
+#define SCTP_CONN_ADDRESS 0x0004
#endif
#define SCTP_IPV4_ADDRESS 0x0005
#define SCTP_IPV6_ADDRESS 0x0006
@@ -405,43 +404,34 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_HOSTNAME_ADDRESS 0x000b
#define SCTP_SUPPORTED_ADDRTYPE 0x000c
-/* draft-ietf-stewart-tsvwg-strreset-xxx */
+/* RFC 6525 */
#define SCTP_STR_RESET_OUT_REQUEST 0x000d
#define SCTP_STR_RESET_IN_REQUEST 0x000e
#define SCTP_STR_RESET_TSN_REQUEST 0x000f
#define SCTP_STR_RESET_RESPONSE 0x0010
#define SCTP_STR_RESET_ADD_OUT_STREAMS 0x0011
-#define SCTP_STR_RESET_ADD_IN_STREAMS 0x0012
+#define SCTP_STR_RESET_ADD_IN_STREAMS 0x0012
#define SCTP_MAX_RESET_PARAMS 2
-#define SCTP_STREAM_RESET_TSN_DELTA 0x1000
+#define SCTP_STREAM_RESET_TSN_DELTA 0x1000
/*************0x4000 series*************/
/*************0x8000 series*************/
#define SCTP_ECN_CAPABLE 0x8000
-/* draft-ietf-tsvwg-auth-xxx */
+/* RFC 4895 */
#define SCTP_RANDOM 0x8002
#define SCTP_CHUNK_LIST 0x8003
#define SCTP_HMAC_LIST 0x8004
-/*
- * draft-ietf-tsvwg-addip-sctp-xx param=0x8008 len=0xNNNN Byte | Byte | Byte
- * | Byte Byte | Byte ...
- *
- * Where each byte is a chunk type extension supported. For example, to support
- * all chunks one would have (in hex):
- *
- * 80 01 00 09 C0 C1 80 81 82 00 00 00
- *
- * Has the parameter. C0 = PR-SCTP (RFC3758) C1, 80 = ASCONF (addip draft) 81
- * = Packet Drop 82 = Stream Reset 83 = Authentication
- */
-#define SCTP_SUPPORTED_CHUNK_EXT 0x8008
+/* RFC 4820 */
+#define SCTP_PAD 0x8005
+/* RFC 5061 */
+#define SCTP_SUPPORTED_CHUNK_EXT 0x8008
/*************0xC000 series*************/
#define SCTP_PRSCTP_SUPPORTED 0xc000
-/* draft-ietf-tsvwg-addip-sctp */
+/* RFC 5061 */
#define SCTP_ADD_IP_ADDRESS 0xc001
#define SCTP_DEL_IP_ADDRESS 0xc002
#define SCTP_ERROR_CAUSE_IND 0xc003
@@ -449,8 +439,8 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_SUCCESS_REPORT 0xc005
#define SCTP_ULP_ADAPTATION 0xc006
/* behave-nat-draft */
-#define SCTP_HAS_NAT_SUPPORT 0xc007
-#define SCTP_NAT_VTAGS 0xc008
+#define SCTP_HAS_NAT_SUPPORT 0xc007
+#define SCTP_NAT_VTAGS 0xc008
/* bits for TOS field */
#define SCTP_ECT0_BIT 0x02
@@ -464,9 +454,8 @@ extern void getwintimeofday(struct timeval *tv);
/* mask to get sticky */
#define SCTP_STICKY_OPTIONS_MASK 0x0c
-
/*
- * SCTP states for internal state machine XXX (should match "user" values)
+ * SCTP states for internal state machine
*/
#define SCTP_STATE_EMPTY 0x0000
#define SCTP_STATE_INUSE 0x0001
@@ -484,10 +473,14 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_STATE_IN_ACCEPT_QUEUE 0x1000
#define SCTP_STATE_MASK 0x007f
-#define SCTP_GET_STATE(asoc) ((asoc)->state & SCTP_STATE_MASK)
-#define SCTP_SET_STATE(asoc, newstate) ((asoc)->state = ((asoc)->state & ~SCTP_STATE_MASK) | newstate)
-#define SCTP_CLEAR_SUBSTATE(asoc, substate) ((asoc)->state &= ~substate)
-#define SCTP_ADD_SUBSTATE(asoc, substate) ((asoc)->state |= substate)
+#define SCTP_GET_STATE(_stcb) \
+ ((_stcb)->asoc.state & SCTP_STATE_MASK)
+#define SCTP_SET_STATE(_stcb, _state) \
+ sctp_set_state(_stcb, _state)
+#define SCTP_CLEAR_SUBSTATE(_stcb, _substate) \
+ (_stcb)->asoc.state &= ~(_substate)
+#define SCTP_ADD_SUBSTATE(_stcb, _substate) \
+ sctp_add_substate(_stcb, _substate)
/* SCTP reachability state for each address */
#define SCTP_ADDR_REACHABLE 0x001
@@ -517,7 +510,7 @@ extern void getwintimeofday(struct timeval *tv);
/* Maximum the mapping array will grow to (TSN mapping array) */
#define SCTP_MAPPING_ARRAY 512
-/* size of the inital malloc on the mapping array */
+/* size of the initial malloc on the mapping array */
#define SCTP_INITIAL_MAPPING_ARRAY 16
/* how much we grow the mapping array each call */
#define SCTP_MAPPING_ARRAY_INCR 32
@@ -553,26 +546,22 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_TIMER_TYPE_ASCONF 10
#define SCTP_TIMER_TYPE_SHUTDOWNGUARD 11
#define SCTP_TIMER_TYPE_AUTOCLOSE 12
-#define SCTP_TIMER_TYPE_EVENTWAKE 13
-#define SCTP_TIMER_TYPE_STRRESET 14
-#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_STRRESET 13
+#define SCTP_TIMER_TYPE_INPKILL 14
+#define SCTP_TIMER_TYPE_ASOCKILL 15
+#define SCTP_TIMER_TYPE_ADDR_WQ 16
+#define SCTP_TIMER_TYPE_PRIM_DELETED 17
/* add new timers here - and increment LAST */
-#define SCTP_TIMER_TYPE_LAST 21
+#define SCTP_TIMER_TYPE_LAST 18
#define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \
((t) < SCTP_TIMER_TYPE_LAST))
-
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
/* Number of ticks to run the main timer at in msec */
#define SCTP_MAIN_TIMER_DEFAULT 10
-#endif
+#endif
/* max number of TSN's dup'd that I will hold */
#define SCTP_MAX_DUP_TSNS 20
@@ -591,22 +580,7 @@ extern void getwintimeofday(struct timeval *tv);
* number of clusters as a base. This way high bandwidth environments will
* not get impacted by the lower bandwidth sending a bunch of 1 byte chunks
*/
-#ifdef __Panda__
-#define SCTP_ASOC_MAX_CHUNKS_ON_QUEUE 10240
-#else
#define SCTP_ASOC_MAX_CHUNKS_ON_QUEUE 512
-#endif
-
-
-/* The conversion from time to ticks and vice versa is done by rounding
- * upwards. This way we can test in the code the time to be positive and
- * know that this corresponds to a positive number of ticks.
- */
-#define MSEC_TO_TICKS(x) ((hz == 1000) ? x : ((((x) * hz) + 999) / 1000))
-#define TICKS_TO_MSEC(x) ((hz == 1000) ? x : ((((x) * 1000) + (hz - 1)) / hz))
-
-#define SEC_TO_TICKS(x) ((x) * hz)
-#define TICKS_TO_SEC(x) (((x) + (hz - 1)) / hz)
/*
* Basically the minimum amount of time before I do a early FR. Making this
@@ -628,10 +602,6 @@ extern void getwintimeofday(struct timeval *tv);
/* 30 seconds + RTO (in ms) */
#define SCTP_HB_DEFAULT_MSEC 30000
-/* Max time I will wait for Shutdown to complete */
-#define SCTP_DEF_MAX_SHUTDOWN_SEC 180
-
-
/*
* This is how long a secret lives, NOT how long a cookie lives how many
* ticks the current secret will live.
@@ -642,7 +612,6 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_RTO_LOWER_BOUND (1000) /* 1 sec is ms */
#define SCTP_RTO_INITIAL (3000) /* 3 sec in ms */
-
#define SCTP_INP_KILL_TIMEOUT 20 /* number of ms to retry kill of inpcb */
#define SCTP_ASOC_KILL_TIMEOUT 10 /* number of ms to retry kill of inpcb */
@@ -653,8 +622,7 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */
-
-/* How many streams I request initally by default */
+/* How many streams I request initially by default */
#define SCTP_OSTREAM_INITIAL 10
#define SCTP_ISTREAM_INITIAL 2048
@@ -736,7 +704,6 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_NUMBER_OF_SECRETS 8 /* or 8 * 4 = 32 octets */
#define SCTP_SECRET_SIZE 32 /* number of octets in a 256 bits */
-
/*
* SCTP upper layer notifications
*/
@@ -777,7 +744,11 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_DEFAULT_SPLIT_POINT_MIN 2904
/* Maximum length of diagnostic information in error causes */
-#define SCTP_DIAG_INFO_LEN 64
+#if defined(__Userspace__)
+#define SCTP_DIAG_INFO_LEN 256
+#else
+#define SCTP_DIAG_INFO_LEN 128
+#endif
/* ABORT CODES and other tell-tale location
* codes are generated by adding the below
@@ -785,18 +756,18 @@ extern void getwintimeofday(struct timeval *tv);
*/
/* File defines */
-#define SCTP_FROM_SCTP_INPUT 0x10000000
-#define SCTP_FROM_SCTP_PCB 0x20000000
-#define SCTP_FROM_SCTP_INDATA 0x30000000
-#define SCTP_FROM_SCTP_TIMER 0x40000000
-#define SCTP_FROM_SCTP_USRREQ 0x50000000
-#define SCTP_FROM_SCTPUTIL 0x60000000
-#define SCTP_FROM_SCTP6_USRREQ 0x70000000
-#define SCTP_FROM_SCTP_ASCONF 0x80000000
-#define SCTP_FROM_SCTP_OUTPUT 0x90000000
-#define SCTP_FROM_SCTP_PEELOFF 0xa0000000
-#define SCTP_FROM_SCTP_PANDA 0xb0000000
-#define SCTP_FROM_SCTP_SYSCTL 0xc0000000
+#define SCTP_FROM_SCTP_INPUT 0x10000000
+#define SCTP_FROM_SCTP_PCB 0x20000000
+#define SCTP_FROM_SCTP_INDATA 0x30000000
+#define SCTP_FROM_SCTP_TIMER 0x40000000
+#define SCTP_FROM_SCTP_USRREQ 0x50000000
+#define SCTP_FROM_SCTPUTIL 0x60000000
+#define SCTP_FROM_SCTP6_USRREQ 0x70000000
+#define SCTP_FROM_SCTP_ASCONF 0x80000000
+#define SCTP_FROM_SCTP_OUTPUT 0x90000000
+#define SCTP_FROM_SCTP_PEELOFF 0xa0000000
+#define SCTP_FROM_SCTP_SYSCTL 0xb0000000
+#define SCTP_FROM_SCTP_CC_FUNCTIONS 0xc0000000
/* Location ID's */
#define SCTP_LOC_1 0x00000001
@@ -832,7 +803,10 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_LOC_31 0x0000001f
#define SCTP_LOC_32 0x00000020
#define SCTP_LOC_33 0x00000021
-
+#define SCTP_LOC_34 0x00000022
+#define SCTP_LOC_35 0x00000023
+#define SCTP_LOC_36 0x00000024
+#define SCTP_LOC_37 0x00000025
/* Free assoc codes */
#define SCTP_NORMAL_PROC 0
@@ -852,7 +826,6 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_DONOT_SETSCOPE 0
#define SCTP_DO_SETSCOPE 1
-
/* This value determines the default for when
* we try to add more on the send queue., if
* there is room. This prevents us from cycling
@@ -879,7 +852,7 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_CHUNKQUEUE_SCALE 10
#endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* clock variance is 1 ms */
#define SCTP_CLOCK_GRANULARITY 1
#else
@@ -908,12 +881,20 @@ extern void getwintimeofday(struct timeval *tv);
/* modular comparison */
/* See RFC 1982 for details. */
-#define SCTP_SSN_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \
- ((a > b) && ((uint16_t)(a - b) < (1U<<15))))
-#define SCTP_SSN_GE(a, b) (SCTP_SSN_GT(a, b) || (a == b))
-#define SCTP_TSN_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \
- ((a > b) && ((uint32_t)(a - b) < (1U<<31))))
-#define SCTP_TSN_GE(a, b) (SCTP_TSN_GT(a, b) || (a == b))
+#define SCTP_UINT16_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \
+ ((a > b) && ((uint16_t)(a - b) < (1U<<15))))
+#define SCTP_UINT16_GE(a, b) (SCTP_UINT16_GT(a, b) || (a == b))
+#define SCTP_UINT32_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \
+ ((a > b) && ((uint32_t)(a - b) < (1U<<31))))
+#define SCTP_UINT32_GE(a, b) (SCTP_UINT32_GT(a, b) || (a == b))
+
+#define SCTP_SSN_GT(a, b) SCTP_UINT16_GT(a, b)
+#define SCTP_SSN_GE(a, b) SCTP_UINT16_GE(a, b)
+#define SCTP_TSN_GT(a, b) SCTP_UINT32_GT(a, b)
+#define SCTP_TSN_GE(a, b) SCTP_UINT32_GE(a, b)
+#define SCTP_MID_GT(i, a, b) (((i) == 1) ? SCTP_UINT32_GT(a, b) : SCTP_UINT16_GT((uint16_t)a, (uint16_t)b))
+#define SCTP_MID_GE(i, a, b) (((i) == 1) ? SCTP_UINT32_GE(a, b) : SCTP_UINT16_GE((uint16_t)a, (uint16_t)b))
+#define SCTP_MID_EQ(i, a, b) (((i) == 1) ? a == b : (uint16_t)a == (uint16_t)b)
/* Mapping array manipulation routines */
#define SCTP_IS_TSN_PRESENT(arry, gap) ((arry[(gap >> 3)] >> (gap & 0x07)) & 0x01)
@@ -927,7 +908,6 @@ extern void getwintimeofday(struct timeval *tv);
} \
} while (0)
-
#define SCTP_RETRAN_DONE -1
#define SCTP_RETRAN_EXIT -2
@@ -936,7 +916,7 @@ extern void getwintimeofday(struct timeval *tv);
* element. Each entry will take 2 4 byte ints (and of course the overhead
* of the next pointer as well). Using 15 as an example will yield * ((8 *
* 15) + 8) or 128 bytes of overhead for each timewait block that gets
- * initialized. Increasing it to 31 would yeild 256 bytes per block.
+ * initialized. Increasing it to 31 would yield 256 bytes per block.
*/
#define SCTP_NUMBER_IN_VTAG_BLOCK 15
/*
@@ -978,15 +958,11 @@ extern void getwintimeofday(struct timeval *tv);
/*-
* defines for socket lock states.
- * Used by __APPLE__ and SCTP_SO_LOCK_TESTING
+ * Used by __APPLE__
*/
#define SCTP_SO_LOCKED 1
#define SCTP_SO_NOT_LOCKED 0
-
-#define SCTP_HOLDS_LOCK 1
-#define SCTP_NOT_LOCKED 0
-
/*-
* For address locks, do we hold the lock?
*/
@@ -1002,17 +978,17 @@ extern void getwintimeofday(struct timeval *tv);
(((uint8_t *)&(a)->s_addr)[1] == 168)))
#define IN4_ISLOOPBACK_ADDRESS(a) \
- ((((uint8_t *)&(a)->s_addr)[0] == 127) && \
- (((uint8_t *)&(a)->s_addr)[1] == 0) && \
- (((uint8_t *)&(a)->s_addr)[2] == 0) && \
- (((uint8_t *)&(a)->s_addr)[3] == 1))
+ (((uint8_t *)&(a)->s_addr)[0] == 127)
#define IN4_ISLINKLOCAL_ADDRESS(a) \
((((uint8_t *)&(a)->s_addr)[0] == 169) && \
(((uint8_t *)&(a)->s_addr)[1] == 254))
+/* Maximum size of optval for IPPROTO_SCTP level socket options. */
+#define SCTP_SOCKET_OPTION_LIMIT (64 * 1024)
+
#if defined(__Userspace__)
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#define SCTP_GETTIME_TIMEVAL(x) getwintimeofday(x)
#define SCTP_GETPTIME_TIMEVAL(x) getwintimeofday(x) /* this doesn't seem to ever be used.. */
#else
@@ -1020,7 +996,6 @@ extern void getwintimeofday(struct timeval *tv);
#define SCTP_GETPTIME_TIMEVAL(x) gettimeofday(x, NULL)
#endif
#endif
-
#if defined(_KERNEL)
#define SCTP_GETTIME_TIMEVAL(x) (getmicrouptime(x))
#define SCTP_GETPTIME_TIMEVAL(x) (microuptime(x))
@@ -1036,11 +1011,11 @@ do { \
} \
} while (0)
-#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
#define sctp_sowwakeup_locked(inp, so) \
do { \
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \
- SOCKBUF_UNLOCK(&((so)->so_snd)); \
+ SOCKBUF_UNLOCK(&((so)->so_snd)); \
inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEOUTPUT; \
} else { \
sowwakeup_locked(so); \
@@ -1050,7 +1025,7 @@ do { \
#define sctp_sowwakeup_locked(inp, so) \
do { \
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \
- SOCKBUF_UNLOCK(&((so)->so_snd)); \
+ SOCKBUF_UNLOCK(&((so)->so_snd)); \
inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEOUTPUT; \
} else { \
sowwakeup(so); \
@@ -1067,12 +1042,12 @@ do { \
} \
} while (0)
-#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
#define sctp_sorwakeup_locked(inp, so) \
do { \
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \
inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEINPUT; \
- SOCKBUF_UNLOCK(&((so)->so_rcv)); \
+ SOCKBUF_UNLOCK(&((so)->so_rcv)); \
} else { \
sorwakeup_locked(so); \
} \
@@ -1083,7 +1058,7 @@ do { \
do { \
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \
inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEINPUT; \
- SOCKBUF_UNLOCK(&((so)->so_rcv)); \
+ SOCKBUF_UNLOCK(&((so)->so_rcv)); \
} else { \
sorwakeup(so); \
} \
diff --git a/netwerk/sctp/src/netinet/sctp_crc32.c b/netwerk/sctp/src/netinet/sctp_crc32.c
index b994aaace0..0b5a06e067 100755
--- a/netwerk/sctp/src/netinet/sctp_crc32.c
+++ b/netwerk/sctp/src/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.
@@ -30,20 +32,31 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.c 235828 2012-05-23 11:26:28Z tuexen $");
-#endif
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.c 362498 2020-06-22 14:36:14Z tuexen $");
+
+#include "opt_sctp.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/gsb_crc32.h>
+#include <sys/mbuf.h>
+
+#include <netinet/sctp.h>
+#include <netinet/sctp_crc32.h>
+#if defined(SCTP) || defined(SCTP_SUPPORT)
+#include <netinet/sctp_os.h>
+#include <netinet/sctp_pcb.h>
+#endif
+#else
#include <netinet/sctp_os.h>
#include <netinet/sctp.h>
#include <netinet/sctp_crc32.h>
#include <netinet/sctp_pcb.h>
+#endif
-
-#if !defined(SCTP_WITH_NO_CSUM)
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
-#else
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
/**
*
* Routine Description:
@@ -94,7 +107,7 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.c 235828 2012-05-23 11:26:28Z tu
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o32[256] =
+static const uint32_t sctp_crc_tableil8_o32[256] =
{
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
@@ -150,7 +163,7 @@ static uint32_t sctp_crc_tableil8_o32[256] =
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o40[256] =
+static const uint32_t sctp_crc_tableil8_o40[256] =
{
0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945,
0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD,
@@ -206,7 +219,7 @@ static uint32_t sctp_crc_tableil8_o40[256] =
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o48[256] =
+static const uint32_t sctp_crc_tableil8_o48[256] =
{
0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469,
0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC,
@@ -262,7 +275,7 @@ static uint32_t sctp_crc_tableil8_o48[256] =
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o56[256] =
+static const uint32_t sctp_crc_tableil8_o56[256] =
{
0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA,
0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C,
@@ -318,7 +331,7 @@ static uint32_t sctp_crc_tableil8_o56[256] =
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o64[256] =
+static const uint32_t sctp_crc_tableil8_o64[256] =
{
0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44,
0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5,
@@ -374,7 +387,7 @@ static uint32_t sctp_crc_tableil8_o64[256] =
* File Name = ............................ 8x256_tables.c
*/
-uint32_t sctp_crc_tableil8_o72[256] =
+static const uint32_t sctp_crc_tableil8_o72[256] =
{
0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD,
0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2,
@@ -430,7 +443,7 @@ uint32_t sctp_crc_tableil8_o72[256] =
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o80[256] =
+static const uint32_t sctp_crc_tableil8_o80[256] =
{
0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089,
0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA,
@@ -486,7 +499,7 @@ static uint32_t sctp_crc_tableil8_o80[256] =
* File Name = ............................ 8x256_tables.c
*/
-static uint32_t sctp_crc_tableil8_o88[256] =
+static const uint32_t sctp_crc_tableil8_o88[256] =
{
0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504,
0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE,
@@ -613,7 +626,7 @@ multitable_crc32c(uint32_t crc32c,
return (sctp_crc32c_sb8_64_bit(crc32c, buffer, length, to_even_word));
}
-static uint32_t sctp_crc_c[256] = {
+static const uint32_t sctp_crc_c[256] = {
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
@@ -696,8 +709,11 @@ singletable_crc32c(uint32_t crc32c,
return (crc32c);
}
-
+#if defined(__Userspace__)
+uint32_t
+#else
static uint32_t
+#endif
calculate_crc32c(uint32_t crc32c,
const unsigned char *buffer,
unsigned int length)
@@ -708,24 +724,26 @@ calculate_crc32c(uint32_t crc32c,
return (multitable_crc32c(crc32c, buffer, length));
}
}
-#endif /* FreeBSD < 80000 || other OS */
+#endif
+#if defined(__Userspace__)
+uint32_t
+#else
static uint32_t
+#endif
sctp_finalize_crc32c(uint32_t crc32c)
{
uint32_t result;
-
#if BYTE_ORDER == BIG_ENDIAN
uint8_t byte0, byte1, byte2, byte3;
-
#endif
+
/* Complement the result */
result = ~crc32c;
#if BYTE_ORDER == BIG_ENDIAN
/*
- * For BIG-ENDIAN.. aka Motorola byte order the result is in
- * little-endian form. So we must manually swap the bytes. Then we
- * can call htonl() which does nothing...
+ * For BIG-ENDIAN platforms the result is in little-endian form. So we
+ * must swap the bytes to return the result in network byte order.
*/
byte0 = result & 0x000000ff;
byte1 = (result >> 8) & 0x000000ff;
@@ -734,66 +752,61 @@ sctp_finalize_crc32c(uint32_t crc32c)
crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
#else
/*
- * For INTEL platforms the result comes out in network order. No
- * htonl is required or the swap above. So we optimize out both the
- * htonl and the manual swap above.
+ * For LITTLE ENDIAN platforms the result is in already in network
+ * byte order.
*/
crc32c = result;
#endif
return (crc32c);
}
+/*
+ * Compute the SCTP checksum in network byte order for a given mbuf chain m
+ * which contains an SCTP packet starting at offset.
+ * Since this function is also called by ipfw, don't assume that
+ * it is compiled on a kernel with SCTP support.
+ */
uint32_t
sctp_calculate_cksum(struct mbuf *m, uint32_t offset)
{
- /*
- * given a mbuf chain with a packetheader offset by 'offset'
- * pointing at a sctphdr (with csum set to 0) go through the chain
- * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also
- * has a side bonus as it will calculate the total length of the
- * mbuf chain. Note: if offset is greater than the total mbuf
- * length, checksum=1, pktlen=0 is returned (ie. no real error code)
- */
uint32_t base = 0xffffffff;
- struct mbuf *at;
-
- at = m;
- /* find the correct mbuf and offset into mbuf */
- while ((at != NULL) && (offset > (uint32_t) SCTP_BUF_LEN(at))) {
- offset -= SCTP_BUF_LEN(at); /* update remaining offset
- * left */
- at = SCTP_BUF_NEXT(at);
- }
- while (at != NULL) {
- if ((SCTP_BUF_LEN(at) - offset) > 0) {
- base = calculate_crc32c(base,
- (unsigned char *)(SCTP_BUF_AT(at, offset)),
- (unsigned int)(SCTP_BUF_LEN(at) - offset));
- }
- if (offset) {
- /* we only offset once into the first mbuf */
- if (offset < (uint32_t) SCTP_BUF_LEN(at))
- offset = 0;
- else
- offset -= SCTP_BUF_LEN(at);
+
+ while (offset > 0) {
+ KASSERT(m != NULL, ("sctp_calculate_cksum, offset > length of mbuf chain"));
+ if (offset < (uint32_t)m->m_len) {
+ break;
}
- at = SCTP_BUF_NEXT(at);
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if (offset > 0) {
+ base = calculate_crc32c(base,
+ (unsigned char *)(m->m_data + offset),
+ (unsigned int)(m->m_len - offset));
+ m = m->m_next;
+ }
+ while (m != NULL) {
+ base = calculate_crc32c(base,
+ (unsigned char *)m->m_data,
+ (unsigned int)m->m_len);
+ m = m->m_next;
}
base = sctp_finalize_crc32c(base);
return (base);
}
-#endif /* !defined(SCTP_WITH_NO_CSUM) */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP) || defined(SCTP_SUPPORT)
-#if defined(__FreeBSD__)
+VNET_DEFINE(struct sctp_base_info, system_base_info);
+
+/*
+ * Compute and insert the SCTP checksum in network byte order for a given
+ * mbuf chain m which contains an SCTP packet starting at offset.
+ */
void
sctp_delayed_cksum(struct mbuf *m, uint32_t offset)
{
-#if defined(SCTP_WITH_NO_CSUM)
-#ifdef INVARIANTS
- panic("sctp_delayed_cksum() called when using no SCTP CRC.");
-#endif
-#else
uint32_t checksum;
checksum = sctp_calculate_cksum(m, offset);
@@ -801,18 +814,18 @@ sctp_delayed_cksum(struct mbuf *m, uint32_t offset)
SCTP_STAT_INCR(sctps_sendswcrc);
offset += offsetof(struct sctphdr, checksum);
- if (offset + sizeof(uint32_t) > (uint32_t) (m->m_len)) {
- SCTP_PRINTF("sctp_delayed_cksum(): m->len: %d, off: %d.\n",
- (uint32_t) m->m_len, offset);
- /*
- * XXX this shouldn't happen, but if it does, the correct
- * behavior may be to insert the checksum in the appropriate
- * next mbuf in the chain.
- */
+ if (offset + sizeof(uint32_t) > (uint32_t)(m->m_pkthdr.len)) {
+#ifdef INVARIANTS
+ panic("sctp_delayed_cksum(): m->m_pkthdr.len: %d, offset: %u.",
+ m->m_pkthdr.len, offset);
+#else
+ SCTP_PRINTF("sctp_delayed_cksum(): m->m_pkthdr.len: %d, offset: %u.\n",
+ m->m_pkthdr.len, offset);
+#endif
return;
}
- *(uint32_t *) (m->m_data + offset) = checksum;
-#endif
+ m_copyback(m, (int)offset, (int)sizeof(uint32_t), (caddr_t)&checksum);
}
#endif
+#endif
diff --git a/netwerk/sctp/src/netinet/sctp_crc32.h b/netwerk/sctp/src/netinet/sctp_crc32.h
index 2cc14f4503..5e76ff21bf 100755
--- a/netwerk/sctp/src/netinet/sctp_crc32.h
+++ b/netwerk/sctp/src/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.
@@ -30,25 +32,25 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.h 235828 2012-05-23 11:26:28Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.h 362338 2020-06-18 19:32:34Z markj $");
#endif
#ifndef _NETINET_SCTP_CRC32_H_
#define _NETINET_SCTP_CRC32_H_
#if defined(_KERNEL)
-#if !defined(SCTP_WITH_NO_CSUM)
uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t);
-#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP) || defined(SCTP_SUPPORT)
void sctp_delayed_cksum(struct mbuf *, uint32_t offset);
#endif
+#endif
#endif /* _KERNEL */
#if defined(__Userspace__)
-#if !defined(SCTP_WITH_NO_CSUM)
+uint32_t calculate_crc32c(uint32_t, const unsigned char *, unsigned int);
+uint32_t sctp_finalize_crc32c(uint32_t);
uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t);
#endif
-#endif
#endif /* __crc32c_h__ */
diff --git a/netwerk/sctp/src/netinet/sctp_header.h b/netwerk/sctp/src/netinet/sctp_header.h
index f62181fecd..9226a9ef99 100755
--- a/netwerk/sctp/src/netinet/sctp_header.h
+++ b/netwerk/sctp/src/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.
@@ -30,24 +32,24 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_header.h 273168 2014-10-16 15:36:04Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_header.h 366114 2020-09-24 12:26:06Z tuexen $");
#endif
#ifndef _NETINET_SCTP_HEADER_H_
#define _NETINET_SCTP_HEADER_H_
-#if defined(__Windows__) && !defined(__Userspace_os_Windows)
+#if defined(_WIN32) && !defined(__Userspace__)
#include <packon.h>
#endif
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <sys/time.h>
#endif
#include <netinet/sctp.h>
#include <netinet/sctp_constants.h>
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#define SCTP_PACKED __attribute__((packed))
#else
#pragma pack (push, 1)
@@ -64,7 +66,6 @@ struct sctp_ipv4addr_param {
#define SCTP_V6_ADDR_BYTES 16
-
struct sctp_ipv6addr_param {
struct sctp_paramhdr ph;/* type=SCTP_IPV6_PARAM_TYPE, len=20 */
uint8_t addr[SCTP_V6_ADDR_BYTES]; /* IPV6 address */
@@ -108,14 +109,12 @@ struct sctp_heartbeat_info_param {
char address[SCTP_ADDRMAX];
} SCTP_PACKED;
-
/* draft-ietf-tsvwg-prsctp */
/* PR-SCTP supported parameter */
struct sctp_prsctp_supported_param {
struct sctp_paramhdr ph;
} SCTP_PACKED;
-
/* draft-ietf-tsvwg-addip-sctp */
struct sctp_asconf_paramhdr { /* an ASCONF "parameter" */
struct sctp_paramhdr ph;/* a SCTP parameter header */
@@ -127,14 +126,12 @@ struct sctp_asconf_addr_param { /* an ASCONF address parameter */
struct sctp_ipv6addr_param addrp; /* max storage size */
} SCTP_PACKED;
-
struct sctp_asconf_tag_param { /* an ASCONF NAT-Vtag parameter */
struct sctp_asconf_paramhdr aph; /* asconf "parameter" */
- uint32_t local_vtag;
- uint32_t remote_vtag;
+ uint32_t local_vtag;
+ uint32_t remote_vtag;
} SCTP_PACKED;
-
struct sctp_asconf_addrv4_param { /* an ASCONF address (v4) parameter */
struct sctp_asconf_paramhdr aph; /* asconf "parameter" */
struct sctp_ipv4addr_param addrp; /* max storage size */
@@ -147,15 +144,14 @@ struct sctp_supported_chunk_types_param {
uint8_t chunk_types[];
} SCTP_PACKED;
-
/*
* Structures for DATA chunks
*/
struct sctp_data {
uint32_t tsn;
- uint16_t stream_id;
- uint16_t stream_sequence;
- uint32_t protocol_id;
+ uint16_t sid;
+ uint16_t ssn;
+ uint32_t ppid;
/* user data follows */
} SCTP_PACKED;
@@ -164,6 +160,23 @@ struct sctp_data_chunk {
struct sctp_data dp;
} SCTP_PACKED;
+struct sctp_idata {
+ uint32_t tsn;
+ uint16_t sid;
+ uint16_t reserved; /* Where does the SSN go? */
+ uint32_t mid;
+ union {
+ uint32_t ppid;
+ uint32_t fsn; /* Fragment Sequence Number */
+ } ppid_fsn;
+ /* user data follows */
+} SCTP_PACKED;
+
+struct sctp_idata_chunk {
+ struct sctp_chunkhdr ch;
+ struct sctp_idata dp;
+} SCTP_PACKED;
+
/*
* Structures for the control chunks
*/
@@ -220,34 +233,6 @@ struct sctp_state_cookie { /* this is our definition... */
*/
} SCTP_PACKED;
-
-/* Used for NAT state error cause */
-struct sctp_missing_nat_state {
- uint16_t cause;
- uint16_t length;
- uint8_t data[];
-} SCTP_PACKED;
-
-
-struct sctp_inv_mandatory_param {
- uint16_t cause;
- uint16_t length;
- uint32_t num_param;
- uint16_t param;
- /*
- * We include this to 0 it since only a missing cookie will cause
- * this error.
- */
- uint16_t resv;
-} SCTP_PACKED;
-
-struct sctp_unresolv_addr {
- uint16_t cause;
- uint16_t length;
- uint16_t addr_type;
- uint16_t reserved; /* Only one invalid addr type */
-} SCTP_PACKED;
-
/* state cookie parameter */
struct sctp_state_cookie_param {
struct sctp_paramhdr ph;
@@ -269,7 +254,6 @@ struct sctp_init_msg {
#define sctp_init_ack_chunk sctp_init_chunk
#define sctp_init_ack_msg sctp_init_msg
-
/* Selective Ack (SACK) */
struct sctp_gap_ack_block {
uint16_t start; /* Gap Ack block start */
@@ -306,7 +290,6 @@ struct sctp_nr_sack_chunk {
struct sctp_nr_sack nr_sack;
} SCTP_PACKED;
-
/* Heartbeat Request (HEARTBEAT) */
struct sctp_heartbeat {
struct sctp_heartbeat_info_param hb_info;
@@ -321,7 +304,6 @@ struct sctp_heartbeat_chunk {
#define sctp_heartbeat_ack sctp_heartbeat
#define sctp_heartbeat_ack_chunk sctp_heartbeat_chunk
-
/* Abort Asssociation (ABORT) */
struct sctp_abort_chunk {
struct sctp_chunkhdr ch;
@@ -333,27 +315,23 @@ struct sctp_abort_msg {
struct sctp_abort_chunk msg;
} SCTP_PACKED;
-
/* Shutdown Association (SHUTDOWN) */
struct sctp_shutdown_chunk {
struct sctp_chunkhdr ch;
uint32_t cumulative_tsn_ack;
} SCTP_PACKED;
-
/* Shutdown Acknowledgment (SHUTDOWN ACK) */
struct sctp_shutdown_ack_chunk {
struct sctp_chunkhdr ch;
} SCTP_PACKED;
-
/* Operation Error (ERROR) */
struct sctp_error_chunk {
struct sctp_chunkhdr ch;
/* optional error causes follow */
} SCTP_PACKED;
-
/* Cookie Echo (COOKIE ECHO) */
struct sctp_cookie_echo_chunk {
struct sctp_chunkhdr ch;
@@ -388,28 +366,11 @@ struct sctp_shutdown_complete_chunk {
struct sctp_chunkhdr ch;
} SCTP_PACKED;
-/* Oper error holding a stale cookie */
-struct sctp_stale_cookie_msg {
- struct sctp_paramhdr ph;/* really an error cause */
- uint32_t time_usec;
-} SCTP_PACKED;
-
struct sctp_adaptation_layer_indication {
struct sctp_paramhdr ph;
uint32_t indication;
} SCTP_PACKED;
-struct sctp_cookie_while_shutting_down {
- struct sctphdr sh;
- struct sctp_chunkhdr ch;
- struct sctp_paramhdr ph;/* really an error cause */
-} SCTP_PACKED;
-
-struct sctp_shutdown_complete_msg {
- struct sctphdr sh;
- struct sctp_shutdown_complete_chunk shut_cmp;
-} SCTP_PACKED;
-
/*
* draft-ietf-tsvwg-addip-sctp
*/
@@ -437,10 +398,16 @@ struct sctp_forward_tsn_chunk {
} SCTP_PACKED;
struct sctp_strseq {
- uint16_t stream;
- uint16_t sequence;
+ uint16_t sid;
+ uint16_t ssn;
} SCTP_PACKED;
+struct sctp_strseq_mid {
+ uint16_t sid;
+ uint16_t flags;
+ uint32_t mid;
+};
+
struct sctp_forward_tsn_msg {
struct sctphdr sh;
struct sctp_forward_tsn_chunk msg;
@@ -456,7 +423,6 @@ struct sctp_chunk_desc {
uint32_t tsn_ifany;
} SCTP_PACKED;
-
struct sctp_pktdrop_chunk {
struct sctp_chunkhdr ch;
uint32_t bottle_bw;
@@ -507,10 +473,10 @@ struct sctp_stream_reset_response_tsn {
} SCTP_PACKED;
struct sctp_stream_reset_add_strm {
- struct sctp_paramhdr ph;
- uint32_t request_seq;
- uint16_t number_of_streams;
- uint16_t reserved;
+ struct sctp_paramhdr ph;
+ uint32_t request_seq;
+ uint16_t number_of_streams;
+ uint16_t reserved;
} SCTP_PACKED;
#define SCTP_STREAM_RESET_RESULT_NOTHING_TO_DO 0x00000000 /* XXX: unused */
@@ -572,12 +538,6 @@ struct sctp_auth_chunk {
uint8_t hmac[];
} SCTP_PACKED;
-struct sctp_auth_invalid_hmac {
- struct sctp_paramhdr ph;
- uint16_t hmac_id;
- uint16_t padding;
-} SCTP_PACKED;
-
/*
* we pre-reserve enough room for a ECNE or CWR AND a SACK with no missing
* pieces. If ENCE is missing we could have a couple of blocks. This way we
@@ -589,49 +549,47 @@ struct sctp_auth_invalid_hmac {
#ifndef SCTP_MAX_OVERHEAD
#ifdef INET6
#define SCTP_MAX_OVERHEAD (sizeof(struct sctp_data_chunk) + \
- sizeof(struct sctphdr) + \
- sizeof(struct sctp_ecne_chunk) + \
- sizeof(struct sctp_sack_chunk) + \
- sizeof(struct ip6_hdr))
+ sizeof(struct sctphdr) + \
+ sizeof(struct sctp_ecne_chunk) + \
+ sizeof(struct sctp_sack_chunk) + \
+ sizeof(struct ip6_hdr))
#define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \
- sizeof(struct sctphdr) + \
- sizeof(struct ip6_hdr))
-
+ sizeof(struct sctphdr) + \
+ sizeof(struct ip6_hdr))
#define SCTP_MIN_OVERHEAD (sizeof(struct ip6_hdr) + \
- sizeof(struct sctphdr))
+ sizeof(struct sctphdr))
#else
#define SCTP_MAX_OVERHEAD (sizeof(struct sctp_data_chunk) + \
- sizeof(struct sctphdr) + \
- sizeof(struct sctp_ecne_chunk) + \
- sizeof(struct sctp_sack_chunk) + \
- sizeof(struct ip))
+ sizeof(struct sctphdr) + \
+ sizeof(struct sctp_ecne_chunk) + \
+ sizeof(struct sctp_sack_chunk) + \
+ sizeof(struct ip))
#define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \
- sizeof(struct sctphdr) + \
- sizeof(struct ip))
-
+ sizeof(struct sctphdr) + \
+ sizeof(struct ip))
#define SCTP_MIN_OVERHEAD (sizeof(struct ip) + \
- sizeof(struct sctphdr))
+ sizeof(struct sctphdr))
#endif /* INET6 */
#endif /* !SCTP_MAX_OVERHEAD */
#define SCTP_MED_V4_OVERHEAD (sizeof(struct sctp_data_chunk) + \
- sizeof(struct sctphdr) + \
- sizeof(struct ip))
+ sizeof(struct sctphdr) + \
+ sizeof(struct ip))
#define SCTP_MIN_V4_OVERHEAD (sizeof(struct ip) + \
- sizeof(struct sctphdr))
+ sizeof(struct sctphdr))
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
#include <packoff.h>
#endif
-#if defined(__Userspace_os_Windows)
-#pragma pack ()
+#if defined(_WIN32) && defined(__Userspace__)
+#pragma pack(pop)
#endif
#undef SCTP_PACKED
#endif /* !__sctp_header_h__ */
diff --git a/netwerk/sctp/src/netinet/sctp_indata.c b/netwerk/sctp/src/netinet/sctp_indata.c
index f697d0ced9..3bce9e99a6 100755
--- a/netwerk/sctp/src/netinet/sctp_indata.c
+++ b/netwerk/sctp/src/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.
@@ -30,24 +32,32 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 280440 2015-03-24 15:05:36Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 367520 2020-11-09 13:12:07Z tuexen $");
#endif
#include <netinet/sctp_os.h>
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <sys/proc.h>
+#endif
#include <netinet/sctp_var.h>
#include <netinet/sctp_sysctl.h>
-#include <netinet/sctp_pcb.h>
#include <netinet/sctp_header.h>
+#include <netinet/sctp_pcb.h>
#include <netinet/sctputil.h>
#include <netinet/sctp_output.h>
-#include <netinet/sctp_input.h>
-#include <netinet/sctp_indata.h>
#include <netinet/sctp_uio.h>
+#include <netinet/sctp_auth.h>
#include <netinet/sctp_timer.h>
-
-
+#include <netinet/sctp_asconf.h>
+#include <netinet/sctp_indata.h>
+#include <netinet/sctp_bsd_addr.h>
+#include <netinet/sctp_input.h>
+#include <netinet/sctp_crc32.h>
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <netinet/sctp_lock_bsd.h>
+#endif
/*
* NOTES: On the outbound side of things I need to check the sack timer to
* see if I should generate a sack into the chunk queue (if I have data to
@@ -57,6 +67,12 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 280440 2015-03-24 15:05:36Z t
* This will cause sctp_service_queues() to get called on the top entry in
* the list.
*/
+static uint32_t
+sctp_add_chk_to_control(struct sctp_queued_to_read *control,
+ struct sctp_stream_in *strm,
+ struct sctp_tcb *stcb,
+ struct sctp_association *asoc,
+ struct sctp_tmit_chunk *chk, int hold_rlock);
void
sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
@@ -76,19 +92,23 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
* sctp_soreceive then we will fix this so that ONLY this
* associations data is taken into account.
*/
- if (stcb->sctp_socket == NULL)
+ if (stcb->sctp_socket == NULL) {
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 */
calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
return (calc);
}
/* get actual space */
calc = (uint32_t) sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv);
-
/*
* take out what has NOT been put on socket queue and we yet hold
* for putting up.
@@ -97,7 +117,6 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
asoc->cnt_on_reasm_queue * MSIZE));
calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_all_streams +
asoc->cnt_on_all_streams * MSIZE));
-
if (calc == 0) {
/* out of space */
return (calc);
@@ -114,8 +133,6 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
return (calc);
}
-
-
/*
* Build out our readq entry based on the incoming packet.
*/
@@ -123,8 +140,8 @@ struct sctp_queued_to_read *
sctp_build_readq_entry(struct sctp_tcb *stcb,
struct sctp_nets *net,
uint32_t tsn, uint32_t ppid,
- uint32_t context, uint16_t stream_no,
- uint16_t stream_seq, uint8_t flags,
+ uint32_t context, uint16_t sid,
+ uint32_t mid, uint8_t flags,
struct mbuf *dm)
{
struct sctp_queued_to_read *read_queue_e = NULL;
@@ -133,73 +150,29 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
if (read_queue_e == NULL) {
goto failed_build;
}
- read_queue_e->sinfo_stream = stream_no;
- read_queue_e->sinfo_ssn = stream_seq;
+ memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read));
+ read_queue_e->sinfo_stream = sid;
read_queue_e->sinfo_flags = (flags << 8);
read_queue_e->sinfo_ppid = ppid;
read_queue_e->sinfo_context = context;
- read_queue_e->sinfo_timetolive = 0;
read_queue_e->sinfo_tsn = tsn;
read_queue_e->sinfo_cumtsn = tsn;
read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb);
+ read_queue_e->mid = mid;
+ read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff;
+ TAILQ_INIT(&read_queue_e->reasm);
read_queue_e->whoFrom = net;
- read_queue_e->length = 0;
atomic_add_int(&net->ref_count, 1);
read_queue_e->data = dm;
- read_queue_e->spec_flags = 0;
- read_queue_e->tail_mbuf = NULL;
- read_queue_e->aux_data = NULL;
read_queue_e->stcb = stcb;
read_queue_e->port_from = stcb->rport;
- read_queue_e->do_not_ref_stcb = 0;
- read_queue_e->end_added = 0;
- read_queue_e->some_taken = 0;
- read_queue_e->pdapi_aborted = 0;
-failed_build:
- return (read_queue_e);
-}
-
-
-/*
- * Build out our readq entry based on the incoming packet.
- */
-static struct sctp_queued_to_read *
-sctp_build_readq_entry_chk(struct sctp_tcb *stcb,
- struct sctp_tmit_chunk *chk)
-{
- struct sctp_queued_to_read *read_queue_e = NULL;
-
- sctp_alloc_a_readq(stcb, read_queue_e);
- if (read_queue_e == NULL) {
- goto failed_build;
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ read_queue_e->do_not_ref_stcb = 1;
}
- read_queue_e->sinfo_stream = chk->rec.data.stream_number;
- read_queue_e->sinfo_ssn = chk->rec.data.stream_seq;
- read_queue_e->sinfo_flags = (chk->rec.data.rcv_flags << 8);
- read_queue_e->sinfo_ppid = chk->rec.data.payloadtype;
- read_queue_e->sinfo_context = stcb->asoc.context;
- read_queue_e->sinfo_timetolive = 0;
- read_queue_e->sinfo_tsn = chk->rec.data.TSN_seq;
- read_queue_e->sinfo_cumtsn = chk->rec.data.TSN_seq;
- read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb);
- read_queue_e->whoFrom = chk->whoTo;
- read_queue_e->aux_data = NULL;
- read_queue_e->length = 0;
- atomic_add_int(&chk->whoTo->ref_count, 1);
- read_queue_e->data = chk->data;
- read_queue_e->tail_mbuf = NULL;
- read_queue_e->stcb = stcb;
- read_queue_e->port_from = stcb->rport;
- read_queue_e->spec_flags = 0;
- read_queue_e->do_not_ref_stcb = 0;
- read_queue_e->end_added = 0;
- read_queue_e->some_taken = 0;
- read_queue_e->pdapi_aborted = 0;
failed_build:
return (read_queue_e);
}
-
struct mbuf *
sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
{
@@ -207,7 +180,7 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
struct sctp_sndrcvinfo *outinfo;
struct sctp_rcvinfo *rcvinfo;
struct sctp_nxtinfo *nxtinfo;
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
WSACMSGHDR *cmh;
#else
struct cmsghdr *cmh;
@@ -230,9 +203,9 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
}
seinfo = (struct sctp_extrcvinfo *)sinfo;
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
- (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
+ (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
provide_nxt = 1;
- len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
+ len += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
} else {
provide_nxt = 0;
}
@@ -256,7 +229,7 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
SCTP_BUF_LEN(ret) = 0;
/* We need a CMSG header followed by the struct */
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
cmh = mtod(ret, WSACMSGHDR *);
#else
cmh = mtod(ret, struct cmsghdr *);
@@ -279,7 +252,7 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn;
rcvinfo->rcv_context = sinfo->sinfo_context;
rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id;
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
cmh = (WSACMSGHDR *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
#else
cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
@@ -291,21 +264,21 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo));
cmh->cmsg_type = SCTP_NXTINFO;
nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh);
- nxtinfo->nxt_sid = seinfo->sreinfo_next_stream;
+ nxtinfo->nxt_sid = seinfo->serinfo_next_stream;
nxtinfo->nxt_flags = 0;
- if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
+ if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
nxtinfo->nxt_flags |= SCTP_UNORDERED;
}
- if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
+ if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
nxtinfo->nxt_flags |= SCTP_NOTIFICATION;
}
- if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
+ if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
nxtinfo->nxt_flags |= SCTP_COMPLETE;
}
- nxtinfo->nxt_ppid = seinfo->sreinfo_next_ppid;
- nxtinfo->nxt_length = seinfo->sreinfo_next_length;
- nxtinfo->nxt_assoc_id = seinfo->sreinfo_next_aid;
-#if defined(__Userspace_os_Windows)
+ nxtinfo->nxt_ppid = seinfo->serinfo_next_ppid;
+ nxtinfo->nxt_length = seinfo->serinfo_next_length;
+ nxtinfo->nxt_assoc_id = seinfo->serinfo_next_aid;
+#if defined(_WIN32)
cmh = (WSACMSGHDR *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
#else
cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
@@ -330,243 +303,207 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
return (ret);
}
-
static void
sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
{
- uint32_t gap, i, cumackp1;
- int fnd = 0;
+ uint32_t gap, i;
+ int in_r, in_nr;
if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
return;
}
- cumackp1 = asoc->cumulative_tsn + 1;
- if (SCTP_TSN_GT(cumackp1, tsn)) {
- /* this tsn is behind the cum ack and thus we don't
+ if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
+ /*
+ * This tsn is behind the cum ack and thus we don't
* need to worry about it being moved from one to the other.
*/
return;
}
SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
- if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
- SCTP_PRINTF("gap:%x tsn:%x\n", gap, tsn);
- sctp_print_mapping_array(asoc);
-#ifdef INVARIANTS
- panic("Things are really messed up now!!");
-#endif
+ in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap);
+ in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap);
+ KASSERT(in_r || in_nr, ("%s: Things are really messed up now", __func__));
+ if (!in_nr) {
+ SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
+ if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
+ asoc->highest_tsn_inside_nr_map = tsn;
+ }
}
- SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
- SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
- asoc->highest_tsn_inside_nr_map = tsn;
- }
- if (tsn == asoc->highest_tsn_inside_map) {
- /* We must back down to see what the new highest is */
- for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) {
- SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
- if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
- asoc->highest_tsn_inside_map = i;
- fnd = 1;
- break;
+ if (in_r) {
+ SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
+ if (tsn == asoc->highest_tsn_inside_map) {
+ /* We must back down to see what the new highest is. */
+ for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) {
+ SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
+ if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
+ asoc->highest_tsn_inside_map = i;
+ break;
+ }
+ }
+ if (!SCTP_TSN_GE(i, asoc->mapping_array_base_tsn)) {
+ asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
}
- }
- if (!fnd) {
- asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
}
}
}
-
-/*
- * We are delivering currently from the reassembly queue. We must continue to
- * deliver until we either: 1) run out of space. 2) run out of sequential
- * TSN's 3) hit the SCTP_DATA_LAST_FRAG flag.
- */
-static void
-sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
+static int
+sctp_place_control_in_stream(struct sctp_stream_in *strm,
+ struct sctp_association *asoc,
+ struct sctp_queued_to_read *control)
{
- struct sctp_tmit_chunk *chk, *nchk;
- uint16_t nxt_todel;
- uint16_t stream_no;
- int end = 0;
- int cntDel;
- struct sctp_queued_to_read *control, *ctl, *nctl;
-
- if (stcb == NULL)
- return;
-
- cntDel = stream_no = 0;
- if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
- (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
- (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
- /* socket above is long gone or going.. */
- abandon:
- asoc->fragmented_delivery_inprogress = 0;
- TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
- TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- asoc->size_on_reasm_queue -= chk->send_size;
- sctp_ucount_decr(asoc->cnt_on_reasm_queue);
- /*
- * Lose the data pointer, since its in the socket
- * buffer
- */
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
+ struct sctp_queued_to_read *at;
+ struct sctp_readhead *q;
+ uint8_t flags, unordered;
+
+ flags = (control->sinfo_flags >> 8);
+ unordered = flags & SCTP_DATA_UNORDERED;
+ if (unordered) {
+ q = &strm->uno_inqueue;
+ if (asoc->idata_supported == 0) {
+ if (!TAILQ_EMPTY(q)) {
+ /* Only one stream can be here in old style -- abort */
+ return (-1);
}
- /* Now free the address and data */
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- /*sa_ignore FREED_MEMORY*/
- }
- return;
- }
- SCTP_TCB_LOCK_ASSERT(stcb);
- TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
- if (chk->rec.data.TSN_seq != (asoc->tsn_last_delivered + 1)) {
- /* Can't deliver more :< */
- return;
- }
- stream_no = chk->rec.data.stream_number;
- nxt_todel = asoc->strmin[stream_no].last_sequence_delivered + 1;
- if (nxt_todel != chk->rec.data.stream_seq &&
- (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) {
- /*
- * Not the next sequence to deliver in its stream OR
- * unordered
- */
- return;
+ TAILQ_INSERT_TAIL(q, control, next_instrm);
+ control->on_strm_q = SCTP_ON_UNORDERED;
+ return (0);
}
- if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
-
- control = sctp_build_readq_entry_chk(stcb, chk);
- if (control == NULL) {
- /* out of memory? */
- return;
- }
- /* save it off for our future deliveries */
- stcb->asoc.control_pdapi = control;
- if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG)
- end = 1;
- else
- end = 0;
- sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
- sctp_add_to_readq(stcb->sctp_ep,
- stcb, control, &stcb->sctp_socket->so_rcv, end,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
- cntDel++;
+ } else {
+ q = &strm->inqueue;
+ }
+ if ((flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ control->end_added = 1;
+ control->first_frag_seen = 1;
+ control->last_frag_seen = 1;
+ }
+ if (TAILQ_EMPTY(q)) {
+ /* Empty queue */
+ TAILQ_INSERT_HEAD(q, control, next_instrm);
+ if (unordered) {
+ control->on_strm_q = SCTP_ON_UNORDERED;
} else {
- if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG)
- end = 1;
- else
- end = 0;
- sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
- if (sctp_append_to_readq(stcb->sctp_ep, stcb,
- stcb->asoc.control_pdapi,
- chk->data, end, chk->rec.data.TSN_seq,
- &stcb->sctp_socket->so_rcv)) {
+ control->on_strm_q = SCTP_ON_ORDERED;
+ }
+ return (0);
+ } else {
+ TAILQ_FOREACH(at, q, next_instrm) {
+ if (SCTP_MID_GT(asoc->idata_supported, at->mid, control->mid)) {
/*
- * something is very wrong, either
- * control_pdapi is NULL, or the tail_mbuf
- * is corrupt, or there is a EOM already on
- * the mbuf chain.
+ * one in queue is bigger than the
+ * new one, insert before this one
*/
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- goto abandon;
+ TAILQ_INSERT_BEFORE(at, control, next_instrm);
+ if (unordered) {
+ control->on_strm_q = SCTP_ON_UNORDERED;
} else {
-#ifdef INVARIANTS
- if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) {
- panic("This should not happen control_pdapi NULL?");
+ control->on_strm_q = SCTP_ON_ORDERED;
+ }
+ break;
+ } else if (SCTP_MID_EQ(asoc->idata_supported, at->mid, control->mid)) {
+ /*
+ * Gak, He sent me a duplicate msg
+ * id number?? return -1 to abort.
+ */
+ return (-1);
+ } else {
+ if (TAILQ_NEXT(at, next_instrm) == NULL) {
+ /*
+ * We are at the end, insert
+ * it after this one
+ */
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
+ sctp_log_strm_del(control, at,
+ SCTP_STR_LOG_FROM_INSERT_TL);
}
- /* if we did not panic, it was a EOM */
- panic("Bad chunking ??");
-#else
- if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) {
- SCTP_PRINTF("This should not happen control_pdapi NULL?\n");
+ TAILQ_INSERT_AFTER(q, at, control, next_instrm);
+ if (unordered) {
+ control->on_strm_q = SCTP_ON_UNORDERED;
+ } else {
+ control->on_strm_q = SCTP_ON_ORDERED;
}
- SCTP_PRINTF("Bad chunking ??\n");
- SCTP_PRINTF("Dumping re-assembly queue this will probably hose the association\n");
-
-#endif
- goto abandon;
+ break;
}
}
- cntDel++;
- }
- /* pull it we did it */
- TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
- asoc->fragmented_delivery_inprogress = 0;
- if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) {
- asoc->strmin[stream_no].last_sequence_delivered++;
- }
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) {
- SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
- }
- } else if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
- /*
- * turn the flag back on since we just delivered
- * yet another one.
- */
- asoc->fragmented_delivery_inprogress = 1;
}
- asoc->tsn_of_pdapi_last_delivered = chk->rec.data.TSN_seq;
- asoc->last_flags_delivered = chk->rec.data.rcv_flags;
- asoc->last_strm_seq_delivered = chk->rec.data.stream_seq;
- asoc->last_strm_no_delivered = chk->rec.data.stream_number;
+ }
+ return (0);
+}
- asoc->tsn_last_delivered = chk->rec.data.TSN_seq;
- asoc->size_on_reasm_queue -= chk->send_size;
- sctp_ucount_decr(asoc->cnt_on_reasm_queue);
- /* free up the chk */
+static void
+sctp_abort_in_reasm(struct sctp_tcb *stcb,
+ struct sctp_queued_to_read *control,
+ struct sctp_tmit_chunk *chk,
+ int *abort_flag, int opspot)
+{
+ char msg[SCTP_DIAG_INFO_LEN];
+ struct mbuf *oper;
+
+ if (stcb->asoc.idata_supported) {
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x",
+ opspot,
+ control->fsn_included,
+ chk->rec.data.tsn,
+ chk->rec.data.sid,
+ chk->rec.data.fsn, chk->rec.data.mid);
+ } else {
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "Reass %x,CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x,SSN:%4.4x",
+ opspot,
+ control->fsn_included,
+ chk->rec.data.tsn,
+ chk->rec.data.sid,
+ chk->rec.data.fsn,
+ (uint16_t)chk->rec.data.mid);
+ }
+ oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, oper, SCTP_SO_NOT_LOCKED);
+ *abort_flag = 1;
+}
+
+static void
+sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control)
+{
+ /*
+ * The control could not be placed and must be cleaned.
+ */
+ struct sctp_tmit_chunk *chk, *nchk;
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ if (chk->data)
+ sctp_m_freem(chk->data);
chk->data = NULL;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
-
- if (asoc->fragmented_delivery_inprogress == 0) {
- /*
- * Now lets see if we can deliver the next one on
- * the stream
- */
- struct sctp_stream_in *strm;
-
- strm = &asoc->strmin[stream_no];
- nxt_todel = strm->last_sequence_delivered + 1;
- TAILQ_FOREACH_SAFE(ctl, &strm->inqueue, next, nctl) {
- /* Deliver more if we can. */
- if (nxt_todel == ctl->sinfo_ssn) {
- TAILQ_REMOVE(&strm->inqueue, ctl, next);
- asoc->size_on_all_streams -= ctl->length;
- sctp_ucount_decr(asoc->cnt_on_all_streams);
- strm->last_sequence_delivered++;
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- ctl,
- &stcb->sctp_socket->so_rcv, 1,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
- } else {
- break;
- }
- nxt_todel = strm->last_sequence_delivered + 1;
- }
- break;
- }
}
+ sctp_free_remote_addr(control->whoFrom);
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_free_a_readq(stcb, control);
}
/*
* Queue the chunk either right into the socket buffer if it is the next one
* to go OR put it in the correct place in the delivery queue. If we do
- * append to the so_buf, keep doing so until we are out of order. One big
- * question still remains, what to do when the socket buffer is FULL??
+ * append to the so_buf, keep doing so until we are out of order as
+ * long as the control's entered are non-fragmented.
*/
static void
-sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
- struct sctp_queued_to_read *control, int *abort_flag)
+sctp_queue_data_to_stream(struct sctp_tcb *stcb,
+ struct sctp_association *asoc,
+ struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm)
{
/*
* FIX-ME maybe? What happens when the ssn wraps? If we are getting
* all the data in one stream this could happen quite rapidly. One
* could use the TSN to keep track of things, but this scheme breaks
- * down in the other type of stream useage that could occur. Send a
+ * down in the other type of stream usage that could occur. Send a
* single msg to stream 0, send 4Billion messages to stream 1, now
* send a message to stream 0. You have a situation where the TSN
* has wrapped but not in the stream. Is this worth worrying about
@@ -580,70 +517,109 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
* SSN alone. Maybe a hybred approach is the answer
*
*/
- struct sctp_stream_in *strm;
struct sctp_queued_to_read *at;
int queue_needed;
- uint16_t nxt_todel;
+ uint32_t nxt_todel;
struct mbuf *op_err;
+ struct sctp_stream_in *strm;
char msg[SCTP_DIAG_INFO_LEN];
- queue_needed = 1;
- asoc->size_on_all_streams += control->length;
- sctp_ucount_incr(asoc->cnt_on_all_streams);
strm = &asoc->strmin[control->sinfo_stream];
- nxt_todel = strm->last_sequence_delivered + 1;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD);
}
- SCTPDBG(SCTP_DEBUG_INDATA1,
- "queue to stream called for ssn:%u lastdel:%u nxt:%u\n",
- (uint32_t) control->sinfo_stream,
- (uint32_t) strm->last_sequence_delivered,
- (uint32_t) nxt_todel);
- if (SCTP_SSN_GE(strm->last_sequence_delivered, control->sinfo_ssn)) {
+ if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) {
/* The incoming sseq is behind where we last delivered? */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ:%d delivered:%d from peer, Abort association\n",
- control->sinfo_ssn, strm->last_sequence_delivered);
- protocol_error:
+ SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n",
+ strm->last_mid_delivered, control->mid);
/*
* throw it in the stream so it gets cleaned up in
* association destruction
*/
- TAILQ_INSERT_HEAD(&strm->inqueue, control, next);
- snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- strm->last_sequence_delivered, control->sinfo_tsn,
- control->sinfo_stream, control->sinfo_ssn);
+ TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm);
+ if (asoc->idata_supported) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x",
+ strm->last_mid_delivered, control->sinfo_tsn,
+ control->sinfo_stream, control->mid);
+ } else {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
+ (uint16_t)strm->last_mid_delivered,
+ control->sinfo_tsn,
+ control->sinfo_stream,
+ (uint16_t)control->mid);
+ }
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_1;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
-
}
- if (nxt_todel == control->sinfo_ssn) {
+ queue_needed = 1;
+ asoc->size_on_all_streams += control->length;
+ sctp_ucount_incr(asoc->cnt_on_all_streams);
+ nxt_todel = strm->last_mid_delivered + 1;
+ if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) {
+#if defined(__APPLE__) && !defined(__Userspace__)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
/* can be delivered right away? */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL);
}
- /* EY it wont be queued if it could be delivered directly*/
+ /* EY it wont be queued if it could be delivered directly */
queue_needed = 0;
- asoc->size_on_all_streams -= control->length;
+ 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
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
- strm->last_sequence_delivered++;
-
+ strm->last_mid_delivered++;
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
- TAILQ_FOREACH_SAFE(control, &strm->inqueue, next, at) {
+ SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED);
+ TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) {
/* all delivered */
- nxt_todel = strm->last_sequence_delivered + 1;
- if (nxt_todel == control->sinfo_ssn) {
- TAILQ_REMOVE(&strm->inqueue, control, next);
- asoc->size_on_all_streams -= control->length;
- sctp_ucount_decr(asoc->cnt_on_all_streams);
- strm->last_sequence_delivered++;
+ nxt_todel = strm->last_mid_delivered + 1;
+ if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) &&
+ (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) {
+ if (control->on_strm_q == SCTP_ON_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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+#ifdef INVARIANTS
+ } else {
+ panic("Huh control: %p is on_strm_q: %d",
+ control, control->on_strm_q);
+#endif
+ }
+ control->on_strm_q = 0;
+ strm->last_mid_delivered++;
/*
* We ignore the return of deliver_data here
* since we always can hold the chunk on the
@@ -659,656 +635,1141 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
control,
&stcb->sctp_socket->so_rcv, 1,
SCTP_READ_LOCK_NOT_HELD,
- SCTP_SO_NOT_LOCKED);
+ SCTP_SO_LOCKED);
continue;
+ } else if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) {
+ *need_reasm = 1;
}
break;
}
+#if defined(__APPLE__) && !defined(__Userspace__)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
if (queue_needed) {
/*
* Ok, we did not deliver this guy, find the correct place
* to put it on the queue.
*/
- if (SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) {
- goto protocol_error;
+ if (sctp_place_control_in_stream(strm, asoc, control)) {
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "Queue to str MID: %u duplicate", control->mid);
+ sctp_clean_up_control(stcb, control);
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ *abort_flag = 1;
}
- if (TAILQ_EMPTY(&strm->inqueue)) {
- /* Empty queue */
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
- sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INSERT_HD);
- }
- TAILQ_INSERT_HEAD(&strm->inqueue, control, next);
- } else {
- TAILQ_FOREACH(at, &strm->inqueue, next) {
- if (SCTP_SSN_GT(at->sinfo_ssn, control->sinfo_ssn)) {
- /*
- * one in queue is bigger than the
- * new one, insert before this one
- */
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
- sctp_log_strm_del(control, at,
- SCTP_STR_LOG_FROM_INSERT_MD);
- }
- TAILQ_INSERT_BEFORE(at, control, next);
- break;
- } else if (at->sinfo_ssn == control->sinfo_ssn) {
- /*
- * Gak, He sent me a duplicate str
- * seq number
- */
- /*
- * foo bar, I guess I will just free
- * this new guy, should we abort
- * too? FIX ME MAYBE? Or it COULD be
- * that the SSN's have wrapped.
- * Maybe I should compare to TSN
- * somehow... sigh for now just blow
- * away the chunk!
- */
+ }
+}
- if (control->data)
- sctp_m_freem(control->data);
- control->data = NULL;
- asoc->size_on_all_streams -= control->length;
- sctp_ucount_decr(asoc->cnt_on_all_streams);
- if (control->whoFrom) {
- sctp_free_remote_addr(control->whoFrom);
- control->whoFrom = NULL;
- }
- sctp_free_a_readq(stcb, control);
- return;
- } else {
- if (TAILQ_NEXT(at, next) == NULL) {
- /*
- * We are at the end, insert
- * it after this one
- */
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
- sctp_log_strm_del(control, at,
- SCTP_STR_LOG_FROM_INSERT_TL);
- }
- TAILQ_INSERT_AFTER(&strm->inqueue,
- at, control, next);
- break;
- }
- }
+static void
+sctp_setup_tail_pointer(struct sctp_queued_to_read *control)
+{
+ struct mbuf *m, *prev = NULL;
+ struct sctp_tcb *stcb;
+
+ stcb = control->stcb;
+ control->held_length = 0;
+ control->length = 0;
+ m = control->data;
+ while (m) {
+ if (SCTP_BUF_LEN(m) == 0) {
+ /* Skip mbufs with NO length */
+ if (prev == NULL) {
+ /* First one */
+ control->data = sctp_m_free(m);
+ m = control->data;
+ } else {
+ SCTP_BUF_NEXT(prev) = sctp_m_free(m);
+ m = SCTP_BUF_NEXT(prev);
+ }
+ if (m == NULL) {
+ control->tail_mbuf = prev;
}
+ continue;
+ }
+ prev = m;
+ atomic_add_int(&control->length, SCTP_BUF_LEN(m));
+ if (control->on_read_q) {
+ /*
+ * On read queue so we must increment the
+ * SB stuff, we assume caller has done any locks of SB.
+ */
+ sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
}
+ m = SCTP_BUF_NEXT(m);
+ }
+ if (prev) {
+ control->tail_mbuf = prev;
}
}
-/*
- * Returns two things: You get the total size of the deliverable parts of the
- * first fragmented message on the reassembly queue. And you get a 1 back if
- * all of the message is ready or a 0 back if the message is still incomplete
- */
-static int
-sctp_is_all_msg_on_reasm(struct sctp_association *asoc, uint32_t *t_size)
+static void
+sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added)
{
- struct sctp_tmit_chunk *chk;
- uint32_t tsn;
+ struct mbuf *prev=NULL;
+ struct sctp_tcb *stcb;
- *t_size = 0;
- chk = TAILQ_FIRST(&asoc->reasmqueue);
- if (chk == NULL) {
- /* nothing on the queue */
- return (0);
+ stcb = control->stcb;
+ if (stcb == NULL) {
+#ifdef INVARIANTS
+ panic("Control broken");
+#else
+ return;
+#endif
}
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) {
- /* Not a first on the queue */
- return (0);
+ if (control->tail_mbuf == NULL) {
+ /* TSNH */
+ sctp_m_freem(control->data);
+ control->data = m;
+ sctp_setup_tail_pointer(control);
+ return;
}
- tsn = chk->rec.data.TSN_seq;
- TAILQ_FOREACH(chk, &asoc->reasmqueue, sctp_next) {
- if (tsn != chk->rec.data.TSN_seq) {
- return (0);
+ control->tail_mbuf->m_next = m;
+ while (m) {
+ if (SCTP_BUF_LEN(m) == 0) {
+ /* Skip mbufs with NO length */
+ if (prev == NULL) {
+ /* First one */
+ control->tail_mbuf->m_next = sctp_m_free(m);
+ m = control->tail_mbuf->m_next;
+ } else {
+ SCTP_BUF_NEXT(prev) = sctp_m_free(m);
+ m = SCTP_BUF_NEXT(prev);
+ }
+ if (m == NULL) {
+ control->tail_mbuf = prev;
+ }
+ continue;
}
- *t_size += chk->send_size;
- if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
- return (1);
+ prev = m;
+ if (control->on_read_q) {
+ /*
+ * On read queue so we must increment the
+ * SB stuff, we assume caller has done any locks of SB.
+ */
+ sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
}
- tsn++;
+ *added += SCTP_BUF_LEN(m);
+ atomic_add_int(&control->length, SCTP_BUF_LEN(m));
+ m = SCTP_BUF_NEXT(m);
+ }
+ if (prev) {
+ control->tail_mbuf = prev;
}
- return (0);
}
static void
-sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc)
+sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control)
{
- struct sctp_tmit_chunk *chk;
- uint16_t nxt_todel;
- uint32_t tsize, pd_point;
-
- doit_again:
- chk = TAILQ_FIRST(&asoc->reasmqueue);
- if (chk == NULL) {
- /* Huh? */
- asoc->size_on_reasm_queue = 0;
- asoc->cnt_on_reasm_queue = 0;
- return;
+ memset(nc, 0, sizeof(struct sctp_queued_to_read));
+ nc->sinfo_stream = control->sinfo_stream;
+ nc->mid = control->mid;
+ TAILQ_INIT(&nc->reasm);
+ nc->top_fsn = control->top_fsn;
+ nc->mid = control->mid;
+ nc->sinfo_flags = control->sinfo_flags;
+ nc->sinfo_ppid = control->sinfo_ppid;
+ nc->sinfo_context = control->sinfo_context;
+ nc->fsn_included = 0xffffffff;
+ nc->sinfo_tsn = control->sinfo_tsn;
+ nc->sinfo_cumtsn = control->sinfo_cumtsn;
+ nc->sinfo_assoc_id = control->sinfo_assoc_id;
+ nc->whoFrom = control->whoFrom;
+ atomic_add_int(&nc->whoFrom->ref_count, 1);
+ nc->stcb = control->stcb;
+ nc->port_from = control->port_from;
+ nc->do_not_ref_stcb = control->do_not_ref_stcb;
+}
+
+static void
+sctp_reset_a_control(struct sctp_queued_to_read *control,
+ struct sctp_inpcb *inp, uint32_t tsn)
+{
+ control->fsn_included = tsn;
+ if (control->on_read_q) {
+ /*
+ * We have to purge it from there,
+ * hopefully this will work :-)
+ */
+ TAILQ_REMOVE(&inp->read_queue, control, next);
+ control->on_read_q = 0;
}
- if (asoc->fragmented_delivery_inprogress == 0) {
- nxt_todel =
- asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1;
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) &&
- (nxt_todel == chk->rec.data.stream_seq ||
- (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) {
- /*
- * Yep the first one is here and its ok to deliver
- * but should we?
- */
- if (stcb->sctp_socket) {
- pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
- stcb->sctp_ep->partial_delivery_point);
- } else {
- pd_point = stcb->sctp_ep->partial_delivery_point;
+}
+
+static int
+sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
+ struct sctp_association *asoc,
+ struct sctp_stream_in *strm,
+ struct sctp_queued_to_read *control,
+ uint32_t pd_point,
+ int inp_read_lock_held)
+{
+ /* Special handling for the old un-ordered data chunk.
+ * All the chunks/TSN's go to mid 0. So
+ * we have to do the old style watching to see
+ * if we have it all. If you return one, no other
+ * control entries on the un-ordered queue will
+ * be looked at. In theory there should be no others
+ * entries in reality, unless the guy is sending both
+ * unordered NDATA and unordered DATA...
+ */
+ struct sctp_tmit_chunk *chk, *lchk, *tchk;
+ uint32_t fsn;
+ struct sctp_queued_to_read *nc;
+ int cnt_added;
+
+ if (control->first_frag_seen == 0) {
+ /* Nothing we can do, we have not seen the first piece yet */
+ return (1);
+ }
+ /* Collapse any we can */
+ cnt_added = 0;
+restart:
+ fsn = control->fsn_included + 1;
+ /* Now what can we add? */
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) {
+ if (chk->rec.data.fsn == fsn) {
+ /* Ok lets add it */
+ sctp_alloc_a_readq(stcb, nc);
+ if (nc == NULL) {
+ break;
}
- if (sctp_is_all_msg_on_reasm(asoc, &tsize) || (tsize >= pd_point)) {
- /*
- * Yes, we setup to start reception, by
- * backing down the TSN just in case we
- * can't deliver. If we
- */
- asoc->fragmented_delivery_inprogress = 1;
- asoc->tsn_last_delivered =
- chk->rec.data.TSN_seq - 1;
- asoc->str_of_pdapi =
- chk->rec.data.stream_number;
- asoc->ssn_of_pdapi = chk->rec.data.stream_seq;
- asoc->pdapi_ppid = chk->rec.data.payloadtype;
- asoc->fragment_flags = chk->rec.data.rcv_flags;
- sctp_service_reassembly(stcb, asoc);
+ memset(nc, 0, sizeof(struct sctp_queued_to_read));
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ sctp_add_chk_to_control(control, strm, stcb, asoc, chk, SCTP_READ_LOCK_NOT_HELD);
+ fsn++;
+ cnt_added++;
+ chk = NULL;
+ if (control->end_added) {
+ /* We are done */
+ if (!TAILQ_EMPTY(&control->reasm)) {
+ /*
+ * Ok we have to move anything left on
+ * the control queue to a new control.
+ */
+ sctp_build_readq_entry_from_ctl(nc, control);
+ tchk = TAILQ_FIRST(&control->reasm);
+ if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+ TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
+ if (asoc->size_on_reasm_queue >= tchk->send_size) {
+ asoc->size_on_reasm_queue -= tchk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_reasm_queue);
+ nc->first_frag_seen = 1;
+ nc->fsn_included = tchk->rec.data.fsn;
+ nc->data = tchk->data;
+ nc->sinfo_ppid = tchk->rec.data.ppid;
+ nc->sinfo_tsn = tchk->rec.data.tsn;
+ sctp_mark_non_revokable(asoc, tchk->rec.data.tsn);
+ tchk->data = NULL;
+ sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED);
+ sctp_setup_tail_pointer(nc);
+ tchk = TAILQ_FIRST(&control->reasm);
+ }
+ /* Spin the rest onto the queue */
+ while (tchk) {
+ TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
+ TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next);
+ tchk = TAILQ_FIRST(&control->reasm);
+ }
+ /* Now lets add it to the queue after removing control */
+ TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm);
+ nc->on_strm_q = SCTP_ON_UNORDERED;
+ if (control->on_strm_q) {
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ }
+ }
+ if (control->pdapi_started) {
+ strm->pd_api_started = 0;
+ control->pdapi_started = 0;
+ }
+ if (control->on_strm_q) {
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
+ }
+ if (control->on_read_q == 0) {
+ sctp_add_to_readq(stcb->sctp_ep, stcb, control,
+ &stcb->sctp_socket->so_rcv, control->end_added,
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
+#if defined(__Userspace__)
+ } else {
+ sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, inp_read_lock_held);
+#endif
+ }
+ sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
+ if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) {
+ /* Switch to the new guy and continue */
+ control = nc;
+ goto restart;
+ } else {
+ if (nc->on_strm_q == 0) {
+ sctp_free_a_readq(stcb, nc);
+ }
+ }
+ return (1);
+ } else {
+ sctp_free_a_readq(stcb, nc);
}
+ } else {
+ /* Can't add more */
+ break;
}
+ }
+ if (cnt_added && strm->pd_api_started) {
+#if defined(__Userspace__)
+ sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, SCTP_READ_LOCK_NOT_HELD);
+#endif
+ sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
+ }
+ if ((control->length > pd_point) && (strm->pd_api_started == 0)) {
+ 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,
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
+ sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
+ return (0);
} else {
- /* Service re-assembly will deliver stream data queued
- * at the end of fragmented delivery.. but it wont know
- * to go back and call itself again... we do that here
- * with the got doit_again
- */
- sctp_service_reassembly(stcb, asoc);
- if (asoc->fragmented_delivery_inprogress == 0) {
- /* finished our Fragmented delivery, could be
- * more waiting?
- */
- goto doit_again;
- }
+ return (1);
}
}
-/*
- * Dump onto the re-assembly queue, in its proper place. After dumping on the
- * queue, see if anthing can be delivered. If so pull it off (or as much as
- * we can. If we run out of space then we must dump what we can and set the
- * appropriate flag to say we queued what we could.
- */
static void
-sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
- struct sctp_tmit_chunk *chk, int *abort_flag)
+sctp_inject_old_unordered_data(struct sctp_tcb *stcb,
+ struct sctp_association *asoc,
+ struct sctp_queued_to_read *control,
+ struct sctp_tmit_chunk *chk,
+ int *abort_flag)
{
- struct mbuf *op_err;
- char msg[SCTP_DIAG_INFO_LEN];
- uint32_t cum_ackp1, prev_tsn, post_tsn;
- struct sctp_tmit_chunk *at, *prev, *next;
-
- prev = next = NULL;
- cum_ackp1 = asoc->tsn_last_delivered + 1;
- if (TAILQ_EMPTY(&asoc->reasmqueue)) {
- /* This is the first one on the queue */
- TAILQ_INSERT_HEAD(&asoc->reasmqueue, chk, sctp_next);
- /*
- * we do not check for delivery of anything when only one
- * fragment is here
- */
- asoc->size_on_reasm_queue = chk->send_size;
- sctp_ucount_incr(asoc->cnt_on_reasm_queue);
- if (chk->rec.data.TSN_seq == cum_ackp1) {
- if (asoc->fragmented_delivery_inprogress == 0 &&
- (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) !=
- SCTP_DATA_FIRST_FRAG) {
- /*
- * An empty queue, no delivery inprogress,
- * we hit the next one and it does NOT have
- * a FIRST fragment mark.
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, its not first, no fragmented delivery in progress\n");
- snprintf(msg, sizeof(msg),
- "Expected B-bit for TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_2;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- } else if (asoc->fragmented_delivery_inprogress &&
- (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) {
- /*
- * We are doing a partial delivery and the
- * NEXT chunk MUST be either the LAST or
- * MIDDLE fragment NOT a FIRST
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS a first and fragmented delivery in progress\n");
- snprintf(msg, sizeof(msg),
- "Didn't expect B-bit for TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_3;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- } else if (asoc->fragmented_delivery_inprogress) {
+ struct sctp_tmit_chunk *at;
+ int inserted;
+ /*
+ * Here we need to place the chunk into the control structure
+ * sorted in the correct order.
+ */
+ if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+ /* Its the very first one. */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "chunk is a first fsn: %u becomes fsn_included\n",
+ chk->rec.data.fsn);
+ at = TAILQ_FIRST(&control->reasm);
+ if (at && SCTP_TSN_GT(chk->rec.data.fsn, at->rec.data.fsn)) {
+ /*
+ * The first chunk in the reassembly is
+ * a smaller TSN than this one, even though
+ * this has a first, it must be from a subsequent
+ * msg.
+ */
+ goto place_chunk;
+ }
+ if (control->first_frag_seen) {
+ /*
+ * In old un-ordered we can reassembly on
+ * one control multiple messages. As long
+ * as the next FIRST is greater then the old
+ * first (TSN i.e. FSN wise)
+ */
+ struct mbuf *tdata;
+ uint32_t tmp;
+
+ if (SCTP_TSN_GT(chk->rec.data.fsn, control->fsn_included)) {
+ /* Easy way the start of a new guy beyond the lowest */
+ goto place_chunk;
+ }
+ if ((chk->rec.data.fsn == control->fsn_included) ||
+ (control->pdapi_started)) {
/*
- * Here we are ok with a MIDDLE or LAST
- * piece
+ * Ok this should not happen, if it does
+ * we started the pd-api on the higher TSN (since
+ * the equals part is a TSN failure it must be that).
+ *
+ * We are completly hosed in that case since I have
+ * no way to recover. This really will only happen
+ * if we can get more TSN's higher before the pd-api-point.
*/
- if (chk->rec.data.stream_number !=
- asoc->str_of_pdapi) {
- /* Got to be the right STR No */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS not same stream number %d vs %d\n",
- chk->rec.data.stream_number,
- asoc->str_of_pdapi);
- snprintf(msg, sizeof(msg),
- "Expected SID=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- asoc->str_of_pdapi,
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_4;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- } else if ((asoc->fragment_flags & SCTP_DATA_UNORDERED) !=
- SCTP_DATA_UNORDERED &&
- chk->rec.data.stream_seq != asoc->ssn_of_pdapi) {
- /* Got to be the right STR Seq */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS not same stream seq %d vs %d\n",
- chk->rec.data.stream_seq,
- asoc->ssn_of_pdapi);
- snprintf(msg, sizeof(msg),
- "Expected SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- asoc->ssn_of_pdapi,
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_5;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- }
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_4);
+
+ return;
}
- }
+ /*
+ * Ok we have two firsts and the one we just got
+ * is smaller than the one we previously placed.. yuck!
+ * We must swap them out.
+ */
+ /* swap the mbufs */
+ tdata = control->data;
+ control->data = chk->data;
+ chk->data = tdata;
+ /* Save the lengths */
+ chk->send_size = control->length;
+ /* Recompute length of control and tail pointer */
+ sctp_setup_tail_pointer(control);
+ /* Fix the FSN included */
+ tmp = control->fsn_included;
+ control->fsn_included = chk->rec.data.fsn;
+ chk->rec.data.fsn = tmp;
+ /* Fix the TSN included */
+ tmp = control->sinfo_tsn;
+ control->sinfo_tsn = chk->rec.data.tsn;
+ chk->rec.data.tsn = tmp;
+ /* Fix the PPID included */
+ tmp = control->sinfo_ppid;
+ control->sinfo_ppid = chk->rec.data.ppid;
+ chk->rec.data.ppid = tmp;
+ /* Fix tail pointer */
+ goto place_chunk;
+ }
+ control->first_frag_seen = 1;
+ control->fsn_included = chk->rec.data.fsn;
+ control->top_fsn = chk->rec.data.fsn;
+ control->sinfo_tsn = chk->rec.data.tsn;
+ control->sinfo_ppid = chk->rec.data.ppid;
+ control->data = chk->data;
+ sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
+ chk->data = NULL;
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ sctp_setup_tail_pointer(control);
return;
}
- /* Find its place */
- TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) {
- if (SCTP_TSN_GT(at->rec.data.TSN_seq, chk->rec.data.TSN_seq)) {
+place_chunk:
+ inserted = 0;
+ TAILQ_FOREACH(at, &control->reasm, sctp_next) {
+ if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
/*
- * one in queue is bigger than the new one, insert
- * before this one
+ * This one in queue is bigger than the new one, insert
+ * the new one before at.
*/
- /* A check */
asoc->size_on_reasm_queue += chk->send_size;
sctp_ucount_incr(asoc->cnt_on_reasm_queue);
- next = at;
+ inserted = 1;
TAILQ_INSERT_BEFORE(at, chk, sctp_next);
break;
- } else if (at->rec.data.TSN_seq == chk->rec.data.TSN_seq) {
- /* Gak, He sent me a duplicate str seq number */
+ } else if (at->rec.data.fsn == chk->rec.data.fsn) {
/*
- * foo bar, I guess I will just free this new guy,
- * should we abort too? FIX ME MAYBE? Or it COULD be
- * that the SSN's have wrapped. Maybe I should
- * compare to TSN somehow... sigh for now just blow
- * away the chunk!
+ * They sent a duplicate fsn number. This
+ * really should not happen since the FSN is
+ * a TSN and it should have been dropped earlier.
*/
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_5);
return;
+ }
+ }
+ if (inserted == 0) {
+ /* Its at the end */
+ asoc->size_on_reasm_queue += chk->send_size;
+ sctp_ucount_incr(asoc->cnt_on_reasm_queue);
+ control->top_fsn = chk->rec.data.fsn;
+ TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
+ }
+}
+
+static int
+sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
+ struct sctp_stream_in *strm, int inp_read_lock_held)
+{
+ /*
+ * Given a stream, strm, see if any of
+ * the SSN's on it that are fragmented
+ * are ready to deliver. If so go ahead
+ * and place them on the read queue. In
+ * so placing if we have hit the end, then
+ * we need to remove them from the stream's queue.
+ */
+ struct sctp_queued_to_read *control, *nctl = NULL;
+ uint32_t next_to_del;
+ uint32_t pd_point;
+ int ret = 0;
+
+ if (stcb->sctp_socket) {
+ pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
+ stcb->sctp_ep->partial_delivery_point);
+ } else {
+ pd_point = stcb->sctp_ep->partial_delivery_point;
+ }
+ control = TAILQ_FIRST(&strm->uno_inqueue);
+
+ if ((control != NULL) &&
+ (asoc->idata_supported == 0)) {
+ /* Special handling needed for "old" data format */
+ if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) {
+ goto done_un;
+ }
+ }
+ if (strm->pd_api_started) {
+ /* Can't add more */
+ return (0);
+ }
+ while (control) {
+ SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n",
+ control, control->end_added, control->mid, control->top_fsn, control->fsn_included);
+ nctl = TAILQ_NEXT(control, next_instrm);
+ if (control->end_added) {
+ /* We just put the last bit on */
+ if (control->on_strm_q) {
+#ifdef INVARIANTS
+ if (control->on_strm_q != SCTP_ON_UNORDERED) {
+ panic("Huh control: %p on_q: %d -- not unordered?",
+ control, control->on_strm_q);
+ }
+#endif
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
+ TAILQ_REMOVE(&strm->uno_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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ control->on_strm_q = 0;
+ }
+ if (control->on_read_q == 0) {
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, control->end_added,
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
+ }
} else {
- prev = at;
- if (TAILQ_NEXT(at, sctp_next) == NULL) {
- /*
- * We are at the end, insert it after this
- * one
- */
- /* check it first */
- asoc->size_on_reasm_queue += chk->send_size;
- sctp_ucount_incr(asoc->cnt_on_reasm_queue);
- TAILQ_INSERT_AFTER(&asoc->reasmqueue, at, chk, sctp_next);
+ /* Can we do a PD-API for this un-ordered guy? */
+ if ((control->length >= pd_point) && (strm->pd_api_started == 0)) {
+ 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,
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
+
break;
}
}
+ control = nctl;
}
- /* Now the audits */
- if (prev) {
- prev_tsn = chk->rec.data.TSN_seq - 1;
- if (prev_tsn == prev->rec.data.TSN_seq) {
- /*
- * Ok the one I am dropping onto the end is the
- * NEXT. A bit of valdiation here.
- */
- if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_FIRST_FRAG ||
- (prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_MIDDLE_FRAG) {
- /*
- * Insert chk MUST be a MIDDLE or LAST
- * fragment
- */
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_FIRST_FRAG) {
- SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - It can be a midlle or last but not a first\n");
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it's a FIRST!\n");
- snprintf(msg, sizeof(msg),
- "Can't handle B-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_6;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- return;
+done_un:
+ control = TAILQ_FIRST(&strm->inqueue);
+ if (strm->pd_api_started) {
+ /* Can't add more */
+ return (0);
+ }
+ if (control == NULL) {
+ return (ret);
+ }
+ if (SCTP_MID_EQ(asoc->idata_supported, strm->last_mid_delivered, control->mid)) {
+ /* Ok the guy at the top was being partially delivered
+ * completed, so we remove it. Note
+ * the pd_api flag was taken off when the
+ * chunk was merged on in sctp_queue_data_for_reasm below.
+ */
+ nctl = TAILQ_NEXT(control, next_instrm);
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n",
+ control, control->end_added, control->mid,
+ control->top_fsn, control->fsn_included,
+ strm->last_mid_delivered);
+ if (control->end_added) {
+ if (control->on_strm_q) {
+#ifdef INVARIANTS
+ if (control->on_strm_q != SCTP_ON_ORDERED) {
+ panic("Huh control: %p on_q: %d -- not ordered?",
+ control, control->on_strm_q);
}
- if (chk->rec.data.stream_number !=
- prev->rec.data.stream_number) {
- /*
- * Huh, need the correct STR here,
- * they must be the same.
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, Evil plot, sid:%d not the same as at:%d\n",
- chk->rec.data.stream_number,
- prev->rec.data.stream_number);
- snprintf(msg, sizeof(msg),
- "Expect SID=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- prev->rec.data.stream_number,
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_7;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- return;
+#endif
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
+ 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
}
- if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) !=
- (prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
- /*
- * Huh, need the same ordering here,
- * they must be the same.
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, Evil plot, U-bit not constant\n");
- snprintf(msg, sizeof(msg),
- "Expect U-bit=%d for TSN=%8.8x, got U-bit=%d",
- (prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0,
- chk->rec.data.TSN_seq,
- (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_7;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- return;
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ control->on_strm_q = 0;
+ }
+ if (strm->pd_api_started && control->pdapi_started) {
+ control->pdapi_started = 0;
+ strm->pd_api_started = 0;
+ }
+ if (control->on_read_q == 0) {
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, control->end_added,
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
+ }
+ control = nctl;
+ }
+ }
+ if (strm->pd_api_started) {
+ /* Can't add more must have gotten an un-ordered above being partially delivered. */
+ return (0);
+ }
+deliver_more:
+ next_to_del = strm->last_mid_delivered + 1;
+ if (control) {
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n",
+ control, control->end_added, control->mid, control->top_fsn, control->fsn_included,
+ next_to_del);
+ nctl = TAILQ_NEXT(control, next_instrm);
+ if (SCTP_MID_EQ(asoc->idata_supported, control->mid, next_to_del) &&
+ (control->first_frag_seen)) {
+ int done;
+
+ /* Ok we can deliver it onto the stream. */
+ if (control->end_added) {
+ /* We are done with it afterwards */
+ if (control->on_strm_q) {
+#ifdef INVARIANTS
+ if (control->on_strm_q != SCTP_ON_ORDERED) {
+ panic("Huh control: %p on_q: %d -- not ordered?",
+ control, control->on_strm_q);
+ }
+#endif
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
+ 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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ control->on_strm_q = 0;
}
- if ((prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 &&
- chk->rec.data.stream_seq !=
- prev->rec.data.stream_seq) {
- /*
- * Huh, need the correct STR here,
- * they must be the same.
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, Evil plot, sseq:%d not the same as at:%d\n",
- chk->rec.data.stream_seq,
- prev->rec.data.stream_seq);
- snprintf(msg, sizeof(msg),
- "Expect SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- prev->rec.data.stream_seq,
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_8;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- return;
+ ret++;
+ }
+ if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ /* A singleton now slipping through - mark it non-revokable too */
+ sctp_mark_non_revokable(asoc, control->sinfo_tsn);
+ } else if (control->end_added == 0) {
+ /* Check if we can defer adding until its all there */
+ if ((control->length < pd_point) || (strm->pd_api_started)) {
+ /* Don't need it or cannot add more (one being delivered that way) */
+ goto out;
}
- } else if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_LAST_FRAG) {
- /* Insert chk MUST be a FIRST */
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) !=
- SCTP_DATA_FIRST_FRAG) {
- SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, evil plot, its not FIRST and it must be!\n");
- snprintf(msg, sizeof(msg),
- "Expect B-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_9;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- return;
+ }
+ 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,
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
+ }
+ strm->last_mid_delivered = next_to_del;
+ if (done) {
+ control = nctl;
+ goto deliver_more;
}
}
}
- if (next) {
- post_tsn = chk->rec.data.TSN_seq + 1;
- if (post_tsn == next->rec.data.TSN_seq) {
+out:
+ return (ret);
+}
+
+uint32_t
+sctp_add_chk_to_control(struct sctp_queued_to_read *control,
+ struct sctp_stream_in *strm,
+ struct sctp_tcb *stcb, struct sctp_association *asoc,
+ struct sctp_tmit_chunk *chk, int hold_rlock)
+{
+ /*
+ * Given a control and a chunk, merge the
+ * data from the chk onto the control and free
+ * up the chunk resources.
+ */
+ uint32_t added=0;
+ int i_locked = 0;
+
+ if (control->on_read_q && (hold_rlock == 0)) {
+ /*
+ * Its being pd-api'd so we must
+ * do some locks.
+ */
+ SCTP_INP_READ_LOCK(stcb->sctp_ep);
+ i_locked = 1;
+ }
+ if (control->data == NULL) {
+ control->data = chk->data;
+ sctp_setup_tail_pointer(control);
+ } else {
+ sctp_add_to_tail_pointer(control, chk->data, &added);
+ }
+ control->fsn_included = chk->rec.data.fsn;
+ asoc->size_on_reasm_queue -= chk->send_size;
+ sctp_ucount_decr(asoc->cnt_on_reasm_queue);
+ sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
+ chk->data = NULL;
+ if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+ control->first_frag_seen = 1;
+ control->sinfo_tsn = chk->rec.data.tsn;
+ control->sinfo_ppid = chk->rec.data.ppid;
+ }
+ if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
+ /* Its complete */
+ if ((control->on_strm_q) && (control->on_read_q)) {
+ if (control->pdapi_started) {
+ control->pdapi_started = 0;
+ strm->pd_api_started = 0;
+ }
+ if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ /* Unordered */
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ } else if (control->on_strm_q == SCTP_ON_ORDERED) {
+ /* Ordered */
+ TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ /*
+ * 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
+ } else if (control->on_strm_q) {
+ panic("Unknown state on ctrl: %p on_strm_q: %d", control,
+ control->on_strm_q);
+#endif
+ }
+ }
+ control->end_added = 1;
+ control->last_frag_seen = 1;
+ }
+ if (i_locked) {
+ SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+ }
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ return (added);
+}
+
+/*
+ * Dump onto the re-assembly queue, in its proper place. After dumping on the
+ * queue, see if anthing can be delivered. If so pull it off (or as much as
+ * we can. If we run out of space then we must dump what we can and set the
+ * appropriate flag to say we queued what we could.
+ */
+static void
+sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
+ struct sctp_queued_to_read *control,
+ struct sctp_tmit_chunk *chk,
+ int created_control,
+ int *abort_flag, uint32_t tsn)
+{
+ uint32_t next_fsn;
+ struct sctp_tmit_chunk *at, *nat;
+ struct sctp_stream_in *strm;
+ int do_wakeup, unordered;
+ uint32_t lenadded;
+
+ strm = &asoc->strmin[control->sinfo_stream];
+ /*
+ * For old un-ordered data chunks.
+ */
+ if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
+ unordered = 1;
+ } else {
+ unordered = 0;
+ }
+ /* Must be added to the stream-in queue */
+ if (created_control) {
+ if ((unordered == 0) || (asoc->idata_supported)) {
+ sctp_ucount_incr(asoc->cnt_on_all_streams);
+ }
+ if (sctp_place_control_in_stream(strm, asoc, control)) {
+ /* Duplicate SSN? */
+ 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))) {
+ /* Ok we created this control and now
+ * lets validate that its legal i.e. there
+ * is a B bit set, if not and we have
+ * up to the cum-ack then its invalid.
+ */
+ if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) {
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_7);
+ return;
+ }
+ }
+ }
+ if ((asoc->idata_supported == 0) && (unordered == 1)) {
+ sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag);
+ return;
+ }
+ /*
+ * Ok we must queue the chunk into the reasembly portion:
+ * o if its the first it goes to the control mbuf.
+ * o if its not first but the next in sequence it goes to the control,
+ * and each succeeding one in order also goes.
+ * o if its not in order we place it on the list in its place.
+ */
+ if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+ /* Its the very first one. */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "chunk is a first fsn: %u becomes fsn_included\n",
+ chk->rec.data.fsn);
+ if (control->first_frag_seen) {
/*
- * Ok the one I am inserting ahead of is my NEXT
- * one. A bit of valdiation here.
+ * Error on senders part, they either
+ * sent us two data chunks with FIRST,
+ * or they sent two un-ordered chunks that
+ * were fragmented at the same time in the same stream.
*/
- if (next->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
- /* Insert chk MUST be a last fragment */
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK)
- != SCTP_DATA_LAST_FRAG) {
- SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Next is FIRST, we must be LAST\n");
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, its not a last!\n");
- snprintf(msg, sizeof(msg),
- "Expect only E-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_10;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_8);
+ return;
+ }
+ control->first_frag_seen = 1;
+ control->sinfo_ppid = chk->rec.data.ppid;
+ control->sinfo_tsn = chk->rec.data.tsn;
+ control->fsn_included = chk->rec.data.fsn;
+ control->data = chk->data;
+ sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
+ chk->data = NULL;
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ sctp_setup_tail_pointer(control);
+ asoc->size_on_all_streams += control->length;
+ } else {
+ /* Place the chunk in our list */
+ int inserted=0;
+ if (control->last_frag_seen == 0) {
+ /* Still willing to raise highest FSN seen */
+ if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) {
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "We have a new top_fsn: %u\n",
+ chk->rec.data.fsn);
+ control->top_fsn = chk->rec.data.fsn;
+ }
+ if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "The last fsn is now in place fsn: %u\n",
+ chk->rec.data.fsn);
+ control->last_frag_seen = 1;
+ if (SCTP_TSN_GT(control->top_fsn, chk->rec.data.fsn)) {
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "New fsn: %u is not at top_fsn: %u -- abort\n",
+ chk->rec.data.fsn,
+ control->top_fsn);
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_9);
return;
}
- } else if ((next->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_MIDDLE_FRAG ||
- (next->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_LAST_FRAG) {
+ }
+ if (asoc->idata_supported || control->first_frag_seen) {
/*
- * Insert chk CAN be MIDDLE or FIRST NOT
- * LAST
+ * For IDATA we always check since we know that
+ * the first fragment is 0. For old DATA we have
+ * to receive the first before we know the first FSN
+ * (which is the TSN).
*/
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) ==
- SCTP_DATA_LAST_FRAG) {
- SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Next is a MIDDLE/LAST\n");
- SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, new prev chunk is a LAST\n");
- snprintf(msg, sizeof(msg),
- "Didn't expect E-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_11;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
+ if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) {
+ /* We have already delivered up to this so its a dup */
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_10);
return;
}
- if (chk->rec.data.stream_number !=
- next->rec.data.stream_number) {
- /*
- * Huh, need the correct STR here,
- * they must be the same.
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Gak, Evil plot, ssn:%d not the same as at:%d\n",
- chk->rec.data.stream_number,
- next->rec.data.stream_number);
- snprintf(msg, sizeof(msg),
- "Required SID %4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- next->rec.data.stream_number,
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_12;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
+ }
+ } else {
+ if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
+ /* Second last? huh? */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Duplicate last fsn: %u (top: %u) -- abort\n",
+ chk->rec.data.fsn, control->top_fsn);
+ sctp_abort_in_reasm(stcb, control,
+ chk, abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_11);
+ return;
+ }
+ if (asoc->idata_supported || control->first_frag_seen) {
+ /*
+ * For IDATA we always check since we know that
+ * the first fragment is 0. For old DATA we have
+ * to receive the first before we know the first FSN
+ * (which is the TSN).
+ */
+
+ if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) {
+ /* We have already delivered up to this so its a dup */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "New fsn: %u is already seen in included_fsn: %u -- abort\n",
+ chk->rec.data.fsn, control->fsn_included);
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_12);
return;
}
- if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) !=
- (next->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
- /*
- * Huh, need the same ordering here,
- * they must be the same.
- */
- SCTPDBG(SCTP_DEBUG_INDATA1, "Next check - Gak, Evil plot, U-bit not constant\n");
- snprintf(msg, sizeof(msg),
- "Expect U-bit=%d for TSN=%8.8x, got U-bit=%d",
- (next->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0,
- chk->rec.data.TSN_seq,
- (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_12;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
+ }
+ /* validate not beyond top FSN if we have seen last one */
+ if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) {
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "New fsn: %u is beyond or at top_fsn: %u -- abort\n",
+ chk->rec.data.fsn,
+ control->top_fsn);
+ sctp_abort_in_reasm(stcb, control, chk,
+ abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_13);
+ return;
+ }
+ }
+ /*
+ * If we reach here, we need to place the
+ * new chunk in the reassembly for this
+ * control.
+ */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "chunk is a not first fsn: %u needs to be inserted\n",
+ chk->rec.data.fsn);
+ TAILQ_FOREACH(at, &control->reasm, sctp_next) {
+ if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
+ if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
+ /* Last not at the end? huh? */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Last fragment not last in list: -- abort\n");
+ sctp_abort_in_reasm(stcb, control,
+ chk, abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_14);
return;
}
- if ((next->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 &&
- chk->rec.data.stream_seq !=
- next->rec.data.stream_seq) {
+ /*
+ * This one in queue is bigger than the new one, insert
+ * the new one before at.
+ */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Insert it before fsn: %u\n",
+ at->rec.data.fsn);
+ asoc->size_on_reasm_queue += chk->send_size;
+ sctp_ucount_incr(asoc->cnt_on_reasm_queue);
+ TAILQ_INSERT_BEFORE(at, chk, sctp_next);
+ inserted = 1;
+ break;
+ } else if (at->rec.data.fsn == chk->rec.data.fsn) {
+ /* Gak, He sent me a duplicate str seq number */
+ /*
+ * foo bar, I guess I will just free this new guy,
+ * should we abort too? FIX ME MAYBE? Or it COULD be
+ * that the SSN's have wrapped. Maybe I should
+ * compare to TSN somehow... sigh for now just blow
+ * away the chunk!
+ */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Duplicate to fsn: %u -- abort\n",
+ at->rec.data.fsn);
+ sctp_abort_in_reasm(stcb, control,
+ chk, abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_15);
+ return;
+ }
+ }
+ if (inserted == 0) {
+ /* Goes on the end */
+ SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n",
+ chk->rec.data.fsn);
+ asoc->size_on_reasm_queue += chk->send_size;
+ sctp_ucount_incr(asoc->cnt_on_reasm_queue);
+ TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
+ }
+ }
+ /*
+ * Ok lets see if we can suck any up into the control
+ * structure that are in seq if it makes sense.
+ */
+ do_wakeup = 0;
+ /*
+ * If the first fragment has not been
+ * seen there is no sense in looking.
+ */
+ if (control->first_frag_seen) {
+ next_fsn = control->fsn_included + 1;
+ TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) {
+ if (at->rec.data.fsn == next_fsn) {
+ /* We can add this one now to the control */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n",
+ control, at,
+ at->rec.data.fsn,
+ 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);
+ if (control->on_read_q) {
+ do_wakeup = 1;
+ } else {
/*
- * Huh, need the correct STR here,
- * they must be the same.
+ * 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.
*/
- SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Gak, Evil plot, sseq:%d not the same as at:%d\n",
- chk->rec.data.stream_seq,
- next->rec.data.stream_seq);
- snprintf(msg, sizeof(msg),
- "Required SSN %4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- next->rec.data.stream_seq,
- chk->rec.data.TSN_seq,
- chk->rec.data.stream_number,
- chk->rec.data.stream_seq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_13;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- return;
+ asoc->size_on_all_streams += lenadded;
}
+ next_fsn++;
+ if (control->end_added && control->pdapi_started) {
+ if (strm->pd_api_started) {
+ strm->pd_api_started = 0;
+ control->pdapi_started = 0;
+ }
+ if (control->on_read_q == 0) {
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, control->end_added,
+ SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ }
+ break;
+ }
+ } else {
+ break;
}
}
}
- /* Do we need to do some delivery? check */
- sctp_deliver_reasm_check(stcb, asoc);
+ if (do_wakeup) {
+#if defined(__Userspace__)
+ sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, SCTP_READ_LOCK_NOT_HELD);
+#endif
+ /* Need to wakeup the reader */
+ sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
+ }
}
-/*
- * This is an unfortunate routine. It checks to make sure a evil guy is not
- * stuffing us full of bad packet fragments. A broken peer could also do this
- * but this is doubtful. It is to bad I must worry about evil crackers sigh
- * :< more cycles.
- */
-static int
-sctp_does_tsn_belong_to_reasm(struct sctp_association *asoc,
- uint32_t TSN_seq)
+static struct sctp_queued_to_read *
+sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t mid, int ordered, int idata_supported)
{
- struct sctp_tmit_chunk *at;
- uint32_t tsn_est;
-
- TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) {
- if (SCTP_TSN_GT(TSN_seq, at->rec.data.TSN_seq)) {
- /* is it one bigger? */
- tsn_est = at->rec.data.TSN_seq + 1;
- if (tsn_est == TSN_seq) {
- /* yep. It better be a last then */
- if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) !=
- SCTP_DATA_LAST_FRAG) {
- /*
- * Ok this guy belongs next to a guy
- * that is NOT last, it should be a
- * middle/last, not a complete
- * chunk.
- */
- return (1);
- } else {
- /*
- * This guy is ok since its a LAST
- * and the new chunk is a fully
- * self- contained one.
- */
- return (0);
- }
+ struct sctp_queued_to_read *control;
+
+ if (ordered) {
+ TAILQ_FOREACH(control, &strm->inqueue, next_instrm) {
+ if (SCTP_MID_EQ(idata_supported, control->mid, mid)) {
+ break;
}
- } else if (TSN_seq == at->rec.data.TSN_seq) {
- /* Software error since I have a dup? */
- return (1);
- } else {
- /*
- * Ok, 'at' is larger than new chunk but does it
- * need to be right before it.
- */
- tsn_est = TSN_seq + 1;
- if (tsn_est == at->rec.data.TSN_seq) {
- /* Yep, It better be a first */
- if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) !=
- SCTP_DATA_FIRST_FRAG) {
- return (1);
- } else {
- return (0);
+ }
+ } else {
+ if (idata_supported) {
+ TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) {
+ if (SCTP_MID_EQ(idata_supported, control->mid, mid)) {
+ break;
}
}
+ } else {
+ control = TAILQ_FIRST(&strm->uno_inqueue);
}
}
- return (0);
+ return (control);
}
static int
sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
- struct mbuf **m, int offset, struct sctp_data_chunk *ch, int chk_length,
- struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag,
- int *break_flag, int last_chunk)
+ struct mbuf **m, int offset, int chk_length,
+ struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag,
+ int *break_flag, int last_chunk, uint8_t chk_type)
{
- /* Process a data chunk */
- /* struct sctp_tmit_chunk *chk; */
- struct sctp_tmit_chunk *chk;
- uint32_t tsn, gap;
+ struct sctp_tmit_chunk *chk = NULL; /* make gcc happy */
+ struct sctp_stream_in *strm;
+ uint32_t tsn, fsn, gap, mid;
struct mbuf *dmbuf;
int the_len;
int need_reasm_check = 0;
- uint16_t strmno, strmseq;
+ uint16_t sid;
struct mbuf *op_err;
char msg[SCTP_DIAG_INFO_LEN];
- struct sctp_queued_to_read *control;
- int ordered;
- uint32_t protocol_id;
- uint8_t chunk_flags;
+ struct sctp_queued_to_read *control, *ncontrol;
+ uint32_t ppid;
+ uint8_t chk_flags;
struct sctp_stream_reset_list *liste;
-
- chk = NULL;
- tsn = ntohl(ch->dp.tsn);
- chunk_flags = ch->ch.chunk_flags;
- if ((chunk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) {
+ int ordered;
+ size_t clen;
+ int created_control = 0;
+
+ if (chk_type == SCTP_IDATA) {
+ struct sctp_idata_chunk *chunk, chunk_buf;
+
+ chunk = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset,
+ sizeof(struct sctp_idata_chunk), (uint8_t *)&chunk_buf);
+ chk_flags = chunk->ch.chunk_flags;
+ clen = sizeof(struct sctp_idata_chunk);
+ tsn = ntohl(chunk->dp.tsn);
+ sid = ntohs(chunk->dp.sid);
+ mid = ntohl(chunk->dp.mid);
+ if (chk_flags & SCTP_DATA_FIRST_FRAG) {
+ fsn = 0;
+ ppid = chunk->dp.ppid_fsn.ppid;
+ } else {
+ fsn = ntohl(chunk->dp.ppid_fsn.fsn);
+ ppid = 0xffffffff; /* Use as an invalid value. */
+ }
+ } else {
+ struct sctp_data_chunk *chunk, chunk_buf;
+
+ chunk = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset,
+ sizeof(struct sctp_data_chunk), (uint8_t *)&chunk_buf);
+ chk_flags = chunk->ch.chunk_flags;
+ clen = sizeof(struct sctp_data_chunk);
+ tsn = ntohl(chunk->dp.tsn);
+ sid = ntohs(chunk->dp.sid);
+ mid = (uint32_t)(ntohs(chunk->dp.ssn));
+ fsn = tsn;
+ ppid = chunk->dp.ppid;
+ }
+ if ((size_t)chk_length == clen) {
+ /*
+ * Need to send an abort since we had a
+ * empty data chunk.
+ */
+ op_err = sctp_generate_no_user_data_cause(tsn);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ *abort_flag = 1;
+ return (0);
+ }
+ if ((chk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) {
asoc->send_sack = 1;
}
- protocol_id = ch->dp.protocol_id;
- ordered = ((chunk_flags & SCTP_DATA_UNORDERED) == 0);
+ ordered = ((chk_flags & SCTP_DATA_UNORDERED) == 0);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
}
if (stcb == NULL) {
return (0);
}
- SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, ch->ch.chunk_type, tsn);
+ SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, chk_type, tsn);
if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
/* It is a duplicate */
SCTP_STAT_INCR(sctps_recvdupdata);
@@ -1370,6 +1831,112 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
* for on a partial delivery API.
*/
+ /* Is the stream valid? */
+ if (sid >= asoc->streamincnt) {
+ struct sctp_error_invalid_stream *cause;
+
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream),
+ 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
+ /* add some space up front so prepend will work well */
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ cause = mtod(op_err, struct sctp_error_invalid_stream *);
+ /*
+ * Error causes are just param's and this one has
+ * two back to back phdr, one with the error type
+ * and size, the other with the streamid and a rsvd
+ */
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream);
+ cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM);
+ cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream));
+ cause->stream_id = htons(sid);
+ cause->reserved = htons(0);
+ sctp_queue_op_err(stcb, op_err);
+ }
+ SCTP_STAT_INCR(sctps_badsid);
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
+ if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
+ asoc->highest_tsn_inside_nr_map = tsn;
+ }
+ if (tsn == (asoc->cumulative_tsn + 1)) {
+ /* Update cum-ack */
+ asoc->cumulative_tsn = tsn;
+ }
+ return (0);
+ }
+ /*
+ * If its a fragmented message, lets see if we can
+ * find the control on the reassembly queues.
+ */
+ if ((chk_type == SCTP_IDATA) &&
+ ((chk_flags & SCTP_DATA_FIRST_FRAG) == 0) &&
+ (fsn == 0)) {
+ /*
+ * The first *must* be fsn 0, and other
+ * (middle/end) pieces can *not* be fsn 0.
+ * XXX: This can happen in case of a wrap around.
+ * Ignore is for now.
+ */
+ SCTP_SNPRINTF(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x", mid, chk_flags);
+ goto err_out;
+ }
+ control = sctp_find_reasm_entry(&asoc->strmin[sid], mid, ordered, asoc->idata_supported);
+ SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n",
+ chk_flags, control);
+ if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
+ /* See if we can find the re-assembly entity */
+ if (control != NULL) {
+ /* We found something, does it belong? */
+ if (ordered && (mid != control->mid)) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid);
+ err_out:
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ *abort_flag = 1;
+ return (0);
+ }
+ if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) {
+ /* We can't have a switched order with an unordered chunk */
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
+ tsn);
+ goto err_out;
+ }
+ if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) {
+ /* We can't have a switched unordered with a ordered chunk */
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
+ tsn);
+ goto err_out;
+ }
+ }
+ } else {
+ /* Its a complete segment. Lets validate we
+ * don't have a re-assembly going on with
+ * the same Stream/Seq (for ordered) or in
+ * the same Stream for unordered.
+ */
+ if (control != NULL) {
+ if (ordered || asoc->idata_supported) {
+ SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on MID: %u\n",
+ chk_flags, mid);
+ SCTP_SNPRINTF(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid);
+ goto err_out;
+ } else {
+ if ((tsn == control->fsn_included + 1) &&
+ (control->end_added == 0)) {
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "Illegal message sequence, missing end for MID: %8.8x",
+ control->fsn_included);
+ goto err_out;
+ } else {
+ control = NULL;
+ }
+ }
+ }
+ }
/* now do the tests */
if (((asoc->cnt_on_all_streams +
asoc->cnt_on_reasm_queue +
@@ -1381,7 +1948,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
*/
if (stcb->sctp_socket->so_rcv.sb_cc) {
/* some to read, wake-up */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -1397,73 +1964,36 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
/* now is it in the mapping array of what we have accepted? */
- if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) &&
- SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
- /* Nope not in the valid range dump it */
- sctp_set_rwnd(stcb, asoc);
- if ((asoc->cnt_on_all_streams +
- asoc->cnt_on_reasm_queue +
- asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) {
- SCTP_STAT_INCR(sctps_datadropchklmt);
- } else {
- SCTP_STAT_INCR(sctps_datadroprwnd);
+ if (chk_type == SCTP_DATA) {
+ if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) &&
+ SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
+ /* Nope not in the valid range dump it */
+ dump_packet:
+ sctp_set_rwnd(stcb, asoc);
+ if ((asoc->cnt_on_all_streams +
+ asoc->cnt_on_reasm_queue +
+ asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) {
+ SCTP_STAT_INCR(sctps_datadropchklmt);
+ } else {
+ SCTP_STAT_INCR(sctps_datadroprwnd);
+ }
+ *break_flag = 1;
+ return (0);
+ }
+ } else {
+ if (control == NULL) {
+ goto dump_packet;
+ }
+ if (SCTP_TSN_GT(fsn, control->top_fsn)) {
+ goto dump_packet;
}
- *break_flag = 1;
- return (0);
- }
- }
- strmno = ntohs(ch->dp.stream_id);
- if (strmno >= asoc->streamincnt) {
- struct sctp_paramhdr *phdr;
- struct mbuf *mb;
-
- mb = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) * 2),
- 0, M_NOWAIT, 1, MT_DATA);
- if (mb != NULL) {
- /* add some space up front so prepend will work well */
- SCTP_BUF_RESV_UF(mb, sizeof(struct sctp_chunkhdr));
- phdr = mtod(mb, struct sctp_paramhdr *);
- /*
- * Error causes are just param's and this one has
- * two back to back phdr, one with the error type
- * and size, the other with the streamid and a rsvd
- */
- SCTP_BUF_LEN(mb) = (sizeof(struct sctp_paramhdr) * 2);
- phdr->param_type = htons(SCTP_CAUSE_INVALID_STREAM);
- phdr->param_length =
- htons(sizeof(struct sctp_paramhdr) * 2);
- phdr++;
- /* We insert the stream in the type field */
- phdr->param_type = ch->dp.stream_id;
- /* And set the length to 0 for the rsvd field */
- phdr->param_length = 0;
- sctp_queue_op_err(stcb, mb);
- }
- SCTP_STAT_INCR(sctps_badsid);
- SCTP_TCB_LOCK_ASSERT(stcb);
- SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
- if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
- asoc->highest_tsn_inside_nr_map = tsn;
- }
- if (tsn == (asoc->cumulative_tsn + 1)) {
- /* Update cum-ack */
- asoc->cumulative_tsn = tsn;
}
- return (0);
}
- /*
- * Before we continue lets validate that we are not being fooled by
- * an evil attacker. We can only have 4k chunks based on our TSN
- * spread allowed by the mapping array 512 * 8 bits, so there is no
- * way our stream sequence numbers could have wrapped. We of course
- * only validate the FIRST fragment so the bit must be set.
- */
- strmseq = ntohs(ch->dp.stream_sequence);
#ifdef SCTP_ASOCLOG_OF_TSNS
SCTP_TCB_LOCK_ASSERT(stcb);
if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) {
@@ -1471,8 +2001,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
asoc->tsn_in_wrapped = 1;
}
asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn;
- asoc->in_tsnlog[asoc->tsn_in_at].strm = strmno;
- asoc->in_tsnlog[asoc->tsn_in_at].seq = strmseq;
+ asoc->in_tsnlog[asoc->tsn_in_at].strm = sid;
+ asoc->in_tsnlog[asoc->tsn_in_at].seq = mid;
asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length;
asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags;
asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb;
@@ -1480,33 +2010,55 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1;
asoc->tsn_in_at++;
#endif
- if ((chunk_flags & SCTP_DATA_FIRST_FRAG) &&
+ /*
+ * Before we continue lets validate that we are not being fooled by
+ * an evil attacker. We can only have Nk chunks based on our TSN
+ * spread allowed by the mapping array N * 8 bits, so there is no
+ * way our stream sequence numbers could have wrapped. We of course
+ * only validate the FIRST fragment so the bit must be set.
+ */
+ if ((chk_flags & SCTP_DATA_FIRST_FRAG) &&
(TAILQ_EMPTY(&asoc->resetHead)) &&
- (chunk_flags & SCTP_DATA_UNORDERED) == 0 &&
- SCTP_SSN_GE(asoc->strmin[strmno].last_sequence_delivered, strmseq)) {
+ (chk_flags & SCTP_DATA_UNORDERED) == 0 &&
+ SCTP_MID_GE(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered, mid)) {
/* The incoming sseq is behind where we last delivered? */
- SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ:%d delivered:%d from peer, Abort!\n",
- strmseq, asoc->strmin[strmno].last_sequence_delivered);
-
- snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- asoc->strmin[strmno].last_sequence_delivered,
- tsn, strmno, strmseq);
+ SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n",
+ mid, asoc->strmin[sid].last_mid_delivered);
+
+ if (asoc->idata_supported) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x",
+ asoc->strmin[sid].last_mid_delivered,
+ tsn,
+ sid,
+ mid);
+ } else {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
+ (uint16_t)asoc->strmin[sid].last_mid_delivered,
+ tsn,
+ sid,
+ (uint16_t)mid);
+ }
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_14;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
}
- /************************************
- * From here down we may find ch-> invalid
- * so its a good idea NOT to use it.
- *************************************/
-
- the_len = (chk_length - sizeof(struct sctp_data_chunk));
+ if (chk_type == SCTP_IDATA) {
+ the_len = (chk_length - sizeof(struct sctp_idata_chunk));
+ } else {
+ the_len = (chk_length - sizeof(struct sctp_data_chunk));
+ }
if (last_chunk == 0) {
- dmbuf = SCTP_M_COPYM(*m,
- (offset + sizeof(struct sctp_data_chunk)),
- the_len, M_NOWAIT);
+ if (chk_type == SCTP_IDATA) {
+ dmbuf = SCTP_M_COPYM(*m,
+ (offset + sizeof(struct sctp_idata_chunk)),
+ the_len, M_NOWAIT);
+ } else {
+ dmbuf = SCTP_M_COPYM(*m,
+ (offset + sizeof(struct sctp_data_chunk)),
+ the_len, M_NOWAIT);
+ }
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY);
@@ -1517,7 +2069,11 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
int l_len;
dmbuf = *m;
/* lop off the top part */
- m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk)));
+ if (chk_type == SCTP_IDATA) {
+ m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk)));
+ } else {
+ m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk)));
+ }
if (SCTP_BUF_NEXT(dmbuf) == NULL) {
l_len = SCTP_BUF_LEN(dmbuf);
} else {
@@ -1540,12 +2096,48 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
SCTP_STAT_INCR(sctps_nomem);
return (0);
}
- if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
- asoc->fragmented_delivery_inprogress == 0 &&
+ /*
+ * Now no matter what, we need a control, get one
+ * if we don't have one (we may have gotten it
+ * above when we found the message was fragmented
+ */
+ if (control == NULL) {
+ sctp_alloc_a_readq(stcb, control);
+ sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
+ ppid,
+ sid,
+ chk_flags,
+ NULL, fsn, mid);
+ if (control == NULL) {
+ SCTP_STAT_INCR(sctps_nomem);
+ return (0);
+ }
+ if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ struct mbuf *mm;
+
+ control->data = dmbuf;
+ control->tail_mbuf = NULL;
+ for (mm = control->data; mm; mm = mm->m_next) {
+ control->length += SCTP_BUF_LEN(mm);
+ if (SCTP_BUF_NEXT(mm) == NULL) {
+ control->tail_mbuf = mm;
+ }
+ }
+ control->end_added = 1;
+ control->last_frag_seen = 1;
+ control->first_frag_seen = 1;
+ control->fsn_included = fsn;
+ control->top_fsn = fsn;
+ }
+ created_control = 1;
+ }
+ SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d MID: %u control: %p\n",
+ chk_flags, ordered, mid, control);
+ if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
TAILQ_EMPTY(&asoc->resetHead) &&
((ordered == 0) ||
- ((uint16_t)(asoc->strmin[strmno].last_sequence_delivered + 1) == strmseq &&
- TAILQ_EMPTY(&asoc->strmin[strmno].inqueue)))) {
+ (SCTP_MID_EQ(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered + 1, mid) &&
+ TAILQ_EMPTY(&asoc->strmin[sid].inqueue)))) {
/* Candidate for express delivery */
/*
* Its not fragmented, No PD-API is up, Nothing in the
@@ -1554,108 +2146,32 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
* And there is room for it in the socket buffer. Lets just
* stuff it up the buffer....
*/
-
- /* It would be nice to avoid this copy if we could :< */
- sctp_alloc_a_readq(stcb, control);
- sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
- protocol_id,
- strmno, strmseq,
- chunk_flags,
- dmbuf);
- if (control == NULL) {
- goto failed_express_del;
- }
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
asoc->highest_tsn_inside_nr_map = tsn;
}
+ SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (MID: %u)\n",
+ control, mid);
+
sctp_add_to_readq(stcb->sctp_ep, stcb,
control, &stcb->sctp_socket->so_rcv,
1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
- if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
+ if ((chk_flags & SCTP_DATA_UNORDERED) == 0) {
/* for ordered, bump what we delivered */
- asoc->strmin[strmno].last_sequence_delivered++;
+ asoc->strmin[sid].last_mid_delivered++;
}
SCTP_STAT_INCR(sctps_recvexpress);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
- sctp_log_strm_del_alt(stcb, tsn, strmseq, strmno,
+ sctp_log_strm_del_alt(stcb, tsn, mid, sid,
SCTP_STR_LOG_FROM_EXPRS_DEL);
}
control = NULL;
-
goto finish_express_del;
}
-failed_express_del:
- /* If we reach here this is a new chunk */
- chk = NULL;
- control = NULL;
- /* Express for fragmented delivery? */
- if ((asoc->fragmented_delivery_inprogress) &&
- (stcb->asoc.control_pdapi) &&
- (asoc->str_of_pdapi == strmno) &&
- (asoc->ssn_of_pdapi == strmseq)
- ) {
- control = stcb->asoc.control_pdapi;
- if ((chunk_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) {
- /* Can't be another first? */
- goto failed_pdapi_express_del;
- }
- if (tsn == (control->sinfo_tsn + 1)) {
- /* Yep, we can add it on */
- int end = 0;
-
- if (chunk_flags & SCTP_DATA_LAST_FRAG) {
- end = 1;
- }
- if (sctp_append_to_readq(stcb->sctp_ep, stcb, control, dmbuf, end,
- tsn,
- &stcb->sctp_socket->so_rcv)) {
- SCTP_PRINTF("Append fails end:%d\n", end);
- goto failed_pdapi_express_del;
- }
-
- SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
- if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
- asoc->highest_tsn_inside_nr_map = tsn;
- }
- SCTP_STAT_INCR(sctps_recvexpressm);
- asoc->tsn_last_delivered = tsn;
- asoc->fragment_flags = chunk_flags;
- asoc->tsn_of_pdapi_last_delivered = tsn;
- asoc->last_flags_delivered = chunk_flags;
- asoc->last_strm_seq_delivered = strmseq;
- asoc->last_strm_no_delivered = strmno;
- if (end) {
- /* clean up the flags and such */
- asoc->fragmented_delivery_inprogress = 0;
- if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
- asoc->strmin[strmno].last_sequence_delivered++;
- }
- stcb->asoc.control_pdapi = NULL;
- if (TAILQ_EMPTY(&asoc->reasmqueue) == 0) {
- /* There could be another message ready */
- need_reasm_check = 1;
- }
- }
- control = NULL;
- goto finish_express_del;
- }
- }
- failed_pdapi_express_del:
- control = NULL;
- if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
- SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
- if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
- asoc->highest_tsn_inside_nr_map = tsn;
- }
- } else {
- SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
- if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) {
- asoc->highest_tsn_inside_map = tsn;
- }
- }
- if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
+
+ /* Now will we need a chunk too? */
+ if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
/* No memory so we drop the chunk */
@@ -1666,203 +2182,120 @@ failed_express_del:
}
return (0);
}
- chk->rec.data.TSN_seq = tsn;
+ chk->rec.data.tsn = tsn;
chk->no_fr_allowed = 0;
- chk->rec.data.stream_seq = strmseq;
- chk->rec.data.stream_number = strmno;
- chk->rec.data.payloadtype = protocol_id;
+ chk->rec.data.fsn = fsn;
+ chk->rec.data.mid = mid;
+ chk->rec.data.sid = sid;
+ chk->rec.data.ppid = ppid;
chk->rec.data.context = stcb->asoc.context;
chk->rec.data.doing_fast_retransmit = 0;
- chk->rec.data.rcv_flags = chunk_flags;
+ chk->rec.data.rcv_flags = chk_flags;
chk->asoc = asoc;
chk->send_size = the_len;
chk->whoTo = net;
+ SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (MID: %u)\n",
+ chk,
+ control, mid);
atomic_add_int(&net->ref_count, 1);
chk->data = dmbuf;
+ }
+ /* Set the appropriate TSN mark */
+ if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
+ SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
+ if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
+ asoc->highest_tsn_inside_nr_map = tsn;
+ }
} else {
- sctp_alloc_a_readq(stcb, control);
- sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
- protocol_id,
- strmno, strmseq,
- chunk_flags,
- dmbuf);
- if (control == NULL) {
- /* No memory so we drop the chunk */
- SCTP_STAT_INCR(sctps_nomem);
- if (last_chunk == 0) {
- /* we copied it, free the copy */
- sctp_m_freem(dmbuf);
- }
- return (0);
+ SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
+ if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) {
+ asoc->highest_tsn_inside_map = tsn;
}
- control->length = the_len;
}
-
- /* Mark it as received */
- /* Now queue it where it belongs */
- if (control != NULL) {
- /* First a sanity check */
- if (asoc->fragmented_delivery_inprogress) {
+ /* Now is it complete (i.e. not fragmented)? */
+ if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ /*
+ * Special check for when streams are resetting. We
+ * could be more smart about this and check the
+ * actual stream to see if it is not being reset..
+ * that way we would not create a HOLB when amongst
+ * streams being reset and those not being reset.
+ *
+ */
+ if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
+ SCTP_TSN_GT(tsn, liste->tsn)) {
/*
- * Ok, we have a fragmented delivery in progress if
- * this chunk is next to deliver OR belongs in our
- * view to the reassembly, the peer is evil or
- * broken.
+ * yep its past where we need to reset... go
+ * ahead and queue it.
*/
- uint32_t estimate_tsn;
-
- estimate_tsn = asoc->tsn_last_delivered + 1;
- if (TAILQ_EMPTY(&asoc->reasmqueue) &&
- (estimate_tsn == control->sinfo_tsn)) {
- /* Evil/Broke peer */
- sctp_m_freem(control->data);
- control->data = NULL;
- if (control->whoFrom) {
- sctp_free_remote_addr(control->whoFrom);
- control->whoFrom = NULL;
- }
- sctp_free_a_readq(stcb, control);
- snprintf(msg, sizeof(msg), "Reas. queue emtpy, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- tsn, strmno, strmseq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_15;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- if (last_chunk) {
- *m = NULL;
- }
- return (0);
+ if (TAILQ_EMPTY(&asoc->pending_reply_queue)) {
+ /* first one on */
+ TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
} else {
- if (sctp_does_tsn_belong_to_reasm(asoc, control->sinfo_tsn)) {
- sctp_m_freem(control->data);
- control->data = NULL;
- if (control->whoFrom) {
- sctp_free_remote_addr(control->whoFrom);
- control->whoFrom = NULL;
- }
- sctp_free_a_readq(stcb, control);
- snprintf(msg, sizeof(msg), "PD ongoing, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- tsn, strmno, strmseq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_16;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- if (last_chunk) {
- *m = NULL;
+ struct sctp_queued_to_read *lcontrol, *nlcontrol;
+ unsigned char inserted = 0;
+ TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) {
+ if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) {
+ continue;
+ } else {
+ /* found it */
+ TAILQ_INSERT_BEFORE(lcontrol, control, next);
+ inserted = 1;
+ break;
}
- return (0);
}
- }
- } else {
- /* No PDAPI running */
- if (!TAILQ_EMPTY(&asoc->reasmqueue)) {
- /*
- * Reassembly queue is NOT empty validate
- * that this tsn does not need to be in
- * reasembly queue. If it does then our peer
- * is broken or evil.
- */
- if (sctp_does_tsn_belong_to_reasm(asoc, control->sinfo_tsn)) {
- sctp_m_freem(control->data);
- control->data = NULL;
- if (control->whoFrom) {
- sctp_free_remote_addr(control->whoFrom);
- control->whoFrom = NULL;
- }
- sctp_free_a_readq(stcb, control);
- snprintf(msg, sizeof(msg), "No PD ongoing, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
- tsn, strmno, strmseq);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_17;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *abort_flag = 1;
- if (last_chunk) {
- *m = NULL;
- }
- return (0);
+ if (inserted == 0) {
+ /*
+ * must be put at end, use
+ * prevP (all setup from
+ * loop) to setup nextP.
+ */
+ TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
}
}
+ goto finish_express_del;
}
- /* ok, if we reach here we have passed the sanity checks */
- if (chunk_flags & SCTP_DATA_UNORDERED) {
+ if (chk_flags & SCTP_DATA_UNORDERED) {
/* queue directly into socket buffer */
+ SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p MID: %u\n",
+ control, mid);
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
- } else {
- /*
- * Special check for when streams are resetting. We
- * could be more smart about this and check the
- * actual stream to see if it is not being reset..
- * that way we would not create a HOLB when amongst
- * streams being reset and those not being reset.
- *
- * We take complete messages that have a stream reset
- * intervening (aka the TSN is after where our
- * cum-ack needs to be) off and put them on a
- * pending_reply_queue. The reassembly ones we do
- * not have to worry about since they are all sorted
- * and proceessed by TSN order. It is only the
- * singletons I must worry about.
- */
- if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
- SCTP_TSN_GT(tsn, liste->tsn)) {
- /*
- * yep its past where we need to reset... go
- * ahead and queue it.
- */
- if (TAILQ_EMPTY(&asoc->pending_reply_queue)) {
- /* first one on */
- TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
- } else {
- struct sctp_queued_to_read *ctlOn, *nctlOn;
- unsigned char inserted = 0;
+ &stcb->sctp_socket->so_rcv, 1,
+ SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
- TAILQ_FOREACH_SAFE(ctlOn, &asoc->pending_reply_queue, next, nctlOn) {
- if (SCTP_TSN_GT(control->sinfo_tsn, ctlOn->sinfo_tsn)) {
- continue;
- } else {
- /* found it */
- TAILQ_INSERT_BEFORE(ctlOn, control, next);
- inserted = 1;
- break;
- }
- }
- if (inserted == 0) {
- /*
- * must be put at end, use
- * prevP (all setup from
- * loop) to setup nextP.
- */
- TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
- }
- }
- } else {
- sctp_queue_data_to_stream(stcb, asoc, control, abort_flag);
- if (*abort_flag) {
- if (last_chunk) {
- *m = NULL;
- }
- return (0);
+ } else {
+ SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering MID: %u\n", control,
+ mid);
+ sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
+ if (*abort_flag) {
+ if (last_chunk) {
+ *m = NULL;
}
+ return (0);
}
}
- } else {
- /* Into the re-assembly queue */
- sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag);
- if (*abort_flag) {
- /*
- * the assoc is now gone and chk was put onto the
- * reasm queue, which has all been freed.
- */
- if (last_chunk) {
- *m = NULL;
- }
- return (0);
+ goto finish_express_del;
+ }
+ /* If we reach here its a reassembly */
+ need_reasm_check = 1;
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Queue data to stream for reasm control: %p MID: %u\n",
+ control, mid);
+ sctp_queue_data_for_reasm(stcb, asoc, control, chk, created_control, abort_flag, tsn);
+ if (*abort_flag) {
+ /*
+ * the assoc is now gone and chk was put onto the
+ * reasm queue, which has all been freed.
+ */
+ if (last_chunk) {
+ *m = NULL;
}
+ return (0);
}
finish_express_del:
+ /* Here we tidy up things */
if (tsn == (asoc->cumulative_tsn + 1)) {
/* Update cum-ack */
asoc->cumulative_tsn = tsn;
@@ -1878,12 +2311,16 @@ finish_express_del:
SCTP_STAT_INCR(sctps_recvdata);
/* Set it present please */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
- sctp_log_strm_del_alt(stcb, tsn, strmseq, strmno, SCTP_STR_LOG_FROM_MARK_TSN);
+ sctp_log_strm_del_alt(stcb, tsn, mid, sid, SCTP_STR_LOG_FROM_MARK_TSN);
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
}
+ if (need_reasm_check) {
+ (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[sid], SCTP_READ_LOCK_NOT_HELD);
+ need_reasm_check = 0;
+ }
/* check the special flag for stream resets */
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) {
@@ -1893,55 +2330,53 @@ finish_express_del:
* pending_reply space 3: distribute any chunks in
* pending_reply_queue.
*/
- struct sctp_queued_to_read *ctl, *nctl;
-
sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams);
TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
+ sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED);
SCTP_FREE(liste, SCTP_M_STRESET);
/*sa_ignore FREED_MEMORY*/
liste = TAILQ_FIRST(&asoc->resetHead);
if (TAILQ_EMPTY(&asoc->resetHead)) {
/* All can be removed */
- TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
- TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
- sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag);
+ TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
+ TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
+ strm = &asoc->strmin[control->sinfo_stream];
+ sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
if (*abort_flag) {
return (0);
}
+ if (need_reasm_check) {
+ (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
+ need_reasm_check = 0;
+ }
}
} else {
- TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
- if (SCTP_TSN_GT(ctl->sinfo_tsn, liste->tsn)) {
+ TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
+ if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) {
break;
}
/*
- * if ctl->sinfo_tsn is <= liste->tsn we can
+ * if control->sinfo_tsn is <= liste->tsn we can
* process it which is the NOT of
- * ctl->sinfo_tsn > liste->tsn
+ * control->sinfo_tsn > liste->tsn
*/
- TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
- sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag);
+ TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
+ strm = &asoc->strmin[control->sinfo_stream];
+ sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
if (*abort_flag) {
return (0);
}
+ if (need_reasm_check) {
+ (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
+ need_reasm_check = 0;
+ }
}
}
- /*
- * Now service re-assembly to pick up anything that has been
- * held on reassembly queue?
- */
- sctp_deliver_reasm_check(stcb, asoc);
- need_reasm_check = 0;
- }
-
- if (need_reasm_check) {
- /* Another one waits ? */
- sctp_deliver_reasm_check(stcb, asoc);
}
return (1);
}
-int8_t sctp_map_lookup_tab[256] = {
+static const int8_t sctp_map_lookup_tab[256] = {
0, 1, 0, 2, 0, 1, 0, 3,
0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3,
@@ -1976,7 +2411,6 @@ int8_t sctp_map_lookup_tab[256] = {
0, 1, 0, 2, 0, 1, 0, 8
};
-
void
sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
{
@@ -1985,7 +2419,7 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
* 1) Did we move the cum-ack point?
*
* When you first glance at this you might think
- * that all entries that make up the postion
+ * that all entries that make up the position
* of the cum-ack would be in the nr-mapping array
* only.. i.e. things up to the cum-ack are always
* deliverable. Thats true with one exception, when
@@ -2083,7 +2517,7 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
#ifdef INVARIANTS
panic("impossible slide");
#else
- SCTP_PRINTF("impossible slide lgap:%x slide_end:%x slide_from:%x? at:%d\n",
+ SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n",
lgap, slide_end, slide_from, at);
return;
#endif
@@ -2092,7 +2526,7 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
#ifdef INVARIANTS
panic("would overrun buffer");
#else
- SCTP_PRINTF("Gak, would have overrun map end:%d slide_end:%d\n",
+ SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n",
asoc->mapping_array_size, slide_end);
slide_end = asoc->mapping_array_size;
#endif
@@ -2112,7 +2546,6 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
* we will be able to slide it forward. Really I
* don't think this should happen :-0
*/
-
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
sctp_log_map((uint32_t) distance, (uint32_t) slide_from,
(uint32_t) asoc->mapping_array_size,
@@ -2124,7 +2557,6 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
for (ii = 0; ii < distance; ii++) {
asoc->mapping_array[ii] = asoc->mapping_array[slide_from + ii];
asoc->nr_mapping_array[ii] = asoc->nr_mapping_array[slide_from + ii];
-
}
for (ii = distance; ii < asoc->mapping_array_size; ii++) {
asoc->mapping_array[ii] = 0;
@@ -2151,19 +2583,23 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
{
struct sctp_association *asoc;
uint32_t highest_tsn;
+ int is_a_gap;
+ sctp_slide_mapping_arrays(stcb);
asoc = &stcb->asoc;
if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
highest_tsn = asoc->highest_tsn_inside_nr_map;
} else {
highest_tsn = asoc->highest_tsn_inside_map;
}
+ /* Is there a gap now? */
+ is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
/*
* Now we need to see if we need to queue a sack or just start the
* timer (if allowed).
*/
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
/*
* Ok special case, in SHUTDOWN-SENT case. here we
* maker sure SACK timer is off and instead send a
@@ -2171,17 +2607,15 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
*/
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA+SCTP_LOC_18);
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_19);
}
sctp_send_shutdown(stcb,
- ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
- sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
+ ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
+ if (is_a_gap) {
+ sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
+ }
} else {
- int is_a_gap;
-
- /* is there a gap now ? */
- is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
-
/*
* CMT DAC algorithm: increase number of packets
* received since last ack
@@ -2194,20 +2628,16 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
(stcb->asoc.numduptsns) || /* we have dup's */
(is_a_gap) || /* is still a gap */
(stcb->asoc.delayed_ack == 0) || /* Delayed sack disabled */
- (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq) /* hit limit of pkts */
- ) {
-
+ (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq)) { /* hit limit of pkts */
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) &&
(stcb->asoc.send_sack == 0) &&
(stcb->asoc.numduptsns == 0) &&
(stcb->asoc.delayed_ack) &&
(!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) {
-
/*
* CMT DAC algorithm: With CMT,
* delay acks even in the face of
-
* reordering. Therefore, if acks
* that do not have to be sent
* because of the above reasons,
@@ -2225,7 +2655,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
* first packet OR there are gaps or
* duplicates.
*/
- (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
}
} else {
@@ -2237,85 +2668,20 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
}
}
-void
-sctp_service_queues(struct sctp_tcb *stcb, struct sctp_association *asoc)
-{
- struct sctp_tmit_chunk *chk;
- uint32_t tsize, pd_point;
- uint16_t nxt_todel;
-
- if (asoc->fragmented_delivery_inprogress) {
- sctp_service_reassembly(stcb, asoc);
- }
- /* Can we proceed further, i.e. the PD-API is complete */
- if (asoc->fragmented_delivery_inprogress) {
- /* no */
- return;
- }
- /*
- * Now is there some other chunk I can deliver from the reassembly
- * queue.
- */
- doit_again:
- chk = TAILQ_FIRST(&asoc->reasmqueue);
- if (chk == NULL) {
- asoc->size_on_reasm_queue = 0;
- asoc->cnt_on_reasm_queue = 0;
- return;
- }
- nxt_todel = asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1;
- if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) &&
- ((nxt_todel == chk->rec.data.stream_seq) ||
- (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) {
- /*
- * Yep the first one is here. We setup to start reception,
- * by backing down the TSN just in case we can't deliver.
- */
-
- /*
- * Before we start though either all of the message should
- * be here or the socket buffer max or nothing on the
- * delivery queue and something can be delivered.
- */
- if (stcb->sctp_socket) {
- pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
- stcb->sctp_ep->partial_delivery_point);
- } else {
- pd_point = stcb->sctp_ep->partial_delivery_point;
- }
- if (sctp_is_all_msg_on_reasm(asoc, &tsize) || (tsize >= pd_point)) {
- asoc->fragmented_delivery_inprogress = 1;
- asoc->tsn_last_delivered = chk->rec.data.TSN_seq - 1;
- asoc->str_of_pdapi = chk->rec.data.stream_number;
- asoc->ssn_of_pdapi = chk->rec.data.stream_seq;
- asoc->pdapi_ppid = chk->rec.data.payloadtype;
- asoc->fragment_flags = chk->rec.data.rcv_flags;
- sctp_service_reassembly(stcb, asoc);
- if (asoc->fragmented_delivery_inprogress == 0) {
- goto doit_again;
- }
- }
- }
-}
-
int
sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
- struct sockaddr *src, struct sockaddr *dst,
- struct sctphdr *sh, struct sctp_inpcb *inp,
- struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t *high_tsn,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
-#endif
- uint32_t vrf_id, uint16_t port)
+ struct sctp_inpcb *inp, struct sctp_tcb *stcb,
+ struct sctp_nets *net, uint32_t *high_tsn)
{
- struct sctp_data_chunk *ch, chunk_buf;
+ struct sctp_chunkhdr *ch, chunk_buf;
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);
@@ -2336,14 +2702,12 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
*/
asoc->last_data_chunk_from = net;
-#ifndef __Panda__
/*-
* Now before we proceed we must figure out if this is a wasted
* cluster... i.e. it is a small packet sent in and yet the driver
* underneath allocated a full cluster for it. If so we must copy it
* to a smaller mbuf and free up the cluster mbuf. This will help
- * with cluster starvation. Note for __Panda__ we don't do this
- * since it has clusters all the way down to 64 bytes.
+ * with cluster starvation.
*/
if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) {
/* we only handle mbufs that are singletons.. not chains */
@@ -2358,17 +2722,17 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
/* copy the length and free up the old */
SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm));
sctp_m_freem(*mm);
- /* sucess, back copy */
+ /* success, back copy */
*mm = m;
} else {
/* We are in trouble in the mbuf world .. yikes */
m = *mm;
}
}
-#endif
/* get pointer to the first chunk header */
- ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf);
+ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
+ sizeof(struct sctp_chunkhdr),
+ (uint8_t *)&chunk_buf);
if (ch == NULL) {
return (1);
}
@@ -2380,14 +2744,44 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
asoc->data_pkts_seen++;
while (stop_proc == 0) {
/* validate chunk length */
- chk_length = ntohs(ch->ch.chunk_length);
+ chk_length = ntohs(ch->chunk_length);
if (length - *offset < chk_length) {
/* all done, mutulated chunk */
stop_proc = 1;
continue;
}
- if (ch->ch.chunk_type == SCTP_DATA) {
- if ((size_t)chk_length < sizeof(struct sctp_data_chunk)) {
+ if ((asoc->idata_supported == 1) &&
+ (ch->chunk_type == SCTP_DATA)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated");
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21;
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return (2);
+ }
+ if ((asoc->idata_supported == 0) &&
+ (ch->chunk_type == SCTP_IDATA)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated");
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22;
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return (2);
+ }
+ if ((ch->chunk_type == SCTP_DATA) ||
+ (ch->chunk_type == SCTP_IDATA)) {
+ uint16_t clen;
+
+ if (ch->chunk_type == SCTP_DATA) {
+ clen = sizeof(struct sctp_data_chunk);
+ } else {
+ clen = sizeof(struct sctp_idata_chunk);
+ }
+ if (chk_length < clen) {
/*
* Need to send an abort since we had a
* invalid data chunk.
@@ -2395,33 +2789,12 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
struct mbuf *op_err;
char msg[SCTP_DIAG_INFO_LEN];
- snprintf(msg, sizeof(msg), "DATA chunk of length %d",
- chk_length);
+ SCTP_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_19;
- sctp_abort_association(inp, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
- return (2);
- }
- if ((size_t)chk_length == sizeof(struct sctp_data_chunk)) {
- /*
- * Need to send an abort since we had an
- * empty data chunk.
- */
- struct mbuf *op_err;
-
- op_err = sctp_generate_no_user_data_cause(ch->dp.tsn);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_19;
- sctp_abort_association(inp, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23;
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (2);
}
#ifdef SCTP_AUDITING_ENABLED
@@ -2432,9 +2805,9 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
} else {
last_chunk = 0;
}
- if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, ch,
+ if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset,
chk_length, net, high_tsn, &abort_flag, &break_flag,
- last_chunk)) {
+ last_chunk, ch->chunk_type)) {
num_chunks++;
}
if (abort_flag)
@@ -2450,7 +2823,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
}
} else {
/* not a data chunk in the data region */
- switch (ch->ch.chunk_type) {
+ switch (ch->chunk_type) {
case SCTP_INITIATION:
case SCTP_INITIATION_ACK:
case SCTP_SELECTIVE_ACK:
@@ -2472,6 +2845,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
case SCTP_STREAM_RESET:
case SCTP_FORWARD_CUM_TSN:
case SCTP_ASCONF:
+ {
/*
* Now, what do we do with KNOWN chunks that
* are NOT in the right place?
@@ -2481,57 +2855,55 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
* switch out and do either an ABORT() or
* possibly process them.
*/
- if (SCTP_BASE_SYSCTL(sctp_strict_data_order)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
+ SCTP_SNPRINTF(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x",
+ ch->chunk_type);
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return (2);
+ }
+ default:
+ /*
+ * 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];
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "");
- sctp_abort_association(inp, stcb,
- m, iphlen,
- src, dst,
- sh, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
+ SCTP_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_24;
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (2);
}
- break;
- default:
- /* unknown chunk type, use bit rules */
- if (ch->ch.chunk_type & 0x40) {
+ if (ch->chunk_type & 0x40) {
/* Add a error report to the queue */
- struct mbuf *merr;
- struct sctp_paramhdr *phd;
-
- merr = sctp_get_mbuf_for_msg(sizeof(*phd), 0, M_NOWAIT, 1, MT_DATA);
- if (merr) {
- phd = mtod(merr, struct sctp_paramhdr *);
- /*
- * We cheat and use param
- * type since we did not
- * bother to define a error
- * cause struct. They are
- * the same basic format
- * with different names.
- */
- phd->param_type =
- htons(SCTP_CAUSE_UNRECOG_CHUNK);
- phd->param_length =
- htons(chk_length + sizeof(*phd));
- SCTP_BUF_LEN(merr) = sizeof(*phd);
- SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
- if (SCTP_BUF_NEXT(merr)) {
- if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(merr), SCTP_SIZE32(chk_length) - chk_length, NULL) == NULL) {
- sctp_m_freem(merr);
- } else {
- sctp_queue_op_err(stcb, merr);
- }
+ struct mbuf *op_err;
+ struct sctp_gen_error_cause *cause;
+
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
+ 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
+ cause = mtod(op_err, struct sctp_gen_error_cause *);
+ cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
+ cause->length = htons((uint16_t)(chk_length + sizeof(struct sctp_gen_error_cause)));
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
+ SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
+ if (SCTP_BUF_NEXT(op_err) != NULL) {
+ sctp_queue_op_err(stcb, op_err);
} else {
- sctp_m_freem(merr);
+ sctp_m_freem(op_err);
}
}
}
- if ((ch->ch.chunk_type & 0x80) == 0) {
+ if ((ch->chunk_type & 0x80) == 0) {
/* discard the rest of this packet */
stop_proc = 1;
} /* else skip this bad chunk and
@@ -2545,8 +2917,9 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
stop_proc = 1;
continue;
}
- ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf);
+ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
+ sizeof(struct sctp_chunkhdr),
+ (uint8_t *)&chunk_buf);
if (ch == NULL) {
*offset = length;
stop_proc = 1;
@@ -2576,10 +2949,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd);
}
/* now service all of the reassm queue if needed */
- if (!(TAILQ_EMPTY(&asoc->reasmqueue)))
- sctp_service_queues(stcb, asoc);
-
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
/* Assure that we ack right away */
stcb->asoc.send_sack = 1;
}
@@ -2622,16 +2992,16 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
(tp1->whoTo->find_pseudo_cumack == 1) &&
(tp1->snd_count == 1)) {
- tp1->whoTo->pseudo_cumack = tp1->rec.data.TSN_seq;
+ tp1->whoTo->pseudo_cumack = tp1->rec.data.tsn;
tp1->whoTo->find_pseudo_cumack = 0;
}
if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
(tp1->whoTo->find_rtx_pseudo_cumack == 1) &&
(tp1->snd_count > 1)) {
- tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.TSN_seq;
+ tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.tsn;
tp1->whoTo->find_rtx_pseudo_cumack = 0;
}
- if (tp1->rec.data.TSN_seq == theTSN) {
+ if (tp1->rec.data.tsn == theTSN) {
if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
/*-
* must be held until
@@ -2645,9 +3015,9 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
* via previous Gap Ack Blocks...
* i.e. ACKED or RESEND.
*/
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
+ if (SCTP_TSN_GT(tp1->rec.data.tsn,
*biggest_newly_acked_tsn)) {
- *biggest_newly_acked_tsn = tp1->rec.data.TSN_seq;
+ *biggest_newly_acked_tsn = tp1->rec.data.tsn;
}
/*-
* CMT: SFR algo (and HTNA) - set
@@ -2659,10 +3029,10 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
if (tp1->rec.data.chunk_was_revoked == 0)
tp1->whoTo->saw_newack = 1;
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
+ if (SCTP_TSN_GT(tp1->rec.data.tsn,
tp1->whoTo->this_sack_highest_newack)) {
tp1->whoTo->this_sack_highest_newack =
- tp1->rec.data.TSN_seq;
+ tp1->rec.data.tsn;
}
/*-
* CMT DAC algo: also update
@@ -2672,12 +3042,12 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
sctp_log_sack(*this_sack_lowest_newack,
last_tsn,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
0,
0,
SCTP_LOG_TSN_ACKED);
}
- *this_sack_lowest_newack = tp1->rec.data.TSN_seq;
+ *this_sack_lowest_newack = tp1->rec.data.tsn;
}
/*-
* CMT: CUCv2 algorithm. If (rtx-)pseudo-cumack for corresp
@@ -2687,16 +3057,16 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
* Separate pseudo_cumack trackers for first transmissions and
* retransmissions.
*/
- if (tp1->rec.data.TSN_seq == tp1->whoTo->pseudo_cumack) {
+ if (tp1->rec.data.tsn == tp1->whoTo->pseudo_cumack) {
if (tp1->rec.data.chunk_was_revoked == 0) {
tp1->whoTo->new_pseudo_cumack = 1;
}
tp1->whoTo->find_pseudo_cumack = 1;
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
+ sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
}
- if (tp1->rec.data.TSN_seq == tp1->whoTo->rtx_pseudo_cumack) {
+ if (tp1->rec.data.tsn == tp1->whoTo->rtx_pseudo_cumack) {
if (tp1->rec.data.chunk_was_revoked == 0) {
tp1->whoTo->new_pseudo_cumack = 1;
}
@@ -2705,7 +3075,7 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
sctp_log_sack(*biggest_newly_acked_tsn,
last_tsn,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
frag_strt,
frag_end,
SCTP_LOG_TSN_ACKED);
@@ -2714,8 +3084,8 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
sctp_flight_size_decrease(tp1);
if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
@@ -2727,7 +3097,7 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
tp1->whoTo->net_ack += tp1->send_size;
if (tp1->snd_count < 2) {
/*-
- * True non-retransmited chunk
+ * True non-retransmitted chunk
*/
tp1->whoTo->net_ack2 += tp1->send_size;
@@ -2735,14 +3105,12 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
* update RTO too ?
*/
if (tp1->do_rtt) {
- if (*rto_ok) {
- tp1->whoTo->RTO =
- sctp_calculate_rto(stcb,
- &stcb->asoc,
- tp1->whoTo,
- &tp1->sent_rcv_time,
- sctp_align_safe_nocopy,
- SCTP_RTT_FROM_DATA);
+ if (*rto_ok &&
+ sctp_calculate_rto(stcb,
+ &stcb->asoc,
+ tp1->whoTo,
+ &tp1->sent_rcv_time,
+ SCTP_RTT_FROM_DATA)) {
*rto_ok = 0;
}
if (tp1->whoTo->rto_needed == 0) {
@@ -2751,13 +3119,12 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
tp1->do_rtt = 0;
}
}
-
}
if (tp1->sent <= SCTP_DATAGRAM_RESEND) {
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
+ if (SCTP_TSN_GT(tp1->rec.data.tsn,
stcb->asoc.this_sack_highest_gap)) {
stcb->asoc.this_sack_highest_gap =
- tp1->rec.data.TSN_seq;
+ tp1->rec.data.tsn;
}
if (tp1->sent == SCTP_DATAGRAM_RESEND) {
sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt);
@@ -2783,13 +3150,18 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
/* NR Sack code here */
if (nr_sacking &&
(tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
- if (stcb->asoc.strmout[tp1->rec.data.stream_number].chunks_on_queues > 0) {
- stcb->asoc.strmout[tp1->rec.data.stream_number].chunks_on_queues--;
+ if (stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
+ stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
#endif
}
+ if ((stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
+ (stcb->asoc.strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
+ TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.sid].outqueue)) {
+ stcb->asoc.trigger_reset = 1;
+ }
tp1->sent = SCTP_DATAGRAM_NR_ACKED;
if (tp1->data) {
/* sa_ignore NO_NULL_CHK */
@@ -2801,8 +3173,8 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
}
}
break;
- } /* if (tp1->TSN_seq == theTSN) */
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, theTSN)) {
+ } /* if (tp1->tsn == theTSN) */
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, theTSN)) {
break;
}
tp1 = TAILQ_NEXT(tp1, sctp_next);
@@ -2821,7 +3193,6 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
return (wake_him); /* Return value only used for nr-sack */
}
-
static int
sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc,
uint32_t last_tsn, uint32_t *biggest_tsn_acked,
@@ -2894,14 +3265,14 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
struct sctp_tmit_chunk *tp1;
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, cumack)) {
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, cumack)) {
/*
* ok this guy is either ACK or MARKED. If it is
* ACKED it has been previously acked but not this
* time i.e. revoked. If it is MARKED it was ACK'ed
* again.
*/
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, biggest_tsn_acked)) {
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked)) {
break;
}
if (tp1->sent == SCTP_DATAGRAM_ACKED) {
@@ -2915,8 +3286,8 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
sctp_flight_size_increase(tp1);
sctp_total_flight_increase(stcb, tp1);
@@ -2927,7 +3298,7 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
sctp_log_sack(asoc->last_acked_seq,
cumack,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
0,
0,
SCTP_LOG_TSN_REVOKED);
@@ -2942,7 +3313,6 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
}
}
-
static void
sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
uint32_t biggest_tsn_acked, uint32_t biggest_tsn_newly_acked, uint32_t this_sack_lowest_newack, int accum_moved)
@@ -2963,7 +3333,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (tp1 == NULL) {
sending_seq = asoc->sending_seq;
} else {
- sending_seq = tp1->rec.data.TSN_seq;
+ sending_seq = tp1->rec.data.tsn;
}
/* CMT DAC algo: finding out if SACK is a mixed SACK */
@@ -2986,11 +3356,11 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
if (tp1->sent < SCTP_DATAGRAM_RESEND)
sctp_log_fr(biggest_tsn_newly_acked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_CHECK_STRIKE);
}
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, biggest_tsn_acked) ||
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked) ||
tp1->sent == SCTP_DATAGRAM_UNSENT) {
/* done */
break;
@@ -2998,7 +3368,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (stcb->asoc.prsctp_supported) {
if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) {
/* Is it expired? */
-#ifndef __FreeBSD__
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (timercmp(&now, &tp1->rec.data.timetodrop, >)) {
#else
if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
@@ -3011,9 +3381,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
continue;
}
}
-
}
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, asoc->this_sack_highest_gap)) {
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->this_sack_highest_gap) &&
+ !(accum_moved && asoc->fast_retran_loss_recovery)) {
/* we are beyond the tsn in the sack */
break;
}
@@ -3037,8 +3407,10 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
* FR using this SACK.
*/
continue;
- } else if (tp1->whoTo && SCTP_TSN_GT(tp1->rec.data.TSN_seq,
- tp1->whoTo->this_sack_highest_newack)) {
+ } else if (tp1->whoTo &&
+ SCTP_TSN_GT(tp1->rec.data.tsn,
+ tp1->whoTo->this_sack_highest_newack) &&
+ !(accum_moved && asoc->fast_retran_loss_recovery)) {
/*
* CMT: New acks were receieved for data sent to
* this dest. But no new acks were seen for data
@@ -3066,7 +3438,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
*/
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(biggest_tsn_newly_acked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_STRIKE_CHUNK);
}
@@ -3087,10 +3459,10 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
* two packets have been received after this missing TSN.
*/
if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
- SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.TSN_seq)) {
+ SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(16 + num_dests_sacked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_STRIKE_CHUNK);
}
@@ -3118,7 +3490,6 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
(1)
#endif
) {
-
if (SCTP_TSN_GE(biggest_tsn_newly_acked,
tp1->rec.data.fast_retran_tsn)) {
/*
@@ -3128,7 +3499,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
*/
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(biggest_tsn_newly_acked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_STRIKE_CHUNK);
}
@@ -3156,10 +3527,10 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
(num_dests_sacked == 1) &&
SCTP_TSN_GT(this_sack_lowest_newack,
- tp1->rec.data.TSN_seq)) {
+ tp1->rec.data.tsn)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(32 + num_dests_sacked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_STRIKE_CHUNK);
}
@@ -3174,7 +3545,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
* JRI: TODO: remove code for HTNA algo. CMT's
* SFR algo covers HTNA.
*/
- } else if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
+ } else if (SCTP_TSN_GT(tp1->rec.data.tsn,
biggest_tsn_newly_acked)) {
/*
* We don't strike these: This is the HTNA
@@ -3186,7 +3557,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
/* Strike the TSN */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(biggest_tsn_newly_acked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_STRIKE_CHUNK);
}
@@ -3207,10 +3578,10 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
* two packets have been received after this missing TSN.
*/
if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
- SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.TSN_seq)) {
+ SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(48 + num_dests_sacked,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
tp1->sent,
SCTP_FR_LOG_STRIKE_CHUNK);
}
@@ -3226,8 +3597,8 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND,
(tp1->whoTo ? (tp1->whoTo->flight_size) : 0),
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
if (tp1->whoTo) {
tp1->whoTo->net_ack++;
@@ -3258,13 +3629,15 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
SCTP_SO_NOT_LOCKED);
}
/* Make sure to flag we had a FR */
- tp1->whoTo->net_ack++;
+ if (tp1->whoTo != NULL) {
+ tp1->whoTo->net_ack++;
+ }
continue;
}
}
/* SCTP_PRINTF("OK, we are now ready to FR this guy\n"); */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
- sctp_log_fr(tp1->rec.data.TSN_seq, tp1->snd_count,
+ sctp_log_fr(tp1->rec.data.tsn, tp1->snd_count,
0, SCTP_FR_MARKED);
}
if (strike_flag) {
@@ -3303,9 +3676,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
tp1->whoTo->find_pseudo_cumack = 1;
tp1->whoTo->find_rtx_pseudo_cumack = 1;
}
-
} else {/* CMT is OFF */
-
#ifdef SCTP_FR_TO_ALTERNATE
/* Can we find an alternate? */
alt = sctp_find_alternate_net(stcb, tp1->whoTo, 0);
@@ -3324,7 +3695,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
/* mark the sending seq for possible subsequent FR's */
/*
* SCTP_PRINTF("Marking TSN for FR new value %x\n",
- * (uint32_t)tpi->rec.data.TSN_seq);
+ * (uint32_t)tpi->rec.data.tsn);
*/
if (TAILQ_EMPTY(&asoc->send_queue)) {
/*
@@ -3347,7 +3718,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
ttt = TAILQ_FIRST(&asoc->send_queue);
tp1->rec.data.fast_retran_tsn =
- ttt->rec.data.TSN_seq;
+ ttt->rec.data.tsn;
}
if (tp1->do_rtt) {
@@ -3395,7 +3766,7 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
(tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
asoc->advanced_peer_ack_point,
- tp1->rec.data.TSN_seq, 0, 0);
+ tp1->rec.data.tsn, 0, 0);
}
}
if (!PR_SCTP_ENABLED(tp1->flags)) {
@@ -3421,7 +3792,7 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
* Now is this one marked for resend and its time is
* now up?
*/
-#ifndef __FreeBSD__
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (timercmp(&now, &tp1->rec.data.timetodrop, >)) {
#else
if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
@@ -3447,10 +3818,10 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
(tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
/* advance PeerAckPoint goes forward */
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, asoc->advanced_peer_ack_point)) {
- asoc->advanced_peer_ack_point = tp1->rec.data.TSN_seq;
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->advanced_peer_ack_point)) {
+ asoc->advanced_peer_ack_point = tp1->rec.data.tsn;
a_adv = tp1;
- } else if (tp1->rec.data.TSN_seq == asoc->advanced_peer_ack_point) {
+ } else if (tp1->rec.data.tsn == asoc->advanced_peer_ack_point) {
/* No update but we do save the chk */
a_adv = tp1;
}
@@ -3470,19 +3841,23 @@ sctp_fs_audit(struct sctp_association *asoc)
{
struct sctp_tmit_chunk *chk;
int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0;
- int entry_flight, entry_cnt, ret;
+ int ret;
+#ifndef INVARIANTS
+ int entry_flight, entry_cnt;
+#endif
+ ret = 0;
+#ifndef INVARIANTS
entry_flight = asoc->total_flight;
entry_cnt = asoc->total_flight_count;
- ret = 0;
-
+#endif
if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt)
return (0);
TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
if (chk->sent < SCTP_DATAGRAM_RESEND) {
- SCTP_PRINTF("Chk TSN:%u size:%d inflight cnt:%d\n",
- chk->rec.data.TSN_seq,
+ SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n",
+ chk->rec.data.tsn,
chk->send_size,
chk->snd_count);
inflight++;
@@ -3501,10 +3876,10 @@ sctp_fs_audit(struct sctp_association *asoc)
#ifdef INVARIANTS
panic("Flight size-express incorrect? \n");
#else
- SCTP_PRINTF("asoc->total_flight:%d cnt:%d\n",
+ SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n",
entry_flight, entry_cnt);
- SCTP_PRINTF("Flight size-express incorrect F:%d I:%d R:%d Ab:%d ACK:%d\n",
+ SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n",
inflight, inbetween, resend, above, acked);
ret = 1;
#endif
@@ -3512,11 +3887,10 @@ sctp_fs_audit(struct sctp_association *asoc)
return (ret);
}
-
static void
sctp_window_probe_recovery(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- struct sctp_tmit_chunk *tp1)
+ struct sctp_association *asoc,
+ struct sctp_tmit_chunk *tp1)
{
tp1->window_probe = 0;
if ((tp1->sent >= SCTP_DATAGRAM_ACKED) || (tp1->data == NULL)) {
@@ -3524,8 +3898,8 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD,
tp1->whoTo ? tp1->whoTo->flight_size : 0,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
return;
}
/* First setup this by shrinking flight */
@@ -3543,8 +3917,8 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
}
@@ -3560,6 +3934,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
int win_probe_recovered = 0;
int j, done_once = 0;
int rto_ok = 1;
+ uint32_t send_s;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
@@ -3612,36 +3987,26 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
(*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack)(stcb, net);
}
}
- if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) {
- uint32_t send_s;
-
- if (!TAILQ_EMPTY(&asoc->sent_queue)) {
- tp1 = TAILQ_LAST(&asoc->sent_queue,
- sctpchunk_listhead);
- send_s = tp1->rec.data.TSN_seq + 1;
- } else {
- send_s = asoc->sending_seq;
- }
- if (SCTP_TSN_GE(cumack, send_s)) {
-#ifndef INVARIANTS
- struct mbuf *op_err;
- char msg[SCTP_DIAG_INFO_LEN];
-
-#endif
-#ifdef INVARIANTS
- panic("Impossible sack 1");
-#else
+ if (!TAILQ_EMPTY(&asoc->sent_queue)) {
+ tp1 = TAILQ_LAST(&asoc->sent_queue,
+ sctpchunk_listhead);
+ send_s = tp1->rec.data.tsn + 1;
+ } else {
+ send_s = asoc->sending_seq;
+ }
+ if (SCTP_TSN_GE(cumack, send_s)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
- *abort_now = 1;
- /* XXX */
- snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal then TSN %8.8x",
- cumack, send_s);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- return;
-#endif
- }
+ *abort_now = 1;
+ /* XXX */
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "Cum ack %8.8x greater or equal than TSN %8.8x",
+ cumack, send_s);
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return;
}
asoc->this_sack_highest_gap = cumack;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
@@ -3655,7 +4020,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
if (SCTP_TSN_GT(cumack, asoc->last_acked_seq)) {
/* process the new consecutive TSN first */
TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
- if (SCTP_TSN_GE(cumack, tp1->rec.data.TSN_seq)) {
+ if (SCTP_TSN_GE(cumack, tp1->rec.data.tsn)) {
if (tp1->sent == SCTP_DATAGRAM_UNSENT) {
SCTP_PRINTF("Warning, an unsent is now acked?\n");
}
@@ -3670,8 +4035,8 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
sctp_flight_size_decrease(tp1);
if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
@@ -3684,7 +4049,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
tp1->whoTo->net_ack += tp1->send_size;
if (tp1->snd_count < 2) {
/*
- * True non-retransmited
+ * True non-retransmitted
* chunk
*/
tp1->whoTo->net_ack2 +=
@@ -3692,17 +4057,12 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
/* update RTO too? */
if (tp1->do_rtt) {
- if (rto_ok) {
- tp1->whoTo->RTO =
- /*
- * sa_ignore
- * NO_NULL_CHK
- */
- sctp_calculate_rto(stcb,
- asoc, tp1->whoTo,
- &tp1->sent_rcv_time,
- sctp_align_safe_nocopy,
- SCTP_RTT_FROM_DATA);
+ if (rto_ok &&
+ sctp_calculate_rto(stcb,
+ &stcb->asoc,
+ tp1->whoTo,
+ &tp1->sent_rcv_time,
+ SCTP_RTT_FROM_DATA)) {
rto_ok = 0;
}
if (tp1->whoTo->rto_needed == 0) {
@@ -3726,10 +4086,9 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
tp1->whoTo->new_pseudo_cumack = 1;
tp1->whoTo->find_pseudo_cumack = 1;
tp1->whoTo->find_rtx_pseudo_cumack = 1;
-
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
/* sa_ignore NO_NULL_CHK */
- sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
+ sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
}
}
if (tp1->sent == SCTP_DATAGRAM_RESEND) {
@@ -3741,14 +4100,19 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
tp1->rec.data.chunk_was_revoked = 0;
}
if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
- if (asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[tp1->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
#endif
}
}
+ if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
+ (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
+ TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) {
+ asoc->trigger_reset = 1;
+ }
TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
if (tp1->data) {
/* sa_ignore NO_NULL_CHK */
@@ -3759,7 +4123,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
sctp_log_sack(asoc->last_acked_seq,
cumack,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
0,
0,
SCTP_LOG_FREE_SENT);
@@ -3770,7 +4134,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
break;
}
}
-
}
#if defined(__Userspace__)
if (stcb->sctp_ep->recv_callback) {
@@ -3790,7 +4153,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
(inp->send_sb_threshold == 0))) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
- inp->send_callback(stcb->sctp_socket, sb_free_now);
+ inp->send_callback(stcb->sctp_socket, sb_free_now, inp->ulp_info);
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
}
@@ -3800,7 +4163,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
/* sa_ignore NO_NULL_CHK */
if (stcb->sctp_socket) {
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
@@ -3809,7 +4172,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
/* sa_ignore NO_NULL_CHK */
sctp_wakeup_log(stcb, 1, SCTP_WAKESND_FROM_SACK);
}
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -3823,7 +4186,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
}
#endif
sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
} else {
@@ -3856,7 +4219,9 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
}
if (net->dest_state & SCTP_ADDR_PF) {
net->dest_state &= ~SCTP_ADDR_PF;
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
/* Done with this net */
@@ -3900,7 +4265,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
again:
j = 0;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- int to_ticks;
if (win_probe_recovery && (net->window_probe)) {
win_probe_recovered = 1;
/*
@@ -3916,15 +4280,9 @@ again:
}
}
}
- 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;
}
@@ -3933,13 +4291,12 @@ again:
/* 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,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
}
}
}
@@ -3978,72 +4335,49 @@ again:
/* clean up */
if ((asoc->stream_queue_cnt == 1) &&
((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
- (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
- (asoc->locked_on_sending)
- ) {
- struct sctp_stream_queue_pending *sp;
- /* I may be in a state where we got
- * all across.. but cannot write more due
- * to a shutdown... we abort since the
- * user did not indicate EOR in this case. The
- * sp will be cleaned during free of the asoc.
- */
- sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue),
- sctp_streamhead);
- if ((sp) && (sp->length == 0)) {
- /* Let cleanup code purge it */
- if (sp->msg_is_complete) {
- asoc->stream_queue_cnt--;
- } else {
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- asoc->locked_on_sending = NULL;
- asoc->stream_queue_cnt--;
- }
- }
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
+ ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc))) {
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
+ }
+ if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
+ (asoc->stream_queue_cnt == 1) &&
+ (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+
+ *abort_now = 1;
+ /* XXX */
+ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return;
}
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
(asoc->stream_queue_cnt == 0)) {
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- /* Need to abort here */
- struct mbuf *op_err;
+ struct sctp_nets *netp;
- abort_out_now:
- *abort_now = 1;
- /* XXX */
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
+ sctp_stop_timers_for_shutdown(stcb);
+ if (asoc->alternate) {
+ netp = asoc->alternate;
} else {
- struct sctp_nets *netp;
-
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_stop_timers_for_shutdown(stcb);
- if (asoc->alternate) {
- netp = asoc->alternate;
- } else {
- netp = asoc->primary_destination;
- }
- sctp_send_shutdown(stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, netp);
+ netp = asoc->primary_destination;
}
- } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ sctp_send_shutdown(stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
+ stcb->sctp_ep, stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
+ stcb->sctp_ep, stcb, NULL);
+ } else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) {
struct sctp_nets *netp;
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- goto abort_out_now;
- }
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
sctp_stop_timers_for_shutdown(stcb);
if (asoc->alternate) {
netp = asoc->alternate;
@@ -4084,10 +4418,15 @@ again:
}
}
}
- if (lchk) {
+ for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
+ if (lchk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (lchk != NULL) {
/* Assure a timer is up */
sctp_timer_start(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, lchk->whoTo);
+ stcb->sctp_ep, stcb, lchk->whoTo);
}
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
@@ -4194,40 +4533,39 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
}
}
- if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) {
- /* reality check */
- if (!TAILQ_EMPTY(&asoc->sent_queue)) {
- tp1 = TAILQ_LAST(&asoc->sent_queue,
- sctpchunk_listhead);
- send_s = tp1->rec.data.TSN_seq + 1;
- } else {
- tp1 = NULL;
- send_s = asoc->sending_seq;
- }
- if (SCTP_TSN_GE(cum_ack, send_s)) {
- struct mbuf *op_err;
- char msg[SCTP_DIAG_INFO_LEN];
+ /* reality check */
+ if (!TAILQ_EMPTY(&asoc->sent_queue)) {
+ tp1 = TAILQ_LAST(&asoc->sent_queue,
+ sctpchunk_listhead);
+ send_s = tp1->rec.data.tsn + 1;
+ } else {
+ tp1 = NULL;
+ send_s = asoc->sending_seq;
+ }
+ if (SCTP_TSN_GE(cum_ack, send_s)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
- /*
- * no way, we have not even sent this TSN out yet.
- * Peer is hopelessly messed up with us.
- */
- SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n",
- cum_ack, send_s);
- if (tp1) {
- SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1:%p\n",
- tp1->rec.data.TSN_seq, (void *)tp1);
- }
- hopeless_peer:
- *abort_now = 1;
- /* XXX */
- snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal then TSN %8.8x",
- cum_ack, send_s);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- return;
- }
+ /*
+ * no way, we have not even sent this TSN out yet.
+ * Peer is hopelessly messed up with us.
+ */
+ SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n",
+ cum_ack, send_s);
+ if (tp1) {
+ SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n",
+ tp1->rec.data.tsn, (void *)tp1);
+ }
+ hopeless_peer:
+ *abort_now = 1;
+ /* XXX */
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "Cum ack %8.8x greater or equal than TSN %8.8x",
+ cum_ack, send_s);
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_29;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return;
}
/**********************/
/* 1) check the range */
@@ -4257,7 +4595,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
/* stop any timers */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
+ stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
net->partial_bytes_acked = 0;
net->flight_size = 0;
}
@@ -4290,10 +4628,18 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
(*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack)(stcb, net);
}
+
+ /*
+ * CMT: SFR algo (and HTNA) - this_sack_highest_newack has
+ * to be greater than the cumack. Also reset saw_newack to 0
+ * for all dests.
+ */
+ net->saw_newack = 0;
+ net->this_sack_highest_newack = last_tsn;
}
/* process the new consecutive TSN first */
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
- if (SCTP_TSN_GE(last_tsn, tp1->rec.data.TSN_seq)) {
+ if (SCTP_TSN_GE(last_tsn, tp1->rec.data.tsn)) {
if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
accum_moved = 1;
if (tp1->sent < SCTP_DATAGRAM_ACKED) {
@@ -4321,8 +4667,8 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
sctp_flight_size_decrease(tp1);
sctp_total_flight_decrease(stcb, tp1);
@@ -4334,12 +4680,12 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
tp1->whoTo->net_ack += tp1->send_size;
/* CMT SFR and DAC algos */
- this_sack_lowest_newack = tp1->rec.data.TSN_seq;
+ this_sack_lowest_newack = tp1->rec.data.tsn;
tp1->whoTo->saw_newack = 1;
if (tp1->snd_count < 2) {
/*
- * True non-retransmited
+ * True non-retransmitted
* chunk
*/
tp1->whoTo->net_ack2 +=
@@ -4347,13 +4693,12 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
/* update RTO too? */
if (tp1->do_rtt) {
- if (rto_ok) {
- tp1->whoTo->RTO =
- sctp_calculate_rto(stcb,
- asoc, tp1->whoTo,
- &tp1->sent_rcv_time,
- sctp_align_safe_nocopy,
- SCTP_RTT_FROM_DATA);
+ if (rto_ok &&
+ sctp_calculate_rto(stcb,
+ &stcb->asoc,
+ tp1->whoTo,
+ &tp1->sent_rcv_time,
+ SCTP_RTT_FROM_DATA)) {
rto_ok = 0;
}
if (tp1->whoTo->rto_needed == 0) {
@@ -4377,18 +4722,16 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
tp1->whoTo->new_pseudo_cumack = 1;
tp1->whoTo->find_pseudo_cumack = 1;
tp1->whoTo->find_rtx_pseudo_cumack = 1;
-
-
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
sctp_log_sack(asoc->last_acked_seq,
cum_ack,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
0,
0,
SCTP_LOG_TSN_ACKED);
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
+ sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
}
}
if (tp1->sent == SCTP_DATAGRAM_RESEND) {
@@ -4416,17 +4759,6 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
asoc->this_sack_highest_gap = last_tsn;
if ((num_seg > 0) || (num_nr_seg > 0)) {
-
- /*
- * CMT: SFR algo (and HTNA) - this_sack_highest_newack has
- * to be greater than the cumack. Also reset saw_newack to 0
- * for all dests.
- */
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- net->saw_newack = 0;
- net->this_sack_highest_newack = last_tsn;
- }
-
/*
* thisSackHighestGap will increase while handling NEW
* segments this_sack_highest_newack will increase while
@@ -4438,20 +4770,18 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
num_seg, num_nr_seg, &rto_ok)) {
wake_him++;
}
- if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) {
+ /*
+ * validate the biggest_tsn_acked in the gap acks if
+ * strict adherence is wanted.
+ */
+ if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) {
/*
- * validate the biggest_tsn_acked in the gap acks if
- * strict adherence is wanted.
+ * peer is either confused or we are under
+ * attack. We must abort.
*/
- if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) {
- /*
- * peer is either confused or we are under
- * attack. We must abort.
- */
- SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n",
- biggest_tsn_acked, send_s);
- goto hopeless_peer;
- }
+ SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n",
+ biggest_tsn_acked, send_s);
+ goto hopeless_peer;
}
}
/*******************************************/
@@ -4462,14 +4792,13 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
if (net->new_pseudo_cumack)
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
-
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_31);
}
} else {
if (accum_moved) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28);
+ stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
}
}
}
@@ -4479,18 +4808,23 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
asoc->last_acked_seq = cum_ack;
TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, cum_ack)) {
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, cum_ack)) {
break;
}
if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
- if (asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[tp1->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
#endif
}
}
+ if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
+ (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
+ TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) {
+ asoc->trigger_reset = 1;
+ }
TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
if (PR_SCTP_ENABLED(tp1->flags)) {
if (asoc->pr_sctp_cnt != 0)
@@ -4509,7 +4843,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
sctp_log_sack(asoc->last_acked_seq,
cum_ack,
- tp1->rec.data.TSN_seq,
+ tp1->rec.data.tsn,
0,
0,
SCTP_LOG_FREE_SENT);
@@ -4519,7 +4853,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
}
if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) {
#ifdef INVARIANTS
- panic("Warning flight size is postive and should be 0");
+ panic("Warning flight size is positive and should be 0");
#else
SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n",
asoc->total_flight);
@@ -4543,7 +4877,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
(inp->send_sb_threshold == 0))) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
- inp->send_callback(stcb->sctp_socket, sb_free_now);
+ inp->send_callback(stcb->sctp_socket, sb_free_now, inp->ulp_info);
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
}
@@ -4553,7 +4887,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
/* sa_ignore NO_NULL_CHK */
if ((wake_him) && (stcb->sctp_socket)) {
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
@@ -4561,7 +4895,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
sctp_wakeup_log(stcb, wake_him, SCTP_WAKESND_FROM_SACK);
}
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4575,7 +4909,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
}
#endif
sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
} else {
@@ -4614,8 +4948,8 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)tp1->whoTo,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)tp1->whoTo,
+ tp1->rec.data.tsn);
}
sctp_flight_size_increase(tp1);
sctp_total_flight_increase(stcb, tp1);
@@ -4667,7 +5001,9 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
if (net->dest_state & SCTP_ADDR_PF) {
net->dest_state &= ~SCTP_ADDR_PF;
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_33);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
/* Done with this net */
@@ -4691,7 +5027,8 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
/* stop all timers */
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
+ stcb, net,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_34);
net->flight_size = 0;
net->partial_bytes_acked = 0;
}
@@ -4716,72 +5053,50 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
/* clean up */
if ((asoc->stream_queue_cnt == 1) &&
((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
- (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
- (asoc->locked_on_sending)
- ) {
- struct sctp_stream_queue_pending *sp;
- /* I may be in a state where we got
- * all across.. but cannot write more due
- * to a shutdown... we abort since the
- * user did not indicate EOR in this case.
- */
- sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue),
- sctp_streamhead);
- if ((sp) && (sp->length == 0)) {
- asoc->locked_on_sending = NULL;
- if (sp->msg_is_complete) {
- asoc->stream_queue_cnt--;
- } else {
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- asoc->stream_queue_cnt--;
- }
- }
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
+ ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc))) {
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
+ }
+ if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
+ (asoc->stream_queue_cnt == 1) &&
+ (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+
+ *abort_now = 1;
+ /* XXX */
+ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return;
}
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
(asoc->stream_queue_cnt == 0)) {
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- /* Need to abort here */
- struct mbuf *op_err;
+ struct sctp_nets *netp;
- abort_out_now:
- *abort_now = 1;
- /* XXX */
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- return;
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
+ sctp_stop_timers_for_shutdown(stcb);
+ if (asoc->alternate) {
+ netp = asoc->alternate;
} else {
- struct sctp_nets *netp;
-
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_stop_timers_for_shutdown(stcb);
- if (asoc->alternate) {
- netp = asoc->alternate;
- } else {
- netp = asoc->primary_destination;
- }
- sctp_send_shutdown(stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, netp);
+ netp = asoc->primary_destination;
}
+ sctp_send_shutdown(stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
+ stcb->sctp_ep, stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
+ stcb->sctp_ep, stcb, NULL);
return;
- } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ } else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) {
struct sctp_nets *netp;
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- goto abort_out_now;
- }
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
sctp_stop_timers_for_shutdown(stcb);
if (asoc->alternate) {
netp = asoc->alternate;
@@ -4892,12 +5207,11 @@ again:
if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.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,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_36);
}
}
}
@@ -4962,7 +5276,12 @@ again:
}
}
}
- if (lchk) {
+ for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
+ if (lchk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (lchk != NULL) {
/* Assure a timer is up */
sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, lchk->whoTo);
@@ -4993,141 +5312,241 @@ sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *ab
static void
sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
- struct sctp_stream_in *strmin)
+ struct sctp_stream_in *strmin)
{
- struct sctp_queued_to_read *ctl, *nctl;
+ struct sctp_queued_to_read *control, *ncontrol;
struct sctp_association *asoc;
- uint16_t tt;
+ uint32_t mid;
+ int need_reasm_check = 0;
asoc = &stcb->asoc;
- tt = strmin->last_sequence_delivered;
+ mid = strmin->last_mid_delivered;
/*
* First deliver anything prior to and including the stream no that
- * came in
+ * came in.
*/
- TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next, nctl) {
- if (SCTP_SSN_GE(tt, ctl->sinfo_ssn)) {
+ TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
+ if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
/* this is deliverable now */
- TAILQ_REMOVE(&strmin->inqueue, ctl, next);
- /* subtract pending on streams */
- asoc->size_on_all_streams -= ctl->length;
- sctp_ucount_decr(asoc->cnt_on_all_streams);
- /* deliver it to at least the delivery-q */
- if (stcb->sctp_socket) {
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- ctl,
- &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
+ if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ if (control->on_strm_q) {
+ if (control->on_strm_q == SCTP_ON_ORDERED) {
+ TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
+#ifdef INVARIANTS
+ } else {
+ panic("strmin: %p ctl: %p unknown %d",
+ strmin, control, control->on_strm_q);
+#endif
+ }
+ control->on_strm_q = 0;
+ }
+ /* subtract pending on streams */
+ 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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ /* deliver it to at least the delivery-q */
+ if (stcb->sctp_socket) {
+ sctp_mark_non_revokable(asoc, control->sinfo_tsn);
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv,
+ 1, SCTP_READ_LOCK_HELD,
+ SCTP_SO_NOT_LOCKED);
+ }
+ } else {
+ /* Its a fragmented message */
+ if (control->first_frag_seen) {
+ /* Make it so this is next to deliver, we restore later */
+ strmin->last_mid_delivered = control->mid - 1;
+ need_reasm_check = 1;
+ break;
+ }
}
} else {
/* no more delivery now. */
break;
}
}
+ if (need_reasm_check) {
+ int ret;
+ ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
+ if (SCTP_MID_GT(asoc->idata_supported, mid, strmin->last_mid_delivered)) {
+ /* Restore the next to deliver unless we are ahead */
+ strmin->last_mid_delivered = mid;
+ }
+ if (ret == 0) {
+ /* Left the front Partial one on */
+ return;
+ }
+ need_reasm_check = 0;
+ }
/*
* now we must deliver things in queue the normal way if any are
* now ready.
*/
- tt = strmin->last_sequence_delivered + 1;
- TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next, nctl) {
- if (tt == ctl->sinfo_ssn) {
- /* this is deliverable now */
- TAILQ_REMOVE(&strmin->inqueue, ctl, next);
- /* subtract pending on streams */
- asoc->size_on_all_streams -= ctl->length;
- sctp_ucount_decr(asoc->cnt_on_all_streams);
- /* deliver it to at least the delivery-q */
- strmin->last_sequence_delivered = ctl->sinfo_ssn;
- if (stcb->sctp_socket) {
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- ctl,
- &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
-
+ mid = strmin->last_mid_delivered + 1;
+ TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
+ if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) {
+ if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ /* this is deliverable now */
+ if (control->on_strm_q) {
+ if (control->on_strm_q == SCTP_ON_ORDERED) {
+ TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
+#ifdef INVARIANTS
+ } else {
+ panic("strmin: %p ctl: %p unknown %d",
+ strmin, control, control->on_strm_q);
+#endif
+ }
+ control->on_strm_q = 0;
+ }
+ /* subtract pending on streams */
+ 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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ /* deliver it to at least the delivery-q */
+ strmin->last_mid_delivered = control->mid;
+ if (stcb->sctp_socket) {
+ sctp_mark_non_revokable(asoc, control->sinfo_tsn);
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, 1,
+ SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
+ }
+ mid = strmin->last_mid_delivered + 1;
+ } else {
+ /* Its a fragmented message */
+ if (control->first_frag_seen) {
+ /* Make it so this is next to deliver */
+ strmin->last_mid_delivered = control->mid - 1;
+ need_reasm_check = 1;
+ break;
+ }
}
- tt = strmin->last_sequence_delivered + 1;
} else {
break;
}
}
+ if (need_reasm_check) {
+ (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
+ }
}
static void
sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- uint16_t stream, uint16_t seq)
+ struct sctp_association *asoc, struct sctp_stream_in *strm,
+ struct sctp_queued_to_read *control, int ordered, uint32_t cumtsn)
{
struct sctp_tmit_chunk *chk, *nchk;
- /* For each one on here see if we need to toss it */
/*
- * For now large messages held on the reasmqueue that are
+ * For now large messages held on the stream reasm that are
* complete will be tossed too. We could in theory do more
* work to spin through and stop after dumping one msg aka
* seeing the start of a new msg at the head, and call the
* delivery function... to see if it can be delivered... But
* for now we just dump everything on the queue.
*/
- TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
- /* Do not toss it if on a different stream or
- * marked for unordered delivery in which case
- * the stream sequence number has no meaning.
- */
- if ((chk->rec.data.stream_number != stream) ||
- ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED)) {
- continue;
- }
- if (chk->rec.data.stream_seq == seq) {
- /* It needs to be tossed */
- TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- if (SCTP_TSN_GT(chk->rec.data.TSN_seq, asoc->tsn_last_delivered)) {
- asoc->tsn_last_delivered = chk->rec.data.TSN_seq;
- asoc->str_of_pdapi = chk->rec.data.stream_number;
- asoc->ssn_of_pdapi = chk->rec.data.stream_seq;
- asoc->fragment_flags = chk->rec.data.rcv_flags;
+ if (!asoc->idata_supported && !ordered &&
+ control->first_frag_seen &&
+ SCTP_TSN_GT(control->fsn_included, cumtsn)) {
+ return;
+ }
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
+ /* Purge hanging chunks */
+ if (!asoc->idata_supported && !ordered) {
+ if (SCTP_TSN_GT(chk->rec.data.tsn, cumtsn)) {
+ break;
}
+ }
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ if (asoc->size_on_reasm_queue >= chk->send_size) {
asoc->size_on_reasm_queue -= chk->send_size;
- sctp_ucount_decr(asoc->cnt_on_reasm_queue);
-
- /* Clear up any stream problem */
- if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != SCTP_DATA_UNORDERED &&
- SCTP_SSN_GT(chk->rec.data.stream_seq, asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered)) {
- /*
- * We must dump forward this streams
- * sequence number if the chunk is
- * not unordered that is being
- * skipped. There is a chance that
- * if the peer does not include the
- * last fragment in its FWD-TSN we
- * WILL have a problem here since
- * you would have a partial chunk in
- * queue that may not be
- * deliverable. Also if a Partial
- * delivery API as started the user
- * may get a partial chunk. The next
- * read returning a new chunk...
- * really ugly but I see no way
- * around it! Maybe a notify??
- */
- asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = chk->rec.data.stream_seq;
- }
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- } else if (SCTP_SSN_GT(chk->rec.data.stream_seq, seq)) {
- /* If the stream_seq is > than the purging one, we are done */
- break;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_reasm_queue);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ }
+ if (!TAILQ_EMPTY(&control->reasm)) {
+ /* This has to be old data, unordered */
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_reset_a_control(control, stcb->sctp_ep, cumtsn);
+ chk = TAILQ_FIRST(&control->reasm);
+ if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ sctp_add_chk_to_control(control, strm, stcb, asoc,
+ chk, SCTP_READ_LOCK_HELD);
}
+ sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD);
+ return;
+ }
+ if (control->on_strm_q == SCTP_ON_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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ control->on_strm_q = 0;
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+#ifdef INVARIANTS
+ } else if (control->on_strm_q) {
+ panic("strm: %p ctl: %p unknown %d",
+ strm, control, control->on_strm_q);
+#endif
+ }
+ control->on_strm_q = 0;
+ if (control->on_read_q == 0) {
+ sctp_free_remote_addr(control->whoFrom);
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_free_a_readq(stcb, control);
}
}
-
void
sctp_handle_forward_tsn(struct sctp_tcb *stcb,
struct sctp_forward_tsn_chunk *fwd,
- int *abort_flag, struct mbuf *m ,int offset)
+ int *abort_flag, struct mbuf *m , int offset)
{
/* The pr-sctp fwd tsn */
/*
@@ -5136,18 +5555,18 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
*
* Assume we get FwdTSN(x):
*
- * 1) update local cumTSN to x 2) try to further advance cumTSN to x +
- * others we have 3) examine and update re-ordering queue on
- * pr-in-streams 4) clean up re-assembly queue 5) Send a sack to
- * report where we are.
+ * 1) update local cumTSN to x
+ * 2) try to further advance cumTSN to x + others we have
+ * 3) examine and update re-ordering queue on pr-in-streams
+ * 4) clean up re-assembly queue
+ * 5) Send a sack to report where we are.
*/
struct sctp_association *asoc;
uint32_t new_cum_tsn, gap;
unsigned int i, fwd_sz, m_size;
uint32_t str_seq;
struct sctp_stream_in *strm;
- struct sctp_tmit_chunk *chk, *nchk;
- struct sctp_queued_to_read *ctl, *sv;
+ struct sctp_queued_to_read *control, *ncontrol, *sv;
asoc = &stcb->asoc;
if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
@@ -5181,11 +5600,11 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
* give out). This must be an attacker.
*/
*abort_flag = 1;
- snprintf(msg, sizeof(msg),
- "New cum ack %8.8x too high, highest TSN %8.8x",
- new_cum_tsn, asoc->highest_tsn_inside_map);
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "New cum ack %8.8x too high, highest TSN %8.8x",
+ new_cum_tsn, asoc->highest_tsn_inside_map);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA+SCTP_LOC_33;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_37;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
}
@@ -5216,69 +5635,20 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
/*************************************************************/
/* 2. Clear up re-assembly queue */
/*************************************************************/
- /*
- * First service it if pd-api is up, just in case we can progress it
- * forward
- */
- if (asoc->fragmented_delivery_inprogress) {
- sctp_service_reassembly(stcb, asoc);
- }
- /* For each one on here see if we need to toss it */
- /*
- * For now large messages held on the reasmqueue that are
- * complete will be tossed too. We could in theory do more
- * work to spin through and stop after dumping one msg aka
- * seeing the start of a new msg at the head, and call the
- * delivery function... to see if it can be delivered... But
- * for now we just dump everything on the queue.
- */
- TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
- if (SCTP_TSN_GE(new_cum_tsn, chk->rec.data.TSN_seq)) {
- /* It needs to be tossed */
- TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- if (SCTP_TSN_GT(chk->rec.data.TSN_seq, asoc->tsn_last_delivered)) {
- asoc->tsn_last_delivered = chk->rec.data.TSN_seq;
- asoc->str_of_pdapi = chk->rec.data.stream_number;
- asoc->ssn_of_pdapi = chk->rec.data.stream_seq;
- asoc->fragment_flags = chk->rec.data.rcv_flags;
- }
- asoc->size_on_reasm_queue -= chk->send_size;
- sctp_ucount_decr(asoc->cnt_on_reasm_queue);
- /* Clear up any stream problem */
- if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != SCTP_DATA_UNORDERED &&
- SCTP_SSN_GT(chk->rec.data.stream_seq, asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered)) {
- /*
- * We must dump forward this streams
- * sequence number if the chunk is
- * not unordered that is being
- * skipped. There is a chance that
- * if the peer does not include the
- * last fragment in its FWD-TSN we
- * WILL have a problem here since
- * you would have a partial chunk in
- * queue that may not be
- * deliverable. Also if a Partial
- * delivery API as started the user
- * may get a partial chunk. The next
- * read returning a new chunk...
- * really ugly but I see no way
- * around it! Maybe a notify??
- */
- asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = chk->rec.data.stream_seq;
- }
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
+ /* This is now done as part of clearing up the stream/seq */
+ if (asoc->idata_supported == 0) {
+ uint16_t sid;
+
+ /* Flush all the un-ordered data based on cum-tsn */
+ SCTP_INP_READ_LOCK(stcb->sctp_ep);
+ for (sid = 0; sid < asoc->streamincnt; sid++) {
+ strm = &asoc->strmin[sid];
+ if (!TAILQ_EMPTY(&strm->uno_inqueue)) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), 0, new_cum_tsn);
}
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- } else {
- /*
- * Ok we have gone beyond the end of the
- * fwd-tsn's mark.
- */
- break;
}
+ SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
}
/*******************************************************/
/* 3. Update the PR-stream re-ordering queues and fix */
@@ -5288,25 +5658,49 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
if (m && fwd_sz) {
/* New method. */
unsigned int num_str;
+ uint32_t mid;
+ uint16_t sid;
+ uint16_t ordered, flags;
struct sctp_strseq *stseq, strseqbuf;
+ struct sctp_strseq_mid *stseq_m, strseqbuf_m;
offset += sizeof(*fwd);
SCTP_INP_READ_LOCK(stcb->sctp_ep);
- num_str = fwd_sz / sizeof(struct sctp_strseq);
+ if (asoc->idata_supported) {
+ num_str = fwd_sz / sizeof(struct sctp_strseq_mid);
+ } else {
+ num_str = fwd_sz / sizeof(struct sctp_strseq);
+ }
for (i = 0; i < num_str; i++) {
- uint16_t st;
- stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
- sizeof(struct sctp_strseq),
- (uint8_t *)&strseqbuf);
- offset += sizeof(struct sctp_strseq);
- if (stseq == NULL) {
- break;
+ if (asoc->idata_supported) {
+ stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset,
+ sizeof(struct sctp_strseq_mid),
+ (uint8_t *)&strseqbuf_m);
+ offset += sizeof(struct sctp_strseq_mid);
+ if (stseq_m == NULL) {
+ break;
+ }
+ sid = ntohs(stseq_m->sid);
+ mid = ntohl(stseq_m->mid);
+ flags = ntohs(stseq_m->flags);
+ if (flags & PR_SCTP_UNORDERED_FLAG) {
+ ordered = 0;
+ } else {
+ ordered = 1;
+ }
+ } else {
+ stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
+ sizeof(struct sctp_strseq),
+ (uint8_t *)&strseqbuf);
+ offset += sizeof(struct sctp_strseq);
+ if (stseq == NULL) {
+ break;
+ }
+ sid = ntohs(stseq->sid);
+ mid = (uint32_t)ntohs(stseq->ssn);
+ ordered = 1;
}
/* Convert */
- st = ntohs(stseq->stream);
- stseq->stream = st;
- st = ntohs(stseq->sequence);
- stseq->sequence = st;
/* now process */
@@ -5315,27 +5709,67 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
* where its not all delivered. If we find it we transmute the
* read entry into a PDI_ABORTED.
*/
- if (stseq->stream >= asoc->streamincnt) {
+ if (sid >= asoc->streamincnt) {
/* screwed up streams, stop! */
break;
}
- if ((asoc->str_of_pdapi == stseq->stream) &&
- (asoc->ssn_of_pdapi == stseq->sequence)) {
+ if ((asoc->str_of_pdapi == sid) &&
+ (asoc->ssn_of_pdapi == mid)) {
/* If this is the one we were partially delivering
* now then we no longer are. Note this will change
* with the reassembly re-write.
*/
asoc->fragmented_delivery_inprogress = 0;
}
- sctp_flush_reassm_for_str_seq(stcb, asoc, stseq->stream, stseq->sequence);
- TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
- if ((ctl->sinfo_stream == stseq->stream) &&
- (ctl->sinfo_ssn == stseq->sequence)) {
- str_seq = (stseq->stream << 16) | stseq->sequence;
- ctl->end_added = 1;
- ctl->pdapi_aborted = 1;
+ strm = &asoc->strmin[sid];
+ if (ordered) {
+ TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, ncontrol) {
+ if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn);
+ }
+ }
+ } else {
+ if (asoc->idata_supported) {
+ TAILQ_FOREACH_SAFE(control, &strm->uno_inqueue, next_instrm, ncontrol) {
+ if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn);
+ }
+ }
+ } else {
+ if (!TAILQ_EMPTY(&strm->uno_inqueue)) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), ordered, new_cum_tsn);
+ }
+ }
+ }
+ TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) {
+ if ((control->sinfo_stream == sid) &&
+ (SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) {
+ str_seq = (sid << 16) | (0x0000ffff & mid);
+ control->pdapi_aborted = 1;
sv = stcb->asoc.control_pdapi;
- stcb->asoc.control_pdapi = ctl;
+ control->end_added = 1;
+ if (control->on_strm_q == SCTP_ON_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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+#ifdef INVARIANTS
+ } else if (control->on_strm_q) {
+ panic("strm: %p ctl: %p unknown %d",
+ strm, control, control->on_strm_q);
+#endif
+ }
+ control->on_strm_q = 0;
+ stcb->asoc.control_pdapi = control;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
stcb,
SCTP_PARTIAL_DELIVERY_ABORTED,
@@ -5343,19 +5777,18 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
SCTP_SO_NOT_LOCKED);
stcb->asoc.control_pdapi = sv;
break;
- } else if ((ctl->sinfo_stream == stseq->stream) &&
- SCTP_SSN_GT(ctl->sinfo_ssn, stseq->sequence)) {
+ } else if ((control->sinfo_stream == sid) &&
+ SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) {
/* We are past our victim SSN */
break;
}
}
- strm = &asoc->strmin[stseq->stream];
- if (SCTP_SSN_GT(stseq->sequence, strm->last_sequence_delivered)) {
+ if (SCTP_MID_GT(asoc->idata_supported, mid, strm->last_mid_delivered)) {
/* Update the sequence number */
- strm->last_sequence_delivered = stseq->sequence;
+ strm->last_mid_delivered = mid;
}
/* now kick the stream the new way */
- /*sa_ignore NO_NULL_CHK*/
+ /*sa_ignore NO_NULL_CHK*/
sctp_kick_prsctp_reorder_queue(stcb, strm);
}
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
@@ -5364,10 +5797,4 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
* Now slide thing forward.
*/
sctp_slide_mapping_arrays(stcb);
-
- if (!TAILQ_EMPTY(&asoc->reasmqueue)) {
- /* now lets kick out and check for more fragmented delivery */
- /*sa_ignore NO_NULL_CHK*/
- sctp_deliver_reasm_check(stcb, &stcb->asoc);
- }
}
diff --git a/netwerk/sctp/src/netinet/sctp_indata.h b/netwerk/sctp/src/netinet/sctp_indata.h
index d90602a21d..651493b917 100755
--- a/netwerk/sctp/src/netinet/sctp_indata.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.h 252585 2013-07-03 18:48:43Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_INDATA_H_
@@ -42,46 +44,40 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.h 252585 2013-07-03 18:48:43Z t
struct sctp_queued_to_read *
sctp_build_readq_entry(struct sctp_tcb *stcb,
- struct sctp_nets *net,
- uint32_t tsn, uint32_t ppid,
- uint32_t context, uint16_t stream_no,
- uint16_t stream_seq, uint8_t flags,
- struct mbuf *dm);
-
+ struct sctp_nets *net,
+ uint32_t tsn, uint32_t ppid,
+ uint32_t context, uint16_t sid,
+ uint32_t mid, uint8_t flags,
+ struct mbuf *dm);
-#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, stream_no, stream_seq, flags, dm) do { \
+#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, sid, flags, dm, tfsn, mid) do { \
if (_ctl) { \
atomic_add_int(&((net)->ref_count), 1); \
- (_ctl)->sinfo_stream = stream_no; \
- (_ctl)->sinfo_ssn = stream_seq; \
+ memset(_ctl, 0, sizeof(struct sctp_queued_to_read)); \
+ (_ctl)->sinfo_stream = sid; \
+ TAILQ_INIT(&_ctl->reasm); \
+ (_ctl)->top_fsn = tfsn; \
+ (_ctl)->mid = mid; \
(_ctl)->sinfo_flags = (flags << 8); \
(_ctl)->sinfo_ppid = ppid; \
(_ctl)->sinfo_context = context; \
- (_ctl)->sinfo_timetolive = 0; \
+ (_ctl)->fsn_included = 0xffffffff; \
(_ctl)->sinfo_tsn = tsn; \
(_ctl)->sinfo_cumtsn = tsn; \
(_ctl)->sinfo_assoc_id = sctp_get_associd((in_it)); \
- (_ctl)->length = 0; \
- (_ctl)->held_length = 0; \
(_ctl)->whoFrom = net; \
(_ctl)->data = dm; \
- (_ctl)->tail_mbuf = NULL; \
- (_ctl)->aux_data = NULL; \
(_ctl)->stcb = (in_it); \
(_ctl)->port_from = (in_it)->rport; \
- (_ctl)->spec_flags = 0; \
- (_ctl)->do_not_ref_stcb = 0; \
- (_ctl)->end_added = 0; \
- (_ctl)->pdapi_aborted = 0; \
- (_ctl)->some_taken = 0; \
+ if ((in_it)->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { \
+ (_ctl)->do_not_ref_stcb = 1; \
+ }\
} \
} while (0)
-
-
struct mbuf *
sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
- struct sctp_sndrcvinfo *sinfo);
+ struct sctp_sndrcvinfo *sinfo);
void sctp_set_rwnd(struct sctp_tcb *, struct sctp_association *);
@@ -90,7 +86,7 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc);
void
sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
- uint32_t rwnd, int *abort_now, int ecne_seen);
+ uint32_t rwnd, int *abort_now, int ecne_seen);
void
sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
@@ -102,7 +98,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
/* draft-ietf-tsvwg-usctp */
void
sctp_handle_forward_tsn(struct sctp_tcb *,
- struct sctp_forward_tsn_chunk *, int *, struct mbuf *, int);
+ struct sctp_forward_tsn_chunk *, int *, struct mbuf *, int);
struct sctp_tmit_chunk *
sctp_try_advance_peer_ack_point(struct sctp_tcb *, struct sctp_association *);
@@ -114,14 +110,8 @@ sctp_update_acked(struct sctp_tcb *, struct sctp_shutdown_chunk *, int *);
int
sctp_process_data(struct mbuf **, int, int *, int,
- struct sockaddr *src, struct sockaddr *dst,
- struct sctphdr *,
- struct sctp_inpcb *, struct sctp_tcb *,
- struct sctp_nets *, uint32_t *,
-#if defined(__FreeBSD__)
- uint8_t, uint32_t,
-#endif
- uint32_t, uint16_t);
+ struct sctp_inpcb *, struct sctp_tcb *,
+ struct sctp_nets *, uint32_t *);
void sctp_slide_mapping_arrays(struct sctp_tcb *stcb);
diff --git a/netwerk/sctp/src/netinet/sctp_input.c b/netwerk/sctp/src/netinet/sctp_input.c
index f469e0f5ce..517189fb6a 100755
--- a/netwerk/sctp/src/netinet/sctp_input.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 279859 2015-03-10 19:49:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 368622 2020-12-13 23:51:51Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -49,20 +51,18 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 279859 2015-03-10 19:49:25Z tu
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_crc32.h>
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <netinet/sctp_kdtrace.h>
+#endif
#if defined(INET) || defined(INET6)
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <netinet/udp.h>
#endif
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/smp.h>
#endif
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 2
-#endif
-
-
static void
sctp_stop_all_cookie_timers(struct sctp_tcb *stcb)
{
@@ -79,12 +79,12 @@ sctp_stop_all_cookie_timers(struct sctp_tcb *stcb)
sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE,
stcb->sctp_ep,
stcb,
- net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_1);
+ net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_1);
} else if (net->rxt_timer.type == SCTP_TIMER_TYPE_INIT) {
sctp_timer_stop(SCTP_TIMER_TYPE_INIT,
stcb->sctp_ep,
stcb,
- net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_2);
+ net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_2);
}
}
}
@@ -94,8 +94,8 @@ static void
sctp_handle_init(struct mbuf *m, int iphlen, int offset,
struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh,
struct sctp_init_chunk *cp, struct sctp_inpcb *inp,
- struct sctp_tcb *stcb, int *abort_no_unlock,
-#if defined(__FreeBSD__)
+ struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_no_unlock,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id, uint16_t port)
@@ -112,7 +112,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_chunk)) {
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -126,7 +126,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
/* protocol error... send abort */
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -138,7 +138,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
/* invalid parameter... send abort */
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -150,7 +150,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
/* protocol error... send abort */
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -162,7 +162,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
/* protocol error... send abort */
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -176,7 +176,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Problem with AUTH parameters");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -184,12 +184,11 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
*abort_no_unlock = 1;
goto outnow;
}
- /* We are only accepting if we have a socket with positive so_qlimit.*/
+ /* We are only accepting if we have a listening socket.*/
if ((stcb == NULL) &&
((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
- (inp->sctp_socket == NULL) ||
- (inp->sctp_socket->so_qlimit == 0))) {
+ (!SCTP_IS_LISTENING(inp)))) {
/*
* FIX ME ?? What about TCP model and we have a
* match/restart case? Actually no fix is needed.
@@ -206,27 +205,26 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"No listener");
sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
}
goto outnow;
}
if ((stcb != NULL) &&
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT)) {
SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending SHUTDOWN-ACK\n");
sctp_send_shutdown_ack(stcb, NULL);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
} else {
SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n");
- sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, src, dst,
- sh, cp,
-#if defined(__FreeBSD__)
+ sctp_send_initiate_ack(inp, stcb, net, m, iphlen, offset,
+ src, dst, sh, cp,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
- vrf_id, port,
- ((stcb == NULL) ? SCTP_HOLDS_LOCK : SCTP_NOT_LOCKED));
+ vrf_id, port);
}
outnow:
if (stcb == NULL) {
@@ -239,23 +237,19 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
*/
int
-sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked)
{
- int unsent_data = 0;
+ int unsent_data;
unsigned int i;
struct sctp_stream_queue_pending *sp;
struct sctp_association *asoc;
- /* This function returns the number of streams that have
- * true unsent data on them. Note that as it looks through
- * it will clean up any places that have old data that
- * has been sent but left at top of stream queue.
+ /* This function returns if any stream has true unsent data on it.
+ * Note that as it looks through it will clean up any places that
+ * have old data that has been sent but left at top of stream queue.
*/
asoc = &stcb->asoc;
+ unsent_data = 0;
SCTP_TCB_SEND_LOCK(stcb);
if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
/* Check to see if some data queued */
@@ -282,6 +276,7 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked
}
atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1);
TAILQ_REMOVE(&stcb->asoc.strmout[i].outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, &asoc->strmout[i], sp, 1);
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -291,8 +286,13 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked
sp->data = NULL;
}
sctp_free_a_strmoq(stcb, sp, so_locked);
+ if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ unsent_data++;
+ }
} else {
unsent_data++;
+ }
+ if (unsent_data > 0) {
break;
}
}
@@ -324,7 +324,6 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE|SCTP_CWND_LOGGING_ENABLE)) {
sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_INITIALIZATION);
}
-
}
}
SCTP_TCB_SEND_LOCK(stcb);
@@ -337,14 +336,14 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
/* abandon the upper streams */
newcnt = ntohs(init->num_inbound_streams);
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
- if (chk->rec.data.stream_number >= newcnt) {
+ if (chk->rec.data.sid >= newcnt) {
TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
asoc->send_queue_cnt--;
- if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
#endif
}
if (chk->data != NULL) {
@@ -364,8 +363,9 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
for (i = newcnt; i < asoc->pre_open_streams; i++) {
outs = &asoc->strmout[i];
TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
+ atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1);
TAILQ_REMOVE(&outs->outqueue, sp, next);
- asoc->stream_queue_cnt--;
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1);
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL,
stcb, 0, sp, SCTP_SO_NOT_LOCKED);
if (sp->data) {
@@ -380,14 +380,19 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
sctp_free_a_strmoq(stcb, sp, SCTP_SO_NOT_LOCKED);
/*sa_ignore FREED_MEMORY*/
}
+ outs->state = SCTP_STREAM_CLOSED;
}
}
/* cut back the count */
asoc->pre_open_streams = newcnt;
}
SCTP_TCB_SEND_UNLOCK(stcb);
- asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams;
-
+ asoc->streamoutcnt = asoc->pre_open_streams;
+ if (asoc->strmout) {
+ for (i = 0; i < asoc->streamoutcnt; i++) {
+ asoc->strmout[i].state = SCTP_STREAM_OPEN;
+ }
+ }
/* EY - nr_sack: initialize highest tsn in nr_mapping_array */
asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
@@ -404,17 +409,9 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
if (asoc->strmin != NULL) {
/* Free the old ones */
- struct sctp_queued_to_read *ctl, *nctl;
-
for (i = 0; i < asoc->streamincnt; i++) {
- TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) {
- TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next);
- sctp_free_remote_addr(ctl->whoFrom);
- ctl->whoFrom = NULL;
- sctp_m_freem(ctl->data);
- ctl->data = NULL;
- sctp_free_a_readq(stcb, ctl);
- }
+ sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue);
+ sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue);
}
SCTP_FREE(asoc->strmin, SCTP_M_STRMI);
}
@@ -431,9 +428,11 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
return (-1);
}
for (i = 0; i < asoc->streamincnt; i++) {
- asoc->strmin[i].stream_no = i;
- asoc->strmin[i].last_sequence_delivered = 0xffff;
+ asoc->strmin[i].sid = i;
+ asoc->strmin[i].last_mid_delivered = 0xffffffff;
TAILQ_INIT(&asoc->strmin[i].inqueue);
+ TAILQ_INIT(&asoc->strmin[i].uno_inqueue);
+ asoc->strmin[i].pd_api_started = 0;
asoc->strmin[i].delivery_started = 0;
}
/*
@@ -457,41 +456,79 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh,
struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb,
struct sctp_nets *net, int *abort_no_unlock,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id)
{
struct sctp_association *asoc;
struct mbuf *op_err;
- int retval, abort_flag;
- uint32_t initack_limit;
+ int retval, abort_flag, cookie_found;
+ int initack_limit;
int nat_friendly = 0;
/* First verify that we have no illegal param's */
abort_flag = 0;
+ cookie_found = 0;
op_err = sctp_arethere_unrecognized_parameters(m,
(offset + sizeof(struct sctp_init_chunk)),
- &abort_flag, (struct sctp_chunkhdr *)cp, &nat_friendly);
+ &abort_flag, (struct sctp_chunkhdr *)cp,
+ &nat_friendly, &cookie_found);
if (abort_flag) {
/* Send an abort and notify peer */
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_no_unlock = 1;
return (-1);
}
+ if (!cookie_found) {
+ uint16_t len;
+
+ /* Only report the missing cookie parameter */
+ if (op_err != NULL) {
+ sctp_m_freem(op_err);
+ }
+ len = (uint16_t)(sizeof(struct sctp_error_missing_param) + sizeof(uint16_t));
+ /* We abort with an error of missing mandatory param */
+ op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
+ struct sctp_error_missing_param *cause;
+
+ SCTP_BUF_LEN(op_err) = len;
+ cause = mtod(op_err, struct sctp_error_missing_param *);
+ /* Subtract the reserved param */
+ cause->cause.code = htons(SCTP_CAUSE_MISSING_PARAM);
+ cause->cause.length = htons(len);
+ cause->num_missing_params = htonl(1);
+ cause->type[0] = htons(SCTP_STATE_COOKIE);
+ }
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
+ *abort_no_unlock = 1;
+ return (-3);
+ }
asoc = &stcb->asoc;
asoc->peer_supports_nat = (uint8_t)nat_friendly;
/* process the peer's parameters in the INIT-ACK */
retval = sctp_process_init((struct sctp_init_chunk *)cp, stcb);
if (retval < 0) {
+ if (op_err != NULL) {
+ sctp_m_freem(op_err);
+ }
return (retval);
}
initack_limit = offset + ntohs(cp->ch.chunk_length);
/* load all addresses */
if ((retval = sctp_load_addresses_from_init(stcb, m,
(offset + sizeof(struct sctp_init_chunk)), initack_limit,
- src, dst, NULL))) {
+ src, dst, NULL, stcb->asoc.port))) {
+ if (op_err != NULL) {
+ sctp_m_freem(op_err);
+ }
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Problem with address parameters");
SCTPDBG(SCTP_DEBUG_INPUT1,
@@ -499,7 +536,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, net->port);
@@ -541,52 +578,38 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
* primary.
*/
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, stcb,
- asoc->primary_destination, SCTP_FROM_SCTP_INPUT+SCTP_LOC_4);
+ 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);
+ 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) {
+ uint32_t inqueue_bytes, sb_free_now;
+ struct sctp_inpcb *inp;
- retval = sctp_send_cookie_echo(m, offset, stcb, net);
- if (retval < 0) {
- /*
- * No cookie, we probably should send a op error. But in any
- * case if there is no cookie in the INIT-ACK, we can
- * abandon the peer, its broke.
- */
- if (retval == -3) {
- /* We abort with an error of missing mandatory param */
- op_err = sctp_generate_cause(SCTP_CAUSE_MISSING_PARAM, "");
- if (op_err) {
- /*
- * Expand beyond to include the mandatory
- * param cookie
- */
- struct sctp_inv_mandatory_param *mp;
-
- SCTP_BUF_LEN(op_err) =
- sizeof(struct sctp_inv_mandatory_param);
- mp = mtod(op_err,
- struct sctp_inv_mandatory_param *);
- /* Subtract the reserved param */
- mp->length =
- htons(sizeof(struct sctp_inv_mandatory_param) - 2);
- mp->num_param = htonl(1);
- mp->param = htons(SCTP_STATE_COOKIE);
- mp->resv = 0;
- }
- sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
-#endif
- vrf_id, net->port);
- *abort_no_unlock = 1;
+ inp = stcb->sctp_ep;
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ sb_free_now = SCTP_SB_LIMIT_SND(stcb->sctp_socket) - (inqueue_bytes + stcb->asoc.sb_send_resv);
+
+ /* check if the amount free in the send socket buffer crossed the threshold */
+ if (inp->send_callback &&
+ (((inp->send_sb_threshold > 0) &&
+ (sb_free_now >= inp->send_sb_threshold) &&
+ (stcb->asoc.chunks_on_out_queue <= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) ||
+ (inp->send_sb_threshold == 0))) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ inp->send_callback(stcb->sctp_socket, sb_free_now, inp->ulp_info);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ }
}
- return (retval);
}
-
- return (0);
+#endif
+ retval = sctp_send_cookie_echo(m, offset, initack_limit, stcb, net);
+ return (retval);
}
static void
@@ -671,7 +694,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
f_net = TAILQ_FIRST(&stcb->asoc.nets);
if (f_net != r_net) {
/* first one on the list is NOT the primary
- * sctp_cmpaddr() is much more efficent if
+ * sctp_cmpaddr() is much more efficient if
* the primary is the first on the list, make it
* so.
*/
@@ -682,17 +705,26 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
}
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb,
+ 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);
+ 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,
@@ -703,7 +735,8 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
}
if (old_error_counter > 0) {
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
+ stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_5);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net);
}
if (r_net == stcb->asoc.primary_destination) {
@@ -721,20 +754,20 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
SCTP_MOBILITY_FASTHANDOFF)) &&
sctp_is_mobility_feature_on(stcb->sctp_ep,
SCTP_MOBILITY_PRIM_DELETED)) {
-
- sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER+SCTP_LOC_7);
+ sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED,
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_6);
if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_FASTHANDOFF)) {
+ SCTP_MOBILITY_FASTHANDOFF)) {
sctp_assoc_immediate_retrans(stcb,
- stcb->asoc.primary_destination);
+ stcb->asoc.primary_destination);
}
if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_BASE)) {
+ SCTP_MOBILITY_BASE)) {
sctp_move_chunks_from_net(stcb,
- stcb->asoc.deleted_primary);
+ stcb->asoc.deleted_primary);
}
- sctp_delete_prim_timer(stcb->sctp_ep, stcb,
- stcb->asoc.deleted_primary);
+ sctp_delete_prim_timer(stcb->sctp_ep, stcb);
}
}
}
@@ -742,22 +775,35 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
static int
sctp_handle_nat_colliding_state(struct sctp_tcb *stcb)
{
- /* return 0 means we want you to proceed with the abort
- * non-zero means no abort processing
- */
+ /*
+ * Return 0 means we want you to proceed with the abort
+ * non-zero means no abort processing.
+ */
+ uint32_t new_vtag;
struct sctpasochead *head;
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
+ new_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ 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);
+ } else {
+ return (0);
+ }
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) {
/* generate a new vtag and send init */
LIST_REMOVE(stcb, sctp_asocs);
- stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ stcb->asoc.my_vtag = new_vtag;
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
/* put it in the bucket in the vtag hash of assoc's for the system */
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
+ SCTP_INP_INFO_WUNLOCK();
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
return (1);
- }
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
+ } else {
/* treat like a case where the cookie expired i.e.:
* - dump current cookie.
* - generate a new vtag.
@@ -765,14 +811,14 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb)
*/
/* generate a new vtag and send init */
LIST_REMOVE(stcb, sctp_asocs);
- stcb->asoc.state &= ~SCTP_STATE_COOKIE_ECHOED;
- stcb->asoc.state |= SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, &stcb->asoc);
- stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ stcb->asoc.my_vtag = new_vtag;
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
/* put it in the bucket in the vtag hash of assoc's for the system */
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
+ SCTP_INP_INFO_WUNLOCK();
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
return (1);
}
@@ -794,12 +840,12 @@ sctp_handle_nat_missing_state(struct sctp_tcb *stcb,
return (1);
}
-
-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)
{
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
uint16_t len;
@@ -807,48 +853,49 @@ sctp_handle_abort(struct sctp_abort_chunk *abort,
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_missing_nat_state *natc;
+ struct sctp_error_cause *cause;
- natc = (struct sctp_missing_nat_state *)(abort + 1);
- error = ntohs(natc->cause);
+ 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",
+ 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",
+ 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 {
error = 0;
}
/* stop any receive timers */
- sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_6);
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_7);
/* notify user of the abort and clean up... */
sctp_abort_notification(stcb, 1, error, abort, SCTP_SO_NOT_LOCKED);
/* free the tcb */
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -856,13 +903,13 @@ sctp_handle_abort(struct sctp_abort_chunk *abort,
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
(void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_INPUT+SCTP_LOC_6);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_8);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n");
+ return (1);
}
static void
@@ -895,14 +942,14 @@ sctp_start_net_timers(struct sctp_tcb *stcb)
}
}
-
static void
sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag)
{
struct sctp_association *asoc;
int some_on_streamwheel;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ int old_state;
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
@@ -911,29 +958,49 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
if (stcb == NULL)
return;
asoc = &stcb->asoc;
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
return;
}
if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_shutdown_chunk)) {
/* Shutdown NOT the expected size */
return;
- } else {
- sctp_update_acked(stcb, cp, abort_flag);
- if (*abort_flag) {
- return;
- }
+ }
+ old_state = SCTP_GET_STATE(stcb);
+ sctp_update_acked(stcb, cp, abort_flag);
+ if (*abort_flag) {
+ return;
}
if (asoc->control_pdapi) {
/* With a normal shutdown
* we assume the end of last record.
*/
SCTP_INP_READ_LOCK(stcb->sctp_ep);
+ if (asoc->control_pdapi->on_strm_q) {
+ struct sctp_stream_in *strm;
+
+ strm = &asoc->strmin[asoc->control_pdapi->sinfo_stream];
+ if (asoc->control_pdapi->on_strm_q == SCTP_ON_UNORDERED) {
+ /* Unordered */
+ TAILQ_REMOVE(&strm->uno_inqueue, asoc->control_pdapi, next_instrm);
+ asoc->control_pdapi->on_strm_q = 0;
+ } else if (asoc->control_pdapi->on_strm_q == SCTP_ON_ORDERED) {
+ /* Ordered */
+ TAILQ_REMOVE(&strm->inqueue, asoc->control_pdapi, next_instrm);
+ asoc->control_pdapi->on_strm_q = 0;
+#ifdef INVARIANTS
+ } else {
+ panic("Unknown state on ctrl:%p on_strm_q:%d",
+ asoc->control_pdapi,
+ asoc->control_pdapi->on_strm_q);
+#endif
+ }
+ }
asoc->control_pdapi->end_added = 1;
asoc->control_pdapi->pdapi_aborted = 1;
asoc->control_pdapi = NULL;
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -946,18 +1013,19 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
return;
}
#endif
- sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (stcb->sctp_socket) {
+ sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
+ }
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
/* goto SHUTDOWN_RECEIVED state to block new requests */
if (stcb->sctp_socket) {
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) {
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_RECEIVED);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT)) {
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_RECEIVED);
/* notify upper layer that peer has initiated a shutdown */
sctp_ulp_notify(SCTP_NOTIFY_PEER_SHUTDOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
@@ -965,12 +1033,13 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
}
}
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
/*
* stop the shutdown timer, since we WILL move to
* SHUTDOWN-ACK-SENT.
*/
- sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_8);
+ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
+ net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_9);
}
/* Now is there unsent data on a stream somewhere? */
some_on_streamwheel = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED);
@@ -984,16 +1053,19 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
/* no outstanding data to send, so move on... */
/* send SHUTDOWN-ACK */
/* move to SHUTDOWN-ACK-SENT state */
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_stop_timers_for_shutdown(stcb);
- sctp_send_shutdown_ack(stcb, net);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep,
- stcb, net);
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) {
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
+ sctp_stop_timers_for_shutdown(stcb);
+ sctp_send_shutdown_ack(stcb, net);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
+ stcb->sctp_ep, stcb, net);
+ } else if (old_state == SCTP_STATE_SHUTDOWN_ACK_SENT) {
+ sctp_send_shutdown_ack(stcb, net);
+ }
}
}
@@ -1003,7 +1075,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
struct sctp_nets *net)
{
struct sctp_association *asoc;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -1015,15 +1087,15 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
asoc = &stcb->asoc;
/* process according to association state */
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
/* unexpected SHUTDOWN-ACK... do OOTB handling... */
sctp_send_shutdown_complete(stcb, net, 1);
SCTP_TCB_UNLOCK(stcb);
return;
}
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* unexpected SHUTDOWN-ACK... so ignore... */
SCTP_TCB_UNLOCK(stcb);
return;
@@ -1037,7 +1109,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
asoc->control_pdapi->pdapi_aborted = 1;
asoc->control_pdapi = NULL;
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
@@ -1050,19 +1122,20 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
}
#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
#ifdef INVARIANTS
if (!TAILQ_EMPTY(&asoc->send_queue) ||
!TAILQ_EMPTY(&asoc->sent_queue) ||
- !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) {
panic("Queues are not empty when handling SHUTDOWN-ACK");
}
#endif
/* stop the timer */
- sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_9);
+ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_10);
/* send SHUTDOWN-COMPLETE */
sctp_send_shutdown_complete(stcb, net, 0);
/* notify upper layer protocol */
@@ -1075,7 +1148,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
}
SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB but first save off the ep */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
@@ -1083,36 +1156,28 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_INPUT+SCTP_LOC_10);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_11);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
-/*
- * Skip past the param header and then we will find the chunk that caused the
- * problem. There are two possiblities 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,
- struct sctp_nets *net)
+sctp_process_unrecog_chunk(struct sctp_tcb *stcb, uint8_t chunk_type)
{
- 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);
+ sctp_asconf_cleanup(stcb);
break;
+ case SCTP_IFORWARD_CUM_TSN:
case SCTP_FORWARD_CUM_TSN:
stcb->asoc.prsctp_supported = 0;
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;
}
}
@@ -1124,12 +1189,9 @@ sctp_process_unrecog_chunk(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr,
* 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;
@@ -1154,66 +1216,72 @@ sctp_process_unrecog_param(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr)
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;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ uint32_t remaining_length, adjust;
+ uint16_t code, cause_code, cause_length;
+#if defined(__APPLE__) && !defined(__Userspace__)
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, ERROR 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, ERROR flags: %x\n",
ch->chunk_flags);
if (sctp_handle_nat_missing_state(stcb, net)) {
- return (0);
+ return (0);
}
break;
case SCTP_CAUSE_STALE_COOKIE:
@@ -1221,18 +1289,21 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
* We only act if we have echoed a cookie and are
* waiting.
*/
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) {
- int *p;
-
- p = (int *)((caddr_t)phdr + sizeof(*phdr));
- /* Save the time doubled */
- asoc->cookie_preserve_req = ntohl(*p) << 1;
+ if ((cause_length >= sizeof(struct sctp_error_stale_cookie)) &&
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
+ struct sctp_error_stale_cookie *stale_cookie;
+
+ stale_cookie = (struct sctp_error_stale_cookie *)cause;
+ /* stable_time is in usec, convert to msec. */
+ asoc->cookie_preserve_req = ntohl(stale_cookie->stale_time) / 1000;
+ /* Double it to be more robust on RTX. */
+ asoc->cookie_preserve_req *= 2;
asoc->stale_cookie_count++;
if (asoc->stale_cookie_count >
asoc->max_init_times) {
sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
/* now free the asoc */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -1241,16 +1312,15 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_INPUT+SCTP_LOC_11);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_12);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
return (-1);
}
/* blast back to INIT state */
sctp_toss_old_cookies(stcb, &stcb->asoc);
- asoc->state &= ~SCTP_STATE_COOKIE_ECHOED;
- asoc->state |= SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
sctp_stop_all_cookie_timers(stcb);
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
}
@@ -1262,17 +1332,28 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
* (or IPv4 for that matter) it does not matter. If
* they don't support that type of address, they can
* NOT possibly get that packet type... i.e. with no
- * IPv6 you can't recieve a IPv6 packet. so we can
+ * IPv6 you can't receive a IPv6 packet. so we can
* safely ignore this one. If we ever added support
* for HOSTNAME Addresses, then we would need to do
* something here.
*/
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);
+ }
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:
/*
@@ -1289,8 +1370,8 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
* 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:
/*
@@ -1302,15 +1383,19 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
*/
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);
}
@@ -1319,7 +1404,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh,
struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb,
struct sctp_nets *net, int *abort_no_unlock,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id)
@@ -1340,7 +1425,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, net->port);
@@ -1354,7 +1439,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, net->port);
@@ -1366,7 +1451,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, net->port);
@@ -1378,7 +1463,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, net->port);
@@ -1390,7 +1475,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, net->port);
@@ -1398,7 +1483,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
return (-1);
}
/* process according to association state... */
- switch (stcb->asoc.state & SCTP_STATE_MASK) {
+ switch (SCTP_GET_STATE(stcb)) {
case SCTP_STATE_COOKIE_WAIT:
/* this is the expected state for this chunk */
/* process the INIT-ACK parameters */
@@ -1417,7 +1502,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
}
if (sctp_process_init_ack(m, iphlen, offset, src, dst, sh, cp, stcb,
net, abort_no_unlock,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id) < 0) {
@@ -1426,7 +1511,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
}
/* update our state */
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to COOKIE-ECHOED state\n");
- SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_ECHOED);
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_ECHOED);
/* reset the RTO calc */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
@@ -1476,12 +1561,11 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctp_inpcb *inp, struct sctp_nets **netp,
struct sockaddr *init_src, int *notification,
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id, uint16_t port);
-
/*
* handle a state cookie for an existing association m: input packet mbuf
* chain-- assumes a pullup on IP/SCTP/COOKIE-ECHO chunk note: this is a
@@ -1495,7 +1579,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets **netp,
struct sockaddr *init_src, int *notification,
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id, uint16_t port)
@@ -1503,8 +1587,14 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
struct sctp_association *asoc;
struct sctp_init_chunk *init_cp, init_buf;
struct sctp_init_ack_chunk *initack_cp, initack_buf;
+ struct sctp_asconf_addr *aparam, *naparam;
+ struct sctp_asconf_ack *aack, *naack;
+ struct sctp_tmit_chunk *chk, *nchk;
+ struct sctp_stream_reset_list *strrst, *nstrrst;
+ struct sctp_queued_to_read *sq, *nsq;
struct sctp_nets *net;
struct mbuf *op_err;
+ struct timeval old;
int init_offset, initack_offset, i;
int retval;
int spec_flag = 0;
@@ -1523,13 +1613,13 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (how_indx < sizeof(asoc->cookie_how)) {
asoc->cookie_how[how_indx] = 1;
}
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
/* SHUTDOWN came in after sending INIT-ACK */
sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination);
op_err = sctp_generate_cause(SCTP_CAUSE_COOKIE_IN_SHUTDOWN, "");
sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, net->port);
if (how_indx < sizeof(asoc->cookie_how))
@@ -1583,7 +1673,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* ----INIT-ACK(tag=t)-->
* ----INIT(tag=t)------> *1
* <---INIT-ACK(tag=a)---
- * <----CE(tag=t)------------- *2
+ * <----CE(tag=t)------------- *2
*
* At point *1 we should be generating a different
* tag t'. Which means we would throw away the CE and send
@@ -1592,9 +1682,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 17;
return (NULL);
-
}
- switch (SCTP_GET_STATE(asoc)) {
+ switch (SCTP_GET_STATE(stcb)) {
case SCTP_STATE_COOKIE_WAIT:
case SCTP_STATE_COOKIE_ECHOED:
/*
@@ -1611,27 +1700,29 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
return (NULL);
}
/* we have already processed the INIT so no problem */
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb,
- net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_12);
- sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_13);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp,
+ stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_13);
+ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp,
+ stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_14);
/* update current state */
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
else
SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
+ SCTP_SET_STATE(stcb, SCTP_STATE_OPEN);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, asoc->primary_destination);
+ stcb->sctp_ep, stcb, NULL);
}
SCTP_STAT_INCR_GAUGE32(sctps_currestab);
sctp_stop_all_cookie_timers(stcb);
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- (inp->sctp_socket->so_qlimit == 0)
- ) {
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (!SCTP_IS_LISTENING(inp))) {
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
/*
@@ -1642,7 +1733,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
stcb->sctp_ep->sctp_flags |=
SCTP_PCB_FLAGS_CONNECTED;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -1655,7 +1746,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
}
#endif
soisconnected(stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -1665,16 +1756,16 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* 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);
+ sctp_calculate_rto(stcb, asoc, net, &old,
+ SCTP_RTT_FROM_NON_DATA);
if (stcb->asoc.sctp_autoclose_ticks &&
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))) {
sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE,
- inp, stcb, NULL);
+ inp, stcb, NULL);
}
break;
default:
@@ -1691,8 +1782,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* really should not fail.
*/
if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk),
- initack_offset, src, dst, init_src)) {
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, stcb->asoc.port)) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 4;
return (NULL);
@@ -1719,7 +1810,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* If nat support, and the below and stcb is established,
* send back a ABORT(colliding state) if we are established.
*/
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) &&
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) &&
(asoc->peer_supports_nat) &&
((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) &&
((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) ||
@@ -1735,8 +1826,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
op_err = sctp_generate_cause(SCTP_CAUSE_NAT_COLLIDING_STATE, "");
sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
return (NULL);
@@ -1772,7 +1863,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
}
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 8;
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_14);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_15);
sctp_stop_all_cookie_timers(stcb);
/*
* since we did not send a HB make sure we don't double
@@ -1782,10 +1874,12 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (stcb->asoc.sctp_autoclose_ticks &&
sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
- NULL);
+ NULL);
}
asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd);
- asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams);
+ if (asoc->pre_open_streams < asoc->streamoutcnt) {
+ asoc->pre_open_streams = asoc->streamoutcnt;
+ }
if (ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) {
/* Ok the peer probably discarded our
@@ -1795,8 +1889,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* kick us so it COULD still take a timeout
* to move these.. but it can't hurt to mark them.
*/
- struct sctp_tmit_chunk *chk;
- TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
+
+ TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
if (chk->sent < SCTP_DATAGRAM_RESEND) {
chk->sent = SCTP_DATAGRAM_RESEND;
sctp_flight_size_decrease(chk);
@@ -1805,7 +1899,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
spec_flag++;
}
}
-
}
/* process the INIT info (peer's info) */
retval = sctp_process_init(init_cp, stcb);
@@ -1815,25 +1908,24 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
return (NULL);
}
if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk),
- initack_offset, src, dst, init_src)) {
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, stcb->asoc.port)) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 10;
return (NULL);
}
- if ((asoc->state & SCTP_STATE_COOKIE_WAIT) ||
- (asoc->state & SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
*notification = SCTP_NOTIFY_ASSOC_UP;
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- (inp->sctp_socket->so_qlimit == 0)) {
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (!SCTP_IS_LISTENING(inp))) {
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
- stcb->sctp_ep->sctp_flags |=
- SCTP_PCB_FLAGS_CONNECTED;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -1846,24 +1938,24 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
}
#endif
soisconnected(stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
else
SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
SCTP_STAT_INCR_GAUGE32(sctps_currestab);
- } else if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ } else if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
SCTP_STAT_INCR_COUNTER32(sctps_restartestab);
} else {
SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
}
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
+ SCTP_SET_STATE(stcb, SCTP_STATE_OPEN);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, asoc->primary_destination);
+ stcb->sctp_ep, stcb, NULL);
}
sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, asoc);
@@ -1888,7 +1980,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
cookie->tie_tag_peer_vtag == asoc->peer_vtag_nonce &&
cookie->tie_tag_peer_vtag != 0) {
struct sctpasochead *head;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
@@ -1902,7 +1994,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
sh, cookie, cookie_len,
inp, netp, init_src,notification,
auth_skipped, auth_offset, auth_len,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port));
@@ -1913,42 +2005,43 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* temp code */
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 12;
- sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_15);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_16);
+ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_17);
/* notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_RESTART;
atomic_add_int(&stcb->asoc.refcnt, 1);
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_OPEN) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) {
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT)) {
SCTP_STAT_INCR_GAUGE32(sctps_currestab);
}
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
SCTP_STAT_INCR_GAUGE32(sctps_restartestab);
- } else if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
+ } else if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) {
SCTP_STAT_INCR_GAUGE32(sctps_collisionestab);
}
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
+ SCTP_SET_STATE(stcb, SCTP_STATE_OPEN);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, asoc->primary_destination);
+ stcb->sctp_ep, stcb, NULL);
- } else if (!(asoc->state & SCTP_STATE_SHUTDOWN_SENT)) {
+ } else if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) {
/* move to OPEN state, if not in SHUTDOWN_SENT */
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
+ SCTP_SET_STATE(stcb, SCTP_STATE_OPEN);
+ }
+ if (asoc->pre_open_streams < asoc->streamoutcnt) {
+ asoc->pre_open_streams = asoc->streamoutcnt;
}
- asoc->pre_open_streams =
- ntohs(initack_cp->init.num_outbound_streams);
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
-
asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1;
-
asoc->str_reset_seq_in = asoc->init_seq_number;
-
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
+ asoc->send_sack = 1;
if (asoc->mapping_array) {
memset(asoc->mapping_array, 0,
asoc->mapping_array_size);
@@ -1958,7 +2051,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
asoc->mapping_array_size);
}
SCTP_TCB_UNLOCK(stcb);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
SCTP_SOCKET_LOCK(so, 1);
#endif
@@ -1969,7 +2062,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* send up all the data */
SCTP_TCB_SEND_LOCK(stcb);
- sctp_report_all_outbound(stcb, 0, 1, SCTP_SO_LOCKED);
+ sctp_report_all_outbound(stcb, 0, SCTP_SO_LOCKED);
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
stcb->asoc.strmout[i].chunks_on_queues = 0;
#if defined(SCTP_DETAILED_STR_STATS)
@@ -1981,10 +2074,62 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
asoc->strmout[i].abandoned_sent[0] = 0;
asoc->strmout[i].abandoned_unsent[0] = 0;
#endif
- stcb->asoc.strmout[i].stream_no = i;
- stcb->asoc.strmout[i].next_sequence_send = 0;
+ stcb->asoc.strmout[i].sid = i;
+ stcb->asoc.strmout[i].next_mid_ordered = 0;
+ stcb->asoc.strmout[i].next_mid_unordered = 0;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
}
+ TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) {
+ TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp);
+ SCTP_FREE(strrst, SCTP_M_STRESET);
+ }
+ TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) {
+ TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next);
+ if (sq->data) {
+ sctp_m_freem(sq->data);
+ sq->data = NULL;
+ }
+ sctp_free_remote_addr(sq->whoFrom);
+ sq->whoFrom = NULL;
+ sq->stcb = NULL;
+ sctp_free_a_readq(stcb, sq);
+ }
+ TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) {
+ TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ if (chk->holds_key_ref)
+ sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED);
+ sctp_free_remote_addr(chk->whoTo);
+ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
+ SCTP_DECR_CHK_COUNT();
+ }
+ TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) {
+ TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ if (chk->holds_key_ref)
+ sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED);
+ sctp_free_remote_addr(chk->whoTo);
+ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
+ SCTP_DECR_CHK_COUNT();
+ }
+ TAILQ_FOREACH_SAFE(aparam, &asoc->asconf_queue, next, naparam) {
+ TAILQ_REMOVE(&asoc->asconf_queue, aparam, next);
+ SCTP_FREE(aparam,SCTP_M_ASC_ADDR);
+ }
+ TAILQ_FOREACH_SAFE(aack, &asoc->asconf_ack_sent, next, naack) {
+ TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next);
+ if (aack->data != NULL) {
+ sctp_m_freem(aack->data);
+ }
+ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), aack);
+ }
+
/* process the INIT-ACK info (my info) */
asoc->my_vtag = ntohl(initack_cp->init.initiate_tag);
asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd);
@@ -1993,7 +2138,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
LIST_REMOVE(stcb, sctp_asocs);
/* re-insert to new vtag position */
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag,
- SCTP_BASE_INFO(hashasocmark))];
+ SCTP_BASE_INFO(hashasocmark))];
/*
* put it in the bucket in the vtag hash of assoc's for the
* system
@@ -2003,7 +2148,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_INP_WUNLOCK(stcb->sctp_ep);
SCTP_INP_INFO_WUNLOCK();
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
asoc->total_flight = 0;
@@ -2023,8 +2168,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
net->hb_responded = 1;
if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk),
- initack_offset, src, dst, init_src)) {
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, stcb->asoc.port)) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 14;
@@ -2045,7 +2190,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
return (NULL);
}
-
/*
* handle a state cookie for a new association m: input packet mbuf chain--
* assumes a pullup on IP/SCTP/COOKIE-ECHO chunk note: this is a "split" mbuf
@@ -2060,7 +2204,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctp_inpcb *inp, struct sctp_nets **netp,
struct sockaddr *init_src, int *notification,
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id, uint16_t port)
@@ -2074,7 +2218,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
int retval;
int error = 0;
uint8_t auth_chunk_buf[SCTP_CHUNK_BUFFER_SIZE];
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
so = SCTP_INP_SO(inp);
@@ -2128,22 +2272,24 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
* and popluate
*/
- /*
+ /*
* Here we do a trick, we set in NULL for the proc/thread argument. We
* do this since in effect we only use the p argument when
* the socket is unbound and we must do an implicit bind.
* Since we are getting a cookie, we cannot be unbound.
*/
stcb = sctp_aloc_assoc(inp, init_src, &error,
- ntohl(initack_cp->init.initiate_tag), vrf_id,
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
- (struct thread *)NULL
-#elif defined(__Windows__)
- (PKTHREAD)NULL
+ ntohl(initack_cp->init.initiate_tag), vrf_id,
+ ntohs(initack_cp->init.num_outbound_streams),
+ port,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ (struct thread *)NULL,
+#elif defined(_WIN32) && !defined(__Userspace__)
+ (PKTHREAD)NULL,
#else
- (struct proc *)NULL
+ (struct proc *)NULL,
#endif
- );
+ SCTP_DONT_INITIALIZE_AUTH_PARAMS);
if (stcb == NULL) {
struct mbuf *op_err;
@@ -2153,16 +2299,12 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
return (NULL);
}
- /* get the correct sctp_nets */
- if (netp)
- *netp = sctp_findnet(stcb, init_src);
-
asoc = &stcb->asoc;
/* get scope variables out of cookie */
asoc->scope.ipv4_local_scope = cookie->ipv4_scope;
@@ -2185,31 +2327,30 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
* cookie was in flight. Only recourse is to abort the
* association.
*/
- atomic_add_int(&stcb->asoc.refcnt, 1);
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_INPUT+SCTP_LOC_16);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_18);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/* process the INIT-ACK info (my info) */
asoc->my_vtag = ntohl(initack_cp->init.initiate_tag);
asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd);
- asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams);
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
@@ -2219,39 +2360,38 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
/* process the INIT info (peer's info) */
- if (netp)
- retval = sctp_process_init(init_cp, stcb);
- else
- retval = 0;
+ retval = sctp_process_init(init_cp, stcb);
if (retval < 0) {
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_16);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/* load all addresses */
if (sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk), initack_offset,
- src, dst, init_src)) {
+ src, dst, init_src, port)) {
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_17);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/*
@@ -2265,8 +2405,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctp_auth_chunk *auth;
if (auth_len <= SCTP_CHUNK_BUFFER_SIZE) {
- auth = (struct sctp_auth_chunk *)
- sctp_m_getptr(m, auth_offset, auth_len, auth_chunk_buf);
+ auth = (struct sctp_auth_chunk *)sctp_m_getptr(m, auth_offset, auth_len, auth_chunk_buf);
} else {
auth = NULL;
}
@@ -2274,33 +2413,24 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
/* auth HMAC failed, dump the assoc and packet */
SCTPDBG(SCTP_DEBUG_AUTH1,
"COOKIE-ECHO: AUTH failed\n");
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_18);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_21);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
} else {
/* remaining chunks checked... good to go */
stcb->asoc.authenticated = 1;
}
}
- /* update current state */
- SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
- if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, asoc->primary_destination);
- }
- sctp_stop_all_cookie_timers(stcb);
- SCTP_STAT_INCR_COUNTER32(sctps_passiveestab);
- SCTP_STAT_INCR_GAUGE32(sctps_currestab);
/*
* if we're doing ASCONFs, check to see if we have any new local
@@ -2349,25 +2479,37 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
break;
#endif
default:
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_19);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_22);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
+ /* update current state */
+ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
+ SCTP_SET_STATE(stcb, SCTP_STATE_OPEN);
+ if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
+ stcb->sctp_ep, stcb, NULL);
+ }
+ sctp_stop_all_cookie_timers(stcb);
+ SCTP_STAT_INCR_COUNTER32(sctps_passiveestab);
+ SCTP_STAT_INCR_GAUGE32(sctps_currestab);
+
/* set up to notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_UP;
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- (inp->sctp_socket->so_qlimit == 0)) {
+ (!SCTP_IS_LISTENING(inp))) {
/*
* This is an endpoint that called connect() how it got a
* cookie that is NEW is a bit of a mystery. It must be that
@@ -2377,7 +2519,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
* a bit of protection is worth having..
*/
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
@@ -2389,11 +2531,11 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
}
#endif
soisconnected(stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
} else if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_socket->so_qlimit)) {
+ (SCTP_IS_LISTENING(inp))) {
/*
* We don't want to do anything with this one. Since it is
* the listening guy. The timer will get started for
@@ -2401,20 +2543,24 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
*/
;
}
- /* since we did not send a HB make sure we don't double things */
- if ((netp) && (*netp))
- (*netp)->hb_responded = 1;
-
if (stcb->asoc.sctp_autoclose_ticks &&
sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL);
}
- /* calculate the RTT */
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- if ((netp) && (*netp)) {
- (*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp,
- &cookie->time_entered, sctp_align_unsafe_makecopy,
- SCTP_RTT_FROM_NON_DATA);
+ *netp = sctp_findnet(stcb, init_src);
+ if (*netp != NULL) {
+ struct timeval old;
+
+ /*
+ * Since we did not send a HB, make sure we don't double
+ * things.
+ */
+ (*netp)->hb_responded = 1;
+ /* Calculate the RTT. */
+ old.tv_sec = cookie->time_entered.tv_sec;
+ old.tv_usec = cookie->time_entered.tv_usec;
+ sctp_calculate_rto(stcb, asoc, *netp, &old, SCTP_RTT_FROM_NON_DATA);
}
/* respond with a COOKIE-ACK */
sctp_send_cookie_ack(stcb);
@@ -2429,7 +2575,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
&store.sa, cookie->local_scope, cookie->site_scope,
cookie->ipv4_scope, cookie->loopback_scope);
-
return (stcb);
}
@@ -2457,7 +2602,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp,
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
struct sctp_tcb **locked_tcb,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id, uint16_t port)
@@ -2470,11 +2615,15 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
struct mbuf *m_sig;
uint8_t calc_sig[SCTP_SIGNATURE_SIZE], tmp_sig[SCTP_SIGNATURE_SIZE];
uint8_t *sig;
+#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+ uint8_t cookie_ok = 1;
+#else
uint8_t cookie_ok = 0;
+#endif
unsigned int sig_offset, cookie_offset;
unsigned int cookie_len;
struct timeval now;
- struct timeval time_expires;
+ struct timeval time_entered, time_expires;
int notification = 0;
struct sctp_nets *netl;
int had_a_existing_tcb = 0;
@@ -2499,8 +2648,14 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
cookie_offset = offset + sizeof(struct sctp_chunkhdr);
cookie_len = ntohs(cp->ch.chunk_length);
- if ((cookie->peerport != sh->src_port) &&
- (cookie->myport != sh->dest_port) &&
+ if (cookie_len < sizeof(struct sctp_cookie_echo_chunk) +
+ sizeof(struct sctp_init_chunk) +
+ sizeof(struct sctp_init_ack_chunk) + SCTP_SIGNATURE_SIZE) {
+ /* cookie too small */
+ return (NULL);
+ }
+ if ((cookie->peerport != sh->src_port) ||
+ (cookie->myport != sh->dest_port) ||
(cookie->my_vtag != sh->v_tag)) {
/*
* invalid ports or bad tag. Note that we always leave the
@@ -2511,12 +2666,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
*/
return (NULL);
}
- if (cookie_len < sizeof(struct sctp_cookie_echo_chunk) +
- sizeof(struct sctp_init_chunk) +
- sizeof(struct sctp_init_ack_chunk) + SCTP_SIGNATURE_SIZE) {
- /* cookie too small */
- return (NULL);
- }
#if defined(__Userspace__)
/*
* Recover the AF_CONN addresses within the cookie.
@@ -2588,7 +2737,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
return (NULL);
}
/* compare the received digest with the computed digest */
- if (memcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) != 0) {
+ if (timingsafe_bcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) != 0) {
/* try the old cookie? */
if ((cookie->time_entered.tv_sec == (long)ep->time_of_secret_change) &&
(ep->current_secret_number != ep->last_secret_number)) {
@@ -2597,7 +2746,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
(uint8_t *)ep->secret_key[(int)ep->last_secret_number],
SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0);
/* compare */
- if (memcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) == 0)
+ if (timingsafe_bcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) == 0)
cookie_ok = 1;
}
} else {
@@ -2626,17 +2775,35 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
return (NULL);
}
+ if (sctp_ticks_to_msecs(cookie->cookie_life) > SCTP_MAX_COOKIE_LIFE) {
+ SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: Invalid cookie lifetime\n");
+ return (NULL);
+ }
+ time_entered.tv_sec = cookie->time_entered.tv_sec;
+ time_entered.tv_usec = cookie->time_entered.tv_usec;
+ if ((time_entered.tv_sec < 0) ||
+ (time_entered.tv_usec < 0) ||
+ (time_entered.tv_usec >= 1000000)) {
+ /* Invalid time stamp. Cookie must have been modified. */
+ SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: Invalid time stamp\n");
+ return (NULL);
+ }
+ (void)SCTP_GETTIME_TIMEVAL(&now);
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
+ if (timercmp(&now, &time_entered, <)) {
+#else
+ if (timevalcmp(&now, &time_entered, <)) {
+#endif
+ SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: cookie generated in the future!\n");
+ return (NULL);
+ }
/*
- * check the cookie timestamps to be sure it's not stale
+ * Check the cookie timestamps to be sure it's not stale.
+ * cookie_life is in ticks, so we convert to seconds.
*/
- (void)SCTP_GETTIME_TIMEVAL(&now);
- /* 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__
+ time_expires.tv_sec = time_entered.tv_sec + sctp_ticks_to_secs(cookie->cookie_life);
+ time_expires.tv_usec = time_entered.tv_usec;
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (timercmp(&now, &time_expires, >))
#else
if (timevalcmp(&now, &time_expires, >))
@@ -2644,29 +2811,41 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
{
/* cookie is stale! */
struct mbuf *op_err;
- struct sctp_stale_cookie_msg *scm;
- uint32_t tim;
- op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_stale_cookie_msg),
- 0, M_NOWAIT, 1, MT_DATA);
+ struct sctp_error_stale_cookie *cause;
+ 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);
if (op_err == NULL) {
/* FOOBAR */
return (NULL);
}
/* Set the len */
- SCTP_BUF_LEN(op_err) = sizeof(struct sctp_stale_cookie_msg);
- scm = mtod(op_err, struct sctp_stale_cookie_msg *);
- scm->ph.param_type = htons(SCTP_CAUSE_STALE_COOKIE);
- scm->ph.param_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;
- scm->time_usec = htonl(tim);
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_stale_cookie);
+ cause = mtod(op_err, struct sctp_error_stale_cookie *);
+ cause->cause.code = htons(SCTP_CAUSE_STALE_COOKIE);
+ cause->cause.length = htons(sizeof(struct sctp_error_stale_cookie));
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
+ timersub(&now, &time_expires, &diff);
+#else
+ diff = now;
+ timevalsub(&diff, &time_expires);
+#endif
+ if ((uint32_t)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,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, l_inp->fibnum,
#endif
vrf_id, port);
return (NULL);
@@ -2768,7 +2947,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
cookie, cookie_len, *inp_p,
netp, to, &notification,
auth_skipped, auth_offset, auth_len,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -2779,7 +2958,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
src, dst, sh,
cookie, cookie_len, *inp_p, *stcb, netp, to,
&notification, auth_skipped, auth_offset, auth_len,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -2789,9 +2968,10 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
/* still no TCB... must be bad cookie-echo */
return (NULL);
}
-#if defined(__FreeBSD__)
- if ((*netp != NULL) && (mflowtype != M_HASHTYPE_NONE)) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (*netp != NULL) {
(*netp)->flowtype = mflowtype;
+ (*netp)->flowid = mflowid;
}
#endif
/*
@@ -2804,7 +2984,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
*/
if (netl == NULL) {
/* TSNH! Huh, why do I need to add this address here? */
- if (sctp_add_remote_addr(*stcb, to, NULL, SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC)) {
+ if (sctp_add_remote_addr(*stcb, to, NULL, port,
+ SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC)) {
return (NULL);
}
netl = sctp_findnet(*stcb, to);
@@ -2842,36 +3023,23 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
return (m);
}
oso = (*inp_p)->sctp_socket;
-#if (defined(__FreeBSD__) && __FreeBSD_version < 700000)
- /*
- * We do this to keep the sockets side happy during
- * the sonewcon ONLY.
- */
- NET_LOCK_GIANT();
-#endif
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
SCTP_TCB_UNLOCK((*stcb));
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_SET(oso->so_vnet);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(oso, 1);
#endif
so = sonewconn(oso, 0
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
,NULL
#endif
-#ifdef __Panda__
- ,NULL , (*inp_p)->def_vrf_id
-#endif
);
-#if (defined(__FreeBSD__) && __FreeBSD_version < 700000)
- NET_UNLOCK_GIANT();
-#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(oso, 1);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_RESTORE();
#endif
SCTP_TCB_LOCK((*stcb));
@@ -2879,7 +3047,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
if (so == NULL) {
struct mbuf *op_err;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *pcb_so;
#endif
/* Too many sockets */
@@ -2887,11 +3055,11 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
sctp_abort_association(*inp_p, NULL, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
pcb_so = SCTP_INP_SO(*inp_p);
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
SCTP_TCB_UNLOCK((*stcb));
@@ -2899,8 +3067,9 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
SCTP_TCB_LOCK((*stcb));
atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_20);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_23);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(pcb_so, 1);
#endif
return (NULL);
@@ -2934,6 +3103,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
inp->partial_delivery_point = (*inp_p)->partial_delivery_point;
inp->sctp_context = (*inp_p)->sctp_context;
inp->local_strreset_support = (*inp_p)->local_strreset_support;
+ inp->fibnum = (*inp_p)->fibnum;
inp->inp_starting_point_for_iterator = NULL;
#if defined(__Userspace__)
inp->ulp_info = (*inp_p)->ulp_info;
@@ -2963,14 +3133,14 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
* the accept state waiting for the accept!
*/
if (*stcb) {
- (*stcb)->asoc.state |= SCTP_STATE_IN_ACCEPT_QUEUE;
+ SCTP_ADD_SUBSTATE(*stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
}
sctp_move_pcb_and_assoc(*inp_p, inp, *stcb);
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
SCTP_TCB_UNLOCK((*stcb));
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb,
0);
#else
@@ -2979,7 +3149,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
SCTP_TCB_LOCK((*stcb));
atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
-
/* now we must check to see if we were aborted while
* the move was going on and the lock/unlock happened.
*/
@@ -3002,13 +3171,13 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
}
/* Pull it from the incomplete queue and wake the guy */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
SCTP_TCB_UNLOCK((*stcb));
SCTP_SOCKET_LOCK(so, 1);
#endif
soisconnected(so);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_TCB_LOCK((*stcb));
atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
SCTP_SOCKET_UNLOCK(so, 1);
@@ -3032,6 +3201,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED,
{
/* cp must not be used, others call this without a c-ack :-) */
struct sctp_association *asoc;
+ struct sctp_tmit_chunk *chk;
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_cookie_ack: handling COOKIE-ACK\n");
@@ -3040,37 +3210,42 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED,
}
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) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) {
/* state change only needed when I am in right state */
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
+ SCTP_SET_STATE(stcb, SCTP_STATE_OPEN);
sctp_start_net_timers(stcb);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, asoc->primary_destination);
-
+ stcb->sctp_ep, stcb, NULL);
}
/* update RTO */
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
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);
+ sctp_calculate_rto(stcb, asoc, net, &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);
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -3081,7 +3256,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED,
if ((stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) == 0) {
soisconnected(stcb->sctp_socket);
}
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -3101,7 +3276,6 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED,
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
stcb, net);
-
if (stcb->asoc.sctp_autoclose_ticks &&
sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_AUTOCLOSE)) {
sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE,
@@ -3128,11 +3302,13 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED,
closed_socket:
/* Toss the cookie if I can */
sctp_toss_old_cookies(stcb, asoc);
- if (!TAILQ_EMPTY(&asoc->sent_queue)) {
- /* Restart the timer if we have pending data */
- struct sctp_tmit_chunk *chk;
-
- chk = TAILQ_FIRST(&asoc->sent_queue);
+ /* Restart the timer if we have pending data */
+ TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
+ if (chk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (chk != NULL) {
sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
}
}
@@ -3167,18 +3343,18 @@ sctp_handle_ecn_echo(struct sctp_ecne_chunk *cp,
if (lchk == NULL) {
window_data_tsn = stcb->asoc.sending_seq - 1;
} else {
- window_data_tsn = lchk->rec.data.TSN_seq;
+ window_data_tsn = lchk->rec.data.tsn;
}
/* Find where it was sent to if possible. */
net = NULL;
TAILQ_FOREACH(lchk, &stcb->asoc.sent_queue, sctp_next) {
- if (lchk->rec.data.TSN_seq == tsn) {
+ if (lchk->rec.data.tsn == tsn) {
net = lchk->whoTo;
net->ecn_prev_cwnd = lchk->rec.data.cwnd_at_send;
break;
}
- if (SCTP_TSN_GT(lchk->rec.data.TSN_seq, tsn)) {
+ if (SCTP_TSN_GT(lchk->rec.data.tsn, tsn)) {
break;
}
}
@@ -3264,14 +3440,14 @@ sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sct
* 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;
}
@@ -3285,9 +3461,9 @@ sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sct
stcb->asoc.ecn_echo_cnt_onq--;
TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk,
sctp_next);
+ stcb->asoc.ctrl_queue_cnt--;
sctp_m_freem(chk->data);
chk->data = NULL;
- stcb->asoc.ctrl_queue_cnt--;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
if (override == 0) {
break;
@@ -3300,8 +3476,7 @@ static void
sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSED,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
- struct sctp_association *asoc;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
@@ -3310,9 +3485,8 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSE
if (stcb == NULL)
return;
- asoc = &stcb->asoc;
/* process according to association state */
- if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) {
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) {
/* unexpected SHUTDOWN-COMPLETE... so ignore... */
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown_complete: not in SCTP_STATE_SHUTDOWN_ACK_SENT --- ignore\n");
@@ -3324,19 +3498,20 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSE
sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
}
#ifdef INVARIANTS
- if (!TAILQ_EMPTY(&asoc->send_queue) ||
- !TAILQ_EMPTY(&asoc->sent_queue) ||
- !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ if (!TAILQ_EMPTY(&stcb->asoc.send_queue) ||
+ !TAILQ_EMPTY(&stcb->asoc.sent_queue) ||
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) {
panic("Queues are not empty when handling SHUTDOWN-COMPLETE");
}
#endif
/* stop the timer */
- sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_22);
+ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_24);
SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB */
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown_complete: calls free-asoc\n");
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -3344,8 +3519,9 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSE
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_23);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_25);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
return;
@@ -3357,18 +3533,19 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
{
switch (desc->chunk_type) {
case SCTP_DATA:
- /* find the tsn to resend (possibly */
+ case SCTP_IDATA:
+ /* find the tsn to resend (possibly) */
{
uint32_t tsn;
struct sctp_tmit_chunk *tp1;
tsn = ntohl(desc->tsn_ifany);
TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) {
- if (tp1->rec.data.TSN_seq == tsn) {
+ if (tp1->rec.data.tsn == tsn) {
/* found it */
break;
}
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, tsn)) {
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, tsn)) {
/* not found */
tp1 = NULL;
break;
@@ -3381,7 +3558,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
*/
SCTP_STAT_INCR(sctps_pdrpdnfnd);
TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) {
- if (tp1->rec.data.TSN_seq == tsn) {
+ if (tp1->rec.data.tsn == tsn) {
/* found it */
break;
}
@@ -3391,8 +3568,6 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
SCTP_STAT_INCR(sctps_pdrptsnnf);
}
if ((tp1) && (tp1->sent < SCTP_DATAGRAM_ACKED)) {
- uint8_t *ddp;
-
if (((flg & SCTP_BADCRC) == 0) &&
((flg & SCTP_FROM_MIDDLE_BOX) == 0)) {
return (0);
@@ -3407,20 +3582,18 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
SCTP_STAT_INCR(sctps_pdrpdizrw);
return (0);
}
- ddp = (uint8_t *) (mtod(tp1->data, caddr_t) +
- sizeof(struct sctp_data_chunk));
- {
- unsigned int iii;
-
- for (iii = 0; iii < sizeof(desc->data_bytes);
- iii++) {
- if (ddp[iii] != desc->data_bytes[iii]) {
- SCTP_STAT_INCR(sctps_pdrpbadd);
- return (-1);
- }
- }
+ if ((uint32_t)SCTP_BUF_LEN(tp1->data) <
+ SCTP_DATA_CHUNK_OVERHEAD(stcb) + SCTP_NUM_DB_TO_VERIFY) {
+ /* Payload not matching. */
+ SCTP_STAT_INCR(sctps_pdrpbadd);
+ return (-1);
+ }
+ if (memcmp(mtod(tp1->data, caddr_t) + SCTP_DATA_CHUNK_OVERHEAD(stcb),
+ desc->data_bytes, SCTP_NUM_DB_TO_VERIFY) != 0) {
+ /* Payload not matching. */
+ SCTP_STAT_INCR(sctps_pdrpbadd);
+ return (-1);
}
-
if (tp1->do_rtt) {
/*
* this guy had a RTO calculation
@@ -3447,12 +3620,13 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
if (TAILQ_EMPTY(&stcb->asoc.send_queue)) {
tp1->rec.data.fast_retran_tsn = stcb->asoc.sending_seq;
} else {
- tp1->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq;
+ tp1->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.tsn;
}
/* restart the timer */
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, tp1->whoTo, SCTP_FROM_SCTP_INPUT+SCTP_LOC_24);
+ stcb, tp1->whoTo,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_26);
sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, tp1->whoTo);
@@ -3461,8 +3635,8 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PDRP,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t)stcb,
- tp1->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)stcb,
+ tp1->rec.data.tsn);
}
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
sctp_flight_size_decrease(tp1);
@@ -3520,7 +3694,8 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
* this, otherwise we let the timer fire.
*/
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep,
- stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_25);
+ stcb, net,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_27);
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
}
break;
@@ -3568,6 +3743,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
/* resend last asconf ack */
sctp_send_asconf_ack(stcb);
break;
+ case SCTP_IFORWARD_CUM_TSN:
case SCTP_FORWARD_CUM_TSN:
send_forward_tsn(stcb, &stcb->asoc);
break;
@@ -3593,7 +3769,7 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *l
uint16_t temp;
/*
- * We set things to 0xffff since this is the last delivered sequence
+ * We set things to 0xffffffff since this is the last delivered sequence
* and we will be sending in 0 after the reset.
*/
@@ -3603,12 +3779,12 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *l
if (temp >= stcb->asoc.streamincnt) {
continue;
}
- stcb->asoc.strmin[temp].last_sequence_delivered = 0xffff;
+ stcb->asoc.strmin[temp].last_mid_delivered = 0xffffffff;
}
} else {
list = NULL;
for (i = 0; i < stcb->asoc.streamincnt; i++) {
- stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
+ stcb->asoc.strmin[i].last_mid_delivered = 0xffffffff;
}
}
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED);
@@ -3627,16 +3803,39 @@ sctp_reset_out_streams(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t
/* no such stream */
continue;
}
- stcb->asoc.strmout[temp].next_sequence_send = 0;
+ stcb->asoc.strmout[temp].next_mid_ordered = 0;
+ stcb->asoc.strmout[temp].next_mid_unordered = 0;
}
} else {
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
- stcb->asoc.strmout[i].next_sequence_send = 0;
+ stcb->asoc.strmout[i].next_mid_ordered = 0;
+ stcb->asoc.strmout[i].next_mid_unordered = 0;
}
}
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_SEND, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED);
}
+static void
+sctp_reset_clear_pending(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *list)
+{
+ uint32_t i;
+ uint16_t temp;
+
+ if (number_entries > 0) {
+ for (i = 0; i < number_entries; i++) {
+ temp = ntohs(list[i]);
+ if (temp >= stcb->asoc.streamoutcnt) {
+ /* no such stream */
+ continue;
+ }
+ stcb->asoc.strmout[temp].state = SCTP_STREAM_OPEN;
+ }
+ } else {
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ stcb->asoc.strmout[i].state = SCTP_STREAM_OPEN;
+ }
+ }
+}
struct sctp_stream_reset_request *
sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chunk **bchk)
@@ -3687,35 +3886,32 @@ static void
sctp_clean_up_stream_reset(struct sctp_tcb *stcb)
{
struct sctp_association *asoc;
- struct sctp_tmit_chunk *chk = stcb->asoc.str_reset;
+ struct sctp_tmit_chunk *chk;
- if (stcb->asoc.str_reset == NULL) {
+ asoc = &stcb->asoc;
+ chk = asoc->str_reset;
+ if (chk == NULL) {
return;
}
- asoc = &stcb->asoc;
-
- sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo, SCTP_FROM_SCTP_INPUT+SCTP_LOC_26);
- TAILQ_REMOVE(&asoc->control_send_queue,
- chk,
- sctp_next);
+ asoc->str_reset = NULL;
+ sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb,
+ NULL, SCTP_FROM_SCTP_INPUT + SCTP_LOC_28);
+ TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
+ asoc->ctrl_queue_cnt--;
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
- asoc->ctrl_queue_cnt--;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- /*sa_ignore NO_NULL_CHK*/
- stcb->asoc.str_reset = NULL;
}
-
static int
sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
uint32_t seq, uint32_t action,
struct sctp_stream_reset_response *respin)
{
uint16_t type;
- int lparm_len;
+ int lparam_len;
struct sctp_association *asoc = &stcb->asoc;
struct sctp_tmit_chunk *chk;
struct sctp_stream_reset_request *req_param;
@@ -3732,10 +3928,12 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
if (req_param != NULL) {
stcb->asoc.str_reset_seq_out++;
type = ntohs(req_param->ph.param_type);
- lparm_len = ntohs(req_param->ph.param_length);
+ lparam_len = ntohs(req_param->ph.param_length);
if (type == SCTP_STR_RESET_OUT_REQUEST) {
+ int no_clear = 0;
+
req_out_param = (struct sctp_stream_reset_out_request *)req_param;
- number_entries = (lparm_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t);
+ number_entries = (lparam_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t);
asoc->stream_reset_out_is_outstanding = 0;
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
@@ -3744,12 +3942,21 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
sctp_reset_out_streams(stcb, number_entries, req_out_param->list_of_streams);
} else if (action == SCTP_STREAM_RESET_RESULT_DENIED) {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_OUT, stcb, number_entries, req_out_param->list_of_streams, SCTP_SO_NOT_LOCKED);
+ } else if (action == SCTP_STREAM_RESET_RESULT_IN_PROGRESS) {
+ /* Set it up so we don't stop retransmitting */
+ asoc->stream_reset_outstanding++;
+ stcb->asoc.str_reset_seq_out--;
+ asoc->stream_reset_out_is_outstanding = 1;
+ no_clear = 1;
} else {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, req_out_param->list_of_streams, SCTP_SO_NOT_LOCKED);
}
+ if (no_clear == 0) {
+ sctp_reset_clear_pending(stcb, number_entries, req_out_param->list_of_streams);
+ }
} else if (type == SCTP_STR_RESET_IN_REQUEST) {
req_in_param = (struct sctp_stream_reset_in_request *)req_param;
- number_entries = (lparm_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t);
+ number_entries = (lparam_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t);
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action == SCTP_STREAM_RESET_RESULT_DENIED) {
@@ -3773,7 +3980,11 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
asoc->stream_reset_outstanding--;
if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) {
/* Put the new streams into effect */
- stcb->asoc.streamoutcnt += num_stream;
+ int i;
+ for (i = asoc->streamoutcnt; i < (asoc->streamoutcnt + num_stream); i++) {
+ asoc->strmout[i].state = SCTP_STREAM_OPEN;
+ }
+ asoc->streamoutcnt += num_stream;
sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0);
} else if (action == SCTP_STREAM_RESET_RESULT_DENIED) {
sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt,
@@ -3850,6 +4061,9 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
}
}
}
+ if (asoc->stream_reset_outstanding == 0) {
+ sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_NOT_LOCKED);
+ }
return (0);
}
@@ -3880,22 +4094,33 @@ sctp_handle_str_reset_request_in(struct sctp_tcb *stcb,
} else if (stcb->asoc.stream_reset_out_is_outstanding == 0) {
len = ntohs(req->ph.param_length);
number_entries = ((len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t));
- for (i = 0; i < number_entries; i++) {
- temp = ntohs(req->list_of_streams[i]);
- req->list_of_streams[i] = temp;
+ if (number_entries) {
+ for (i = 0; i < number_entries; i++) {
+ temp = ntohs(req->list_of_streams[i]);
+ if (temp >= stcb->asoc.streamoutcnt) {
+ asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED;
+ goto bad_boy;
+ }
+ req->list_of_streams[i] = temp;
+ }
+ for (i = 0; i < number_entries; i++) {
+ if (stcb->asoc.strmout[req->list_of_streams[i]].state == SCTP_STREAM_OPEN) {
+ stcb->asoc.strmout[req->list_of_streams[i]].state = SCTP_STREAM_RESET_PENDING;
+ }
+ }
+ } else {
+ /* Its all */
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN)
+ stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING;
+ }
}
asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED;
- sctp_add_stream_reset_out(chk, number_entries, req->list_of_streams,
- asoc->str_reset_seq_out,
- seq, (asoc->sending_seq - 1));
- asoc->stream_reset_out_is_outstanding = 1;
- asoc->str_reset = chk;
- sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo);
- stcb->asoc.stream_reset_outstanding++;
} else {
/* Can't do it, since we have sent one out */
asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_ERR_IN_PROGRESS;
}
+ bad_boy:
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
asoc->str_reset_seq_in++;
} else if (asoc->str_reset_seq_in - 1 == seq) {
@@ -3905,6 +4130,7 @@ sctp_handle_str_reset_request_in(struct sctp_tcb *stcb,
} else {
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO);
}
+ sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_NOT_LOCKED);
}
static int
@@ -4023,11 +4249,12 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
return;
}
+ liste->seq = seq;
liste->tsn = tsn;
liste->number_entries = number_entries;
memcpy(&liste->list_of_streams, req->list_of_streams, number_entries * sizeof(uint16_t));
TAILQ_INSERT_TAIL(&asoc->resetHead, liste, next_resp);
- asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED;
+ asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_IN_PROGRESS;
}
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
asoc->str_reset_seq_in++;
@@ -4092,20 +4319,28 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
/* copy off the old data */
for (i = 0; i < stcb->asoc.streamincnt; i++) {
TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
- stcb->asoc.strmin[i].stream_no = i;
- stcb->asoc.strmin[i].last_sequence_delivered = oldstrm[i].last_sequence_delivered;
+ TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue);
+ stcb->asoc.strmin[i].sid = i;
+ stcb->asoc.strmin[i].last_mid_delivered = oldstrm[i].last_mid_delivered;
stcb->asoc.strmin[i].delivery_started = oldstrm[i].delivery_started;
+ stcb->asoc.strmin[i].pd_api_started = oldstrm[i].pd_api_started;
/* now anything on those queues? */
- TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next, nctl) {
- TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next);
- TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next);
+ TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next_instrm, nctl) {
+ TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next_instrm);
+ TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next_instrm);
+ }
+ TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].uno_inqueue, next_instrm, nctl) {
+ TAILQ_REMOVE(&oldstrm[i].uno_inqueue, ctl, next_instrm);
+ TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].uno_inqueue, ctl, next_instrm);
}
}
/* Init the new streams */
for (i = stcb->asoc.streamincnt; i < num_stream; i++) {
TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
- stcb->asoc.strmin[i].stream_no = i;
- stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
+ TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue);
+ stcb->asoc.strmin[i].sid = i;
+ stcb->asoc.strmin[i].last_mid_delivered = 0xffffffff;
+ stcb->asoc.strmin[i].pd_api_started = 0;
stcb->asoc.strmin[i].delivery_started = 0;
}
SCTP_FREE(oldstrm, SCTP_M_STRMI);
@@ -4130,7 +4365,6 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]);
} else {
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO);
-
}
}
@@ -4165,7 +4399,7 @@ sctp_handle_str_reset_add_out_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk
mychk += num_stream;
if (mychk < 0x10000) {
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED;
- if (sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, 1, num_stream, 0, 1)) {
+ if (sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, num_stream, 0, 1)) {
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED;
}
} else {
@@ -4191,11 +4425,9 @@ sctp_handle_str_reset_add_out_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk
}
}
-#if !defined(__Panda__)
#ifdef __GNUC__
__attribute__ ((noinline))
#endif
-#endif
static int
sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset,
struct sctp_chunkhdr *ch_req)
@@ -4377,104 +4609,116 @@ static void
sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t limit)
{
- uint32_t bottle_bw, on_queue;
- uint16_t trunc_len;
- unsigned int chlen;
- unsigned int at;
struct sctp_chunk_desc desc;
- struct sctp_chunkhdr *ch;
-
- chlen = ntohs(cp->ch.chunk_length);
- chlen -= sizeof(struct sctp_pktdrop_chunk);
- /* XXX possible chlen underflow */
- if (chlen == 0) {
- ch = NULL;
- if (cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX)
+ struct sctp_chunkhdr *chk_hdr;
+ struct sctp_data_chunk *data_chunk;
+ struct sctp_idata_chunk *idata_chunk;
+ uint32_t bottle_bw, on_queue;
+ uint32_t offset, chk_len;
+ uint16_t pktdrp_len;
+ uint8_t pktdrp_flags;
+
+ KASSERT(sizeof(struct sctp_pktdrop_chunk) <= limit,
+ ("PKTDROP chunk too small"));
+ pktdrp_flags = cp->ch.chunk_flags;
+ pktdrp_len = ntohs(cp->ch.chunk_length);
+ KASSERT(limit <= pktdrp_len, ("Inconsistent limit"));
+ if (pktdrp_flags & SCTP_PACKET_TRUNCATED) {
+ if (ntohs(cp->trunc_len) <= pktdrp_len - sizeof(struct sctp_pktdrop_chunk)) {
+ /* The peer plays games with us. */
+ return;
+ }
+ }
+ limit -= sizeof(struct sctp_pktdrop_chunk);
+ offset = 0;
+ if (offset == limit) {
+ if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) {
SCTP_STAT_INCR(sctps_pdrpbwrpt);
+ }
+ } else if (offset + sizeof(struct sctphdr) > limit) {
+ /* Only a partial SCTP common header. */
+ SCTP_STAT_INCR(sctps_pdrpcrupt);
+ offset = limit;
} else {
- ch = (struct sctp_chunkhdr *)(cp->data + sizeof(struct sctphdr));
- chlen -= sizeof(struct sctphdr);
- /* XXX possible chlen underflow */
- memset(&desc, 0, sizeof(desc));
+ /* XXX: Check embedded SCTP common header. */
+ offset += sizeof(struct sctphdr);
}
- trunc_len = (uint16_t) ntohs(cp->trunc_len);
- if (trunc_len > limit) {
- trunc_len = limit;
- }
-
- /* now the chunks themselves */
- while ((ch != NULL) && (chlen >= sizeof(struct sctp_chunkhdr))) {
- desc.chunk_type = ch->chunk_type;
- /* get amount we need to move */
- at = ntohs(ch->chunk_length);
- if (at < sizeof(struct sctp_chunkhdr)) {
- /* corrupt chunk, maybe at the end? */
+ /* Now parse through the chunks themselves. */
+ while (offset < limit) {
+ if (offset + sizeof(struct sctp_chunkhdr) > limit) {
SCTP_STAT_INCR(sctps_pdrpcrupt);
break;
}
- if (trunc_len == 0) {
- /* we are supposed to have all of it */
- if (at > chlen) {
- /* corrupt skip it */
- SCTP_STAT_INCR(sctps_pdrpcrupt);
+ chk_hdr = (struct sctp_chunkhdr *)(cp->data + offset);
+ desc.chunk_type = chk_hdr->chunk_type;
+ /* get amount we need to move */
+ chk_len = (uint32_t)ntohs(chk_hdr->chunk_length);
+ if (chk_len < sizeof(struct sctp_chunkhdr)) {
+ /* Someone is lying... */
+ break;
+ }
+ if (desc.chunk_type == SCTP_DATA) {
+ if (stcb->asoc.idata_supported) {
+ /* Some is playing games with us. */
break;
}
- } else {
- /* is there enough of it left ? */
- if (desc.chunk_type == SCTP_DATA) {
- if (chlen < (sizeof(struct sctp_data_chunk) +
- sizeof(desc.data_bytes))) {
- break;
- }
- } else {
- if (chlen < sizeof(struct sctp_chunkhdr)) {
- break;
- }
+ if (chk_len <= sizeof(struct sctp_data_chunk)) {
+ /* Some is playing games with us. */
+ break;
}
- }
- if (desc.chunk_type == SCTP_DATA) {
- /* can we get out the tsn? */
- if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX))
+ if (chk_len < sizeof(struct sctp_data_chunk) + SCTP_NUM_DB_TO_VERIFY) {
+ /* Not enough data bytes available in the chunk. */
+ SCTP_STAT_INCR(sctps_pdrpnedat);
+ goto next_chunk;
+ }
+ if (offset + sizeof(struct sctp_data_chunk) + SCTP_NUM_DB_TO_VERIFY > limit) {
+ /* Not enough data in buffer. */
+ break;
+ }
+ data_chunk = (struct sctp_data_chunk *)(cp->data + offset);
+ memcpy(desc.data_bytes, data_chunk + 1, SCTP_NUM_DB_TO_VERIFY);
+ desc.tsn_ifany = data_chunk->dp.tsn;
+ if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) {
SCTP_STAT_INCR(sctps_pdrpmbda);
-
- if (chlen >= (sizeof(struct sctp_data_chunk) + sizeof(uint32_t))) {
- /* yep */
- struct sctp_data_chunk *dcp;
- uint8_t *ddp;
- unsigned int iii;
-
- dcp = (struct sctp_data_chunk *)ch;
- ddp = (uint8_t *) (dcp + 1);
- for (iii = 0; iii < sizeof(desc.data_bytes); iii++) {
- desc.data_bytes[iii] = ddp[iii];
- }
- desc.tsn_ifany = dcp->dp.tsn;
- } else {
- /* nope we are done. */
+ }
+ } else if (desc.chunk_type == SCTP_IDATA) {
+ if (!stcb->asoc.idata_supported) {
+ /* Some is playing games with us. */
+ break;
+ }
+ if (chk_len <= sizeof(struct sctp_idata_chunk)) {
+ /* Some is playing games with us. */
+ break;
+ }
+ if (chk_len < sizeof(struct sctp_idata_chunk) + SCTP_NUM_DB_TO_VERIFY) {
+ /* Not enough data bytes available in the chunk. */
SCTP_STAT_INCR(sctps_pdrpnedat);
+ goto next_chunk;
+ }
+ if (offset + sizeof(struct sctp_idata_chunk) + SCTP_NUM_DB_TO_VERIFY > limit) {
+ /* Not enough data in buffer. */
break;
}
+ idata_chunk = (struct sctp_idata_chunk *)(cp->data + offset);
+ memcpy(desc.data_bytes, idata_chunk + 1, SCTP_NUM_DB_TO_VERIFY);
+ desc.tsn_ifany = idata_chunk->dp.tsn;
+ if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) {
+ SCTP_STAT_INCR(sctps_pdrpmbda);
+ }
} else {
- if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX))
+ if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) {
SCTP_STAT_INCR(sctps_pdrpmbct);
+ }
}
-
- if (process_chunk_drop(stcb, &desc, net, cp->ch.chunk_flags)) {
+ if (process_chunk_drop(stcb, &desc, net, pktdrp_flags)) {
SCTP_STAT_INCR(sctps_pdrppdbrk);
break;
}
- if (SCTP_SIZE32(at) > chlen) {
- break;
- }
- chlen -= SCTP_SIZE32(at);
- if (chlen < sizeof(struct sctp_chunkhdr)) {
- /* done, none left */
- break;
- }
- ch = (struct sctp_chunkhdr *)((caddr_t)ch + SCTP_SIZE32(at));
+next_chunk:
+ offset += SCTP_SIZE32(chk_len);
}
/* Now update any rwnd --- possibly */
- if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX) == 0) {
+ if ((pktdrp_flags & SCTP_FROM_MIDDLE_BOX) == 0) {
/* From a peer, we get a rwnd report */
uint32_t a_rwnd;
@@ -4510,11 +4754,11 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
}
/* now middle boxes in sat networks get a cwnd bump */
- if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX) &&
+ if ((pktdrp_flags & SCTP_FROM_MIDDLE_BOX) &&
(stcb->asoc.sat_t3_loss_recovery == 0) &&
(stcb->asoc.sat_network)) {
/*
- * This is debateable but for sat networks it makes sense
+ * This is debatable but for sat networks it makes sense
* Note if a T3 timer has went off, we will prohibit any
* changes to cwnd until we exit the t3 loss recovery.
*/
@@ -4532,18 +4776,16 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
* cookie-echo processing - return NULL to discard the packet (ie. no asoc,
* bad packet,...) otherwise return the tcb for this packet
*/
-#if !defined(__Panda__)
#ifdef __GNUC__
__attribute__ ((noinline))
#endif
-#endif
static struct sctp_tcb *
sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets **netp, int *fwd_tsn_seen,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
#endif
uint32_t vrf_id, uint16_t port)
{
@@ -4552,7 +4794,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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;
@@ -4562,43 +4804,40 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
* 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;
int asconf_cnt = 0;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
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);
}
@@ -4621,9 +4860,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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,
@@ -4632,10 +4868,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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;
@@ -4672,8 +4905,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
* sctp_findassociation_ep_asconf().
*/
SCTP_INP_DECR_REF(inp);
- } else {
- locked_tcb = stcb;
}
/* now go back and verify any auth chunk to be sure */
@@ -4681,9 +4912,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
struct sctp_auth_chunk *auth;
if (auth_len <= SCTP_CHUNK_BUFFER_SIZE) {
- auth = (struct sctp_auth_chunk *)
- sctp_m_getptr(m, auth_offset,
- auth_len, chunk_buf);
+ auth = (struct sctp_auth_chunk *)sctp_m_getptr(m, auth_offset, auth_len, chunk_buf);
got_auth = 1;
auth_skipped = 0;
} else {
@@ -4693,10 +4922,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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;
@@ -4704,19 +4930,16 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
}
if (stcb == NULL) {
- snprintf(msg, sizeof(msg), "OOTB, %s:%d at %s\n", __FILE__, __LINE__, __FUNCTION__);
+ SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
/* no association, so it's out of the blue... */
sctp_handle_ootb(m, iphlen, *offset, src, dst, sh, inp, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
*offset = length;
- if (locked_tcb) {
- SCTP_TCB_UNLOCK(locked_tcb);
- }
return (NULL);
}
asoc = &stcb->asoc;
@@ -4728,13 +4951,14 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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);
}
@@ -4747,16 +4971,16 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
* 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\n", __FILE__, __LINE__, __FUNCTION__);
+ SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
sctp_handle_ootb(m, iphlen, *offset, src, dst,
sh, inp, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
return (NULL);
@@ -4769,8 +4993,8 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
"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);
@@ -4783,16 +5007,8 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
if (((ch->chunk_type == SCTP_SELECTIVE_ACK) ||
(ch->chunk_type == SCTP_NR_SELECTIVE_ACK) ||
(ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) &&
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ (SCTP_GET_STATE(stcb) == 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);
}
@@ -4807,66 +5023,36 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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) {
@@ -4886,7 +5072,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
/* check to see if this chunk required auth, but isn't */
if ((stcb != NULL) &&
- (stcb->asoc.auth_supported == 1) &&
sctp_auth_is_required_chunk(ch->chunk_type, stcb->asoc.local_auth_chunks) &&
!stcb->asoc.authenticated) {
/* "silently" ignore */
@@ -4899,15 +5084,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
/* The INIT chunk must be the only chunk. */
if ((num_chunks > 1) ||
(length - *offset > (int)SCTP_SIZE32(chk_length))) {
- op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
- "INIT not the only chunk");
- sctp_abort_association(inp, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
+ /* RFC 4960 requires that no ABORT is sent */
*offset = length;
+ if (stcb != NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
return (NULL);
}
/* Honor our resource limit. */
@@ -4915,7 +5096,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
sctp_abort_association(inp, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -4924,33 +5105,29 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
sctp_handle_init(m, iphlen, *offset, src, dst, sh,
(struct sctp_init_chunk *)ch, inp,
- stcb, &abort_no_unlock,
-#if defined(__FreeBSD__)
+ stcb, *netp, &abort_no_unlock,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#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 != stcb) {
- /* Very unlikely */
- SCTP_TCB_UNLOCK(locked_tcb);
- }
*offset = length;
- if (stcb) {
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (stcb != NULL) {
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4958,8 +5135,9 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_27);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_29);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -4970,18 +5148,15 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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,
stcb, *netp,
&abort_no_unlock,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id);
@@ -4999,44 +5174,57 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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;
-
- 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;
- }
+ 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, "%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) == 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) {
@@ -5045,78 +5233,15 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
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) {
@@ -5124,108 +5249,91 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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);
- }
- /* 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__);
+ return (stcb);
}
- 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,
@@ -5237,51 +5345,68 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
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;
return (NULL);
}
}
- /*
+ /*-
* First are we accepting? We do this again here
* since it is possible that a previous endpoint WAS
* listening responded to a INIT-ACK and then
* closed. We opened and bound.. and are now no
* longer listening.
+ *
+ * XXXGL: notes on checking listen queue length.
+ * 1) SCTP_IS_LISTENING() doesn't necessarily mean
+ * SOLISTENING(), because a listening "UDP type"
+ * socket isn't listening in terms of the socket
+ * layer. It is a normal data flow socket, that
+ * can fork off new connections. Thus, we should
+ * look into sol_qlen only in case we are !UDP.
+ * 2) Checking sol_qlen in general requires locking
+ * the socket, and this code lacks that.
*/
-
- if ((stcb == NULL) && (inp->sctp_socket->so_qlen >= inp->sctp_socket->so_qlimit)) {
+ if ((stcb == NULL) &&
+ (!SCTP_IS_LISTENING(inp) ||
+ (!(inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ inp->sctp_socket->sol_qlen >= inp->sctp_socket->sol_qlimit))) {
+#else
+ inp->sctp_socket->so_qlen >= inp->sctp_socket->so_qlimit))) {
+#endif
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit))) {
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
sctp_abort_association(inp, stcb, m, iphlen,
src, dst, sh, op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
@@ -5291,13 +5416,15 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
} else {
struct mbuf *ret_buf;
struct sctp_inpcb *linp;
+ struct sctp_tmit_chunk *chk;
+
if (stcb) {
linp = NULL;
} else {
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)) {
@@ -5306,7 +5433,10 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
}
- if (netp) {
+ if (netp != NULL) {
+ struct sctp_tcb *locked_stcb;
+
+ locked_stcb = stcb;
ret_buf =
sctp_handle_cookie_echo(m, iphlen,
*offset,
@@ -5317,22 +5447,28 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
auth_skipped,
auth_offset,
auth_len,
- &locked_tcb,
-#if defined(__FreeBSD__)
+ &locked_stcb,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
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");
@@ -5344,32 +5480,28 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
got_auth = 1;
auth_skipped = 0;
}
- if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
- /*
- * Restart the timer if we have
- * pending data
- */
- struct sctp_tmit_chunk *chk;
-
- chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
+ /* Restart the timer if we have pending data */
+ TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
+ if (chk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (chk != NULL) {
sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
}
}
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 */
if ((stcb) && (stcb->asoc.total_output_queue_size)) {
;
} else if (stcb) {
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -5377,93 +5509,52 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_27);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_30);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
*offset = length;
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);
}
@@ -5472,35 +5563,23 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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;
}
@@ -5520,35 +5599,37 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
break;
case SCTP_FORWARD_CUM_TSN:
- SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_FWD-TSN\n");
+ case SCTP_IFORWARD_CUM_TSN:
+ SCTPDBG(SCTP_DEBUG_INPUT3, "%s\n",
+ ch->chunk_type == SCTP_FORWARD_CUM_TSN ? "FORWARD_TSN" : "I_FORWARD_TSN");
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__);
+ if (((stcb->asoc.idata_supported == 1) && (ch->chunk_type == SCTP_FORWARD_CUM_TSN)) ||
+ ((stcb->asoc.idata_supported == 0) && (ch->chunk_type == SCTP_IFORWARD_CUM_TSN))) {
+ if (ch->chunk_type == SCTP_FORWARD_CUM_TSN) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s", "FORWARD-TSN chunk received when I-FORWARD-TSN was negotiated");
+ } else {
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-FORWARD-TSN chunk received when FORWARD-TSN was negotiated");
+ }
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ *offset = length;
+ return (NULL);
}
*fwd_tsn_seen = 1;
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -5556,40 +5637,33 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_29);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_31);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
*offset = length;
return (NULL);
}
+ /*
+ * For sending a SACK this looks like DATA
+ * chunks.
+ */
+ stcb->asoc.last_data_chunk_from = stcb->asoc.last_control_chunk_from;
sctp_handle_forward_tsn(stcb,
(struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset);
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)))) {
+ if ((stcb == 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;
@@ -5605,24 +5679,18 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
/* 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 ((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");
@@ -5643,19 +5711,15 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
(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 */
goto next_chunk;
}
got_auth = 1;
- if ((ch == NULL) || sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch,
- m, *offset)) {
+ if (sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch, m, *offset)) {
/* auth HMAC failed so dump the packet */
*offset = length;
return (stcb);
@@ -5668,40 +5732,32 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
default:
unknown_chunk:
/* it's an unknown chunk! */
- if ((ch->chunk_type & 0x40) && (stcb != NULL)) {
- struct mbuf *mm;
- struct sctp_paramhdr *phd;
+ if ((ch->chunk_type & 0x40) &&
+ (stcb != NULL) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_EMPTY) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_INUSE) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT)) {
+ struct sctp_gen_error_cause *cause;
int len;
- mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
- 0, M_NOWAIT, 1, MT_DATA);
- if (mm) {
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
+ 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
len = min(SCTP_SIZE32(chk_length), (uint32_t)(length - *offset));
- phd = mtod(mm, struct sctp_paramhdr *);
- /*
- * We cheat and use param type since
- * we did not bother to define a
- * error cause struct. They are the
- * same basic format with different
- * names.
- */
- phd->param_type = htons(SCTP_CAUSE_UNRECOG_CHUNK);
- phd->param_length = htons(len + sizeof(*phd));
- SCTP_BUF_LEN(mm) = sizeof(*phd);
- SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
- if (SCTP_BUF_NEXT(mm)) {
- if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(mm), SCTP_SIZE32(len) - len, NULL) == NULL) {
- sctp_m_freem(mm);
- } else {
+ cause = mtod(op_err, struct sctp_gen_error_cause *);
+ cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
+ cause->length = htons((uint16_t)(len + sizeof(struct sctp_gen_error_cause)));
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
+ SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
+ if (SCTP_BUF_NEXT(op_err) != NULL) {
#ifdef SCTP_MBUF_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- sctp_log_mbc(SCTP_BUF_NEXT(mm), SCTP_MBUF_ICOPY);
- }
-#endif
- sctp_queue_op_err(stcb, mm);
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
+ sctp_log_mbc(SCTP_BUF_NEXT(op_err), SCTP_MBUF_ICOPY);
}
+#endif
+ sctp_queue_op_err(stcb, op_err);
} else {
- sctp_m_freem(mm);
+ sctp_m_freem(op_err);
}
}
}
@@ -5713,7 +5769,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
break;
} /* switch (ch->chunk_type) */
-
next_chunk:
/* get the next chunk */
*offset += SCTP_SIZE32(chk_length);
@@ -5724,46 +5779,17 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
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);
}
-
-#ifdef INVARIANTS
-#ifdef __GNUC__
-__attribute__((noinline))
-#endif
-void
-sctp_validate_no_locks(struct sctp_inpcb *inp)
-{
-#ifndef __APPLE__
- struct sctp_tcb *lstcb;
-
- LIST_FOREACH(lstcb, &inp->sctp_asoc_list, sctp_tcblist) {
- if (mtx_owned(&lstcb->tcb_mtx)) {
- panic("Own lock on stcb at return from input");
- }
- }
- if (mtx_owned(&inp->inp_create_mtx)) {
- panic("Own create lock on inp");
- }
- if (mtx_owned(&inp->inp_mtx)) {
- panic("Own inp lock on inp");
- }
-#endif
-}
-#endif
-
/*
* common input chunk processing (v4 and v6)
*/
@@ -5771,12 +5797,10 @@ void
sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int length,
struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, struct sctp_chunkhdr *ch,
-#if !defined(SCTP_WITH_NO_CSUM)
uint8_t compute_crc,
-#endif
uint8_t ecn_bits,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
#endif
uint32_t vrf_id, uint16_t port)
{
@@ -5789,13 +5813,15 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
struct sctp_inpcb *inp = NULL, *inp_decr = NULL;
struct sctp_tcb *stcb = NULL;
struct sctp_nets *net = NULL;
+#if defined(__Userspace__)
+ struct socket *upcall_socket = NULL;
+#endif
SCTP_STAT_INCR(sctps_recvdatagrams);
#ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xE0, 1);
sctp_auditing(0, inp, stcb, net);
#endif
-#if !defined(SCTP_WITH_NO_CSUM)
if (compute_crc != 0) {
uint32_t check, calc_check;
@@ -5809,17 +5835,28 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
stcb = sctp_findassociation_addr(m, offset, src, dst,
sh, ch, &inp, &net, vrf_id);
#if defined(INET) || defined(INET6)
- if ((net != NULL) && (port != 0)) {
+ if ((ch->chunk_type != SCTP_INITIATION) &&
+ (net != NULL) && (net->port != port)) {
if (net->port == 0) {
- sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
+ /* UDP encapsulation turned on. */
+ net->mtu -= sizeof(struct udphdr);
+ if (stcb->asoc.smallest_mtu > net->mtu) {
+ sctp_pathmtu_adjustment(stcb, net->mtu);
+ }
+ } else if (port == 0) {
+ /* UDP encapsulation turned off. */
+ net->mtu += sizeof(struct udphdr);
+ /* XXX Update smallest_mtu */
}
net->port = port;
}
#endif
-#if defined(__FreeBSD__)
- if ((net != NULL) && (mflowtype != M_HASHTYPE_NONE)) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (net != NULL) {
net->flowtype = mflowtype;
+ net->flowid = mflowid;
}
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
#endif
if ((inp != NULL) && (stcb != NULL)) {
sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1);
@@ -5832,7 +5869,6 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
goto out;
}
}
-#endif
/* Destination port of 0 is illegal, based on RFC4960. */
if (sh->dest_port == 0) {
SCTP_STAT_INCR(sctps_hdrops);
@@ -5841,29 +5877,42 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
stcb = sctp_findassociation_addr(m, offset, src, dst,
sh, ch, &inp, &net, vrf_id);
#if defined(INET) || defined(INET6)
- if ((net != NULL) && (port != 0)) {
+ if ((ch->chunk_type != SCTP_INITIATION) &&
+ (net != NULL) && (net->port != port)) {
if (net->port == 0) {
- sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
+ /* UDP encapsulation turned on. */
+ net->mtu -= sizeof(struct udphdr);
+ if (stcb->asoc.smallest_mtu > net->mtu) {
+ sctp_pathmtu_adjustment(stcb, net->mtu);
+ }
+ } else if (port == 0) {
+ /* UDP encapsulation turned off. */
+ net->mtu += sizeof(struct udphdr);
+ /* XXX Update smallest_mtu */
}
net->port = port;
}
#endif
-#if defined(__FreeBSD__)
- if ((net != NULL) && (mflowtype != M_HASHTYPE_NONE)) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (net != NULL) {
net->flowtype = mflowtype;
+ net->flowid = mflowid;
}
#endif
if (inp == NULL) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+#endif
SCTP_STAT_INCR(sctps_noport);
-#if defined(__FreeBSD__) && (((__FreeBSD_version < 900000) && (__FreeBSD_version >= 804000)) || (__FreeBSD_version > 900000))
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) {
goto out;
}
#endif
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
sctp_send_shutdown_complete2(src, dst, sh,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
goto out;
@@ -5879,8 +5928,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
"Out of the blue");
sctp_send_abort(m, iphlen, src, dst,
sh, 0, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
}
@@ -5889,34 +5938,6 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
} else if (stcb == NULL) {
inp_decr = inp;
}
-#ifdef IPSEC
- /*-
- * I very much doubt any of the IPSEC stuff will work but I have no
- * idea, so I will leave it in place.
- */
- if (inp != NULL) {
- switch (dst->sa_family) {
-#ifdef INET
- case AF_INET:
- if (ipsec4_in_reject(m, &inp->ip_inp.inp)) {
- SCTP_STAT_INCR(sctps_hdrops);
- goto out;
- }
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- if (ipsec6_in_reject(m, &inp->ip_inp.inp)) {
- SCTP_STAT_INCR(sctps_hdrops);
- goto out;
- }
- break;
-#endif
- default:
- break;
- }
- }
-#endif
SCTPDBG(SCTP_DEBUG_INPUT1, "Ok, Common input processing called, m:%p iphlen:%d offset:%d length:%d stcb:%p\n",
(void *)m, iphlen, offset, length, (void *)stcb);
if (stcb) {
@@ -5936,26 +5957,42 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
*/
SCTP_TCB_UNLOCK(stcb);
stcb = NULL;
- snprintf(msg, sizeof(msg), "OOTB, %s:%d at %s\n", __FILE__, __LINE__, __FUNCTION__);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+#endif
+ SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
goto out;
}
-
}
+#if defined(__Userspace__)
+ if ((stcb != NULL) &&
+ !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL)) {
+ if (stcb->sctp_socket->so_head != NULL) {
+ upcall_socket = stcb->sctp_socket->so_head;
+ } else {
+ upcall_socket = stcb->sctp_socket;
+ }
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ }
+#endif
if (IS_SCTP_CONTROL(ch)) {
/* process the control portion of the SCTP packet */
/* sa_ignore NO_NULL_CHK */
stcb = sctp_process_control(m, iphlen, &offset, length,
src, dst, sh, ch,
inp, stcb, &net, &fwd_tsn_seen,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
if (stcb) {
@@ -5964,9 +6001,18 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
*/
inp = stcb->sctp_ep;
#if defined(INET) || defined(INET6)
- if ((net) && (port)) {
+ if ((ch->chunk_type != SCTP_INITIATION) &&
+ (net != NULL) && (net->port != port)) {
if (net->port == 0) {
- sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
+ /* UDP encapsulation turned on. */
+ net->mtu -= sizeof(struct udphdr);
+ if (stcb->asoc.smallest_mtu > net->mtu) {
+ sctp_pathmtu_adjustment(stcb, net->mtu);
+ }
+ } else if (port == 0) {
+ /* UDP encapsulation turned off. */
+ net->mtu += sizeof(struct udphdr);
+ /* XXX Update smallest_mtu */
}
net->port = port;
}
@@ -5984,31 +6030,42 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
* chunks
*/
if ((stcb != NULL) &&
- (stcb->asoc.auth_supported == 1) &&
sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks)) {
/* "silently" ignore */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+#endif
SCTP_STAT_INCR(sctps_recvauthmissing);
goto out;
}
if (stcb == NULL) {
/* out of the blue DATA chunk */
- snprintf(msg, sizeof(msg), "OOTB, %s:%d at %s\n", __FILE__, __LINE__, __FUNCTION__);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, NULL, m, NULL, sh);
+#endif
+ SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
goto out;
}
if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) {
/* v_tag mismatch! */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+#endif
SCTP_STAT_INCR(sctps_badvtag);
goto out;
}
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+#endif
if (stcb == NULL) {
/*
* no valid TCB for this packet, or we found it's a bad
@@ -6017,6 +6074,20 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
*/
goto out;
}
+#if defined(__Userspace__)
+ if ((upcall_socket == NULL) &&
+ !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL)) {
+ if (stcb->sctp_socket->so_head != NULL) {
+ upcall_socket = stcb->sctp_socket->so_head;
+ } else {
+ upcall_socket = stcb->sctp_socket;
+ }
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ }
+#endif
/*
* DATA chunk processing
@@ -6029,7 +6100,6 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
*/
if ((length > offset) &&
(stcb != NULL) &&
- (stcb->asoc.auth_supported == 1) &&
sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks) &&
!stcb->asoc.authenticated) {
/* "silently" ignore */
@@ -6046,33 +6116,25 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
* not get here unless we really did have a tag, so we don't
* abort if this happens, just dump the chunk silently.
*/
- switch (SCTP_GET_STATE(&stcb->asoc)) {
+ switch (SCTP_GET_STATE(stcb)) {
case SCTP_STATE_COOKIE_ECHOED:
/*
* we consider data with valid tags in this state
* 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:
/*
* We consider OOTB any data sent during asoc setup.
*/
- snprintf(msg, sizeof(msg), "OOTB, %s:%d at %s\n", __FILE__, __LINE__, __FUNCTION__);
+ SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
goto out;
@@ -6092,12 +6154,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
}
/* plow through the data chunks while length > offset */
retval = sctp_process_data(mm, iphlen, &offset, length,
- src, dst, sh,
- inp, stcb, net, &high_tsn,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
+ inp, stcb, net, &high_tsn);
if (retval == 2) {
/*
* The association aborted, NO UNLOCK needed since
@@ -6106,7 +6163,9 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
stcb = NULL;
goto out;
}
- data_processed = 1;
+ if (retval == 0) {
+ data_processed = 1;
+ }
/*
* Anything important needs to have been m_copy'ed in
* process_data
@@ -6151,10 +6210,11 @@ trigger_send:
if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
cnt_ctrl_ready = stcb->asoc.ctrl_queue_cnt - stcb->asoc.ecn_echo_cnt_onq;
}
- if (cnt_ctrl_ready ||
- ((un_sent) &&
- (stcb->asoc.peers_rwnd > 0 ||
- (stcb->asoc.peers_rwnd <= 0 && stcb->asoc.total_flight == 0)))) {
+ if (!TAILQ_EMPTY(&stcb->asoc.asconf_send_queue) ||
+ cnt_ctrl_ready ||
+ stcb->asoc.trigger_reset ||
+ ((un_sent > 0) &&
+ (stcb->asoc.peers_rwnd > 0 || stcb->asoc.total_flight == 0))) {
SCTPDBG(SCTP_DEBUG_INPUT3, "Calling chunk OUTPUT\n");
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
SCTPDBG(SCTP_DEBUG_INPUT3, "chunk OUTPUT returns\n");
@@ -6167,37 +6227,33 @@ trigger_send:
if (stcb != NULL) {
SCTP_TCB_UNLOCK(stcb);
}
+#if defined(__Userspace__)
+ if (upcall_socket != NULL) {
+ if (upcall_socket->so_upcall != NULL) {
+ if (soreadable(upcall_socket) ||
+ sowriteable(upcall_socket) ||
+ upcall_socket->so_error) {
+ (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
+ }
+ }
+ ACCEPT_LOCK();
+ SOCK_LOCK(upcall_socket);
+ sorele(upcall_socket);
+ }
+#endif
if (inp_decr != NULL) {
/* reduce ref-count */
SCTP_INP_WLOCK(inp_decr);
SCTP_INP_DECR_REF(inp_decr);
SCTP_INP_WUNLOCK(inp_decr);
}
-#ifdef INVARIANTS
- if (inp != NULL) {
- sctp_validate_no_locks(inp);
- }
-#endif
return;
}
#ifdef INET
#if !defined(__Userspace__)
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
void
sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
-#elif defined(__Panda__)
-void
-sctp_input(pakhandle_type i_pak)
-#else
-void
-#if __STDC__
-sctp_input(struct mbuf *i_pak,...)
-#else
-sctp_input(i_pak, va_alist)
- struct mbuf *i_pak;
-#endif
-#endif
{
struct mbuf *m;
int iphlen;
@@ -6208,32 +6264,22 @@ sctp_input(i_pak, va_alist)
struct sctphdr *sh;
struct sctp_chunkhdr *ch;
int length, offset;
-#if !defined(SCTP_WITH_NO_CSUM)
uint8_t compute_crc;
-#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint32_t mflowid;
uint8_t mflowtype;
+ uint16_t fibnum;
#endif
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__))
+#if defined(__Userspace__)
uint16_t port = 0;
#endif
-#if defined(__Panda__)
- /* This is Evil, but its the only way to make panda work right. */
- iphlen = sizeof(struct ip);
-#else
iphlen = off;
-#endif
if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) {
SCTP_RELEASE_PKT(i_pak);
return;
}
m = SCTP_HEADER_TO_CHAIN(i_pak);
-#ifdef __Panda__
- SCTP_DETACH_HEADER_FROM_CHAIN(i_pak);
- (void)SCTP_RELEASE_HEADER(i_pak);
-#endif
#ifdef SCTP_MBUF_LOGGING
/* Log in any input mbufs */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
@@ -6245,28 +6291,14 @@ sctp_input(i_pak, va_alist)
sctp_packet_log(m);
}
#endif
-#if defined(__FreeBSD__)
-#if __FreeBSD_version > 1000049
+#if defined(__FreeBSD__) && !defined(__Userspace__)
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
m->m_pkthdr.len,
if_name(m->m_pkthdr.rcvif),
(int)m->m_pkthdr.csum_flags, CSUM_BITS);
-#elif __FreeBSD_version >= 800000
- SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
- "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
- m->m_pkthdr.len,
- if_name(m->m_pkthdr.rcvif),
- m->m_pkthdr.csum_flags);
-#else
- SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
- "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
- m->m_pkthdr.len,
- m->m_pkthdr.rcvif->if_xname,
- m->m_pkthdr.csum_flags);
-#endif
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp_input(): Packet of length %d received on %s%d with csum_flags 0x%x.\n",
m->m_pkthdr.len,
@@ -6274,16 +6306,17 @@ sctp_input(i_pak, va_alist)
m->m_pkthdr.rcvif->if_unit,
m->m_pkthdr.csum_flags);
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
m->m_pkthdr.len,
m->m_pkthdr.rcvif->if_xname,
m->m_pkthdr.csum_flags);
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowid = m->m_pkthdr.flowid;
mflowtype = M_HASHTYPE_GET(m);
+ fibnum = M_GETFIB(m);
#endif
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
@@ -6313,26 +6346,22 @@ sctp_input(i_pak, va_alist)
#endif
dst.sin_port = sh->dest_port;
dst.sin_addr = ip->ip_dst;
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
NTOHS(ip->ip_len);
#endif
-#if defined(__Userspace_os_Linux) || defined(__Userspace_os_Windows)
+#if defined(__linux__) || (defined(_WIN32) && defined(__Userspace__))
ip->ip_len = ntohs(ip->ip_len);
#endif
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 1000000
- length = ntohs(ip->ip_len);
+#if defined(__Userspace__)
+#if defined(__linux__) || defined(_WIN32)
+ length = ip->ip_len;
#else
length = ip->ip_len + iphlen;
#endif
+#elif defined(__FreeBSD__)
+ length = ntohs(ip->ip_len);
#elif defined(__APPLE__)
length = ip->ip_len + iphlen;
-#elif defined(__Userspace__)
-#if defined(__Userspace_os_Linux) || defined(__Userspace_os_Windows)
- length = ip->ip_len;
-#else
- length = ip->ip_len + iphlen;
-#endif
#else
length = ip->ip_len;
#endif
@@ -6351,10 +6380,7 @@ sctp_input(i_pak, va_alist)
goto out;
}
ecn_bits = ip->ip_tos;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_recvnocrc);
-#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
SCTP_STAT_INCR(sctps_recvhwcrc);
compute_crc = 0;
@@ -6363,24 +6389,21 @@ sctp_input(i_pak, va_alist)
if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
((src.sin_addr.s_addr == dst.sin_addr.s_addr) ||
(SCTP_IS_IT_LOOPBACK(m)))) {
- SCTP_STAT_INCR(sctps_recvnocrc);
+ SCTP_STAT_INCR(sctps_recvhwcrc);
compute_crc = 0;
} else {
#endif
SCTP_STAT_INCR(sctps_recvswcrc);
compute_crc = 1;
}
-#endif
sctp_common_input_processing(&m, iphlen, offset, length,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
compute_crc,
-#endif
ecn_bits,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
out:
@@ -6390,11 +6413,13 @@ sctp_input(i_pak, va_alist)
return;
}
-#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_MCORE_INPUT) && defined(SMP)
extern int *sctp_cpuarry;
#endif
+#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int
sctp_input(struct mbuf **mp, int *offp, int proto SCTP_UNUSED)
{
@@ -6408,7 +6433,8 @@ void
sctp_input(struct mbuf *m, int off)
{
#endif
-#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_MCORE_INPUT) && defined(SMP)
if (mp_ncpus > 1) {
struct ip *ip;
struct sctphdr *sh;
@@ -6426,11 +6452,7 @@ sctp_input(struct mbuf *m, int off)
if (SCTP_BUF_LEN(m) < offset) {
if ((m = m_pullup(m, offset)) == NULL) {
SCTP_STAT_INCR(sctps_hdrops);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020
return (IPPROTO_DONE);
-#else
- return;
-#endif
}
}
ip = mtod(m, struct ip *);
@@ -6438,19 +6460,16 @@ sctp_input(struct mbuf *m, int off)
tag = htonl(sh->v_tag);
flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port);
m->m_pkthdr.flowid = flowid;
- M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
+ M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE_HASH);
}
cpu_to_use = sctp_cpuarry[flowid % mp_ncpus];
sctp_queue_to_mcore(m, off, cpu_to_use);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020
return (IPPROTO_DONE);
-#else
- return;
-#endif
}
#endif
+#endif
sctp_input_with_port(m, off, 0);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020
+#if defined(__FreeBSD__) && !defined(__Userspace__)
return (IPPROTO_DONE);
#endif
}
diff --git a/netwerk/sctp/src/netinet/sctp_input.h b/netwerk/sctp/src/netinet/sctp_input.h
index 5d45fef20c..47ae2127be 100755
--- a/netwerk/sctp/src/netinet/sctp_input.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.h 273168 2014-10-16 15:36:04Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_INPUT_H_
@@ -43,12 +45,10 @@ void
sctp_common_input_processing(struct mbuf **, int, int, int,
struct sockaddr *, struct sockaddr *,
struct sctphdr *, struct sctp_chunkhdr *,
-#if !defined(SCTP_WITH_NO_CSUM)
uint8_t,
-#endif
uint8_t,
-#if defined(__FreeBSD__)
- uint8_t, uint32_t,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t, uint32_t, uint16_t,
#endif
uint32_t, uint16_t);
@@ -56,9 +56,9 @@ struct sctp_stream_reset_request *
sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq,
struct sctp_tmit_chunk **bchk);
-void sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries,
- uint16_t *list);
-
+void
+sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries,
+ uint16_t *list);
int sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked);
diff --git a/netwerk/sctp/src/netinet/sctp_lock_userspace.h b/netwerk/sctp/src/netinet/sctp_lock_userspace.h
index 83a565c371..0aed34770a 100755
--- a/netwerk/sctp/src/netinet/sctp_lock_userspace.h
+++ b/netwerk/sctp/src/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.
@@ -31,7 +33,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#endif
@@ -66,7 +68,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_WQ_ADDR_DESTROY()
#define SCTP_WQ_ADDR_LOCK()
#define SCTP_WQ_ADDR_UNLOCK()
-
+#define SCTP_WQ_ADDR_LOCK_ASSERT()
#define SCTP_IPI_ADDR_INIT()
#define SCTP_IPI_ADDR_DESTROY()
@@ -74,20 +76,19 @@ __FBSDID("$FreeBSD$");
#define SCTP_IPI_ADDR_WLOCK()
#define SCTP_IPI_ADDR_RUNLOCK()
#define SCTP_IPI_ADDR_WUNLOCK()
+#define SCTP_IPI_ADDR_LOCK_ASSERT()
+#define SCTP_IPI_ADDR_WLOCK_ASSERT()
#define SCTP_IPI_ITERATOR_WQ_INIT()
#define SCTP_IPI_ITERATOR_WQ_DESTROY()
#define SCTP_IPI_ITERATOR_WQ_LOCK()
#define SCTP_IPI_ITERATOR_WQ_UNLOCK()
-
#define SCTP_IP_PKTLOG_INIT()
#define SCTP_IP_PKTLOG_LOCK()
#define SCTP_IP_PKTLOG_UNLOCK()
#define SCTP_IP_PKTLOG_DESTROY()
-
-
#define SCTP_INP_READ_INIT(_inp)
#define SCTP_INP_READ_DESTROY(_inp)
#define SCTP_INP_READ_LOCK(_inp)
@@ -98,9 +99,10 @@ __FBSDID("$FreeBSD$");
#define SCTP_INP_LOCK_DESTROY(_inp)
#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp)
-
#define SCTP_INP_RLOCK(_inp)
#define SCTP_INP_WLOCK(_inp)
+#define SCTP_INP_RLOCK_ASSERT(_inp)
+#define SCTP_INP_WLOCK_ASSERT(_inp)
#define SCTP_INP_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */
@@ -212,14 +214,6 @@ __FBSDID("$FreeBSD$");
} while (0)
-/* not sure if __Userspace__ needs these (but copied nonetheless...) */
-#if defined(SCTP_SO_LOCK_TESTING)
-#define SCTP_INP_SO(sctpinp) (sctpinp)->ip_inp.inp.inp_socket
-#define SCTP_SOCKET_LOCK(so, refcnt)
-#define SCTP_SOCKET_UNLOCK(so, refcnt)
-#endif
-
-
/* these were in sctp_lock_empty.h but aren't in sctp_lock_bsd.h ... */
#if 0
#define SCTP_IPI_ADDR_LOCK()
diff --git a/netwerk/sctp/src/netinet/sctp_os.h b/netwerk/sctp/src/netinet/sctp_os.h
index 48883811a1..0e03ce9e59 100755
--- a/netwerk/sctp/src/netinet/sctp_os.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_os.h 235828 2012-05-23 11:26:28Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_os.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_OS_H_
@@ -62,25 +64,18 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_os.h 235828 2012-05-23 11:26:28Z tuexe
* SCTP_ZONE_DESTROY(zone)
*/
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <netinet/sctp_os_bsd.h>
#else
#define MODULE_GLOBAL(_B) (_B)
#endif
-
#if defined(__Userspace__)
#include <netinet/sctp_os_userspace.h>
#endif
-
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#include <netinet/sctp_os_macosx.h>
#endif
-
-#if defined(__Panda__)
-#include <ip/sctp/sctp_os_iox.h>
-#endif
-
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
#include <netinet/sctp_os_windows.h>
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_os_userspace.h b/netwerk/sctp/src/netinet/sctp_os_userspace.h
index 46d6ba9c26..1476660540 100755
--- a/netwerk/sctp/src/netinet/sctp_os_userspace.h
+++ b/netwerk/sctp/src/netinet/sctp_os_userspace.h
@@ -1,9 +1,10 @@
/*-
+ * 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.
* Copyright (c) 2008-2011, by Brad Penoff. All rights reserved.
- * Copyright (c) 2020 by Moonchild Productions. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,37 +43,67 @@
#include <errno.h>
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#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
+enum {
+ C_SIGNAL = 0,
+ C_BROADCAST = 1,
+ C_MAX_EVENTS = 2
+};
+typedef struct
+{
+ u_int waiters_count;
+ CRITICAL_SECTION waiters_count_lock;
+ HANDLE events_[C_MAX_EVENTS];
+} userland_cond_t;
+void InitializeXPConditionVariable(userland_cond_t *);
+void DeleteXPConditionVariable(userland_cond_t *);
+int SleepXPConditionVariable(userland_cond_t *, userland_mutex_t *);
+void WakeAllXPConditionVariable(userland_cond_t *);
+#define InitializeConditionVariable(cond) InitializeXPConditionVariable(cond)
+#define DeleteConditionVariable(cond) DeleteXPConditionVariable(cond)
+#define SleepConditionVariableCS(cond, mtx, time) SleepXPConditionVariable(cond, mtx)
+#define WakeAllConditionVariable(cond) WakeAllXPConditionVariable(cond)
+#else
#define DeleteConditionVariable(cond)
typedef CONDITION_VARIABLE userland_cond_t;
+#endif
typedef HANDLE userland_thread_t;
#define ADDRESS_FAMILY unsigned __int8
#define IPVERSION 4
#define MAXTTL 255
+/* VS2010 comes with stdint.h */
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
#include <stdint.h>
+#else
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef __int32 int32_t;
+typedef unsigned __int16 uint16_t;
+typedef __int16 int16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int8 int8_t;
+#endif
#ifndef _SIZE_T_DEFINED
-#define size_t __int32
-#endif
-#define u_long unsigned __int64
-#define u_int unsigned __int32
-#define u_int32_t unsigned __int32
-#define u_int16_t unsigned __int16
-#define u_int8_t unsigned __int8
-#define u_char unsigned char
-#define n_short unsigned __int16
-#define u_short unsigned __int16
-#define n_time unsigned __int32
-#define sa_family_t unsigned __int8
-#define ssize_t __int64
+#typedef __int32 size_t;
+#endif
+typedef unsigned __int32 u_int;
+typedef unsigned char u_char;
+typedef unsigned __int16 u_short;
+typedef unsigned __int8 sa_family_t;
+#ifndef _SSIZE_T_DEFINED
+typedef __int64 ssize_t;
+#endif
+#if !defined(__MINGW32__)
#define __func__ __FUNCTION__
-
+#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#endif
@@ -186,6 +217,19 @@ typedef char* caddr_t;
#define bzero(buf, len) memset(buf, 0, len)
#define bcopy(srcKey, dstKey, len) memcpy(dstKey, srcKey, len)
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900) && !defined(__MINGW32__)
+#define SCTP_SNPRINTF(data, size, format, ...) \
+ if (_snprintf_s(data, size, _TRUNCATE, format, __VA_ARGS__) < 0) { \
+ data[0] = '\0'; \
+ }
+#else
+#define SCTP_SNPRINTF(data, ...) \
+ if (snprintf(data, __VA_ARGS__) < 0 ) { \
+ data[0] = '\0'; \
+ }
+#endif
+
#define inline __inline
#define __inline__ __inline
#define MSG_EOR 0x8 /* data completes record */
@@ -239,7 +283,7 @@ typedef char* caddr_t;
#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(__DragonFly__) || defined(__FreeBSD__) || defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__native_client__) || defined(__Fuchsia__) || defined(__EMSCRIPTEN_PTHREADS__)
#include <pthread.h>
#endif
typedef pthread_mutex_t userland_mutex_t;
@@ -247,7 +291,7 @@ typedef pthread_cond_t userland_cond_t;
typedef pthread_t userland_thread_t;
#endif
-#if defined(__Userspace_os_Windows) || defined(__Userspace_os_NaCl)
+#if defined(_WIN32) || defined(__native_client__)
#define IFNAMSIZ 64
@@ -289,7 +333,7 @@ struct ip {
u_char ip_ttl;
u_char ip_p;
u_short ip_sum;
- struct in_addr ip_src, ip_dst;
+ struct in_addr ip_src, ip_dst;
};
struct ifaddrs {
@@ -310,7 +354,7 @@ struct udphdr {
};
struct iovec {
- unsigned long len;
+ size_t len;
char *buf;
};
@@ -341,43 +385,9 @@ struct ifkpi {
int ifk_value;
} ifk_data;
};
-
-struct ifreq {
- char ifr_name[16];
- union {
- struct sockaddr ifru_addr;
- struct sockaddr ifru_dstaddr;
- struct sockaddr ifru_broadaddr;
- short ifru_flags;
- int ifru_metric;
- int ifru_mtu;
- int ifru_phys;
- int ifru_media;
- int ifru_intval;
- char* ifru_data;
- struct ifdevmtu ifru_devmtu;
- struct ifkpi ifru_kpi;
- uint32_t ifru_wake_flags;
- } ifr_ifru;
-#define ifr_addr ifr_ifru.ifru_addr
-#define ifr_dstaddr ifr_ifru.ifru_dstaddr
-#define ifr_broadaddr ifr_ifru.ifru_broadaddr
-#define ifr_flags ifr_ifru.ifru_flags[0]
-#define ifr_prevflags ifr_ifru.ifru_flags[1]
-#define ifr_metric ifr_ifru.ifru_metric
-#define ifr_mtu ifr_ifru.ifru_mtu
-#define ifr_phys ifr_ifru.ifru_phys
-#define ifr_media ifr_ifru.ifru_media
-#define ifr_data ifr_ifru.ifru_data
-#define ifr_devmtu ifr_ifru.ifru_devmtu
-#define ifr_intval ifr_ifru.ifru_intval
-#define ifr_kpi ifr_ifru.ifru_kpi
-#define ifr_wake_flags ifr_ifru.ifru_wake_flags
-};
-
#endif
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
int Win_getifaddrs(struct ifaddrs**);
#define getifaddrs(interfaces) (int)Win_getifaddrs(interfaces)
int win_if_nametoindex(const char *);
@@ -388,9 +398,9 @@ int win_if_nametoindex(const char *);
#define mtx_unlock(arg1)
#define mtx_assert(arg1,arg2)
#define MA_OWNED 7 /* sys/mutex.h typically on FreeBSD */
-#if !defined(__Userspace_os_FreeBSD)
+#if !defined(__FreeBSD__)
struct mtx {int dummy;};
-#if !defined(__Userspace_os_NetBSD)
+#if !defined(__NetBSD__)
struct selinfo {int dummy;};
#endif
struct sx {int dummy;};
@@ -398,6 +408,7 @@ struct sx {int dummy;};
#include <stdio.h>
#include <string.h>
+#include <stdbool.h>
/* #include <sys/param.h> in FreeBSD defines MSIZE */
/* #include <sys/ktr.h> */
/* #include <sys/systm.h> */
@@ -420,22 +431,22 @@ struct sx {int dummy;};
#include <user_mbuf.h>
/* #include <sys/uio.h> */
/* #include <sys/lock.h> */
-#if defined(__FreeBSD__) && __FreeBSD_version > 602000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/rwlock.h>
#endif
/* #include <sys/kthread.h> */
-#if defined(__FreeBSD__) && __FreeBSD_version > 602000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#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)
+#if defined(__APPLE__)
/* was a 0 byte file. needed for structs if_data(64) and net_event_data */
#include <net/if_var.h>
#endif
-#if defined(__Userspace_os_FreeBSD)
+#if defined(__FreeBSD__)
#include <net/if_types.h>
/* #include <net/if_var.h> was a 0 byte file. causes struct mtx redefinition */
#endif
@@ -443,7 +454,7 @@ struct sx {int dummy;};
* userspace as well? */
/* on FreeBSD, this results in a redefintion of struct route */
/* #include <net/route.h> */
-#if !defined(__Userspace_os_Windows) && !defined(__Userspace_os_NaCl)
+#if !defined(_WIN32) && !defined(__native_client__)
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -459,7 +470,7 @@ struct sx {int dummy;};
/* for getifaddrs */
#include <sys/types.h>
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#if defined(INET) || defined(INET6)
#include <ifaddrs.h>
#endif
@@ -469,6 +480,8 @@ struct sx {int dummy;};
/* for close, etc. */
#include <unistd.h>
+/* for gettimeofday */
+#include <sys/time.h>
#endif
/* lots of errno's used and needed in userspace */
@@ -476,7 +489,7 @@ struct sx {int dummy;};
/* for offsetof */
#include <stddef.h>
-#if defined(SCTP_PROCESS_LEVEL_LOCKS) && !defined(__Userspace_os_Windows)
+#if defined(SCTP_PROCESS_LEVEL_LOCKS) && !defined(_WIN32)
/* for pthread_mutex_lock, pthread_mutex_unlock, etc. */
#include <pthread.h>
#endif
@@ -487,22 +500,21 @@ struct sx {int dummy;};
#endif /* IPSEC */
#ifdef INET6
-#if defined(__Userspace_os_FreeBSD)
+#if defined(__FreeBSD__)
#include <sys/domain.h>
#endif
#ifdef IPSEC
#include <netipsec/ipsec6.h>
#endif
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
#endif
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_Linux) || defined(__Userspace_os_NetBSD) || defined(__Userspace_os_OpenBSD) || defined(__Userspace_os_Windows)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(_WIN32) || defined(__EMSCRIPTEN__)
#include "user_ip6_var.h"
#else
#include <netinet6/ip6_var.h>
#endif
-#if defined(__Userspace_os_FreeBSD)
+#if defined(__FreeBSD__)
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6protosw.h>
/* #include <netinet6/nd6.h> was a 0 byte file */
@@ -517,7 +529,7 @@ struct sx {int dummy;};
#include "netinet/sctp_sha1.h"
-#if __FreeBSD_version >= 700000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <netinet/ip_options.h>
#endif
@@ -526,11 +538,6 @@ struct sx {int dummy;};
SCTP_BASE_VAR(debug_printf)(__VA_ARGS__); \
}
-#if defined(__FreeBSD__)
-#ifndef in6pcb
-#define in6pcb inpcb
-#endif
-#endif
/* Declare all the malloc names for all the various mallocs */
MALLOC_DECLARE(SCTP_M_MAP);
MALLOC_DECLARE(SCTP_M_STRMI);
@@ -575,12 +582,12 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT);
/*
*
*/
-#if !defined(__Userspace_os_Darwin)
+#if !defined(__APPLE__)
#define USER_ADDR_NULL (NULL) /* FIX ME: temp */
#endif
-#if defined(SCTP_DEBUG)
#include <netinet/sctp_constants.h>
+#if defined(SCTP_DEBUG)
#define SCTPDBG(level, ...) \
{ \
do { \
@@ -634,7 +641,7 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT);
#define SCTP_VRF_IFN_HASH_SIZE 3
#define SCTP_INIT_VRF_TABLEID(vrf)
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#define SCTP_IFN_IS_IFT_LOOP(ifn) (strncmp((ifn)->ifn_name, "lo", 2) == 0)
/* BSD definition */
/* #define SCTP_ROUTE_IS_REAL_LOOP(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifa && (ro)->ro_rt->rt_ifa->ifa_ifp && (ro)->ro_rt->rt_ifa->ifa_ifp->if_type == IFT_LOOP) */
@@ -728,14 +735,6 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT);
umem_cache_destroy(zone);
#endif
-/* global struct ifaddrs used in sctp_init_ifns_for_vrf getifaddrs call
- * but references to fields are needed to persist as the vrf is queried.
- * getifaddrs allocates memory that needs to be freed with a freeifaddrs
- * call; this global is used to call freeifaddrs upon in sctp_pcb_finish
- */
-extern struct ifaddrs *g_interfaces;
-
-
/*
* __Userspace__ Defining sctp_hashinit_flags() and sctp_hashdestroy() for userland.
*/
@@ -775,10 +774,8 @@ sctp_hashfreedestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask);
/*__Userspace__ defining KTR_SUBSYS 1 as done in sctp_os_macosx.h */
#define KTR_SUBSYS 1
-#define sctp_get_tick_count() (ticks)
-
/* The packed define for 64 bit platforms */
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#define SCTP_PACKED __attribute__((packed))
#define SCTP_UNUSED __attribute__((unused))
#else
@@ -807,6 +804,13 @@ sctp_hashfreedestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask);
M_ALIGN(m, len); \
}
+#if !defined(_WIN32)
+#define SCTP_SNPRINTF(data, ...) \
+ if (snprintf(data, __VA_ARGS__) < 0) { \
+ data[0] = '\0'; \
+ }
+#endif
+
/* We make it so if you have up to 4 threads
* writting based on the default size of
* the packet log 65 k, that would be
@@ -853,7 +857,7 @@ static inline void sctp_userspace_rtalloc(sctp_route_t *ro)
* SCTP_GET_IF_INDEX_FROM_ROUTE macro.
*/
}
-#define SCTP_RTALLOC(ro, vrf_id) sctp_userspace_rtalloc((sctp_route_t *)ro)
+#define SCTP_RTALLOC(ro, vrf_id, fibnum) sctp_userspace_rtalloc((sctp_route_t *)ro)
/* dummy rtfree needed once user_route.h is included */
static inline void sctp_userspace_rtfree(sctp_rtentry_t *rt)
@@ -865,7 +869,6 @@ static inline void sctp_userspace_rtfree(sctp_rtentry_t *rt)
return;
}
free(rt);
- rt = NULL;
}
#define rtfree(arg1) sctp_userspace_rtfree(arg1)
@@ -886,10 +889,6 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af);
rt->rt_rmx.rmx_mtu = mtu; \
} while(0)
-/* (de-)register interface event notifications */
-#define SCTP_REGISTER_INTERFACE(ifhandle, af)
-#define SCTP_DEREGISTER_INTERFACE(ifhandle, af)
-
/*************************/
/* These are for logging */
@@ -914,13 +913,6 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af);
#define SCTP_GET_HEADER_FOR_OUTPUT(o_pak) 0
#define SCTP_RELEASE_HEADER(m)
#define SCTP_RELEASE_PKT(m) sctp_m_freem(m)
-/* UDP __Userspace__ - dummy definition */
-#define SCTP_ENABLE_UDP_CSUM(m) m=m
-/* BSD definition */
-/* #define SCTP_ENABLE_UDP_CSUM(m) do { \ */
-/* m->m_pkthdr.csum_flags = CSUM_UDP; \ */
-/* m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); \ */
-/* } while (0) */
#define SCTP_GET_PKT_VRFID(m, vrf_id) ((vrf_id = SCTP_DEFAULT_VRFID) != SCTP_DEFAULT_VRFID)
@@ -946,11 +938,11 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af);
*/
/* get the v6 hop limit */
-#define SCTP_GET_HLIM(inp, ro) 128 /* As done for __Windows__ */
+#define SCTP_GET_HLIM(inp, ro) 128
#define IPv6_HOP_LIMIT 128
/* is the endpoint v6only? */
-#define SCTP_IPV6_V6ONLY(inp) (((struct inpcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
+#define SCTP_IPV6_V6ONLY(sctp_inpcb) ((sctp_inpcb)->ip_inp.inp.inp_flags & IN6P_IPV6_V6ONLY)
/* is the socket non-blocking? */
#define SCTP_SO_IS_NBIO(so) ((so)->so_state & SS_NBIO)
#define SCTP_SET_SO_NBIO(so) ((so)->so_state |= SS_NBIO)
@@ -972,11 +964,6 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af);
#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
@@ -990,7 +977,7 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af);
/* sctp_pcb.h */
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#define SHUT_RD 1
#define SHUT_WR 2
#define SHUT_RDWR 3
@@ -1009,12 +996,22 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af);
struct sockaddr_conn {
#ifdef HAVE_SCONN_LEN
uint8_t sconn_len;
-#endif
uint8_t sconn_family;
+#else
+ uint16_t sconn_family;
+#endif
uint16_t sconn_port;
void *sconn_addr;
};
+typedef void *(*start_routine_t)(void *);
+
+extern int
+sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine);
+
+void
+sctp_userspace_set_threadname(const char *name);
+
/*
* SCTP protocol specific mbuf flags.
*/
@@ -1053,7 +1050,7 @@ extern void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
{ \
if (stcb && stcb->sctp_ep) \
result = ip6_output(o_pak, \
- ((struct in6pcb *)(stcb->sctp_ep))->in6p_outputopts, \
+ ((struct inpcb *)(stcb->sctp_ep))->in6p_outputopts, \
(ro), 0, 0, ifp, NULL); \
else \
result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \
@@ -1067,12 +1064,12 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int a
/* with the current included files, this is defined in Linux but
* in FreeBSD, it is behind a _KERNEL in sys/socket.h ...
*/
-#if defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_OpenBSD) || defined(__Userspace_os_NaCl)
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__native_client__)
/* stolen from /usr/include/sys/socket.h */
#define CMSG_ALIGN(n) _ALIGN(n)
-#elif defined(__Userspace_os_NetBSD)
+#elif defined(__NetBSD__)
#define CMSG_ALIGN(n) (((n) + __ALIGNBYTES) & ~__ALIGNBYTES)
-#elif defined(__Userspace_os_Darwin)
+#elif defined(__APPLE__)
#if !defined(__DARWIN_ALIGNBYTES)
#define __DARWIN_ALIGNBYTES (sizeof(__darwin_size_t) - 1)
#endif
@@ -1092,7 +1089,7 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int a
#endif
#define I_AM_HERE \
do { \
- SCTP_PRINTF("%s:%d at %s\n", __FILE__, __LINE__ , __FUNCTION__); \
+ SCTP_PRINTF("%s:%d at %s\n", __FILE__, __LINE__ , __func__); \
} while (0)
#ifndef timevalsub
@@ -1107,7 +1104,7 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int a
} while (0)
#endif
-#if defined(__Userspace_os_Linux)
+#if defined(__linux__)
#if !defined(TAILQ_FOREACH_SAFE)
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = ((head)->tqh_first); \
@@ -1121,16 +1118,23 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int a
(var) = (tvar))
#endif
#endif
-#if defined(__Userspace_os_DragonFly)
+#if defined(__DragonFly__)
#define TAILQ_FOREACH_SAFE TAILQ_FOREACH_MUTABLE
#define LIST_FOREACH_SAFE LIST_FOREACH_MUTABLE
#endif
-#if defined(__Userspace_os_NaCl)
+#if defined(__native_client__)
#define timercmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
#endif
+#define SCTP_IS_LISTENING(inp) ((inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) != 0)
+
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__linux__) || defined(__native_client__) || defined(__NetBSD__) || defined(_WIN32) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+int
+timingsafe_bcmp(const void *, const void *, size_t);
+#endif
+
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_output.c b/netwerk/sctp/src/netinet/sctp_output.c
index 3f1a9525d7..6a7dff99c2 100755
--- a/netwerk/sctp/src/netinet/sctp_output.c
+++ b/netwerk/sctp/src/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.
@@ -30,13 +32,13 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 280371 2015-03-23 15:12:02Z tuexen $");
+__FBSDID("$FreeBSD$");
#endif
#include <netinet/sctp_os.h>
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/proc.h>
#endif
#include <netinet/sctp_var.h>
@@ -54,32 +56,30 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 280371 2015-03-23 15:12:02Z t
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_input.h>
#include <netinet/sctp_crc32.h>
-#if defined(__Userspace_os_Linux)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <netinet/sctp_kdtrace.h>
+#endif
+#if defined(__linux__)
#define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */
#endif
#if defined(INET) || defined(INET6)
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <netinet/udp.h>
#endif
#endif
+#if !defined(__Userspace__)
#if defined(__APPLE__)
#include <netinet/in.h>
#endif
-#if defined(__FreeBSD__)
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <netinet/udp_var.h>
-#endif
#include <machine/in_cksum.h>
#endif
+#endif
#if defined(__Userspace__) && defined(INET6)
#include <netinet6/sctp6_var.h>
#endif
-
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 3
-#endif
-
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if !(defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD))
#define SCTP_MAX_LINKHDR 16
#endif
@@ -94,7 +94,7 @@ struct sack_track {
struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY];
};
-struct sack_track sack_array[256] = {
+const struct sack_track sack_array[256] = {
{0, 0, 0, 0, /* 0x00 */
{{0, 0},
{0, 0},
@@ -1889,7 +1889,6 @@ struct sack_track sack_array[256] = {
}
};
-
int
sctp_is_address_in_scope(struct sctp_ifa *ifa,
struct sctp_scoping *scope,
@@ -1928,14 +1927,12 @@ sctp_is_address_in_scope(struct sctp_ifa *ifa,
if (scope->ipv6_addr_legal) {
struct sockaddr_in6 *sin6;
-#if !defined(__Panda__)
/* Must update the flags, bummer, which
* means any IFA locks must now be applied HERE <->
*/
if (do_update) {
sctp_gather_internal_ifa_flags(ifa);
}
-#endif
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
return (0);
}
@@ -1975,7 +1972,7 @@ static struct mbuf *
sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
{
#if defined(INET) || defined(INET6)
- struct sctp_paramhdr *parmh;
+ struct sctp_paramhdr *paramh;
struct mbuf *mret;
uint16_t plen;
#endif
@@ -1997,7 +1994,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
#if defined(INET) || defined(INET6)
if (M_TRAILINGSPACE(m) >= plen) {
/* easy side we just drop it on the end */
- parmh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
+ paramh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
mret = m;
} else {
/* Need more space */
@@ -2011,7 +2008,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
return (m);
}
mret = SCTP_BUF_NEXT(mret);
- parmh = mtod(mret, struct sctp_paramhdr *);
+ paramh = mtod(mret, struct sctp_paramhdr *);
}
/* now add the parameter */
switch (ifa->address.sa.sa_family) {
@@ -2022,9 +2019,9 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
struct sockaddr_in *sin;
sin = &ifa->address.sin;
- ipv4p = (struct sctp_ipv4addr_param *)parmh;
- parmh->param_type = htons(SCTP_IPV4_ADDRESS);
- parmh->param_length = htons(plen);
+ ipv4p = (struct sctp_ipv4addr_param *)paramh;
+ paramh->param_type = htons(SCTP_IPV4_ADDRESS);
+ paramh->param_length = htons(plen);
ipv4p->addr = sin->sin_addr.s_addr;
SCTP_BUF_LEN(mret) += plen;
break;
@@ -2037,9 +2034,9 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
struct sockaddr_in6 *sin6;
sin6 = &ifa->address.sin6;
- ipv6p = (struct sctp_ipv6addr_param *)parmh;
- parmh->param_type = htons(SCTP_IPV6_ADDRESS);
- parmh->param_length = htons(plen);
+ ipv6p = (struct sctp_ipv6addr_param *)paramh;
+ paramh->param_type = htons(SCTP_IPV6_ADDRESS);
+ paramh->param_length = htons(plen);
memcpy(ipv6p->addr, &sin6->sin6_addr,
sizeof(ipv6p->addr));
#if defined(SCTP_EMBEDDED_V6_SCOPE)
@@ -2060,7 +2057,6 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
#endif
}
-
struct mbuf *
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_scoping *scope,
@@ -2098,7 +2094,7 @@ sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
continue;
}
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifap->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -2148,7 +2144,7 @@ sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
continue;
}
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifap->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -2470,7 +2466,7 @@ sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
continue;
}
if (laddr->ifa == ifa) {
@@ -2481,7 +2477,6 @@ sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
return (0);
}
-
int
sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
{
@@ -2492,7 +2487,7 @@ sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
continue;
}
if ((laddr->ifa == ifa) && laddr->action == 0)
@@ -2502,8 +2497,6 @@ sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
return (0);
}
-
-
static struct sctp_ifa *
sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
sctp_route_t *ro,
@@ -2536,7 +2529,7 @@ sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
if (sctp_ifn) {
/* is a preferred one on the interface we route out? */
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -2638,8 +2631,6 @@ sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
return (NULL);
}
-
-
static struct sctp_ifa *
sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
@@ -2668,7 +2659,7 @@ sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
- sctp_ifn = sctp_find_ifn( ifn, ifn_index);
+ sctp_ifn = sctp_find_ifn(ifn, ifn_index);
/*
* first question, is the ifn we will emit on in our list? If so,
@@ -2678,7 +2669,7 @@ sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
if (sctp_ifn) {
/* first try for a preferred address on the ep */
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -2714,7 +2705,7 @@ sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
}
/* next try for an acceptable address on the ep */
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -2748,7 +2739,6 @@ sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
return (sifa);
}
}
-
}
/*
* if we can't find one like that then we must look at all
@@ -2835,19 +2825,18 @@ sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
static struct sctp_ifa *
sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct sctp_inpcb *inp,
#else
struct sctp_inpcb *inp SCTP_UNUSED,
#endif
- struct sctp_tcb *stcb,
- int non_asoc_addr_ok,
- uint8_t dest_is_loop,
- uint8_t dest_is_priv,
- int addr_wanted,
- sa_family_t fam,
- sctp_route_t *ro
- )
+ struct sctp_tcb *stcb,
+ int non_asoc_addr_ok,
+ uint8_t dest_is_loop,
+ uint8_t dest_is_priv,
+ int addr_wanted,
+ sa_family_t fam,
+ sctp_route_t *ro)
{
struct sctp_ifa *ifa, *sifa;
int num_eligible_addr = 0;
@@ -2866,7 +2855,7 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn,
#endif /* SCTP_EMBEDDED_V6_SCOPE */
#endif /* INET6 */
LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -2966,10 +2955,9 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn,
return (NULL);
}
-
static int
sctp_count_num_preferred_boundall(struct sctp_ifn *ifn,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct sctp_inpcb *inp,
#else
struct sctp_inpcb *inp SCTP_UNUSED,
@@ -2984,7 +2972,7 @@ sctp_count_num_preferred_boundall(struct sctp_ifn *ifn,
int num_eligible_addr = 0;
LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -3151,7 +3139,7 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
ifn, num_preferred);
if (num_preferred == 0) {
/* None on this interface. */
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefered -- skipping to next\n");
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "No preferred -- skipping to next\n");
continue;
}
SCTPDBG(SCTP_DEBUG_OUTPUT2,
@@ -3194,7 +3182,7 @@ again_with_private_addresses_allowed:
}
LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifa:%p\n", (void *)sctp_ifa);
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -3238,12 +3226,10 @@ again_with_private_addresses_allowed:
* It is restricted for some
* reason.. probably not yet added.
*/
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its resticted\n");
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its restricted\n");
sifa = NULL;
continue;
}
- } else {
- SCTP_PRINTF("Stcb is null - no print\n");
}
atomic_add_int(&sifa->refcount, 1);
goto out;
@@ -3262,7 +3248,7 @@ again_with_private_addresses_allowed:
continue;
}
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -3308,12 +3294,14 @@ again_with_private_addresses_allowed:
}
}
#ifdef INET
- if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) {
- stcb->asoc.scope.ipv4_local_scope = 1;
- retried = 1;
- goto again_with_private_addresses_allowed;
- } else if (retried == 1) {
- stcb->asoc.scope.ipv4_local_scope = 0;
+ if (stcb) {
+ if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) {
+ stcb->asoc.scope.ipv4_local_scope = 1;
+ retried = 1;
+ goto again_with_private_addresses_allowed;
+ } else if (retried == 1) {
+ stcb->asoc.scope.ipv4_local_scope = 0;
+ }
}
#endif
out:
@@ -3328,7 +3316,7 @@ out:
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
struct sctp_ifa *tmp_sifa;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
@@ -3386,8 +3374,6 @@ out:
return (sifa);
}
-
-
/* tcb may be NULL */
struct sctp_ifa *
sctp_source_address_selection(struct sctp_inpcb *inp,
@@ -3407,10 +3393,11 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
#endif
/**
- * Rules: - Find the route if needed, cache if I can. - Look at
- * interface address in route, Is it in the bound list. If so we
- * have the best source. - If not we must rotate amongst the
- * addresses.
+ * Rules:
+ * - Find the route if needed, cache if I can.
+ * - Look at interface address in route, Is it in the bound list. If so we
+ * have the best source.
+ * - If not we must rotate amongst the addresses.
*
* Cavets and issues
*
@@ -3468,16 +3455,24 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
* addresses. If the bound set is NOT assigned to the interface then
* we must use rotation amongst the bound addresses..
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ro->ro_nh == NULL) {
+#else
if (ro->ro_rt == NULL) {
+#endif
/*
* Need a route to cache.
*/
- SCTP_RTALLOC(ro, vrf_id);
+ SCTP_RTALLOC(ro, vrf_id, inp->fibnum);
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ro->ro_nh == NULL) {
+#else
if (ro->ro_rt == NULL) {
+#endif
return (NULL);
}
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
/* On Windows the sa_family is U_SHORT or ADDRESS_FAMILY */
fam = (sa_family_t)ro->ro_dst.sa_family;
#else
@@ -3503,7 +3498,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
#ifdef INET6
case AF_INET6:
/* Scope based on outbound address */
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
#else
if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr) ||
@@ -3560,37 +3555,40 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
static int
sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
{
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
WSACMSGHDR cmh;
#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) &&
@@ -3598,11 +3596,14 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
(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)), cpsize, (caddr_t)data);
+ m_copydata(control, cmsg_data_off, (int)cpsize, (caddr_t)data);
return (1);
} else {
struct sctp_sndrcvinfo *sndrcvinfo;
@@ -3616,10 +3617,10 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
}
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;
@@ -3627,10 +3628,10 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
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 {
@@ -3639,10 +3640,10 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
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;
@@ -3652,7 +3653,6 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
found = 1;
}
}
- at += CMSG_ALIGN(cmh.cmsg_len);
}
return (found);
}
@@ -3660,12 +3660,11 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
static int
sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *error)
{
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
WSACMSGHDR cmh;
#else
struct cmsghdr cmh;
#endif
- int tlen, at;
struct sctp_initmsg initmsg;
#ifdef INET
struct sockaddr_in sin;
@@ -3673,34 +3672,37 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
+ int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off;
- tlen = SCTP_BUF_LEN(control);
- at = 0;
- while (at < tlen) {
- if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+ 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. */
*error = EINVAL;
return (1);
}
- 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. */
*error = EINVAL;
return (1);
}
- 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. */
*error = EINVAL;
return (1);
}
+ 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) {
switch (cmh.cmsg_type) {
case SCTP_INIT:
- if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_initmsg)) {
+ if (cmsg_data_len < (int)sizeof(struct sctp_initmsg)) {
*error = EINVAL;
return (1);
}
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_initmsg), (caddr_t)&initmsg);
+ m_copydata(control, cmsg_data_off, sizeof(struct sctp_initmsg), (caddr_t)&initmsg);
if (initmsg.sinit_max_attempts)
stcb->asoc.max_init_times = initmsg.sinit_max_attempts;
if (initmsg.sinit_num_ostreams)
@@ -3735,7 +3737,8 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].chunks_on_queues = 0;
- stcb->asoc.strmout[i].next_sequence_send = 0;
+ stcb->asoc.strmout[i].next_mid_ordered = 0;
+ stcb->asoc.strmout[i].next_mid_unordered = 0;
#if defined(SCTP_DETAILED_STR_STATS)
for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
stcb->asoc.strmout[i].abandoned_sent[j] = 0;
@@ -3745,15 +3748,16 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
stcb->asoc.strmout[i].abandoned_sent[0] = 0;
stcb->asoc.strmout[i].abandoned_unsent[0] = 0;
#endif
- stcb->asoc.strmout[i].stream_no = i;
+ stcb->asoc.strmout[i].sid = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+ stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING;
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL);
}
}
break;
#ifdef INET
case SCTP_DSTADDRV4:
- if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct in_addr)) {
+ if (cmsg_data_len < (int)sizeof(struct in_addr)) {
*error = EINVAL;
return (1);
}
@@ -3763,14 +3767,14 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
sin.sin_len = sizeof(struct sockaddr_in);
#endif
sin.sin_port = stcb->rport;
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct in_addr), (caddr_t)&sin.sin_addr);
+ m_copydata(control, cmsg_data_off, sizeof(struct in_addr), (caddr_t)&sin.sin_addr);
if ((sin.sin_addr.s_addr == INADDR_ANY) ||
(sin.sin_addr.s_addr == INADDR_BROADCAST) ||
IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
*error = EINVAL;
return (1);
}
- if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
@@ -3779,7 +3783,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
#endif
#ifdef INET6
case SCTP_DSTADDRV6:
- if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct in6_addr)) {
+ if (cmsg_data_len < (int)sizeof(struct in6_addr)) {
*error = EINVAL;
return (1);
}
@@ -3789,7 +3793,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
sin6.sin6_port = stcb->rport;
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr);
+ m_copydata(control, cmsg_data_off, sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr);
if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) ||
IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) {
*error = EINVAL;
@@ -3804,14 +3808,14 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
*error = EINVAL;
return (1);
}
- if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
}
} else
#endif
- if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL,
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, stcb->asoc.port,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
@@ -3822,11 +3826,11 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
break;
}
}
- at += CMSG_ALIGN(cmh.cmsg_len);
}
return (0);
}
+#if defined(INET) || defined(INET6)
static struct sctp_tcb *
sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
uint16_t port,
@@ -3834,12 +3838,11 @@ sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
struct sctp_nets **net_p,
int *error)
{
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
WSACMSGHDR cmh;
#else
struct cmsghdr cmh;
#endif
- int tlen, at;
struct sctp_tcb *stcb;
struct sockaddr *addr;
#ifdef INET
@@ -3848,31 +3851,34 @@ sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
+ int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off;
- tlen = SCTP_BUF_LEN(control);
- at = 0;
- while (at < tlen) {
- if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+ 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. */
*error = EINVAL;
return (NULL);
}
- 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. */
*error = EINVAL;
return (NULL);
}
- 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. */
*error = EINVAL;
return (NULL);
}
+ 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) {
switch (cmh.cmsg_type) {
#ifdef INET
case SCTP_DSTADDRV4:
- if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct in_addr)) {
+ if (cmsg_data_len < (int)sizeof(struct in_addr)) {
*error = EINVAL;
return (NULL);
}
@@ -3882,13 +3888,13 @@ sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
sin.sin_len = sizeof(struct sockaddr_in);
#endif
sin.sin_port = port;
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct in_addr), (caddr_t)&sin.sin_addr);
+ m_copydata(control, cmsg_data_off, sizeof(struct in_addr), (caddr_t)&sin.sin_addr);
addr = (struct sockaddr *)&sin;
break;
#endif
#ifdef INET6
case SCTP_DSTADDRV6:
- if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct in6_addr)) {
+ if (cmsg_data_len < (int)sizeof(struct in6_addr)) {
*error = EINVAL;
return (NULL);
}
@@ -3898,7 +3904,7 @@ sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
sin6.sin6_port = port;
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr);
+ m_copydata(control, cmsg_data_off, sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr);
#ifdef INET
if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
in6_sin6_2_sin(&sin, &sin6);
@@ -3919,10 +3925,10 @@ sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
}
}
}
- at += CMSG_ALIGN(cmh.cmsg_len);
}
return (NULL);
}
+#endif
static struct mbuf *
sctp_add_cookie(struct mbuf *init, int init_offset,
@@ -3931,8 +3937,6 @@ sctp_add_cookie(struct mbuf *init, int init_offset,
struct mbuf *copy_init, *copy_initack, *m_at, *sig, *mret;
struct sctp_state_cookie *stc;
struct sctp_paramhdr *ph;
- uint8_t *foo;
- int sig_offset;
uint16_t cookie_sz;
mret = sctp_get_mbuf_for_msg((sizeof(struct sctp_state_cookie) +
@@ -3996,25 +4000,21 @@ sctp_add_cookie(struct mbuf *init, int init_offset,
break;
}
}
- sig = sctp_get_mbuf_for_msg(SCTP_SECRET_SIZE, 0, M_NOWAIT, 1, MT_DATA);
+ sig = sctp_get_mbuf_for_msg(SCTP_SIGNATURE_SIZE, 0, M_NOWAIT, 1, MT_DATA);
if (sig == NULL) {
/* no space, so free the entire chain */
sctp_m_freem(mret);
return (NULL);
}
- SCTP_BUF_LEN(sig) = 0;
SCTP_BUF_NEXT(m_at) = sig;
- sig_offset = 0;
- foo = (uint8_t *) (mtod(sig, caddr_t) + sig_offset);
- memset(foo, 0, SCTP_SIGNATURE_SIZE);
- *signature = foo;
- SCTP_BUF_LEN(sig) += SCTP_SIGNATURE_SIZE;
+ SCTP_BUF_LEN(sig) = SCTP_SIGNATURE_SIZE;
cookie_sz += SCTP_SIGNATURE_SIZE;
ph->param_length = htons(cookie_sz);
+ *signature = (uint8_t *)mtod(sig, caddr_t);
+ memset(*signature, 0, SCTP_SIGNATURE_SIZE);
return (mret);
}
-
static uint8_t
sctp_get_ect(struct sctp_tcb *stcb)
{
@@ -4088,15 +4088,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
uint32_t v_tag,
uint16_t port,
union sctp_sockstore *over_addr,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- int so_locked SCTP_UNUSED
-#else
- int so_locked
-#endif
- )
+int so_locked)
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
{
/**
@@ -4112,9 +4107,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* interface and smallest_mtu size as well.
*/
/* Will need ifdefs around this */
-#ifdef __Panda__
- pakhandle_type o_pak;
-#endif
struct mbuf *newm;
struct sctphdr *sctphdr;
int packet_length;
@@ -4123,18 +4115,16 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
uint32_t vrf_id;
#endif
#if defined(INET) || defined(INET6)
-#if !defined(__Panda__)
struct mbuf *o_pak;
-#endif
sctp_route_t *ro = NULL;
struct udphdr *udp = NULL;
#endif
uint8_t tos_value;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so = NULL;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -4175,7 +4165,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_route_t iproute;
int len;
- len = sizeof(struct ip) + sizeof(struct sctphdr);
+ len = SCTP_MIN_V4_OVERHEAD;
if (port) {
len += sizeof(struct udphdr);
}
@@ -4189,7 +4179,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTP_BUF_LEN(newm) = len;
SCTP_BUF_NEXT(newm) = m;
m = newm;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (net != NULL) {
m->m_pkthdr.flowid = net->flowid;
M_HASHTYPE_SET(m, net->flowtype);
@@ -4207,53 +4197,44 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* This means especially, that it is not set at the
* SCTP layer. So use the value from the IP layer.
*/
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)
tos_value = inp->ip_inp.inp.inp_ip_tos;
-#else
- tos_value = inp->inp_ip_tos;
-#endif
}
tos_value &= 0xfc;
if (ecn_ok) {
tos_value |= sctp_get_ect(stcb);
}
- if ((nofragment_flag) && (port == 0)) {
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 1000000
+ if ((nofragment_flag) && (port == 0)) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ip->ip_off = htons(IP_DF);
-#else
- ip->ip_off = IP_DF;
-#endif
-#elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) || defined(__Userspace__)
+#elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__)
ip->ip_off = IP_DF;
#else
ip->ip_off = htons(IP_DF);
#endif
} else {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ip->ip_off = htons(0);
#else
ip->ip_off = 0;
#endif
}
-#if defined(__FreeBSD__)
+#if defined(__Userspace__)
+ ip->ip_id = htons(SCTP_IP_ID(inp)++);
+#elif defined(__FreeBSD__)
/* FreeBSD has a function for ip_id's */
- ip->ip_id = ip_newid();
-#elif defined(RANDOM_IP_ID)
- /* Apple has RANDOM_IP_ID switch */
- ip->ip_id = htons(ip_randomid());
-#elif defined(__Userspace__)
- ip->ip_id = htons(SCTP_IP_ID(inp)++);
+ ip_fillid(ip);
+#elif defined(__APPLE__)
+#if RANDOM_IP_ID
+ ip->ip_id = ip_randomid();
+#else
+ ip->ip_id = htons(ip_id++);
+#endif
#else
ip->ip_id = SCTP_IP_ID(inp)++;
#endif
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)
ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl;
-#else
- ip->ip_ttl = inp->inp_ip_ttl;
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ip->ip_len = htons(packet_length);
#else
ip->ip_len = packet_length;
@@ -4285,10 +4266,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(ro);
+#else
if (ro->ro_rt) {
RTFREE(ro->ro_rt);
ro->ro_rt = NULL;
}
+#endif
}
if (net->src_addr_selected == 0) {
/* Cache the source address */
@@ -4324,7 +4309,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_free_ifa(_lsrc);
} else {
ip->ip_src = over_addr->sin.sin_addr;
- SCTP_RTALLOC(ro, vrf_id);
+ SCTP_RTALLOC(ro, vrf_id, inp->fibnum);
}
}
if (port) {
@@ -4337,9 +4322,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip));
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(packet_length - sizeof(struct ip));
-#if !defined(__Windows__) && !defined(__Userspace__)
-#if defined(__FreeBSD__) && ((__FreeBSD_version > 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000)
+ udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip)));
+#if !defined(__Userspace__)
+#if defined(__FreeBSD__)
if (V_udp_cksum) {
udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
} else {
@@ -4368,7 +4353,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* that somewhere and abort the association right away
* (assuming this is an INIT being sent).
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ro->ro_nh == NULL) {
+#else
if (ro->ro_rt == NULL) {
+#endif
/*
* src addr selection failed to find a route (or
* valid source addr), so we can't get there from
@@ -4386,8 +4375,13 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
(uint32_t) (ntohl(ip->ip_src.s_addr)));
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Destination is %x\n",
(uint32_t)(ntohl(ip->ip_dst.s_addr)));
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n",
+ (void *)ro->ro_nh);
+#else
SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n",
(void *)ro->ro_rt);
+#endif
if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
/* failed to prepend data, give up */
@@ -4397,24 +4391,19 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr));
SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
-#if defined(__FreeBSD__) && ((__FreeBSD_version > 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000)
+#if !defined(__Userspace__)
+#if defined(__FreeBSD__)
if (V_udp_cksum) {
SCTP_ENABLE_UDP_CSUM(o_pak);
}
#else
SCTP_ENABLE_UDP_CSUM(o_pak);
#endif
+#endif
} else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
m->m_pkthdr.csum_flags = CSUM_SCTP;
m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
SCTP_STAT_INCR(sctps_sendhwcrc);
@@ -4424,24 +4413,26 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip));
SCTP_STAT_INCR(sctps_sendswcrc);
} else {
- SCTP_STAT_INCR(sctps_sendnocrc);
+ SCTP_STAT_INCR(sctps_sendhwcrc);
}
#endif
-#endif
}
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
sctp_packet_log(o_pak);
#endif
/* send it out. table id is taken from stcb */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) {
so = SCTP_INP_SO(inp);
SCTP_SOCKET_UNLOCK(so, 0);
}
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(send, NULL, stcb, ip, stcb, sctphdr);
+#endif
SCTP_IP_OUTPUT(ret, o_pak, ro, stcb, vrf_id);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4450,6 +4441,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
atomic_subtract_int(&stcb->asoc.refcnt, 1);
}
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (port) {
+ UDPSTAT_INC(udps_opackets);
+ }
+#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret)
@@ -4458,8 +4454,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTPDBG(SCTP_DEBUG_OUTPUT3, "IP output returns %d\n", ret);
if (net == NULL) {
/* free tempy routes */
-#if defined(__FreeBSD__) && __FreeBSD_version > 901000
- RO_RTFREE(ro);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(ro);
#else
if (ro->ro_rt) {
RTFREE(ro->ro_rt);
@@ -4467,19 +4463,35 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
#endif
} else {
- /* PMTU check versus smallest asoc MTU goes here */
- if ((ro->ro_rt != NULL) &&
- (net->ro._s_addr)) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if ((ro->ro_nh != NULL) && (net->ro._s_addr) &&
+#else
+ if ((ro->ro_rt != NULL) && (net->ro._s_addr) &&
+#endif
+ ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) {
uint32_t mtu;
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_nh);
+#else
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);
- net->mtu = mtu;
+#endif
+ if (mtu > 0) {
+ if (net->port) {
+ mtu -= sizeof(struct udphdr);
+ }
+ if (mtu < net->mtu) {
+ if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) {
+ sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+ }
+ net->mtu = mtu;
+ }
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ } else if (ro->ro_nh == NULL) {
+#else
} else if (ro->ro_rt == NULL) {
+#endif
/* route was freed */
if (net->ro._s_addr &&
net->src_addr_selected) {
@@ -4498,7 +4510,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
uint32_t flowlabel, flowinfo;
struct ip6_hdr *ip6h;
struct route_in6 ip6route;
-#if !(defined(__Panda__) || defined(__Userspace__))
+#if !defined(__Userspace__)
struct ifnet *ifp;
#endif
struct sockaddr_in6 *sin6, tmp, *lsa6, lsa6_tmp;
@@ -4522,14 +4534,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* This means especially, that it is not set at the
* SCTP layer. So use the value from the IP layer.
*/
-#if defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
+#if defined(__APPLE__) && !defined(__Userspace__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
flowlabel = ntohl(inp->ip_inp.inp.inp_flow);
#else
- flowlabel = ntohl(((struct in6pcb *)inp)->in6p_flowinfo);
+ flowlabel = ntohl(((struct inpcb *)inp)->inp_flow);
#endif
}
flowlabel &= 0x000fffff;
- len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr);
+ len = SCTP_MIN_OVERHEAD;
if (port) {
len += sizeof(struct udphdr);
}
@@ -4543,7 +4555,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTP_BUF_LEN(newm) = len;
SCTP_BUF_NEXT(newm) = m;
m = newm;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (net != NULL) {
m->m_pkthdr.flowid = net->flowid;
M_HASHTYPE_SET(m, net->flowtype);
@@ -4562,7 +4574,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#ifdef SCTP_EMBEDDED_V6_SCOPE
/* KAME hack: embed scopeid */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0)
#else
@@ -4575,6 +4587,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#endif
{
SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ sctp_m_freem(m);
return (EINVAL);
}
#endif /* SCTP_EMBEDDED_V6_SCOPE */
@@ -4598,12 +4611,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* This means especially, that it is not set at the
* SCTP layer. So use the value from the IP layer.
*/
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)
-#if defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
+#if defined(__APPLE__) && !defined(__Userspace__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
tos_value = (ntohl(inp->ip_inp.inp.inp_flow) >> 20) & 0xff;
#else
- tos_value = (ntohl(((struct in6pcb *)inp)->in6p_flowinfo) >> 20) & 0xff;
-#endif
+ tos_value = (ntohl(((struct inpcb *)inp)->inp_flow) >> 20) & 0xff;
#endif
}
tos_value &= 0xfc;
@@ -4621,7 +4632,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
} else {
ip6h->ip6_nxt = IPPROTO_SCTP;
}
- ip6h->ip6_plen = (packet_length - sizeof(struct ip6_hdr));
+ ip6h->ip6_plen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr)));
ip6h->ip6_dst = sin6->sin6_addr;
/*
@@ -4629,7 +4640,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* limited degree the kame src-addr-sel, since we can try
* their selection but it may not be bound.
*/
- bzero(&lsa6_tmp, sizeof(lsa6_tmp));
+ memset(&lsa6_tmp, 0, sizeof(lsa6_tmp));
lsa6_tmp.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
lsa6_tmp.sin6_len = sizeof(lsa6_tmp);
@@ -4640,16 +4651,20 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(ro);
+#else
if (ro->ro_rt) {
RTFREE(ro->ro_rt);
ro->ro_rt = NULL;
}
+#endif
}
if (net->src_addr_selected == 0) {
#ifdef SCTP_EMBEDDED_V6_SCOPE
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
/* KAME hack: embed scopeid */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0)
#else
@@ -4662,6 +4677,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#endif
{
SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ sctp_m_freem(m);
return (EINVAL);
}
#endif /* SCTP_EMBEDDED_V6_SCOPE */
@@ -4694,7 +4710,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#ifdef SCTP_EMBEDDED_V6_SCOPE
sin6 = (struct sockaddr_in6 *)&ro->ro_dst;
/* KAME hack: embed scopeid */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0)
#else
@@ -4707,6 +4723,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#endif
{
SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ sctp_m_freem(m);
return (EINVAL);
}
#endif /* SCTP_EMBEDDED_V6_SCOPE */
@@ -4727,7 +4744,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_free_ifa(_lsrc);
} else {
lsa6->sin6_addr = over_addr->sin6.sin6_addr;
- SCTP_RTALLOC(ro, vrf_id);
+ SCTP_RTALLOC(ro, vrf_id, inp->fibnum);
}
#ifdef SCTP_EMBEDDED_V6_SCOPE
#ifdef SCTP_KAME
@@ -4739,7 +4756,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
lsa6->sin6_port = inp->sctp_lport;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ro->ro_nh == NULL) {
+#else
if (ro->ro_rt == NULL) {
+#endif
/*
* src addr selection failed to find a route (or
* valid source addr), so we can't get there from
@@ -4756,7 +4777,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* XXX: sa6 may not have a valid sin6_scope_id in the
* non-SCOPEDROUTING case.
*/
- bzero(&lsa6_storage, sizeof(lsa6_storage));
+ memset(&lsa6_storage, 0, sizeof(lsa6_storage));
lsa6_storage.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
lsa6_storage.sin6_len = sizeof(lsa6_storage);
@@ -4790,7 +4811,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr));
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(packet_length - sizeof(struct ip6_hdr));
+ udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr)));
udp->uh_sum = 0;
sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr));
} else {
@@ -4807,7 +4828,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* that our ro pointer is now filled
*/
ip6h->ip6_hlim = SCTP_GET_HLIM(inp, ro);
-#if !(defined(__Panda__) || defined(__Userspace__))
+#if !defined(__Userspace__)
ifp = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
#endif
@@ -4837,49 +4858,34 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
-#if defined(__Windows__)
+#if !defined(__Userspace__)
+#if defined(_WIN32)
udp->uh_sum = 0;
-#elif !defined(__Userspace__)
+#else
if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) {
udp->uh_sum = 0xffff;
}
#endif
+#endif
} else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
-#if __FreeBSD_version < 900000
- sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr));
- SCTP_STAT_INCR(sctps_sendswcrc);
-#else
-#if __FreeBSD_version > 901000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
m->m_pkthdr.csum_flags = CSUM_SCTP_IPV6;
-#else
- m->m_pkthdr.csum_flags = CSUM_SCTP;
-#endif
m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
SCTP_STAT_INCR(sctps_sendhwcrc);
-#endif
#else
if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
(stcb) && (stcb->asoc.scope.loopback_scope))) {
sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr));
SCTP_STAT_INCR(sctps_sendswcrc);
} else {
- SCTP_STAT_INCR(sctps_sendnocrc);
+ SCTP_STAT_INCR(sctps_sendhwcrc);
}
#endif
-#endif
}
/* send it out. table id is taken from stcb */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) {
so = SCTP_INP_SO(inp);
SCTP_SOCKET_UNLOCK(so, 0);
@@ -4889,12 +4895,15 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
sctp_packet_log(o_pak);
#endif
-#if !(defined(__Panda__) || defined(__Userspace__))
+#if !defined(__Userspace__)
+#if defined(__FreeBSD__)
+ SCTP_PROBE5(send, NULL, stcb, ip6h, stcb, sctphdr);
+#endif
SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, &ifp, stcb, vrf_id);
#else
SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, NULL, stcb, vrf_id);
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4909,6 +4918,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sin6->sin6_port = prev_port;
}
SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (port) {
+ UDPSTAT_INC(udps_opackets);
+ }
+#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret) {
@@ -4916,8 +4930,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
if (net == NULL) {
/* Now if we had a temp route free it */
-#if defined(__FreeBSD__) && __FreeBSD_version > 901000
- RO_RTFREE(ro);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(ro);
#else
if (ro->ro_rt) {
RTFREE(ro->ro_rt);
@@ -4926,7 +4940,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#endif
} else {
/* PMTU check versus smallest asoc MTU goes here */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ro->ro_nh == NULL) {
+#else
if (ro->ro_rt == NULL) {
+#endif
/* Route was freed */
if (net->ro._s_addr &&
net->src_addr_selected) {
@@ -4935,22 +4953,34 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
net->src_addr_selected = 0;
}
- if ((ro->ro_rt != NULL) &&
- (net->ro._s_addr)) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if ((ro->ro_nh != NULL) && (net->ro._s_addr) &&
+#else
+ if ((ro->ro_rt != NULL) && (net->ro._s_addr) &&
+#endif
+ ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) {
uint32_t mtu;
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_nh);
+#else
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;
+#endif
+ if (mtu > 0) {
if (net->port) {
- net->mtu -= sizeof(struct udphdr);
+ mtu -= sizeof(struct udphdr);
+ }
+ if (mtu < net->mtu) {
+ if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) {
+ sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+ }
+ net->mtu = mtu;
}
}
}
-#if !defined(__Panda__) && !defined(__Userspace__)
+#if !defined(__Userspace__)
else if (ifp) {
-#if defined(__Windows__)
+#if defined(_WIN32)
#define ND_IFINFO(ifp) (ifp)
#define linkmtu if_mtu
#endif
@@ -4991,12 +5021,12 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctphdr->dest_port = dest_port;
sctphdr->v_tag = v_tag;
sctphdr->checksum = 0;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- sctphdr->checksum = sctp_calculate_cksum(m, 0);
- SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
+ if (SCTP_BASE_VAR(crc32c_offloaded) == 0) {
+ sctphdr->checksum = sctp_calculate_cksum(m, 0);
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendhwcrc);
+ }
if (tos_value == 0) {
tos_value = inp->ip_inp.inp.inp_ip_tos;
}
@@ -5025,13 +5055,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
}
-
void
-sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked)
{
struct mbuf *m, *m_last;
struct sctp_nets *net;
@@ -5041,10 +5066,10 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
struct sctp_supported_chunk_types_param *pr_supported;
struct sctp_paramhdr *ph;
int cnt_inits_to = 0;
- int ret;
+ int error;
uint16_t num_ext, chunk_len, padding_len, parameter_len;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
} else {
@@ -5151,6 +5176,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t) + chunk_len);
if (stcb->asoc.prsctp_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
+ if (stcb->asoc.idata_supported) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN;
+ }
}
if (stcb->asoc.auth_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION;
@@ -5162,6 +5190,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
if (stcb->asoc.reconfig_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
}
+ if (stcb->asoc.idata_supported) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IDATA;
+ }
if (stcb->asoc.nrsack_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
}
@@ -5232,7 +5263,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
}
/* now any cookie time extensions */
- if (stcb->asoc.cookie_preserve_req) {
+ if (stcb->asoc.cookie_preserve_req > 0) {
struct sctp_cookie_perserve_param *cookie_preserve;
if (padding_len > 0) {
@@ -5298,23 +5329,33 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
}
}
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n");
- ret = sctp_lowlevel_chunk_output(inp, stcb, net,
- (struct sockaddr *)&net->ro._l_addr,
- m, 0, NULL, 0, 0, 0, 0,
- inp->sctp_lport, stcb->rport, htonl(0),
- net->port, NULL,
-#if defined(__FreeBSD__)
- 0, 0,
-#endif
- so_locked);
- SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
+ if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
+ (struct sockaddr *)&net->ro._l_addr,
+ m, 0, NULL, 0, 0, 0, 0,
+ inp->sctp_lport, stcb->rport, htonl(0),
+ net->port, NULL,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ 0, 0,
+#endif
+ so_locked))) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
+ if (error == ENOBUFS) {
+ stcb->asoc.ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ }
+ } else {
+ stcb->asoc.ifp_had_enobuf = 0;
+ }
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
(void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
}
struct mbuf *
sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
- int param_offset, int *abort_processing, struct sctp_chunkhdr *cp, int *nat_friendly)
+ int param_offset, int *abort_processing,
+ struct sctp_chunkhdr *cp,
+ int *nat_friendly,
+ int *cookie_found)
{
/*
* Given a mbuf containing an INIT or INIT-ACK with the param_offset
@@ -5332,18 +5373,20 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
*/
struct sctp_paramhdr *phdr, params;
- struct mbuf *mat, *op_err;
- char tempbuf[SCTP_PARAM_BUFFER_SIZE];
+ struct mbuf *mat, *m_tmp, *op_err, *op_err_last;
int at, limit, pad_needed;
uint16_t ptype, plen, padded_size;
- int err_at;
*abort_processing = 0;
+ if (cookie_found != NULL) {
+ *cookie_found = 0;
+ }
mat = in_initpkt;
- err_at = 0;
limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk);
at = param_offset;
op_err = NULL;
+ op_err_last = NULL;
+ pad_needed = 0;
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Check for unrecognized param's\n");
phdr = sctp_get_next_param(mat, at, &params, sizeof(params));
while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) {
@@ -5366,12 +5409,17 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
switch (ptype) {
/* Param's with variable size */
case SCTP_HEARTBEAT_INFO:
- case SCTP_STATE_COOKIE:
case SCTP_UNRECOG_PARAM:
case SCTP_ERROR_CAUSE_IND:
/* ok skip fwd */
at += padded_size;
break;
+ case SCTP_STATE_COOKIE:
+ if (cookie_found != NULL) {
+ *cookie_found = 1;
+ }
+ at += padded_size;
+ break;
/* Param's with variable size within a range */
case SCTP_CHUNK_LIST:
case SCTP_SUPPORTED_CHUNK_EXT:
@@ -5460,66 +5508,47 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
break;
case SCTP_HOSTNAME_ADDRESS:
{
- /* We can NOT handle HOST NAME addresses!! */
+ /* Hostname parameters are deprecated. */
+ struct sctp_gen_error_cause *cause;
int l_len;
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Can't handle hostname addresses.. abort processing\n");
*abort_processing = 1;
- if (op_err == NULL) {
- /* Ok need to try to get a mbuf */
+ sctp_m_freem(op_err);
+ op_err = NULL;
+ op_err_last = NULL;
#ifdef INET6
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_OVERHEAD;
#else
- l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_V4_OVERHEAD;
#endif
- l_len += plen;
- l_len += sizeof(struct sctp_paramhdr);
- op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
- if (op_err) {
- SCTP_BUF_LEN(op_err) = 0;
- /*
- * pre-reserve space for ip and sctp
- * header and chunk hdr
- */
+ l_len += sizeof(struct sctp_chunkhdr);
+ l_len += sizeof(struct sctp_gen_error_cause);
+ op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
+ /*
+ * Pre-reserve space for IP, SCTP, and
+ * chunk header.
+ */
#ifdef INET6
- SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
-#else
- SCTP_BUF_RESV_UF(op_err, sizeof(struct ip));
-#endif
- SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
- SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
- }
- }
- if (op_err) {
- /* If we have space */
- struct sctp_paramhdr s;
-
- if (err_at % 4) {
- uint32_t cpthis = 0;
-
- pad_needed = 4 - (err_at % 4);
- m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
- err_at += pad_needed;
- }
- s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR);
- s.param_length = htons(sizeof(s) + plen);
- m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
- err_at += sizeof(s);
- phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf),plen));
- if (phdr == NULL) {
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
+#else
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct ip));
+#endif
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
+ cause = mtod(op_err, struct sctp_gen_error_cause *);
+ cause->code = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR);
+ cause->length = htons((uint16_t)(sizeof(struct sctp_gen_error_cause) + plen));
+ SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT);
+ if (SCTP_BUF_NEXT(op_err) == NULL) {
sctp_m_freem(op_err);
- /*
- * we are out of memory but we still
- * need to have a look at what to do
- * (the system is in trouble
- * though).
- */
- return (NULL);
+ op_err = NULL;
+ op_err_last = NULL;
}
- m_copyback(op_err, err_at, plen, (caddr_t)phdr);
}
return (op_err);
- break;
}
default:
/*
@@ -5534,11 +5563,11 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
int l_len;
/* Ok need to try to get an mbuf */
#ifdef INET6
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_OVERHEAD;
#else
- l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_V4_OVERHEAD;
#endif
- l_len += plen;
+ l_len += sizeof(struct sctp_chunkhdr);
l_len += sizeof(struct sctp_paramhdr);
op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
if (op_err) {
@@ -5550,41 +5579,55 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
#endif
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ op_err_last = op_err;
}
}
- if (op_err) {
+ if (op_err != NULL) {
/* If we have space */
- struct sctp_paramhdr s;
+ struct sctp_paramhdr *param;
- if (err_at % 4) {
- uint32_t cpthis = 0;
-
- pad_needed = 4 - (err_at % 4);
- m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
- err_at += pad_needed;
+ if (pad_needed > 0) {
+ op_err_last = sctp_add_pad_tombuf(op_err_last, pad_needed);
+ }
+ if (op_err_last == NULL) {
+ sctp_m_freem(op_err);
+ op_err = NULL;
+ op_err_last = NULL;
+ goto more_processing;
}
- s.param_type = htons(SCTP_UNRECOG_PARAM);
- s.param_length = htons(sizeof(s) + plen);
- m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
- err_at += sizeof(s);
- if (plen > sizeof(tempbuf)) {
- plen = sizeof(tempbuf);
+ if (M_TRAILINGSPACE(op_err_last) < (int)sizeof(struct sctp_paramhdr)) {
+ m_tmp = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
+ if (m_tmp == NULL) {
+ sctp_m_freem(op_err);
+ op_err = NULL;
+ op_err_last = NULL;
+ goto more_processing;
+ }
+ SCTP_BUF_LEN(m_tmp) = 0;
+ SCTP_BUF_NEXT(m_tmp) = NULL;
+ SCTP_BUF_NEXT(op_err_last) = m_tmp;
+ op_err_last = m_tmp;
}
- phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf),plen));
- if (phdr == NULL) {
+ param = (struct sctp_paramhdr *)(mtod(op_err_last, caddr_t) + SCTP_BUF_LEN(op_err_last));
+ param->param_type = htons(SCTP_UNRECOG_PARAM);
+ param->param_length = htons((uint16_t)sizeof(struct sctp_paramhdr) + plen);
+ SCTP_BUF_LEN(op_err_last) += sizeof(struct sctp_paramhdr);
+ SCTP_BUF_NEXT(op_err_last) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT);
+ if (SCTP_BUF_NEXT(op_err_last) == NULL) {
sctp_m_freem(op_err);
- /*
- * we are out of memory but
- * we still need to have a
- * look at what to do (the
- * system is in trouble
- * though).
- */
op_err = NULL;
+ op_err_last = NULL;
goto more_processing;
+ } else {
+ while (SCTP_BUF_NEXT(op_err_last) != NULL) {
+ op_err_last = SCTP_BUF_NEXT(op_err_last);
+ }
+ }
+ if (plen % 4 != 0) {
+ pad_needed = 4 - (plen % 4);
+ } else {
+ pad_needed = 0;
}
- m_copyback(op_err, err_at, plen, (caddr_t)phdr);
- err_at += plen;
}
}
more_processing:
@@ -5597,7 +5640,6 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
at += SCTP_SIZE32(plen);
}
break;
-
}
phdr = sctp_get_next_param(mat, at, &params, sizeof(params));
}
@@ -5605,13 +5647,18 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
invalid_size:
SCTPDBG(SCTP_DEBUG_OUTPUT1, "abort flag set\n");
*abort_processing = 1;
- if ((op_err == NULL) && phdr) {
+ sctp_m_freem(op_err);
+ op_err = NULL;
+ op_err_last = NULL;
+ if (phdr != NULL) {
+ struct sctp_paramhdr *param;
int l_len;
#ifdef INET6
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_OVERHEAD;
#else
- l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_V4_OVERHEAD;
#endif
+ l_len += sizeof(struct sctp_chunkhdr);
l_len += (2 * sizeof(struct sctp_paramhdr));
op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
if (op_err) {
@@ -5623,25 +5670,15 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
#endif
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ SCTP_BUF_LEN(op_err) = 2 * sizeof(struct sctp_paramhdr);
+ param = mtod(op_err, struct sctp_paramhdr *);
+ param->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
+ param->param_length = htons(2 * sizeof(struct sctp_paramhdr));
+ param++;
+ param->param_type = htons(ptype);
+ param->param_length = htons(plen);
}
}
- if ((op_err) && phdr) {
- struct sctp_paramhdr s;
-
- if (err_at % 4) {
- uint32_t cpthis = 0;
-
- pad_needed = 4 - (err_at % 4);
- m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
- err_at += pad_needed;
- }
- s.param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
- s.param_length = htons(sizeof(s) + sizeof(struct sctp_paramhdr));
- m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
- err_at += sizeof(s);
- /* Only copy back the p-hdr that caused the issue */
- m_copyback(op_err, err_at, sizeof(struct sctp_paramhdr), (caddr_t)phdr);
- }
return (op_err);
}
@@ -5662,12 +5699,16 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
uint16_t ptype, plen;
uint8_t fnd;
struct sctp_nets *net;
+ int check_src;
#ifdef INET
struct sockaddr_in sin4, *sa4;
#endif
#ifdef INET6
struct sockaddr_in6 sin6, *sa6;
#endif
+#if defined(__Userspace__)
+ struct sockaddr_conn *sac;
+#endif
#ifdef INET
memset(&sin4, 0, sizeof(sin4));
@@ -5684,39 +5725,80 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
#endif
#endif
/* First what about the src address of the pkt ? */
- fnd = 0;
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- sa = (struct sockaddr *)&net->ro._l_addr;
- if (sa->sa_family == src->sa_family) {
+ check_src = 0;
+ switch (src->sa_family) {
#ifdef INET
- if (sa->sa_family == AF_INET) {
- struct sockaddr_in *src4;
+ case AF_INET:
+ if (asoc->scope.ipv4_addr_legal) {
+ check_src = 1;
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (asoc->scope.ipv6_addr_legal) {
+ check_src = 1;
+ }
+ break;
+#endif
+#if defined(__Userspace__)
+ case AF_CONN:
+ if (asoc->scope.conn_addr_legal) {
+ check_src = 1;
+ }
+ break;
+#endif
+ default:
+ /* TSNH */
+ break;
+ }
+ if (check_src) {
+ fnd = 0;
+ TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
+ sa = (struct sockaddr *)&net->ro._l_addr;
+ if (sa->sa_family == src->sa_family) {
+#ifdef INET
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *src4;
- sa4 = (struct sockaddr_in *)sa;
- src4 = (struct sockaddr_in *)src;
- if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) {
- fnd = 1;
- break;
+ sa4 = (struct sockaddr_in *)sa;
+ src4 = (struct sockaddr_in *)src;
+ if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) {
+ fnd = 1;
+ break;
+ }
}
- }
#endif
#ifdef INET6
- if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *src6;
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *src6;
- sa6 = (struct sockaddr_in6 *)sa;
- src6 = (struct sockaddr_in6 *)src;
- if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) {
- fnd = 1;
- break;
+ sa6 = (struct sockaddr_in6 *)sa;
+ src6 = (struct sockaddr_in6 *)src;
+ if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) {
+ fnd = 1;
+ break;
+ }
+ }
+#endif
+#if defined(__Userspace__)
+ if (sa->sa_family == AF_CONN) {
+ struct sockaddr_conn *srcc;
+
+ sac = (struct sockaddr_conn *)sa;
+ srcc = (struct sockaddr_conn *)src;
+ if (sac->sconn_addr == srcc->sconn_addr) {
+ fnd = 1;
+ break;
+ }
}
- }
#endif
+ }
+ }
+ if (fnd == 0) {
+ /* New address added! no need to look further. */
+ return (1);
}
- }
- if (fnd == 0) {
- /* New address added! no need to look futher. */
- return (1);
}
/* Ok so far lets munge through the rest of the packet */
offset += sizeof(struct sctp_init_chunk);
@@ -5731,15 +5813,19 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
{
struct sctp_ipv4addr_param *p4, p4_buf;
+ if (plen != sizeof(struct sctp_ipv4addr_param)) {
+ return (1);
+ }
phdr = sctp_get_next_param(in_initpkt, offset,
(struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf));
- if (plen != sizeof(struct sctp_ipv4addr_param) ||
- phdr == NULL) {
+ if (phdr == NULL) {
return (1);
}
- p4 = (struct sctp_ipv4addr_param *)phdr;
- sin4.sin_addr.s_addr = p4->addr;
- sa_touse = (struct sockaddr *)&sin4;
+ if (asoc->scope.ipv4_addr_legal) {
+ p4 = (struct sctp_ipv4addr_param *)phdr;
+ sin4.sin_addr.s_addr = p4->addr;
+ sa_touse = (struct sockaddr *)&sin4;
+ }
break;
}
#endif
@@ -5748,16 +5834,20 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
{
struct sctp_ipv6addr_param *p6, p6_buf;
+ if (plen != sizeof(struct sctp_ipv6addr_param)) {
+ return (1);
+ }
phdr = sctp_get_next_param(in_initpkt, offset,
(struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf));
- if (plen != sizeof(struct sctp_ipv6addr_param) ||
- phdr == NULL) {
+ if (phdr == NULL) {
return (1);
}
- p6 = (struct sctp_ipv6addr_param *)phdr;
- memcpy((caddr_t)&sin6.sin6_addr, p6->addr,
- sizeof(p6->addr));
- sa_touse = (struct sockaddr *)&sin6;
+ if (asoc->scope.ipv6_addr_legal) {
+ p6 = (struct sctp_ipv6addr_param *)phdr;
+ memcpy((caddr_t)&sin6.sin6_addr, p6->addr,
+ sizeof(p6->addr));
+ sa_touse = (struct sockaddr *)&sin6;
+ }
break;
}
#endif
@@ -5813,13 +5903,14 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
*/
void
sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct mbuf *init_pkt, int iphlen, int offset,
+ struct sctp_nets *src_net, struct mbuf *init_pkt,
+ int iphlen, int offset,
struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, struct sctp_init_chunk *init_chk,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
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;
@@ -5829,6 +5920,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
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;
@@ -5852,6 +5944,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
uint16_t his_limit, i_want;
int abort_flag;
int nat_friendly = 0;
+ int error;
struct socket *so;
uint16_t num_ext, chunk_len, padding_len, parameter_len;
@@ -5861,40 +5954,62 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc = NULL;
}
if ((asoc != NULL) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) &&
- (sctp_are_there_new_addresses(asoc, init_pkt, offset, src))) {
- /* new addresses, out of here in non-cookie-wait states */
- /*
- * Send a ABORT, we don't add the new address error clause
- * though we even set the T bit and copy in the 0 tag.. this
- * looks no different than if no listener was present.
- */
- op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
- "Address added");
- sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT)) {
+ if (sctp_are_there_new_addresses(asoc, init_pkt, offset, src)) {
+ /*
+ * new addresses, out of here in non-cookie-wait states
+ *
+ * Send an ABORT, without the new address error cause.
+ * This looks no different than if no listener
+ * was present.
+ */
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Address added");
+ sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
- vrf_id, port);
- return;
+ vrf_id, port);
+ return;
+ }
+ if (src_net != NULL && (src_net->port != port)) {
+ /*
+ * change of remote encapsulation port, out of here in
+ * non-cookie-wait states
+ *
+ * Send an ABORT, without an specific error cause.
+ * This looks no different than if no listener
+ * was present.
+ */
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Remote encapsulation port changed");
+ sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
+#endif
+ vrf_id, port);
+ return;
+ }
}
abort_flag = 0;
op_err = sctp_arethere_unrecognized_parameters(init_pkt,
- (offset + sizeof(struct sctp_init_chunk)),
- &abort_flag, (struct sctp_chunkhdr *)init_chk, &nat_friendly);
+ (offset + sizeof(struct sctp_init_chunk)),
+ &abort_flag,
+ (struct sctp_chunkhdr *)init_chk,
+ &nat_friendly, NULL);
if (abort_flag) {
do_a_abort:
if (op_err == NULL) {
char msg[SCTP_DIAG_INFO_LEN];
- snprintf(msg, sizeof(msg), "%s:%d at %s\n", __FILE__, __LINE__, __FUNCTION__);
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
}
sctp_send_abort(init_pkt, iphlen, src, dst, sh,
init_chk->init.initiate_tag, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
return;
@@ -5902,8 +6017,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (m == NULL) {
/* No memory, INIT timer will re-attempt. */
- if (op_err)
- sctp_m_freem(op_err);
+ sctp_m_freem(op_err);
return;
}
chunk_len = (uint16_t)sizeof(struct sctp_init_ack_chunk);
@@ -5918,7 +6032,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
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) {
@@ -5939,7 +6055,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stc.peerport = sh->src_port;
/*
- * If we wanted to honor cookie life extentions, we would add to
+ * If we wanted to honor cookie life extensions, we would add to
* stc.cookie_life. For now we should NOT honor any extension
*/
stc.site_scope = stc.local_scope = stc.loopback_scope = 0;
@@ -5967,11 +6083,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stc.ipv4_addr_legal = 1;
#endif
}
-#ifdef SCTP_DONT_DO_PRIVADDR_SCOPE
- stc.ipv4_scope = 1;
-#else
stc.ipv4_scope = 0;
-#endif
if (net == NULL) {
to = src;
switch (dst->sa_family) {
@@ -5992,13 +6104,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stc.laddr_type = SCTP_IPV4_ADDRESS;
/* scope_id is only for v6 */
stc.scope_id = 0;
-#ifndef SCTP_DONT_DO_PRIVADDR_SCOPE
- if (IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) {
+ if ((IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) ||
+ (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))){
stc.ipv4_scope = 1;
}
-#else
- stc.ipv4_scope = 1;
-#endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */
/* Must use the address in this case */
if (sctp_is_address_on_local_host(src, vrf_id)) {
stc.loopback_scope = 1;
@@ -6014,8 +6123,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
{
stc.addr_type = SCTP_IPV6_ADDRESS;
memcpy(&stc.address, &src6->sin6_addr, sizeof(struct in6_addr));
-#if defined(__FreeBSD__) && (((__FreeBSD_version < 900000) && (__FreeBSD_version >= 804000)) || (__FreeBSD_version > 900000))
- stc.scope_id = in6_getscope(&src6->sin6_addr);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ stc.scope_id = ntohs(in6_getscope(&src6->sin6_addr));
#else
stc.scope_id = 0;
#endif
@@ -6024,17 +6133,18 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stc.local_scope = 0;
stc.site_scope = 1;
stc.ipv4_scope = 1;
- } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr)) {
+ } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr) ||
+ IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) {
/*
- * If the new destination is a LINK_LOCAL we
- * must have common both site and local
- * scope. Don't set local scope though since
- * we must depend on the source to be added
- * implicitly. We cannot assure just because
- * we share one link that all links are
+ * If the new destination or source is a
+ * LINK_LOCAL we must have common both site and
+ * local scope. Don't set local scope though
+ * since we must depend on the source to be
+ * added implicitly. We cannot assure just
+ * because we share one link that all links are
* common.
*/
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
/* Mac OS X currently doesn't have in6_getscope() */
stc.scope_id = src6->sin6_addr.s6_addr16[1];
#endif
@@ -6049,10 +6159,12 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
cnt_inits_to = 1;
/* pull out the scope_id from incoming pkt */
- } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr)) {
+ } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr) ||
+ IN6_IS_ADDR_SITELOCAL(&dst6->sin6_addr)) {
/*
- * If the new destination is SITE_LOCAL then
- * we must have site scope in common.
+ * If the new destination or source is
+ * SITE_LOCAL then we must have site scope in
+ * common.
*/
stc.site_scope = 1;
}
@@ -6132,11 +6244,13 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
net->ro._s_addr = sctp_source_address_selection(inp,
stcb, (sctp_route_t *)&net->ro,
net, 0, vrf_id);
- if (net->ro._s_addr == NULL)
+ if (net->ro._s_addr == NULL) {
+ sctp_m_freem(op_err);
+ sctp_m_freem(m);
return;
+ }
net->src_addr_selected = 1;
-
}
stc.laddress[0] = net->ro._s_addr->address.sin.sin_addr.s_addr;
stc.laddress[1] = 0;
@@ -6162,8 +6276,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
net->ro._s_addr = sctp_source_address_selection(inp,
stcb, (sctp_route_t *)&net->ro,
net, 0, vrf_id);
- if (net->ro._s_addr == NULL)
+ if (net->ro._s_addr == NULL) {
+ sctp_m_freem(op_err);
+ sctp_m_freem(m);
return;
+ }
net->src_addr_selected = 1;
}
@@ -6195,7 +6312,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* Now lets put the SCTP header in place */
initack = mtod(m, struct sctp_init_ack_chunk *);
/* Save it off for quick ref */
- stc.peers_vtag = init_chk->init.initiate_tag;
+ stc.peers_vtag = ntohl(init_chk->init.initiate_tag);
/* who are we */
memcpy(stc.identification, SCTP_VERSION_STRING,
min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification)));
@@ -6207,18 +6324,15 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
initack->ch.chunk_length = 0;
/* place in my tag */
if ((asoc != NULL) &&
- ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_INUSE) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) {
+ ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_INUSE) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED))) {
/* re-use the v-tags and init-seq here */
initack->init.initiate_tag = htonl(asoc->my_vtag);
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);
@@ -6237,12 +6351,12 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
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);
}
@@ -6254,6 +6368,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
so = inp->sctp_socket;
if (so == NULL) {
/* memory problem */
+ sctp_m_freem(op_err);
sctp_m_freem(m);
return;
} else {
@@ -6263,10 +6378,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
his_limit = ntohs(init_chk->init.num_inbound_streams);
/* choose what I want */
if (asoc != NULL) {
- if (asoc->streamoutcnt > inp->sctp_ep.pre_open_stream_count) {
+ if (asoc->streamoutcnt > asoc->pre_open_streams) {
i_want = asoc->streamoutcnt;
} else {
- i_want = inp->sctp_ep.pre_open_stream_count;
+ i_want = asoc->pre_open_streams;
}
} else {
i_want = inp->sctp_ep.pre_open_stream_count;
@@ -6327,6 +6442,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (((asoc != NULL) && (asoc->prsctp_supported == 1)) ||
((asoc == NULL) && (inp->prsctp_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
+ if (((asoc != NULL) && (asoc->idata_supported == 1)) ||
+ ((asoc == NULL) && (inp->idata_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN;
+ }
}
if (((asoc != NULL) && (asoc->auth_supported == 1)) ||
((asoc == NULL) && (inp->auth_supported == 1))) {
@@ -6341,6 +6460,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
((asoc == NULL) && (inp->reconfig_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
}
+ if (((asoc != NULL) && (asoc->idata_supported == 1)) ||
+ ((asoc == NULL) && (inp->idata_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IDATA;
+ }
if (((asoc != NULL) && (asoc->nrsack_supported == 1)) ||
((asoc == NULL) && (inp->nrsack_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
@@ -6356,7 +6479,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
chunk_len += parameter_len;
}
-
+
/* add authentication parameters */
if (((asoc != NULL) && (asoc->auth_supported == 1)) ||
((asoc == NULL) && (inp->auth_supported == 1))) {
@@ -6529,18 +6652,29 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
over_addr = NULL;
}
- (void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
- 0, 0,
- inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag,
- port, over_addr,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+ if ((error = sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
+ 0, 0,
+ inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag,
+ port, over_addr,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
#endif
- SCTP_SO_NOT_LOCKED);
+ SCTP_SO_NOT_LOCKED))) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
+ if (error == ENOBUFS) {
+ if (asoc != NULL) {
+ asoc->ifp_had_enobuf = 1;
+ }
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ }
+ } else {
+ if (asoc != NULL) {
+ asoc->ifp_had_enobuf = 0;
+ }
+ }
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
-
static void
sctp_prune_prsctp(struct sctp_tcb *stcb,
struct sctp_association *asoc,
@@ -6565,13 +6699,13 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
* This one is PR-SCTP AND buffer space
* limited type
*/
- if (chk->rec.data.timetodrop.tv_sec >= (long)srcv->sinfo_timetolive) {
+ if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) {
/*
* Lower numbers equates to higher
- * priority so if the one we are
- * looking at has a larger or equal
- * priority we want to drop the data
- * and NOT retransmit it.
+ * priority. So if the one we are
+ * looking at has a larger priority,
+ * we want to drop the data and NOT
+ * retransmit it.
*/
if (chk->data) {
/*
@@ -6593,14 +6727,14 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
return;
}
} /* if chunk was present */
- } /* if of sufficent priority */
+ } /* if of sufficient priority */
} /* if chunk has enabled */
} /* tailqforeach */
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
/* Here we must move to the sent queue and mark */
if (PR_SCTP_BUF_ENABLED(chk->flags)) {
- if (chk->rec.data.timetodrop.tv_sec >= (long)srcv->sinfo_timetolive) {
+ if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) {
if (chk->data) {
/*
* We release the book_size
@@ -6634,11 +6768,19 @@ sctp_get_frag_point(struct sctp_tcb *stcb,
* we use a larger frag point.
*/
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MED_OVERHEAD;
+ ovh = SCTP_MIN_OVERHEAD;
} else {
- ovh = SCTP_MED_V4_OVERHEAD;
+#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)
siz = asoc->smallest_mtu - ovh;
else
@@ -6695,7 +6837,7 @@ sctp_set_prsctp_policy(struct sctp_stream_queue_pending *sp)
/* TODO sctp_constants.h needs alternative time macros when
* _KERNEL is undefined.
*/
-#ifndef __FreeBSD__
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
timeradd(&sp->ts, &tv, &sp->ts);
#else
timevaladd(&sp->ts, &tv);
@@ -6747,9 +6889,9 @@ sctp_msg_append(struct sctp_tcb *stcb,
}
strm = &stcb->asoc.strmout[srcv->sinfo_stream];
/* Now can we send this? */
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_SENT) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
(stcb->asoc.state & SCTP_STATE_SHUTDOWN_PENDING)) {
/* got data while shutting down */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
@@ -6766,6 +6908,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
sp->context = srcv->sinfo_context;
+ sp->fsn = 0;
if (sp->sinfo_flags & SCTP_ADDR_OVER) {
sp->net = net;
atomic_add_int(&sp->net->ref_count, 1);
@@ -6773,7 +6916,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
sp->net = NULL;
}
(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
- sp->stream = srcv->sinfo_stream;
+ sp->sid = srcv->sinfo_stream;
sp->msg_is_complete = 1;
sp->sender_all_done = 1;
sp->some_taken = 0;
@@ -6817,7 +6960,6 @@ out_now:
return (error);
}
-
static struct mbuf *
sctp_copy_mbufchain(struct mbuf *clonechain,
struct mbuf *outchain,
@@ -6842,12 +6984,7 @@ sctp_copy_mbufchain(struct mbuf *clonechain,
appendchain = clonechain;
} else {
if (!copy_by_ref &&
-#if defined(__Panda__)
- 0
-#else
- (sizeofcpy <= (int)((((SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count) - 1) * MLEN) + MHLEN)))
-#endif
- ) {
+ (sizeofcpy <= (int)((((SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count) - 1) * MLEN) + MHLEN)))) {
/* Its not in a cluster */
if (*endofchain == NULL) {
/* lets get a mbuf cluster */
@@ -6881,10 +7018,10 @@ sctp_copy_mbufchain(struct mbuf *clonechain,
}
}
/* get the new end of length */
- len = M_TRAILINGSPACE(*endofchain);
+ len = (int)M_TRAILINGSPACE(*endofchain);
} else {
/* how much is left at the end? */
- len = M_TRAILINGSPACE(*endofchain);
+ len = (int)M_TRAILINGSPACE(*endofchain);
}
/* Find the end of the data, for appending */
cp = (mtod((*endofchain), caddr_t) + SCTP_BUF_LEN((*endofchain)));
@@ -6946,7 +7083,7 @@ sctp_copy_mbufchain(struct mbuf *clonechain,
}
/*
* save off the end and update the end-chain
- * postion
+ * position
*/
m = appendchain;
while (m) {
@@ -6958,7 +7095,7 @@ sctp_copy_mbufchain(struct mbuf *clonechain,
}
return (outchain);
} else {
- /* save off the end and update the end-chain postion */
+ /* save off the end and update the end-chain position */
m = appendchain;
while (m) {
if (SCTP_BUF_NEXT(m) == NULL) {
@@ -6978,11 +7115,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int *num_out,
int *reason_code,
int control_only, int from_where,
- struct timeval *now, int *now_filled, int frag_point, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- );
+ struct timeval *now, int *now_filled, int frag_point, int so_locked);
static void
sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
@@ -7039,7 +7172,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
ph = mtod(m, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr) + ca->sndlen);
+ ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + ca->sndlen));
}
/* We add one here to keep the assoc from
* dis-appearing on us.
@@ -7068,31 +7201,27 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
asoc = &stcb->asoc;
if (ca->sndrcv.sinfo_flags & SCTP_EOF) {
/* shutdown this assoc */
- int cnt;
- cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED);
-
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
- (cnt == 0)) {
- if (asoc->locked_on_sending) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED) == 0) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
goto abort_anyway;
}
/* there is nothing queued to send, so I'm done... */
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* only send SHUTDOWN the first time through */
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb, net);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
net);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
- asoc->primary_destination);
+ NULL);
added_control = 1;
do_chunk_output = 0;
}
@@ -7107,38 +7236,38 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
* data to be sent first and move to
* SHUTDOWN-PENDING
*/
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
- if (asoc->locked_on_sending) {
- /* Locked to send out the data */
- struct sctp_stream_queue_pending *sp;
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp) {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
}
- asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
abort_anyway:
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "%s:%d at %s", __FILE__, __LINE__, __func__);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(stcb->sctp_ep, stcb,
- NULL, SCTP_SO_NOT_LOCKED);
+ op_err, SCTP_SO_NOT_LOCKED);
atomic_add_int(&stcb->asoc.refcnt, -1);
goto no_chunk_output;
}
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
- asoc->primary_destination);
+ NULL);
}
}
-
}
}
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ (stcb->asoc.stream_queue_cnt * SCTP_DATA_CHUNK_OVERHEAD(stcb)));
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
@@ -7173,22 +7302,26 @@ sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED)
/*
* Do a notify here? Kacheong suggests that the notify be done at
* the send time.. so you would push up a notification if any send
- * failed. Don't know if this is feasable since the only failures we
+ * failed. Don't know if this is feasible since the only failures we
* have is "memory" related and if you cannot get an mbuf to send
* the data you surely can't get an mbuf to send up to notify the
* user you can't send the data :->
*/
/* now free everything */
+ if (ca->inp) {
+ /* Lets clear the flag to allow others to run. */
+ ca->inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP;
+ }
sctp_m_freem(ca->m);
SCTP_FREE(ca, SCTP_M_COPYAL);
}
static struct mbuf *
-sctp_copy_out_all(struct uio *uio, int len)
+sctp_copy_out_all(struct uio *uio, ssize_t len)
{
struct mbuf *ret, *at;
- int left, willcpy, cancpy, error;
+ ssize_t left, willcpy, cancpy, error;
ret = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_WAITOK, 1, MT_DATA);
if (ret == NULL) {
@@ -7198,28 +7331,28 @@ sctp_copy_out_all(struct uio *uio, int len)
left = len;
SCTP_BUF_LEN(ret) = 0;
/* save space for the data chunk header */
- cancpy = M_TRAILINGSPACE(ret);
+ cancpy = (int)M_TRAILINGSPACE(ret);
willcpy = min(cancpy, left);
at = ret;
while (left > 0) {
/* Align data to the end */
- error = uiomove(mtod(at, caddr_t), willcpy, uio);
+ error = uiomove(mtod(at, caddr_t), (int)willcpy, uio);
if (error) {
err_out_now:
sctp_m_freem(at);
return (NULL);
}
- SCTP_BUF_LEN(at) = willcpy;
+ SCTP_BUF_LEN(at) = (int)willcpy;
SCTP_BUF_NEXT_PKT(at) = SCTP_BUF_NEXT(at) = 0;
left -= willcpy;
if (left > 0) {
- SCTP_BUF_NEXT(at) = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 1, MT_DATA);
+ SCTP_BUF_NEXT(at) = sctp_get_mbuf_for_msg((unsigned int)left, 0, M_WAITOK, 1, MT_DATA);
if (SCTP_BUF_NEXT(at) == NULL) {
goto err_out_now;
}
at = SCTP_BUF_NEXT(at);
SCTP_BUF_LEN(at) = 0;
- cancpy = M_TRAILINGSPACE(at);
+ cancpy = (int)M_TRAILINGSPACE(at);
willcpy = min(cancpy, left);
}
}
@@ -7233,6 +7366,22 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
int ret;
struct sctp_copy_all *ca;
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SND_ITERATOR_UP) {
+ /* There is another. */
+ return (EBUSY);
+ }
+#if defined(__APPLE__) && !defined(__Userspace__)
+#if defined(APPLE_LEOPARD)
+ if (uio->uio_resid > SCTP_BASE_SYSCTL(sctp_sendall_limit)) {
+#else
+ if (uio_resid(uio) > SCTP_BASE_SYSCTL(sctp_sendall_limit)) {
+#endif
+#else
+ if (uio->uio_resid > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) {
+#endif
+ /* You must not be larger than the limit! */
+ return (EMSGSIZE);
+ }
SCTP_MALLOC(ca, struct sctp_copy_all *, sizeof(struct sctp_copy_all),
SCTP_M_COPYAL);
if (ca == NULL) {
@@ -7253,7 +7402,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL;
/* get length and mbuf chain */
if (uio) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
ca->sndlen = uio->uio_resid;
#else
@@ -7262,11 +7411,11 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
#else
ca->sndlen = uio->uio_resid;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 0);
#endif
ca->m = sctp_copy_out_all(uio, ca->sndlen);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 0);
#endif
if (ca->m == NULL) {
@@ -7283,13 +7432,14 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
ca->sndlen += SCTP_BUF_LEN(mat);
}
}
+ inp->sctp_flags |= SCTP_PCB_FLAGS_SND_ITERATOR_UP;
ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL,
SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES,
SCTP_ASOC_ANY_STATE,
(void *)ca, 0,
sctp_sendall_completes, inp, 1);
if (ret) {
- SCTP_PRINTF("Failed to initiate iterator for sendall\n");
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP;
SCTP_FREE(ca, SCTP_M_COPYAL);
SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
return (EFAULT);
@@ -7297,7 +7447,6 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
return (0);
}
-
void
sctp_toss_old_cookies(struct sctp_tcb *stcb, struct sctp_association *asoc)
{
@@ -7306,11 +7455,11 @@ sctp_toss_old_cookies(struct sctp_tcb *stcb, struct sctp_association *asoc)
TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) {
if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) {
TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
+ asoc->ctrl_queue_cnt--;
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
- asoc->ctrl_queue_cnt--;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
}
@@ -7335,17 +7484,16 @@ sctp_toss_old_asconf(struct sctp_tcb *stcb)
}
}
TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next);
+ asoc->ctrl_queue_cnt--;
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
- asoc->ctrl_queue_cnt--;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
}
}
-
static void
sctp_clean_up_datalist(struct sctp_tcb *stcb,
struct sctp_association *asoc,
@@ -7371,14 +7519,14 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb,
/* record time */
data_list[i]->sent_rcv_time = net->last_sent_time;
data_list[i]->rec.data.cwnd_at_send = net->cwnd;
- data_list[i]->rec.data.fast_retran_tsn = data_list[i]->rec.data.TSN_seq;
+ data_list[i]->rec.data.fast_retran_tsn = data_list[i]->rec.data.tsn;
if (data_list[i]->whoTo == NULL) {
data_list[i]->whoTo = net;
atomic_add_int(&net->ref_count, 1);
}
/* on to the sent queue */
tp1 = TAILQ_LAST(&asoc->sent_queue, sctpchunk_listhead);
- if ((tp1) && SCTP_TSN_GT(tp1->rec.data.TSN_seq, data_list[i]->rec.data.TSN_seq)) {
+ if ((tp1) && SCTP_TSN_GT(tp1->rec.data.tsn, data_list[i]->rec.data.tsn)) {
struct sctp_tmit_chunk *tpp;
/* need to move back */
@@ -7389,7 +7537,7 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb,
goto all_done;
}
tp1 = tpp;
- if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, data_list[i]->rec.data.TSN_seq)) {
+ if (SCTP_TSN_GT(tp1->rec.data.tsn, data_list[i]->rec.data.tsn)) {
goto back_up_more;
}
TAILQ_INSERT_AFTER(&asoc->sent_queue, tp1, data_list[i], sctp_next);
@@ -7417,8 +7565,8 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
data_list[i]->whoTo->flight_size,
data_list[i]->book_size,
- (uintptr_t)data_list[i]->whoTo,
- data_list[i]->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)data_list[i]->whoTo,
+ data_list[i]->rec.data.tsn);
}
sctp_flight_size_increase(data_list[i]);
sctp_total_flight_increase(stcb, data_list[i]);
@@ -7439,11 +7587,7 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb,
}
static void
-sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_locked)
{
struct sctp_tmit_chunk *chk, *nchk;
@@ -7463,13 +7607,14 @@ sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_l
/* Stray chunks must be cleaned up */
clean_up_anyway:
TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
+ asoc->ctrl_queue_cnt--;
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
- asoc->ctrl_queue_cnt--;
- if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN)
+ if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) {
asoc->fwd_tsn_cnt--;
+ }
sctp_free_a_chunk(stcb, chk, so_locked);
} else if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) {
/* special handling, we must look into the param */
@@ -7480,11 +7625,9 @@ sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_l
}
}
-
-static int
-sctp_can_we_split_this(struct sctp_tcb *stcb,
- uint32_t length,
- uint32_t goal_mtu, uint32_t frag_point, int eeor_on)
+static uint32_t
+sctp_can_we_split_this(struct sctp_tcb *stcb, uint32_t length,
+ uint32_t space_left, uint32_t frag_point, int eeor_on)
{
/* Make a decision on if I should split a
* msg into multiple parts. This is only asked of
@@ -7495,7 +7638,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
* it if its the entire thing, since it might
* be all the guy is putting in the hopper.
*/
- if (goal_mtu >= length) {
+ if (space_left >= length) {
/*-
* If we have data outstanding,
* we get another chance when the sack
@@ -7511,7 +7654,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
} else {
/* You can fill the rest */
- return (goal_mtu);
+ return (space_left);
}
}
/*-
@@ -7522,46 +7665,41 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
if (SCTP_SB_LIMIT_SND(stcb->sctp_socket) < frag_point) {
return (length);
}
-
- if ((length <= goal_mtu) ||
- ((length - goal_mtu) < SCTP_BASE_SYSCTL(sctp_min_residual))) {
+ if ((length <= space_left) ||
+ ((length - space_left) < SCTP_BASE_SYSCTL(sctp_min_residual))) {
/* Sub-optimial residual don't split in non-eeor mode. */
return (0);
}
/* If we reach here length is larger
- * than the goal_mtu. Do we wish to split
+ * than the space_left. Do we wish to split
* it for the sake of packet putting together?
*/
- if (goal_mtu >= min(SCTP_BASE_SYSCTL(sctp_min_split_point), frag_point)) {
+ if (space_left >= min(SCTP_BASE_SYSCTL(sctp_min_split_point), frag_point)) {
/* Its ok to split it */
- return (min(goal_mtu, frag_point));
+ return (min(space_left, frag_point));
}
/* Nope, can't split */
return (0);
-
}
static uint32_t
sctp_move_to_outqueue(struct sctp_tcb *stcb,
struct sctp_stream_out *strq,
- uint32_t goal_mtu,
+ uint32_t space_left,
uint32_t frag_point,
- int *locked,
int *giveup,
int eeor_mode,
int *bail,
- int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ int so_locked)
{
/* Move from the stream to the send_queue keeping track of the total */
struct sctp_association *asoc;
struct sctp_stream_queue_pending *sp;
struct sctp_tmit_chunk *chk;
- struct sctp_data_chunk *dchkh;
+ struct sctp_data_chunk *dchkh=NULL;
+ struct sctp_idata_chunk *ndchkh=NULL;
uint32_t to_move, length;
+ int leading;
uint8_t rcv_flags = 0;
uint8_t some_taken;
uint8_t send_lock_up = 0;
@@ -7572,7 +7710,6 @@ one_more_time:
/*sa_ignore FREED_MEMORY*/
sp = TAILQ_FIRST(&strq->outqueue);
if (sp == NULL) {
- *locked = 0;
if (send_lock_up == 0) {
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
@@ -7581,9 +7718,11 @@ one_more_time:
if (sp) {
goto one_more_time;
}
- if (strq->last_msg_incomplete) {
+ if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_EXPLICIT_EOR) == 0) &&
+ (stcb->asoc.idata_supported == 0) &&
+ (strq->last_msg_incomplete)) {
SCTP_PRINTF("Huh? Stream:%d lm_in_c=%d but queue is NULL\n",
- strq->stream_no,
+ strq->sid,
strq->last_msg_incomplete);
strq->last_msg_incomplete = 0;
}
@@ -7596,7 +7735,7 @@ one_more_time:
}
if ((sp->msg_is_complete) && (sp->length == 0)) {
if (sp->sender_all_done) {
- /* We are doing differed cleanup. Last
+ /* We are doing deferred cleanup. Last
* time through when we took all the data
* the sender_all_done was not set.
*/
@@ -7616,6 +7755,11 @@ one_more_time:
atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&strq->outqueue, sp, next);
stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
+ if ((strq->state == SCTP_STREAM_RESET_PENDING) &&
+ (strq->chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&strq->outqueue)) {
+ stcb->asoc.trigger_reset = 1;
+ }
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -7626,8 +7770,6 @@ one_more_time:
}
sctp_free_a_strmoq(stcb, sp, so_locked);
/* we can't be locked to it */
- *locked = 0;
- stcb->asoc.locked_on_sending = NULL;
if (send_lock_up) {
SCTP_TCB_SEND_UNLOCK(stcb);
send_lock_up = 0;
@@ -7638,7 +7780,6 @@ one_more_time:
/* sender just finished this but
* still holds a reference
*/
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7647,7 +7788,6 @@ one_more_time:
/* is there some to get */
if (sp->length == 0) {
/* no */
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7658,7 +7798,7 @@ one_more_time:
}
/* Whack down the size */
atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length);
- if ((stcb->sctp_socket != NULL) && \
+ if ((stcb->sctp_socket != NULL) &&
((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc, sp->length);
@@ -7670,16 +7810,12 @@ one_more_time:
}
sp->length = 0;
sp->some_taken = 1;
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
}
}
some_taken = sp->some_taken;
- if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
- sp->msg_is_complete = 1;
- }
re_look:
length = sp->length;
if (sp->msg_is_complete) {
@@ -7689,10 +7825,12 @@ re_look:
/* All of it fits in the MTU */
if (sp->some_taken) {
rcv_flags |= SCTP_DATA_LAST_FRAG;
- sp->put_last_out = 1;
} else {
rcv_flags |= SCTP_DATA_NOT_FRAG;
- sp->put_last_out = 1;
+ }
+ sp->put_last_out = 1;
+ if (sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) {
+ rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY;
}
} else {
/* Not all of it fits, we fragment */
@@ -7702,7 +7840,7 @@ re_look:
sp->some_taken = 1;
}
} else {
- to_move = sctp_can_we_split_this(stcb, length, goal_mtu, frag_point, eeor_mode);
+ to_move = sctp_can_we_split_this(stcb, length, space_left, frag_point, eeor_mode);
if (to_move) {
/*-
* We use a snapshot of length in case it
@@ -7732,9 +7870,6 @@ re_look:
}
} else {
/* Nothing to take. */
- if (sp->some_taken) {
- *locked = 1;
- }
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7755,8 +7890,8 @@ re_look:
if (sp->sinfo_flags & SCTP_UNORDERED) {
rcv_flags |= SCTP_DATA_UNORDERED;
}
- if ((SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && ((sp->sinfo_flags & SCTP_EOF) == SCTP_EOF)) ||
- ((sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) == SCTP_SACK_IMMEDIATELY)) {
+ if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) &&
+ (sp->sinfo_flags & SCTP_EOF) == SCTP_EOF) {
rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY;
}
/* clear out the chunk before setting up */
@@ -7814,7 +7949,6 @@ re_look:
sp->tail_mbuf = sp->data = NULL;
sp->length = 0;
#endif
-
}
sctp_m_free(m);
m = sp->data;
@@ -7825,7 +7959,7 @@ re_look:
} else {
chk->copy_by_ref = 0;
}
- /* get last_mbuf and counts of mb useage
+ /* get last_mbuf and counts of mb usage
* This is ugly but hopefully its only one mbuf.
*/
if (chk->last_mbuf == NULL) {
@@ -7849,11 +7983,12 @@ re_look:
} else {
atomic_subtract_int(&sp->length, to_move);
}
- if (M_LEADINGSPACE(chk->data) < (int)sizeof(struct sctp_data_chunk)) {
+ leading = SCTP_DATA_CHUNK_OVERHEAD(stcb);
+ if (M_LEADINGSPACE(chk->data) < leading) {
/* Not enough room for a chunk header, get some */
struct mbuf *m;
- m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 0, MT_DATA);
+ m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 1, MT_DATA);
if (m == NULL) {
/*
* we're in trouble here. _PREPEND below will free
@@ -7889,7 +8024,7 @@ re_look:
M_ALIGN(chk->data, 4);
}
}
- SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT);
+ SCTP_BUF_PREPEND(chk->data, SCTP_DATA_CHUNK_OVERHEAD(stcb), M_NOWAIT);
if (chk->data == NULL) {
/* HELP, TSNH since we assured it would not above? */
#ifdef INVARIANTS
@@ -7902,8 +8037,8 @@ re_look:
to_move = 0;
goto out_of;
}
- sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
- chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk));
+ sctp_snd_sb_alloc(stcb, SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ chk->book_size = chk->send_size = (uint16_t)(to_move + SCTP_DATA_CHUNK_OVERHEAD(stcb));
chk->book_size_scale = 0;
chk->sent = SCTP_DATAGRAM_UNSENT;
@@ -7911,13 +8046,31 @@ re_look:
chk->asoc = &stcb->asoc;
chk->pad_inplace = 0;
chk->no_fr_allowed = 0;
- chk->rec.data.stream_seq = strq->next_sequence_send;
- if ((rcv_flags & SCTP_DATA_LAST_FRAG) &&
- !(rcv_flags & SCTP_DATA_UNORDERED)) {
- strq->next_sequence_send++;
+ if (stcb->asoc.idata_supported == 0) {
+ if (rcv_flags & SCTP_DATA_UNORDERED) {
+ /* Just use 0. The receiver ignores the values. */
+ chk->rec.data.mid = 0;
+ } else {
+ chk->rec.data.mid = strq->next_mid_ordered;
+ if (rcv_flags & SCTP_DATA_LAST_FRAG) {
+ strq->next_mid_ordered++;
+ }
+ }
+ } else {
+ if (rcv_flags & SCTP_DATA_UNORDERED) {
+ chk->rec.data.mid = strq->next_mid_unordered;
+ if (rcv_flags & SCTP_DATA_LAST_FRAG) {
+ strq->next_mid_unordered++;
+ }
+ } else {
+ chk->rec.data.mid = strq->next_mid_ordered;
+ if (rcv_flags & SCTP_DATA_LAST_FRAG) {
+ strq->next_mid_ordered++;
+ }
+ }
}
- chk->rec.data.stream_number = sp->stream;
- chk->rec.data.payloadtype = sp->ppid;
+ chk->rec.data.sid = sp->sid;
+ chk->rec.data.ppid = sp->ppid;
chk->rec.data.context = sp->context;
chk->rec.data.doing_fast_retransmit = 0;
@@ -7935,18 +8088,22 @@ re_look:
sctp_auth_key_acquire(stcb, chk->auth_keyid);
chk->holds_key_ref = 1;
}
-#if defined(__FreeBSD__) || defined(__Panda__)
- chk->rec.data.TSN_seq = atomic_fetchadd_int(&asoc->sending_seq, 1);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ chk->rec.data.tsn = atomic_fetchadd_int(&asoc->sending_seq, 1);
#else
- chk->rec.data.TSN_seq = asoc->sending_seq++;
+ chk->rec.data.tsn = asoc->sending_seq++;
#endif
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_AT_SEND_2_OUTQ) {
sctp_misc_ints(SCTP_STRMOUT_LOG_SEND,
- (uintptr_t)stcb, sp->length,
- (uint32_t)((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq),
- chk->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)stcb, sp->length,
+ (uint32_t)((chk->rec.data.sid << 16) | (0x0000ffff & chk->rec.data.mid)),
+ chk->rec.data.tsn);
+ }
+ if (stcb->asoc.idata_supported == 0) {
+ dchkh = mtod(chk->data, struct sctp_data_chunk *);
+ } else {
+ ndchkh = mtod(chk->data, struct sctp_idata_chunk *);
}
- dchkh = mtod(chk->data, struct sctp_data_chunk *);
/*
* Put the rest of the things in place now. Size was done
* earlier in previous loop prior to padding.
@@ -7958,9 +8115,9 @@ re_look:
asoc->tsn_out_at = 0;
asoc->tsn_out_wrapped = 1;
}
- asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.TSN_seq;
- asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.stream_number;
- asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.stream_seq;
+ asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.tsn;
+ asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.sid;
+ asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.mid;
asoc->out_tsnlog[asoc->tsn_out_at].sz = chk->send_size;
asoc->out_tsnlog[asoc->tsn_out_at].flgs = chk->rec.data.rcv_flags;
asoc->out_tsnlog[asoc->tsn_out_at].stcb = (void *)stcb;
@@ -7968,14 +8125,28 @@ re_look:
asoc->out_tsnlog[asoc->tsn_out_at].in_out = 2;
asoc->tsn_out_at++;
#endif
-
- dchkh->ch.chunk_type = SCTP_DATA;
- dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
- dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
- dchkh->dp.stream_id = htons(strq->stream_no);
- dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq);
- dchkh->dp.protocol_id = chk->rec.data.payloadtype;
- dchkh->ch.chunk_length = htons(chk->send_size);
+ if (stcb->asoc.idata_supported == 0) {
+ dchkh->ch.chunk_type = SCTP_DATA;
+ dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
+ dchkh->dp.tsn = htonl(chk->rec.data.tsn);
+ dchkh->dp.sid = htons(strq->sid);
+ dchkh->dp.ssn = htons((uint16_t)chk->rec.data.mid);
+ dchkh->dp.ppid = chk->rec.data.ppid;
+ dchkh->ch.chunk_length = htons(chk->send_size);
+ } else {
+ ndchkh->ch.chunk_type = SCTP_IDATA;
+ ndchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
+ ndchkh->dp.tsn = htonl(chk->rec.data.tsn);
+ ndchkh->dp.sid = htons(strq->sid);
+ ndchkh->dp.reserved = htons(0);
+ ndchkh->dp.mid = htonl(chk->rec.data.mid);
+ if (sp->fsn == 0)
+ ndchkh->dp.ppid_fsn.ppid = chk->rec.data.ppid;
+ else
+ ndchkh->dp.ppid_fsn.fsn = htonl(sp->fsn);
+ sp->fsn++;
+ ndchkh->ch.chunk_length = htons(chk->send_size);
+ }
/* Now advance the chk->send_size by the actual pad needed. */
if (chk->send_size < SCTP_SIZE32(chk->book_size)) {
/* need a pad */
@@ -7995,7 +8166,6 @@ re_look:
}
if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) {
/* All done pull and kill the message */
- atomic_subtract_int(&asoc->stream_queue_cnt, 1);
if (sp->put_last_out == 0) {
SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n");
SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n",
@@ -8009,8 +8179,14 @@ re_look:
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
}
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&strq->outqueue, sp, next);
stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
+ if ((strq->state == SCTP_STREAM_RESET_PENDING) &&
+ (strq->chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&strq->outqueue)) {
+ stcb->asoc.trigger_reset = 1;
+ }
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -8020,13 +8196,6 @@ re_look:
sp->data = NULL;
}
sctp_free_a_strmoq(stcb, sp, so_locked);
-
- /* we can't be locked to it */
- *locked = 0;
- stcb->asoc.locked_on_sending = NULL;
- } else {
- /* more to go, we are locked */
- *locked = 1;
}
asoc->chunks_on_out_queue++;
strq->chunks_on_queues++;
@@ -8039,84 +8208,69 @@ out_of:
return (to_move);
}
-
static void
sctp_fill_outqueue(struct sctp_tcb *stcb,
- struct sctp_nets *net, int frag_point, int eeor_mode, int *quit_now, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+ struct sctp_nets *net, int frag_point, int eeor_mode, int *quit_now, int so_locked)
{
struct sctp_association *asoc;
struct sctp_stream_out *strq;
- int goal_mtu, moved_how_much, total_moved = 0, bail = 0;
- int locked, giveup;
+ uint32_t space_left, moved, total_moved;
+ int bail, giveup;
SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc;
+ total_moved = 0;
switch (net->ro._l_addr.sa.sa_family) {
#ifdef INET
case AF_INET:
- goal_mtu = net->mtu - SCTP_MIN_V4_OVERHEAD;
+ space_left = net->mtu - SCTP_MIN_V4_OVERHEAD;
break;
#endif
#ifdef INET6
case AF_INET6:
- goal_mtu = net->mtu - SCTP_MIN_OVERHEAD;
+ space_left = net->mtu - SCTP_MIN_OVERHEAD;
break;
#endif
#if defined(__Userspace__)
case AF_CONN:
- goal_mtu = net->mtu - sizeof(struct sctphdr);
+ space_left = net->mtu - sizeof(struct sctphdr);
break;
#endif
default:
/* TSNH */
- goal_mtu = net->mtu;
+ space_left = net->mtu;
break;
}
/* Need an allowance for the data chunk header too */
- goal_mtu -= sizeof(struct sctp_data_chunk);
+ space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb);
/* must make even word boundary */
- goal_mtu &= 0xfffffffc;
- if (asoc->locked_on_sending) {
- /* We are stuck on one stream until the message completes. */
- strq = asoc->locked_on_sending;
- locked = 1;
- } else {
+ space_left &= 0xfffffffc;
+ strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
+ giveup = 0;
+ bail = 0;
+ while ((space_left > 0) && (strq != NULL)) {
+ moved = sctp_move_to_outqueue(stcb, strq, space_left, frag_point,
+ &giveup, eeor_mode, &bail, so_locked);
+ stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved);
+ if ((giveup != 0) || (bail != 0)) {
+ break;
+ }
strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
- locked = 0;
- }
- while ((goal_mtu > 0) && strq) {
- giveup = 0;
- bail = 0;
- moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &locked,
- &giveup, eeor_mode, &bail, so_locked);
- if (moved_how_much)
- stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much);
-
- if (locked) {
- asoc->locked_on_sending = strq;
- if ((moved_how_much == 0) || (giveup) || bail)
- /* no more to move for now */
- break;
+ total_moved += moved;
+ if (space_left >= moved) {
+ space_left -= moved;
} else {
- asoc->locked_on_sending = NULL;
- if ((giveup) || bail) {
- break;
- }
- strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
- if (strq == NULL) {
- break;
- }
+ space_left = 0;
+ }
+ if (space_left >= SCTP_DATA_CHUNK_OVERHEAD(stcb)) {
+ space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb);
+ } else {
+ space_left = 0;
}
- total_moved += moved_how_much;
- goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk));
- goal_mtu &= 0xfffffffc;
+ space_left &= 0xfffffffc;
}
- if (bail)
+ if (bail != 0)
*quit_now = 1;
stcb->asoc.ss_functions.sctp_ss_packet_done(stcb, net, asoc);
@@ -8180,20 +8334,19 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int *num_out,
int *reason_code,
int control_only, int from_where,
- struct timeval *now, int *now_filled, int frag_point, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ struct timeval *now, int *now_filled, int frag_point, int so_locked)
{
/**
* Ok this is the generic chunk service queue. we must do the
- * following: - Service the stream queue that is next, moving any
- * message (note I must get a complete message i.e. FIRST/MIDDLE and
- * LAST to the out queue in one pass) and assigning TSN's - Check to
- * see if the cwnd/rwnd allows any output, if so we go ahead and
- * fomulate and send the low level chunks. Making sure to combine
- * any control in the control chunk queue also.
+ * following:
+ * - Service the stream queue that is next, moving any
+ * message (note I must get a complete message i.e. FIRST/MIDDLE and
+ * LAST to the out queue in one pass) and assigning TSN's. This
+ * only applys though if the peer does not support NDATA. For NDATA
+ * chunks its ok to not send the entire message ;-)
+ * - Check to see if the cwnd/rwnd allows any output, if so we go ahead and
+ * fomulate and send the low level chunks. Making sure to combine
+ * any control in the control chunk queue also.
*/
struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL;
struct mbuf *outchain, *endoutchain;
@@ -8208,8 +8361,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int bundle_at, ctl_cnt, no_data_chunks, eeor_mode;
unsigned int mtu, r_mtu, omtu, mx_mtu, to_out;
int tsns_sent = 0;
- uint32_t auth_offset = 0;
- struct sctp_auth_chunk *auth = NULL;
+ uint32_t auth_offset;
+ struct sctp_auth_chunk *auth;
uint16_t auth_keyid;
int override_ok = 1;
int skip_fill_up = 0;
@@ -8218,7 +8371,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
the destination. */
int quit_now = 0;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
} else {
@@ -8229,7 +8382,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
*reason_code = 0;
auth_keyid = stcb->asoc.authinfo.active_keyid;
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
- (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
eeor_mode = 1;
} else {
@@ -8246,7 +8399,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
#endif
SCTP_TCB_LOCK_ASSERT(stcb);
hbflag = 0;
- if ((control_only) || (asoc->stream_reset_outstanding))
+ if (control_only)
no_data_chunks = 1;
else
no_data_chunks = 0;
@@ -8256,7 +8409,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
(asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) &&
TAILQ_EMPTY(&asoc->asconf_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, so_locked) == 0) {
nothing_to_send:
*reason_code = 9;
return (0);
@@ -8301,7 +8454,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
break;
}
}
-
}
if ((no_data_chunks == 0) &&
(skip_fill_up == 0) &&
@@ -8327,7 +8479,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
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)) {
@@ -8389,7 +8541,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
}
old_start_at = NULL;
again_one_more_time:
- for (net = start_at ; net != NULL; net = TAILQ_NEXT(net, sctp_next)) {
+ for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) {
/* how much can we send? */
/* SCTPDBG("Examine for sending net:%x\n", (uint32_t)net); */
if (old_start_at && (old_start_at == net)) {
@@ -8407,6 +8559,8 @@ again_one_more_time:
}
bundle_at = 0;
endoutchain = outchain = NULL;
+ auth = NULL;
+ auth_offset = 0;
no_fragmentflg = 1;
one_chunk = 0;
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
@@ -8417,12 +8571,12 @@ again_one_more_time:
switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
#ifdef INET
case AF_INET:
- mtu = net->mtu - (sizeof(struct ip) + sizeof(struct sctphdr));
+ mtu = net->mtu - SCTP_MIN_V4_OVERHEAD;
break;
#endif
#ifdef INET6
case AF_INET6:
- mtu = net->mtu - (sizeof(struct ip6_hdr) + sizeof(struct sctphdr));
+ mtu = net->mtu - SCTP_MIN_OVERHEAD;
break;
#endif
#if defined(__Userspace__)
@@ -8449,6 +8603,7 @@ again_one_more_time:
} else {
r_mtu = mtu;
}
+ error = 0;
/************************/
/* ASCONF transmission */
/************************/
@@ -8574,6 +8729,12 @@ again_one_more_time:
* appropriate source address
* selection.
*/
+ if (*now_filled == 0) {
+ (void)SCTP_GETTIME_TIMEVAL(now);
+ *now_filled = 1;
+ }
+ net->last_sent_time = *now;
+ hbflag = 0;
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain, auth_offset, auth,
@@ -8582,25 +8743,19 @@ again_one_more_time:
inp->sctp_lport, stcb->rport,
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
so_locked))) {
- if (error == ENOBUFS) {
- asoc->ifp_had_enobuf = 1;
- SCTP_STAT_INCR(sctps_lowlevelerr);
- }
+ /* error, we could not output */
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
}
- hbflag = 0;
/* error, could not output */
if (error == EHOSTUNREACH) {
/*
@@ -8611,17 +8766,10 @@ again_one_more_time:
sctp_move_chunks_from_net(stcb, net);
}
*reason_code = 7;
- continue;
- } else
- asoc->ifp_had_enobuf = 0;
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
+ break;
} else {
- net->last_sent_time = *now;
+ asoc->ifp_had_enobuf = 0;
}
- hbflag = 0;
/*
* increase the number we sent, if a
* cookie is sent we don't tell them
@@ -8659,6 +8807,10 @@ again_one_more_time:
}
}
}
+ if (error != 0) {
+ /* try next net */
+ continue;
+ }
/************************/
/* Control transmission */
/************************/
@@ -8790,7 +8942,8 @@ again_one_more_time:
/* turn off the timer */
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- inp, stcb, net, SCTP_FROM_SCTP_OUTPUT+SCTP_LOC_1);
+ inp, stcb, NULL,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1);
}
}
ctl_cnt++;
@@ -8843,6 +8996,15 @@ again_one_more_time:
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
cookie = 0;
}
+ /* Only HB or ASCONF advances time */
+ if (hbflag) {
+ if (*now_filled == 0) {
+ (void)SCTP_GETTIME_TIMEVAL(now);
+ *now_filled = 1;
+ }
+ net->last_sent_time = *now;
+ hbflag = 0;
+ }
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain,
@@ -8852,27 +9014,18 @@ again_one_more_time:
inp->sctp_lport, stcb->rport,
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
so_locked))) {
- if (error == ENOBUFS) {
- asoc->ifp_had_enobuf = 1;
- SCTP_STAT_INCR(sctps_lowlevelerr);
- }
+ /* error, we could not output */
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- /* error, could not output */
- if (hbflag) {
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- hbflag = 0;
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
}
if (error == EHOSTUNREACH) {
/*
@@ -8883,19 +9036,9 @@ again_one_more_time:
sctp_move_chunks_from_net(stcb, net);
}
*reason_code = 7;
- continue;
- } else
+ break;
+ } else {
asoc->ifp_had_enobuf = 0;
- /* Only HB or ASCONF advances time */
- if (hbflag) {
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- hbflag = 0;
}
/*
* increase the number we sent, if a
@@ -8934,6 +9077,10 @@ again_one_more_time:
}
}
}
+ if (error != 0) {
+ /* try next net */
+ continue;
+ }
/* JRI: if dest is in PF state, do not send data to it */
if ((asoc->sctp_cmt_on_off > 0) &&
(net != stcb->asoc.alternate) &&
@@ -8978,16 +9125,16 @@ again_one_more_time:
switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
#ifdef INET
case AF_INET:
- if (net->mtu > (sizeof(struct ip) + sizeof(struct sctphdr)))
- omtu = net->mtu - (sizeof(struct ip) + sizeof(struct sctphdr));
+ if (net->mtu > SCTP_MIN_V4_OVERHEAD)
+ omtu = net->mtu - SCTP_MIN_V4_OVERHEAD;
else
omtu = 0;
break;
#endif
#ifdef INET6
case AF_INET6:
- if (net->mtu > (sizeof(struct ip6_hdr) + sizeof(struct sctphdr)))
- omtu = net->mtu - (sizeof(struct ip6_hdr) + sizeof(struct sctphdr));
+ if (net->mtu > SCTP_MIN_OVERHEAD)
+ omtu = net->mtu - SCTP_MIN_OVERHEAD;
else
omtu = 0;
break;
@@ -9006,7 +9153,8 @@ again_one_more_time:
omtu = 0;
break;
}
- if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) &&
+ if ((((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
(skip_data_for_this_net == 0)) ||
(cookie)) {
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
@@ -9055,7 +9203,7 @@ again_one_more_time:
chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
}
if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) &&
- ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) == SCTP_STATE_SHUTDOWN_PENDING)) {
+ (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) {
struct sctp_data_chunk *dchkh;
dchkh = mtod(chk->data, struct sctp_data_chunk *);
@@ -9185,6 +9333,14 @@ again_one_more_time:
*/
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
+ if (bundle_at || hbflag) {
+ /* For data/asconf and hb set time */
+ if (*now_filled == 0) {
+ (void)SCTP_GETTIME_TIMEVAL(now);
+ *now_filled = 1;
+ }
+ net->last_sent_time = *now;
+ }
/* Now send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp,
stcb,
@@ -9200,28 +9356,18 @@ again_one_more_time:
inp->sctp_lport, stcb->rport,
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
so_locked))) {
/* error, we could not output */
- if (error == ENOBUFS) {
- SCTP_STAT_INCR(sctps_lowlevelerr);
- asoc->ifp_had_enobuf = 1;
- }
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
- if (hbflag) {
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- hbflag = 0;
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
}
if (error == EHOSTUNREACH) {
/*
@@ -9237,7 +9383,7 @@ again_one_more_time:
* the top of the for, but just to make sure
* I will reset these again here.
*/
- ctl_cnt = bundle_at = 0;
+ ctl_cnt = 0;
continue; /* This takes us back to the for() for the nets. */
} else {
asoc->ifp_had_enobuf = 0;
@@ -9245,22 +9391,12 @@ again_one_more_time:
endoutchain = NULL;
auth = NULL;
auth_offset = 0;
- if (bundle_at || hbflag) {
- /* For data/asconf and hb set time */
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- }
if (!no_out_cnt) {
*num_out += (ctl_cnt + bundle_at);
}
if (bundle_at) {
/* setup for a RTO measurement */
- tsns_sent = data_list[0]->rec.data.TSN_seq;
+ tsns_sent = data_list[0]->rec.data.tsn;
/* fill time if not already filled */
if (*now_filled == 0) {
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_last_sent);
@@ -9316,9 +9452,37 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
*/
struct sctp_chunkhdr *hdr;
struct sctp_tmit_chunk *chk;
- struct mbuf *mat;
+ struct mbuf *mat, *last_mbuf;
+ uint32_t chunk_length;
+ uint16_t padding_length;
SCTP_TCB_LOCK_ASSERT(stcb);
+ SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT);
+ if (op_err == NULL) {
+ return;
+ }
+ last_mbuf = NULL;
+ chunk_length = 0;
+ for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) {
+ chunk_length += SCTP_BUF_LEN(mat);
+ if (SCTP_BUF_NEXT(mat) == NULL) {
+ last_mbuf = mat;
+ }
+ }
+ if (chunk_length > SCTP_MAX_CHUNK_LENGTH) {
+ sctp_m_freem(op_err);
+ return;
+ }
+ padding_length = chunk_length % 4;
+ if (padding_length != 0) {
+ padding_length = 4 - padding_length;
+ }
+ if (padding_length != 0) {
+ if (sctp_add_pad_tombuf(last_mbuf, padding_length) == NULL) {
+ sctp_m_freem(op_err);
+ return;
+ }
+ }
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
/* no memory */
@@ -9326,15 +9490,10 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
return;
}
chk->copy_by_ref = 0;
- SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT);
- if (op_err == NULL) {
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- return;
- }
- chk->send_size = 0;
- for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) {
- chk->send_size += SCTP_BUF_LEN(mat);
- }
+ chk->rec.chunk_id.id = SCTP_OPERATION_ERROR;
+ chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
+ chk->send_size = (uint16_t)chunk_length;
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->asoc = &stcb->asoc;
@@ -9344,15 +9503,13 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
hdr->chunk_type = SCTP_OPERATION_ERROR;
hdr->chunk_flags = 0;
hdr->chunk_length = htons(chk->send_size);
- TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue,
- chk,
- sctp_next);
+ TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
}
int
sctp_send_cookie_echo(struct mbuf *m,
- int offset,
+ int offset, int limit,
struct sctp_tcb *stcb,
struct sctp_nets *net)
{
@@ -9362,7 +9519,7 @@ sctp_send_cookie_echo(struct mbuf *m,
*/
int at;
struct mbuf *cookie;
- struct sctp_paramhdr parm, *phdr;
+ struct sctp_paramhdr param, *phdr;
struct sctp_chunkhdr *hdr;
struct sctp_tmit_chunk *chk;
uint16_t ptype, plen;
@@ -9372,24 +9529,35 @@ sctp_send_cookie_echo(struct mbuf *m,
cookie = NULL;
at = offset + sizeof(struct sctp_init_chunk);
for (;;) {
- phdr = sctp_get_next_param(m, at, &parm, sizeof(parm));
+ phdr = sctp_get_next_param(m, at, &param, sizeof(param));
if (phdr == NULL) {
return (-3);
}
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
+ if (plen < sizeof(struct sctp_paramhdr)) {
+ return (-6);
+ }
if (ptype == SCTP_STATE_COOKIE) {
int pad;
/* found the cookie */
- if ((pad = (plen % 4))) {
- plen += 4 - pad;
+ if (at + plen > limit) {
+ return (-7);
}
cookie = SCTP_M_COPYM(m, at, plen, M_NOWAIT);
if (cookie == NULL) {
/* No memory */
return (-2);
}
+ if ((pad = (plen % 4)) > 0) {
+ pad = 4 - pad;
+ }
+ if (pad > 0) {
+ if (sctp_pad_lastmbuf(cookie, pad, NULL) == NULL) {
+ return (-8);
+ }
+ }
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
sctp_log_mbc(cookie, SCTP_MBUF_ICOPY);
@@ -9415,7 +9583,7 @@ sctp_send_cookie_echo(struct mbuf *m,
chk->rec.chunk_id.id = SCTP_COOKIE_ECHO;
chk->rec.chunk_id.can_take_data = 0;
chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
- chk->send_size = plen;
+ chk->send_size = SCTP_SIZE32(plen);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->asoc = &stcb->asoc;
@@ -9441,7 +9609,6 @@ sctp_send_heartbeat_ack(struct sctp_tcb *stcb,
struct sctp_chunkhdr *chdr;
struct sctp_tmit_chunk *chk;
-
if (net == NULL)
/* must have a net pointer */
return;
@@ -9459,13 +9626,8 @@ sctp_send_heartbeat_ack(struct sctp_tcb *stcb,
chdr = mtod(outchain, struct sctp_chunkhdr *);
chdr->chunk_type = SCTP_HEARTBEAT_ACK;
chdr->chunk_flags = 0;
- if (chk_length % 4) {
- /* need pad */
- uint32_t cpthis = 0;
- int padlen;
-
- padlen = 4 - (chk_length % 4);
- m_copyback(outchain, chk_length, padlen, (caddr_t)&cpthis);
+ if (chk_length % 4 != 0) {
+ sctp_pad_lastmbuf(outchain, 4 - (chk_length % 4), NULL);
}
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
@@ -9535,7 +9697,6 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb)
return;
}
-
void
sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net)
{
@@ -9563,7 +9724,6 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net)
chk->send_size = sizeof(struct sctp_chunkhdr);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = m_shutdown_ack;
chk->whoTo = net;
@@ -9588,40 +9748,60 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net)
struct sctp_shutdown_chunk *shutdown_cp;
struct sctp_tmit_chunk *chk;
- m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER);
- if (m_shutdown == NULL) {
- /* no mbuf's */
- return;
+ TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
+ if (chk->rec.chunk_id.id == SCTP_SHUTDOWN) {
+ /* We already have a SHUTDOWN queued. Reuse it. */
+ if (chk->whoTo) {
+ sctp_free_remote_addr(chk->whoTo);
+ chk->whoTo = NULL;
+ }
+ break;
+ }
}
- SCTP_BUF_RESV_UF(m_shutdown, SCTP_MIN_OVERHEAD);
- sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
- /* no memory */
- sctp_m_freem(m_shutdown);
- return;
- }
- chk->copy_by_ref = 0;
- chk->rec.chunk_id.id = SCTP_SHUTDOWN;
- chk->rec.chunk_id.can_take_data = 1;
- chk->flags = 0;
- chk->send_size = sizeof(struct sctp_shutdown_chunk);
- chk->sent = SCTP_DATAGRAM_UNSENT;
- chk->snd_count = 0;
- chk->flags = 0;
- chk->asoc = &stcb->asoc;
- chk->data = m_shutdown;
- chk->whoTo = net;
- if (chk->whoTo) {
- atomic_add_int(&chk->whoTo->ref_count, 1);
+ m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER);
+ if (m_shutdown == NULL) {
+ /* no mbuf's */
+ return;
+ }
+ SCTP_BUF_RESV_UF(m_shutdown, SCTP_MIN_OVERHEAD);
+ sctp_alloc_a_chunk(stcb, chk);
+ if (chk == NULL) {
+ /* no memory */
+ sctp_m_freem(m_shutdown);
+ return;
+ }
+ chk->copy_by_ref = 0;
+ chk->rec.chunk_id.id = SCTP_SHUTDOWN;
+ chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
+ chk->send_size = sizeof(struct sctp_shutdown_chunk);
+ chk->sent = SCTP_DATAGRAM_UNSENT;
+ chk->snd_count = 0;
+ chk->asoc = &stcb->asoc;
+ chk->data = m_shutdown;
+ chk->whoTo = net;
+ if (chk->whoTo) {
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ }
+ shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *);
+ shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
+ shutdown_cp->ch.chunk_flags = 0;
+ shutdown_cp->ch.chunk_length = htons(chk->send_size);
+ shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn);
+ SCTP_BUF_LEN(m_shutdown) = chk->send_size;
+ TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
+ chk->asoc->ctrl_queue_cnt++;
+ } else {
+ TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, sctp_next);
+ chk->whoTo = net;
+ if (chk->whoTo) {
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ }
+ shutdown_cp = mtod(chk->data, struct sctp_shutdown_chunk *);
+ shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn);
+ TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
}
- shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *);
- shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
- shutdown_cp->ch.chunk_flags = 0;
- shutdown_cp->ch.chunk_length = htons(chk->send_size);
- shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn);
- SCTP_BUF_LEN(m_shutdown) = chk->send_size;
- TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
- chk->asoc->ctrl_queue_cnt++;
return;
}
@@ -9767,16 +9947,11 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
return;
}
-
static int
sctp_chunk_retransmission(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_association *asoc,
- int *cnt_out, struct timeval *now, int *now_filled, int *fr_done, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ int *cnt_out, struct timeval *now, int *now_filled, int *fr_done, int so_locked)
{
/*-
* send out one MTU of retransmission. If fast_retransmit is
@@ -9805,7 +9980,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
int data_auth_reqd = 0;
uint32_t dmtu = 0;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
} else {
@@ -9813,7 +9988,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
}
#endif
SCTP_TCB_LOCK_ASSERT(stcb);
- tmr_started = ctl_cnt = bundle_at = error = 0;
+ tmr_started = ctl_cnt = 0;
no_fragmentflg = 1;
fwd_tsn = 0;
*cnt_out = 0;
@@ -9874,7 +10049,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
cnt_thru = 0;
/* do we have control chunks to retransmit? */
if (m != NULL) {
- /* Start a timer no matter if we suceed or fail */
+ /* Start a timer no matter if we succeed or fail */
if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) {
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo);
} else if (chk->rec.chunk_id.id == SCTP_ASCONF)
@@ -9886,12 +10061,18 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
no_fragmentflg, 0, 0,
inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
chk->whoTo->port, NULL,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
so_locked))) {
- SCTP_STAT_INCR(sctps_lowlevelerr);
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ }
return (error);
+ } else {
+ asoc->ifp_had_enobuf = 0;
}
endofchain = NULL;
auth = NULL;
@@ -9919,8 +10100,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
if (TAILQ_EMPTY(&asoc->sent_queue)) {
return (SCTP_RETRAN_DONE);
}
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT)) {
/* not yet open, resend the cookie and that is it */
return (1);
}
@@ -9935,17 +10116,21 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
}
if (chk->data == NULL) {
SCTP_PRINTF("TSN:%x chk->snd_count:%d chk->sent:%d can't retran - no data\n",
- chk->rec.data.TSN_seq, chk->snd_count, chk->sent);
+ chk->rec.data.tsn, chk->snd_count, chk->sent);
continue;
}
if ((SCTP_BASE_SYSCTL(sctp_max_retran_chunk)) &&
(chk->snd_count >= SCTP_BASE_SYSCTL(sctp_max_retran_chunk))) {
- /* Gak, we have exceeded max unlucky retran, abort! */
- SCTP_PRINTF("Gak, chk->snd_count:%d >= max:%d - send abort\n",
- chk->snd_count,
- SCTP_BASE_SYSCTL(sctp_max_retran_chunk));
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
+ SCTP_SNPRINTF(msg, sizeof(msg), "TSN %8.8x retransmitted %d times, giving up",
+ chk->rec.data.tsn, chk->snd_count);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, so_locked);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err,
+ so_locked);
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (SCTP_RETRAN_EXIT);
@@ -9979,7 +10164,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
uint32_t tsn;
tsn = asoc->last_acked_seq + 1;
- if (tsn == chk->rec.data.TSN_seq) {
+ if (tsn == chk->rec.data.tsn) {
/*
* we make a special exception for this
* case. The peer has no rwnd but is missing
@@ -10139,7 +10324,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
/* Is there something to send for this destination? */
if (m) {
/*
- * No matter if we fail/or suceed we should start a
+ * No matter if we fail/or succeed we should start a
* timer. A failure is like a lost IP packet :-)
*/
if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
@@ -10157,13 +10342,19 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
no_fragmentflg, 0, 0,
inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
net->port, NULL,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
so_locked))) {
/* error, we could not output */
- SCTP_STAT_INCR(sctps_lowlevelerr);
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ }
return (error);
+ } else {
+ asoc->ifp_had_enobuf = 0;
}
endofchain = NULL;
auth = NULL;
@@ -10190,7 +10381,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
sctp_audit_log(0xC4, bundle_at);
#endif
if (bundle_at) {
- tsns_sent = data_list[0]->rec.data.TSN_seq;
+ tsns_sent = data_list[0]->rec.data.tsn;
}
for (i = 0; i < bundle_at; i++) {
SCTP_STAT_INCR(sctps_sendretransdata);
@@ -10222,8 +10413,6 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
*/
atomic_add_int(&((asoc)->total_output_queue_size),data_list[i]->book_size);
data_list[i]->book_size *= 2;
-
-
} else {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
sctp_log_rwnd(SCTP_DECREASE_PEER_RWND,
@@ -10237,8 +10426,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_RSND,
data_list[i]->whoTo->flight_size,
data_list[i]->book_size,
- (uintptr_t)data_list[i]->whoTo,
- data_list[i]->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)data_list[i]->whoTo,
+ data_list[i]->rec.data.tsn);
}
sctp_flight_size_increase(data_list[i]);
sctp_total_flight_increase(stcb, data_list[i]);
@@ -10261,7 +10450,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
* t3-expiring.
*/
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net,
- SCTP_FROM_SCTP_OUTPUT+SCTP_LOC_4);
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2);
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
}
@@ -10317,14 +10506,10 @@ sctp_timer_validation(struct sctp_inpcb *inp,
}
void
-sctp_chunk_output (struct sctp_inpcb *inp,
+sctp_chunk_output(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
int from_where,
- int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ int so_locked)
{
/*-
* Ok this is the generic chunk service queue. we must do the
@@ -10351,7 +10536,7 @@ sctp_chunk_output (struct sctp_inpcb *inp,
int fr_done;
unsigned int tot_frs = 0;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
} else {
@@ -10359,6 +10544,7 @@ sctp_chunk_output (struct sctp_inpcb *inp,
}
#endif
asoc = &stcb->asoc;
+do_it_again:
/* The Nagle algorithm is only applied when handling a send call. */
if (from_where == SCTP_OUTPUT_FROM_USR_SEND) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY)) {
@@ -10376,7 +10562,8 @@ sctp_chunk_output (struct sctp_inpcb *inp,
if ((un_sent <= 0) &&
(TAILQ_EMPTY(&asoc->control_send_queue)) &&
(TAILQ_EMPTY(&asoc->asconf_send_queue)) &&
- (asoc->sent_queue_retran_cnt == 0)) {
+ (asoc->sent_queue_retran_cnt == 0) &&
+ (asoc->trigger_reset == 0)) {
/* Nothing to do unless there is something to be sent left */
return;
}
@@ -10385,7 +10572,8 @@ sctp_chunk_output (struct sctp_inpcb *inp,
*/
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
sctp_send_sack(stcb, so_locked);
- (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3);
}
while (asoc->sent_queue_retran_cnt) {
/*-
@@ -10504,7 +10692,6 @@ sctp_chunk_output (struct sctp_inpcb *inp,
}
}
}
-
}
burst_cnt = 0;
do {
@@ -10539,18 +10726,16 @@ sctp_chunk_output (struct sctp_inpcb *inp,
* have data in flight we stop, except if we are
* handling a fragmented user message.
*/
- un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) &&
- (stcb->asoc.total_flight > 0) &&
- ((stcb->asoc.locked_on_sending == NULL) ||
- sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
+ (stcb->asoc.total_flight > 0)) {
+/* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/
break;
}
}
if (TAILQ_EMPTY(&asoc->control_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, so_locked) == 0) {
/* Nothing left to send */
break;
}
@@ -10587,30 +10772,27 @@ sctp_chunk_output (struct sctp_inpcb *inp,
*/
if (stcb->asoc.ecn_echo_cnt_onq)
sctp_fix_ecn_echo(asoc);
+
+ if (stcb->asoc.trigger_reset) {
+ if (sctp_send_stream_reset_out_if_possible(stcb, so_locked) == 0) {
+ goto do_it_again;
+ }
+ }
return;
}
-
int
sctp_output(
struct sctp_inpcb *inp,
-#if defined(__Panda__)
- pakhandle_type m,
-#else
struct mbuf *m,
-#endif
struct sockaddr *addr,
-#if defined(__Panda__)
- pakhandle_type control,
-#else
struct mbuf *control,
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct thread *p,
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
PKTHREAD p,
#else
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct proc *p SCTP_UNUSED,
#else
struct proc *p,
@@ -10632,7 +10814,7 @@ sctp_output(
(struct uio *)NULL,
m,
control,
-#if defined(__APPLE__) || defined(__Panda__)
+#if defined(__APPLE__) && !defined(__Userspace__)
flags
#else
flags, p
@@ -10644,11 +10826,16 @@ void
send_forward_tsn(struct sctp_tcb *stcb,
struct sctp_association *asoc)
{
- struct sctp_tmit_chunk *chk;
+ struct sctp_tmit_chunk *chk, *at, *tp1, *last;
struct sctp_forward_tsn_chunk *fwdtsn;
+ struct sctp_strseq *strseq;
+ struct sctp_strseq_mid *strseq_m;
uint32_t advance_peer_ack_point;
+ unsigned int cnt_of_space, i, ovh;
+ unsigned int space_needed;
+ unsigned int cnt_of_skipped = 0;
- SCTP_TCB_LOCK_ASSERT(stcb);
+ SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) {
/* mark it to unsent */
@@ -10669,6 +10856,13 @@ send_forward_tsn(struct sctp_tcb *stcb,
}
asoc->fwd_tsn_cnt++;
chk->copy_by_ref = 0;
+ /*
+ * We don't do the old thing here since
+ * this is used not for on-wire but to
+ * tell if we are sending a fwd-tsn by
+ * the stack during output. And if its
+ * a IFORWARD or a FORWARD it is a fwd-tsn.
+ */
chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN;
chk->rec.chunk_id.can_take_data = 0;
chk->flags = 0;
@@ -10690,142 +10884,162 @@ sctp_fill_in_rest:
* stream/seq of the ones we skip.
*/
SCTP_BUF_LEN(chk->data) = 0;
- {
- struct sctp_tmit_chunk *at, *tp1, *last;
- struct sctp_strseq *strseq;
- unsigned int cnt_of_space, i, ovh;
- unsigned int space_needed;
- unsigned int cnt_of_skipped = 0;
-
- TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
- if ((at->sent != SCTP_FORWARD_TSN_SKIP) &&
- (at->sent != SCTP_DATAGRAM_NR_ACKED)) {
- /* no more to look at */
- break;
- }
- if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
- /* We don't report these */
- continue;
- }
- cnt_of_skipped++;
+ TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
+ if ((at->sent != SCTP_FORWARD_TSN_SKIP) &&
+ (at->sent != SCTP_DATAGRAM_NR_ACKED)) {
+ /* no more to look at */
+ break;
}
+ if (!asoc->idata_supported && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
+ /* We don't report these */
+ continue;
+ }
+ cnt_of_skipped++;
+ }
+ if (asoc->idata_supported) {
space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
- (cnt_of_skipped * sizeof(struct sctp_strseq)));
-
- cnt_of_space = M_TRAILINGSPACE(chk->data);
+ (cnt_of_skipped * sizeof(struct sctp_strseq_mid)));
+ } else {
+ space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
+ (cnt_of_skipped * sizeof(struct sctp_strseq)));
+ }
+ cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data);
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MIN_OVERHEAD;
- } else {
- ovh = SCTP_MIN_V4_OVERHEAD;
- }
- if (cnt_of_space > (asoc->smallest_mtu - ovh)) {
- /* trim to a mtu size */
- cnt_of_space = asoc->smallest_mtu - ovh;
- }
+ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ ovh = SCTP_MIN_OVERHEAD;
+ } else {
+ ovh = SCTP_MIN_V4_OVERHEAD;
+ }
+ if (cnt_of_space > (asoc->smallest_mtu - ovh)) {
+ /* trim to a mtu size */
+ cnt_of_space = asoc->smallest_mtu - ovh;
+ }
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
+ sctp_misc_ints(SCTP_FWD_TSN_CHECK,
+ 0xff, 0, cnt_of_skipped,
+ asoc->advanced_peer_ack_point);
+ }
+ advance_peer_ack_point = asoc->advanced_peer_ack_point;
+ if (cnt_of_space < space_needed) {
+ /*-
+ * ok we must trim down the chunk by lowering the
+ * advance peer ack point.
+ */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, 0, cnt_of_skipped,
- asoc->advanced_peer_ack_point);
-
+ 0xff, 0xff, cnt_of_space,
+ space_needed);
}
- advance_peer_ack_point = asoc->advanced_peer_ack_point;
- if (cnt_of_space < space_needed) {
- /*-
- * ok we must trim down the chunk by lowering the
- * advance peer ack point.
- */
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
- sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, 0xff, cnt_of_space,
- space_needed);
- }
- cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
+ cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
+ if (asoc->idata_supported) {
+ cnt_of_skipped /= sizeof(struct sctp_strseq_mid);
+ } else {
cnt_of_skipped /= sizeof(struct sctp_strseq);
- /*-
- * Go through and find the TSN that will be the one
- * we report.
- */
- at = TAILQ_FIRST(&asoc->sent_queue);
- if (at != NULL) {
- for (i = 0; i < cnt_of_skipped; i++) {
- tp1 = TAILQ_NEXT(at, sctp_next);
- if (tp1 == NULL) {
- break;
- }
- at = tp1;
+ }
+ /*-
+ * Go through and find the TSN that will be the one
+ * we report.
+ */
+ at = TAILQ_FIRST(&asoc->sent_queue);
+ if (at != NULL) {
+ for (i = 0; i < cnt_of_skipped; i++) {
+ tp1 = TAILQ_NEXT(at, sctp_next);
+ if (tp1 == NULL) {
+ break;
}
+ at = tp1;
}
- if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
- sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, cnt_of_skipped, at->rec.data.TSN_seq,
- asoc->advanced_peer_ack_point);
- }
- last = at;
- /*-
- * last now points to last one I can report, update
- * peer ack point
- */
- if (last)
- advance_peer_ack_point = last->rec.data.TSN_seq;
+ }
+ if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
+ sctp_misc_ints(SCTP_FWD_TSN_CHECK,
+ 0xff, cnt_of_skipped, at->rec.data.tsn,
+ asoc->advanced_peer_ack_point);
+ }
+ last = at;
+ /*-
+ * last now points to last one I can report, update
+ * peer ack point
+ */
+ if (last) {
+ advance_peer_ack_point = last->rec.data.tsn;
+ }
+ if (asoc->idata_supported) {
+ space_needed = sizeof(struct sctp_forward_tsn_chunk) +
+ cnt_of_skipped * sizeof(struct sctp_strseq_mid);
+ } else {
space_needed = sizeof(struct sctp_forward_tsn_chunk) +
cnt_of_skipped * sizeof(struct sctp_strseq);
}
- chk->send_size = space_needed;
- /* Setup the chunk */
- fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
- fwdtsn->ch.chunk_length = htons(chk->send_size);
- fwdtsn->ch.chunk_flags = 0;
+ }
+ chk->send_size = space_needed;
+ /* Setup the chunk */
+ fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
+ fwdtsn->ch.chunk_length = htons(chk->send_size);
+ fwdtsn->ch.chunk_flags = 0;
+ if (asoc->idata_supported) {
+ fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN;
+ } else {
fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
- fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
- SCTP_BUF_LEN(chk->data) = chk->send_size;
- fwdtsn++;
- /*-
- * Move pointer to after the fwdtsn and transfer to the
- * strseq pointer.
- */
+ }
+ fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ fwdtsn++;
+ /*-
+ * Move pointer to after the fwdtsn and transfer to the
+ * strseq pointer.
+ */
+ if (asoc->idata_supported) {
+ strseq_m = (struct sctp_strseq_mid *)fwdtsn;
+ strseq = NULL;
+ } else {
strseq = (struct sctp_strseq *)fwdtsn;
- /*-
- * Now populate the strseq list. This is done blindly
- * without pulling out duplicate stream info. This is
- * inefficent but won't harm the process since the peer will
- * look at these in sequence and will thus release anything.
- * It could mean we exceed the PMTU and chop off some that
- * we could have included.. but this is unlikely (aka 1432/4
- * would mean 300+ stream seq's would have to be reported in
- * one FWD-TSN. With a bit of work we can later FIX this to
- * optimize and pull out duplcates.. but it does add more
- * overhead. So for now... not!
- */
- at = TAILQ_FIRST(&asoc->sent_queue);
- for (i = 0; i < cnt_of_skipped; i++) {
- tp1 = TAILQ_NEXT(at, sctp_next);
- if (tp1 == NULL)
- break;
+ strseq_m = NULL;
+ }
+ /*-
+ * Now populate the strseq list. This is done blindly
+ * without pulling out duplicate stream info. This is
+ * inefficent but won't harm the process since the peer will
+ * look at these in sequence and will thus release anything.
+ * It could mean we exceed the PMTU and chop off some that
+ * we could have included.. but this is unlikely (aka 1432/4
+ * would mean 300+ stream seq's would have to be reported in
+ * one FWD-TSN. With a bit of work we can later FIX this to
+ * optimize and pull out duplicates.. but it does add more
+ * overhead. So for now... not!
+ */
+ i = 0;
+ TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
+ if (i >= cnt_of_skipped) {
+ break;
+ }
+ if (!asoc->idata_supported && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
+ /* We don't report these */
+ continue;
+ }
+ if (at->rec.data.tsn == advance_peer_ack_point) {
+ at->rec.data.fwd_tsn_cnt = 0;
+ }
+ if (asoc->idata_supported) {
+ strseq_m->sid = htons(at->rec.data.sid);
if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
- /* We don't report these */
- i--;
- at = tp1;
- continue;
- }
- if (at->rec.data.TSN_seq == advance_peer_ack_point) {
- at->rec.data.fwd_tsn_cnt = 0;
+ strseq_m->flags = htons(PR_SCTP_UNORDERED_FLAG);
+ } else {
+ strseq_m->flags = 0;
}
- strseq->stream = ntohs(at->rec.data.stream_number);
- strseq->sequence = ntohs(at->rec.data.stream_seq);
+ strseq_m->mid = htonl(at->rec.data.mid);
+ strseq_m++;
+ } else {
+ strseq->sid = htons(at->rec.data.sid);
+ strseq->ssn = htons((uint16_t)at->rec.data.mid);
strseq++;
- at = tp1;
}
+ i++;
}
return;
}
void
-sctp_send_sack(struct sctp_tcb *stcb, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+sctp_send_sack(struct sctp_tcb *stcb, int so_locked)
{
/*-
* Queue up a SACK or NR-SACK in the control queue.
@@ -10838,7 +11052,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
struct sctp_sack_chunk *sack;
struct sctp_nr_sack_chunk *nr_sack;
struct sctp_gap_ack_block *gap_descriptor;
- struct sack_track *selector;
+ const struct sack_track *selector;
int mergeable = 0;
int offset;
caddr_t limit;
@@ -10890,7 +11104,8 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
/* No memory so we drop the idea, and set a timer */
if (stcb->asoc.delayed_ack) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4);
sctp_timer_start(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL);
} else {
@@ -10912,32 +11127,17 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
a_chk->sent = SCTP_DATAGRAM_UNSENT;
a_chk->whoTo = NULL;
- if ((asoc->numduptsns) ||
- (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE))) {
+ if (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE)) {
/*-
- * Ok, we have some duplicates or the destination for the
- * sack is unreachable, lets see if we can select an
- * alternate than asoc->last_data_chunk_from
+ * Ok, the destination for the SACK is unreachable, lets see if
+ * we can select an alternate to asoc->last_data_chunk_from
*/
- if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) &&
- (asoc->used_alt_onsack > asoc->numnets)) {
- /* We used an alt last time, don't this time */
- a_chk->whoTo = NULL;
- } else {
- asoc->used_alt_onsack++;
- a_chk->whoTo = sctp_find_alternate_net(stcb, asoc->last_data_chunk_from, 0);
- }
+ a_chk->whoTo = sctp_find_alternate_net(stcb, asoc->last_data_chunk_from, 0);
if (a_chk->whoTo == NULL) {
/* Nope, no alternate */
a_chk->whoTo = asoc->last_data_chunk_from;
- asoc->used_alt_onsack = 0;
}
} else {
- /*
- * No duplicates so we use the last place we received data
- * from.
- */
- asoc->used_alt_onsack = 0;
a_chk->whoTo = asoc->last_data_chunk_from;
}
if (a_chk->whoTo) {
@@ -10973,7 +11173,8 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
/* sa_ignore NO_NULL_CHK */
if (stcb->asoc.delayed_ack) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
sctp_timer_start(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL);
} else {
@@ -10983,7 +11184,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
}
/* ok, lets go through and fill it in */
SCTP_BUF_RESV_UF(a_chk->data, SCTP_MIN_OVERHEAD);
- space = M_TRAILINGSPACE(a_chk->data);
+ space = (unsigned int)M_TRAILINGSPACE(a_chk->data);
if (space > (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD)) {
space = (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD);
}
@@ -11019,7 +11220,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
if (highest_tsn > asoc->mapping_array_base_tsn) {
siz = (((highest_tsn - asoc->mapping_array_base_tsn) + 1) + 7) / 8;
} else {
- siz = (((MAX_TSN - highest_tsn) + 1) + highest_tsn + 7) / 8;
+ siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + highest_tsn + 7) / 8;
}
} else {
sack = NULL;
@@ -11052,7 +11253,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* Clear all bits corresponding to TSNs
* smaller or equal to the cumulative TSN.
*/
- tsn_map &= (~0 << (1 - offset));
+ tsn_map &= (~0U << (1 - offset));
}
selector = &sack_array[tsn_map];
if (mergeable && selector->right_edge) {
@@ -11103,7 +11304,6 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
}
if ((type == SCTP_NR_SELECTIVE_ACK) &&
(limit_reached == 0)) {
-
mergeable = 0;
if (asoc->highest_tsn_inside_nr_map > asoc->mapping_array_base_tsn) {
@@ -11126,7 +11326,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* Clear all bits corresponding to TSNs
* smaller or equal to the cumulative TSN.
*/
- tsn_map &= (~0 << (1 - offset));
+ tsn_map &= (~0U << (1 - offset));
}
selector = &sack_array[tsn_map];
if (mergeable && selector->right_edge) {
@@ -11195,9 +11395,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* queue.
*/
if (type == SCTP_SELECTIVE_ACK) {
- a_chk->send_size = sizeof(struct sctp_sack_chunk) +
- (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
- num_dups * sizeof(int32_t);
+ a_chk->send_size = (uint16_t)(sizeof(struct sctp_sack_chunk) +
+ (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
+ num_dups * sizeof(int32_t));
SCTP_BUF_LEN(a_chk->data) = a_chk->send_size;
sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
sack->sack.a_rwnd = htonl(asoc->my_rwnd);
@@ -11207,9 +11407,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
sack->ch.chunk_flags = flags;
sack->ch.chunk_length = htons(a_chk->send_size);
} else {
- a_chk->send_size = sizeof(struct sctp_nr_sack_chunk) +
- (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
- num_dups * sizeof(int32_t);
+ a_chk->send_size = (uint16_t)(sizeof(struct sctp_nr_sack_chunk) +
+ (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
+ num_dups * sizeof(int32_t));
SCTP_BUF_LEN(a_chk->data) = a_chk->send_size;
nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
nr_sack->nr_sack.a_rwnd = htonl(asoc->my_rwnd);
@@ -11230,11 +11430,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
}
void
-sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked)
{
struct mbuf *m_abort, *m, *m_last;
struct mbuf *m_out, *m_end = NULL;
@@ -11243,9 +11439,10 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
struct sctp_nets *net;
uint32_t vtag;
uint32_t auth_offset = 0;
+ int error;
uint16_t cause_len, chunk_len, padding_len;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep));
} else {
@@ -11321,15 +11518,23 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
return;
}
}
- (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
- (struct sockaddr *)&net->ro._l_addr,
- m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, 0,
- stcb->sctp_ep->sctp_lport, stcb->rport, htonl(vtag),
- stcb->asoc.primary_destination->port, NULL,
-#if defined(__FreeBSD__)
- 0, 0,
+ if ((error = sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
+ (struct sockaddr *)&net->ro._l_addr,
+ m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, 0,
+ stcb->sctp_ep->sctp_lport, stcb->rport, htonl(vtag),
+ stcb->asoc.primary_destination->port, NULL,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ 0, 0,
#endif
- so_locked);
+ so_locked))) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
+ if (error == ENOBUFS) {
+ stcb->asoc.ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ }
+ } else {
+ stcb->asoc.ifp_had_enobuf = 0;
+ }
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -11342,6 +11547,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
struct mbuf *m_shutdown_comp;
struct sctp_shutdown_complete_chunk *shutdown_complete;
uint32_t vtag;
+ int error;
uint8_t flags;
m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER);
@@ -11361,26 +11567,34 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
shutdown_complete->ch.chunk_flags = flags;
shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk);
- (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
- (struct sockaddr *)&net->ro._l_addr,
- m_shutdown_comp, 0, NULL, 0, 1, 0, 0,
- stcb->sctp_ep->sctp_lport, stcb->rport,
- htonl(vtag),
- net->port, NULL,
-#if defined(__FreeBSD__)
- 0, 0,
-#endif
- SCTP_SO_NOT_LOCKED);
+ if ((error = sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
+ (struct sockaddr *)&net->ro._l_addr,
+ m_shutdown_comp, 0, NULL, 0, 1, 0, 0,
+ stcb->sctp_ep->sctp_lport, stcb->rport,
+ htonl(vtag),
+ net->port, NULL,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ 0, 0,
+#endif
+ SCTP_SO_NOT_LOCKED))) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
+ if (error == ENOBUFS) {
+ stcb->asoc.ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ }
+ } else {
+ stcb->asoc.ifp_had_enobuf = 0;
+ }
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static void
sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, uint32_t vtag,
uint8_t type, struct mbuf *cause,
- uint8_t mflowtype, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
uint32_t vrf_id, uint16_t port)
#else
static void
@@ -11390,21 +11604,16 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
uint32_t vrf_id SCTP_UNUSED, uint16_t port)
#endif
{
-#ifdef __Panda__
- pakhandle_type o_pak;
-#else
struct mbuf *o_pak;
-#endif
struct mbuf *mout;
struct sctphdr *shout;
struct sctp_chunkhdr *ch;
#if defined(INET) || defined(INET6)
struct udphdr *udp;
- int ret;
#endif
- int len, cause_len, padding_len;
+ int ret, len, cause_len, padding_len;
#ifdef INET
-#if defined(__APPLE__) || defined(__Panda__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sctp_route_t ro;
#endif
struct sockaddr_in *src_sin, *dst_sin;
@@ -11459,7 +11668,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
len += sizeof(struct udphdr);
}
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_NOWAIT, 1, MT_DATA);
#else
@@ -11474,7 +11683,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
}
return;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
SCTP_BUF_RESV_UF(mout, max_linkhdr);
#else
@@ -11485,7 +11694,8 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
#endif
SCTP_BUF_LEN(mout) = len;
SCTP_BUF_NEXT(mout) = cause;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ M_SETFIB(mout, fibnum);
mout->m_pkthdr.flowid = mflowid;
M_HASHTYPE_SET(mout, mflowtype);
#endif
@@ -11504,8 +11714,17 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
ip->ip_v = IPVERSION;
ip->ip_hl = (sizeof(struct ip) >> 2);
ip->ip_tos = 0;
-#if defined(__FreeBSD__)
- ip->ip_id = ip_newid();
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ ip->ip_off = htons(IP_DF);
+#elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__)
+ ip->ip_off = IP_DF;
+#else
+ ip->ip_off = htons(IP_DF);
+#endif
+#if defined(__Userspace__)
+ ip->ip_id = htons(ip_id++);
+#elif defined(__FreeBSD__)
+ ip_fillid(ip);
#elif defined(__APPLE__)
#if RANDOM_IP_ID
ip->ip_id = ip_randomid();
@@ -11513,9 +11732,8 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
ip->ip_id = htons(ip_id++);
#endif
#else
- ip->ip_id = htons(ip_id++);
+ ip->ip_id = ip_id++;
#endif
- ip->ip_off = 0;
ip->ip_ttl = MODULE_GLOBAL(ip_defttl);
if (port) {
ip->ip_p = IPPROTO_UDP;
@@ -11535,7 +11753,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
dst_sin6 = (struct sockaddr_in6 *)dst;
ip6 = mtod(mout, struct ip6_hdr *);
ip6->ip6_flow = htonl(0x60000000);
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (V_ip6_auto_flowlabel) {
ip6->ip6_flow |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
}
@@ -11571,10 +11789,10 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
udp->uh_sum = 0;
- udp->uh_ulen = htons(sizeof(struct udphdr) +
- sizeof(struct sctphdr) +
- sizeof(struct sctp_chunkhdr) +
- cause_len + padding_len);
+ udp->uh_ulen = htons((uint16_t)(sizeof(struct udphdr) +
+ sizeof(struct sctphdr) +
+ sizeof(struct sctp_chunkhdr) +
+ cause_len + padding_len));
len += sizeof(struct udphdr);
shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr));
} else {
@@ -11597,7 +11815,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
} else {
ch->chunk_flags = SCTP_HAD_NO_TCB;
}
- ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len);
+ ch->chunk_length = htons((uint16_t)(sizeof(struct sctp_chunkhdr) + cause_len));
len += sizeof(struct sctp_chunkhdr);
len += cause_len + padding_len;
@@ -11609,16 +11827,13 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
-#if defined(__APPLE__) || defined(__Panda__)
+#if defined(__APPLE__) && !defined(__Userspace__)
/* zap the stack pointer to the route */
- bzero(&ro, sizeof(sctp_route_t));
-#if defined(__Panda__)
- ro._l_addr.sa.sa_family = AF_INET;
-#endif
+ memset(&ro, 0, sizeof(sctp_route_t));
#endif
if (port) {
-#if !defined(__Windows__) && !defined(__Userspace__)
-#if defined(__FreeBSD__) && ((__FreeBSD_version > 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000)
+#if !defined(_WIN32) && !defined(__Userspace__)
+#if defined(__FreeBSD__)
if (V_udp_cksum) {
udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
} else {
@@ -11631,36 +11846,27 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
udp->uh_sum = 0;
#endif
}
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 1000000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
ip->ip_len = htons(len);
-#else
- ip->ip_len = len;
-#endif
#elif defined(__APPLE__) || defined(__Userspace__)
ip->ip_len = len;
#else
ip->ip_len = htons(len);
#endif
if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip) + sizeof(struct udphdr));
SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
-#if defined(__FreeBSD__) && ((__FreeBSD_version > 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000)
+#if !defined(_WIN32) && !defined(__Userspace__)
+#if defined(__FreeBSD__)
if (V_udp_cksum) {
SCTP_ENABLE_UDP_CSUM(o_pak);
}
#else
SCTP_ENABLE_UDP_CSUM(o_pak);
#endif
+#endif
} else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mout->m_pkthdr.csum_flags = CSUM_SCTP;
mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
SCTP_STAT_INCR(sctps_sendhwcrc);
@@ -11668,14 +11874,13 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip));
SCTP_STAT_INCR(sctps_sendswcrc);
#endif
-#endif
}
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
sctp_packet_log(o_pak);
}
#endif
-#if defined(__APPLE__) || defined(__Panda__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id);
/* Free the route if we got one back */
if (ro.ro_rt) {
@@ -11683,50 +11888,46 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
ro.ro_rt = NULL;
}
#else
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(send, NULL, NULL, ip, NULL, shout);
+#endif
SCTP_IP_OUTPUT(ret, o_pak, NULL, NULL, vrf_id);
#endif
break;
#endif
#ifdef INET6
case AF_INET6:
- ip6->ip6_plen = len - sizeof(struct ip6_hdr);
+ ip6->ip6_plen = htons((uint16_t)(len - sizeof(struct ip6_hdr)));
if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
-#if defined(__Windows__)
+#if !defined(__Userspace__)
+#if defined(_WIN32)
udp->uh_sum = 0;
-#elif !defined(__Userspace__)
+#else
if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
udp->uh_sum = 0xffff;
}
#endif
+#endif
} else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 900000
-#if __FreeBSD_version > 901000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
mout->m_pkthdr.csum_flags = CSUM_SCTP_IPV6;
-#else
- mout->m_pkthdr.csum_flags = CSUM_SCTP;
-#endif
mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
SCTP_STAT_INCR(sctps_sendhwcrc);
#else
shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr));
SCTP_STAT_INCR(sctps_sendswcrc);
#endif
-#endif
}
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
sctp_packet_log(o_pak);
}
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(send, NULL, NULL, ip6, NULL, shout);
+#endif
SCTP_IP6_OUTPUT(ret, o_pak, NULL, NULL, NULL, vrf_id);
break;
#endif
@@ -11737,12 +11938,12 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
struct sockaddr_conn *sconn;
sconn = (struct sockaddr_conn *)src;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- shout->checksum = sctp_calculate_cksum(mout, 0);
- SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
+ if (SCTP_BASE_VAR(crc32c_offloaded) == 0) {
+ shout->checksum = sctp_calculate_cksum(mout, 0);
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendhwcrc);
+ }
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
sctp_packet_log(mout);
@@ -11751,8 +11952,10 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
/* Don't alloc/free for each packet */
if ((buffer = malloc(len)) != NULL) {
m_copydata(mout, 0, len, buffer);
- SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, len, 0, 0);
+ ret = SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, len, 0, 0);
free(buffer);
+ } else {
+ ret = ENOMEM;
}
sctp_m_freem(mout);
break;
@@ -11765,33 +11968,38 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
SCTP_LTRACE_ERR_RET_PKT(mout, NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
return;
}
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (port) {
+ UDPSTAT_INC(udps_opackets);
+ }
+#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
+ if (ret) {
+ SCTP_STAT_INCR(sctps_senderrors);
+ }
return;
}
void
sctp_send_shutdown_complete2(struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
#endif
uint32_t vrf_id, uint16_t port)
{
sctp_send_resp_msg(src, dst, sh, 0, SCTP_SHUTDOWN_COMPLETE, NULL,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
}
void
-sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net,int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net,int so_locked)
{
struct sctp_tmit_chunk *chk;
struct sctp_heartbeat_chunk *hb;
@@ -11914,6 +12122,11 @@ sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net,int so_locked
break;
#endif
default:
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ sctp_free_a_chunk(stcb, chk, so_locked);
return;
break;
}
@@ -12027,7 +12240,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
chk->flags = 0;
len -= iphlen;
chk->send_size = len;
- /* Validate that we do not have an ABORT in here. */
+ /* Validate that we do not have an ABORT in here. */
offset = iphlen + sizeof(struct sctphdr);
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
sizeof(*ch), (uint8_t *) & chunk_buf);
@@ -12089,7 +12302,7 @@ jump_out:
/* Len is already adjusted to size minus overhead above
* take out the pkt_drop chunk itself from it.
*/
- chk->send_size = len - sizeof(struct sctp_pktdrop_chunk);
+ chk->send_size = (uint16_t)(len - sizeof(struct sctp_pktdrop_chunk));
len = chk->send_size;
} else {
/* no truncation needed */
@@ -12194,30 +12407,60 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u
asoc->ctrl_queue_cnt++;
}
-void
-sctp_add_stream_reset_out(struct sctp_tmit_chunk *chk,
- int number_entries, uint16_t * list,
+static int
+sctp_add_stream_reset_out(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk,
uint32_t seq, uint32_t resp_seq, uint32_t last_sent)
{
uint16_t len, old_len, i;
struct sctp_stream_reset_out_request *req_out;
struct sctp_chunkhdr *ch;
+ int at;
+ int number_entries=0;
ch = mtod(chk->data, struct sctp_chunkhdr *);
old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length));
-
/* get to new offset for the param. */
req_out = (struct sctp_stream_reset_out_request *)((caddr_t)ch + len);
/* now how long will this param be? */
- len = (sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries));
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) &&
+ (stcb->asoc.strmout[i].chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ number_entries++;
+ }
+ }
+ if (number_entries == 0) {
+ return (0);
+ }
+ if (number_entries == stcb->asoc.streamoutcnt) {
+ number_entries = 0;
+ }
+ if (number_entries > SCTP_MAX_STREAMS_AT_ONCE_RESET) {
+ number_entries = SCTP_MAX_STREAMS_AT_ONCE_RESET;
+ }
+ len = (uint16_t)(sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries));
req_out->ph.param_type = htons(SCTP_STR_RESET_OUT_REQUEST);
req_out->ph.param_length = htons(len);
req_out->request_seq = htonl(seq);
req_out->response_seq = htonl(resp_seq);
req_out->send_reset_at_tsn = htonl(last_sent);
+ at = 0;
if (number_entries) {
- for (i = 0; i < number_entries; i++) {
- req_out->list_of_streams[i] = htons(list[i]);
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) &&
+ (stcb->asoc.strmout[i].chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ req_out->list_of_streams[at] = htons(i);
+ at++;
+ stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT;
+ if (at >= number_entries) {
+ break;
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT;
}
}
if (SCTP_SIZE32(len) > len) {
@@ -12234,7 +12477,7 @@ sctp_add_stream_reset_out(struct sctp_tmit_chunk *chk,
chk->book_size_scale = 0;
chk->send_size = SCTP_SIZE32(chk->book_size);
SCTP_BUF_LEN(chk->data) = chk->send_size;
- return;
+ return (1);
}
static void
@@ -12252,7 +12495,7 @@ sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk,
/* get to new offset for the param. */
req_in = (struct sctp_stream_reset_in_request *)((caddr_t)ch + len);
/* now how long will this param be? */
- len = (sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries));
+ len = (uint16_t)(sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries));
req_in->ph.param_type = htons(SCTP_STR_RESET_IN_REQUEST);
req_in->ph.param_length = htons(len);
req_in->request_seq = htonl(seq);
@@ -12336,6 +12579,68 @@ sctp_add_stream_reset_result(struct sctp_tmit_chunk *chk,
}
void
+sctp_send_deferred_reset_response(struct sctp_tcb *stcb,
+ struct sctp_stream_reset_list *ent,
+ int response)
+{
+ struct sctp_association *asoc;
+ struct sctp_tmit_chunk *chk;
+ struct sctp_chunkhdr *ch;
+
+ asoc = &stcb->asoc;
+
+ /*
+ * Reset our last reset action to the new one IP -> response
+ * (PERFORMED probably). This assures that if we fail to send, a
+ * retran from the peer will get the new response.
+ */
+ asoc->last_reset_action[0] = response;
+ if (asoc->stream_reset_outstanding) {
+ return;
+ }
+ sctp_alloc_a_chunk(stcb, chk);
+ if (chk == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return;
+ }
+ chk->copy_by_ref = 0;
+ chk->rec.chunk_id.id = SCTP_STREAM_RESET;
+ chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
+ chk->asoc = &stcb->asoc;
+ chk->book_size = sizeof(struct sctp_chunkhdr);
+ chk->send_size = SCTP_SIZE32(chk->book_size);
+ chk->book_size_scale = 0;
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
+ if (chk->data == NULL) {
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return;
+ }
+ SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
+ /* setup chunk parameters */
+ chk->sent = SCTP_DATAGRAM_UNSENT;
+ chk->snd_count = 0;
+ if (stcb->asoc.alternate) {
+ chk->whoTo = stcb->asoc.alternate;
+ } else {
+ chk->whoTo = stcb->asoc.primary_destination;
+ }
+ ch = mtod(chk->data, struct sctp_chunkhdr *);
+ ch->chunk_type = SCTP_STREAM_RESET;
+ ch->chunk_flags = 0;
+ ch->chunk_length = htons(chk->book_size);
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ sctp_add_stream_reset_result(chk, ent->seq, response);
+ /* insert the chunk for sending */
+ TAILQ_INSERT_TAIL(&asoc->control_send_queue,
+ chk,
+ sctp_next);
+ asoc->ctrl_queue_cnt++;
+}
+
+void
sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk,
uint32_t resp_seq, uint32_t result,
uint32_t send_una, uint32_t recv_next)
@@ -12433,19 +12738,90 @@ sctp_add_an_in_stream(struct sctp_tmit_chunk *chk,
}
int
+sctp_send_stream_reset_out_if_possible(struct sctp_tcb *stcb, int so_locked)
+{
+ struct sctp_association *asoc;
+ struct sctp_tmit_chunk *chk;
+ struct sctp_chunkhdr *ch;
+ uint32_t seq;
+
+ asoc = &stcb->asoc;
+ asoc->trigger_reset = 0;
+ if (asoc->stream_reset_outstanding) {
+ return (EALREADY);
+ }
+ sctp_alloc_a_chunk(stcb, chk);
+ if (chk == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return (ENOMEM);
+ }
+ chk->copy_by_ref = 0;
+ chk->rec.chunk_id.id = SCTP_STREAM_RESET;
+ chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
+ chk->asoc = &stcb->asoc;
+ chk->book_size = sizeof(struct sctp_chunkhdr);
+ chk->send_size = SCTP_SIZE32(chk->book_size);
+ chk->book_size_scale = 0;
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
+ if (chk->data == NULL) {
+ sctp_free_a_chunk(stcb, chk, so_locked);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return (ENOMEM);
+ }
+ SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
+
+ /* setup chunk parameters */
+ chk->sent = SCTP_DATAGRAM_UNSENT;
+ chk->snd_count = 0;
+ if (stcb->asoc.alternate) {
+ chk->whoTo = stcb->asoc.alternate;
+ } else {
+ chk->whoTo = stcb->asoc.primary_destination;
+ }
+ ch = mtod(chk->data, struct sctp_chunkhdr *);
+ ch->chunk_type = SCTP_STREAM_RESET;
+ ch->chunk_flags = 0;
+ ch->chunk_length = htons(chk->book_size);
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ seq = stcb->asoc.str_reset_seq_out;
+ if (sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1))) {
+ seq++;
+ asoc->stream_reset_outstanding++;
+ } else {
+ m_freem(chk->data);
+ chk->data = NULL;
+ sctp_free_a_chunk(stcb, chk, so_locked);
+ return (ENOENT);
+ }
+ asoc->str_reset = chk;
+ /* insert the chunk for sending */
+ TAILQ_INSERT_TAIL(&asoc->control_send_queue,
+ chk,
+ sctp_next);
+ asoc->ctrl_queue_cnt++;
+
+ if (stcb->asoc.send_sack) {
+ sctp_send_sack(stcb, so_locked);
+ }
+ sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo);
+ return (0);
+}
+
+int
sctp_send_str_reset_req(struct sctp_tcb *stcb,
uint16_t number_entries, uint16_t *list,
- uint8_t send_out_req,
uint8_t send_in_req,
uint8_t send_tsn_req,
uint8_t add_stream,
uint16_t adding_o,
uint16_t adding_i, uint8_t peer_asked)
{
-
struct sctp_association *asoc;
struct sctp_tmit_chunk *chk;
struct sctp_chunkhdr *ch;
+ int can_send_out_req=0;
uint32_t seq;
asoc = &stcb->asoc;
@@ -12456,16 +12832,18 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY);
return (EBUSY);
}
- if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0) &&
+ if ((send_in_req == 0) && (send_tsn_req == 0) &&
(add_stream == 0)) {
/* nothing to do */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
- if (send_tsn_req && (send_out_req || send_in_req)) {
+ if (send_tsn_req && send_in_req) {
/* error, can't do that */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
+ } else if (send_in_req) {
+ can_send_out_req = 1;
}
if (number_entries > (MCLBYTES -
SCTP_MIN_OVERHEAD -
@@ -12488,7 +12866,6 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
chk->book_size = sizeof(struct sctp_chunkhdr);
chk->send_size = SCTP_SIZE32(chk->book_size);
chk->book_size_scale = 0;
-
chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED);
@@ -12513,12 +12890,13 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
SCTP_BUF_LEN(chk->data) = chk->send_size;
seq = stcb->asoc.str_reset_seq_out;
- if (send_out_req) {
- sctp_add_stream_reset_out(chk, number_entries, list,
- seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1));
- asoc->stream_reset_out_is_outstanding = 1;
- seq++;
- asoc->stream_reset_outstanding++;
+ if (can_send_out_req) {
+ int ret;
+ ret = sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1));
+ if (ret) {
+ seq++;
+ asoc->stream_reset_outstanding++;
+ }
}
if ((add_stream & 1) &&
((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < adding_o)) {
@@ -12533,7 +12911,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
oldstream = stcb->asoc.strmout;
/* get some more */
SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
- ((stcb->asoc.streamoutcnt+adding_o) * sizeof(struct sctp_stream_out)),
+ (stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out),
SCTP_M_STRMO);
if (stcb->asoc.strmout == NULL) {
uint8_t x;
@@ -12551,22 +12929,19 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].chunks_on_queues = oldstream[i].chunks_on_queues;
- stcb->asoc.strmout[i].next_sequence_send = oldstream[i].next_sequence_send;
+ stcb->asoc.strmout[i].next_mid_ordered = oldstream[i].next_mid_ordered;
+ stcb->asoc.strmout[i].next_mid_unordered = oldstream[i].next_mid_unordered;
stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
- stcb->asoc.strmout[i].stream_no = i;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
+ stcb->asoc.strmout[i].sid = i;
+ stcb->asoc.strmout[i].state = oldstream[i].state;
+ /* FIX ME FIX ME */
+ /* This should be a SS_COPY operation FIX ME STREAM SCHEDULER EXPERT */
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], &oldstream[i]);
/* now anything on those queues? */
TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
}
- /* Now move assoc pointers too */
- if (stcb->asoc.last_out_stream == &oldstream[i]) {
- stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
- }
- if (stcb->asoc.locked_on_sending == &oldstream[i]) {
- stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
- }
}
/* now the new streams */
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
@@ -12582,10 +12957,12 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
stcb->asoc.strmout[i].abandoned_sent[0] = 0;
stcb->asoc.strmout[i].abandoned_unsent[0] = 0;
#endif
- stcb->asoc.strmout[i].next_sequence_send = 0x0;
- stcb->asoc.strmout[i].stream_no = i;
+ stcb->asoc.strmout[i].next_mid_ordered = 0;
+ stcb->asoc.strmout[i].next_mid_unordered = 0;
+ stcb->asoc.strmout[i].sid = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL);
+ stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED;
}
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o;
SCTP_FREE(oldstream, SCTP_M_STRMO);
@@ -12619,6 +12996,9 @@ skip_stuff:
chk,
sctp_next);
asoc->ctrl_queue_cnt++;
+ if (stcb->asoc.send_sack) {
+ sctp_send_sack(stcb, SCTP_SO_LOCKED);
+ }
sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo);
return (0);
}
@@ -12626,8 +13006,8 @@ skip_stuff:
void
sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, uint32_t vtag, struct mbuf *cause,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
#endif
uint32_t vrf_id, uint16_t port)
{
@@ -12638,8 +13018,8 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockadd
return;
}
sctp_send_resp_msg(src, dst, sh, vtag, SCTP_ABORT_ASSOCIATION, cause,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
return;
@@ -12648,14 +13028,14 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockadd
void
sctp_send_operr_to(struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, uint32_t vtag, struct mbuf *cause,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
#endif
uint32_t vrf_id, uint16_t port)
{
sctp_send_resp_msg(src, dst, sh, vtag, SCTP_OPERATION_ERROR, cause,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
return;
@@ -12664,27 +13044,14 @@ sctp_send_operr_to(struct sockaddr *src, struct sockaddr *dst,
static struct mbuf *
sctp_copy_resume(struct uio *uio,
int max_send_len,
-#if defined(__FreeBSD__) && __FreeBSD_version > 602000
+#if defined(__FreeBSD__) || defined(__Userspace__)
int user_marks_eor,
#endif
int *error,
uint32_t *sndout,
struct mbuf **new_tail)
{
-#if defined(__Panda__)
- struct mbuf *m;
-
- m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0,
- (user_marks_eor ? M_EOR : 0));
- if (m == NULL) {
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- *error = ENOBUFS;
- } else {
- *sndout = m_length(m, NULL);
- *new_tail = m_last(m);
- }
- return (m);
-#elif defined(__FreeBSD__) && __FreeBSD_version > 602000
+#if defined(__FreeBSD__) || defined(__Userspace__)
struct mbuf *m;
m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0,
@@ -12701,14 +13068,14 @@ sctp_copy_resume(struct uio *uio,
int left, cancpy, willcpy;
struct mbuf *m, *head;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
- left = min(uio->uio_resid, max_send_len);
+ left = (int)min(uio->uio_resid, max_send_len);
#else
- left = min(uio_resid(uio), max_send_len);
+ left = (int)min(uio_resid(uio), max_send_len);
#endif
#else
- left = min(uio->uio_resid, max_send_len);
+ left = (int)min(uio->uio_resid, max_send_len);
#endif
/* Always get a header just in case */
head = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA);
@@ -12717,7 +13084,7 @@ sctp_copy_resume(struct uio *uio,
*error = ENOBUFS;
return (NULL);
}
- cancpy = M_TRAILINGSPACE(head);
+ cancpy = (int)M_TRAILINGSPACE(head);
willcpy = min(cancpy, left);
*error = uiomove(mtod(head, caddr_t), willcpy, uio);
if (*error) {
@@ -12740,7 +13107,7 @@ sctp_copy_resume(struct uio *uio,
return (NULL);
}
m = SCTP_BUF_NEXT(m);
- cancpy = M_TRAILINGSPACE(m);
+ cancpy = (int)M_TRAILINGSPACE(m);
willcpy = min(cancpy, left);
*error = uiomove(mtod(m, caddr_t), willcpy, uio);
if (*error) {
@@ -12767,21 +13134,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
struct uio *uio,
int resv_upfront)
{
- int left;
-#if defined(__Panda__)
- left = sp->length;
- sp->data = m_uiotombuf(uio, M_WAITOK, sp->length,
- resv_upfront, 0);
- if (sp->data == NULL) {
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- return (ENOBUFS);
- }
-
- sp->tail_mbuf = m_last(sp->data);
- return (0);
-
-#elif defined(__FreeBSD__) && __FreeBSD_version > 602000
- left = sp->length;
+#if defined(__FreeBSD__) || defined(__Userspace__)
sp->data = m_uiotombuf(uio, M_WAITOK, sp->length,
resv_upfront, 0);
if (sp->data == NULL) {
@@ -12792,6 +13145,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
sp->tail_mbuf = m_last(sp->data);
return (0);
#else
+ int left;
int cancpy, willcpy, error;
struct mbuf *m, *head;
int cpsz = 0;
@@ -12808,7 +13162,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
* have a bad cnt.
*/
SCTP_BUF_RESV_UF(m, resv_upfront);
- cancpy = M_TRAILINGSPACE(m);
+ cancpy = (int)M_TRAILINGSPACE(m);
willcpy = min(cancpy, left);
while (left > 0) {
/* move in user data */
@@ -12832,7 +13186,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
return (ENOBUFS);
}
m = SCTP_BUF_NEXT(m);
- cancpy = M_TRAILINGSPACE(m);
+ cancpy = (int)M_TRAILINGSPACE(m);
willcpy = min(cancpy, left);
} else {
sp->tail_mbuf = m;
@@ -12845,15 +13199,13 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
#endif
}
-
-
static struct sctp_stream_queue_pending *
sctp_copy_it_in(struct sctp_tcb *stcb,
struct sctp_association *asoc,
struct sctp_sndrcvinfo *srcv,
struct uio *uio,
struct sctp_nets *net,
- int max_send_len,
+ ssize_t max_send_len,
int user_marks_eor,
int *error)
@@ -12870,9 +13222,9 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
*error = 0;
/* Now can we send this? */
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
(asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) {
/* got data while shutting down */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
@@ -12891,19 +13243,20 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
sp->context = srcv->sinfo_context;
+ sp->fsn = 0;
(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
- sp->stream = srcv->sinfo_stream;
-#if defined(__APPLE__)
+ sp->sid = srcv->sinfo_stream;
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
- sp->length = min(uio->uio_resid, max_send_len);
+ sp->length = (uint32_t)min(uio->uio_resid, max_send_len);
#else
- sp->length = min(uio_resid(uio), max_send_len);
+ sp->length = (uint32_t)min(uio_resid(uio), max_send_len);
#endif
#else
- sp->length = min(uio->uio_resid, max_send_len);
+ sp->length = (uint32_t)min(uio->uio_resid, max_send_len);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if ((sp->length == (uint32_t)uio->uio_resid) &&
#else
@@ -12922,10 +13275,9 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
sp->sender_all_done = 0;
sp->some_taken = 0;
sp->put_last_out = 0;
- resv_in_first = sizeof(struct sctp_data_chunk);
+ 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) {
@@ -12937,16 +13289,22 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
sctp_auth_key_acquire(stcb, sp->auth_keyid);
sp->holds_key_ref = 1;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(SCTP_INP_SO(stcb->sctp_ep), 0);
#endif
*error = sctp_copy_one(sp, uio, resv_in_first);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(SCTP_INP_SO(stcb->sctp_ep), 0);
#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) {
@@ -12961,25 +13319,19 @@ out_now:
return (sp);
}
-
int
sctp_sosend(struct socket *so,
struct sockaddr *addr,
struct uio *uio,
-#ifdef __Panda__
- pakhandle_type top,
- pakhandle_type icontrol,
-#else
struct mbuf *top,
struct mbuf *control,
-#endif
-#if defined(__APPLE__) || defined(__Panda__)
+#if defined(__APPLE__) && !defined(__Userspace__)
int flags
#else
int flags,
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct thread *p
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
PKTHREAD p
#else
#if defined(__Userspace__)
@@ -12993,10 +13345,7 @@ sctp_sosend(struct socket *so,
#endif
)
{
-#ifdef __Panda__
- struct mbuf *control = NULL;
-#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct proc *p = current_proc();
#endif
int error, use_sndinfo = 0;
@@ -13006,12 +13355,9 @@ sctp_sosend(struct socket *so,
struct sockaddr_in sin;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(so, 1);
#endif
-#ifdef __Panda__
- control = SCTP_HEADER_TO_CHAIN(icontrol);
-#endif
if (control) {
/* process cmsg snd/rcv info (maybe a assoc-id) */
if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control,
@@ -13033,42 +13379,32 @@ sctp_sosend(struct socket *so,
}
#endif
error = sctp_lower_sosend(so, addr_to_use, uio, top,
-#ifdef __Panda__
- icontrol,
-#else
control,
-#endif
flags,
use_sndinfo ? &sndrcvninfo: NULL
-#if !(defined(__Panda__) || defined(__Userspace__))
+#if !defined(__Userspace__)
, p
#endif
);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
return (error);
}
-
int
sctp_lower_sosend(struct socket *so,
struct sockaddr *addr,
struct uio *uio,
-#ifdef __Panda__
- pakhandle_type i_pak,
- pakhandle_type i_control,
-#else
struct mbuf *i_pak,
struct mbuf *control,
-#endif
int flags,
struct sctp_sndrcvinfo *srcv
-#if !(defined( __Panda__) || defined(__Userspace__))
+#if !defined(__Userspace__)
,
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__)
struct thread *p
-#elif defined(__Windows__)
+#elif defined(_WIN32)
PKTHREAD p
#else
struct proc *p
@@ -13076,12 +13412,12 @@ sctp_lower_sosend(struct socket *so,
#endif
)
{
- unsigned int sndlen = 0, max_len;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
+ ssize_t sndlen = 0, max_len, local_add_more;
int error, len;
struct mbuf *top = NULL;
-#ifdef __Panda__
- struct mbuf *control = NULL;
-#endif
int queue_only = 0, queue_only_for_init = 0;
int free_cnt_applied = 0;
int un_sent;
@@ -13101,7 +13437,7 @@ sctp_lower_sosend(struct socket *so,
int got_all_of_the_send = 0;
int hold_tcblock = 0;
int non_blocking = 0;
- uint32_t local_add_more, local_soresv = 0;
+ ssize_t local_soresv = 0;
uint16_t port;
uint16_t sinfo_flags;
sctp_assoc_t sinfo_assoc_id;
@@ -13111,7 +13447,7 @@ sctp_lower_sosend(struct socket *so,
stcb = NULL;
asoc = NULL;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sctp_lock_assert(so);
#endif
t_inp = inp = (struct sctp_inpcb *)so->so_pcb;
@@ -13130,7 +13466,7 @@ sctp_lower_sosend(struct socket *so,
user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
atomic_add_int(&inp->total_sends, 1);
if (uio) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if (uio->uio_resid < 0) {
#else
@@ -13142,7 +13478,7 @@ sctp_lower_sosend(struct socket *so,
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
sndlen = uio->uio_resid;
#else
@@ -13153,41 +13489,13 @@ sctp_lower_sosend(struct socket *so,
#endif
} else {
top = SCTP_HEADER_TO_CHAIN(i_pak);
-#ifdef __Panda__
- /*-
- * app len indicates the datalen, dgsize for cases
- * of SCTP_EOF/ABORT will not have the right len
- */
- sndlen = SCTP_APP_DATA_LEN(i_pak);
- /*-
- * Set the particle len also to zero to match
- * up with app len. We only have one particle
- * if app len is zero for Panda. This is ensured
- * in the socket lib
- */
- if (sndlen == 0) {
- SCTP_BUF_LEN(top) = 0;
- }
- /*-
- * We delink the chain from header, but keep
- * the header around as we will need it in
- * EAGAIN case
- */
- SCTP_DETACH_HEADER_FROM_CHAIN(i_pak);
-#else
sndlen = SCTP_HEADER_LEN(i_pak);
-#endif
}
- SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n",
- (void *)addr,
+ SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n",
+ (void *)addr,
sndlen);
-#ifdef __Panda__
- if (i_control) {
- control = SCTP_HEADER_TO_CHAIN(i_control);
- }
-#endif
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_socket->so_qlimit)) {
+ SCTP_IS_LISTENING(inp)) {
/* The listener can NOT send */
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
error = ENOTCONN;
@@ -13259,6 +13567,14 @@ sctp_lower_sosend(struct socket *so,
sinfo_flags = inp->def_send.sinfo_flags;
sinfo_assoc_id = inp->def_send.sinfo_assoc_id;
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (flags & MSG_EOR) {
+ sinfo_flags |= SCTP_EOR;
+ }
+ if (flags & MSG_EOF) {
+ sinfo_flags |= SCTP_EOF;
+ }
+#endif
if (sinfo_flags & SCTP_SENDALL) {
/* its a sendall */
error = sctp_sendall(inp, uio, top, srcv);
@@ -13281,7 +13597,10 @@ sctp_lower_sosend(struct socket *so,
}
SCTP_INP_RUNLOCK(inp);
} else if (sinfo_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0);
+ stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1);
+ if (stcb != NULL) {
+ hold_tcblock = 1;
+ }
} else if (addr) {
/*-
* Since we did not use findep we must
@@ -13310,7 +13629,6 @@ sctp_lower_sosend(struct socket *so,
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
-
}
if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
(addr->sa_family == AF_INET6)) {
@@ -13323,9 +13641,11 @@ sctp_lower_sosend(struct socket *so,
SCTP_INP_WUNLOCK(inp);
/* With the lock applied look again */
stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL);
+#if defined(INET) || defined(INET6)
if ((stcb == NULL) && (control != NULL) && (port > 0)) {
stcb = sctp_findassociation_cmsgs(&t_inp, port, control, &net, &error);
}
+#endif
if (stcb == NULL) {
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
@@ -13369,12 +13689,14 @@ sctp_lower_sosend(struct socket *so,
}
#endif
stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
-#if !(defined( __Panda__) || defined(__Userspace__))
- p
+ inp->sctp_ep.pre_open_stream_count,
+ inp->sctp_ep.port,
+#if !defined(__Userspace__)
+ p,
#else
- (struct proc *)NULL
+ (struct proc *)NULL,
#endif
- );
+ SCTP_INITIALIZE_AUTH_PARAMS);
if (stcb == NULL) {
/* Error is setup for us in the call */
goto out_unlocked;
@@ -13394,15 +13716,13 @@ sctp_lower_sosend(struct socket *so,
/* Turn on queue only flag to prevent data from being sent */
queue_only = 1;
asoc = &stcb->asoc;
- SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT);
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
- /* initialize authentication params for the assoc */
- sctp_initialize_auth_params(inp, stcb);
-
if (control) {
if (sctp_process_cmsgs_for_init(stcb, control, &error)) {
- sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_7);
+ sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
hold_tcblock = 0;
stcb = NULL;
goto out_unlocked;
@@ -13419,9 +13739,19 @@ sctp_lower_sosend(struct socket *so,
}
} else
asoc = &stcb->asoc;
- if (srcv == NULL)
+ if (srcv == NULL) {
srcv = (struct sctp_sndrcvinfo *)&asoc->def_send;
- if (srcv->sinfo_flags & SCTP_ADDR_OVER) {
+ sinfo_flags = srcv->sinfo_flags;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (flags & MSG_EOR) {
+ sinfo_flags |= SCTP_EOR;
+ }
+ if (flags & MSG_EOF) {
+ sinfo_flags |= SCTP_EOF;
+ }
+#endif
+ }
+ if (sinfo_flags & SCTP_ADDR_OVER) {
if (addr)
net = sctp_findnet(stcb, addr);
else
@@ -13445,7 +13775,7 @@ sctp_lower_sosend(struct socket *so,
free_cnt_applied = 1;
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) {
- if (sndlen > asoc->smallest_mtu) {
+ if (sndlen > (ssize_t)asoc->smallest_mtu) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE);
error = EMSGSIZE;
goto out_unlocked;
@@ -13457,29 +13787,36 @@ sctp_lower_sosend(struct socket *so,
}
#endif
if (SCTP_SO_IS_NBIO(so)
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
- || (flags & MSG_NBIO)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ || (flags & (MSG_NBIO | MSG_DONTWAIT)) != 0
#endif
) {
non_blocking = 1;
}
/* would we block? */
if (non_blocking) {
+ ssize_t amount;
+
if (hold_tcblock == 0) {
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
- if ((SCTP_SB_LIMIT_SND(so) < (sndlen + inqueue_bytes + stcb->asoc.sb_send_resv)) ||
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (user_marks_eor == 0) {
+ amount = sndlen;
+ } else {
+ amount = 1;
+ }
+ if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + stcb->asoc.sb_send_resv)) ||
(stcb->asoc.chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK);
- if (sndlen > SCTP_SB_LIMIT_SND(so))
+ if (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so))
error = EMSGSIZE;
else
error = EWOULDBLOCK;
goto out_unlocked;
}
- stcb->asoc.sb_send_resv += sndlen;
+ stcb->asoc.sb_send_resv += (uint32_t)sndlen;
SCTP_TCB_UNLOCK(stcb);
hold_tcblock = 0;
} else {
@@ -13495,16 +13832,28 @@ sctp_lower_sosend(struct socket *so,
SCTP_ASOC_CREATE_UNLOCK(inp);
create_lock_applied = 0;
}
- if (asoc->stream_reset_outstanding) {
+ /* Is the stream no. valid? */
+ if (srcv->sinfo_stream >= asoc->streamoutcnt) {
+ /* Invalid stream number */
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ error = EINVAL;
+ goto out_unlocked;
+ }
+ if ((asoc->strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPEN) &&
+ (asoc->strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPENING)) {
/*
* Can't queue any data while stream reset is underway.
*/
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN);
- error = EAGAIN;
+ if (asoc->strmout[srcv->sinfo_stream].state > SCTP_STREAM_OPEN) {
+ error = EAGAIN;
+ } else {
+ error = EINVAL;
+ }
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error);
goto out_unlocked;
}
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
queue_only = 1;
}
/* we are now done with all control */
@@ -13512,11 +13861,11 @@ sctp_lower_sosend(struct socket *so,
sctp_m_freem(control);
control = NULL;
}
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
(asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) {
- if (srcv->sinfo_flags & SCTP_ABORT) {
+ if (sinfo_flags & SCTP_ABORT) {
;
} else {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
@@ -13525,25 +13874,23 @@ sctp_lower_sosend(struct socket *so,
}
}
/* Ok, we will attempt a msgsnd :> */
-#if !(defined(__Panda__) || defined(__Windows__) || defined(__Userspace__))
+#if !(defined(_WIN32) || defined(__Userspace__))
if (p) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 603000
+#if defined(__FreeBSD__)
p->td_ru.ru_msgsnd++;
-#elif defined(__FreeBSD__) && __FreeBSD_version >= 500000
- p->td_proc->p_stats->p_ru.ru_msgsnd++;
#else
p->p_stats->p_ru.ru_msgsnd++;
#endif
}
#endif
/* Are we aborting? */
- if (srcv->sinfo_flags & SCTP_ABORT) {
+ if (sinfo_flags & SCTP_ABORT) {
struct mbuf *mm;
- int tot_demand, tot_out = 0, max_out;
+ ssize_t tot_demand, tot_out = 0, max_out;
SCTP_STAT_INCR(sctps_sends_with_abort);
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
/* It has to be up before we abort */
/* how big is the user initiated abort? */
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
@@ -13573,7 +13920,7 @@ sctp_lower_sosend(struct socket *so,
error = EMSGSIZE;
goto out;
}
- mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAITOK, 1, MT_DATA);
+ mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_WAITOK, 1, MT_DATA);
}
if (mm == NULL) {
SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
@@ -13591,15 +13938,15 @@ sctp_lower_sosend(struct socket *so,
/* now move forward the data pointer */
ph = mtod(mm, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr) + tot_out);
+ ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out));
ph++;
- SCTP_BUF_LEN(mm) = tot_out + sizeof(struct sctp_paramhdr);
+ SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr));
if (top == NULL) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 0);
#endif
error = uiomove((caddr_t)ph, (int)tot_out, uio);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(so, 0);
#endif
if (error) {
@@ -13623,7 +13970,13 @@ sctp_lower_sosend(struct socket *so,
atomic_add_int(&stcb->asoc.refcnt, -1);
free_cnt_applied = 0;
/* release this lock, otherwise we hang on ourselves */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_abort_an_association(stcb->sctp_ep, stcb, mm, SCTP_SO_LOCKED);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
/* now relock the stcb so everything is sane */
hold_tcblock = 0;
stcb = NULL;
@@ -13638,14 +13991,9 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked;
}
/* Calculate the maximum we can send */
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
- if (non_blocking) {
- /* we already checked for non-blocking above. */
- max_len = sndlen;
- } else {
- max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
- }
+ max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
} else {
max_len = 0;
}
@@ -13653,13 +14001,6 @@ sctp_lower_sosend(struct socket *so,
SCTP_TCB_UNLOCK(stcb);
hold_tcblock = 0;
}
- /* Is the stream no. valid? */
- if (srcv->sinfo_stream >= asoc->streamoutcnt) {
- /* Invalid stream number */
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
- error = EINVAL;
- goto out_unlocked;
- }
if (asoc->strmout == NULL) {
/* huh? software error */
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
@@ -13669,7 +14010,7 @@ sctp_lower_sosend(struct socket *so,
/* Unless E_EOR mode is on, we must make a send FIT in one call. */
if ((user_marks_eor == 0) &&
- (sndlen > SCTP_SB_LIMIT_SND(stcb->sctp_socket))) {
+ (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) {
/* It will NEVER fit */
SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE);
error = EMSGSIZE;
@@ -13686,7 +14027,7 @@ sctp_lower_sosend(struct socket *so,
}
if (user_marks_eor) {
- local_add_more = min(SCTP_SB_LIMIT_SND(so), SCTP_BASE_SYSCTL(sctp_add_more_threshold));
+ local_add_more = (ssize_t)min(SCTP_SB_LIMIT_SND(so), SCTP_BASE_SYSCTL(sctp_add_more_threshold));
} else {
/*-
* For non-eeor the whole message must fit in
@@ -13699,15 +14040,15 @@ sctp_lower_sosend(struct socket *so,
goto skip_preblock;
}
if (((max_len <= local_add_more) &&
- (SCTP_SB_LIMIT_SND(so) >= local_add_more)) ||
+ ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) ||
(max_len == 0) ||
((stcb->asoc.chunks_on_out_queue+stcb->asoc.stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
/* No room right now ! */
SOCKBUF_LOCK(&so->so_snd);
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) ||
- ((stcb->asoc.stream_queue_cnt+stcb->asoc.chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
- SCTPDBG(SCTP_DEBUG_OUTPUT1,"pre_block limit:%u <(inq:%d + %d) || (%d+%d > %d)\n",
+ ((stcb->asoc.stream_queue_cnt + stcb->asoc.chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT1,"pre_block limit:%u <(inq:%d + %zd) || (%d+%d > %d)\n",
(unsigned int)SCTP_SB_LIMIT_SND(so),
inqueue_bytes,
local_add_more,
@@ -13718,7 +14059,7 @@ sctp_lower_sosend(struct socket *so,
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, asoc, sndlen);
}
be.error = 0;
-#if !defined(__Panda__) && !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
stcb->block_entry = &be;
#endif
error = sbwait(&so->so_snd);
@@ -13739,9 +14080,10 @@ sctp_lower_sosend(struct socket *so,
asoc, stcb->asoc.total_output_queue_size);
}
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SOCKBUF_UNLOCK(&so->so_snd);
goto out_unlocked;
}
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
}
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
@@ -13755,7 +14097,7 @@ skip_preblock:
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
goto out_unlocked;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
error = sblock(&so->so_snd, SBLOCKWAIT(flags));
#endif
/* sndlen covers for mbuf case
@@ -13763,7 +14105,7 @@ skip_preblock:
* NOTE: uio will be null when top/mbuf is passed
*/
if (sndlen == 0) {
- if (srcv->sinfo_flags & SCTP_EOF) {
+ if (sinfo_flags & SCTP_EOF) {
got_all_of_the_send = 1;
goto dataless_eof;
} else {
@@ -13785,13 +14127,12 @@ skip_preblock:
error = EINVAL;
goto out;
}
- SCTP_TCB_SEND_UNLOCK(stcb);
-
strm = &stcb->asoc.strmout[srcv->sinfo_stream];
if (strm->last_msg_incomplete == 0) {
do_a_copy_in:
+ SCTP_TCB_SEND_UNLOCK(stcb);
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);
@@ -13803,22 +14144,22 @@ skip_preblock:
* case of an interrupt.
*/
strm->last_msg_incomplete = 1;
- asoc->stream_locked = 1;
- asoc->stream_locked_on = srcv->sinfo_stream;
+ if (stcb->asoc.idata_supported == 0) {
+ asoc->stream_locked = 1;
+ asoc->stream_locked_on = srcv->sinfo_stream;
+ }
sp->sender_all_done = 0;
}
sctp_snd_sb_alloc(stcb, sp->length);
atomic_add_int(&asoc->stream_queue_cnt, 1);
- if (srcv->sinfo_flags & SCTP_UNORDERED) {
+ if (sinfo_flags & SCTP_UNORDERED) {
SCTP_STAT_INCR(sctps_sends_with_unord);
}
+ sp->processing = 1;
TAILQ_INSERT_TAIL(&strm->outqueue, sp, next);
stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp, 1);
- SCTP_TCB_SEND_UNLOCK(stcb);
} else {
- SCTP_TCB_SEND_LOCK(stcb);
sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead);
- SCTP_TCB_SEND_UNLOCK(stcb);
if (sp == NULL) {
/* ???? Huh ??? last msg is gone */
#ifdef INVARIANTS
@@ -13828,10 +14169,18 @@ skip_preblock:
strm->last_msg_incomplete = 0;
#endif
goto do_a_copy_in;
-
+ }
+ if (sp->processing) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ error = EINVAL;
+ goto out;
+ } else {
+ sp->processing = 1;
}
}
-#if defined(__APPLE__)
+ SCTP_TCB_SEND_UNLOCK(stcb);
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
while (uio->uio_resid > 0) {
#else
@@ -13843,21 +14192,22 @@ skip_preblock:
/* How much room do we have? */
struct mbuf *new_tail, *mm;
- if (SCTP_SB_LIMIT_SND(so) > stcb->asoc.total_output_queue_size)
- max_len = SCTP_SB_LIMIT_SND(so) - stcb->asoc.total_output_queue_size;
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
+ max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
else
max_len = 0;
- if ((max_len > SCTP_BASE_SYSCTL(sctp_add_more_threshold)) ||
+ if ((max_len > (ssize_t)SCTP_BASE_SYSCTL(sctp_add_more_threshold)) ||
(max_len && (SCTP_SB_LIMIT_SND(so) < SCTP_BASE_SYSCTL(sctp_add_more_threshold))) ||
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
- (uio->uio_resid && (uio->uio_resid <= (int)max_len))) {
+ (uio->uio_resid && (uio->uio_resid <= max_len))) {
#else
- (uio_resid(uio) && (uio_resid(uio) <= (int)max_len))) {
+ (uio_resid(uio) && (uio_resid(uio) <= max_len))) {
#endif
#else
- (uio->uio_resid && (uio->uio_resid <= (int)max_len))) {
+ (uio->uio_resid && (uio->uio_resid <= max_len))) {
#endif
sndout = 0;
new_tail = NULL;
@@ -13865,31 +14215,39 @@ skip_preblock:
SCTP_TCB_UNLOCK(stcb);
hold_tcblock = 0;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 0);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version > 602000
- mm = sctp_copy_resume(uio, max_len, user_marks_eor, &error, &sndout, &new_tail);
+#if defined(__FreeBSD__) || defined(__Userspace__)
+ mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail);
#else
- mm = sctp_copy_resume(uio, max_len, &error, &sndout, &new_tail);
+ mm = sctp_copy_resume(uio, (int)max_len, &error, &sndout, &new_tail);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(so, 0);
#endif
if ((mm == NULL) || error) {
if (mm) {
sctp_m_freem(mm);
}
+ SCTP_TCB_SEND_LOCK(stcb);
+ if (((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
+ ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) == 0) &&
+ (sp != NULL)) {
+ sp->processing = 0;
+ }
+ SCTP_TCB_SEND_UNLOCK(stcb);
goto out;
}
/* Update the mbuf and count */
SCTP_TCB_SEND_LOCK(stcb);
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+ (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
/* we need to get out.
* Peer probably aborted.
*/
sctp_m_freem(mm);
- if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED) {
+ if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
error = ECONNRESET;
}
@@ -13906,11 +14264,14 @@ skip_preblock:
sp->tail_mbuf = new_tail;
}
sctp_snd_sb_alloc(stcb, sndout);
- atomic_add_int(&sp->length,sndout);
+ atomic_add_int(&sp->length, sndout);
len += sndout;
+ if (sinfo_flags & SCTP_SACK_IMMEDIATELY) {
+ sp->sinfo_flags |= SCTP_SACK_IMMEDIATELY;
+ }
/* Did we reach EOR? */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if ((uio->uio_resid == 0) &&
#else
@@ -13920,15 +14281,15 @@ skip_preblock:
if ((uio->uio_resid == 0) &&
#endif
((user_marks_eor == 0) ||
- (srcv->sinfo_flags & SCTP_EOF) ||
- (user_marks_eor && (srcv->sinfo_flags & SCTP_EOR)))) {
+ (sinfo_flags & SCTP_EOF) ||
+ (user_marks_eor && (sinfo_flags & SCTP_EOR)))) {
sp->msg_is_complete = 1;
} else {
sp->msg_is_complete = 0;
}
SCTP_TCB_SEND_UNLOCK(stcb);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if (uio->uio_resid == 0) {
#else
@@ -13947,9 +14308,9 @@ skip_preblock:
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- sctp_prune_prsctp(stcb, asoc, srcv, sndlen);
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
- if (SCTP_SB_LIMIT_SND(so) > stcb->asoc.total_output_queue_size)
+ sctp_prune_prsctp(stcb, asoc, srcv, (int)sndlen);
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
else
max_len = 0;
@@ -13962,6 +14323,11 @@ skip_preblock:
/* wait for space now */
if (non_blocking) {
/* Non-blocking io in place out */
+ SCTP_TCB_SEND_LOCK(stcb);
+ if (sp != NULL) {
+ sp->processing = 0;
+ }
+ SCTP_TCB_SEND_UNLOCK(stcb);
goto skip_out_eof;
}
/* What about the INIT, send it maybe */
@@ -13970,12 +14336,18 @@ skip_preblock:
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
/* a collision took us forward? */
queue_only = 0;
} else {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
- SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
queue_only = 1;
}
}
@@ -13990,17 +14362,15 @@ skip_preblock:
}
asoc->ifp_had_enobuf = 0;
}
- un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
(stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
(un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) {
-
/*-
* Ok, Nagle is set on and we have data outstanding.
* Don't send anything and let SACKs drive out the
- * data unless wen have a "full" segment to send.
+ * data unless we have a "full" segment to send.
*/
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) {
sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED);
@@ -14016,7 +14386,6 @@ skip_preblock:
nagle_applies = 0;
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
-
sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only,
nagle_applies, un_sent);
sctp_misc_ints(SCTP_CWNDLOG_PRESEND, stcb->asoc.total_output_queue_size,
@@ -14033,6 +14402,9 @@ skip_preblock:
* the input via the net is happening
* and I don't need to start output :-D
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
if (hold_tcblock == 0) {
if (SCTP_TCB_TRYLOCK(stcb)) {
hold_tcblock = 1;
@@ -14045,10 +14417,13 @@ skip_preblock:
stcb,
SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
- if (hold_tcblock == 1) {
- SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
- }
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
+ }
+ if (hold_tcblock == 1) {
+ SCTP_TCB_UNLOCK(stcb);
+ hold_tcblock = 0;
}
SOCKBUF_LOCK(&so->so_snd);
/*-
@@ -14065,10 +14440,11 @@ skip_preblock:
* size we KNOW we will get to sleep safely with the
* wakeup flag in place.
*/
- if (SCTP_SB_LIMIT_SND(so) <= (stcb->asoc.total_output_queue_size +
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes +
min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK,
asoc, uio->uio_resid);
@@ -14082,10 +14458,10 @@ skip_preblock:
#endif
}
be.error = 0;
-#if !defined(__Panda__) && !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
stcb->block_entry = &be;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sbunlock(&so->so_snd, 1);
#endif
error = sbwait(&so->so_snd);
@@ -14100,10 +14476,17 @@ skip_preblock:
}
}
SOCKBUF_UNLOCK(&so->so_snd);
+ SCTP_TCB_SEND_LOCK(stcb);
+ if (((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
+ ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) == 0) &&
+ (sp != NULL)) {
+ sp->processing = 0;
+ }
+ SCTP_TCB_SEND_UNLOCK(stcb);
goto out_unlocked;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
error = sblock(&so->so_snd, SBLOCKWAIT(flags));
#endif
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
@@ -14112,28 +14495,40 @@ skip_preblock:
}
}
SOCKBUF_UNLOCK(&so->so_snd);
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SCTP_TCB_SEND_LOCK(stcb);
+ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+ (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
goto out_unlocked;
}
+ SCTP_TCB_SEND_UNLOCK(stcb);
}
SCTP_TCB_SEND_LOCK(stcb);
+ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+ (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
+ goto out_unlocked;
+ }
if (sp) {
if (sp->msg_is_complete == 0) {
strm->last_msg_incomplete = 1;
- asoc->stream_locked = 1;
- asoc->stream_locked_on = srcv->sinfo_stream;
+ if (stcb->asoc.idata_supported == 0) {
+ asoc->stream_locked = 1;
+ asoc->stream_locked_on = srcv->sinfo_stream;
+ }
} else {
sp->sender_all_done = 1;
strm->last_msg_incomplete = 0;
asoc->stream_locked = 0;
}
+ sp->processing = 0;
} else {
SCTP_PRINTF("Huh no sp TSNH?\n");
strm->last_msg_incomplete = 0;
asoc->stream_locked = 0;
}
SCTP_TCB_SEND_UNLOCK(stcb);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if (uio->uio_resid == 0) {
#else
@@ -14148,13 +14543,7 @@ skip_preblock:
/* We send in a 0, since we do NOT have any locks */
error = sctp_msg_append(stcb, net, top, srcv, 0);
top = NULL;
- if (srcv->sinfo_flags & SCTP_EOF) {
- /*
- * This should only happen for Panda for the mbuf
- * send case, which does NOT yet support EEOR mode.
- * Thus, we can just set this flag to do the proper
- * EOF handling.
- */
+ if (sinfo_flags & SCTP_EOF) {
got_all_of_the_send = 1;
}
}
@@ -14163,34 +14552,31 @@ skip_preblock:
}
dataless_eof:
/* EOF thing ? */
- if ((srcv->sinfo_flags & SCTP_EOF) &&
+ if ((sinfo_flags & SCTP_EOF) &&
(got_all_of_the_send == 1)) {
- int cnt;
SCTP_STAT_INCR(sctps_sends_with_eof);
error = 0;
if (hold_tcblock == 0) {
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED);
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
- (cnt == 0)) {
- if (asoc->locked_on_sending) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
goto abort_anyway;
}
/* there is nothing queued to send, so I'm done... */
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
struct sctp_nets *netp;
/* only send SHUTDOWN the first time through */
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
@@ -14201,7 +14587,7 @@ dataless_eof:
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
- asoc->primary_destination);
+ NULL);
}
} else {
/*-
@@ -14214,40 +14600,47 @@ dataless_eof:
* data to be sent first and move to
* SHUTDOWN-PENDING
*/
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
if (hold_tcblock == 0) {
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- if (asoc->locked_on_sending) {
- /* Locked to send out the data */
- struct sctp_stream_queue_pending *sp;
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp) {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
}
- asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
abort_anyway:
if (free_cnt_applied) {
atomic_add_int(&stcb->asoc.refcnt, -1);
free_cnt_applied = 0;
}
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "%s:%d at %s", __FILE__, __LINE__, __func__);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_abort_an_association(stcb->sctp_ep, stcb,
- NULL, SCTP_SO_LOCKED);
+ op_err, SCTP_SO_LOCKED);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
/* now relock the stcb so everything is sane */
hold_tcblock = 0;
stcb = NULL;
goto out;
}
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
- asoc->primary_destination);
+ NULL);
sctp_feature_off(inp, SCTP_PCB_FLAGS_NODELAY);
}
}
@@ -14261,12 +14654,18 @@ skip_out_eof:
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
/* a collision took us forward? */
queue_only = 0;
} else {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
- SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
queue_only = 1;
}
}
@@ -14281,8 +14680,7 @@ skip_out_eof:
}
asoc->ifp_had_enobuf = 0;
}
- un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
(stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
@@ -14312,6 +14710,9 @@ skip_out_eof:
stcb->asoc.total_flight,
stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count);
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) {
/* we can attempt to send too. */
if (hold_tcblock == 0) {
@@ -14344,13 +14745,16 @@ skip_out_eof:
(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
&reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED);
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n",
queue_only, stcb->asoc.peers_rwnd, un_sent,
stcb->asoc.total_flight, stcb->asoc.chunks_on_out_queue,
stcb->asoc.total_output_queue_size, error);
out:
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sbunlock(&so->so_snd, 1);
#endif
out_unlocked:
@@ -14368,7 +14772,7 @@ out_unlocked:
atomic_add_int(&stcb->asoc.refcnt, -1);
}
#ifdef INVARIANTS
-#if !defined(__APPLE__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (stcb) {
if (mtx_owned(&stcb->tcb_mtx)) {
panic("Leaving with tcb mtx owned?");
@@ -14379,40 +14783,6 @@ out_unlocked:
}
#endif
#endif
-#ifdef __Panda__
- /*
- * Handle the EAGAIN/ENOMEM cases to reattach the pak header
- * to particle when pak is passed in, so that caller
- * can try again with this pak
- *
- * NOTE: For other cases, including success case,
- * we simply want to return the header back to free
- * pool
- */
- if (top) {
- if ((error == EAGAIN) || (error == ENOMEM)) {
- SCTP_ATTACH_CHAIN(i_pak, top, sndlen);
- top = NULL;
- } else {
- (void)SCTP_RELEASE_HEADER(i_pak);
- }
- } else {
- /* This is to handle cases when top has
- * been reset to NULL but pak might not
- * be freed
- */
- if (i_pak) {
- (void)SCTP_RELEASE_HEADER(i_pak);
- }
- }
-#endif
-#ifdef INVARIANTS
- if (inp) {
- sctp_validate_no_locks(inp);
- } else {
- SCTP_PRINTF("Warning - inp is NULL so cant validate locks\n");
- }
-#endif
if (top) {
sctp_m_freem(top);
}
@@ -14422,7 +14792,6 @@ out_unlocked:
return (error);
}
-
/*
* generate an AUTHentication chunk, if required
*/
@@ -14457,7 +14826,7 @@ sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end,
SCTP_BUF_RESV_UF(m_auth, SCTP_MIN_OVERHEAD);
/* fill in the AUTH chunk details */
auth = mtod(m_auth, struct sctp_auth_chunk *);
- bzero(auth, sizeof(*auth));
+ memset(auth, 0, sizeof(*auth));
auth->ch.chunk_type = SCTP_AUTHENTICATION;
auth->ch.chunk_flags = 0;
chunk_len = sizeof(*auth) +
@@ -14481,7 +14850,7 @@ sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end,
return (m);
}
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
#ifdef INET6
int
sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro)
@@ -14490,10 +14859,17 @@ sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro)
struct nd_pfxrouter *pfxrtr = NULL;
struct sockaddr_in6 gw6;
+#if defined(__FreeBSD__)
+ if (ro == NULL || ro->ro_nh == NULL || src6->sin6_family != AF_INET6)
+#else
if (ro == NULL || ro->ro_rt == NULL || src6->sin6_family != AF_INET6)
+#endif
return (0);
/* get prefix entry of address */
+#if defined(__FreeBSD__)
+ ND6_RLOCK();
+#endif
LIST_FOREACH(pfx, &MODULE_GLOBAL(nd_prefix), ndpr_entry) {
if (pfx->ndpr_stateflags & NDPRF_DETACHED)
continue;
@@ -14503,6 +14879,9 @@ sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro)
}
/* no prefix entry in the prefix list */
if (pfx == NULL) {
+#if defined(__FreeBSD__)
+ ND6_RUNLOCK();
+#endif
SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefix entry for ");
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6);
return (0);
@@ -14523,13 +14902,24 @@ sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro)
SCTPDBG(SCTP_DEBUG_OUTPUT2, "prefix router is ");
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&gw6);
SCTPDBG(SCTP_DEBUG_OUTPUT2, "installed router is ");
+#if defined(__FreeBSD__)
+ SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ro->ro_nh->gw_sa);
+#else
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway);
- if (sctp_cmpaddr((struct sockaddr *)&gw6,
- ro->ro_rt->rt_gateway)) {
+#endif
+#if defined(__FreeBSD__)
+ if (sctp_cmpaddr((struct sockaddr *)&gw6, &ro->ro_nh->gw_sa)) {
+ ND6_RUNLOCK();
+#else
+ if (sctp_cmpaddr((struct sockaddr *)&gw6, ro->ro_rt->rt_gateway)) {
+#endif
SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is installed\n");
return (1);
}
}
+#if defined(__FreeBSD__)
+ ND6_RUNLOCK();
+#endif
SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is not installed\n");
return (0);
}
@@ -14543,7 +14933,11 @@ sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro)
struct ifaddr *ifa;
struct in_addr srcnetaddr, gwnetaddr;
+#if defined(__FreeBSD__)
+ if (ro == NULL || ro->ro_nh == NULL ||
+#else
if (ro == NULL || ro->ro_rt == NULL ||
+#endif
sifa->address.sa.sa_family != AF_INET) {
return (0);
}
@@ -14555,10 +14949,18 @@ sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro)
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa);
SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", srcnetaddr.s_addr);
+#if defined(__FreeBSD__)
+ sin = &ro->ro_nh->gw4_sa;
+#else
sin = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
+#endif
gwnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr);
SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: nexthop is ");
+#if defined(__FreeBSD__)
+ SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ro->ro_nh->gw_sa);
+#else
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway);
+#endif
SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", gwnetaddr.s_addr);
if (srcnetaddr.s_addr == gwnetaddr.s_addr) {
return (1);
diff --git a/netwerk/sctp/src/netinet/sctp_output.h b/netwerk/sctp/src/netinet/sctp_output.h
index d03bead046..dad10e00a7 100755
--- a/netwerk/sctp/src/netinet/sctp_output.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 272751 2014-10-08 15:30:59Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 366114 2020-09-24 12:26:06Z tuexen $");
#endif
#ifndef _NETINET_SCTP_OUTPUT_H_
@@ -42,76 +44,68 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 272751 2014-10-08 15:30:59Z t
#if defined(_KERNEL) || defined(__Userspace__)
-
struct mbuf *
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
- struct sctp_scoping *scope,
- struct mbuf *m_at,
- int cnt_inits_to,
- uint16_t *padding_len, uint16_t *chunk_len);
-
+ struct sctp_scoping *scope,
+ struct mbuf *m_at,
+ int cnt_inits_to,
+ uint16_t *padding_len, uint16_t *chunk_len);
int sctp_is_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
-
int
sctp_is_address_in_scope(struct sctp_ifa *ifa,
struct sctp_scoping *scope,
- int do_update);
+ int do_update);
int
sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa);
struct sctp_ifa *
sctp_source_address_selection(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- sctp_route_t *ro, struct sctp_nets *net,
- int non_asoc_addr_ok, uint32_t vrf_id);
+ struct sctp_tcb *stcb,
+ sctp_route_t *ro, struct sctp_nets *net,
+ int non_asoc_addr_ok, uint32_t vrf_id);
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
-int
-sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro);
-int
-sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro);
-#endif
+int sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro);
-void sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
+int sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro);
#endif
- );
+
+void sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int);
void
-sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *, struct mbuf *,
+sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
+ struct sctp_nets *, struct mbuf *,
int, int,
struct sockaddr *, struct sockaddr *,
struct sctphdr *, struct sctp_init_chunk *,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t, uint32_t,
#endif
- uint32_t, uint16_t, int);
+ uint32_t, uint16_t);
struct mbuf *
sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
- struct sctp_chunkhdr *, int *);
+ struct sctp_chunkhdr *, int *, int *);
void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *);
int
-sctp_send_cookie_echo(struct mbuf *, int, struct sctp_tcb *,
- struct sctp_nets *);
+sctp_send_cookie_echo(struct mbuf *, int, int, struct sctp_tcb *,
+ struct sctp_nets *);
void sctp_send_cookie_ack(struct sctp_tcb *);
void
sctp_send_heartbeat_ack(struct sctp_tcb *, struct mbuf *, int, int,
- struct sctp_nets *);
+ struct sctp_nets *);
void
sctp_remove_from_wheel(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- struct sctp_stream_out *strq, int holds_lock);
-
+ struct sctp_association *asoc,
+ struct sctp_stream_out *strq, int holds_lock);
void sctp_send_shutdown(struct sctp_tcb *, struct sctp_nets *);
@@ -121,8 +115,8 @@ void sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *, int);
void sctp_send_shutdown_complete2(struct sockaddr *, struct sockaddr *,
struct sctphdr *,
-#if defined(__FreeBSD__)
- uint8_t, uint32_t,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t, uint32_t, uint16_t,
#endif
uint32_t, uint16_t);
@@ -140,11 +134,15 @@ void sctp_fix_ecn_echo(struct sctp_association *);
void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#define SCTP_DATA_CHUNK_OVERHEAD(stcb) ((stcb)->asoc.idata_supported ? \
+ sizeof(struct sctp_idata_chunk) : \
+ sizeof(struct sctp_data_chunk))
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int
sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, struct thread *, int);
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, PKTHREAD, int);
#else
@@ -153,30 +151,15 @@ sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
#endif
int
sctp_output(struct sctp_inpcb *,
-#if defined(__Panda__)
- pakhandle_type,
-#else
struct mbuf *,
-#endif
struct sockaddr *,
-#if defined(__Panda__)
- pakhandle_type,
-#else
struct mbuf *,
-#endif
struct proc *, int);
#endif
-void sctp_chunk_output(struct sctp_inpcb *, struct sctp_tcb *, int, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- );
-void sctp_send_abort_tcb(struct sctp_tcb *, struct mbuf *, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- );
+void sctp_chunk_output(struct sctp_inpcb *, struct sctp_tcb *, int, int);
+
+void sctp_send_abort_tcb(struct sctp_tcb *, struct mbuf *, int);
void send_forward_tsn(struct sctp_tcb *, struct sctp_association *);
@@ -186,45 +169,45 @@ void sctp_send_hb(struct sctp_tcb *, struct sctp_nets *, int);
void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t);
-
void
sctp_send_packet_dropped(struct sctp_tcb *, struct sctp_nets *, struct mbuf *,
int, int, int);
-
-
void sctp_send_cwr(struct sctp_tcb *, struct sctp_nets *, uint32_t, uint8_t);
-
void
-sctp_add_stream_reset_out(struct sctp_tmit_chunk *,
- int, uint16_t *, uint32_t, uint32_t, uint32_t);
+sctp_add_stream_reset_result(struct sctp_tmit_chunk *, uint32_t, uint32_t);
void
-sctp_add_stream_reset_result(struct sctp_tmit_chunk *, uint32_t, uint32_t);
+sctp_send_deferred_reset_response(struct sctp_tcb *,
+ struct sctp_stream_reset_list *,
+ int);
void
sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *,
uint32_t, uint32_t, uint32_t, uint32_t);
+int
+sctp_send_stream_reset_out_if_possible(struct sctp_tcb *, int);
int
-sctp_send_str_reset_req(struct sctp_tcb *, uint16_t , uint16_t *, uint8_t,
+sctp_send_str_reset_req(struct sctp_tcb *, uint16_t , uint16_t *,
uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, uint8_t);
void
sctp_send_abort(struct mbuf *, int, struct sockaddr *, struct sockaddr *,
struct sctphdr *, uint32_t, struct mbuf *,
-#if defined(__FreeBSD__)
- uint8_t, uint32_t,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t, uint32_t, uint16_t,
#endif
uint32_t, uint16_t);
-void sctp_send_operr_to(struct sockaddr *, struct sockaddr *,
- struct sctphdr *, uint32_t, struct mbuf *,
-#if defined(__FreeBSD__)
- uint8_t, uint32_t,
+void
+sctp_send_operr_to(struct sockaddr *, struct sockaddr *,
+ struct sctphdr *, uint32_t, struct mbuf *,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t, uint32_t, uint16_t,
#endif
- uint32_t, uint16_t);
+ uint32_t, uint16_t);
#endif /* _KERNEL || __Userspace__ */
@@ -233,20 +216,15 @@ int
sctp_sosend(struct socket *so,
struct sockaddr *addr,
struct uio *uio,
-#ifdef __Panda__
- pakhandle_type top,
- pakhandle_type control,
-#else
struct mbuf *top,
struct mbuf *control,
-#endif
-#if defined(__APPLE__) || defined(__Panda__)
+#if defined(__APPLE__) && !defined(__Userspace__)
int flags
#else
int flags,
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct thread *p
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
PKTHREAD p
#else
#if defined(__Userspace__)
diff --git a/netwerk/sctp/src/netinet/sctp_pcb.c b/netwerk/sctp/src/netinet/sctp_pcb.c
index ea5725c85c..89a66bce87 100755
--- a/netwerk/sctp/src/netinet/sctp_pcb.c
+++ b/netwerk/sctp/src/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.
@@ -30,13 +32,13 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 355931 2019-12-20 15:25:08Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 366483 2020-10-06 11:29:08Z tuexen $");
#endif
#include <netinet/sctp_os.h>
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/proc.h>
#endif
#include <netinet/sctp_var.h>
@@ -49,11 +51,8 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 355931 2019-12-20 15:25:08Z tuex
#include <netinet/sctp_output.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_bsd_addr.h>
-#if defined(__FreeBSD__) && __FreeBSD_version >= 803000
-#include <netinet/sctp_dtrace_define.h>
-#endif
#if defined(INET) || defined(INET6)
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <netinet/udp.h>
#endif
#endif
@@ -64,32 +63,22 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 355931 2019-12-20 15:25:08Z tuex
#include <netinet6/ip6_var.h>
#endif
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/unistd.h>
#endif
#if defined(__Userspace__)
#include <user_socketvar.h>
-#if !defined(__Userspace_os_Windows)
+#include <user_atomic.h>
+#if !defined(_WIN32)
#include <netdb.h>
#endif
#endif
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 4
-#endif
-
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
-VNET_DEFINE(struct sctp_base_info, system_base_info);
-#else
+#if !defined(__FreeBSD__) || defined(__Userspace__)
struct sctp_base_info system_base_info;
-#endif
-#if defined(__Userspace__)
-#if defined(INET) || defined(INET6)
-struct ifaddrs *g_interfaces;
-#endif
#endif
/* FIX: we don't handle multiple link local scopes */
/* "scopeless" replacement IN6_ARE_ADDR_EQUAL */
@@ -98,7 +87,7 @@ int
SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
{
#ifdef SCTP_EMBEDDED_V6_SCOPE
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct in6_addr tmp_a, tmp_b;
tmp_a = a->sin6_addr;
@@ -261,7 +250,6 @@ sctp_allocate_vrf(int vrf_id)
return (vrf);
}
-
struct sctp_ifn *
sctp_find_ifn(void *ifn, uint32_t ifn_index)
{
@@ -271,6 +259,7 @@ sctp_find_ifn(void *ifn, uint32_t ifn_index)
/* We assume the lock is held for the addresses
* if that's wrong problems could occur :-)
*/
+ SCTP_IPI_ADDR_LOCK_ASSERT();
hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))];
LIST_FOREACH(sctp_ifnp, hash_ifn_head, next_bucket) {
if (sctp_ifnp->ifn_index == ifn_index) {
@@ -283,7 +272,6 @@ sctp_find_ifn(void *ifn, uint32_t ifn_index)
return (NULL);
}
-
struct sctp_vrf *
sctp_find_vrf(uint32_t vrf_id)
{
@@ -299,7 +287,6 @@ sctp_find_vrf(uint32_t vrf_id)
return (NULL);
}
-
void
sctp_free_vrf(struct sctp_vrf *vrf)
{
@@ -315,7 +302,6 @@ sctp_free_vrf(struct sctp_vrf *vrf)
}
}
-
void
sctp_free_ifn(struct sctp_ifn *sctp_ifnp)
{
@@ -329,7 +315,6 @@ sctp_free_ifn(struct sctp_ifn *sctp_ifnp)
}
}
-
void
sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu)
{
@@ -341,7 +326,6 @@ sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu)
}
}
-
void
sctp_free_ifa(struct sctp_ifa *sctp_ifap)
{
@@ -355,7 +339,6 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap)
}
}
-
static void
sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock)
{
@@ -366,19 +349,20 @@ sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock)
/* Not in the list.. sorry */
return;
}
- if (hold_addr_lock == 0)
+ if (hold_addr_lock == 0) {
SCTP_IPI_ADDR_WLOCK();
+ } else {
+ SCTP_IPI_ADDR_WLOCK_ASSERT();
+ }
LIST_REMOVE(sctp_ifnp, next_bucket);
LIST_REMOVE(sctp_ifnp, next_ifn);
- SCTP_DEREGISTER_INTERFACE(sctp_ifnp->ifn_index,
- sctp_ifnp->registered_af);
- if (hold_addr_lock == 0)
+ if (hold_addr_lock == 0) {
SCTP_IPI_ADDR_WUNLOCK();
+ }
/* Take away the reference, and possibly free it */
sctp_free_ifn(sctp_ifnp);
}
-
void
sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr,
const char *if_name, uint32_t ifn_index)
@@ -391,7 +375,6 @@ sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr,
if (vrf == NULL) {
SCTPDBG(SCTP_DEBUG_PCB4, "Can't find vrf_id 0x%x\n", vrf_id);
goto out;
-
}
sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED);
if (sctp_ifap == NULL) {
@@ -399,7 +382,7 @@ sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr,
goto out;
}
if (sctp_ifap->ifn_p == NULL) {
- SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unuseable\n");
+ SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n");
goto out;
}
if (if_name) {
@@ -422,7 +405,6 @@ sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr,
SCTP_IPI_ADDR_RUNLOCK();
}
-
void
sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr,
const char *if_name, uint32_t ifn_index)
@@ -435,7 +417,6 @@ sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr,
if (vrf == NULL) {
SCTPDBG(SCTP_DEBUG_PCB4, "Can't find vrf_id 0x%x\n", vrf_id);
goto out;
-
}
sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED);
if (sctp_ifap == NULL) {
@@ -443,7 +424,7 @@ sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr,
goto out;
}
if (sctp_ifap->ifn_p == NULL) {
- SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unuseable\n");
+ SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n");
goto out;
}
if (if_name) {
@@ -466,7 +447,6 @@ sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr,
SCTP_IPI_ADDR_RUNLOCK();
}
-
/*-
* Add an ifa to an ifn.
* Register the interface as necessary.
@@ -499,12 +479,10 @@ sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap)
}
if (sctp_ifnp->ifa_count == 1) {
/* register the new interface */
- SCTP_REGISTER_INTERFACE(sctp_ifnp->ifn_index, ifa_af);
sctp_ifnp->registered_af = ifa_af;
}
}
-
/*-
* Remove an ifa from its ifn.
* If no more addresses exist, remove the ifn too. Otherwise, re-register
@@ -540,13 +518,9 @@ sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap)
/* re-register address family type, if needed */
if ((sctp_ifap->ifn_p->num_v6 == 0) &&
(sctp_ifap->ifn_p->registered_af == AF_INET6)) {
- SCTP_DEREGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET6);
- SCTP_REGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET);
sctp_ifap->ifn_p->registered_af = AF_INET;
} else if ((sctp_ifap->ifn_p->num_v4 == 0) &&
(sctp_ifap->ifn_p->registered_af == AF_INET)) {
- SCTP_DEREGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET);
- SCTP_REGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET6);
sctp_ifap->ifn_p->registered_af = AF_INET6;
}
/* free the ifn refcount */
@@ -556,7 +530,6 @@ sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap)
}
}
-
struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
uint32_t ifn_type, const char *if_name, void *ifa,
@@ -564,8 +537,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
int dynamic_add)
{
struct sctp_vrf *vrf;
- struct sctp_ifn *sctp_ifnp = NULL;
- struct sctp_ifa *sctp_ifap = NULL;
+ struct sctp_ifn *sctp_ifnp, *new_sctp_ifnp;
+ struct sctp_ifa *sctp_ifap, *new_sctp_ifap;
struct sctp_ifalist *hash_addr_head;
struct sctp_ifnlist *hash_ifn_head;
uint32_t hash_of_addr;
@@ -575,6 +548,23 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: adding address: ", vrf_id);
SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr);
#endif
+ SCTP_MALLOC(new_sctp_ifnp, struct sctp_ifn *,
+ sizeof(struct sctp_ifn), SCTP_M_IFN);
+ if (new_sctp_ifnp == NULL) {
+#ifdef INVARIANTS
+ panic("No memory for IFN");
+#endif
+ return (NULL);
+ }
+ SCTP_MALLOC(new_sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA);
+ if (new_sctp_ifap == NULL) {
+#ifdef INVARIANTS
+ panic("No memory for IFA");
+#endif
+ SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
+ return (NULL);
+ }
+
SCTP_IPI_ADDR_WLOCK();
sctp_ifnp = sctp_find_ifn(ifn, ifn_index);
if (sctp_ifnp) {
@@ -585,6 +575,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
vrf = sctp_allocate_vrf(vrf_id);
if (vrf == NULL) {
SCTP_IPI_ADDR_WUNLOCK();
+ SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
+ SCTP_FREE(new_sctp_ifap, SCTP_M_IFA);
return (NULL);
}
}
@@ -593,15 +585,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
/* build one and add it, can't hold lock
* until after malloc done though.
*/
- SCTP_IPI_ADDR_WUNLOCK();
- SCTP_MALLOC(sctp_ifnp, struct sctp_ifn *,
- sizeof(struct sctp_ifn), SCTP_M_IFN);
- if (sctp_ifnp == NULL) {
-#ifdef INVARIANTS
- panic("No memory for IFN");
-#endif
- return (NULL);
- }
+ sctp_ifnp = new_sctp_ifnp;
+ new_sctp_ifnp = NULL;
memset(sctp_ifnp, 0, sizeof(struct sctp_ifn));
sctp_ifnp->ifn_index = ifn_index;
sctp_ifnp->ifn_p = ifn;
@@ -611,13 +596,12 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
atomic_add_int(&vrf->refcount, 1);
sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index, addr->sa_family);
if (if_name != NULL) {
- snprintf(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", if_name);
+ SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", if_name);
} else {
- snprintf(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", "unknown");
+ SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", "unknown");
}
hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))];
LIST_INIT(&sctp_ifnp->ifalist);
- SCTP_IPI_ADDR_WLOCK();
LIST_INSERT_HEAD(hash_ifn_head, sctp_ifnp, next_bucket);
LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn);
atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifns), 1);
@@ -644,6 +628,10 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
}
exit_stage_left:
SCTP_IPI_ADDR_WUNLOCK();
+ if (new_sctp_ifnp != NULL) {
+ SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
+ }
+ SCTP_FREE(new_sctp_ifap, SCTP_M_IFA);
return (sctp_ifap);
} else {
if (sctp_ifap->ifn_p) {
@@ -670,14 +658,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
goto exit_stage_left;
}
}
- SCTP_IPI_ADDR_WUNLOCK();
- SCTP_MALLOC(sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA);
- if (sctp_ifap == NULL) {
-#ifdef INVARIANTS
- panic("No memory for IFA");
-#endif
- return (NULL);
- }
+ sctp_ifap = new_sctp_ifap;
memset(sctp_ifap, 0, sizeof(struct sctp_ifa));
sctp_ifap->ifn_p = sctp_ifnp;
atomic_add_int(&sctp_ifnp->refcount, 1);
@@ -766,7 +747,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
(sctp_ifap->src_is_loop == 0)) {
sctp_ifap->src_is_glob = 1;
}
- SCTP_IPI_ADDR_WLOCK();
hash_addr_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
LIST_INSERT_HEAD(hash_addr_head, sctp_ifap, next_bucket);
sctp_ifap->refcount = 1;
@@ -775,10 +755,13 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
vrf->total_ifa_count++;
atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifas), 1);
if (new_ifn_af) {
- SCTP_REGISTER_INTERFACE(ifn_index, new_ifn_af);
sctp_ifnp->registered_af = new_ifn_af;
}
SCTP_IPI_ADDR_WUNLOCK();
+ if (new_sctp_ifnp != NULL) {
+ SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
+ }
+
if (dynamic_add) {
/* Bump up the refcount so that when the timer
* completes it will drop back down.
@@ -799,19 +782,18 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
return (NULL);
}
SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
+ memset(wi, 0, sizeof(*wi));
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
wi->ifa = sctp_ifap;
wi->action = SCTP_ADD_IP_ADDRESS;
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;
@@ -844,8 +826,7 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
int valid = 0;
/*-
* The name has priority over the ifn_index
- * if its given. We do this especially for
- * panda who might recycle indexes fast.
+ * if its given.
*/
if (if_name) {
if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) == 0) {
@@ -870,7 +851,7 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
}
SCTPDBG(SCTP_DEBUG_PCB4, "Deleting ifa %p\n", (void *)sctp_ifap);
sctp_ifap->localifa_flags &= SCTP_ADDR_VALID;
- /*
+ /*
* We don't set the flag. This means that the structure will
* hang around in EP's that have bound specific to it until
* they close. This gives us TCP like behavior if someone
@@ -907,7 +888,7 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
return;
}
SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
+ memset(wi, 0, sizeof(*wi));
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
wi->ifa = sctp_ifap;
wi->action = SCTP_DEL_IP_ADDRESS;
@@ -917,17 +898,15 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
* 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;
}
-
static int
sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
{
@@ -997,7 +976,7 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -1019,7 +998,7 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
#endif
sin6 = &sctp_ifa->address.sin6;
rsin6 = (struct sockaddr_in6 *)to;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -1142,14 +1121,12 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
/* TSNH */
break;
}
-
}
}
SCTP_IPI_ADDR_RUNLOCK();
return (0);
}
-
static struct sctp_tcb *
sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id)
@@ -1224,7 +1201,7 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
SCTP_INP_RUNLOCK(inp);
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
switch (to->sa_family) {
#ifdef INET
case AF_INET:
@@ -1283,9 +1260,8 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
int match = 0;
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
-
if (laddr->ifa == NULL) {
- SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n", __FUNCTION__);
+ SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n", __func__);
continue;
}
if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
@@ -1379,7 +1355,6 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
}
/* Does this TCB have a matching address? */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
-
if (net->ro._l_addr.sa.sa_family != from->sa_family) {
/* not the same family, can't be a match */
continue;
@@ -1458,7 +1433,6 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
return (NULL);
}
-
/*
* rules for use
*
@@ -1492,7 +1466,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
#endif
#if defined(__Userspace__)
case AF_CONN:
- rport = (((struct sockaddr_in6 *)remote)->sin6_port);
+ rport = (((struct sockaddr_conn *)remote)->sconn_port);
break;
#endif
default:
@@ -1516,7 +1490,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
* it is the acceptor, then do the special_lookup to hash
* and find the real inp.
*/
- if ((inp->sctp_socket) && (inp->sctp_socket->so_qlimit)) {
+ if ((inp->sctp_socket) && SCTP_IS_LISTENING(inp)) {
/* to is peer addr, from is my addr */
#ifndef SCTP_MVRF
stcb = sctp_tcb_special_locate(inp_p, remote, local,
@@ -1825,7 +1799,6 @@ null_return:
return (NULL);
}
-
/*
* Find an association for a specific endpoint using the association id given
* out in the COMM_UP notification
@@ -1877,7 +1850,6 @@ sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int
return (NULL);
}
-
struct sctp_tcb *
sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock)
{
@@ -1889,7 +1861,6 @@ sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int
return (stcb);
}
-
/*
* Endpoint probe expects that the INP_INFO is locked.
*/
@@ -1965,7 +1936,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
SCTP_INP_RUNLOCK(inp);
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
SCTP_INP_RUNLOCK(inp);
@@ -1981,7 +1952,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
SCTP_INP_RUNLOCK(inp);
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
SCTP_INP_RUNLOCK(inp);
@@ -2084,7 +2055,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
continue;
}
SCTPDBG(SCTP_DEBUG_PCB1, "Ok laddr->ifa:%p is possible, ",
@@ -2098,7 +2069,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
switch (nam->sa_family) {
#ifdef INET
case AF_INET:
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (sin == NULL) {
/* TSNH */
break;
@@ -2137,7 +2108,6 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
return (NULL);
}
-
static struct sctp_inpcb *
sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id)
{
@@ -2198,7 +2168,6 @@ sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id)
return (NULL);
}
-
int
sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp)
{
@@ -2228,7 +2197,7 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp)
if (tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
continue;
}
- if (tinp->sctp_socket->so_qlimit) {
+ if (SCTP_IS_LISTENING(tinp)) {
continue;
}
SCTP_INP_WLOCK(tinp);
@@ -2250,7 +2219,6 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp)
return (0);
}
-
struct sctp_inpcb *
sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock,
uint32_t vrf_id)
@@ -2336,7 +2304,6 @@ sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock,
return (inp);
}
-
/*
* Find an association for an endpoint with the pointer to whom you want to
* send to and the endpoint pointer. The address can be IPv4 or IPv6. We may
@@ -2388,7 +2355,6 @@ sctp_findassociation_addr_sa(struct sockaddr *from, struct sockaddr *to,
return (stcb);
}
-
/*
* This routine will grub through the mbuf that is a INIT or INIT-ACK and
* find all addresses that the sender has specified in any address list. Each
@@ -2399,7 +2365,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp,
struct sockaddr *dst)
{
- struct sctp_paramhdr *phdr, parm_buf;
+ struct sctp_paramhdr *phdr, param_buf;
#if defined(INET) || defined(INET6)
struct sctp_tcb *stcb;
uint16_t ptype;
@@ -2431,7 +2397,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
offset += sizeof(struct sctp_init_chunk);
- phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf, sizeof(param_buf));
while (phdr != NULL) {
/* now we must see if we want the parameter */
#if defined(INET) || defined(INET6)
@@ -2445,10 +2411,10 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
if (ptype == SCTP_IPV4_ADDRESS &&
plen == sizeof(struct sctp_ipv4addr_param)) {
/* Get the rest of the address */
- struct sctp_ipv4addr_param ip4_parm, *p4;
+ struct sctp_ipv4addr_param ip4_param, *p4;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&ip4_parm, min(plen, sizeof(ip4_parm)));
+ (struct sctp_paramhdr *)&ip4_param, sizeof(ip4_param));
if (phdr == NULL) {
return (NULL);
}
@@ -2466,10 +2432,10 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
if (ptype == SCTP_IPV6_ADDRESS &&
plen == sizeof(struct sctp_ipv6addr_param)) {
/* Get the rest of the address */
- struct sctp_ipv6addr_param ip6_parm, *p6;
+ struct sctp_ipv6addr_param ip6_param, *p6;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&ip6_parm, min(plen,sizeof(ip6_parm)));
+ (struct sctp_paramhdr *)&ip6_param, sizeof(ip6_param));
if (phdr == NULL) {
return (NULL);
}
@@ -2484,8 +2450,8 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
}
#endif
offset += SCTP_SIZE32(plen);
- phdr = sctp_get_next_param(m, offset, &parm_buf,
- sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf,
+ sizeof(param_buf));
}
return (NULL);
}
@@ -2597,7 +2563,6 @@ sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag
return (NULL);
}
-
/*
* Find an association with the pointer to the inbound IP packet. This can be
* a IPv4 or IPv6 packet.
@@ -2608,7 +2573,6 @@ sctp_findassociation_addr(struct mbuf *m, int offset,
struct sctphdr *sh, struct sctp_chunkhdr *ch,
struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id)
{
- int find_tcp_pool;
struct sctp_tcb *stcb;
struct sctp_inpcb *inp;
@@ -2621,21 +2585,13 @@ sctp_findassociation_addr(struct mbuf *m, int offset,
}
}
- find_tcp_pool = 0;
- if ((ch->chunk_type != SCTP_INITIATION) &&
- (ch->chunk_type != SCTP_INITIATION_ACK) &&
- (ch->chunk_type != SCTP_COOKIE_ACK) &&
- (ch->chunk_type != SCTP_COOKIE_ECHO)) {
- /* Other chunk types go to the tcp pool. */
- find_tcp_pool = 1;
- }
if (inp_p) {
stcb = sctp_findassociation_addr_sa(src, dst, inp_p, netp,
- find_tcp_pool, vrf_id);
+ 1, vrf_id);
inp = *inp_p;
} else {
stcb = sctp_findassociation_addr_sa(src, dst, &inp, netp,
- find_tcp_pool, vrf_id);
+ 1, vrf_id);
}
SCTPDBG(SCTP_DEBUG_PCB1, "stcb:%p inp:%p\n", (void *)stcb, (void *)inp);
if (stcb == NULL && inp) {
@@ -2678,7 +2634,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
{
struct sctp_tcb *stcb;
union sctp_sockstore remote_store;
- struct sctp_paramhdr parm_buf, *phdr;
+ struct sctp_paramhdr param_buf, *phdr;
int ptype;
int zero_address = 0;
#ifdef INET
@@ -2690,10 +2646,10 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
memset(&remote_store, 0, sizeof(remote_store));
phdr = sctp_get_next_param(m, offset + sizeof(struct sctp_asconf_chunk),
- &parm_buf, sizeof(struct sctp_paramhdr));
+ &param_buf, sizeof(struct sctp_paramhdr));
if (phdr == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf lookup addr\n",
- __FUNCTION__);
+ __func__);
return NULL;
}
ptype = (int)((uint32_t) ntohs(phdr->param_type));
@@ -2710,10 +2666,10 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
}
p6 = (struct sctp_ipv6addr_param *)sctp_get_next_param(m,
offset + sizeof(struct sctp_asconf_chunk),
- &p6_buf.ph, sizeof(*p6));
+ &p6_buf.ph, sizeof(p6_buf));
if (p6 == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf v6 lookup addr\n",
- __FUNCTION__);
+ __func__);
return (NULL);
}
sin6 = &remote_store.sin6;
@@ -2739,10 +2695,10 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
}
p4 = (struct sctp_ipv4addr_param *)sctp_get_next_param(m,
offset + sizeof(struct sctp_asconf_chunk),
- &p4_buf.ph, sizeof(*p4));
+ &p4_buf.ph, sizeof(p4_buf));
if (p4 == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf v4 lookup addr\n",
- __FUNCTION__);
+ __func__);
return (NULL);
}
sin = &remote_store.sin;
@@ -2776,7 +2732,6 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
return (stcb);
}
-
/*
* allocate a sctp_inpcb and setup a temporary binding to a port/all
* addresses. This way if we don't get a bind we by default pick a ephemeral
@@ -2810,20 +2765,20 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
return (ENOBUFS);
}
/* zap it */
- bzero(inp, sizeof(*inp));
+ memset(inp, 0, sizeof(*inp));
/* bump generations */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
inp->ip_inp.inp.inp_state = INPCB_STATE_INUSE;
#endif
/* setup socket pointers */
inp->sctp_socket = so;
inp->ip_inp.inp.inp_socket = so;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
inp->ip_inp.inp.inp_cred = crhold(so->so_cred);
#endif
#ifdef INET6
-#if !defined(__Userspace__) && !defined(__Windows__)
+#if !defined(__Userspace__) && !defined(_WIN32)
if (INP_SOCKAF(so) == AF_INET6) {
if (MODULE_GLOBAL(ip6_auto_flowlabel)) {
inp->ip_inp.inp.inp_flags |= IN6P_AUTOFLOWLABEL;
@@ -2846,6 +2801,13 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
inp->reconfig_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_reconfig_enable);
inp->nrsack_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_nrsack_enable);
inp->pktdrop_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_pktdrop_enable);
+ inp->idata_supported = 0;
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ inp->fibnum = so->so_fibnum;
+#else
+ inp->fibnum = 0;
+#endif
#if defined(__Userspace__)
inp->ulp_info = NULL;
inp->recv_callback = NULL;
@@ -2855,48 +2817,20 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
/* init the small hash table we use to track asocid <-> tcb */
inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark);
if (inp->sctp_asocidhash == NULL) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
crfree(inp->ip_inp.inp.inp_cred);
#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_INP_INFO_WUNLOCK();
return (ENOBUFS);
}
-#ifdef IPSEC
-#if !(defined(__APPLE__))
- {
- struct inpcbpolicy *pcb_sp = NULL;
-
- error = ipsec_init_policy(so, &pcb_sp);
- /* Arrange to share the policy */
- inp->ip_inp.inp.inp_sp = pcb_sp;
- ((struct in6pcb *)(&inp->ip_inp.inp))->in6p_sp = pcb_sp;
- }
-#else
- /* not sure what to do for openbsd here */
- error = 0;
-#endif
- if (error != 0) {
-#if defined(__FreeBSD__)
- crfree(inp->ip_inp.inp.inp_cred);
-#endif
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
- SCTP_INP_INFO_WUNLOCK();
- return error;
- }
-#endif /* IPSEC */
SCTP_INCR_EP_COUNT();
inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
SCTP_INP_INFO_WUNLOCK();
so->so_pcb = (caddr_t)inp;
-#if defined(__FreeBSD__) && __FreeBSD_version < 803000
- if ((SCTP_SO_TYPE(so) == SOCK_DGRAM) ||
- (SCTP_SO_TYPE(so) == SOCK_SEQPACKET)) {
-#else
if (SCTP_SO_TYPE(so) == SOCK_SEQPACKET) {
-#endif
/* UDP style socket */
inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
SCTP_PCB_FLAGS_UNBOUND);
@@ -2907,17 +2841,9 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
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);
-#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
+ SOCK_UNLOCK(so);
} else {
/*
* unsupported socket type (RAW, etc)- in case we missed it
@@ -2925,7 +2851,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP);
so->so_pcb = NULL;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
crfree(inp->ip_inp.inp.inp_cred);
#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
@@ -2947,7 +2873,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n");
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
so->so_pcb = NULL;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
crfree(inp->ip_inp.inp.inp_cred);
#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
@@ -2961,7 +2887,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
so->so_pcb = NULL;
SCTP_HASH_FREE(inp->sctp_tcbhash, inp->sctp_hashmark);
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
crfree(inp->ip_inp.inp.inp_cred);
#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
@@ -2972,7 +2898,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
#endif
inp->def_vrf_id = vrf_id;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
inp->ip_inp.inp.inpcb_mtx = lck_mtx_alloc_init(SCTP_BASE_INFO(sctbinfo).mtx_grp, SCTP_BASE_INFO(sctbinfo).mtx_attr);
if (inp->ip_inp.inp.inpcb_mtx == NULL) {
@@ -2982,9 +2908,6 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
#endif
SCTP_HASH_FREE(inp->sctp_tcbhash, inp->sctp_hashmark);
so->so_pcb = NULL;
-#if defined(__FreeBSD__)
- crfree(inp->ip_inp.inp.inp_cred);
-#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_UNLOCK_EXC(SCTP_BASE_INFO(sctbinfo).ipi_lock);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM);
@@ -2998,7 +2921,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
#endif
SCTP_INP_INFO_WLOCK();
SCTP_INP_LOCK_INIT(inp);
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
INP_LOCK_INIT(&inp->ip_inp.inp, "inp", "sctpinp");
#endif
SCTP_INP_READ_INIT(inp);
@@ -3008,7 +2931,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
/* add it to the info area */
LIST_INSERT_HEAD(&SCTP_BASE_INFO(listhead), inp, sctp_list);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
inp->ip_inp.inp.inp_pcbinfo = &SCTP_BASE_INFO(sctbinfo);
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION)
LIST_INSERT_HEAD(SCTP_BASE_INFO(sctbinfo).listhead, &inp->ip_inp.inp, inp_list);
@@ -3035,13 +2958,13 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
m = &inp->sctp_ep;
/* setup the base timeout information */
- m->sctp_timeoutticks[SCTP_TIMER_SEND] = SEC_TO_TICKS(SCTP_SEND_SEC); /* needed ? */
- m->sctp_timeoutticks[SCTP_TIMER_INIT] = SEC_TO_TICKS(SCTP_INIT_SEC); /* needed ? */
- m->sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default));
- m->sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default));
- m->sctp_timeoutticks[SCTP_TIMER_PMTU] = SEC_TO_TICKS(SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default));
- m->sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] = SEC_TO_TICKS(SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default));
- m->sctp_timeoutticks[SCTP_TIMER_SIGNATURE] = SEC_TO_TICKS(SCTP_BASE_SYSCTL(sctp_secret_lifetime_default));
+ m->sctp_timeoutticks[SCTP_TIMER_SEND] = sctp_secs_to_ticks(SCTP_SEND_SEC); /* needed ? */
+ m->sctp_timeoutticks[SCTP_TIMER_INIT] = sctp_secs_to_ticks(SCTP_INIT_SEC); /* needed ? */
+ m->sctp_timeoutticks[SCTP_TIMER_RECV] = sctp_msecs_to_ticks(SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default));
+ m->sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default));
+ m->sctp_timeoutticks[SCTP_TIMER_PMTU] = sctp_secs_to_ticks(SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default));
+ m->sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] = sctp_secs_to_ticks(SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default));
+ m->sctp_timeoutticks[SCTP_TIMER_SIGNATURE] = sctp_secs_to_ticks(SCTP_BASE_SYSCTL(sctp_secret_lifetime_default));
/* all max/min max are in ms */
m->sctp_maxrto = SCTP_BASE_SYSCTL(sctp_rto_max_default);
m->sctp_minrto = SCTP_BASE_SYSCTL(sctp_rto_min_default);
@@ -3063,6 +2986,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
/* 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;
@@ -3088,7 +3012,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL);
/* How long is a cookie good for ? */
- m->def_cookie_life = MSEC_TO_TICKS(SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default));
+ m->def_cookie_life = sctp_msecs_to_ticks(SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default));
/*
* Initialize authentication parameters
*/
@@ -3114,7 +3038,6 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
return (error);
}
-
void
sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
struct sctp_tcb *stcb)
@@ -3200,7 +3123,7 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
continue;
}
SCTP_INCR_LADDR_COUNT();
- bzero(laddr, sizeof(*laddr));
+ memset(laddr, 0, sizeof(*laddr));
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
laddr->ifa = oladdr->ifa;
atomic_add_int(&laddr->ifa->refcount, 1);
@@ -3212,31 +3135,100 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
}
}
}
- /* Now any running timers need to be adjusted
- * since we really don't care if they are running
- * or not just blast in the new_inp into all of
- * them.
- */
-
- stcb->asoc.dack_timer.ep = (void *)new_inp;
- stcb->asoc.asconf_timer.ep = (void *)new_inp;
- stcb->asoc.strreset_timer.ep = (void *)new_inp;
- stcb->asoc.shut_guard_timer.ep = (void *)new_inp;
- stcb->asoc.autoclose_timer.ep = (void *)new_inp;
- stcb->asoc.delayed_event_timer.ep = (void *)new_inp;
- stcb->asoc.delete_prim_timer.ep = (void *)new_inp;
+ /* Now any running timers need to be adjusted. */
+ if (stcb->asoc.dack_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ stcb->asoc.dack_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (stcb->asoc.asconf_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ stcb->asoc.asconf_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (stcb->asoc.strreset_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ stcb->asoc.strreset_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (stcb->asoc.shut_guard_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ stcb->asoc.shut_guard_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (stcb->asoc.autoclose_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ stcb->asoc.autoclose_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (stcb->asoc.delete_prim_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ stcb->asoc.delete_prim_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
/* now what about the nets? */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- net->pmtu_timer.ep = (void *)new_inp;
- net->hb_timer.ep = (void *)new_inp;
- net->rxt_timer.ep = (void *)new_inp;
+ if (net->pmtu_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ net->pmtu_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (net->hb_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ net->hb_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
+ if (net->rxt_timer.ep == old_inp) {
+ SCTP_INP_DECR_REF(old_inp);
+ net->rxt_timer.ep = new_inp;
+ SCTP_INP_INCR_REF(new_inp);
+ }
}
SCTP_INP_WUNLOCK(new_inp);
SCTP_INP_WUNLOCK(old_inp);
}
+/*
+ * insert an laddr entry with the given ifa for the desired list
+ */
+static int
+sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
+{
+ struct sctp_laddr *laddr;
+ laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
+ if (laddr == NULL) {
+ /* out of memory? */
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
+ return (EINVAL);
+ }
+ SCTP_INCR_LADDR_COUNT();
+ memset(laddr, 0, sizeof(*laddr));
+ (void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
+ laddr->ifa = ifa;
+ laddr->action = act;
+ atomic_add_int(&ifa->refcount, 1);
+ /* insert it */
+ LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr);
+
+ return (0);
+}
+
+/*
+ * Remove an laddr entry from the local address list (on an assoc)
+ */
+static void
+sctp_remove_laddr(struct sctp_laddr *laddr)
+{
+
+ /* remove from the list */
+ LIST_REMOVE(laddr, sctp_nxt_addr);
+ sctp_free_ifa(laddr->ifa);
+ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr);
+ SCTP_DECR_LADDR_COUNT();
+}
#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__))
+
/*
* Don't know why, but without this there is an unknown reference when
* compiling NetBSD... hmm
@@ -3244,13 +3236,12 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *sin6);
#endif
-
/* sctp_ifap is used to bypass normal local address validation checks */
int
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
struct sctp_ifa *sctp_ifap, struct thread *p)
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
struct sctp_ifa *sctp_ifap, PKTHREAD p)
#else
@@ -3261,7 +3252,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
/* bind a ep to a socket address */
struct sctppcbhead *head;
struct sctp_inpcb *inp, *inp_tmp;
-#if defined(INET) || (defined(INET6) && defined(__APPLE__)) || defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
struct inpcb *ip_inp;
#endif
int port_reuse_active = 0;
@@ -3276,7 +3267,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
lport = 0;
bindall = 1;
inp = (struct sctp_inpcb *)so->so_pcb;
-#if defined(INET) || (defined(INET6) && defined(__APPLE__)) || defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
ip_inp = (struct inpcb *)so->so_pcb;
#endif
#ifdef SCTP_DEBUG
@@ -3292,7 +3283,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INVARIANTS
if (p == NULL)
panic("null proc/thread");
@@ -3306,7 +3297,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
struct sockaddr_in *sin;
/* IPV6_V6ONLY socket? */
- if (SCTP_IPV6_V6ONLY(ip_inp)) {
+ if (SCTP_IPV6_V6ONLY(inp)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
@@ -3319,7 +3310,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
sin = (struct sockaddr_in *)addr;
lport = sin->sin_port;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/*
* For LOOPBACK the prison_local_ip4() call will transmute the ip address
* to the proper value.
@@ -3350,7 +3341,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
}
#endif
lport = sin6->sin6_port;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/*
* For LOOPBACK the prison_local_ip6() call will transmute the ipv6 address
* to the proper value.
@@ -3370,7 +3361,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
if (in6_embedscope(&sin6->sin6_addr, sin6, ip_inp, NULL) != 0) {
#else
@@ -3379,7 +3370,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) && !defined(__Userspace__)
error = scope6_check_id(sin6, MODULE_GLOBAL(ip6_use_defzone));
if (error != 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error);
@@ -3437,41 +3428,26 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
* already has this one bound.
*/
/* got to be root to get at low ports */
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
if (ntohs(lport) < IPPORT_RESERVED) {
- if (p && (error =
-#ifdef __FreeBSD__
-#if __FreeBSD_version > 602000
+ if ((p != NULL) && ((error =
+#if defined(__FreeBSD__) && !defined(__Userspace__)
priv_check(p, PRIV_NETINET_RESERVEDPORT)
-#elif __FreeBSD_version >= 500000
- suser_cred(p->td_ucred, 0)
-#else
- suser(p)
-#endif
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
suser(p->p_ucred, &p->p_acflag)
#elif defined(__Userspace__) /* must be true to use raw socket */
1
#else
suser(p, 0)
#endif
- )) {
+ ) != 0)) {
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
return (error);
}
-#if defined(__Panda__)
- if (!SCTP_IS_PRIVILEDGED(so)) {
- SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
- SCTP_INP_INFO_WUNLOCK();
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EACCES);
- return (EACCES);
- }
-#endif
}
-#endif /* __Windows__ */
+#endif
SCTP_INP_WUNLOCK(inp);
if (bindall) {
#ifdef SCTP_MVRF
@@ -3554,26 +3530,20 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
uint16_t count;
int done;
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
first = 1;
last = 0xffff;
#else
#if defined(__Userspace__)
/* TODO ensure uid is 0, etc... */
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
if (ip_inp->inp_flags & INP_HIGHPORT) {
first = MODULE_GLOBAL(ipport_hifirstauto);
last = MODULE_GLOBAL(ipport_hilastauto);
} else if (ip_inp->inp_flags & INP_LOWPORT) {
if (p && (error =
-#ifdef __FreeBSD__
-#if __FreeBSD_version > 602000
+#if defined(__FreeBSD__)
priv_check(p, PRIV_NETINET_RESERVEDPORT)
-#elif __FreeBSD_version >= 500000
- suser_cred(p->td_ucred, 0)
-#else
- suser(p)
-#endif
#elif defined(__APPLE__)
suser(p->p_ucred, &p->p_acflag)
#else
@@ -3592,10 +3562,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
#endif
first = MODULE_GLOBAL(ipport_firstauto);
last = MODULE_GLOBAL(ipport_lastauto);
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
}
#endif
-#endif /* __Windows__ */
+#endif
if (first > last) {
uint16_t temp;
@@ -3734,7 +3704,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
} else {
/* Note for BSD we hit here always other
* O/S's will pass things in via the
- * sctp_ifap argument (Panda).
+ * sctp_ifap argument.
*/
ifa = sctp_find_ifa_by_addr(&store.sa,
vrf_id, SCTP_ADDR_NOT_LOCKED);
@@ -3796,7 +3766,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
return (0);
}
-
static void
sctp_iterator_inp_being_freed(struct sctp_inpcb *inp)
{
@@ -3807,7 +3776,7 @@ sctp_iterator_inp_being_freed(struct sctp_inpcb *inp)
* lock on the inp_info stuff.
*/
it = sctp_it_ctl.cur_it;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (it && (it->vn != curvnet)) {
/* Its not looking at our VNET */
return;
@@ -3838,7 +3807,7 @@ sctp_iterator_inp_being_freed(struct sctp_inpcb *inp)
*/
SCTP_IPI_ITERATOR_WQ_LOCK();
TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (it->vn != curvnet) {
continue;
}
@@ -3884,16 +3853,15 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
struct socket *so;
int being_refed = 0;
struct sctp_queued_to_read *sq, *nsq;
-#if !defined(__Panda__) && !defined(__Userspace__)
-#if !defined(__FreeBSD__) || __FreeBSD_version < 500000
+#if !defined(__Userspace__)
+#if !defined(__FreeBSD__)
sctp_rtentry_t *rt;
#endif
#endif
int cnt;
sctp_sharedkey_t *shared_key, *nshared_key;
-
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sctp_lock_assert(SCTP_INP_SO(inp));
#endif
#ifdef SCTP_LOG_CLOSING
@@ -3922,11 +3890,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
inp->sctp_flags |= SCTP_PCB_FLAGS_DONT_WAKE;
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
-
}
/* First time through we have the socket lock, after that no more. */
sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL,
- SCTP_FROM_SCTP_PCB+SCTP_LOC_1);
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_1);
if (inp->control) {
sctp_m_freem(inp->control);
@@ -3954,14 +3921,14 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* timer on the asoc due to it was not
* closed. So go ahead and start it now.
*/
- asoc->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
+ SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_IN_ACCEPT_QUEUE);
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, asoc, NULL);
}
SCTP_TCB_UNLOCK(asoc);
continue;
}
- if (((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_ECHOED)) &&
+ if (((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) &&
(asoc->asoc.total_output_queue_size == 0)) {
/* If we have data in queue, we don't want to just
* free since the app may have done, send()/close
@@ -3970,14 +3937,14 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
*/
/* Just abandon things in the front states */
if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE,
- SCTP_FROM_SCTP_PCB+SCTP_LOC_2) == 0) {
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) {
cnt_in_sd++;
}
continue;
}
/* Disconnect the socket please */
asoc->sctp_socket = NULL;
- asoc->asoc.state |= SCTP_STATE_CLOSED_SOCKET;
+ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_CLOSED_SOCKET);
if ((asoc->asoc.size_on_reasm_queue > 0) ||
(asoc->asoc.control_pdapi) ||
(asoc->asoc.size_on_all_streams > 0) ||
@@ -3986,38 +3953,37 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
struct mbuf *op_err;
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB+SCTP_LOC_3;
+ asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3;
sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
if (sctp_free_assoc(inp, asoc,
- SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB+SCTP_LOC_4) == 0) {
+ SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_4) == 0) {
cnt_in_sd++;
}
continue;
} else if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
TAILQ_EMPTY(&asoc->asoc.sent_queue) &&
(asoc->asoc.stream_queue_cnt == 0)) {
- if (asoc->asoc.locked_on_sending) {
+ if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(asoc, &asoc->asoc)) {
goto abort_anyway;
}
- if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
struct sctp_nets *netp;
/*
* there is nothing queued to send,
* so I send shutdown
*/
- if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(asoc);
if (asoc->asoc.alternate) {
netp = asoc->asoc.alternate;
@@ -4027,28 +3993,15 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
sctp_send_shutdown(asoc, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc,
netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
- asoc->asoc.primary_destination);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, NULL);
sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED);
}
} else {
/* mark into shutdown pending */
- struct sctp_stream_queue_pending *sp;
-
- asoc->asoc.state |= SCTP_STATE_SHUTDOWN_PENDING;
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
- asoc->asoc.primary_destination);
- if (asoc->asoc.locked_on_sending) {
- sp = TAILQ_LAST(&((asoc->asoc.locked_on_sending)->outqueue),
- sctp_streamhead);
- if (sp == NULL) {
- SCTP_PRINTF("Error, sp is NULL, locked on sending is %p strm:%d\n",
- (void *)asoc->asoc.locked_on_sending,
- asoc->asoc.locked_on_sending->stream_no);
- } else {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, NULL);
+ if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(asoc, &asoc->asoc)) {
+ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT);
}
if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
TAILQ_EMPTY(&asoc->asoc.sent_queue) &&
@@ -4056,16 +4009,16 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
struct mbuf *op_err;
abort_anyway:
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB+SCTP_LOC_5;
+ asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5;
sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
if (sctp_free_assoc(inp, asoc,
SCTP_PCBFREE_NOFORCE,
- SCTP_FROM_SCTP_PCB+SCTP_LOC_6) == 0) {
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_6) == 0) {
cnt_in_sd++;
}
continue;
@@ -4108,22 +4061,27 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
cnt = 0;
LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_list, sctp_tcblist, nasoc) {
SCTP_TCB_LOCK(asoc);
+ if (immediate != SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE) {
+ /* Disconnect the socket please */
+ asoc->sctp_socket = NULL;
+ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_CLOSED_SOCKET);
+ }
if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
if (asoc->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) {
- asoc->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
+ SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_IN_ACCEPT_QUEUE);
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, asoc, NULL);
}
- cnt++;
+ cnt++;
SCTP_TCB_UNLOCK(asoc);
continue;
}
/* Free associations that are NOT killing us */
- if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_COOKIE_WAIT) &&
+ if ((SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) &&
((asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) {
struct mbuf *op_err;
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB+SCTP_LOC_7;
+ asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_7;
sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
} else if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
@@ -4131,17 +4089,17 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_TCB_UNLOCK(asoc);
continue;
}
- if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB+SCTP_LOC_8) == 0) {
+ if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) {
cnt++;
}
}
if (cnt) {
/* Ok we have someone out there that will kill us */
- (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer);
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 3);
#endif
@@ -4156,11 +4114,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
being_refed++;
if (SCTP_ASOC_CREATE_LOCK_CONTENDED(inp))
being_refed++;
-
+ /* NOTE: 0 refcount also means no timers are referencing us. */
if ((inp->refcount) ||
(being_refed) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP)) {
- (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer);
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 4);
#endif
@@ -4179,42 +4136,15 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_INP_WUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
- /* Now we release all locks. Since this INP
- * cannot be found anymore except possibly by the
- * kill timer that might be running. We call
- * the drain function here. It should hit the case
- * were it sees the ACTIVE flag cleared and exit
- * out freeing us to proceed and destroy everything.
- */
- if (from != SCTP_CALLED_FROM_INPKILL_TIMER) {
- (void)SCTP_OS_TIMER_STOP_DRAIN(&inp->sctp_ep.signature_change.timer);
- } else {
- /* Probably un-needed */
- (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer);
- }
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 5);
#endif
-
-#if !(defined(__Panda__) || defined(__Windows__) || defined(__Userspace__))
-#if !defined(__FreeBSD__) || __FreeBSD_version < 500000
+#if !(defined(_WIN32) || defined(__Userspace__))
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
rt = ip_pcb->inp_route.ro_rt;
#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;
@@ -4237,8 +4167,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* no need to free the net count, since at this point all
* assoc's are gone.
*/
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq);
- SCTP_DECR_READQ_COUNT();
+ sctp_free_a_readq(NULL, sq);
}
/* Now the sctp_pcb things */
/*
@@ -4246,56 +4175,30 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* macro here since le_next will get freed as part of the
* sctp_free_assoc() call.
*/
- if (so) {
-#ifdef IPSEC
- ipsec_delete_pcbpolicy(ip_pcb);
-#endif /* IPSEC */
-
- /* Unlocks not needed since the socket is gone now */
- }
-#ifndef __Panda__
if (ip_pcb->inp_options) {
(void)sctp_m_free(ip_pcb->inp_options);
ip_pcb->inp_options = 0;
}
-#endif
-
-#if !(defined(__Panda__) || defined(__Windows__) || defined(__Userspace__))
-#if !defined(__FreeBSD__) || __FreeBSD_version < 500000
+#if !(defined(_WIN32) || defined(__Userspace__))
+#if !defined(__FreeBSD__)
if (rt) {
RTFREE(rt);
ip_pcb->inp_route.ro_rt = 0;
}
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 803000
-#ifdef INET
- if (ip_pcb->inp_moptions) {
- inp_freemoptions(ip_pcb->inp_moptions);
- ip_pcb->inp_moptions = 0;
- }
-#endif
#endif
-#endif
-
#ifdef INET6
-#if !(defined(__Panda__) || defined(__Windows__) || defined(__Userspace__))
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if !(defined(_WIN32) || defined(__Userspace__))
+#if (defined(__FreeBSD__) || defined(__APPLE__) && !defined(__Userspace__))
if (ip_pcb->inp_vflag & INP_IPV6) {
#else
if (inp->inp_vflag & INP_IPV6) {
#endif
- struct in6pcb *in6p;
-
- in6p = (struct in6pcb *)inp;
- ip6_freepcbopts(in6p->in6p_outputopts);
+ ip6_freepcbopts(ip_pcb->in6p_outputopts);
}
#endif
#endif /* INET6 */
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- inp->inp_vflag = 0;
-#else
ip_pcb->inp_vflag = 0;
-#endif
/* free up authentication fields */
if (inp->sctp_ep.local_auth_chunks != NULL)
sctp_free_chunklist(inp->sctp_ep.local_auth_chunks);
@@ -4308,7 +4211,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
/*sa_ignore FREED_MEMORY*/
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
inp->ip_inp.inp.inp_state = INPCB_STATE_DEAD;
if (in_pcb_checkstate(&inp->ip_inp.inp, WNT_STOPUSING, 1) != WNT_STOPUSING) {
#ifdef INVARIANTS
@@ -4346,14 +4249,14 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
inp->sctp_tcbhash = NULL;
}
/* Now we must put the ep memory back into the zone pool */
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
crfree(inp->ip_inp.inp.inp_cred);
INP_LOCK_DESTROY(&inp->ip_inp.inp);
#endif
SCTP_INP_LOCK_DESTROY(inp);
SCTP_INP_READ_DESTROY(inp);
SCTP_ASOC_CREATE_LOCK_DESTROY(inp);
-#if !defined(__APPLE__)
+#if !(defined(__APPLE__) && !defined(__Userspace__))
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_DECR_EP_COUNT();
#else
@@ -4361,7 +4264,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
#endif
}
-
struct sctp_nets *
sctp_findnet(struct sctp_tcb *stcb, struct sockaddr *addr)
{
@@ -4374,13 +4276,9 @@ sctp_findnet(struct sctp_tcb *stcb, struct sockaddr *addr)
return (NULL);
}
-
int
sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
{
-#ifdef __Panda__
- return (0);
-#else
struct sctp_ifa *sctp_ifa;
sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, SCTP_ADDR_NOT_LOCKED);
if (sctp_ifa) {
@@ -4388,7 +4286,6 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
} else {
return (0);
}
-#endif
}
/*
@@ -4398,7 +4295,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
*/
int
sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
- struct sctp_nets **netp, int set_scope, int from)
+ struct sctp_nets **netp, uint16_t port, int set_scope, int from)
{
/*
* The following is redundant to the same lines in the
@@ -4445,7 +4342,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
/* Invalid address */
return (-1);
}
- /* zero out the bzero area */
+ /* zero out the zero area */
memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
/* assure len is set */
@@ -4453,13 +4350,9 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
sin->sin_len = sizeof(struct sockaddr_in);
#endif
if (set_scope) {
-#ifdef SCTP_DONT_DO_PRIVADDR_SCOPE
- stcb->asoc.scope.ipv4_local_scope = 1;
-#else
if (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
stcb->asoc.scope.ipv4_local_scope = 1;
}
-#endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */
} else {
/* Validate the address is in scope */
if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) &&
@@ -4549,7 +4442,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
return (-1);
}
SCTP_INCR_RADDR_COUNT();
- bzero(net, sizeof(struct sctp_nets));
+ memset(net, 0, sizeof(struct sctp_nets));
(void)SCTP_GETTIME_TIMEVAL(&net->start_time);
#ifdef HAVE_SA_LEN
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
@@ -4612,7 +4505,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
stcb->asoc.numnets++;
net->ref_count = 1;
net->cwr_window_tsn = net->last_cwr_tsn = stcb->asoc.sending_seq - 1;
- net->port = stcb->asoc.port;
+ net->port = port;
net->dscp = stcb->asoc.default_dscp;
#ifdef INET6
net->flowlabel = stcb->asoc.default_flowlabel;
@@ -4641,7 +4534,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
(void)in6_embedscope(&sin6->sin6_addr, sin6, &stcb->sctp_ep->ip_inp.inp, NULL);
#else
@@ -4658,67 +4551,122 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
}
#endif /* SCTP_EMBEDDED_V6_SCOPE */
#endif
- SCTP_RTALLOC((sctp_route_t *)&net->ro, stcb->asoc.vrf_id);
+ SCTP_RTALLOC((sctp_route_t *)&net->ro,
+ stcb->asoc.vrf_id,
+ stcb->sctp_ep->fibnum);
-#if defined(__Userspace__)
net->src_addr_selected = 0;
-#else
+#if !defined(__Userspace__)
if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro)) {
/* Get source address */
net->ro._s_addr = sctp_source_address_selection(stcb->sctp_ep,
- stcb,
- (sctp_route_t *)&net->ro,
- net,
- 0,
- stcb->asoc.vrf_id);
- if (net->ro._s_addr != NULL) {
+ stcb,
+ (sctp_route_t *)&net->ro,
+ net,
+ 0,
+ stcb->asoc.vrf_id);
+ 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;
/* Now get the interface MTU */
if (net->ro._s_addr->ifn_p != NULL) {
- net->mtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p);
+ imtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p);
+ } else {
+ imtu = 0;
}
- } else {
- net->src_addr_selected = 0;
- }
- if (net->mtu > 0) {
- uint32_t rmtu;
-
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_nh);
+ hcmtu = sctp_hc_get_mtu(&net->ro._l_addr, stcb->sctp_ep->fibnum);
+#else
rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt);
+ hcmtu = 0;
+#endif
+ net->mtu = sctp_min_mtu(hcmtu, rmtu, imtu);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#else
if (rmtu == 0) {
/* Start things off to match mtu of interface please. */
SCTP_SET_MTU_OF_ROUTE(&net->ro._l_addr.sa,
- net->ro.ro_rt, net->mtu);
- } else {
- /* we take the route mtu over the interface, since
- * the route may be leading out the loopback, or
- * a different interface.
- */
- net->mtu = rmtu;
+ net->ro.ro_rt, net->mtu);
}
+#endif
}
- } else {
- net->src_addr_selected = 0;
}
#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)
@@ -4730,7 +4678,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
stcb->asoc.smallest_mtu = net->mtu;
}
if (stcb->asoc.smallest_mtu > net->mtu) {
- stcb->asoc.smallest_mtu = net->mtu;
+ sctp_pathmtu_adjustment(stcb, net->mtu);
}
#ifdef INET6
#ifdef SCTP_EMBEDDED_V6_SCOPE
@@ -4757,37 +4705,47 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
*/
net->find_pseudo_cumack = 1;
net->find_rtx_pseudo_cumack = 1;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* Choose an initial flowid. */
net->flowid = stcb->asoc.my_vtag ^
ntohs(stcb->rport) ^
ntohs(stcb->sctp_ep->sctp_lport);
- net->flowtype = M_HASHTYPE_OPAQUE;
+ net->flowtype = M_HASHTYPE_OPAQUE_HASH;
#endif
if (netp) {
*netp = net;
}
netfirst = TAILQ_FIRST(&stcb->asoc.nets);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (net->ro.ro_nh == NULL) {
+#else
if (net->ro.ro_rt == NULL) {
+#endif
/* Since we have no route put it at the back */
TAILQ_INSERT_TAIL(&stcb->asoc.nets, net, sctp_next);
} else if (netfirst == NULL) {
/* We are the first one in the pool. */
TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ } else if (netfirst->ro.ro_nh == NULL) {
+#else
} else if (netfirst->ro.ro_rt == NULL) {
+#endif
/*
* First one has NO route. Place this one ahead of the first
* one.
*/
TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next);
-#ifndef __Panda__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ } else if (net->ro.ro_nh->nh_ifp != netfirst->ro.ro_nh->nh_ifp) {
+#else
} else if (net->ro.ro_rt->rt_ifp != netfirst->ro.ro_rt->rt_ifp) {
+#endif
/*
* This one has a different interface than the one at the
* top of the list. Place it ahead.
*/
TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next);
-#endif
} else {
/*
* Ok we have the same interface as the first one. Move
@@ -4803,34 +4761,39 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
/* End of the list */
TAILQ_INSERT_TAIL(&stcb->asoc.nets, net, sctp_next);
break;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ } else if (netlook->ro.ro_nh == NULL) {
+#else
} else if (netlook->ro.ro_rt == NULL) {
+#endif
/* next one has NO route */
TAILQ_INSERT_BEFORE(netfirst, net, sctp_next);
break;
- }
-#ifndef __Panda__
- else if (netlook->ro.ro_rt->rt_ifp != net->ro.ro_rt->rt_ifp)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ } else if (netlook->ro.ro_nh->nh_ifp != net->ro.ro_nh->nh_ifp) {
#else
- else
+ } else if (netlook->ro.ro_rt->rt_ifp != net->ro.ro_rt->rt_ifp) {
#endif
- {
TAILQ_INSERT_AFTER(&stcb->asoc.nets, netlook,
- net, sctp_next);
+ net, sctp_next);
break;
}
-#ifndef __Panda__
/* Shift forward */
netfirst = netlook;
-#endif
} while (netlook != NULL);
}
/* got to have a primary set */
if (stcb->asoc.primary_destination == 0) {
stcb->asoc.primary_destination = net;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ } else if ((stcb->asoc.primary_destination->ro.ro_nh == NULL) &&
+ (net->ro.ro_nh) &&
+#else
} else if ((stcb->asoc.primary_destination->ro.ro_rt == NULL) &&
- (net->ro.ro_rt) &&
- ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) {
+ (net->ro.ro_rt) &&
+#endif
+ ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) {
/* No route to current primary adopt new primary */
stcb->asoc.primary_destination = net;
}
@@ -4851,7 +4814,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
return (0);
}
-
static uint32_t
sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
{
@@ -4859,11 +4821,9 @@ sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
struct sctpasochead *head;
struct sctp_tcb *lstcb;
- SCTP_INP_WLOCK(inp);
try_again:
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
/* TSNH */
- SCTP_INP_WUNLOCK(inp);
return (0);
}
/*
@@ -4882,8 +4842,7 @@ sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)];
LIST_INSERT_HEAD(head, stcb, sctp_tcbasocidhash);
stcb->asoc.in_asocid_hash = 1;
- SCTP_INP_WUNLOCK(inp);
- return id;
+ return (id);
}
/*
@@ -4893,18 +4852,19 @@ sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
*/
struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
- int *error, uint32_t override_tag, uint32_t vrf_id,
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
- struct thread *p
-#elif defined(__Windows__)
- PKTHREAD p
+ int *error, uint32_t override_tag, uint32_t vrf_id,
+ uint16_t o_streams, uint16_t port,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct thread *p,
+#elif defined(_WIN32) && !defined(__Userspace__)
+ PKTHREAD p,
#else
#if defined(__Userspace__)
/* __Userspace__ NULL proc is going to be passed here. See sctp_lower_sosend */
#endif
- struct proc *p
+ struct proc *p,
#endif
-)
+ int initialize_auth_params)
{
/* note the p argument is only valid in unbound sockets */
@@ -4995,7 +4955,15 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
if ((ntohs(sin->sin_port) == 0) ||
(sin->sin_addr.s_addr == INADDR_ANY) ||
(sin->sin_addr.s_addr == INADDR_BROADCAST) ||
- IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
+ IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) ||
+#if defined(__Userspace__)
+ (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) != 0) ||
+ (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) &&
+ (SCTP_IPV6_V6ONLY(inp) != 0)))) {
+#else
+ (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) &&
+ (SCTP_IPV6_V6ONLY(inp) != 0))) {
+#endif
/* Invalid address */
SCTP_INP_RUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
@@ -5014,7 +4982,8 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
sin6 = (struct sockaddr_in6 *)firstaddr;
if ((ntohs(sin6->sin6_port) == 0) ||
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
- IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+ IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) ||
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)) {
/* Invalid address */
SCTP_INP_RUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
@@ -5032,7 +5001,8 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
sconn = (struct sockaddr_conn *)firstaddr;
if ((ntohs(sconn->sconn_port) == 0) ||
- (sconn->sconn_addr == NULL)) {
+ (sconn->sconn_addr == NULL) ||
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) == 0)) {
/* Invalid address */
SCTP_INP_RUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
@@ -5056,15 +5026,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
* If you have not performed a bind, then we need to do the
* ephemeral bind for you.
*/
- if ((err = sctp_inpcb_bind(inp->sctp_socket,
- (struct sockaddr *)NULL,
- (struct sctp_ifa *)NULL,
-#ifndef __Panda__
- p
-#else
- (struct proc *)NULL
-#endif
- ))) {
+ if ((err = sctp_inpcb_bind(inp->sctp_socket, NULL, NULL, p))) {
/* bind error, probably perm */
*error = err;
return (NULL);
@@ -5079,21 +5041,19 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
}
SCTP_INCR_ASOC_COUNT();
- bzero(stcb, sizeof(*stcb));
+ memset(stcb, 0, sizeof(*stcb));
asoc = &stcb->asoc;
- asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb);
SCTP_TCB_LOCK_INIT(stcb);
SCTP_TCB_SEND_LOCK_INIT(stcb);
stcb->rport = rport;
/* setup back pointer's */
stcb->sctp_ep = inp;
stcb->sctp_socket = inp->sctp_socket;
- if ((err = sctp_init_asoc(inp, stcb, override_tag, vrf_id))) {
+ if ((err = sctp_init_asoc(inp, stcb, override_tag, vrf_id, o_streams))) {
/* failed */
SCTP_TCB_LOCK_DESTROY(stcb);
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
- LIST_REMOVE(stcb, sctp_tcbasocidhash);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
SCTP_DECR_ASOC_COUNT();
*error = err;
@@ -5106,7 +5066,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
/* inpcb freed while alloc going on */
SCTP_TCB_LOCK_DESTROY(stcb);
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
- LIST_REMOVE(stcb, sctp_tcbasocidhash);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
@@ -5117,13 +5076,14 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
}
SCTP_TCB_LOCK(stcb);
+ asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb);
/* now that my_vtag is set, add it to the hash */
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
/* put it in the bucket in the vtag hash of assoc's for the system */
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
SCTP_INP_INFO_WUNLOCK();
- if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
+ if (sctp_add_remote_addr(stcb, firstaddr, NULL, port, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC)) {
/* failure.. memory error? */
if (asoc->strmout) {
SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
@@ -5154,7 +5114,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->shut_guard_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->autoclose_timer.timer);
- SCTP_OS_TIMER_INIT(&asoc->delayed_event_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->delete_prim_timer.timer);
LIST_INSERT_HEAD(&inp->sctp_asoc_list, stcb, sctp_tcblist);
@@ -5164,17 +5123,21 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
inp->sctp_hashmark)];
LIST_INSERT_HEAD(head, stcb, sctp_tcbhash);
}
+ if (initialize_auth_params == SCTP_INITIALIZE_AUTH_PARAMS) {
+ sctp_initialize_auth_params(inp, stcb);
+ }
SCTP_INP_WUNLOCK(inp);
SCTPDBG(SCTP_DEBUG_PCB1, "Association %p now allocated\n", (void *)stcb);
return (stcb);
}
-
void
sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
{
+ struct sctp_inpcb *inp;
struct sctp_association *asoc;
+ inp = stcb->sctp_ep;
asoc = &stcb->asoc;
asoc->numnets--;
TAILQ_REMOVE(&asoc->nets, net, sctp_next);
@@ -5222,6 +5185,11 @@ out:
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
+ sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_9);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_10);
+ net->dest_state |= SCTP_ADDR_BEING_DELETED;
sctp_free_remote_addr(net);
}
@@ -5318,7 +5286,6 @@ sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport)
return (found);
}
-
void
sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport)
{
@@ -5375,9 +5342,6 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t
SCTP_MALLOC(twait_block, struct sctp_tagblock *,
sizeof(struct sctp_tagblock), SCTP_M_TIMW);
if (twait_block == NULL) {
-#ifdef INVARIANTS
- panic("Can not alloc tagblock");
-#endif
return;
}
memset(twait_block, 0, sizeof(struct sctp_tagblock));
@@ -5389,10 +5353,46 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t
}
}
+void
+sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh)
+{
+ struct sctp_tmit_chunk *chk, *nchk;
+ struct sctp_queued_to_read *control, *ncontrol;
-#ifdef __Panda__
-void panda_wakeup_socket(struct socket *so);
-#endif
+ TAILQ_FOREACH_SAFE(control, rh, next_instrm, ncontrol) {
+ TAILQ_REMOVE(rh, control, next_instrm);
+ control->on_strm_q = 0;
+ if (control->on_read_q == 0) {
+ sctp_free_remote_addr(control->whoFrom);
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ }
+ /* Reassembly free? */
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ if (chk->holds_key_ref)
+ sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED);
+ sctp_free_remote_addr(chk->whoTo);
+ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
+ SCTP_DECR_CHK_COUNT();
+ /*sa_ignore FREED_MEMORY*/
+ }
+ /*
+ * We don't free the address here
+ * since all the net's were freed
+ * above.
+ */
+ if (control->on_read_q == 0) {
+ sctp_free_a_readq(stcb, control);
+ }
+ }
+}
/*-
* Free the association after un-hashing the remote port. This
@@ -5419,7 +5419,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
struct socket *so;
/* first, lets purge the entry from the hash table. */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sctp_lock_assert(SCTP_INP_SO(inp));
#endif
@@ -5433,17 +5433,18 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* there is no asoc, really TSNH :-0 */
return (1);
}
+ SCTP_TCB_SEND_LOCK(stcb);
if (stcb->asoc.alternate) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
-#if !defined(__APPLE__) /* TEMP: moved to below */
- /* TEMP CODE */
+#if !(defined(__APPLE__) && !defined(__Userspace__))
+ /* TEMP CODE */
if (stcb->freed_from_where == 0) {
/* Only record the first place free happened from */
stcb->freed_from_where = from_location;
}
- /* TEMP CODE */
+ /* TEMP CODE */
#endif
asoc = &stcb->asoc;
@@ -5469,6 +5470,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* nope, reader or writer in the way */
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
/* no asoc destroyed */
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, stcb, 8);
@@ -5476,40 +5478,11 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
return (0);
}
}
- /* now clean up any other timers */
- (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
- asoc->dack_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
- /*-
- * For stream reset we don't blast this unless
- * it is a str-reset timer, it might be the
- * free-asoc timer which we DON'T want to
- * disturb.
- */
- if (asoc->strreset_timer.type == SCTP_TIMER_TYPE_STRRESET)
- asoc->strreset_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
- asoc->asconf_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
- asoc->autoclose_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&asoc->shut_guard_timer.timer);
- asoc->shut_guard_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
- asoc->delayed_event_timer.self = NULL;
- /* Mobility adaptation */
- (void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer);
- asoc->delete_prim_timer.self = NULL;
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
- net->rxt_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
- net->pmtu_timer.self = NULL;
- (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
- net->hb_timer.self = NULL;
- }
+ /* Now clean up any other timers */
+ sctp_stop_association_timers(stcb, false);
/* Now the read queue needs to be cleaned up (only once) */
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) {
- stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED;
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_ABOUT_TO_BE_FREED);
SCTP_INP_READ_LOCK(inp);
TAILQ_FOREACH(sq, &inp->read_queue, next) {
if (sq->stcb == stcb) {
@@ -5530,7 +5503,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
*/
uint32_t strseq;
stcb->asoc.control_pdapi = sq;
- strseq = (sq->sinfo_stream << 16) | sq->sinfo_ssn;
+ strseq = (sq->sinfo_stream << 16) | (sq->mid & 0x0000ffff);
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
stcb,
SCTP_PARTIAL_DELIVERY_ABORTED,
@@ -5556,9 +5529,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
if ((stcb->asoc.refcnt) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
- stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
+ SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
}
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE))
@@ -5597,10 +5571,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
if (from_inpcbfree == SCTP_NORMAL_PROC) {
atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
SCTP_INP_INFO_WLOCK();
SCTP_INP_WLOCK(inp);
SCTP_TCB_LOCK(stcb);
+ SCTP_TCB_SEND_LOCK(stcb);
}
/* Double check the GONE flag */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
@@ -5618,18 +5594,18 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
inp->sctp_flags &= ~SCTP_PCB_FLAGS_CONNECTED;
inp->sctp_flags |= SCTP_PCB_FLAGS_WAS_CONNECTED;
if (so) {
- SOCK_LOCK(so);
- if (so->so_rcv.sb_cc == 0) {
- so->so_state &= ~(SS_ISCONNECTING |
- SS_ISDISCONNECTING |
- SS_ISCONFIRMING |
- SS_ISCONNECTED);
- }
-#if defined(__APPLE__)
+ SOCKBUF_LOCK(&so->so_rcv);
+ so->so_state &= ~(SS_ISCONNECTING |
+ SS_ISDISCONNECTING |
+ SS_ISCONFIRMING |
+ SS_ISCONNECTED);
+ so->so_state |= SS_ISDISCONNECTED;
+#if defined(__APPLE__) && !defined(__Userspace__)
socantrcvmore(so);
#else
socantrcvmore_locked(so);
#endif
+ socantsendmore(so);
sctp_sowwakeup(inp, so);
sctp_sorwakeup(inp, so);
SCTP_SOWAKEUP(so);
@@ -5645,12 +5621,13 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
atomic_add_int(&stcb->asoc.refcnt, -1);
}
if (stcb->asoc.refcnt) {
- stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
+ SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
if (from_inpcbfree == SCTP_NORMAL_PROC) {
SCTP_INP_INFO_WUNLOCK();
SCTP_INP_WUNLOCK(inp);
}
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
return (0);
}
@@ -5675,20 +5652,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* Now restop the timers to be sure
* this is paranoia at is finest!
*/
- (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->shut_guard_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
- }
-
- asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE;
+ sctp_stop_association_timers(stcb, true);
+
/*
* The chunk lists and such SHOULD be empty but we check them just
* in case.
@@ -5700,7 +5665,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
outs = &asoc->strmout[i];
/* now clean up any chunks here */
TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&outs->outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1);
sctp_free_spbufspace(stcb, asoc, sp);
if (sp->data) {
if (so) {
@@ -5737,8 +5704,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
sq->whoFrom = NULL;
sq->stcb = NULL;
/* Free the ctl entry */
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq);
- SCTP_DECR_READQ_COUNT();
+ sctp_free_a_readq(stcb, sq);
/*sa_ignore FREED_MEMORY*/
}
TAILQ_FOREACH_SAFE(chk, &asoc->free_chunks, sctp_next, nchk) {
@@ -5757,11 +5723,11 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
/* pending send queue SHOULD be empty */
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
- if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
#endif
}
TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
@@ -5789,11 +5755,11 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* sent queue SHOULD be empty */
TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
- if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
#endif
}
}
@@ -5851,20 +5817,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_DECR_CHK_COUNT();
/*sa_ignore FREED_MEMORY*/
}
- TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
- TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
- if (chk->holds_key_ref)
- sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED);
- sctp_free_remote_addr(chk->whoTo);
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
- SCTP_DECR_CHK_COUNT();
- /*sa_ignore FREED_MEMORY*/
- }
-
if (asoc->mapping_array) {
SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
asoc->mapping_array = NULL;
@@ -5880,24 +5832,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
asoc->strm_realoutsize = asoc->streamoutcnt = 0;
if (asoc->strmin) {
- struct sctp_queued_to_read *ctl, *nctl;
-
for (i = 0; i < asoc->streamincnt; i++) {
- TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) {
- TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next);
- sctp_free_remote_addr(ctl->whoFrom);
- if (ctl->data) {
- sctp_m_freem(ctl->data);
- ctl->data = NULL;
- }
- /*
- * We don't free the address here
- * since all the net's were freed
- * above.
- */
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl);
- SCTP_DECR_READQ_COUNT();
- }
+ sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue);
+ sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue);
}
SCTP_FREE(asoc->strmin, SCTP_M_STRMI);
asoc->strmin = NULL;
@@ -5953,6 +5890,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* Insert new items here :> */
/* Get rid of LOCK */
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
SCTP_TCB_LOCK_DESTROY(stcb);
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
@@ -5960,7 +5898,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_INP_INFO_WUNLOCK();
SCTP_INP_RLOCK(inp);
}
-#if defined(__APPLE__) /* TEMP CODE */
+#if defined(__APPLE__) && !defined(__Userspace__)
+ /* TEMP CODE */
stcb->freed_from_where = from_location;
#endif
#ifdef SCTP_TRACK_FREED_ASOCS
@@ -5993,16 +5932,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
SCTP_CALLED_DIRECTLY_NOCMPSET);
SCTP_INP_DECR_REF(inp);
- goto out_of;
} else {
/* The socket is still open. */
SCTP_INP_DECR_REF(inp);
+ SCTP_INP_RUNLOCK(inp);
}
}
- if (from_inpcbfree == SCTP_NORMAL_PROC) {
- SCTP_INP_RUNLOCK(inp);
- }
- out_of:
/* destroyed the asoc */
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 11);
@@ -6010,8 +5945,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
return (1);
}
-
-
/*
* determine if a destination is "reachable" based upon the addresses bound
* to the current endpoint (e.g. only v4 or v6 currently bound)
@@ -6051,20 +5984,12 @@ sctp_destination_is_reachable(struct sctp_tcb *stcb, struct sockaddr *destaddr)
switch (destaddr->sa_family) {
#ifdef INET6
case AF_INET6:
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- answer = inp->inp_vflag & INP_IPV6;
-#else
answer = inp->ip_inp.inp.inp_vflag & INP_IPV6;
-#endif
break;
#endif
#ifdef INET
case AF_INET:
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- answer = inp->inp_vflag & INP_IPV4;
-#else
answer = inp->ip_inp.inp.inp_vflag & INP_IPV4;
-#endif
break;
#endif
#if defined(__Userspace__)
@@ -6089,16 +6014,12 @@ sctp_update_ep_vflag(struct sctp_inpcb *inp)
struct sctp_laddr *laddr;
/* first clear the flag */
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- inp->inp_vflag = 0;
-#else
inp->ip_inp.inp.inp_vflag = 0;
-#endif
/* set the flag based on addresses on the ep list */
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
continue;
}
@@ -6108,20 +6029,12 @@ sctp_update_ep_vflag(struct sctp_inpcb *inp)
switch (laddr->ifa->address.sa.sa_family) {
#ifdef INET6
case AF_INET6:
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- inp->inp_vflag |= INP_IPV6;
-#else
inp->ip_inp.inp.inp_vflag |= INP_IPV6;
-#endif
break;
#endif
#ifdef INET
case AF_INET:
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- inp->inp_vflag |= INP_IPV4;
-#else
inp->ip_inp.inp.inp_vflag |= INP_IPV4;
-#endif
break;
#endif
#if defined(__Userspace__)
@@ -6143,6 +6056,7 @@ void
sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t action)
{
struct sctp_laddr *laddr;
+ struct sctp_tcb *stcb;
int fnd, error = 0;
fnd = 0;
@@ -6177,20 +6091,12 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac
switch (ifa->address.sa.sa_family) {
#ifdef INET6
case AF_INET6:
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- inp->inp_vflag |= INP_IPV6;
-#else
inp->ip_inp.inp.inp_vflag |= INP_IPV6;
-#endif
break;
#endif
#ifdef INET
case AF_INET:
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
- inp->inp_vflag |= INP_IPV4;
-#else
inp->ip_inp.inp.inp_vflag |= INP_IPV4;
-#endif
break;
#endif
#if defined(__Userspace__)
@@ -6201,11 +6107,13 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac
default:
break;
}
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ sctp_add_local_addr_restricted(stcb, ifa);
+ }
}
return;
}
-
/*
* select a new (hopefully reachable) destination net (should only be used
* when we deleted an ep addr that is the only usable source address to reach
@@ -6229,9 +6137,8 @@ sctp_select_primary_destination(struct sctp_tcb *stcb)
/* I can't there from here! ...we're gonna die shortly... */
}
-
/*
- * Delete the address from the endpoint local address list There is nothing
+ * Delete the address from the endpoint local address list. There is nothing
* to be done if we are bound to all addresses
*/
void
@@ -6272,15 +6179,18 @@ sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
/* clean up "last_used_address" */
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
struct sctp_nets *net;
+
SCTP_TCB_LOCK(stcb);
if (stcb->asoc.last_used_address == laddr)
/* delete this address */
stcb->asoc.last_used_address = NULL;
/* Now spin through all the nets and purge any ref to laddr */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (net->ro._s_addr &&
- (net->ro._s_addr->ifa == laddr->ifa)) {
+ if (net->ro._s_addr == laddr->ifa) {
/* Yep, purge src address selected */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(&net->ro);
+#else
sctp_rtentry_t *rt;
/* delete this address if cached */
@@ -6289,6 +6199,7 @@ sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
RTFREE(rt);
net->ro.ro_rt = NULL;
}
+#endif
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
@@ -6343,46 +6254,6 @@ sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
}
/*
- * insert an laddr entry with the given ifa for the desired list
- */
-int
-sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
-{
- struct sctp_laddr *laddr;
-
- laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
- if (laddr == NULL) {
- /* out of memory? */
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
- return (EINVAL);
- }
- SCTP_INCR_LADDR_COUNT();
- bzero(laddr, sizeof(*laddr));
- (void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
- laddr->ifa = ifa;
- laddr->action = act;
- atomic_add_int(&ifa->refcount, 1);
- /* insert it */
- LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr);
-
- return (0);
-}
-
-/*
- * Remove an laddr entry from the local address list (on an assoc)
- */
-void
-sctp_remove_laddr(struct sctp_laddr *laddr)
-{
-
- /* remove from the list */
- LIST_REMOVE(laddr, sctp_nxt_addr);
- sctp_free_ifa(laddr->ifa);
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr);
- SCTP_DECR_LADDR_COUNT();
-}
-
-/*
* Remove a local address from the TCB local address restricted list
*/
void
@@ -6424,20 +6295,17 @@ sctp_del_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
return;
}
-#if defined(__FreeBSD__)
-/*
- * Temporarily remove for __APPLE__ until we use the Tiger equivalents
- */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
/* sysctl */
static int sctp_max_number_of_assoc = SCTP_MAX_NUM_OF_ASOC;
static int sctp_scale_up_for_address = SCTP_SCALE_FOR_ADDR;
-#endif /* FreeBSD || APPLE */
-
-
+#endif
-#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_MCORE_INPUT) && defined(SMP)
struct sctp_mcore_ctrl *sctp_mcore_workers = NULL;
int *sctp_cpuarry = NULL;
+
void
sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use)
{
@@ -6445,6 +6313,7 @@ sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use)
struct sctp_mcore_queue *qent;
struct sctp_mcore_ctrl *wkq;
int need_wake = 0;
+
if (sctp_mcore_workers == NULL) {
/* Something went way bad during setup */
sctp_input_with_port(m, off, 0);
@@ -6458,9 +6327,7 @@ sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use)
sctp_input_with_port(m, off, 0);
return;
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
qent->vn = curvnet;
-#endif
qent->m = m;
qent->off = off;
qent->v6 = 0;
@@ -6512,9 +6379,7 @@ sctp_mcore_thread(void *arg)
if (qent) {
TAILQ_REMOVE(&wkq->que, qent, next);
SCTP_MCORE_QUNLOCK(wkq);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
CURVNET_SET(qent->vn);
-#endif
m = qent->m;
off = qent->off;
v6 = qent->v6;
@@ -6525,9 +6390,7 @@ sctp_mcore_thread(void *arg)
SCTP_PRINTF("V6 not yet supported\n");
sctp_m_freem(m);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
CURVNET_RESTORE();
-#endif
SCTP_MCORE_QLOCK(wkq);
}
wkq->running = 0;
@@ -6581,30 +6444,21 @@ sctp_startup_mcore_threads(void)
i++;
}
}
-
/* Now start them all */
CPU_FOREACH(cpu) {
-#if __FreeBSD_version <= 701000
- (void)kthread_create(sctp_mcore_thread,
- (void *)&sctp_mcore_workers[cpu],
- &sctp_mcore_workers[cpu].thread_proc,
- RFPROC,
- SCTP_KTHREAD_PAGES,
- SCTP_MCORE_NAME);
-
-#else
(void)kproc_create(sctp_mcore_thread,
(void *)&sctp_mcore_workers[cpu],
&sctp_mcore_workers[cpu].thread_proc,
RFPROC,
SCTP_KTHREAD_PAGES,
SCTP_MCORE_NAME);
-#endif
-
}
}
#endif
-#if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1200000
+#endif
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_NOT_YET)
static struct mbuf *
sctp_netisr_hdlr(struct mbuf *m, uintptr_t source)
{
@@ -6630,17 +6484,23 @@ sctp_netisr_hdlr(struct mbuf *m, uintptr_t source)
tag = htonl(sh->v_tag);
flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port);
m->m_pkthdr.flowid = flowid;
+ /* FIX ME */
m->m_flags |= M_FLOWID;
return (m);
}
-#endif
+#endif
+#endif
void
-sctp_pcb_init()
+#if defined(__Userspace__)
+sctp_pcb_init(int start_threads)
+#else
+sctp_pcb_init(void)
+#endif
{
/*
* SCTP initialization for the PCB structures should be called by
- * the sctp_init() funciton.
+ * the sctp_init() function.
*/
int i;
struct timeval tv;
@@ -6651,33 +6511,49 @@ sctp_pcb_init()
}
SCTP_BASE_VAR(sctp_pcb_initialized) = 1;
+#if defined(SCTP_PROCESS_LEVEL_LOCKS)
+#if !defined(_WIN32)
+ pthread_mutexattr_init(&SCTP_BASE_VAR(mtx_attr));
+#ifdef INVARIANTS
+ pthread_mutexattr_settype(&SCTP_BASE_VAR(mtx_attr), PTHREAD_MUTEX_ERRORCHECK);
+#endif
+#endif
+#endif
#if defined(SCTP_LOCAL_TRACE_BUF)
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
if (SCTP_BASE_SYSCTL(sctp_log) != NULL) {
- bzero(SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log));
+ memset(SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log));
}
#else
- bzero(&SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log));
+ memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log));
#endif
#endif
-#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
SCTP_MALLOC(SCTP_BASE_STATS, struct sctpstat *,
((mp_maxid+1) * sizeof(struct sctpstat)),
SCTP_M_MCORE);
#endif
+#endif
(void)SCTP_GETTIME_TIMEVAL(&tv);
-#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
- bzero(SCTP_BASE_STATS, (sizeof(struct sctpstat) * (mp_maxid+1)));
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
+ memset(SCTP_BASE_STATS, 0, sizeof(struct sctpstat) * (mp_maxid+1));
SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_sec = (uint32_t)tv.tv_sec;
SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_usec = (uint32_t)tv.tv_usec;
#else
- bzero(&SCTP_BASE_STATS, sizeof(struct sctpstat));
+ memset(&SCTP_BASE_STATS, 0, sizeof(struct sctpstat));
+ SCTP_BASE_STAT(sctps_discontinuitytime).tv_sec = (uint32_t)tv.tv_sec;
+ SCTP_BASE_STAT(sctps_discontinuitytime).tv_usec = (uint32_t)tv.tv_usec;
+#endif
+#else
+ memset(&SCTP_BASE_STATS, 0, sizeof(struct sctpstat));
SCTP_BASE_STAT(sctps_discontinuitytime).tv_sec = (uint32_t)tv.tv_sec;
SCTP_BASE_STAT(sctps_discontinuitytime).tv_usec = (uint32_t)tv.tv_usec;
#endif
/* init the empty list of (All) Endpoints */
LIST_INIT(&SCTP_BASE_INFO(listhead));
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
LIST_INIT(&SCTP_BASE_INFO(inplisthead));
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION)
SCTP_BASE_INFO(sctbinfo).listhead = &SCTP_BASE_INFO(inplisthead);
@@ -6700,21 +6576,11 @@ sctp_pcb_init()
#endif
#endif
-
/* init the hash table of endpoints */
-#if defined(__FreeBSD__)
-#if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version >= 440000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", &SCTP_BASE_SYSCTL(sctp_hashtblsize));
TUNABLE_INT_FETCH("net.inet.sctp.pcbhashsize", &SCTP_BASE_SYSCTL(sctp_pcbtblsize));
TUNABLE_INT_FETCH("net.inet.sctp.chunkscale", &SCTP_BASE_SYSCTL(sctp_chunkscale));
-#else
- TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", SCTP_TCBHASHSIZE,
- SCTP_BASE_SYSCTL(sctp_hashtblsize));
- TUNABLE_INT_FETCH("net.inet.sctp.pcbhashsize", SCTP_PCBHASHSIZE,
- SCTP_BASE_SYSCTL(sctp_pcbtblsize));
- TUNABLE_INT_FETCH("net.inet.sctp.chunkscale", SCTP_CHUNKQUEUE_SCALE,
- SCTP_BASE_SYSCTL(sctp_chunkscale));
-#endif
#endif
SCTP_BASE_INFO(sctp_asochash) = SCTP_HASH_INIT((SCTP_BASE_SYSCTL(sctp_hashtblsize) * 31),
&SCTP_BASE_INFO(hashasocmark));
@@ -6723,8 +6589,6 @@ sctp_pcb_init()
SCTP_BASE_INFO(sctp_tcpephash) = SCTP_HASH_INIT(SCTP_BASE_SYSCTL(sctp_hashtblsize),
&SCTP_BASE_INFO(hashtcpmark));
SCTP_BASE_INFO(hashtblsize) = SCTP_BASE_SYSCTL(sctp_hashtblsize);
-
-
SCTP_BASE_INFO(sctp_vrfhash) = SCTP_HASH_INIT(SCTP_SIZE_OF_VRF_HASH,
&SCTP_BASE_INFO(hashvrfmark));
@@ -6769,7 +6633,6 @@ sctp_pcb_init()
sizeof(struct sctp_asconf_ack),
(sctp_max_number_of_assoc * SCTP_BASE_SYSCTL(sctp_chunkscale)));
-
/* Master Lock INIT for info structure */
SCTP_INP_INFO_LOCK_INIT();
SCTP_STATLOG_INIT_LOCK();
@@ -6809,7 +6672,7 @@ sctp_pcb_init()
LIST_INIT(&SCTP_BASE_INFO(vtag_timewait)[i]);
}
#if defined(SCTP_PROCESS_LEVEL_LOCKS)
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
InitializeConditionVariable(&sctp_it_ctl.iterator_wakeup);
#else
(void)pthread_cond_init(&sctp_it_ctl.iterator_wakeup, NULL);
@@ -6817,19 +6680,19 @@ sctp_pcb_init()
#endif
sctp_startup_iterator();
-#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_MCORE_INPUT) && defined(SMP)
sctp_startup_mcore_threads();
#endif
+#endif
-#ifndef __Panda__
/*
* INIT the default VRF which for BSD is the only one, other O/S's
* may have more. But initially they must start with one and then
* add the VRF's as addresses are added.
*/
sctp_init_vrf_list(SCTP_DEFAULT_VRF);
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1200000
+#if defined(__FreeBSD__) && !defined(__Userspace__) && defined(SCTP_NOT_YET)
if (ip_register_flow_handler(sctp_netisr_hdlr, IPPROTO_SCTP)) {
SCTP_PRINTF("***SCTP- Error can't register netisr handler***\n");
}
@@ -6840,10 +6703,11 @@ sctp_pcb_init()
TAILQ_INIT(&SCTP_BASE_INFO(callqueue));
#endif
#if defined(__Userspace__)
- mbuf_init(NULL);
+ mbuf_initialize(NULL);
atomic_init();
#if defined(INET) || defined(INET6)
- recv_thread_init();
+ if (start_threads)
+ recv_thread_init();
#endif
#endif
}
@@ -6863,15 +6727,20 @@ sctp_pcb_finish(void)
struct sctp_laddr *wi, *nwi;
int i;
struct sctp_iterator *it, *nit;
-
-#if !defined(__FreeBSD__)
+
+ if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
+ SCTP_PRINTF("%s: race condition on teardown.\n", __func__);
+ return;
+ }
+ SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
/* Notify the iterator to exit. */
SCTP_IPI_ITERATOR_WQ_LOCK();
sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_MUST_EXIT;
sctp_wakeup_iterator();
SCTP_IPI_ITERATOR_WQ_UNLOCK();
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)
in_pcbinfo_detach(&SCTP_BASE_INFO(sctbinfo));
#endif
@@ -6884,7 +6753,7 @@ sctp_pcb_finish(void)
thread_deallocate(sctp_it_ctl.thread_proc);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
if (sctp_it_ctl.iterator_thread_obj != NULL) {
NTSTATUS status = STATUS_SUCCESS;
@@ -6898,8 +6767,8 @@ sctp_pcb_finish(void)
}
#endif
#if defined(__Userspace__)
- if (sctp_it_ctl.thread_proc) {
-#if defined(__Userspace_os_Windows)
+ if (SCTP_BASE_VAR(iterator_thread_started)) {
+#if defined(_WIN32)
WaitForSingleObject(sctp_it_ctl.thread_proc, INFINITE);
CloseHandle(sctp_it_ctl.thread_proc);
sctp_it_ctl.thread_proc = NULL;
@@ -6910,10 +6779,11 @@ sctp_pcb_finish(void)
}
#endif
#if defined(SCTP_PROCESS_LEVEL_LOCKS)
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
DeleteConditionVariable(&sctp_it_ctl.iterator_wakeup);
#else
pthread_cond_destroy(&sctp_it_ctl.iterator_wakeup);
+ pthread_mutexattr_destroy(&SCTP_BASE_VAR(mtx_attr));
#endif
#endif
/* In FreeBSD the iterator thread never exits
@@ -6921,9 +6791,28 @@ sctp_pcb_finish(void)
* The only way FreeBSD reaches here is if we have VRF's
* but we still add the ifdef to make it compile on old versions.
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+retry:
+#endif
SCTP_IPI_ITERATOR_WQ_LOCK();
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ /*
+ * sctp_iterator_worker() might be working on an it entry without
+ * holding the lock. We won't find it on the list either and
+ * continue and free/destroy it. While holding the lock, spin, to
+ * avoid the race condition as sctp_iterator_worker() will have to
+ * wait to re-acquire the lock.
+ */
+ if (sctp_it_ctl.iterator_running != 0 || sctp_it_ctl.cur_it != NULL) {
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ SCTP_PRINTF("%s: Iterator running while we held the lock. Retry. "
+ "cur_it=%p\n", __func__, sctp_it_ctl.cur_it);
+ DELAY(10);
+ goto retry;
+ }
+#endif
TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (it->vn != curvnet) {
continue;
}
@@ -6935,7 +6824,7 @@ sctp_pcb_finish(void)
SCTP_FREE(it,SCTP_M_ITER);
}
SCTP_IPI_ITERATOR_WQ_UNLOCK();
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
SCTP_ITERATOR_LOCK();
if ((sctp_it_ctl.cur_it) &&
(sctp_it_ctl.cur_it->vn == curvnet)) {
@@ -6943,11 +6832,11 @@ sctp_pcb_finish(void)
}
SCTP_ITERATOR_UNLOCK();
#endif
-#if !defined(__FreeBSD__)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
SCTP_IPI_ITERATOR_WQ_DESTROY();
SCTP_ITERATOR_LOCK_DESTROY();
#endif
- SCTP_OS_TIMER_STOP(&SCTP_BASE_INFO(addr_wq_timer.timer));
+ SCTP_OS_TIMER_STOP_DRAIN(&SCTP_BASE_INFO(addr_wq_timer.timer));
SCTP_WQ_ADDR_LOCK();
LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
LIST_REMOVE(wi, sctp_nxt_addr);
@@ -6963,6 +6852,7 @@ sctp_pcb_finish(void)
* free the vrf/ifn/ifa lists and hashes (be sure address monitor
* is destroyed first).
*/
+ SCTP_IPI_ADDR_WLOCK();
vrf_bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(SCTP_DEFAULT_VRFID & SCTP_BASE_INFO(hashvrfmark))];
LIST_FOREACH_SAFE(vrf, vrf_bucket, next_vrf, nvrf) {
LIST_FOREACH_SAFE(ifn, &vrf->ifnlist, next_ifn, nifn) {
@@ -6982,15 +6872,10 @@ sctp_pcb_finish(void)
LIST_REMOVE(vrf, next_vrf);
SCTP_FREE(vrf, SCTP_M_VRF);
}
+ SCTP_IPI_ADDR_WUNLOCK();
/* free the vrf hashes */
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_vrfhash), SCTP_BASE_INFO(hashvrfmark));
SCTP_HASH_FREE(SCTP_BASE_INFO(vrf_ifn_hash), SCTP_BASE_INFO(vrf_ifn_hashmark));
-#if defined(__Userspace__) && !defined(__Userspace_os_Windows)
- /* free memory allocated by getifaddrs call */
-#if defined(INET) || defined(INET6)
- freeifaddrs(g_interfaces);
-#endif
-#endif
/* free the TIMEWAIT list elements malloc'd in the function
* sctp_add_vtag_to_timewait()...
@@ -7010,14 +6895,14 @@ sctp_pcb_finish(void)
}
/* free the locks and mutexes */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_TIMERQ_LOCK_DESTROY();
#endif
#ifdef SCTP_PACKET_LOGGING
SCTP_IP_PKTLOG_DESTROY();
#endif
SCTP_IPI_ADDR_DESTROY();
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_IPI_COUNT_DESTROY();
#endif
SCTP_STATLOG_DESTROY();
@@ -7025,7 +6910,7 @@ sctp_pcb_finish(void)
SCTP_WQ_ADDR_DESTROY();
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION)
lck_grp_attr_free(SCTP_BASE_INFO(sctbinfo).mtx_grp_attr);
lck_grp_free(SCTP_BASE_INFO(sctbinfo).mtx_grp);
@@ -7042,7 +6927,15 @@ sctp_pcb_finish(void)
SCTP_ZONE_DESTROY(zone_clust);
SCTP_ZONE_DESTROY(zone_ext_refcnt);
#endif
-#if defined(__Windows__) || defined(__FreeBSD__) || defined(__Userspace__)
+ /* Get rid of other stuff too. */
+ if (SCTP_BASE_INFO(sctp_asochash) != NULL)
+ SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark));
+ if (SCTP_BASE_INFO(sctp_ephash) != NULL)
+ SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark));
+ if (SCTP_BASE_INFO(sctp_tcpephash) != NULL)
+ SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark));
+
+#if defined(_WIN32) || defined(__FreeBSD__) || defined(__Userspace__)
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_ep));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asoc));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_laddr));
@@ -7053,24 +6946,18 @@ sctp_pcb_finish(void)
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf_ack));
#endif
- /* Get rid of other stuff to */
- if (SCTP_BASE_INFO(sctp_asochash) != NULL)
- SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark));
- if (SCTP_BASE_INFO(sctp_ephash) != NULL)
- SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark));
- if (SCTP_BASE_INFO(sctp_tcpephash) != NULL)
- SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark));
-#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
SCTP_FREE(SCTP_BASE_STATS, SCTP_M_MCORE);
#endif
+#endif
}
-
int
sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
int offset, int limit,
struct sockaddr *src, struct sockaddr *dst,
- struct sockaddr *altsa)
+ struct sockaddr *altsa, uint16_t port)
{
/*
* grub through the INIT pulling addresses and loading them to the
@@ -7081,7 +6968,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
*/
struct sctp_inpcb *inp;
struct sctp_nets *net, *nnet, *net_tmp;
- struct sctp_paramhdr *phdr, parm_buf;
+ struct sctp_paramhdr *phdr, param_buf;
struct sctp_tcb *stcb_tmp;
uint16_t ptype, plen;
struct sockaddr *sa;
@@ -7107,6 +6994,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
uint8_t peer_supports_reconfig;
uint8_t peer_supports_nrsack;
uint8_t peer_supports_pktdrop;
+ uint8_t peer_supports_idata;
#ifdef INET
struct sockaddr_in sin;
#endif
@@ -7136,10 +7024,12 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
} else {
sa = src;
}
+ peer_supports_idata = 0;
peer_supports_ecn = 0;
peer_supports_prsctp = 0;
peer_supports_auth = 0;
peer_supports_asconf = 0;
+ peer_supports_asconf_ack = 0;
peer_supports_reconfig = 0;
peer_supports_nrsack = 0;
peer_supports_pktdrop = 0;
@@ -7160,7 +7050,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
#ifdef INET
case AF_INET:
if (stcb->asoc.scope.ipv4_addr_legal) {
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
return (-1);
}
}
@@ -7169,7 +7059,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
#ifdef INET6
case AF_INET6:
if (stcb->asoc.scope.ipv6_addr_legal) {
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
return (-2);
}
}
@@ -7178,7 +7068,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
#if defined(__Userspace__)
case AF_CONN:
if (stcb->asoc.scope.conn_addr_legal) {
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
return (-2);
}
}
@@ -7202,7 +7092,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
return (-4);
}
/* now we must go through each of the params. */
- phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf, sizeof(param_buf));
while (phdr) {
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
@@ -7263,7 +7153,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
/* the assoc was freed? */
return (-7);
}
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) {
return (-8);
}
} else if (stcb_tmp == stcb) {
@@ -7282,10 +7172,18 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
* assoc? straighten out locks.
*/
if (stcb_tmp) {
- if (SCTP_GET_STATE(&stcb_tmp->asoc) & SCTP_STATE_COOKIE_WAIT) {
+ if (SCTP_GET_STATE(stcb_tmp) == SCTP_STATE_COOKIE_WAIT) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
/* in setup state we abort this guy */
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "%s:%d at %s", __FILE__, __LINE__, __func__);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
sctp_abort_an_association(stcb_tmp->sctp_ep,
- stcb_tmp, NULL, SCTP_SO_NOT_LOCKED);
+ stcb_tmp, op_err,
+ SCTP_SO_NOT_LOCKED);
goto add_it_now;
}
SCTP_TCB_UNLOCK(stcb_tmp);
@@ -7345,7 +7243,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
* we must add the address, no scope
* set
*/
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) {
return (-17);
}
} else if (stcb_tmp == stcb) {
@@ -7367,15 +7265,23 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
* strange, address is in another
* assoc? straighten out locks.
*/
- if (stcb_tmp)
- if (SCTP_GET_STATE(&stcb_tmp->asoc) & SCTP_STATE_COOKIE_WAIT) {
+ if (stcb_tmp) {
+ if (SCTP_GET_STATE(stcb_tmp) == SCTP_STATE_COOKIE_WAIT) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
/* in setup state we abort this guy */
+ SCTP_SNPRINTF(msg, sizeof(msg),
+ "%s:%d at %s", __FILE__, __LINE__, __func__);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
sctp_abort_an_association(stcb_tmp->sctp_ep,
- stcb_tmp, NULL, SCTP_SO_NOT_LOCKED);
+ stcb_tmp, op_err,
+ SCTP_SO_NOT_LOCKED);
goto add_it_now6;
}
- SCTP_TCB_UNLOCK(stcb_tmp);
-
+ SCTP_TCB_UNLOCK(stcb_tmp);
+ }
if (stcb->asoc.state == 0) {
/* the assoc was freed? */
return (-21);
@@ -7418,7 +7324,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&lstore,
- min(plen,sizeof(lstore)));
+ plen);
if (phdr == NULL) {
return (-24);
}
@@ -7471,8 +7377,11 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
int num_ent, i;
+ if (plen > sizeof(local_store)) {
+ return (-35);
+ }
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&local_store, min(sizeof(local_store),plen));
+ (struct sctp_paramhdr *)&local_store, plen);
if (phdr == NULL) {
return (-25);
}
@@ -7501,10 +7410,12 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
case SCTP_AUTHENTICATION:
peer_supports_auth = 1;
break;
+ case SCTP_IDATA:
+ peer_supports_idata = 1;
+ break;
default:
/* one I have not learned yet */
break;
-
}
}
} else if (ptype == SCTP_RANDOM) {
@@ -7516,7 +7427,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)random_store,
- min(sizeof(random_store),plen));
+ plen);
if (phdr == NULL)
return (-26);
p_random = (struct sctp_auth_random *)phdr;
@@ -7539,7 +7450,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)hmacs_store,
- min(plen,sizeof(hmacs_store)));
+ plen);
if (phdr == NULL)
return (-28);
hmacs = (struct sctp_auth_hmac_algo *)phdr;
@@ -7570,7 +7481,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store,
- min(plen,sizeof(chunks_store)));
+ plen);
if (phdr == NULL)
return (-30);
chunks = (struct sctp_auth_chunk_list *)phdr;
@@ -7587,7 +7498,6 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
saw_asconf = 1;
if (chunks->chunk_types[i] == SCTP_ASCONF_ACK)
saw_asconf_ack = 1;
-
}
got_chklist = 1;
} else if ((ptype == SCTP_HEARTBEAT_INFO) ||
@@ -7599,7 +7509,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
(ptype == SCTP_DEL_IP_ADDRESS) ||
(ptype == SCTP_ERROR_CAUSE_IND) ||
(ptype == SCTP_SUCCESS_REPORT)) {
- /* don't care */ ;
+ /* don't care */
} else {
if ((ptype & 0x8000) == 0x0000) {
/*
@@ -7618,8 +7528,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
if (offset >= limit) {
break;
}
- phdr = sctp_get_next_param(m, offset, &parm_buf,
- sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf,
+ sizeof(param_buf));
}
/* Now check to see if we need to purge any addresses */
TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
@@ -7659,6 +7569,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
(peer_supports_reconfig == 0)) {
stcb->asoc.reconfig_supported = 0;
}
+ if ((stcb->asoc.idata_supported == 1) &&
+ (peer_supports_idata == 0)) {
+ stcb->asoc.idata_supported = 0;
+ }
if ((stcb->asoc.nrsack_supported == 1) &&
(peer_supports_nrsack == 0)) {
stcb->asoc.nrsack_supported = 0;
@@ -7690,20 +7604,20 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
/* copy in the RANDOM */
if (p_random != NULL) {
keylen = sizeof(*p_random) + random_len;
- bcopy(p_random, new_key->key, keylen);
+ memcpy(new_key->key, p_random, keylen);
} else {
keylen = 0;
}
/* append in the AUTH chunks */
if (chunks != NULL) {
- bcopy(chunks, new_key->key + keylen,
- sizeof(*chunks) + num_chunks);
+ memcpy(new_key->key + keylen, chunks,
+ sizeof(*chunks) + num_chunks);
keylen += sizeof(*chunks) + num_chunks;
}
/* append in the HMACs */
if (hmacs != NULL) {
- bcopy(hmacs, new_key->key + keylen,
- sizeof(*hmacs) + hmacs_len);
+ memcpy(new_key->key + keylen, hmacs,
+ sizeof(*hmacs) + hmacs_len);
}
} else {
/* failed to get memory for the key */
@@ -7837,7 +7751,7 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
struct sctp_association *asoc;
struct sctp_tmit_chunk *chk, *nchk;
uint32_t cumulative_tsn_p1;
- struct sctp_queued_to_read *ctl, *nctl;
+ struct sctp_queued_to_read *control, *ncontrol;
int cnt, strmat;
uint32_t gap, i;
int fnd = 0;
@@ -7852,41 +7766,126 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
SCTP_STAT_INCR(sctps_protocol_drains_done);
cumulative_tsn_p1 = asoc->cumulative_tsn + 1;
cnt = 0;
- /* First look in the re-assembly queue */
- TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
- if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumulative_tsn_p1)) {
- /* Yep it is above cum-ack */
- cnt++;
- SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn);
- asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
- sctp_ucount_decr(asoc->cnt_on_reasm_queue);
- SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- }
- }
/* Ok that was fun, now we will drain all the inbound streams? */
for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
- TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next, nctl) {
- if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
+ TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].inqueue, next_instrm, ncontrol) {
+#ifdef INVARIANTS
+ if (control->on_strm_q != SCTP_ON_ORDERED) {
+ panic("Huh control: %p on_q: %d -- not ordered?",
+ control, control->on_strm_q);
+ }
+#endif
+ if (SCTP_TSN_GT(control->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
- SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn);
- asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
+ SCTP_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn);
+ KASSERT(control->length > 0, ("control has zero length"));
+ 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
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next);
- if (ctl->data) {
- sctp_m_freem(ctl->data);
- ctl->data = NULL;
+ if (control->on_read_q) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
+ control->on_read_q = 0;
}
- sctp_free_remote_addr(ctl->whoFrom);
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl);
- SCTP_DECR_READQ_COUNT();
+ TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_free_remote_addr(control->whoFrom);
+ /* Now its reasm? */
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
+ cnt++;
+ SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn);
+ KASSERT(chk->send_size > 0, ("chunk has zero length"));
+ if (asoc->size_on_reasm_queue >= chk->send_size) {
+ asoc->size_on_reasm_queue -= chk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_reasm_queue);
+ SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ }
+ sctp_free_a_readq(stcb, control);
+ }
+ }
+ TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].uno_inqueue, next_instrm, ncontrol) {
+#ifdef INVARIANTS
+ if (control->on_strm_q != SCTP_ON_UNORDERED) {
+ panic("Huh control: %p on_q: %d -- not unordered?",
+ control, control->on_strm_q);
+ }
+#endif
+ if (SCTP_TSN_GT(control->sinfo_tsn, cumulative_tsn_p1)) {
+ /* Yep it is above cum-ack */
+ cnt++;
+ SCTP_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn);
+ KASSERT(control->length > 0, ("control has zero length"));
+ 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
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
+ if (control->on_read_q) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
+ control->on_read_q = 0;
+ }
+ TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_free_remote_addr(control->whoFrom);
+ /* Now its reasm? */
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
+ cnt++;
+ SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn);
+ KASSERT(chk->send_size > 0, ("chunk has zero length"));
+ if (asoc->size_on_reasm_queue >= chk->send_size) {
+ asoc->size_on_reasm_queue -= chk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_reasm_queue);
+ SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ }
+ sctp_free_a_readq(stcb, control);
}
}
}
@@ -7926,7 +7925,8 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
* asoc->highest_tsn_inside_map?
*/
asoc->last_revoke_count = cnt;
- (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_11);
/*sa_ignore NO_NULL_CHK*/
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN, SCTP_SO_NOT_LOCKED);
@@ -7950,7 +7950,7 @@ sctp_drain()
* is LOW on MBUF's and needs help. This is where reneging will
* occur. We really hope this does NOT happen!
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
VNET_ITERATOR_DECL(vnet_iter);
#else
struct sctp_inpcb *inp;
@@ -7961,7 +7961,7 @@ sctp_drain()
return;
}
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
VNET_LIST_RLOCK_NOSLEEP();
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
@@ -7969,7 +7969,7 @@ sctp_drain()
struct sctp_tcb *stcb;
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
SCTP_STAT_INCR(sctps_protocol_drain_calls);
if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
#ifdef VIMAGE
@@ -7992,7 +7992,7 @@ sctp_drain()
SCTP_INP_RUNLOCK(inp);
}
SCTP_INP_INFO_RUNLOCK();
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_RESTORE();
}
VNET_LIST_RUNLOCK_NOSLEEP();
@@ -8026,11 +8026,16 @@ sctp_initiate_iterator(inp_func inpf,
if (af == NULL) {
return (-1);
}
+ if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
+ SCTP_PRINTF("%s: abort on initialize being %d\n", __func__,
+ SCTP_BASE_VAR(sctp_pcb_initialized));
+ return (-1);
+ }
SCTP_MALLOC(it, struct sctp_iterator *, sizeof(struct sctp_iterator),
SCTP_M_ITER);
if (it == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM);
- return (ENOMEM);
+ return (-1);
}
memset(it, 0, sizeof(*it));
it->function_assoc = af;
@@ -8047,7 +8052,7 @@ sctp_initiate_iterator(inp_func inpf,
it->asoc_state = asoc_state;
it->function_inp_end = inpe;
it->no_chunk_output = chunk_output_off;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
it->vn = curvnet;
#endif
if (s_inp) {
@@ -8063,10 +8068,15 @@ sctp_initiate_iterator(inp_func inpf,
}
SCTP_INP_INFO_RUNLOCK();
it->iterator_flags = SCTP_ITERATOR_DO_ALL_INP;
-
}
SCTP_IPI_ITERATOR_WQ_LOCK();
-
+ if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ SCTP_PRINTF("%s: rollback on initialize being %d it=%p\n", __func__,
+ SCTP_BASE_VAR(sctp_pcb_initialized), it);
+ SCTP_FREE(it, SCTP_M_ITER);
+ return (-1);
+ }
TAILQ_INSERT_TAIL(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
if (sctp_it_ctl.iterator_running == 0) {
sctp_wakeup_iterator();
diff --git a/netwerk/sctp/src/netinet/sctp_pcb.h b/netwerk/sctp/src/netinet/sctp_pcb.h
index cab584bb47..0382430d22 100755
--- a/netwerk/sctp/src/netinet/sctp_pcb.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 279859 2015-03-10 19:49:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_PCB_H_
@@ -109,7 +111,7 @@ struct sctp_ifa {
* appropriate locks. This is for V6.
*/
union sctp_sockstore address;
- uint32_t refcount; /* number of folks refering to this */
+ uint32_t refcount; /* number of folks referring to this */
uint32_t flags;
uint32_t localifa_flags;
uint32_t vrf_id; /* vrf_id of this addr (for deleting) */
@@ -145,9 +147,8 @@ struct sctp_tagblock {
struct sctp_timewait vtag_block[SCTP_NUMBER_IN_VTAG_BLOCK];
};
-
struct sctp_epinfo {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#ifdef INET
struct socket *udp4_tun_socket;
#endif
@@ -187,7 +188,7 @@ struct sctp_epinfo {
struct sctppcbhead listhead;
struct sctpladdr addr_wq;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct inpcbhead inplisthead;
struct inpcbinfo sctbinfo;
#endif
@@ -202,18 +203,10 @@ struct sctp_epinfo {
sctp_zone_t ipi_zone_asconf;
sctp_zone_t ipi_zone_asconf_ack;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 503000
-#if __FreeBSD_version <= 602000
- struct mtx ipi_ep_mtx;
-#else
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct rwlock ipi_ep_mtx;
-#endif
struct mtx ipi_iterator_wq_mtx;
-#if __FreeBSD_version <= 602000
- struct mtx ipi_addr_mtx;
-#else
struct rwlock ipi_addr_mtx;
-#endif
struct mtx ipi_pktlog_mtx;
struct mtx wq_addr_mtx;
#elif defined(SCTP_PROCESS_LEVEL_LOCKS)
@@ -222,7 +215,7 @@ struct sctp_epinfo {
userland_mutex_t ipi_count_mtx;
userland_mutex_t ipi_pktlog_mtx;
userland_mutex_t wq_addr_mtx;
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
#ifdef _KERN_LOCKS_H_
lck_mtx_t *ipi_addr_mtx;
lck_mtx_t *ipi_count_mtx;
@@ -233,13 +226,12 @@ struct sctp_epinfo {
void *ipi_count_mtx;
void *logging_mtx;
#endif /* _KERN_LOCKS_H_ */
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
struct rwlock ipi_ep_lock;
struct rwlock ipi_addr_lock;
struct spinlock ipi_pktlog_mtx;
struct rwlock wq_addr_mtx;
#elif defined(__Userspace__)
- /* TODO decide on __Userspace__ locks */
#endif
uint32_t ipi_count_ep;
@@ -284,17 +276,20 @@ struct sctp_epinfo {
#endif
};
-
struct sctp_base_info {
/* All static structures that
* anchor the system must be here.
*/
struct sctp_epinfo sctppcbinfo;
-#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
struct sctpstat *sctpstat;
#else
struct sctpstat sctpstat;
#endif
+#else
+ struct sctpstat sctpstat;
+#endif
struct sctp_sysctl sctpsysctl;
uint8_t first_time;
char sctp_pcb_initialized;
@@ -303,33 +298,50 @@ struct sctp_base_info {
int packet_log_end;
uint8_t packet_log_buffer[SCTP_PACKET_LOG_SIZE];
#endif
-#if defined(__APPLE__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ eventhandler_tag eh_tag;
+#endif
+#if defined(__APPLE__) && !defined(__Userspace__)
int sctp_main_timer_ticks;
#endif
#if defined(__Userspace__)
userland_mutex_t timer_mtx;
userland_thread_t timer_thread;
- uint8_t timer_thread_should_exit;
-#if !defined(__Userspace_os_Windows)
+ int timer_thread_should_exit;
+ int iterator_thread_started;
+ int timer_thread_started;
+#if !defined(_WIN32)
+ pthread_mutexattr_t mtx_attr;
#if defined(INET) || defined(INET6)
int userspace_route;
userland_thread_t recvthreadroute;
#endif
#endif
#ifdef INET
+#if defined(_WIN32) && !defined(__MINGW32__)
+ SOCKET userspace_rawsctp;
+ SOCKET userspace_udpsctp;
+#else
int userspace_rawsctp;
int userspace_udpsctp;
+#endif
userland_thread_t recvthreadraw;
userland_thread_t recvthreadudp;
#endif
#ifdef INET6
+#if defined(_WIN32) && !defined(__MINGW32__)
+ SOCKET userspace_rawsctp6;
+ SOCKET userspace_udpsctp6;
+#else
int userspace_rawsctp6;
int userspace_udpsctp6;
+#endif
userland_thread_t recvthreadraw6;
userland_thread_t recvthreadudp6;
#endif
int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df);
void (*debug_printf)(const char *format, ...);
+ int crc32c_offloaded;
#endif
};
@@ -344,11 +356,11 @@ struct sctp_pcb {
uint32_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_NUMBER_OF_SECRETS];
unsigned int size_of_a_cookie;
- unsigned int sctp_timeoutticks[SCTP_NUM_TMRS];
- unsigned int sctp_minrto;
- unsigned int sctp_maxrto;
- unsigned int initial_rto;
- int initial_init_rto_max;
+ uint32_t sctp_timeoutticks[SCTP_NUM_TMRS];
+ uint32_t sctp_minrto;
+ uint32_t sctp_maxrto;
+ uint32_t initial_rto;
+ uint32_t initial_init_rto_max;
unsigned int sctp_sack_freq;
uint32_t sctp_sws_sender;
@@ -361,6 +373,7 @@ struct sctp_pcb {
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 */
@@ -388,13 +401,9 @@ struct sctp_pcb {
*/
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;
+ uint32_t auto_close_time;
uint32_t initial_sequence_debug;
uint32_t adaptation_layer_indicator;
uint8_t adaptation_layer_indicator_provided;
@@ -429,19 +438,17 @@ struct sctp_pcbtsn_rlog {
};
#define SCTP_READ_LOG_SIZE 135 /* we choose the number to make a pcb a page */
-
struct sctp_inpcb {
/*-
* put an inpcb in front of it all, kind of a waste but we need to
- * for compatability with all the other stuff.
+ * for compatibility with all the other stuff.
*/
union {
struct inpcb inp;
- char align[(sizeof(struct in6pcb) + SCTP_ALIGNM1) &
+ char align[(sizeof(struct inpcb) + SCTP_ALIGNM1) &
~SCTP_ALIGNM1];
} ip_inp;
-
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
/* leave some space in case i386 inpcb is bigger than ppc */
uint8_t padding[128];
#endif
@@ -450,7 +457,7 @@ struct sctp_inpcb {
struct sctp_readhead read_queue;
LIST_ENTRY(sctp_inpcb) sctp_list; /* lists all endpoints */
- /* hash of all endpoints for model */
+ /* hash of all endpoints for model */
LIST_ENTRY(sctp_inpcb) sctp_hash;
/* count of local addresses bound, 0 if bound all */
int laddr_count;
@@ -484,6 +491,7 @@ struct sctp_inpcb {
uint8_t ecn_supported;
uint8_t prsctp_supported;
uint8_t auth_supported;
+ uint8_t idata_supported;
uint8_t asconf_supported;
uint8_t reconfig_supported;
uint8_t nrsack_supported;
@@ -497,26 +505,9 @@ struct sctp_inpcb {
* they are candidates with sctp_sendm for
* de-supporting.
*/
-#ifdef __Panda__
- pakhandle_type pak_to_read;
- pakhandle_type pak_to_read_sendq;
-#endif
struct mbuf *pkt, *pkt_last;
struct mbuf *control;
-#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__))
-#ifndef INP_IPV6
-#define INP_IPV6 0x1
-#endif
-#ifndef INP_IPV4
-#define INP_IPV4 0x2
-#endif
- uint8_t inp_vflag;
- /* TODO __Userspace__ where is our inp_vlag going to be? */
- uint8_t inp_ip_ttl;
- uint8_t inp_ip_tos; /* defined as macro in user_inpcb.h */
- uint8_t inp_ip_resv;
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 503000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct mtx inp_mtx;
struct mtx inp_create_mtx;
struct mtx inp_rdata_mtx;
@@ -526,7 +517,7 @@ struct sctp_inpcb {
userland_mutex_t inp_create_mtx;
userland_mutex_t inp_rdata_mtx;
int32_t refcount;
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
#if defined(SCTP_APPLE_RWLOCK)
lck_rw_t *inp_mtx;
#else
@@ -534,16 +525,15 @@ struct sctp_inpcb {
#endif
lck_mtx_t *inp_create_mtx;
lck_mtx_t *inp_rdata_mtx;
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
struct rwlock inp_lock;
struct spinlock inp_create_lock;
struct spinlock inp_rdata_lock;
int32_t refcount;
#elif defined(__Userspace__)
- /* TODO decide on __Userspace__ locks */
int32_t refcount;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
int32_t refcount;
uint32_t lock_caller1;
@@ -564,6 +554,7 @@ struct sctp_inpcb {
uint32_t i_am_here_line;
#endif
uint32_t def_vrf_id;
+ uint16_t fibnum;
#ifdef SCTP_MVRF
uint32_t *m_vrf_ids;
uint32_t num_vrfs;
@@ -586,7 +577,7 @@ struct sctp_inpcb {
int (*recv_callback)(struct socket *, union sctp_sockstore, void *, size_t,
struct sctp_rcvinfo, int, void *);
uint32_t send_sb_threshold;
- int (*send_callback)(struct socket *, uint32_t);
+ int (*send_callback)(struct socket *, uint32_t, void *);
#endif
};
@@ -594,8 +585,9 @@ struct sctp_inpcb {
int register_recv_cb (struct socket *,
int (*)(struct socket *, union sctp_sockstore, void *, size_t,
struct sctp_rcvinfo, int, void *));
-int register_send_cb (struct socket *, uint32_t, int (*)(struct socket *, uint32_t));
+int register_send_cb (struct socket *, uint32_t, int (*)(struct socket *, uint32_t, void *));
int register_ulp_info (struct socket *, void *);
+int retrieve_ulp_info (struct socket *, void **);
#endif
struct sctp_tcb {
@@ -623,34 +615,30 @@ struct sctp_tcb {
int freed_from_where;
uint16_t rport; /* remote port in network format */
uint16_t resv;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 503000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct mtx tcb_mtx;
struct mtx tcb_send_mtx;
#elif defined(SCTP_PROCESS_LEVEL_LOCKS)
userland_mutex_t tcb_mtx;
userland_mutex_t tcb_send_mtx;
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
lck_mtx_t* tcb_mtx;
lck_mtx_t* tcb_send_mtx;
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
struct spinlock tcb_lock;
struct spinlock tcb_send_lock;
#elif defined(__Userspace__)
- /* TODO decide on __Userspace__ locks */
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
uint32_t caller1;
uint32_t caller2;
uint32_t caller3;
#endif
};
-
-#if defined(__FreeBSD__) && __FreeBSD_version >= 503000
-
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <netinet/sctp_lock_bsd.h>
-
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
/*
* Apple MacOS X 10.4 "Tiger"
*/
@@ -661,7 +649,7 @@ struct sctp_tcb {
#include <netinet/sctp_process_lock.h>
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
#include <netinet/sctp_lock_windows.h>
@@ -676,15 +664,14 @@ struct sctp_tcb {
#include <netinet/sctp_lock_empty.h>
#endif
-/* TODO where to put non-_KERNEL things for __Userspace__? */
#if defined(_KERNEL) || defined(__Userspace__)
/* Attention Julian, this is the extern that
* goes with the base info. sctp_pcb.c has
* the real definition.
*/
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
-VNET_DECLARE(struct sctp_base_info, system_base_info) ;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+VNET_DECLARE(struct sctp_base_info, system_base_info);
#else
extern struct sctp_base_info system_base_info;
#endif
@@ -726,20 +713,17 @@ void sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu);
void sctp_free_ifn(struct sctp_ifn *sctp_ifnp);
void sctp_free_ifa(struct sctp_ifa *sctp_ifap);
-
void sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
uint32_t ifn_index, const char *if_name);
-
-
struct sctp_nets *sctp_findnet(struct sctp_tcb *, struct sockaddr *);
struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, int, uint32_t);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int sctp_inpcb_bind(struct socket *, struct sockaddr *,
struct sctp_ifa *,struct thread *);
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
int sctp_inpcb_bind(struct socket *, struct sockaddr *,
struct sctp_ifa *,PKTHREAD);
#else
@@ -790,24 +774,28 @@ int sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id);
void sctp_inpcb_free(struct sctp_inpcb *, int, int);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#define SCTP_DONT_INITIALIZE_AUTH_PARAMS 0
+#define SCTP_INITIALIZE_AUTH_PARAMS 1
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
- int *, uint32_t, uint32_t, struct thread *);
-#elif defined(__Windows__)
+ int *, uint32_t, uint32_t, uint16_t, uint16_t, struct thread *,
+ int);
+#elif defined(_WIN32) && !defined(__Userspace__)
struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
- int *, uint32_t, uint32_t, PKTHREAD);
+ int *, uint32_t, uint32_t, uint16_t, uint16_t, PKTHREAD, int);
#else
/* proc will be NULL for __Userspace__ */
struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
- int *, uint32_t, uint32_t, struct proc *);
+ int *, uint32_t, uint32_t, uint16_t, uint16_t, struct proc *,
+ int);
#endif
int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int);
-
void sctp_delete_from_timewait(uint32_t, uint16_t, uint16_t);
int sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport);
@@ -817,19 +805,19 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t
void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t);
-int sctp_insert_laddr(struct sctpladdr *, struct sctp_ifa *, uint32_t);
-
-void sctp_remove_laddr(struct sctp_laddr *);
-
void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *);
-int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int);
+int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, uint16_t, int, int);
void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *);
int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *);
+#if defined(__Userspace__)
+void sctp_pcb_init(int);
+#else
void sctp_pcb_init(void);
+#endif
void sctp_pcb_finish(void);
@@ -838,7 +826,7 @@ void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
int
sctp_load_addresses_from_init(struct sctp_tcb *, struct mbuf *, int, int,
- struct sockaddr *, struct sockaddr *, struct sockaddr *);
+ struct sockaddr *, struct sockaddr *, struct sockaddr *, uint16_t);
int
sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *,
@@ -846,11 +834,14 @@ sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *,
int sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *);
+/* void sctp_drain(void); */
int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *);
int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp);
+void sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh);
+
/*-
* Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg
* indicates run on ONLY assoc's of the specified endpoint.
@@ -865,15 +856,12 @@ sctp_initiate_iterator(inp_func inpf,
end_func ef,
struct sctp_inpcb *,
uint8_t co_off);
-#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_MCORE_INPUT) && defined(SMP)
void
sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use);
#endif
-
-#ifdef INVARIANTS
-void
-sctp_validate_no_locks(struct sctp_inpcb *inp);
#endif
#endif /* _KERNEL */
diff --git a/netwerk/sctp/src/netinet/sctp_peeloff.c b/netwerk/sctp/src/netinet/sctp_peeloff.c
index 7f21f86f98..8581f515f4 100755
--- a/netwerk/sctp/src/netinet/sctp_peeloff.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.c 279859 2015-03-10 19:49:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.c 362054 2020-06-11 13:34:09Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -47,10 +49,6 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.c 279859 2015-03-10 19:49:25Z
#include <netinet/sctputil.h>
#include <netinet/sctp_auth.h>
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 5
-#endif
-
int
sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
{
@@ -77,7 +75,7 @@ sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOENT);
return (ENOENT);
}
- state = SCTP_GET_STATE((&stcb->asoc));
+ state = SCTP_GET_STATE(stcb);
if ((state == SCTP_STATE_EMPTY) ||
(state == SCTP_STATE_INUSE)) {
SCTP_TCB_UNLOCK(stcb);
@@ -107,7 +105,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
return (ENOTCONN);
}
- state = SCTP_GET_STATE((&stcb->asoc));
+ state = SCTP_GET_STATE(stcb);
if ((state == SCTP_STATE_EMPTY) ||
(state == SCTP_STATE_INUSE)) {
SCTP_TCB_UNLOCK(stcb);
@@ -162,7 +160,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT);
#else
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
@@ -176,14 +174,6 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
struct socket *
sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
{
-#if defined(__Userspace__)
- /* if __Userspace__ chooses to originally not support peeloff, put it here... */
-#endif
-#if defined(__Panda__)
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EINVAL);
- *error = EINVAL;
- return (NULL);
-#else
struct socket *newso;
struct sctp_inpcb *inp, *n_inp;
struct sctp_tcb *stcb;
@@ -203,18 +193,15 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
}
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_SET(head->so_vnet);
#endif
newso = sonewconn(head, SS_ISCONNECTED
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
, NULL
-#elif defined(__Panda__)
- /* place this socket in the assoc's vrf id */
- , NULL, stcb->asoc.vrf_id
#endif
);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_RESTORE();
#endif
if (newso == NULL) {
@@ -225,7 +212,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
return (NULL);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
else {
SCTP_SOCKET_LOCK(newso, 1);
}
@@ -277,14 +264,15 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE);
n_inp->sctp_ep.auto_close_time = 0;
sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, n_inp, stcb, NULL,
- SCTP_FROM_SCTP_PEELOFF+SCTP_LOC_1);
+ 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__)
#ifdef SCTP_LOCK_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
@@ -293,34 +281,23 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
TAILQ_REMOVE(&head->so_comp, newso, so_list);
head->so_qlen--;
SOCK_UNLOCK(head);
-#else
- 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);
- *error = ENOTCONN;
- return (NULL);
-
- }
-#endif
/*
* 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);
/*
* And now the final hack. We move data in the pending side i.e.
* head to the new socket buffer. Let the GRUBBING begin :-0
*/
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT);
#else
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
#endif
atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (newso);
-#endif
}
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_peeloff.h b/netwerk/sctp/src/netinet/sctp_peeloff.h
index 69f48065cd..7e1c5eceeb 100755
--- a/netwerk/sctp/src/netinet/sctp_peeloff.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.h 243516 2012-11-25 14:25:08Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.h 309607 2016-12-06 10:21:25Z tuexen $");
#endif
#ifndef _NETINET_SCTP_PEELOFF_H_
@@ -40,13 +42,13 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.h 243516 2012-11-25 14:25:08Z
#if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
/* socket option peeloff */
struct sctp_peeloff_opt {
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
int s;
#else
HANDLE s;
#endif
sctp_assoc_t assoc_id;
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
int new_sd;
#else
HANDLE new_sd;
diff --git a/netwerk/sctp/src/netinet/sctp_process_lock.h b/netwerk/sctp/src/netinet/sctp_process_lock.h
index 1d109857a2..ff0e05048e 100755
--- a/netwerk/sctp/src/netinet/sctp_process_lock.h
+++ b/netwerk/sctp/src/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.
@@ -51,7 +53,7 @@
* per socket level locking
*/
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
/* Lock for INFO stuff */
#define SCTP_INP_INFO_LOCK_INIT()
#define SCTP_INP_INFO_RLOCK()
@@ -84,7 +86,9 @@
#define SCTP_INP_RLOCK(_inp)
#define SCTP_INP_RUNLOCK(_inp)
#define SCTP_INP_WLOCK(_inp)
-#define SCTP_INP_WUNLOCK(_inep)
+#define SCTP_INP_WUNLOCK(_inp)
+#define SCTP_INP_RLOCK_ASSERT(_inp)
+#define SCTP_INP_WLOCK_ASSERT(_inp)
#define SCTP_INP_INCR_REF(_inp)
#define SCTP_INP_DECR_REF(_inp)
@@ -113,16 +117,16 @@
*/
#define SCTP_IPI_COUNT_INIT()
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#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_WQ_ADDR_LOCK_ASSERT()
#define SCTP_INP_INFO_LOCK_INIT() \
InitializeCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx))
@@ -131,20 +135,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 +168,53 @@
#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_INP_RLOCK_ASSERT(_tcb)
+#define SCTP_INP_WLOCK_ASSERT(_tcb)
#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 +234,83 @@
#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_WQ_ADDR_LOCK_ASSERT() \
+ KASSERT(pthread_mutex_trylock(&SCTP_BASE_INFO(wq_addr_mtx)) == EBUSY, ("%s: wq_addr_mtx not locked", __func__))
#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 +319,124 @@
* 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); \
+#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_INP_RLOCK(_inp) do { \
- (void)pthread_mutex_lock(&(_inp)->inp_mtx); \
+#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 { \
- (void)pthread_mutex_lock(&(_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); \
+ (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_RLOCK_ASSERT(_inp) \
+ KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s: inp_mtx not locked", __func__))
+#define SCTP_INP_WLOCK_ASSERT(_inp) \
+ KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s: inp_mtx not locked", __func__))
+#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, NULL)
-
+ (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)
-
-#define SCTP_TCB_SEND_LOCK(_tcb) do { \
- (void)pthread_mutex_lock(&(_tcb)->tcb_send_mtx); \
-} while (0)
-
+#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_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) \
+ (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, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \
- (void)pthread_mutex_lock(&(_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); \
+ 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) do { \
- (void)pthread_mutex_lock(&(_inp)->inp_create_mtx); \
+#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_INP_RUNLOCK(_inp) \
- (void)pthread_mutex_unlock(&(_inp)->inp_mtx)
-#define SCTP_INP_WUNLOCK(_inp) \
- (void)pthread_mutex_unlock(&(_inp)->inp_mtx)
#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 +446,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); \
+#define SCTP_TCB_LOCK(_tcb) \
+ KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__))
+#endif
+#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_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) (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 +492,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)
+#if defined(_WIN32)
#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)
-#endif
+#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 SOCK_LOCK(_so)
-#define SOCK_UNLOCK(_so)
-#define SOCKBUF_LOCK(_so_buf)
-#define SOCKBUF_UNLOCK(_so_buf)
-#define SOCKBUF_LOCK_ASSERT(_so_buf)
+#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
+#define SOCK_LOCK(_so) \
+ SOCKBUF_LOCK(&(_so)->so_rcv)
+#define SOCK_UNLOCK(_so) \
+ SOCKBUF_UNLOCK(&(_so)->so_rcv)
#endif
#define SCTP_STATLOG_INIT_LOCK()
@@ -464,179 +529,149 @@
#define SCTP_STATLOG_UNLOCK()
#define SCTP_STATLOG_DESTROY()
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
/* address list locks */
#define SCTP_IPI_ADDR_INIT() \
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))
+#define SCTP_IPI_ADDR_LOCK_ASSERT()
+#define SCTP_IPI_ADDR_WLOCK_ASSERT()
/* 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_UNLOCK() \
- LeaveCriticalSection(&sctp_it_ctl.it_mtx)
-
#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_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 */
+#else
/* 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__))
+#define SCTP_IPI_ADDR_LOCK_ASSERT() \
+ KASSERT(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_addr_mtx)) == EBUSY, ("%s: ipi_addr_mtx not locked", __func__))
+#define SCTP_IPI_ADDR_WLOCK_ASSERT() \
+ KASSERT(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_addr_mtx)) == EBUSY, ("%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))
-
+#define SCTP_IPI_ADDR_LOCK_ASSERT()
+#define SCTP_IPI_ADDR_WLOCK_ASSERT()
+#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/netwerk/sctp/src/netinet/sctp_sha1.c b/netwerk/sctp/src/netinet/sctp_sha1.c
index c86517f91c..db0e7533ff 100755
--- a/netwerk/sctp/src/netinet/sctp_sha1.c
+++ b/netwerk/sctp/src/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.
@@ -82,9 +84,9 @@ sctp_sha1_final(unsigned char *digest, struct sctp_sha1_context *ctx)
#else
#include <string.h>
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32) && defined(__Userspace__)
#include <winsock2.h>
-#elif !defined(__Windows__)
+#elif !(defined(_WIN32) && !defined(__Userspace__))
#include <arpa/inet.h>
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_sha1.h b/netwerk/sctp/src/netinet/sctp_sha1.h
index 01e3c2edc4..d535ee4639 100755
--- a/netwerk/sctp/src/netinet/sctp_sha1.h
+++ b/netwerk/sctp/src/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.
@@ -30,7 +32,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#endif
@@ -41,16 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#if defined(SCTP_USE_NSS_SHA1)
-#if defined(__Userspace_os_Darwin)
-/* The NSS sources require __APPLE__ to be defined.
- * XXX: Remove this ugly hack once the platform defines have been cleaned up.
- */
-#define __APPLE__
-#endif
#include <pk11pub.h>
-#if defined(__Userspace_os_Darwin)
-#undef __APPLE__
-#endif
#elif defined(SCTP_USE_OPENSSL_SHA1)
#include <openssl/sha.h>
#endif
@@ -81,7 +74,7 @@ struct sctp_sha1_context {
#endif
};
-#if (defined(__APPLE__) && defined(KERNEL))
+#if (defined(__APPLE__) && !defined(__Userspace__) && defined(KERNEL))
#ifndef _KERNEL
#define _KERNEL
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_ss_functions.c b/netwerk/sctp/src/netinet/sctp_ss_functions.c
index d6ccd933a9..431cbf23ae 100755
--- a/netwerk/sctp/src/netinet/sctp_ss_functions.c
+++ b/netwerk/sctp/src/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.
@@ -26,9 +28,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 235828 2012-05-23 11:26:28Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 365071 2020-09-01 21:19:14Z mjg $");
#endif
#include <netinet/sctp_pcb.h>
@@ -57,7 +59,12 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
{
uint16_t i;
- TAILQ_INIT(&asoc->ss_data.out_wheel);
+ if (holds_lock == 0) {
+ SCTP_TCB_SEND_LOCK(stcb);
+ }
+ asoc->ss_data.locked_on_sending = NULL;
+ asoc->ss_data.last_out_stream = NULL;
+ TAILQ_INIT(&asoc->ss_data.out.wheel);
/*
* If there is data in the stream queues already,
* the scheduler of an existing association has
@@ -67,7 +74,10 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
&stcb->asoc.strmout[i],
- NULL, holds_lock);
+ NULL, 1);
+ }
+ if (holds_lock == 0) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
}
return;
}
@@ -79,13 +89,15 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (holds_lock == 0) {
SCTP_TCB_SEND_LOCK(stcb);
}
- while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.rr.next_spoke);
+ while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ struct sctp_stream_out *strq;
+
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
strq->ss_params.rr.next_spoke.tqe_next = NULL;
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
}
- asoc->last_out_stream = NULL;
+ asoc->ss_data.last_out_stream = NULL;
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
}
@@ -93,8 +105,16 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq SCTP_UNUSED)
+sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
{
+ if (with_strq != NULL) {
+ if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ }
+ if (stcb->asoc.ss_data.last_out_stream == with_strq) {
+ stcb->asoc.ss_data.last_out_stream = strq;
+ }
+ }
strq->ss_params.rr.next_spoke.tqe_next = NULL;
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
return;
@@ -112,7 +132,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (!TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
(strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel,
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
strq, ss_params.rr.next_spoke);
}
if (holds_lock == 0) {
@@ -124,7 +144,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
static int
sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
{
- if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
+ if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
return (1);
} else {
return (0);
@@ -143,19 +163,19 @@ sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.rr.next_spoke.tqe_next != NULL ||
strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream,
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
sctpwheel_listhead,
ss_params.rr.next_spoke);
- if (asoc->last_out_stream == NULL) {
- asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
+ if (asoc->ss_data.last_out_stream == NULL) {
+ asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
sctpwheel_listhead);
}
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = NULL;
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = NULL;
}
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
strq->ss_params.rr.next_spoke.tqe_next = NULL;
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
}
@@ -165,22 +185,24 @@ sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
return;
}
-
static struct sctp_stream_out *
sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
struct sctp_association *asoc)
{
struct sctp_stream_out *strq, *strqt;
- strqt = asoc->last_out_stream;
+ if (asoc->ss_data.locked_on_sending) {
+ return (asoc->ss_data.locked_on_sending);
+ }
+ strqt = asoc->ss_data.last_out_stream;
default_again:
/* Find the next stream to use */
if (strqt == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
if (strq == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
@@ -200,7 +222,7 @@ default_again:
if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
- if (strq == asoc->last_out_stream) {
+ if (strq == asoc->ss_data.last_out_stream) {
return (NULL);
} else {
strqt = strq;
@@ -212,11 +234,25 @@ default_again:
}
static void
-sctp_ss_default_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
- struct sctp_association *asoc SCTP_UNUSED,
- struct sctp_stream_out *strq, int moved_how_much SCTP_UNUSED)
+sctp_ss_default_scheduled(struct sctp_tcb *stcb,
+ struct sctp_nets *net SCTP_UNUSED,
+ struct sctp_association *asoc,
+ struct sctp_stream_out *strq,
+ int moved_how_much SCTP_UNUSED)
{
- asoc->last_out_stream = strq;
+ struct sctp_stream_queue_pending *sp;
+
+ asoc->ss_data.last_out_stream = strq;
+ if (stcb->asoc.idata_supported == 0) {
+ sp = TAILQ_FIRST(&strq->outqueue);
+ if ((sp != NULL) && (sp->some_taken == 1)) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
return;
}
@@ -244,6 +280,26 @@ sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_associa
return (-1);
}
+static int
+sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
+{
+ struct sctp_stream_out *strq;
+ struct sctp_stream_queue_pending *sp;
+
+ if (asoc->stream_queue_cnt != 1) {
+ return (0);
+ }
+ strq = asoc->ss_data.locked_on_sending;
+ if (strq == NULL) {
+ return (0);
+ }
+ sp = TAILQ_FIRST(&strq->outqueue);
+ if (sp == NULL) {
+ return (0);
+ }
+ return (!sp->msg_is_complete);
+}
+
/*
* Real round-robin algorithm.
* Always interates the streams in ascending order.
@@ -261,17 +317,17 @@ sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (!TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
(strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
- if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
+ if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
} else {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
- while (strqt != NULL && (strqt->stream_no < strq->stream_no)) {
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
+ while (strqt != NULL && (strqt->sid < strq->sid)) {
strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
}
if (strqt != NULL) {
TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
} else {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
}
}
}
@@ -290,7 +346,7 @@ static struct sctp_stream_out *
sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
struct sctp_association *asoc)
{
- return (asoc->last_out_stream);
+ return (asoc->ss_data.last_out_stream);
}
static void
@@ -299,15 +355,15 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net
{
struct sctp_stream_out *strq, *strqt;
- strqt = asoc->last_out_stream;
+ strqt = asoc->ss_data.last_out_stream;
rrp_again:
/* Find the next stream to use */
if (strqt == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
if (strq == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
@@ -327,7 +383,7 @@ rrp_again:
if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
- if (strq == asoc->last_out_stream) {
+ if (strq == asoc->ss_data.last_out_stream) {
strq = NULL;
} else {
strqt = strq;
@@ -335,11 +391,10 @@ rrp_again:
}
}
}
- asoc->last_out_stream = strq;
+ asoc->ss_data.last_out_stream = strq;
return;
}
-
/*
* Priority algorithm.
* Always prefers streams based on their priority id.
@@ -351,17 +406,18 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (holds_lock == 0) {
SCTP_TCB_SEND_LOCK(stcb);
}
- while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ struct sctp_stream_out *strq;
+
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
if (clear_values) {
strq->ss_params.prio.priority = 0;
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.prio.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
strq->ss_params.prio.next_spoke.tqe_next = NULL;
strq->ss_params.prio.next_spoke.tqe_prev = NULL;
-
}
- asoc->last_out_stream = NULL;
+ asoc->ss_data.last_out_stream = NULL;
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
}
@@ -369,8 +425,16 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_prio_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
+sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
{
+ if (with_strq != NULL) {
+ if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ }
+ if (stcb->asoc.ss_data.last_out_stream == with_strq) {
+ stcb->asoc.ss_data.last_out_stream = strq;
+ }
+ }
strq->ss_params.prio.next_spoke.tqe_next = NULL;
strq->ss_params.prio.next_spoke.tqe_prev = NULL;
if (with_strq != NULL) {
@@ -395,17 +459,17 @@ sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (!TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
(strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
- if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
+ if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
} else {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
}
if (strqt != NULL) {
TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
} else {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
}
}
}
@@ -427,18 +491,18 @@ sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.prio.next_spoke.tqe_next != NULL ||
strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead,
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
ss_params.prio.next_spoke);
- if (asoc->last_out_stream == NULL) {
- asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
+ if (asoc->ss_data.last_out_stream == NULL) {
+ asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
sctpwheel_listhead);
}
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = NULL;
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = NULL;
}
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
strq->ss_params.prio.next_spoke.tqe_next = NULL;
strq->ss_params.prio.next_spoke.tqe_prev = NULL;
}
@@ -454,18 +518,21 @@ sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
{
struct sctp_stream_out *strq, *strqt, *strqn;
- strqt = asoc->last_out_stream;
+ if (asoc->ss_data.locked_on_sending) {
+ return (asoc->ss_data.locked_on_sending);
+ }
+ strqt = asoc->ss_data.last_out_stream;
prio_again:
/* Find the next stream to use */
if (strqt == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
if (strqn != NULL &&
strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
strq = strqn;
} else {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
@@ -485,7 +552,7 @@ prio_again:
if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
- if (strq == asoc->last_out_stream) {
+ if (strq == asoc->ss_data.last_out_stream) {
return (NULL);
} else {
strqt = strq;
@@ -531,16 +598,18 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (holds_lock == 0) {
SCTP_TCB_SEND_LOCK(stcb);
}
- while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ struct sctp_stream_out *strq;
+
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
if (clear_values) {
strq->ss_params.fb.rounds = -1;
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.fb.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
strq->ss_params.fb.next_spoke.tqe_next = NULL;
strq->ss_params.fb.next_spoke.tqe_prev = NULL;
}
- asoc->last_out_stream = NULL;
+ asoc->ss_data.last_out_stream = NULL;
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
}
@@ -548,8 +617,16 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_fb_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
+sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
{
+ if (with_strq != NULL) {
+ if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ }
+ if (stcb->asoc.ss_data.last_out_stream == with_strq) {
+ stcb->asoc.ss_data.last_out_stream = strq;
+ }
+ }
strq->ss_params.fb.next_spoke.tqe_next = NULL;
strq->ss_params.fb.next_spoke.tqe_prev = NULL;
if (with_strq != NULL) {
@@ -573,7 +650,7 @@ sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
(strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
if (strq->ss_params.fb.rounds < 0)
strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -593,18 +670,18 @@ sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.fb.next_spoke.tqe_next != NULL ||
strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead,
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
ss_params.fb.next_spoke);
- if (asoc->last_out_stream == NULL) {
- asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
+ if (asoc->ss_data.last_out_stream == NULL) {
+ asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
sctpwheel_listhead);
}
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = NULL;
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = NULL;
}
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
strq->ss_params.fb.next_spoke.tqe_next = NULL;
strq->ss_params.fb.next_spoke.tqe_prev = NULL;
}
@@ -620,11 +697,14 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
{
struct sctp_stream_out *strq = NULL, *strqt;
- if (asoc->last_out_stream == NULL ||
- TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ if (asoc->ss_data.locked_on_sending) {
+ return (asoc->ss_data.locked_on_sending);
+ }
+ if (asoc->ss_data.last_out_stream == NULL ||
+ TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
- strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke);
+ strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
}
do {
if ((strqt != NULL) &&
@@ -641,22 +721,33 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
if (strqt != NULL) {
strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
} else {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
} while (strqt != strq);
return (strq);
}
static void
-sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
+sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
struct sctp_association *asoc, struct sctp_stream_out *strq,
int moved_how_much SCTP_UNUSED)
{
+ struct sctp_stream_queue_pending *sp;
struct sctp_stream_out *strqt;
int subtract;
+ if (stcb->asoc.idata_supported == 0) {
+ sp = TAILQ_FIRST(&strq->outqueue);
+ if ((sp != NULL) && (sp->some_taken == 1)) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
subtract = strq->ss_params.fb.rounds;
- TAILQ_FOREACH(strqt, &asoc->ss_data.out_wheel, ss_params.fb.next_spoke) {
+ TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
strqt->ss_params.fb.rounds -= subtract;
if (strqt->ss_params.fb.rounds < 0)
strqt->ss_params.fb.rounds = 0;
@@ -666,7 +757,7 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SC
} else {
strq->ss_params.fb.rounds = -1;
}
- asoc->last_out_stream = strq;
+ asoc->ss_data.last_out_stream = strq;
return;
}
@@ -676,8 +767,8 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SC
*/
static void
sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
- struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
- int holds_lock);
+ struct sctp_stream_out *strq SCTP_UNUSED,
+ struct sctp_stream_queue_pending *sp, int holds_lock);
static void
sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
@@ -687,7 +778,10 @@ sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_queue_pending *sp;
uint16_t i;
- TAILQ_INIT(&asoc->ss_data.out_list);
+ if (holds_lock == 0) {
+ SCTP_TCB_SEND_LOCK(stcb);
+ }
+ TAILQ_INIT(&asoc->ss_data.out.list);
/*
* If there is data in the stream queues already,
* the scheduler of an existing association has
@@ -706,12 +800,15 @@ sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
x++;
}
if (sp != NULL) {
- sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, holds_lock);
+ sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
add_more = 1;
}
}
n++;
}
+ if (holds_lock == 0) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
+ }
return;
}
@@ -719,12 +816,17 @@ static void
sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
int clear_values, int holds_lock)
{
+ struct sctp_stream_queue_pending *sp;
+
if (clear_values) {
if (holds_lock == 0) {
SCTP_TCB_SEND_LOCK(stcb);
}
- while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) {
- TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), ss_next);
+ while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
+ sp = TAILQ_FIRST(&asoc->ss_data.out.list);
+ TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
+ sp->ss_next.tqe_next = NULL;
+ sp->ss_next.tqe_prev = NULL;
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -734,9 +836,18 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_fcfs_init_stream(struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_out *with_strq SCTP_UNUSED)
+sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
{
- /* Nothing to be done here */
+ if (with_strq != NULL) {
+ if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ }
+ if (stcb->asoc.ss_data.last_out_stream == with_strq) {
+ stcb->asoc.ss_data.last_out_stream = strq;
+ }
+ }
+ strq->ss_params.fb.next_spoke.tqe_next = NULL;
+ strq->ss_params.fb.next_spoke.tqe_prev = NULL;
return;
}
@@ -750,7 +861,7 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
if (sp && (sp->ss_next.tqe_next == NULL) &&
(sp->ss_next.tqe_prev == NULL)) {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, ss_next);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -761,7 +872,7 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
static int
sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
{
- if (TAILQ_EMPTY(&asoc->ss_data.out_list)) {
+ if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
return (1);
} else {
return (0);
@@ -779,7 +890,9 @@ sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (sp &&
((sp->ss_next.tqe_next != NULL) ||
(sp->ss_next.tqe_prev != NULL))) {
- TAILQ_REMOVE(&asoc->ss_data.out_list, sp, ss_next);
+ TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
+ sp->ss_next.tqe_next = NULL;
+ sp->ss_next.tqe_prev = NULL;
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -787,7 +900,6 @@ sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
return;
}
-
static struct sctp_stream_out *
sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
struct sctp_association *asoc)
@@ -795,10 +907,13 @@ sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
struct sctp_stream_out *strq;
struct sctp_stream_queue_pending *sp;
- sp = TAILQ_FIRST(&asoc->ss_data.out_list);
+ if (asoc->ss_data.locked_on_sending) {
+ return (asoc->ss_data.locked_on_sending);
+ }
+ sp = TAILQ_FIRST(&asoc->ss_data.out.list);
default_again:
if (sp != NULL) {
- strq = &asoc->strmout[sp->stream];
+ strq = &asoc->strmout[sp->sid];
} else {
strq = NULL;
}
@@ -827,10 +942,10 @@ default_again:
return (strq);
}
-struct sctp_ss_functions sctp_ss_functions[] = {
+const struct sctp_ss_functions sctp_ss_functions[] = {
/* SCTP_SS_DEFAULT */
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32)
sctp_ss_default_init,
sctp_ss_default_clear,
sctp_ss_default_init_stream,
@@ -841,7 +956,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
sctp_ss_default_scheduled,
sctp_ss_default_packet_done,
sctp_ss_default_get_value,
- sctp_ss_default_set_value
+ sctp_ss_default_set_value,
+ sctp_ss_default_is_user_msgs_incomplete
#else
.sctp_ss_init = sctp_ss_default_init,
.sctp_ss_clear = sctp_ss_default_clear,
@@ -853,12 +969,13 @@ struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
#endif
},
/* SCTP_SS_ROUND_ROBIN */
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32)
sctp_ss_default_init,
sctp_ss_default_clear,
sctp_ss_default_init_stream,
@@ -869,7 +986,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
sctp_ss_default_scheduled,
sctp_ss_default_packet_done,
sctp_ss_default_get_value,
- sctp_ss_default_set_value
+ sctp_ss_default_set_value,
+ sctp_ss_default_is_user_msgs_incomplete
#else
.sctp_ss_init = sctp_ss_default_init,
.sctp_ss_clear = sctp_ss_default_clear,
@@ -881,12 +999,13 @@ struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
#endif
},
/* SCTP_SS_ROUND_ROBIN_PACKET */
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32)
sctp_ss_default_init,
sctp_ss_default_clear,
sctp_ss_default_init_stream,
@@ -897,7 +1016,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
sctp_ss_default_scheduled,
sctp_ss_rrp_packet_done,
sctp_ss_default_get_value,
- sctp_ss_default_set_value
+ sctp_ss_default_set_value,
+ sctp_ss_default_is_user_msgs_incomplete
#else
.sctp_ss_init = sctp_ss_default_init,
.sctp_ss_clear = sctp_ss_default_clear,
@@ -909,12 +1029,13 @@ struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_rrp_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
#endif
},
/* SCTP_SS_PRIORITY */
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32)
sctp_ss_default_init,
sctp_ss_prio_clear,
sctp_ss_prio_init_stream,
@@ -925,7 +1046,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
sctp_ss_default_scheduled,
sctp_ss_default_packet_done,
sctp_ss_prio_get_value,
- sctp_ss_prio_set_value
+ sctp_ss_prio_set_value,
+ sctp_ss_default_is_user_msgs_incomplete
#else
.sctp_ss_init = sctp_ss_default_init,
.sctp_ss_clear = sctp_ss_prio_clear,
@@ -937,12 +1059,13 @@ struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_prio_get_value,
- .sctp_ss_set_value = sctp_ss_prio_set_value
+ .sctp_ss_set_value = sctp_ss_prio_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
#endif
},
/* SCTP_SS_FAIR_BANDWITH */
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32)
sctp_ss_default_init,
sctp_ss_fb_clear,
sctp_ss_fb_init_stream,
@@ -953,7 +1076,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
sctp_ss_fb_scheduled,
sctp_ss_default_packet_done,
sctp_ss_default_get_value,
- sctp_ss_default_set_value
+ sctp_ss_default_set_value,
+ sctp_ss_default_is_user_msgs_incomplete
#else
.sctp_ss_init = sctp_ss_default_init,
.sctp_ss_clear = sctp_ss_fb_clear,
@@ -965,12 +1089,13 @@ struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_fb_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
#endif
},
/* SCTP_SS_FIRST_COME */
{
-#if defined(__Windows__) || defined(__Userspace_os_Windows)
+#if defined(_WIN32)
sctp_ss_fcfs_init,
sctp_ss_fcfs_clear,
sctp_ss_fcfs_init_stream,
@@ -981,7 +1106,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
sctp_ss_default_scheduled,
sctp_ss_default_packet_done,
sctp_ss_default_get_value,
- sctp_ss_default_set_value
+ sctp_ss_default_set_value,
+ sctp_ss_default_is_user_msgs_incomplete
#else
.sctp_ss_init = sctp_ss_fcfs_init,
.sctp_ss_clear = sctp_ss_fcfs_clear,
@@ -993,7 +1119,8 @@ struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
#endif
}
};
diff --git a/netwerk/sctp/src/netinet/sctp_structs.h b/netwerk/sctp/src/netinet/sctp_structs.h
index 7047b41886..708ab702f1 100755
--- a/netwerk/sctp/src/netinet/sctp_structs.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 279859 2015-03-10 19:49:25Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_STRUCTS_H_
@@ -53,7 +55,7 @@ struct sctp_timer {
void *ep;
void *tcb;
void *net;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
void *vnet;
#endif
@@ -63,7 +65,6 @@ struct sctp_timer {
uint32_t stopped_from;
};
-
struct sctp_foo_stuff {
struct sctp_inpcb *inp;
uint32_t lineno;
@@ -71,7 +72,6 @@ struct sctp_foo_stuff {
int updown;
};
-
/*
* This is the information we track on each interface that we know about from
* the distant end.
@@ -80,6 +80,7 @@ TAILQ_HEAD(sctpnetlisthead, sctp_nets);
struct sctp_stream_reset_list {
TAILQ_ENTRY(sctp_stream_reset_list) next_resp;
+ uint32_t seq;
uint32_t tsn;
uint32_t number_entries;
uint16_t list_of_streams[];
@@ -110,13 +111,12 @@ typedef void (*asoc_func) (struct sctp_inpcb *, struct sctp_tcb *, void *ptr,
typedef int (*inp_func) (struct sctp_inpcb *, void *ptr, uint32_t val);
typedef void (*end_func) (void *ptr, uint32_t val);
-#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SCTP_MCORE_INPUT) && defined(SMP)
/* whats on the mcore control struct */
struct sctp_mcore_queue {
TAILQ_ENTRY(sctp_mcore_queue) next;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
struct vnet *vn;
-#endif
struct mbuf *m;
int off;
int v6;
@@ -132,14 +132,12 @@ struct sctp_mcore_ctrl {
int running;
int cpuid;
};
-
-
#endif
-
+#endif
struct sctp_iterator {
TAILQ_ENTRY(sctp_iterator) sctp_nxt_itr;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct vnet *vn;
#endif
struct sctp_timer tmr;
@@ -163,14 +161,13 @@ struct sctp_iterator {
#define SCTP_ITERATOR_DO_ALL_INP 0x00000001
#define SCTP_ITERATOR_DO_SINGLE_INP 0x00000002
-
TAILQ_HEAD(sctpiterators, sctp_iterator);
struct sctp_copy_all {
struct sctp_inpcb *inp; /* ep */
struct mbuf *m;
struct sctp_sndrcvinfo sndrcv;
- int sndlen;
+ ssize_t sndlen;
int cnt_sent;
int cnt_failed;
};
@@ -181,10 +178,10 @@ struct sctp_asconf_iterator {
};
struct iterator_control {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct mtx ipi_iterator_wq_mtx;
struct mtx it_mtx;
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
lck_mtx_t *ipi_iterator_wq_mtx;
lck_mtx_t *it_mtx;
#elif defined(SCTP_PROCESS_LEVEL_LOCKS)
@@ -197,7 +194,7 @@ struct iterator_control {
pthread_mutex_t it_mtx;
pthread_cond_t iterator_wakeup;
#endif
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
struct spinlock it_lock;
struct spinlock ipi_iterator_wq_lock;
KEVENT iterator_wakeup[2];
@@ -205,7 +202,7 @@ struct iterator_control {
#else
void *it_mtx;
#endif
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
#if !defined(__Userspace__)
SCTP_PROCESS_STRUCT thread_proc;
#else
@@ -217,7 +214,7 @@ struct iterator_control {
uint32_t iterator_running;
uint32_t iterator_flags;
};
-#if !defined(__FreeBSD__)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
#define SCTP_ITERATOR_MUST_EXIT 0x00000001
#define SCTP_ITERATOR_EXITED 0x00000002
#endif
@@ -225,17 +222,21 @@ struct iterator_control {
#define SCTP_ITERATOR_STOP_CUR_INP 0x00000008
struct sctp_net_route {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct nhop_object *ro_nh;
+ struct llentry *ro_lle;
+ char *ro_prepend;
+ uint16_t ro_plen;
+ uint16_t ro_flags;
+ uint16_t ro_mtu;
+ uint16_t spare;
+#else
sctp_rtentry_t *ro_rt;
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800000
- void *ro_lle;
-#endif
-#if __FreeBSD_version >= 900000
- void *ro_ia;
- int ro_flags;
#endif
+#if defined(__APPLE__) && !defined(__Userspace__)
+#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN)
+ struct llentry *ro_lle;
#endif
-#if defined(__APPLE__)
#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)
struct ifaddr *ro_srcia;
#endif
@@ -289,7 +290,6 @@ struct rtcc_cc {
uint8_t last_inst_ind; /* Last saved inst indication */
};
-
struct sctp_nets {
TAILQ_ENTRY(sctp_nets) sctp_next; /* next link */
@@ -317,7 +317,7 @@ struct sctp_nets {
int lastsa;
int lastsv;
uint64_t rtt; /* last measured rtt value in us */
- unsigned int RTO;
+ uint32_t RTO;
/* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */
struct sctp_timer rxt_timer;
@@ -426,18 +426,17 @@ struct sctp_nets {
uint8_t last_hs_used; /* index into the last HS table entry we used */
uint8_t lan_type;
uint8_t rto_needed;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint32_t flowid;
uint8_t flowtype;
#endif
};
-
struct sctp_data_chunkrec {
- uint32_t TSN_seq; /* the TSN of this transmit */
- uint16_t stream_seq; /* the stream sequence number of this transmit */
- uint16_t stream_number; /* the stream number of this guy */
- uint32_t payloadtype;
+ uint32_t tsn; /* the TSN of this transmit */
+ uint32_t mid; /* the message identifier of this transmit */
+ uint16_t sid; /* the stream number of this guy */
+ uint32_t ppid;
uint32_t context; /* from send */
uint32_t cwnd_at_send;
/*
@@ -446,6 +445,7 @@ struct sctp_data_chunkrec {
*/
uint32_t fast_retran_tsn; /* sending_seq at the time of FR */
struct timeval timetodrop; /* time we drop it from queue */
+ uint32_t fsn; /* Fragment Sequence Number */
uint8_t doing_fast_retransmit;
uint8_t rcv_flags; /* flags pulled from data chunk on inbound for
* outbound holds sending flags for PR-SCTP.
@@ -470,7 +470,6 @@ struct chk_id {
uint8_t can_take_data;
};
-
struct sctp_tmit_chunk {
union {
struct sctp_data_chunkrec data;
@@ -498,14 +497,8 @@ struct sctp_tmit_chunk {
uint8_t window_probe;
};
-/*
- * The first part of this structure MUST be the entire sinfo structure. Maybe
- * I should have made it a sub structure... we can circle back later and do
- * that if we want.
- */
struct sctp_queued_to_read { /* sinfo structure Pluse more */
uint16_t sinfo_stream; /* off the wire */
- uint16_t sinfo_ssn; /* off the wire */
uint16_t sinfo_flags; /* SCTP_UNORDERED from wire use SCTP_EOF for
* EOR */
uint32_t sinfo_ppid; /* off the wire */
@@ -515,8 +508,11 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
uint32_t sinfo_cumtsn; /* Use this in reassembly as last TSN */
sctp_assoc_t sinfo_assoc_id; /* our assoc id */
/* Non sinfo stuff */
+ uint32_t mid; /* Fragment Index */
uint32_t length; /* length of data */
uint32_t held_length; /* length held in sb */
+ uint32_t top_fsn; /* Highest FSN in queue */
+ uint32_t fsn_included; /* Highest FSN in *data portion */
struct sctp_nets *whoFrom; /* where it came from */
struct mbuf *data; /* front of the mbuf chain of data with
* PKT_HDR */
@@ -524,14 +520,24 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
struct mbuf *aux_data; /* used to hold/cache control if o/s does not take it from us */
struct sctp_tcb *stcb; /* assoc, used for window update */
TAILQ_ENTRY(sctp_queued_to_read) next;
+ TAILQ_ENTRY(sctp_queued_to_read) next_instrm;
+ struct sctpchunk_listhead reasm;
uint16_t port_from;
uint16_t spec_flags; /* Flags to hold the notification field */
uint8_t do_not_ref_stcb;
uint8_t end_added;
uint8_t pdapi_aborted;
+ uint8_t pdapi_started;
uint8_t some_taken;
+ uint8_t last_frag_seen;
+ uint8_t first_frag_seen;
+ uint8_t on_read_q;
+ uint8_t on_strm_q;
};
+#define SCTP_ON_ORDERED 1
+#define SCTP_ON_UNORDERED 2
+
/* This data structure will be on the outbound
* stream queues. Data will be pulled off from
* the front of the mbuf data and chunk-ified
@@ -557,12 +563,13 @@ struct sctp_stream_queue_pending {
struct sctp_nets *net;
TAILQ_ENTRY (sctp_stream_queue_pending) next;
TAILQ_ENTRY (sctp_stream_queue_pending) ss_next;
+ uint32_t fsn;
uint32_t length;
uint32_t timetolive;
uint32_t ppid;
uint32_t context;
uint16_t sinfo_flags;
- uint16_t stream;
+ uint16_t sid;
uint16_t act_flags;
uint16_t auth_keyid;
uint8_t holds_key_ref;
@@ -571,6 +578,7 @@ struct sctp_stream_queue_pending {
uint8_t sender_all_done;
uint8_t put_last_out;
uint8_t discard_rest;
+ uint8_t processing;
};
/*
@@ -580,9 +588,11 @@ struct sctp_stream_queue_pending {
TAILQ_HEAD(sctpwheelunrel_listhead, sctp_stream_in);
struct sctp_stream_in {
struct sctp_readhead inqueue;
- uint16_t stream_no;
- uint16_t last_sequence_delivered; /* used for re-order */
+ struct sctp_readhead uno_inqueue;
+ uint32_t last_mid_delivered; /* used for re-order */
+ uint16_t sid;
uint8_t delivery_started;
+ uint8_t pd_api_started;
};
TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out);
@@ -614,9 +624,14 @@ struct ss_fb {
* This union holds all data necessary for
* different stream schedulers.
*/
-union scheduling_data {
- struct sctpwheel_listhead out_wheel;
- struct sctplist_listhead out_list;
+struct scheduling_data {
+ struct sctp_stream_out *locked_on_sending;
+ /* circular looking for output selection */
+ struct sctp_stream_out *last_out_stream;
+ union {
+ struct sctpwheel_listhead wheel;
+ struct sctplist_listhead list;
+ } out;
};
/*
@@ -629,11 +644,20 @@ union scheduling_parameters {
struct ss_fb fb;
};
+/* States for outgoing streams */
+#define SCTP_STREAM_CLOSED 0x00
+#define SCTP_STREAM_OPENING 0x01
+#define SCTP_STREAM_OPEN 0x02
+#define SCTP_STREAM_RESET_PENDING 0x03
+#define SCTP_STREAM_RESET_IN_FLIGHT 0x04
+
+#define SCTP_MAX_STREAMS_AT_ONCE_RESET 200
+
/* This struct is used to track the traffic on outbound streams */
struct sctp_stream_out {
struct sctp_streamhead outqueue;
union scheduling_parameters ss_params;
- uint32_t chunks_on_queues;
+ uint32_t chunks_on_queues; /* send queue and sent queue */
#if defined(SCTP_DETAILED_STR_STATS)
uint32_t abandoned_unsent[SCTP_PR_SCTP_MAX + 1];
uint32_t abandoned_sent[SCTP_PR_SCTP_MAX + 1];
@@ -642,9 +666,14 @@ struct sctp_stream_out {
uint32_t abandoned_unsent[1];
uint32_t abandoned_sent[1];
#endif
- uint16_t stream_no;
- uint16_t next_sequence_send; /* next one I expect to send out */
+ /* For associations using DATA chunks, the lower 16-bit of
+ * next_mid_ordered are used as the next SSN.
+ */
+ uint32_t next_mid_ordered;
+ uint32_t next_mid_unordered;
+ uint16_t sid;
uint8_t last_msg_incomplete;
+ uint8_t state;
};
/* used to keep track of the addresses yet to try to add/delete */
@@ -674,12 +703,13 @@ struct sctp_scoping {
struct sctp_tsn_log {
void *stcb;
uint32_t tsn;
+ uint32_t seq;
uint16_t strm;
- uint16_t seq;
uint16_t sz;
uint16_t flgs;
uint16_t in_pos;
uint16_t in_out;
+ uint16_t resv;
};
#define SCTP_FS_SPEC_LOG_SIZE 200
@@ -755,7 +785,7 @@ struct sctp_ss_functions {
int holds_lock);
void (*sctp_ss_clear)(struct sctp_tcb *stcb, struct sctp_association *asoc,
int clear_values, int holds_lock);
- void (*sctp_ss_init_stream)(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq);
+ void (*sctp_ss_init_stream)(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq);
void (*sctp_ss_add_to_stream)(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock);
int (*sctp_ss_is_empty)(struct sctp_tcb *stcb, struct sctp_association *asoc);
@@ -771,6 +801,7 @@ struct sctp_ss_functions {
struct sctp_stream_out *strq, uint16_t *value);
int (*sctp_ss_set_value)(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_out *strq, uint16_t value);
+ int (*sctp_ss_is_user_msgs_incomplete)(struct sctp_tcb *stcb, struct sctp_association *asoc);
};
/* used to save ASCONF chunks for retransmission */
@@ -818,7 +849,6 @@ struct sctp_association {
struct sctp_timer strreset_timer; /* stream reset */
struct sctp_timer shut_guard_timer; /* shutdown guard */
struct sctp_timer autoclose_timer; /* automatic close timer */
- struct sctp_timer delayed_event_timer; /* timer for delayed events */
struct sctp_timer delete_prim_timer; /* deleting primary dst */
/* list of restricted local addresses */
@@ -850,20 +880,8 @@ struct sctp_association {
struct sctpchunk_listhead sent_queue;
struct sctpchunk_listhead send_queue;
- /* re-assembly queue for fragmented chunks on the inbound path */
- struct sctpchunk_listhead reasmqueue;
-
/* Scheduling queues */
- union scheduling_data ss_data;
-
- /* This pointer will be set to NULL
- * most of the time. But when we have
- * a fragmented message, where we could
- * not get out all of the message at
- * the last send then this will point
- * to the stream to go get data from.
- */
- struct sctp_stream_out *locked_on_sending;
+ struct scheduling_data ss_data;
/* If an iterator is looking at me, this is it */
struct sctp_iterator *stcb_starting_point_for_iterator;
@@ -896,9 +914,6 @@ struct sctp_association {
/* last place I got a control from */
struct sctp_nets *last_control_chunk_from;
- /* circular looking for output selection */
- struct sctp_stream_out *last_out_stream;
-
/*
* wait to the point the cum-ack passes req->send_reset_at_tsn for
* any req on the list.
@@ -918,7 +933,6 @@ struct sctp_association {
uint32_t stream_scheduling_module;
uint32_t vrf_id;
-
uint32_t cookie_preserve_req;
/* ASCONF next seq I am sending out, inits at init-tsn */
uint32_t asconf_seq_out;
@@ -963,7 +977,6 @@ struct sctp_association {
/* Original seq number I used ??questionable to keep?? */
uint32_t init_seq_number;
-
/* The Advanced Peer Ack Point, as required by the PR-SCTP */
/* (A1 in Section 4.2) */
uint32_t advanced_peer_ack_point;
@@ -992,7 +1005,7 @@ struct sctp_association {
uint32_t sat_t3_recovery_tsn;
uint32_t tsn_last_delivered;
/*
- * For the pd-api we should re-write this a bit more efficent. We
+ * For the pd-api we should re-write this a bit more efficient. We
* could have multiple sctp_queued_to_read's that we are building at
* once. Now we only do this when we get ready to deliver to the
* socket buffer. Note that we depend on the fact that the struct is
@@ -1087,7 +1100,7 @@ struct sctp_association {
uint32_t heart_beat_delay;
/* autoclose */
- unsigned int sctp_autoclose_ticks;
+ uint32_t sctp_autoclose_ticks;
/* how many preopen streams we have */
unsigned int pre_open_streams;
@@ -1096,7 +1109,7 @@ struct sctp_association {
unsigned int max_inbound_streams;
/* the cookie life I award for any cookie, in seconds */
- unsigned int cookie_life;
+ uint32_t cookie_life;
/* time to delay acks for */
unsigned int delayed_ack;
unsigned int old_delayed_ack;
@@ -1105,10 +1118,10 @@ struct sctp_association {
unsigned int numduptsns;
int dup_tsns[SCTP_MAX_DUP_TSNS];
- unsigned int initial_init_rto_max; /* initial RTO for INIT's */
- unsigned int initial_rto; /* initial send RTO */
- unsigned int minrto; /* per assoc RTO-MIN */
- unsigned int maxrto; /* per assoc RTO-MAX */
+ uint32_t initial_init_rto_max; /* initial RTO for INIT's */
+ uint32_t initial_rto; /* initial send RTO */
+ uint32_t minrto; /* per assoc RTO-MIN */
+ uint32_t maxrto; /* per assoc RTO-MAX */
/* authentication fields */
sctp_auth_chklist_t *local_auth_chunks;
@@ -1125,6 +1138,7 @@ struct sctp_association {
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 */
/*
@@ -1198,7 +1212,7 @@ struct sctp_association {
uint8_t hb_random_idx;
uint8_t default_dscp;
uint8_t asconf_del_pending; /* asconf delete last addr pending */
-
+ uint8_t trigger_reset;
/*
* This value, plus all other ack'd but above cum-ack is added
* together to cross check against the bit that we have yet to
@@ -1214,17 +1228,16 @@ struct sctp_association {
uint8_t reconfig_supported;
uint8_t nrsack_supported;
uint8_t pktdrop_supported;
+ uint8_t idata_supported;
/* Did the peer make the stream config (add out) request */
uint8_t peer_req_out;
uint8_t local_strreset_support;
-
uint8_t peer_supports_nat;
struct sctp_scoping scope;
/* flags to handle send alternate net tracking */
- uint8_t used_alt_onsack;
uint8_t used_alt_asconfack;
uint8_t fast_retran_loss_recovery;
uint8_t sat_t3_loss_recovery;
diff --git a/netwerk/sctp/src/netinet/sctp_sysctl.c b/netwerk/sctp/src/netinet/sctp_sysctl.c
index 43f59313e1..bb49e17385 100755
--- a/netwerk/sctp/src/netinet/sctp_sysctl.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 277424 2015-01-20 19:08:55Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 365071 2020-09-01 21:19:14Z mjg $");
#endif
#include <netinet/sctp_os.h>
@@ -42,15 +44,15 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 277424 2015-01-20 19:08:55Z t
#include <netinet/sctp_pcb.h>
#include <netinet/sctputil.h>
#include <netinet/sctp_output.h>
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/smp.h>
#include <sys/sysctl.h>
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#include <netinet/sctp_bsd_addr.h>
#endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
FEATURE(sctp, "Stream Control Transmission Protocol");
#endif
@@ -72,20 +74,35 @@ sctp_init_sysctls()
SCTP_BASE_SYSCTL(sctp_reconfig_enable) = SCTPCTL_RECONFIG_ENABLE_DEFAULT;
SCTP_BASE_SYSCTL(sctp_nrsack_enable) = SCTPCTL_NRSACK_ENABLE_DEFAULT;
SCTP_BASE_SYSCTL(sctp_pktdrop_enable) = SCTPCTL_PKTDROP_ENABLE_DEFAULT;
- SCTP_BASE_SYSCTL(sctp_strict_sacks) = SCTPCTL_STRICT_SACKS_DEFAULT;
-#if !(defined(__FreeBSD__) && __FreeBSD_version >= 800000)
-#if !defined(SCTP_WITH_NO_CSUM)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) = SCTPCTL_LOOPBACK_NOCSUM_DEFAULT;
#endif
-#endif
SCTP_BASE_SYSCTL(sctp_peer_chunk_oh) = SCTPCTL_PEER_CHKOH_DEFAULT;
SCTP_BASE_SYSCTL(sctp_max_burst_default) = SCTPCTL_MAXBURST_DEFAULT;
SCTP_BASE_SYSCTL(sctp_fr_max_burst_default) = SCTPCTL_FRMAXBURST_DEFAULT;
SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = SCTPCTL_MAXCHUNKS_DEFAULT;
+#if defined(__Userspace__)
+ if (SCTP_BASE_SYSCTL(sctp_hashtblsize) == 0) {
+ SCTP_BASE_SYSCTL(sctp_hashtblsize) = SCTPCTL_TCBHASHSIZE_DEFAULT;
+ }
+#else
SCTP_BASE_SYSCTL(sctp_hashtblsize) = SCTPCTL_TCBHASHSIZE_DEFAULT;
+#endif
+#if defined(__Userspace__)
+ if (SCTP_BASE_SYSCTL(sctp_pcbtblsize) == 0) {
+ SCTP_BASE_SYSCTL(sctp_pcbtblsize) = SCTPCTL_PCBHASHSIZE_DEFAULT;
+ }
+#else
SCTP_BASE_SYSCTL(sctp_pcbtblsize) = SCTPCTL_PCBHASHSIZE_DEFAULT;
+#endif
SCTP_BASE_SYSCTL(sctp_min_split_point) = SCTPCTL_MIN_SPLIT_POINT_DEFAULT;
+#if defined(__Userspace__)
+ if (SCTP_BASE_SYSCTL(sctp_chunkscale) == 0) {
+ SCTP_BASE_SYSCTL(sctp_chunkscale) = SCTPCTL_CHUNKSCALE_DEFAULT;
+ }
+#else
SCTP_BASE_SYSCTL(sctp_chunkscale) = SCTPCTL_CHUNKSCALE_DEFAULT;
+#endif
SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default) = SCTPCTL_DELAYED_SACK_TIME_DEFAULT;
SCTP_BASE_SYSCTL(sctp_sack_freq_default) = SCTPCTL_SACK_FREQ_DEFAULT;
SCTP_BASE_SYSCTL(sctp_system_free_resc_limit) = SCTPCTL_SYS_RESOURCE_DEFAULT;
@@ -115,7 +132,6 @@ sctp_init_sysctls()
SCTP_BASE_SYSCTL(sctp_do_drain) = SCTPCTL_DO_SCTP_DRAIN_DEFAULT;
SCTP_BASE_SYSCTL(sctp_hb_maxburst) = SCTPCTL_HB_MAX_BURST_DEFAULT;
SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit) = SCTPCTL_ABORT_AT_LIMIT_DEFAULT;
- SCTP_BASE_SYSCTL(sctp_strict_data_order) = SCTPCTL_STRICT_DATA_ORDER_DEFAULT;
SCTP_BASE_SYSCTL(sctp_min_residual) = SCTPCTL_MIN_RESIDUAL_DEFAULT;
SCTP_BASE_SYSCTL(sctp_max_retran_chunk) = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT;
SCTP_BASE_SYSCTL(sctp_logging_level) = SCTPCTL_LOGGING_LEVEL_DEFAULT;
@@ -133,9 +149,10 @@ sctp_init_sysctls()
SCTP_BASE_SYSCTL(sctp_steady_step) = SCTPCTL_RTTVAR_STEADYS_DEFAULT;
SCTP_BASE_SYSCTL(sctp_use_dccc_ecn) = SCTPCTL_RTTVAR_DCCCECN_DEFAULT;
SCTP_BASE_SYSCTL(sctp_blackhole) = SCTPCTL_BLACKHOLE_DEFAULT;
+ SCTP_BASE_SYSCTL(sctp_sendall_limit) = SCTPCTL_SENDALL_LIMIT_DEFAULT;
SCTP_BASE_SYSCTL(sctp_diag_info_code) = SCTPCTL_DIAG_INFO_CODE_DEFAULT;
#if defined(SCTP_LOCAL_TRACE_BUF)
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
/* On Windows, the resource for global variables is limited. */
MALLOC(SCTP_BASE_SYSCTL(sctp_log), struct sctp_log *, sizeof(struct sctp_log), M_SYSCTL, M_ZERO);
#else
@@ -148,18 +165,18 @@ sctp_init_sysctls()
#if defined(SCTP_DEBUG)
SCTP_BASE_SYSCTL(sctp_debug_on) = SCTPCTL_DEBUG_DEFAULT;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_BASE_SYSCTL(sctp_ignore_vmware_interfaces) = SCTPCTL_IGNORE_VMWARE_INTERFACES_DEFAULT;
SCTP_BASE_SYSCTL(sctp_main_timer) = SCTPCTL_MAIN_TIMER_DEFAULT;
SCTP_BASE_SYSCTL(sctp_addr_watchdog_limit) = SCTPCTL_ADDR_WATCHDOG_LIMIT_DEFAULT;
SCTP_BASE_SYSCTL(sctp_vtag_watchdog_limit) = SCTPCTL_VTAG_WATCHDOG_LIMIT_DEFAULT;
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_BASE_SYSCTL(sctp_output_unlocked) = SCTPCTL_OUTPUT_UNLOCKED_DEFAULT;
#endif
}
+#if defined(_WIN32) && !defined(__Userspace__)
-#if defined(__Windows__)
void
sctp_finish_sysctls()
{
@@ -172,7 +189,7 @@ sctp_finish_sysctls()
}
#endif
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__Windows__)
+#if !defined(__Userspace__)
/* It returns an upper limit. No filtering is done here */
static unsigned int
sctp_sysctl_number_of_addresses(struct sctp_inpcb *inp)
@@ -312,7 +329,7 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
sin = &sctp_ifa->address.sin;
if (sin->sin_addr.s_addr == 0)
continue;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -330,13 +347,10 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
if (ipv6_addr_legal) {
struct sockaddr_in6 *sin6;
-#if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME)
- struct sockaddr_in6 lsa6;
-#endif
sin6 = &sctp_ifa->address.sin6;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
continue;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -345,21 +359,6 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0)
continue;
-#if defined(SCTP_EMBEDDED_V6_SCOPE)
- if (sin6->sin6_scope_id == 0) {
-#ifdef SCTP_KAME
- /* bad link local address */
- if (sa6_recoverscope(sin6) != 0)
- continue;
-#else
- lsa6 = *sin6;
- /* bad link local address */
- if (in6_recoverscope(&lsa6, &lsa6.sin6_addr, NULL))
- continue;
- sin6 = &lsa6;
-#endif /* SCTP_KAME */
- }
-#endif /* SCTP_EMBEDDED_V6_SCOPE */
}
if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)))
continue;
@@ -429,7 +428,7 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
/*
* sysctl functions
*/
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_assoclist SYSCTL_HANDLER_ARGS
{
@@ -459,7 +458,7 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
number_of_remote_addresses = 0;
SCTP_INP_INFO_RLOCK();
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (req->oldptr == USER_ADDR_NULL) {
#else
if (req->oldptr == NULL) {
@@ -484,14 +483,14 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
(number_of_remote_addresses + number_of_associations) * sizeof(struct xsctp_raddr);
/* request some more memory than needed */
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
req->oldidx = (n + n / 8);
#else
req->dataidx = (n + n / 8);
#endif
return (0);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (req->newptr != USER_ADDR_NULL) {
#else
if (req->newptr != NULL) {
@@ -500,6 +499,9 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_SYSCTL, EPERM);
return (EPERM);
}
+ memset(&xinpcb, 0, sizeof(xinpcb));
+ memset(&xstcb, 0, sizeof(xstcb));
+ memset(&xraddr, 0, sizeof(xraddr));
LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) {
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
@@ -509,23 +511,34 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
xinpcb.last = 0;
xinpcb.local_port = ntohs(inp->sctp_lport);
xinpcb.flags = inp->sctp_flags;
-#if defined(__FreeBSD__) && __FreeBSD_version < 1000048
- xinpcb.features = (uint32_t)inp->sctp_features;
-#else
xinpcb.features = inp->sctp_features;
-#endif
xinpcb.total_sends = inp->total_sends;
xinpcb.total_recvs = inp->total_recvs;
xinpcb.total_nospaces = inp->total_nospaces;
xinpcb.fragmentation_point = inp->sctp_frag_point;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ xinpcb.socket = (uintptr_t)inp->sctp_socket;
+#else
+ xinpcb.socket = inp->sctp_socket;
+#endif
so = inp->sctp_socket;
if ((so == NULL) ||
+ (!SCTP_IS_LISTENING(inp)) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
xinpcb.qlen = 0;
xinpcb.maxqlen = 0;
} else {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ xinpcb.qlen = so->sol_qlen;
+ xinpcb.qlen_old = so->sol_qlen > USHRT_MAX ?
+ USHRT_MAX : (uint16_t) so->sol_qlen;
+ xinpcb.maxqlen = so->sol_qlimit;
+ xinpcb.maxqlen_old = so->sol_qlimit > USHRT_MAX ?
+ USHRT_MAX : (uint16_t) so->sol_qlimit;
+#else
xinpcb.qlen = so->so_qlen;
xinpcb.maxqlen = so->so_qlimit;
+#endif
}
SCTP_INP_INCR_REF(inp);
SCTP_INP_RUNLOCK(inp);
@@ -552,17 +565,9 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
if (stcb->asoc.primary_destination != NULL)
xstcb.primary_addr = stcb->asoc.primary_destination->ro._l_addr;
xstcb.heartbeat_interval = stcb->asoc.heart_beat_delay;
- xstcb.state = SCTP_GET_STATE(&stcb->asoc); /* FIXME */
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800000
- /* 7.0 does not support these */
+ xstcb.state = (uint32_t)sctp_map_assoc_state(stcb->asoc.state);
xstcb.assoc_id = sctp_get_associd(stcb);
xstcb.peers_rwnd = stcb->asoc.peers_rwnd;
-#endif
-#else
- xstcb.assoc_id = sctp_get_associd(stcb);
- xstcb.peers_rwnd = stcb->asoc.peers_rwnd;
-#endif
xstcb.in_streams = stcb->asoc.streamincnt;
xstcb.out_streams = stcb->asoc.streamoutcnt;
xstcb.max_nr_retrans = stcb->asoc.overall_error_count;
@@ -614,15 +619,17 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
xraddr.cwnd = net->cwnd;
xraddr.flight_size = net->flight_size;
xraddr.mtu = net->mtu;
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800000
xraddr.rtt = net->rtt / 1000;
xraddr.heartbeat_interval = net->heart_beat_delay;
-#endif
-#else
- xraddr.rtt = net->rtt / 1000;
- xraddr.heartbeat_interval = net->heart_beat_delay;
-#endif
+ 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;
+ }
xraddr.start_time.tv_sec = (uint32_t)net->start_time.tv_sec;
xraddr.start_time.tv_usec = (uint32_t)net->start_time.tv_usec;
SCTP_INP_RUNLOCK(inp);
@@ -669,7 +676,7 @@ skip:
return (error);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_udp_tunneling SYSCTL_HANDLER_ARGS
{
@@ -686,22 +693,14 @@ sctp_sysctl_handle_udp_tunneling(SYSCTL_HANDLER_ARGS)
old = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port);
SCTP_INP_INFO_RUNLOCK();
new = old;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800056 && __FreeBSD_version < 1000100
-#ifdef VIMAGE
- error = vnet_sysctl_handle_int(oidp, &new, 0, req);
-#else
- error = sysctl_handle_int(oidp, &new, 0, req);
-#endif
-#else
error = sysctl_handle_int(oidp, &new, 0, req);
-#endif
if ((error == 0) &&
-#if defined (__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
(req->newptr != USER_ADDR_NULL)) {
#else
(req->newptr != NULL)) {
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
SCTP_INP_INFO_WLOCK();
sctp_over_udp_restart();
SCTP_INP_INFO_WUNLOCK();
@@ -728,8 +727,8 @@ sctp_sysctl_handle_udp_tunneling(SYSCTL_HANDLER_ARGS)
}
return (error);
}
+#if defined(__APPLE__) && !defined(__Userspace__)
-#if defined(__APPLE__)
int sctp_is_vmware_interface(struct ifnet *);
static int
@@ -762,7 +761,7 @@ sctp_sysctl_handle_vmware_interfaces SYSCTL_HANDLER_ARGS
}
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_auth SYSCTL_HANDLER_ARGS
{
@@ -776,17 +775,9 @@ sctp_sysctl_handle_auth(SYSCTL_HANDLER_ARGS)
uint32_t new;
new = SCTP_BASE_SYSCTL(sctp_auth_enable);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800056 && __FreeBSD_version < 1000100
-#ifdef VIMAGE
- error = vnet_sysctl_handle_int(oidp, &new, 0, req);
-#else
- error = sysctl_handle_int(oidp, &new, 0, req);
-#endif
-#else
error = sysctl_handle_int(oidp, &new, 0, req);
-#endif
if ((error == 0) &&
-#if defined (__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
(req->newptr != USER_ADDR_NULL)) {
#else
(req->newptr != NULL)) {
@@ -807,7 +798,7 @@ sctp_sysctl_handle_auth(SYSCTL_HANDLER_ARGS)
return (error);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_asconf SYSCTL_HANDLER_ARGS
{
@@ -821,17 +812,9 @@ sctp_sysctl_handle_asconf(SYSCTL_HANDLER_ARGS)
uint32_t new;
new = SCTP_BASE_SYSCTL(sctp_asconf_enable);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800056 && __FreeBSD_version < 1000100
-#ifdef VIMAGE
- error = vnet_sysctl_handle_int(oidp, &new, 0, req);
-#else
- error = sysctl_handle_int(oidp, &new, 0, req);
-#endif
-#else
error = sysctl_handle_int(oidp, &new, 0, req);
-#endif
if ((error == 0) &&
-#if defined (__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
(req->newptr != USER_ADDR_NULL)) {
#else
(req->newptr != NULL)) {
@@ -852,7 +835,7 @@ sctp_sysctl_handle_asconf(SYSCTL_HANDLER_ARGS)
return (error);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_stats SYSCTL_HANDLER_ARGS
{
@@ -863,7 +846,7 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
{
#endif
int error;
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
struct sctpstat *sarry;
struct sctpstat sb;
@@ -872,7 +855,7 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
struct sctpstat sb_temp;
#endif
-#if defined (__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if ((req->newptr != USER_ADDR_NULL) &&
#else
if ((req->newptr != NULL) &&
@@ -880,7 +863,7 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
(req->newlen != sizeof(struct sctpstat))) {
return (EINVAL);
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
memset(&sb_temp, 0, sizeof(struct sctpstat));
if (req->newptr != NULL) {
@@ -932,7 +915,6 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
sb.sctps_recvauthfailed += sarry->sctps_recvauthfailed;
sb.sctps_recvexpress += sarry->sctps_recvexpress;
sb.sctps_recvexpressm += sarry->sctps_recvexpressm;
- sb.sctps_recvnocrc += sarry->sctps_recvnocrc;
sb.sctps_recvswcrc += sarry->sctps_recvswcrc;
sb.sctps_recvhwcrc += sarry->sctps_recvhwcrc;
sb.sctps_sendpackets += sarry->sctps_sendpackets;
@@ -945,7 +927,6 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
sb.sctps_sendecne += sarry->sctps_sendecne;
sb.sctps_sendauth += sarry->sctps_sendauth;
sb.sctps_senderrors += sarry->sctps_senderrors;
- sb.sctps_sendnocrc += sarry->sctps_sendnocrc;
sb.sctps_sendswcrc += sarry->sctps_sendswcrc;
sb.sctps_sendhwcrc += sarry->sctps_sendhwcrc;
sb.sctps_pdrpfmbox += sarry->sctps_pdrpfmbox;
@@ -1039,7 +1020,7 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
}
#if defined(SCTP_LOCAL_TRACE_BUF)
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_trace_log SYSCTL_HANDLER_ARGS
{
@@ -1051,7 +1032,7 @@ sctp_sysctl_handle_trace_log(SYSCTL_HANDLER_ARGS)
#endif
int error;
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
error = SYSCTL_OUT(req, SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log));
#else
error = SYSCTL_OUT(req, &SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log));
@@ -1059,7 +1040,7 @@ sctp_sysctl_handle_trace_log(SYSCTL_HANDLER_ARGS)
return (error);
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
static int
sctp_sysctl_handle_trace_log_clear SYSCTL_HANDLER_ARGS
{
@@ -1070,7 +1051,7 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS)
{
#endif
int error = 0;
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
int value = 0;
if (req->new_data == NULL) {
@@ -1088,33 +1069,8 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS)
}
#endif
-#if defined(__APPLE__) || defined(__FreeBSD__)
+#if (defined(__APPLE__) || defined(__FreeBSD__)) && !defined(__Userspace__)
#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800056 && __FreeBSD_version < 1000100
-#ifdef VIMAGE
-#define SCTP_UINT_SYSCTL(name, var_name, prefix) \
- static int \
- sctp_sysctl_handle_##mib_name(SYSCTL_HANDLER_ARGS) \
- { \
- int error; \
- uint32_t new; \
- \
- new = SCTP_BASE_SYSCTL(var_name); \
- error = vnet_sysctl_handle_int(oidp, &new, 0, req); \
- if ((error == 0) && (req->newptr != NULL)) { \
- if ((new < prefix##_MIN) || \
- (new > prefix##_MAX)) { \
- error = EINVAL; \
- } else { \
- SCTP_BASE_SYSCTL(var_name) = new; \
- } \
- } \
- return (error); \
- } \
- SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \
- CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, \
- sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC);
-#else
#define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \
static int \
sctp_sysctl_handle_##mib_name(SYSCTL_HANDLER_ARGS) \
@@ -1137,31 +1093,6 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \
CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, \
sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC);
-#endif
-#else
-#define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \
- static int \
- sctp_sysctl_handle_##mib_name(SYSCTL_HANDLER_ARGS) \
- { \
- int error; \
- uint32_t new; \
- \
- new = SCTP_BASE_SYSCTL(var_name); \
- error = sysctl_handle_int(oidp, &new, 0, req); \
- if ((error == 0) && (req->newptr != NULL)) { \
- if ((new < prefix##_MIN) || \
- (new > prefix##_MAX)) { \
- error = EINVAL; \
- } else { \
- SCTP_BASE_SYSCTL(var_name) = new; \
- } \
- } \
- return (error); \
- } \
- SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \
- CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, \
- sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC);
-#endif
#else
#define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \
static int \
@@ -1208,12 +1139,9 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, CTLFLAG_VNET|CTLTYPE_UINT|C
SCTP_UINT_SYSCTL(reconfig_enable, sctp_reconfig_enable, SCTPCTL_RECONFIG_ENABLE)
SCTP_UINT_SYSCTL(nrsack_enable, sctp_nrsack_enable, SCTPCTL_NRSACK_ENABLE)
SCTP_UINT_SYSCTL(pktdrop_enable, sctp_pktdrop_enable, SCTPCTL_PKTDROP_ENABLE)
-SCTP_UINT_SYSCTL(strict_sacks, sctp_strict_sacks, SCTPCTL_STRICT_SACKS)
-#if defined(__APPLE__)
-#if !defined(SCTP_WITH_NO_CSUM)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_UINT_SYSCTL(loopback_nocsum, sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM)
#endif
-#endif
SCTP_UINT_SYSCTL(peer_chkoh, sctp_peer_chunk_oh, SCTPCTL_PEER_CHKOH)
SCTP_UINT_SYSCTL(maxburst, sctp_max_burst_default, SCTPCTL_MAXBURST)
SCTP_UINT_SYSCTL(fr_maxburst, sctp_fr_max_burst_default, SCTPCTL_FRMAXBURST)
@@ -1251,7 +1179,6 @@ SCTP_UINT_SYSCTL(max_chained_mbufs, sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAIN
SCTP_UINT_SYSCTL(do_sctp_drain, sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN)
SCTP_UINT_SYSCTL(hb_max_burst, sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST)
SCTP_UINT_SYSCTL(abort_at_limit, sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT)
-SCTP_UINT_SYSCTL(strict_data_order, sctp_strict_data_order, SCTPCTL_STRICT_DATA_ORDER)
SCTP_UINT_SYSCTL(min_residual, sctp_min_residual, SCTPCTL_MIN_RESIDUAL)
SCTP_UINT_SYSCTL(max_retran_chunk, sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK)
SCTP_UINT_SYSCTL(log_level, sctp_logging_level, SCTPCTL_LOGGING_LEVEL)
@@ -1279,18 +1206,19 @@ SCTP_UINT_SYSCTL(rttvar_eqret, sctp_rttvar_eqret, SCTPCTL_RTTVAR_EQRET)
SCTP_UINT_SYSCTL(rttvar_steady_step, sctp_steady_step, SCTPCTL_RTTVAR_STEADYS)
SCTP_UINT_SYSCTL(use_dcccecn, sctp_use_dccc_ecn, SCTPCTL_RTTVAR_DCCCECN)
SCTP_UINT_SYSCTL(blackhole, sctp_blackhole, SCTPCTL_BLACKHOLE)
+SCTP_UINT_SYSCTL(sendall_limit, sctp_sendall_limit, SCTPCTL_SENDALL_LIMIT)
SCTP_UINT_SYSCTL(diag_info_code, sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE)
#ifdef SCTP_DEBUG
SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG)
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_UINT_SYSCTL(main_timer, sctp_main_timer, SCTPCTL_MAIN_TIMER)
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, ignore_vmware_interfaces, CTLTYPE_UINT|CTLFLAG_RW,
NULL, 0, sctp_sysctl_handle_vmware_interfaces, "IU", SCTPCTL_IGNORE_VMWARE_INTERFACES_DESC);
SCTP_UINT_SYSCTL(addr_watchdog_limit, sctp_addr_watchdog_limit, SCTPCTL_ADDR_WATCHDOG_LIMIT)
SCTP_UINT_SYSCTL(vtag_watchdog_limit, sctp_vtag_watchdog_limit, SCTPCTL_VTAG_WATCHDOG_LIMIT)
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_UINT_SYSCTL(output_unlocked, sctp_output_unlocked, SCTPCTL_OUTPUT_UNLOCKED)
#endif
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_VNET|CTLTYPE_STRUCT|CTLFLAG_RW,
@@ -1298,7 +1226,7 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_VNET|CTLTYPE_STRUCT|CTLFLAG
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_VNET|CTLTYPE_OPAQUE|CTLFLAG_RD,
NULL, 0, sctp_sysctl_handle_assoclist, "S,xassoc", "List of active SCTP associations");
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
#define RANGECHK(var, min, max) \
if ((var) < (min)) { (var) = (min); } \
@@ -1320,10 +1248,7 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS)
RANGECHK(SCTP_BASE_SYSCTL(sctp_reconfig_enable), SCTPCTL_RECONFIG_ENABLE_MIN, SCTPCTL_RECONFIG_ENABLE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_nrsack_enable), SCTPCTL_NRSACK_ENABLE_MIN, SCTPCTL_NRSACK_ENABLE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_pktdrop_enable), SCTPCTL_PKTDROP_ENABLE_MIN, SCTPCTL_PKTDROP_ENABLE_MAX);
- RANGECHK(SCTP_BASE_SYSCTL(sctp_strict_sacks), SCTPCTL_STRICT_SACKS_MIN, SCTPCTL_STRICT_SACKS_MAX);
-#if !defined(SCTP_WITH_NO_CSUM)
RANGECHK(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), SCTPCTL_LOOPBACK_NOCSUM_MIN, SCTPCTL_LOOPBACK_NOCSUM_MAX);
-#endif
RANGECHK(SCTP_BASE_SYSCTL(sctp_peer_chunk_oh), SCTPCTL_PEER_CHKOH_MIN, SCTPCTL_PEER_CHKOH_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_max_burst_default), SCTPCTL_MAXBURST_MIN, SCTPCTL_MAXBURST_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_fr_max_burst_default), SCTPCTL_FRMAXBURST_MIN, SCTPCTL_FRMAXBURST_MAX);
@@ -1361,7 +1286,6 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS)
RANGECHK(SCTP_BASE_SYSCTL(sctp_do_drain), SCTPCTL_DO_SCTP_DRAIN_MIN, SCTPCTL_DO_SCTP_DRAIN_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_hb_maxburst), SCTPCTL_HB_MAX_BURST_MIN, SCTPCTL_HB_MAX_BURST_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), SCTPCTL_ABORT_AT_LIMIT_MIN, SCTPCTL_ABORT_AT_LIMIT_MAX);
- RANGECHK(SCTP_BASE_SYSCTL(sctp_strict_data_order), SCTPCTL_STRICT_DATA_ORDER_MIN, SCTPCTL_STRICT_DATA_ORDER_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_min_residual), SCTPCTL_MIN_RESIDUAL_MIN, SCTPCTL_MIN_RESIDUAL_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_max_retran_chunk), SCTPCTL_MAX_RETRAN_CHUNK_MIN, SCTPCTL_MAX_RETRAN_CHUNK_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_logging_level), SCTPCTL_LOGGING_LEVEL_MIN, SCTPCTL_LOGGING_LEVEL_MAX);
@@ -1381,6 +1305,7 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS)
RANGECHK(SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN, SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), SCTPCTL_NAT_FRIENDLY_INITS_MIN, SCTPCTL_NAT_FRIENDLY_INITS_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_blackhole), SCTPCTL_BLACKHOLE_MIN, SCTPCTL_BLACKHOLE_MAX);
+ RANGECHK(SCTP_BASE_SYSCTL(sctp_sendall_limit), SCTPCTL_SENDALL_LIMIT_MIN, SCTPCTL_SENDALL_LIMIT_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_diag_info_code), SCTPCTL_DIAG_INFO_CODE_MIN, SCTPCTL_DIAG_INFO_CODE_MAX);
#ifdef SCTP_DEBUG
RANGECHK(SCTP_BASE_SYSCTL(sctp_debug_on), SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX);
@@ -1393,149 +1318,143 @@ void
sysctl_setup_sctp(void)
{
sysctl_add_oid(&sysctl_oid_top, "sendspace", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_sendspace), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_sendspace), 0, sctp_sysctl_handle_int,
SCTPCTL_MAXDGRAM_DESC);
sysctl_add_oid(&sysctl_oid_top, "recvspace", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_recvspace), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_recvspace), 0, sctp_sysctl_handle_int,
SCTPCTL_RECVSPACE_DESC);
sysctl_add_oid(&sysctl_oid_top, "auto_asconf", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_auto_asconf), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_auto_asconf), 0, sctp_sysctl_handle_int,
SCTPCTL_AUTOASCONF_DESC);
sysctl_add_oid(&sysctl_oid_top, "ecn_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_ecn_enable), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_ecn_enable), 0, sctp_sysctl_handle_int,
SCTPCTL_ECN_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "pr_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_pr_enable), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_pr_enable), 0, sctp_sysctl_handle_int,
SCTPCTL_PR_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "auth_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_auth_enable), 0, sctp_sysctl_handle_auth,
+ &SCTP_BASE_SYSCTL(sctp_auth_enable), 0, sctp_sysctl_handle_auth,
SCTPCTL_AUTH_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "asconf_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_asconf_enable), 0, sctp_sysctl_handle_asconf,
+ &SCTP_BASE_SYSCTL(sctp_asconf_enable), 0, sctp_sysctl_handle_asconf,
SCTPCTL_ASCONF_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "reconfig_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_reconfig_enable), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_reconfig_enable), 0, sctp_sysctl_handle_int,
SCTPCTL_RECONFIG_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "nrsack_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_nrsack_enable), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_nrsack_enable), 0, sctp_sysctl_handle_int,
SCTPCTL_NRSACK_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "pktdrop_enable", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_pktdrop_enable), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_pktdrop_enable), 0, sctp_sysctl_handle_int,
SCTPCTL_PKTDROP_ENABLE_DESC);
- sysctl_add_oid(&sysctl_oid_top, "strict_sacks", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_strict_sacks), 0, sctp_sysctl_handle_int,
- SCTPCTL_STRICT_SACKS_DESC);
-
-#if !defined(SCTP_WITH_NO_CSUM)
sysctl_add_oid(&sysctl_oid_top, "loopback_nocsum", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), 0, sctp_sysctl_handle_int,
SCTPCTL_LOOPBACK_NOCSUM_DESC);
-#endif
sysctl_add_oid(&sysctl_oid_top, "peer_chkoh", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_peer_chunk_oh), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_peer_chunk_oh), 0, sctp_sysctl_handle_int,
SCTPCTL_PEER_CHKOH_DESC);
sysctl_add_oid(&sysctl_oid_top, "maxburst", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_max_burst_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_max_burst_default), 0, sctp_sysctl_handle_int,
SCTPCTL_MAXBURST_DESC);
sysctl_add_oid(&sysctl_oid_top, "fr_maxburst", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_fr_max_burst_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_fr_max_burst_default), 0, sctp_sysctl_handle_int,
SCTPCTL_FRMAXBURST_DESC);
sysctl_add_oid(&sysctl_oid_top, "maxchunks", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue), 0, sctp_sysctl_handle_int,
SCTPCTL_MAXCHUNKS_DESC);
sysctl_add_oid(&sysctl_oid_top, "tcbhashsize", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_hashtblsize), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_hashtblsize), 0, sctp_sysctl_handle_int,
SCTPCTL_TCBHASHSIZE_DESC);
sysctl_add_oid(&sysctl_oid_top, "pcbhashsize", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_pcbtblsize), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_pcbtblsize), 0, sctp_sysctl_handle_int,
SCTPCTL_PCBHASHSIZE_DESC);
sysctl_add_oid(&sysctl_oid_top, "min_split_point", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_min_split_point), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_min_split_point), 0, sctp_sysctl_handle_int,
SCTPCTL_MIN_SPLIT_POINT_DESC);
sysctl_add_oid(&sysctl_oid_top, "chunkscale", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_chunkscale), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_chunkscale), 0, sctp_sysctl_handle_int,
SCTPCTL_CHUNKSCALE_DESC);
sysctl_add_oid(&sysctl_oid_top, "delayed_sack_time", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default), 0, sctp_sysctl_handle_int,
SCTPCTL_DELAYED_SACK_TIME_DESC);
sysctl_add_oid(&sysctl_oid_top, "sack_freq", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_sack_freq_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_sack_freq_default), 0, sctp_sysctl_handle_int,
SCTPCTL_SACK_FREQ_DESC);
sysctl_add_oid(&sysctl_oid_top, "sys_resource", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_system_free_resc_limit), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_system_free_resc_limit), 0, sctp_sysctl_handle_int,
SCTPCTL_SYS_RESOURCE_DESC);
sysctl_add_oid(&sysctl_oid_top, "asoc_resource", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_asoc_free_resc_limit), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_asoc_free_resc_limit), 0, sctp_sysctl_handle_int,
SCTPCTL_ASOC_RESOURCE_DESC);
sysctl_add_oid(&sysctl_oid_top, "heartbeat_interval", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default), 0, sctp_sysctl_handle_int,
SCTPCTL_HEARTBEAT_INTERVAL_DESC);
sysctl_add_oid(&sysctl_oid_top, "pmtu_raise_time", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default), 0, sctp_sysctl_handle_int,
SCTPCTL_PMTU_RAISE_TIME_DESC);
sysctl_add_oid(&sysctl_oid_top, "shutdown_guard_time", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default), 0, sctp_sysctl_handle_int,
SCTPCTL_SHUTDOWN_GUARD_TIME_DESC);
sysctl_add_oid(&sysctl_oid_top, "secret_lifetime", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_secret_lifetime_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_secret_lifetime_default), 0, sctp_sysctl_handle_int,
SCTPCTL_SECRET_LIFETIME_DESC);
sysctl_add_oid(&sysctl_oid_top, "rto_max", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_rto_max_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_rto_max_default), 0, sctp_sysctl_handle_int,
SCTPCTL_RTO_MAX_DESC);
sysctl_add_oid(&sysctl_oid_top, "rto_min", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_rto_min_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_rto_min_default), 0, sctp_sysctl_handle_int,
SCTPCTL_RTO_MIN_DESC);
sysctl_add_oid(&sysctl_oid_top, "rto_initial", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_rto_initial_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_rto_initial_default), 0, sctp_sysctl_handle_int,
SCTPCTL_RTO_INITIAL_DESC);
sysctl_add_oid(&sysctl_oid_top, "init_rto_max", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_init_rto_max_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_init_rto_max_default), 0, sctp_sysctl_handle_int,
SCTPCTL_INIT_RTO_MAX_DESC);
sysctl_add_oid(&sysctl_oid_top, "valid_cookie_life", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default), 0, sctp_sysctl_handle_int,
SCTPCTL_VALID_COOKIE_LIFE_DESC);
sysctl_add_oid(&sysctl_oid_top, "init_rtx_max", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), 0, sctp_sysctl_handle_int,
SCTPCTL_INIT_RTX_MAX_DESC);
sysctl_add_oid(&sysctl_oid_top, "assoc_rtx_max", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), 0, sctp_sysctl_handle_int,
SCTPCTL_ASSOC_RTX_MAX_DESC);
sysctl_add_oid(&sysctl_oid_top, "path_rtx_max", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sctp_sysctl_handle_int,
SCTPCTL_PATH_RTX_MAX_DESC);
sysctl_add_oid(&sysctl_oid_top, "path_pf_threshold", CTLTYPE_INT|CTLFLAG_RW,
@@ -1543,87 +1462,83 @@ sysctl_setup_sctp(void)
SCTPCTL_PATH_PF_THRESHOLD_DESC);
sysctl_add_oid(&sysctl_oid_top, "add_more_on_output", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sctp_sysctl_handle_int,
SCTPCTL_ADD_MORE_ON_OUTPUT_DESC);
sysctl_add_oid(&sysctl_oid_top, "incoming_streams", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_nr_incoming_streams_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_nr_incoming_streams_default), 0, sctp_sysctl_handle_int,
SCTPCTL_INCOMING_STREAMS_DESC);
sysctl_add_oid(&sysctl_oid_top, "outgoing_streams", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), 0, sctp_sysctl_handle_int,
SCTPCTL_OUTGOING_STREAMS_DESC);
sysctl_add_oid(&sysctl_oid_top, "cmt_on_off", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_cmt_on_off), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_cmt_on_off), 0, sctp_sysctl_handle_int,
SCTPCTL_CMT_ON_OFF_DESC);
sysctl_add_oid(&sysctl_oid_top, "cmt_use_dac", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sctp_sysctl_handle_int,
SCTPCTL_CMT_USE_DAC_DESC);
sysctl_add_oid(&sysctl_oid_top, "cwnd_maxburst", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sctp_sysctl_handle_int,
SCTPCTL_CWND_MAXBURST_DESC);
sysctl_add_oid(&sysctl_oid_top, "nat_friendly", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_nat_friendly), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_nat_friendly), 0, sctp_sysctl_handle_int,
SCTPCTL_NAT_FRIENDLY_DESC);
sysctl_add_oid(&sysctl_oid_top, "abc_l_var", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_L2_abc_variable), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_L2_abc_variable), 0, sctp_sysctl_handle_int,
SCTPCTL_ABC_L_VAR_DESC);
sysctl_add_oid(&sysctl_oid_top, "max_chained_mbufs", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count), 0, sctp_sysctl_handle_int,
SCTPCTL_MAX_CHAINED_MBUFS_DESC);
sysctl_add_oid(&sysctl_oid_top, "do_sctp_drain", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_do_drain), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_do_drain), 0, sctp_sysctl_handle_int,
SCTPCTL_DO_SCTP_DRAIN_DESC);
sysctl_add_oid(&sysctl_oid_top, "hb_max_burst", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_hb_maxburst), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_hb_maxburst), 0, sctp_sysctl_handle_int,
SCTPCTL_HB_MAX_BURST_DESC);
sysctl_add_oid(&sysctl_oid_top, "abort_at_limit", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), 0, sctp_sysctl_handle_int,
SCTPCTL_ABORT_AT_LIMIT_DESC);
- sysctl_add_oid(&sysctl_oid_top, "strict_data_order", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_strict_data_order), 0, sctp_sysctl_handle_int,
- SCTPCTL_STRICT_DATA_ORDER_DESC);
-
sysctl_add_oid(&sysctl_oid_top, "min_residual", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_min_residual), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_min_residual), 0, sctp_sysctl_handle_int,
SCTPCTL_MIN_RESIDUAL_DESC);
sysctl_add_oid(&sysctl_oid_top, "max_retran_chunk", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_max_retran_chunk), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_max_retran_chunk), 0, sctp_sysctl_handle_int,
SCTPCTL_MAX_RETRAN_CHUNK_DESC);
sysctl_add_oid(&sysctl_oid_top, "log_level", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_logging_level), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_logging_level), 0, sctp_sysctl_handle_int,
SCTPCTL_LOGGING_LEVEL_DESC);
sysctl_add_oid(&sysctl_oid_top, "default_cc_module", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_default_cc_module), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_default_cc_module), 0, sctp_sysctl_handle_int,
SCTPCTL_DEFAULT_CC_MODULE_DESC);
sysctl_add_oid(&sysctl_oid_top, "default_ss_module", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_default_ss_module), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_default_ss_module), 0, sctp_sysctl_handle_int,
SCTPCTL_DEFAULT_SS_MODULE_DESC);
sysctl_add_oid(&sysctl_oid_top, "default_frag_interleave", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_default_frag_interleave), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_default_frag_interleave), 0, sctp_sysctl_handle_int,
SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC);
sysctl_add_oid(&sysctl_oid_top, "mobility_base", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_mobility_base), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_mobility_base), 0, sctp_sysctl_handle_int,
SCTPCTL_MOBILITY_BASE_DESC);
sysctl_add_oid(&sysctl_oid_top, "mobility_fasthandoff", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), 0, sctp_sysctl_handle_int,
SCTPCTL_MOBILITY_FASTHANDOFF_DESC);
#if defined(SCTP_LOCAL_TRACE_BUF)
@@ -1641,52 +1556,56 @@ sysctl_setup_sctp(void)
SCTPCTL_UDP_TUNNELING_PORT_DESC);
sysctl_add_oid(&sysctl_oid_top, "enable_sack_immediately", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), 0, sctp_sysctl_handle_int,
SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC);
sysctl_add_oid(&sysctl_oid_top, "nat_friendly_init", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), 0, sctp_sysctl_handle_int,
SCTPCTL_NAT_FRIENDLY_DESC);
sysctl_add_oid(&sysctl_oid_top, "vtag_time_wait", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_vtag_time_wait), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_vtag_time_wait), 0, sctp_sysctl_handle_int,
SCTPCTL_TIME_WAIT_DESC);
sysctl_add_oid(&sysctl_oid_top, "buffer_splitting", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_buffer_splitting), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_buffer_splitting), 0, sctp_sysctl_handle_int,
SCTPCTL_BUFFER_SPLITTING_DESC);
sysctl_add_oid(&sysctl_oid_top, "initial_cwnd", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_initial_cwnd), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_initial_cwnd), 0, sctp_sysctl_handle_int,
SCTPCTL_INITIAL_CWND_DESC);
sysctl_add_oid(&sysctl_oid_top, "rttvar_bw", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_rttvar_bw), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_rttvar_bw), 0, sctp_sysctl_handle_int,
SCTPCTL_RTTVAR_BW_DESC);
sysctl_add_oid(&sysctl_oid_top, "rttvar_rtt", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_rttvar_rtt), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_rttvar_rtt), 0, sctp_sysctl_handle_int,
SCTPCTL_RTTVAR_RTT_DESC);
sysctl_add_oid(&sysctl_oid_top, "rttvar_eqret", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_rttvar_eqret), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_rttvar_eqret), 0, sctp_sysctl_handle_int,
SCTPCTL_RTTVAR_EQRET_DESC);
sysctl_add_oid(&sysctl_oid_top, "rttvar_steady_step", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_steady_step), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_steady_step), 0, sctp_sysctl_handle_int,
SCTPCTL_RTTVAR_STEADYS_DESC);
sysctl_add_oid(&sysctl_oid_top, "use_dcccecn", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_use_dccc_ecn), 0, sctp_sysctl_handle_int,
+ &SCTP_BASE_SYSCTL(sctp_use_dccc_ecn), 0, sctp_sysctl_handle_int,
SCTPCTL_RTTVAR_DCCCECN_DESC);
sysctl_add_oid(&sysctl_oid_top, "blackhole", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_blackhole), 0, sctp_sysctl_handle_int,
- SCTPCTL_BLACKHOLE_DESC);
+ &SCTP_BASE_SYSCTL(sctp_blackhole), 0, sctp_sysctl_handle_int,
+ SCTPCTL_BLACKHOLE_DESC);
+
+ sysctl_add_oid(&sysctl_oid_top, "sendall_limit", CTLTYPE_INT|CTLFLAG_RW,
+ &SCTP_BASE_SYSCTL(sctp_sendall_limit), 0, sctp_sysctl_handle_int,
+ SCTPCTL_SENDALL_LIMIT_DESC);
sysctl_add_oid(&sysctl_oid_top, "diag_info_code", CTLTYPE_INT|CTLFLAG_RW,
- &SCTP_BASE_SYSCTL(sctp_diag_info_code), 0, sctp_sysctl_handle_int,
- SCTPCTL_DIAG_INFO_CODE_DESC);
+ &SCTP_BASE_SYSCTL(sctp_diag_info_code), 0, sctp_sysctl_handle_int,
+ SCTPCTL_DIAG_INFO_CODE_DESC);
#ifdef SCTP_DEBUG
sysctl_add_oid(&sysctl_oid_top, "debug", CTLTYPE_INT|CTLFLAG_RW,
diff --git a/netwerk/sctp/src/netinet/sctp_sysctl.h b/netwerk/sctp/src/netinet/sctp_sysctl.h
index 3a33b71f9b..006a11f31d 100755
--- a/netwerk/sctp/src/netinet/sctp_sysctl.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.h 271204 2014-09-06 19:12:14Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.h 366750 2020-10-16 10:44:48Z tuexen $");
#endif
#ifndef _NETINET_SCTP_SYSCTL_H_
@@ -54,12 +56,9 @@ struct sctp_sysctl {
uint32_t sctp_nrsack_enable;
uint32_t sctp_pktdrop_enable;
uint32_t sctp_fr_max_burst_default;
- uint32_t sctp_strict_sacks;
-#if !(defined(__FreeBSD__) && __FreeBSD_version >= 800000)
-#if !defined(SCTP_WITH_NO_CSUM)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
uint32_t sctp_no_csum_on_loopback;
#endif
-#endif
uint32_t sctp_peer_chunk_oh;
uint32_t sctp_max_burst_default;
uint32_t sctp_max_chunks_on_queue;
@@ -96,7 +95,6 @@ struct sctp_sysctl {
uint32_t sctp_do_drain;
uint32_t sctp_hb_maxburst;
uint32_t sctp_abort_if_one_2_one_hits_limit;
- uint32_t sctp_strict_data_order;
uint32_t sctp_min_residual;
uint32_t sctp_max_retran_chunk;
uint32_t sctp_logging_level;
@@ -115,7 +113,7 @@ struct sctp_sysctl {
uint32_t sctp_use_dccc_ecn;
uint32_t sctp_diag_info_code;
#if defined(SCTP_LOCAL_TRACE_BUF)
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
struct sctp_log *sctp_log;
#else
struct sctp_log sctp_log;
@@ -127,16 +125,17 @@ struct sctp_sysctl {
uint32_t sctp_buffer_splitting;
uint32_t sctp_initial_cwnd;
uint32_t sctp_blackhole;
+ uint32_t sctp_sendall_limit;
#if defined(SCTP_DEBUG)
uint32_t sctp_debug_on;
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
uint32_t sctp_ignore_vmware_interfaces;
uint32_t sctp_main_timer;
uint32_t sctp_addr_watchdog_limit;
uint32_t sctp_vtag_watchdog_limit;
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
uint32_t sctp_output_unlocked;
#endif
};
@@ -148,13 +147,21 @@ struct sctp_sysctl {
#define SCTPCTL_MAXDGRAM_DESC "Maximum outgoing SCTP buffer size"
#define SCTPCTL_MAXDGRAM_MIN 0
#define SCTPCTL_MAXDGRAM_MAX 0xFFFFFFFF
+#if defined(__Userspace__)
+#define SCTPCTL_MAXDGRAM_DEFAULT SB_MAX
+#else
#define SCTPCTL_MAXDGRAM_DEFAULT 262144 /* 256k */
+#endif
/* recvspace: Maximum incoming SCTP buffer size */
#define SCTPCTL_RECVSPACE_DESC "Maximum incoming SCTP buffer size"
#define SCTPCTL_RECVSPACE_MIN 0
#define SCTPCTL_RECVSPACE_MAX 0xFFFFFFFF
+#if defined(__Userspace__)
+#define SCTPCTL_RECVSPACE_DEFAULT SB_RAW
+#else
#define SCTPCTL_RECVSPACE_DEFAULT 262144 /* 256k */
+#endif
/* autoasconf: Enable SCTP Auto-ASCONF */
#define SCTPCTL_AUTOASCONF_DESC "Enable SCTP Auto-ASCONF"
@@ -210,12 +217,6 @@ struct sctp_sysctl {
#define SCTPCTL_PKTDROP_ENABLE_MAX 1
#define SCTPCTL_PKTDROP_ENABLE_DEFAULT 0
-/* strict_sacks: Enable SCTP Strict SACK checking */
-#define SCTPCTL_STRICT_SACKS_DESC "Enable SCTP Strict SACK checking"
-#define SCTPCTL_STRICT_SACKS_MIN 0
-#define SCTPCTL_STRICT_SACKS_MAX 1
-#define SCTPCTL_STRICT_SACKS_DEFAULT 1
-
/* loopback_nocsum: Enable NO Csum on packets sent on loopback */
#define SCTPCTL_LOOPBACK_NOCSUM_DESC "Enable NO Csum on packets sent on loopback"
#define SCTPCTL_LOOPBACK_NOCSUM_MIN 0
@@ -235,12 +236,11 @@ struct sctp_sysctl {
#define SCTPCTL_MAXBURST_DEFAULT SCTP_DEF_MAX_BURST
/* fr_maxburst: Default max burst for sctp endpoints when fast retransmitting */
-#define SCTPCTL_FRMAXBURST_DESC "Default fr max burst for sctp endpoints"
+#define SCTPCTL_FRMAXBURST_DESC "Default max burst for SCTP endpoints when fast retransmitting"
#define SCTPCTL_FRMAXBURST_MIN 0
#define SCTPCTL_FRMAXBURST_MAX 0xFFFFFFFF
#define SCTPCTL_FRMAXBURST_DEFAULT SCTP_DEF_FRMAX_BURST
-
/* maxchunks: Default max chunks on queue per asoc */
#define SCTPCTL_MAXCHUNKS_DESC "Default max chunks on queue per asoc"
#define SCTPCTL_MAXCHUNKS_MIN 0
@@ -266,7 +266,7 @@ struct sctp_sysctl {
#define SCTPCTL_MIN_SPLIT_POINT_DEFAULT SCTP_DEFAULT_SPLIT_POINT_MIN
/* chunkscale: Tunable for Scaling of number of chunks and messages */
-#define SCTPCTL_CHUNKSCALE_DESC "Tunable for Scaling of number of chunks and messages"
+#define SCTPCTL_CHUNKSCALE_DESC "Tunable for scaling of number of chunks and messages"
#define SCTPCTL_CHUNKSCALE_MIN 1
#define SCTPCTL_CHUNKSCALE_MAX 0xFFFFFFFF
#define SCTPCTL_CHUNKSCALE_DEFAULT SCTP_CHUNKQUEUE_SCALE
@@ -308,10 +308,10 @@ struct sctp_sysctl {
#define SCTPCTL_PMTU_RAISE_TIME_DEFAULT SCTP_DEF_PMTU_RAISE_SEC
/* shutdown_guard_time: Default shutdown guard timer in seconds */
-#define SCTPCTL_SHUTDOWN_GUARD_TIME_DESC "Default shutdown guard timer in seconds"
+#define SCTPCTL_SHUTDOWN_GUARD_TIME_DESC "Shutdown guard timer in seconds (0 means 5 times RTO.Max)"
#define SCTPCTL_SHUTDOWN_GUARD_TIME_MIN 0
#define SCTPCTL_SHUTDOWN_GUARD_TIME_MAX 0xFFFFFFFF
-#define SCTPCTL_SHUTDOWN_GUARD_TIME_DEFAULT SCTP_DEF_MAX_SHUTDOWN_SEC
+#define SCTPCTL_SHUTDOWN_GUARD_TIME_DEFAULT 0
/* secret_lifetime: Default secret lifetime in seconds */
#define SCTPCTL_SECRET_LIFETIME_DESC "Default secret lifetime in seconds"
@@ -343,14 +343,14 @@ struct sctp_sysctl {
#define SCTPCTL_INIT_RTO_MAX_MAX 0xFFFFFFFF
#define SCTPCTL_INIT_RTO_MAX_DEFAULT SCTP_RTO_UPPER_BOUND
-/* valid_cookie_life: Default cookie lifetime in sec */
-#define SCTPCTL_VALID_COOKIE_LIFE_DESC "Default cookie lifetime in seconds"
-#define SCTPCTL_VALID_COOKIE_LIFE_MIN 0
-#define SCTPCTL_VALID_COOKIE_LIFE_MAX 0xFFFFFFFF
+/* valid_cookie_life: Default cookie lifetime in ms */
+#define SCTPCTL_VALID_COOKIE_LIFE_DESC "Default cookie lifetime in ms"
+#define SCTPCTL_VALID_COOKIE_LIFE_MIN SCTP_MIN_COOKIE_LIFE
+#define SCTPCTL_VALID_COOKIE_LIFE_MAX SCTP_MAX_COOKIE_LIFE
#define SCTPCTL_VALID_COOKIE_LIFE_DEFAULT SCTP_DEFAULT_COOKIE_LIFE
/* init_rtx_max: Default maximum number of retransmission for INIT chunks */
-#define SCTPCTL_INIT_RTX_MAX_DESC "Default maximum number of retransmission for INIT chunks"
+#define SCTPCTL_INIT_RTX_MAX_DESC "Default maximum number of retransmissions for INIT chunks"
#define SCTPCTL_INIT_RTX_MAX_MIN 0
#define SCTPCTL_INIT_RTX_MAX_MAX 0xFFFFFFFF
#define SCTPCTL_INIT_RTX_MAX_DEFAULT SCTP_DEF_MAX_INIT
@@ -403,8 +403,8 @@ struct sctp_sysctl {
#define SCTPCTL_CMT_USE_DAC_MAX 1
#define SCTPCTL_CMT_USE_DAC_DEFAULT 0
-/* cwnd_maxburst: Use a CWND adjusting maxburst */
-#define SCTPCTL_CWND_MAXBURST_DESC "Use a CWND adjusting maxburst"
+/* cwnd_maxburst: Use a CWND adjusting to implement maxburst */
+#define SCTPCTL_CWND_MAXBURST_DESC "Adjust congestion control window to limit maximum burst when sending"
#define SCTPCTL_CWND_MAXBURST_MIN 0
#define SCTPCTL_CWND_MAXBURST_MAX 1
#define SCTPCTL_CWND_MAXBURST_DEFAULT 1
@@ -440,17 +440,11 @@ struct sctp_sysctl {
#define SCTPCTL_HB_MAX_BURST_DEFAULT SCTP_DEF_HBMAX_BURST
/* abort_at_limit: When one-2-one hits qlimit abort */
-#define SCTPCTL_ABORT_AT_LIMIT_DESC "When one-2-one hits qlimit abort"
+#define SCTPCTL_ABORT_AT_LIMIT_DESC "Abort when one-to-one hits qlimit"
#define SCTPCTL_ABORT_AT_LIMIT_MIN 0
#define SCTPCTL_ABORT_AT_LIMIT_MAX 1
#define SCTPCTL_ABORT_AT_LIMIT_DEFAULT 0
-/* strict_data_order: Enforce strict data ordering, abort if control inside data */
-#define SCTPCTL_STRICT_DATA_ORDER_DESC "Enforce strict data ordering, abort if control inside data"
-#define SCTPCTL_STRICT_DATA_ORDER_MIN 0
-#define SCTPCTL_STRICT_DATA_ORDER_MAX 1
-#define SCTPCTL_STRICT_DATA_ORDER_DEFAULT 0
-
/* min_residual: min residual in a data fragment leftover */
#define SCTPCTL_MIN_RESIDUAL_DESC "Minimum residual data chunk in second part of split"
#define SCTPCTL_MIN_RESIDUAL_MIN 20
@@ -458,7 +452,7 @@ struct sctp_sysctl {
#define SCTPCTL_MIN_RESIDUAL_DEFAULT 1452
/* max_retran_chunk: max chunk retransmissions */
-#define SCTPCTL_MAX_RETRAN_CHUNK_DESC "Maximum times an unlucky chunk can be retran'd before assoc abort"
+#define SCTPCTL_MAX_RETRAN_CHUNK_DESC "Maximum times an unlucky chunk can be retransmitted before assoc abort"
#define SCTPCTL_MAX_RETRAN_CHUNK_MIN 0
#define SCTPCTL_MAX_RETRAN_CHUNK_MAX 65535
#define SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT 30
@@ -503,74 +497,80 @@ struct sctp_sysctl {
#define SCTPCTL_UDP_TUNNELING_PORT_DESC "Set the SCTP/UDP tunneling port"
#define SCTPCTL_UDP_TUNNELING_PORT_MIN 0
#define SCTPCTL_UDP_TUNNELING_PORT_MAX 65535
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#define SCTPCTL_UDP_TUNNELING_PORT_DEFAULT 0
#else
#define SCTPCTL_UDP_TUNNELING_PORT_DEFAULT SCTP_OVER_UDP_TUNNELING_PORT
#endif
/* Enable sending of the SACK-IMMEDIATELY bit */
-#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC "Enable sending of the SACK-IMMEDIATELY-bit."
+#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC "Enable sending of the SACK-IMMEDIATELY-bit"
#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN 0
#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX 1
-#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN
+#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX
/* Enable sending of the NAT-FRIENDLY message */
-#define SCTPCTL_NAT_FRIENDLY_INITS_DESC "Enable sending of the nat-friendly SCTP option on INITs."
+#define SCTPCTL_NAT_FRIENDLY_INITS_DESC "Enable sending of the nat-friendly SCTP option on INITs"
#define SCTPCTL_NAT_FRIENDLY_INITS_MIN 0
#define SCTPCTL_NAT_FRIENDLY_INITS_MAX 1
#define SCTPCTL_NAT_FRIENDLY_INITS_DEFAULT SCTPCTL_NAT_FRIENDLY_INITS_MIN
/* Vtag time wait in seconds */
-#define SCTPCTL_TIME_WAIT_DESC "Vtag time wait time in seconds, 0 disables it."
+#define SCTPCTL_TIME_WAIT_DESC "Vtag time wait time in seconds, 0 disables it"
#define SCTPCTL_TIME_WAIT_MIN 0
#define SCTPCTL_TIME_WAIT_MAX 0xffffffff
#define SCTPCTL_TIME_WAIT_DEFAULT SCTP_TIME_WAIT
/* Enable Send/Receive buffer splitting */
-#define SCTPCTL_BUFFER_SPLITTING_DESC "Enable send/receive buffer splitting."
+#define SCTPCTL_BUFFER_SPLITTING_DESC "Enable send/receive buffer splitting"
#define SCTPCTL_BUFFER_SPLITTING_MIN 0
#define SCTPCTL_BUFFER_SPLITTING_MAX 0x3
#define SCTPCTL_BUFFER_SPLITTING_DEFAULT SCTPCTL_BUFFER_SPLITTING_MIN
-/* Initial congestion window in MTU */
-#define SCTPCTL_INITIAL_CWND_DESC "Initial congestion window in MTUs"
+/* Initial congestion window in MTUs */
+#define SCTPCTL_INITIAL_CWND_DESC "Defines the initial congestion window size in MTUs"
#define SCTPCTL_INITIAL_CWND_MIN 0
#define SCTPCTL_INITIAL_CWND_MAX 0xffffffff
#define SCTPCTL_INITIAL_CWND_DEFAULT 3
/* rttvar smooth avg for bw calc */
-#define SCTPCTL_RTTVAR_BW_DESC "Shift amount for bw smoothing on rtt calc"
+#define SCTPCTL_RTTVAR_BW_DESC "Shift amount DCCC uses for bw smoothing on rtt calc"
#define SCTPCTL_RTTVAR_BW_MIN 0
#define SCTPCTL_RTTVAR_BW_MAX 32
#define SCTPCTL_RTTVAR_BW_DEFAULT 4
/* rttvar smooth avg for bw calc */
-#define SCTPCTL_RTTVAR_RTT_DESC "Shift amount for rtt smoothing on rtt calc"
+#define SCTPCTL_RTTVAR_RTT_DESC "Shift amount DCCC uses for rtt smoothing on rtt calc"
#define SCTPCTL_RTTVAR_RTT_MIN 0
#define SCTPCTL_RTTVAR_RTT_MAX 32
#define SCTPCTL_RTTVAR_RTT_DEFAULT 5
-#define SCTPCTL_RTTVAR_EQRET_DESC "What to return when rtt and bw are unchanged"
+#define SCTPCTL_RTTVAR_EQRET_DESC "Whether DCCC increases cwnd when the rtt and bw are unchanged"
#define SCTPCTL_RTTVAR_EQRET_MIN 0
#define SCTPCTL_RTTVAR_EQRET_MAX 1
#define SCTPCTL_RTTVAR_EQRET_DEFAULT 0
-#define SCTPCTL_RTTVAR_STEADYS_DESC "How many the sames it takes to try step down of cwnd"
+#define SCTPCTL_RTTVAR_STEADYS_DESC "Number of identical bw measurements DCCC takes to try step down of cwnd"
#define SCTPCTL_RTTVAR_STEADYS_MIN 0
#define SCTPCTL_RTTVAR_STEADYS_MAX 0xFFFF
#define SCTPCTL_RTTVAR_STEADYS_DEFAULT 20 /* 0 means disable feature */
-#define SCTPCTL_RTTVAR_DCCCECN_DESC "Enable for RTCC CC datacenter ECN"
+#define SCTPCTL_RTTVAR_DCCCECN_DESC "Enable ECN for DCCC."
#define SCTPCTL_RTTVAR_DCCCECN_MIN 0
#define SCTPCTL_RTTVAR_DCCCECN_MAX 1
#define SCTPCTL_RTTVAR_DCCCECN_DEFAULT 1 /* 0 means disable feature */
-#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing"
+#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing, see blackhole(4) for more details"
#define SCTPCTL_BLACKHOLE_MIN 0
#define SCTPCTL_BLACKHOLE_MAX 2
#define SCTPCTL_BLACKHOLE_DEFAULT SCTPCTL_BLACKHOLE_MIN
+/* sendall_limit: Maximum message with SCTP_SENDALL */
+#define SCTPCTL_SENDALL_LIMIT_DESC "Maximum size of a message send with SCTP_SENDALL"
+#define SCTPCTL_SENDALL_LIMIT_MIN 0
+#define SCTPCTL_SENDALL_LIMIT_MAX 0xFFFFFFFF
+#define SCTPCTL_SENDALL_LIMIT_DEFAULT 1432
+
#define SCTPCTL_DIAG_INFO_CODE_DESC "Diagnostic information error cause code"
#define SCTPCTL_DIAG_INFO_CODE_MIN 0
#define SCTPCTL_DIAG_INFO_CODE_MAX 65535
@@ -584,7 +584,7 @@ struct sctp_sysctl {
#define SCTPCTL_DEBUG_DEFAULT 0
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#define SCTPCTL_MAIN_TIMER_DESC "Main timer interval in ms"
#define SCTPCTL_MAIN_TIMER_MIN 1
#define SCTPCTL_MAIN_TIMER_MAX 0xFFFFFFFF
@@ -594,16 +594,12 @@ struct sctp_sysctl {
#define SCTPCTL_IGNORE_VMWARE_INTERFACES_MIN 0
#define SCTPCTL_IGNORE_VMWARE_INTERFACES_MAX 1
#define SCTPCTL_IGNORE_VMWARE_INTERFACES_DEFAULT SCTPCTL_IGNORE_VMWARE_INTERFACES_MAX
-#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-#define SCTPCTL_OUTPUT_UNLOCKED_DESC "Unlock socket when sending packets down to IP."
+#define SCTPCTL_OUTPUT_UNLOCKED_DESC "Unlock socket when sending packets down to IP"
#define SCTPCTL_OUTPUT_UNLOCKED_MIN 0
#define SCTPCTL_OUTPUT_UNLOCKED_MAX 1
#define SCTPCTL_OUTPUT_UNLOCKED_DEFAULT SCTPCTL_OUTPUT_UNLOCKED_MIN
-#endif
-#if defined(__APPLE__)
#define SCTPCTL_ADDR_WATCHDOG_LIMIT_DESC "Address watchdog limit"
#define SCTPCTL_ADDR_WATCHDOG_LIMIT_MIN 0
#define SCTPCTL_ADDR_WATCHDOG_LIMIT_MAX 0xFFFFFFFF
@@ -613,8 +609,8 @@ struct sctp_sysctl {
#define SCTPCTL_VTAG_WATCHDOG_LIMIT_MIN 0
#define SCTPCTL_VTAG_WATCHDOG_LIMIT_MAX 0xFFFFFFFF
#define SCTPCTL_VTAG_WATCHDOG_LIMIT_DEFAULT SCTPCTL_VTAG_WATCHDOG_LIMIT_MIN
-#endif
+#endif
#if defined(_KERNEL) || defined(__Userspace__)
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
#if defined(SYSCTL_DECL)
@@ -623,7 +619,7 @@ SYSCTL_DECL(_net_inet_sctp);
#endif
void sctp_init_sysctls(void);
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
void sctp_finish_sysctls(void);
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_timer.c b/netwerk/sctp/src/netinet/sctp_timer.c
index 48ad459028..a0ca4aabf4 100755
--- a/netwerk/sctp/src/netinet/sctp_timer.c
+++ b/netwerk/sctp/src/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.
@@ -30,16 +32,16 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 279841 2015-03-10 09:16:31Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 365071 2020-09-01 21:19:14Z mjg $");
#endif
#define _IP_VHL
#include <netinet/sctp_os.h>
#include <netinet/sctp_pcb.h>
#ifdef INET6
-#if defined(__Userspace_os_FreeBSD)
+#if defined(__FreeBSD__) && defined(__Userspace__)
#include <netinet6/sctp6_var.h>
#endif
#endif
@@ -55,15 +57,11 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 279841 2015-03-10 09:16:31Z tu
#include <netinet/sctp.h>
#include <netinet/sctp_uio.h>
#if defined(INET) || defined(INET6)
-#if !defined(__Userspace_os_Windows)
+#if !(defined(_WIN32) && defined(__Userspace__))
#include <netinet/udp.h>
#endif
#endif
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 6
-#endif
-
void
sctp_audit_retranmission_queue(struct sctp_association *asoc)
{
@@ -95,7 +93,7 @@ sctp_audit_retranmission_queue(struct sctp_association *asoc)
asoc->sent_queue_cnt);
}
-int
+static int
sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net, uint16_t threshold)
{
@@ -120,8 +118,10 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
net->dest_state |= SCTP_ADDR_PF;
net->last_active = sctp_get_tick_count();
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ inp, stcb, net,
+ SCTP_FROM_SCTP_TIMER + SCTP_LOC_1);
+ sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
}
}
}
@@ -161,9 +161,9 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* Abort notification sends a ULP notify */
struct mbuf *op_err;
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION,
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Association error counter exceeded");
- inp->last_abort_code = SCTP_FROM_SCTP_TIMER+SCTP_LOC_1;
+ inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_2;
sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (1);
}
@@ -344,7 +344,11 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
return (NULL);
}
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (alt->ro.ro_nh == NULL) {
+#else
if (alt->ro.ro_rt == NULL) {
+#endif
if (alt->ro._s_addr) {
sctp_free_ifa(alt->ro._s_addr);
alt->ro._s_addr = NULL;
@@ -352,7 +356,11 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
alt->src_addr_selected = 0;
}
if (((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ (alt->ro.ro_nh != NULL) &&
+#else
(alt->ro.ro_rt != NULL) &&
+#endif
(!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))) {
/* Found a reachable address */
break;
@@ -401,7 +409,11 @@ sctp_backoff_on_timeout(struct sctp_tcb *stcb,
int num_marked, int num_abandoned)
{
if (net->RTO == 0) {
- net->RTO = stcb->asoc.minrto;
+ if (net->RTO_measured) {
+ net->RTO = stcb->asoc.minrto;
+ } else {
+ net->RTO = stcb->asoc.initial_rto;
+ }
}
net->RTO <<= 1;
if (net->RTO > stcb->asoc.maxrto) {
@@ -423,14 +435,19 @@ sctp_recover_sent_list(struct sctp_tcb *stcb)
asoc = &stcb->asoc;
TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
- if (SCTP_TSN_GE(asoc->last_acked_seq, chk->rec.data.TSN_seq)) {
+ if (SCTP_TSN_GE(asoc->last_acked_seq, chk->rec.data.tsn)) {
SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n",
- (void *)chk, chk->rec.data.TSN_seq, asoc->last_acked_seq);
+ (void *)chk, chk->rec.data.tsn, asoc->last_acked_seq);
if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
- if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
}
}
+ if ((asoc->strmout[chk->rec.data.sid].chunks_on_queues == 0) &&
+ (asoc->strmout[chk->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
+ TAILQ_EMPTY(&asoc->strmout[chk->rec.data.sid].outqueue)) {
+ asoc->trigger_reset = 1;
+ }
TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
if (PR_SCTP_ENABLED(chk->flags)) {
if (asoc->pr_sctp_cnt != 0)
@@ -451,7 +468,7 @@ sctp_recover_sent_list(struct sctp_tcb *stcb)
}
SCTP_PRINTF("after recover order is as follows\n");
TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
- SCTP_PRINTF("chk:%p TSN:%x\n", (void *)chk, chk->rec.data.TSN_seq);
+ SCTP_PRINTF("chk:%p TSN:%x\n", (void *)chk, chk->rec.data.tsn);
}
}
#endif
@@ -482,7 +499,6 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
uint32_t tsnlast, tsnfirst;
int recovery_cnt = 0;
-
/* none in flight now */
audit_tf = 0;
fir = 0;
@@ -504,7 +520,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
}
tv.tv_sec = cur_rto / 1000000;
tv.tv_usec = cur_rto % 1000000;
-#ifndef __FreeBSD__
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
timersub(&now, &tv, &min_wait);
#else
min_wait = now;
@@ -539,10 +555,10 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
start_again:
#endif
TAILQ_FOREACH_SAFE(chk, &stcb->asoc.sent_queue, sctp_next, nchk) {
- if (SCTP_TSN_GE(stcb->asoc.last_acked_seq, chk->rec.data.TSN_seq)) {
+ if (SCTP_TSN_GE(stcb->asoc.last_acked_seq, chk->rec.data.tsn)) {
/* Strange case our list got out of order? */
SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x\n",
- (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.TSN_seq);
+ (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.tsn);
recovery_cnt++;
#ifdef INVARIANTS
panic("last acked >= chk on sent-Q");
@@ -567,7 +583,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
/* validate its been outstanding long enough */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
- sctp_log_fr(chk->rec.data.TSN_seq,
+ sctp_log_fr(chk->rec.data.tsn,
chk->sent_rcv_time.tv_sec,
chk->sent_rcv_time.tv_usec,
SCTP_FR_T3_MARK_TIME);
@@ -601,7 +617,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
}
if (stcb->asoc.prsctp_supported && PR_SCTP_TTL_ENABLED(chk->flags)) {
/* Is it expired? */
-#ifndef __FreeBSD__
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (timercmp(&now, &chk->rec.data.timetodrop, >)) {
#else
if (timevalcmp(&now, &chk->rec.data.timetodrop, >)) {
@@ -635,11 +651,11 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
num_mk++;
if (fir == 0) {
fir = 1;
- tsnfirst = chk->rec.data.TSN_seq;
+ tsnfirst = chk->rec.data.tsn;
}
- tsnlast = chk->rec.data.TSN_seq;
+ tsnlast = chk->rec.data.tsn;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
- sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
+ sctp_log_fr(chk->rec.data.tsn, chk->snd_count,
0, SCTP_FR_T3_MARKED);
}
@@ -654,8 +670,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO,
chk->whoTo->flight_size,
chk->book_size,
- (uintptr_t)chk->whoTo,
- chk->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)chk->whoTo,
+ chk->rec.data.tsn);
}
sctp_flight_size_decrease(chk);
sctp_total_flight_decrease(stcb, chk);
@@ -663,6 +679,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
}
chk->sent = SCTP_DATAGRAM_RESEND;
+ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
SCTP_STAT_INCR(sctps_markedretrans);
/* reset the TSN for striking and other FR stuff */
@@ -685,7 +702,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
if (TAILQ_EMPTY(&stcb->asoc.send_queue)) {
chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq;
} else {
- chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq;
+ chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.tsn;
}
}
/* CMT: Do not allow FRs on retransmitted TSNs.
@@ -715,13 +732,9 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
if (num_mk) {
SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n",
tsnlast);
- SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n",
- num_mk, (u_long)stcb->asoc.peers_rwnd);
- SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n",
- tsnlast);
- SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n",
+ SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%u\n",
num_mk,
- (int)stcb->asoc.peers_rwnd);
+ stcb->asoc.peers_rwnd);
}
#endif
*num_marked = num_mk;
@@ -740,6 +753,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
chk->whoTo = alt;
if (chk->sent != SCTP_DATAGRAM_RESEND) {
chk->sent = SCTP_DATAGRAM_RESEND;
+ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
cnt_mk++;
}
@@ -782,8 +796,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
chk->whoTo->flight_size,
chk->book_size,
- (uintptr_t)chk->whoTo,
- chk->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)chk->whoTo,
+ chk->rec.data.tsn);
}
sctp_flight_size_increase(chk);
@@ -795,7 +809,6 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
return (0);
}
-
int
sctp_t3rxt_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
@@ -931,10 +944,14 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
net->src_addr_selected = 0;
/* Force a route allocation too */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ RO_NHFREE(&net->ro);
+#else
if (net->ro.ro_rt) {
RTFREE(net->ro.ro_rt);
net->ro.ro_rt = NULL;
}
+#endif
/* Was it our primary? */
if ((stcb->asoc.primary_destination == net) && (alt != net)) {
@@ -956,7 +973,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
* Special case for cookie-echo'ed case, we don't do output but must
* await the COOKIE-ACK before retransmission
*/
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) {
/*
* Here we just reset the timer and start again since we
* have not established the asoc
@@ -971,7 +988,12 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
/* C3. See if we need to send a Fwd-TSN */
if (SCTP_TSN_GT(stcb->asoc.advanced_peer_ack_point, stcb->asoc.last_acked_seq)) {
send_forward_tsn(stcb, &stcb->asoc);
- if (lchk) {
+ for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
+ if (lchk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (lchk != NULL) {
/* Assure a timer is up */
sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo);
}
@@ -998,7 +1020,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp,
sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED);
return (0);
}
- if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) {
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) {
return (0);
}
if (sctp_threshold_management(inp, stcb, net,
@@ -1046,19 +1068,19 @@ sctp_cookie_timer(struct sctp_inpcb *inp,
}
}
if (cookie == NULL) {
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) {
/* FOOBAR! */
struct mbuf *op_err;
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION,
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Cookie timer expired, but no cookie");
- inp->last_abort_code = SCTP_FROM_SCTP_TIMER+SCTP_LOC_4;
+ inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3;
sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
} else {
#ifdef INVARIANTS
panic("Cookie timer expires in wrong state?");
#else
- SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc));
+ SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(stcb));
return (0);
#endif
}
@@ -1071,8 +1093,8 @@ sctp_cookie_timer(struct sctp_inpcb *inp,
return (1);
}
/*
- * cleared theshold management now lets backoff the address & select
- * an alternate
+ * Cleared threshold management, now lets backoff the address
+ * and select an alternate
*/
stcb->asoc.dropped_special_cnt = 0;
sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0);
@@ -1087,6 +1109,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp,
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
}
cookie->sent = SCTP_DATAGRAM_RESEND;
+ cookie->flags |= CHUNK_FLAGS_FRAGMENT_OK;
/*
* Now call the output routine to kick out the cookie again, Note we
* don't mark any chunks for retran so that FR will need to kick in
@@ -1096,10 +1119,9 @@ sctp_cookie_timer(struct sctp_inpcb *inp,
}
int
-sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct sctp_nets *net)
+sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
{
- struct sctp_nets *alt;
+ struct sctp_nets *alt, *net;
struct sctp_tmit_chunk *strrst = NULL, *chk = NULL;
if (stcb->asoc.stream_reset_outstanding == 0) {
@@ -1110,19 +1132,18 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (strrst == NULL) {
return (0);
}
+ net = strrst->whoTo;
/* do threshold management */
- if (sctp_threshold_management(inp, stcb, strrst->whoTo,
- stcb->asoc.max_send_times)) {
+ if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
/* Assoc is over */
return (1);
}
/*
- * cleared theshold management now lets backoff the address & select
- * an alternate
+ * Cleared threshold management, now lets backoff the address
+ * and select an alternate
*/
- sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0);
- alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0);
- sctp_free_remote_addr(strrst->whoTo);
+ sctp_backoff_on_timeout(stcb, net, 1, 0, 0);
+ alt = sctp_find_alternate_net(stcb, net, 0);
strrst->whoTo = alt;
atomic_add_int(&alt->ref_count, 1);
@@ -1133,6 +1154,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_free_remote_addr(chk->whoTo);
if (chk->sent != SCTP_DATAGRAM_RESEND) {
chk->sent = SCTP_DATAGRAM_RESEND;
+ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
}
chk->whoTo = alt;
@@ -1146,13 +1168,16 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
sctp_move_chunks_from_net(stcb, net);
}
+ sctp_free_remote_addr(net);
+
/* mark the retran info */
if (strrst->sent != SCTP_DATAGRAM_RESEND)
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
strrst->sent = SCTP_DATAGRAM_RESEND;
+ strrst->flags |= CHUNK_FLAGS_FRAGMENT_OK;
/* restart the timer */
- sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo);
+ sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, alt);
return (0);
}
@@ -1177,8 +1202,9 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (asconf == NULL) {
return (0);
}
+ net = asconf->whoTo;
/* do threshold management */
- if (sctp_threshold_management(inp, stcb, asconf->whoTo,
+ if (sctp_threshold_management(inp, stcb, net,
stcb->asoc.max_send_times)) {
/* Assoc is over */
return (1);
@@ -1191,17 +1217,16 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* Mark this peer as ASCONF incapable and cleanup.
*/
SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n");
- sctp_asconf_cleanup(stcb, net);
+ sctp_asconf_cleanup(stcb);
return (0);
}
/*
* cleared threshold management, so now backoff the net and
* select an alternate
*/
- sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0);
- alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0);
+ sctp_backoff_on_timeout(stcb, net, 1, 0, 0);
+ alt = sctp_find_alternate_net(stcb, net, 0);
if (asconf->whoTo != alt) {
- sctp_free_remote_addr(asconf->whoTo);
asconf->whoTo = alt;
atomic_add_int(&alt->ref_count, 1);
}
@@ -1214,6 +1239,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
chk->whoTo = alt;
if (chk->sent != SCTP_DATAGRAM_RESEND) {
chk->sent = SCTP_DATAGRAM_RESEND;
+ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
}
atomic_add_int(&alt->ref_count, 1);
@@ -1228,6 +1254,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT)
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
chk->sent = SCTP_DATAGRAM_RESEND;
+ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
}
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
/*
@@ -1236,10 +1263,13 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
sctp_move_chunks_from_net(stcb, net);
}
+ sctp_free_remote_addr(net);
+
/* mark the retran info */
if (asconf->sent != SCTP_DATAGRAM_RESEND)
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
asconf->sent = SCTP_DATAGRAM_RESEND;
+ asconf->flags |= CHUNK_FLAGS_FRAGMENT_OK;
/* send another ASCONF if any and we can do */
sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED);
@@ -1249,8 +1279,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* Mobility adaptation */
void
-sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct sctp_nets *net SCTP_UNUSED)
+sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
{
if (stcb->asoc.deleted_primary == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n");
@@ -1277,7 +1306,7 @@ sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
{
struct sctp_nets *alt;
- /* first threshold managment */
+ /* first threshold management */
if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
/* Assoc is over */
return (1);
@@ -1300,7 +1329,7 @@ sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
{
struct sctp_nets *alt;
- /* first threshold managment */
+ /* first threshold management */
if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
/* Assoc is over */
return (1);
@@ -1424,7 +1453,7 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if ((net->last_sent_time.tv_sec > 0) ||
(net->last_sent_time.tv_usec > 0)) {
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct timeval diff;
SCTP_GETTIME_TIMEVAL(&diff);
@@ -1470,7 +1499,7 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
if (net->ro._l_addr.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
/* KAME hack: embed scopeid */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)
(void)in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL);
#else
@@ -1503,7 +1532,11 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
net->src_addr_selected = 1;
}
if (net->ro._s_addr) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_nh);
+#else
mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt);
+#endif
#if defined(INET) || defined(INET6)
if (net->port) {
mtu -= sizeof(struct udphdr);
@@ -1511,6 +1544,8 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
#endif
if (mtu > next_mtu) {
net->mtu = next_mtu;
+ } else {
+ net->mtu = mtu;
}
}
}
@@ -1519,16 +1554,14 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
}
void
-sctp_autoclose_timer(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- struct sctp_nets *net)
+sctp_autoclose_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
{
struct timeval tn, *tim_touse;
struct sctp_association *asoc;
- int ticks_gone_by;
+ uint32_t ticks_gone_by;
(void)SCTP_GETTIME_TIMEVAL(&tn);
- if (stcb->asoc.sctp_autoclose_ticks &&
+ if (stcb->asoc.sctp_autoclose_ticks > 0 &&
sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
/* Auto close is on */
asoc = &stcb->asoc;
@@ -1540,9 +1573,8 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
tim_touse = &asoc->time_last_sent;
}
/* Now has long enough transpired to autoclose? */
- ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec);
- if ((ticks_gone_by > 0) &&
- (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) {
+ ticks_gone_by = sctp_secs_to_ticks((uint32_t)(tn.tv_sec - tim_touse->tv_sec));
+ if (ticks_gone_by >= asoc->sctp_autoclose_ticks) {
/*
* autoclose time has hit, call the output routine,
* which should do nothing just to be SURE we don't
@@ -1558,29 +1590,26 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
* there is nothing queued to send, so I'm
* done...
*/
- if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) {
/* only send SHUTDOWN 1st time thru */
- struct sctp_nets *netp;
+ struct sctp_nets *net;
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
+ net = stcb->asoc.alternate;
} else {
- netp = stcb->asoc.primary_destination;
+ net = stcb->asoc.primary_destination;
}
- sctp_send_shutdown(stcb, netp);
+ sctp_send_shutdown(stcb, net);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb,
- netp);
+ stcb->sctp_ep, stcb, net);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb,
- netp);
+ stcb->sctp_ep, stcb, NULL);
}
}
} else {
@@ -1588,13 +1617,12 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
* No auto close at this time, reset t-o to check
* later
*/
- int tmp;
+ uint32_t tmp;
/* fool the timer startup to use the time left */
tmp = asoc->sctp_autoclose_ticks;
asoc->sctp_autoclose_ticks -= ticks_gone_by;
- sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
- net);
+ sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL);
/* restore the real tick value */
asoc->sctp_autoclose_ticks = tmp;
}
diff --git a/netwerk/sctp/src/netinet/sctp_timer.h b/netwerk/sctp/src/netinet/sctp_timer.h
index 3662bd2c7a..8cfbbca5da 100755
--- a/netwerk/sctp/src/netinet/sctp_timer.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 235828 2012-05-23 11:26:28Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_TIMER_H_
@@ -44,22 +46,20 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 235828 2012-05-23 11:26:28Z tu
#define SCTP_RTT_VAR_SHIFT 2
struct sctp_nets *
-sctp_find_alternate_net(struct sctp_tcb *,
- struct sctp_nets *, int mode);
-
-int
-sctp_threshold_management(struct sctp_inpcb *, struct sctp_tcb *,
- struct sctp_nets *, uint16_t);
+sctp_find_alternate_net(struct sctp_tcb *, struct sctp_nets *, int);
int
sctp_t3rxt_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
+
int
sctp_t1init_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
+
int
sctp_shutdown_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
+
int
sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
@@ -76,32 +76,28 @@ int
sctp_shutdownack_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
int
-sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct sctp_nets *net);
+sctp_strreset_timer(struct sctp_inpcb *, struct sctp_tcb *);
int
sctp_asconf_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
void
-sctp_delete_prim_timer(struct sctp_inpcb *, struct sctp_tcb *,
- struct sctp_nets *);
+sctp_delete_prim_timer(struct sctp_inpcb *, struct sctp_tcb *);
void
-sctp_autoclose_timer(struct sctp_inpcb *, struct sctp_tcb *,
- struct sctp_nets *net);
+sctp_autoclose_timer(struct sctp_inpcb *, struct sctp_tcb *);
void sctp_audit_retranmission_queue(struct sctp_association *);
void sctp_iterator_timer(struct sctp_iterator *it);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION)
void sctp_slowtimo(void);
#else
void sctp_gc(struct inpcbinfo *);
#endif
#endif
-
#endif
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_uio.h b/netwerk/sctp/src/netinet/sctp_uio.h
index 7cf02ed252..18956f1a14 100755
--- a/netwerk/sctp/src/netinet/sctp_uio.h
+++ b/netwerk/sctp/src/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.
@@ -30,29 +32,28 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_uio.h 269945 2014-08-13 15:50:16Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_uio.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_UIO_H_
#define _NETINET_SCTP_UIO_H_
-#if (defined(__APPLE__) && defined(KERNEL))
+#if (defined(__APPLE__) && !defined(__Userspace__) && defined(KERNEL))
#ifndef _KERNEL
#define _KERNEL
#endif
#endif
-
-#if !(defined(__Windows__)) && !defined(__Userspace_os_Windows)
-#if ! defined(_KERNEL)
+#if !defined(_WIN32)
+#if !defined(_KERNEL)
#include <stdint.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
#pragma warning(push)
#pragma warning(disable: 4200)
#if defined(_KERNEL)
@@ -108,14 +109,8 @@ struct sctp_event_subscribe {
* ancillary data structures
*/
struct sctp_initmsg {
-#if defined(__FreeBSD__) && __FreeBSD_version < 800000
- /* This is a bug. Not fixed for ABI compatibility */
- uint32_t sinit_num_ostreams;
- uint32_t sinit_max_instreams;
-#else
uint16_t sinit_num_ostreams;
uint16_t sinit_max_instreams;
-#endif
uint16_t sinit_max_attempts;
uint16_t sinit_max_init_timeo;
};
@@ -133,7 +128,6 @@ struct sctp_initmsg {
* all sendrcvinfo's need a verfid for SENDING only.
*/
-
#define SCTP_ALIGN_RESV_PAD 92
#define SCTP_ALIGN_RESV_PAD_SHORT 76
@@ -141,9 +135,6 @@ struct sctp_sndrcvinfo {
uint16_t sinfo_stream;
uint16_t sinfo_ssn;
uint16_t sinfo_flags;
-#if defined(__FreeBSD__) && __FreeBSD_version < 800000
- uint16_t sinfo_pr_policy;
-#endif
uint32_t sinfo_ppid;
uint32_t sinfo_context;
uint32_t sinfo_timetolive;
@@ -159,24 +150,27 @@ struct sctp_extrcvinfo {
uint16_t sinfo_stream;
uint16_t sinfo_ssn;
uint16_t sinfo_flags;
-#if defined(__FreeBSD__) && __FreeBSD_version < 800000
- uint16_t sinfo_pr_policy;
-#endif
uint32_t sinfo_ppid;
uint32_t sinfo_context;
- uint32_t sinfo_timetolive;
+ uint32_t sinfo_timetolive; /* should have been sinfo_pr_value */
uint32_t sinfo_tsn;
uint32_t sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
- uint16_t sreinfo_next_flags;
- uint16_t sreinfo_next_stream;
- uint32_t sreinfo_next_aid;
- uint32_t sreinfo_next_length;
- uint32_t sreinfo_next_ppid;
+ uint16_t serinfo_next_flags;
+ uint16_t serinfo_next_stream;
+ uint32_t serinfo_next_aid;
+ uint32_t serinfo_next_length;
+ uint32_t serinfo_next_ppid;
uint16_t sinfo_keynumber;
uint16_t sinfo_keynumber_valid;
uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD_SHORT];
};
+#define sinfo_pr_value sinfo_timetolive
+#define sreinfo_next_flags serinfo_next_flags
+#define sreinfo_next_stream serinfo_next_stream
+#define sreinfo_next_aid serinfo_next_aid
+#define sreinfo_next_length serinfo_next_length
+#define sreinfo_next_ppid serinfo_next_ppid
struct sctp_sndinfo {
uint16_t snd_sid;
@@ -282,7 +276,8 @@ struct sctp_snd_all_completes {
/* The lower four bits is an enumeration of PR-SCTP policies */
#define SCTP_PR_SCTP_NONE 0x0000 /* Reliable transfer */
#define SCTP_PR_SCTP_TTL 0x0001 /* Time based PR-SCTP */
-#define SCTP_PR_SCTP_BUF 0x0002 /* Buffer based PR-SCTP */
+#define SCTP_PR_SCTP_PRIO 0x0002 /* Buffer based PR-SCTP */
+#define SCTP_PR_SCTP_BUF SCTP_PR_SCTP_PRIO /* For backwards compatibility */
#define SCTP_PR_SCTP_RTX 0x0003 /* Number of retransmissions based PR-SCTP */
#define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_RTX
#define SCTP_PR_SCTP_ALL 0x000f /* Used for aggregated stats */
@@ -341,12 +336,13 @@ struct sctp_assoc_change {
#define SCTP_CANT_STR_ASSOC 0x0005
/* sac_info values */
-#define SCTP_ASSOC_SUPPORTS_PR 0x01
-#define SCTP_ASSOC_SUPPORTS_AUTH 0x02
-#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03
-#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04
-#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05
-#define SCTP_ASSOC_SUPPORTS_MAX 0x05
+#define SCTP_ASSOC_SUPPORTS_PR 0x01
+#define SCTP_ASSOC_SUPPORTS_AUTH 0x02
+#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03
+#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04
+#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05
+#define SCTP_ASSOC_SUPPORTS_INTERLEAVING 0x06
+#define SCTP_ASSOC_SUPPORTS_MAX 0x06
/*
* Address event
*/
@@ -443,7 +439,6 @@ struct sctp_setadaption {
uint32_t ssb_adaption_ind;
};
-
/*
* Partial Delivery API event
*/
@@ -460,7 +455,6 @@ struct sctp_pdapi_event {
/* indication values */
#define SCTP_PARTIAL_DELIVERY_ABORTED 0x0001
-
/*
* authentication key event
*/
@@ -480,7 +474,6 @@ struct sctp_authkey_event {
#define SCTP_AUTH_NO_AUTH 0x0002
#define SCTP_AUTH_FREE_KEY 0x0003
-
struct sctp_sender_dry_event {
uint16_t sender_dry_type;
uint16_t sender_dry_flags;
@@ -488,7 +481,6 @@ struct sctp_sender_dry_event {
sctp_assoc_t sender_dry_assoc_id;
};
-
/*
* Stream reset event - subscribe to SCTP_STREAM_RESET_EVENT
*/
@@ -536,7 +528,6 @@ struct sctp_stream_change_event {
#define SCTP_STREAM_CHANGE_DENIED 0x0004
#define SCTP_STREAM_CHANGE_FAILED 0x0008
-
/* SCTP notification event */
struct sctp_tlv {
uint16_t sn_type;
@@ -611,6 +602,7 @@ struct sctp_paddrthlds {
sctp_assoc_t spt_assoc_id;
uint16_t spt_pathmaxrxt;
uint16_t spt_pathpfthld;
+ uint16_t spt_pathcpthld;
};
struct sctp_paddrinfo {
@@ -651,10 +643,18 @@ struct sctp_setpeerprim {
uint8_t sspp_padding[4];
};
+union sctp_sockstore {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+#if defined(__Userspace__)
+ struct sockaddr_conn sconn;
+#endif
+ struct sockaddr sa;
+};
+
struct sctp_getaddresses {
sctp_assoc_t sget_assoc_id;
- /* addr is filled in for N * sockaddr_storage */
- struct sockaddr addr[1];
+ union sctp_sockstore addr[];
};
struct sctp_status {
@@ -1001,7 +1001,7 @@ struct sctpstat {
uint32_t sctps_recvauthfailed; /* total number of auth failed */
uint32_t sctps_recvexpress; /* total fast path receives all one chunk */
uint32_t sctps_recvexpressm; /* total fast path multi-part data */
- uint32_t sctps_recvnocrc;
+ uint32_t sctps_recv_spare; /* formerly sctps_recvnocrc */
uint32_t sctps_recvswcrc;
uint32_t sctps_recvhwcrc;
@@ -1012,13 +1012,13 @@ struct sctpstat {
uint32_t sctps_sendretransdata; /* total output retransmitted DATA chunks */
uint32_t sctps_sendfastretrans; /* total output fast retransmitted DATA chunks */
uint32_t sctps_sendmultfastretrans; /* total FR's that happened more than once
- * to same chunk (u-del multi-fr algo).
- */
+ * to same chunk (u-del multi-fr algo).
+ */
uint32_t sctps_sendheartbeat; /* total output HB chunks */
uint32_t sctps_sendecne; /* total output ECNE chunks */
uint32_t sctps_sendauth; /* total output AUTH chunks FIXME */
- uint32_t sctps_senderrors; /* ip_output error counter */
- uint32_t sctps_sendnocrc;
+ uint32_t sctps_senderrors; /* ip_output error counter */
+ uint32_t sctps_send_spare; /* formerly sctps_sendnocrc */
uint32_t sctps_sendswcrc;
uint32_t sctps_sendhwcrc;
/* PCKDROPREP statistics: */
@@ -1110,13 +1110,18 @@ struct sctpstat {
#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1)
#define SCTP_STAT_DECR(_x) SCTP_STAT_DECR_BY(_x,1)
-#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
#define SCTP_STAT_INCR_BY(_x,_d) (SCTP_BASE_STATS[PCPU_GET(cpuid)]._x += _d)
#define SCTP_STAT_DECR_BY(_x,_d) (SCTP_BASE_STATS[PCPU_GET(cpuid)]._x -= _d)
#else
#define SCTP_STAT_INCR_BY(_x,_d) atomic_add_int(&SCTP_BASE_STAT(_x), _d)
#define SCTP_STAT_DECR_BY(_x,_d) atomic_subtract_int(&SCTP_BASE_STAT(_x), _d)
#endif
+#else
+#define SCTP_STAT_INCR_BY(_x,_d) atomic_add_int(&SCTP_BASE_STAT(_x), _d)
+#define SCTP_STAT_DECR_BY(_x,_d) atomic_subtract_int(&SCTP_BASE_STAT(_x), _d)
+#endif
/* The following macros are for handling MIB values, */
#define SCTP_STAT_INCR_COUNTER32(_x) SCTP_STAT_INCR(_x)
#define SCTP_STAT_INCR_COUNTER64(_x) SCTP_STAT_INCR(_x)
@@ -1125,34 +1130,14 @@ struct sctpstat {
#define SCTP_STAT_DECR_COUNTER64(_x) SCTP_STAT_DECR(_x)
#define SCTP_STAT_DECR_GAUGE32(_x) SCTP_STAT_DECR(_x)
-#if defined(__Userspace__)
-union sctp_sockstore {
-#if defined(INET)
- struct sockaddr_in sin;
-#endif
-#if defined(INET6)
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr_conn sconn;
- struct sockaddr sa;
-};
-#else
-union sctp_sockstore {
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- struct sockaddr sa;
-};
-#endif
-
-
/***********************************/
/* And something for us old timers */
/***********************************/
-#ifndef __APPLE__
-#ifndef __Userspace__
+#if !(defined(__APPLE__) && !defined(__Userspace__))
+#if !defined(__Userspace__)
#ifndef ntohll
-#if defined(__Userspace_os_Linux)
+#if defined(__linux__)
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
@@ -1164,7 +1149,7 @@ union sctp_sockstore {
#endif
#ifndef htonll
-#if defined(__Userspace_os_Linux)
+#if defined(__linux__)
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
@@ -1178,30 +1163,33 @@ union sctp_sockstore {
#endif
/***********************************/
-
struct xsctp_inpcb {
uint32_t last;
uint32_t flags;
-#if defined(__FreeBSD__) && __FreeBSD_version < 1000048
- uint32_t features;
-#else
uint64_t features;
-#endif
uint32_t total_sends;
uint32_t total_recvs;
uint32_t total_nospaces;
uint32_t fragmentation_point;
uint16_t local_port;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint16_t qlen_old;
+ uint16_t maxqlen_old;
+#else
uint16_t qlen;
uint16_t maxqlen;
-#if defined(__Windows__)
- uint16_t padding;
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 1000048
- uint32_t extra_padding[32]; /* future */
+ uint16_t __spare16;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ kvaddr_t socket;
#else
- uint32_t extra_padding[31]; /* future */
+ void *socket;
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint32_t qlen;
+ uint32_t maxqlen;
+#endif
+ uint32_t extra_padding[26]; /* future */
};
struct xsctp_tcb {
@@ -1230,18 +1218,9 @@ struct xsctp_tcb {
uint16_t remote_port; /* sctpAssocEntry 4 */
struct sctp_timeval start_time; /* sctpAssocEntry 16 */
struct sctp_timeval discontinuity_time; /* sctpAssocEntry 17 */
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800000
uint32_t peers_rwnd;
sctp_assoc_t assoc_id; /* sctpAssocEntry 1 */
uint32_t extra_padding[32]; /* future */
-#else
-#endif
-#else
- uint32_t peers_rwnd;
- sctp_assoc_t assoc_id; /* sctpAssocEntry 1 */
- uint32_t extra_padding[32]; /* future */
-#endif
};
struct xsctp_laddr {
@@ -1266,17 +1245,12 @@ struct xsctp_raddr {
uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */
uint8_t potentially_failed;
struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800000
uint32_t rtt;
uint32_t heartbeat_interval;
- uint32_t extra_padding[31]; /* future */
-#endif
-#else
- uint32_t rtt;
- uint32_t heartbeat_interval;
- uint32_t extra_padding[31]; /* future */
-#endif
+ uint32_t ssthresh;
+ uint16_t encaps_port;
+ uint16_t state;
+ uint32_t extra_padding[29]; /* future */
};
#define SCTP_MAX_LOGGING_SIZE 30000
@@ -1303,19 +1277,14 @@ int
sctp_lower_sosend(struct socket *so,
struct sockaddr *addr,
struct uio *uio,
-#if defined(__Panda__)
- pakhandle_type i_pak,
- pakhandle_type i_control,
-#else
struct mbuf *i_pak,
struct mbuf *control,
-#endif
int flags,
struct sctp_sndrcvinfo *srcv
-#if !(defined(__Panda__) || defined(__Userspace__))
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if !defined(__Userspace__)
+#if defined(__FreeBSD__)
,struct thread *p
-#elif defined(__Windows__)
+#elif defined(_WIN32)
, PKTHREAD p
#else
,struct proc *p
@@ -1326,11 +1295,7 @@ sctp_lower_sosend(struct socket *so,
int
sctp_sorecvmsg(struct socket *so,
struct uio *uio,
-#if defined(__Panda__)
- particletype **mp,
-#else
struct mbuf **mp,
-#endif
struct sockaddr *from,
int fromlen,
int *msg_flags,
@@ -1344,45 +1309,6 @@ sctp_sorecvmsg(struct socket *so,
#if !(defined(_KERNEL)) && !(defined(__Userspace__))
__BEGIN_DECLS
-#if defined(__FreeBSD__) && __FreeBSD_version < 902000
-int sctp_peeloff __P((int, sctp_assoc_t));
-int sctp_bindx __P((int, struct sockaddr *, int, int));
-int sctp_connectx __P((int, const struct sockaddr *, int, sctp_assoc_t *));
-int sctp_getaddrlen __P((sa_family_t));
-int sctp_getpaddrs __P((int, sctp_assoc_t, struct sockaddr **));
-void sctp_freepaddrs __P((struct sockaddr *));
-int sctp_getladdrs __P((int, sctp_assoc_t, struct sockaddr **));
-void sctp_freeladdrs __P((struct sockaddr *));
-int sctp_opt_info __P((int, sctp_assoc_t, int, void *, socklen_t *));
-
-/* deprecated */
-ssize_t sctp_sendmsg __P((int, const void *, size_t, const struct sockaddr *,
- socklen_t, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
-
-/* deprecated */
-ssize_t sctp_send __P((int, const void *, size_t,
- const struct sctp_sndrcvinfo *, int));
-
-/* deprecated */
-ssize_t sctp_sendx __P((int, const void *, size_t, struct sockaddr *,
- int, struct sctp_sndrcvinfo *, int));
-
-/* deprecated */
-ssize_t sctp_sendmsgx __P((int sd, const void *, size_t, struct sockaddr *,
- int, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
-
-sctp_assoc_t sctp_getassocid __P((int, struct sockaddr *));
-
-/* deprecated */
-ssize_t sctp_recvmsg __P((int, void *, size_t, struct sockaddr *, socklen_t *,
- struct sctp_sndrcvinfo *, int *));
-
-ssize_t sctp_sendv __P((int, const struct iovec *, int, struct sockaddr *,
- int, void *, socklen_t, unsigned int, int));
-
-ssize_t sctp_recvv __P((int, const struct iovec *, int, struct sockaddr *,
- socklen_t *, void *, socklen_t *, unsigned int *, int *));
-#else
int sctp_peeloff(int, sctp_assoc_t);
int sctp_bindx(int, struct sockaddr *, int, int);
int sctp_connectx(int, const struct sockaddr *, int, sctp_assoc_t *);
@@ -1420,7 +1346,6 @@ ssize_t sctp_sendv(int, const struct iovec *, int, struct sockaddr *,
ssize_t sctp_recvv(int, const struct iovec *, int, struct sockaddr *,
socklen_t *, void *, socklen_t *, unsigned int *, int *);
-#endif
__END_DECLS
#endif /* !_KERNEL */
diff --git a/netwerk/sctp/src/netinet/sctp_userspace.c b/netwerk/sctp/src/netinet/sctp_userspace.c
index 7841a89e1e..ba64aaff77 100755
--- a/netwerk/sctp/src/netinet/sctp_userspace.c
+++ b/netwerk/sctp/src/netinet/sctp_userspace.c
@@ -31,31 +31,94 @@
#include <netinet/sctp_pcb.h>
#include <sys/timeb.h>
#include <iphlpapi.h>
-#pragma comment(lib, "IPHLPAPI.lib")
+#if !defined(__MINGW32__)
+#pragma comment(lib, "iphlpapi.lib")
+#endif
#endif
#include <netinet/sctp_os_userspace.h>
+#if defined(__FreeBSD__)
+#include <pthread_np.h>
+#endif
+
+#if defined(__linux__)
+#include <sys/prctl.h>
+#endif
+
+#if defined(_WIN32)
+/* Adapter to translate Unix thread start routines to Windows thread start
+ * routines.
+ */
+#if defined(__MINGW32__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+static DWORD WINAPI
+sctp_create_thread_adapter(void *arg) {
+ start_routine_t start_routine = (start_routine_t)arg;
+ return start_routine(NULL) == NULL;
+}
-#if !defined(_WIN32) && !defined(__Userspace_os_NaCl)
+int
+sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine)
+{
+ *thread = CreateThread(NULL, 0, sctp_create_thread_adapter,
+ (void *)start_routine, 0, NULL);
+ if (*thread == NULL)
+ return GetLastError();
+ return 0;
+}
+
+#if defined(__MINGW32__)
+#pragma GCC diagnostic pop
+#endif
+
+#else
+int
+sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine)
+{
+ return pthread_create(thread, NULL, start_routine, NULL);
+}
+#endif
+
+void
+sctp_userspace_set_threadname(const char *name)
+{
+#if defined(__APPLE__)
+ pthread_setname_np(name);
+#endif
+#if defined(__linux__)
+ prctl(PR_SET_NAME, name);
+#endif
+#if defined(__FreeBSD__)
+ pthread_set_name_np(pthread_self(), name);
+#endif
+}
+
+#if !defined(_WIN32) && !defined(__native_client__)
int
sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af)
{
struct ifreq ifr;
int fd;
- if_indextoname(if_index, ifr.ifr_name);
- /* TODO can I use the raw socket here and not have to open a new one with each query? */
- if ((fd = socket(af, SOCK_DGRAM, 0)) < 0)
- return (0);
- if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (if_indextoname(if_index, ifr.ifr_name) != NULL) {
+ /* TODO can I use the raw socket here and not have to open a new one with each query? */
+ if ((fd = socket(af, SOCK_DGRAM, 0)) < 0)
+ return (0);
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ close(fd);
+ return (0);
+ }
close(fd);
+ return ifr.ifr_mtu;
+ } else {
return (0);
}
- close(fd);
- return ifr.ifr_mtu;
}
#endif
-#if defined(__Userspace_os_NaCl)
+#if defined(__native_client__)
int
sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af)
{
@@ -63,132 +126,86 @@ sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af)
}
#endif
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__linux__) || defined(__native_client__) || defined(__NetBSD__) || defined(_WIN32) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+int
+timingsafe_bcmp(const void *b1, const void *b2, size_t n)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ int ret = 0;
+
+ for (; n > 0; n--)
+ ret |= *p1++ ^ *p2++;
+ return (ret != 0);
+}
+#endif
+
#ifdef _WIN32
int
sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af)
{
PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt;
DWORD AdapterAddrsSize, Err;
+ int ret;
+ ret = 0;
AdapterAddrsSize = 0;
+ pAdapterAddrs = NULL;
if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &AdapterAddrsSize)) != 0) {
if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() sizing failed with error code %d, AdapterAddrsSize = %d\n", Err, AdapterAddrsSize);
- return (-1);
+ ret = -1;
+ goto cleanup;
}
}
if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) {
SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n");
- return (-1);
+ ret = -1;
+ goto cleanup;
}
if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) {
SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() failed with error code %d\n", Err);
- return (-1);
+ ret = -1;
+ goto cleanup;
}
for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) {
- if (pAdapt->IfIndex == if_index)
- return (pAdapt->Mtu);
+ if (pAdapt->IfIndex == if_index) {
+ ret = pAdapt->Mtu;
+ break;
+ }
}
- return (0);
+cleanup:
+ if (pAdapterAddrs != NULL) {
+ GlobalFree(pAdapterAddrs);
+ }
+ return (ret);
}
void
getwintimeofday(struct timeval *tv)
{
- struct timeb tb;
-
- ftime(&tb);
- tv->tv_sec = (long)tb.time;
- tv->tv_usec = (long)(tb.millitm) * 1000L;
-}
+ FILETIME filetime;
+ ULARGE_INTEGER ularge;
-int
-Win_getifaddrs(struct ifaddrs** interfaces)
-{
-#if defined(INET) || defined(INET6)
- DWORD Err, AdapterAddrsSize;
- int count;
- PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt;
- struct ifaddrs *ifa;
-#endif
-#if defined(INET)
- struct sockaddr_in *addr;
-#endif
-#if defined(INET6)
- struct sockaddr_in6 *addr6;
+ GetSystemTimeAsFileTime(&filetime);
+ ularge.LowPart = filetime.dwLowDateTime;
+ ularge.HighPart = filetime.dwHighDateTime;
+ /* Change base from Jan 1 1601 00:00:00 to Jan 1 1970 00:00:00 */
+#if defined(__MINGW32__)
+ ularge.QuadPart -= 116444736000000000ULL;
+#else
+ ularge.QuadPart -= 116444736000000000UI64;
#endif
-#if defined(INET) || defined(INET6)
- count = 0;
-#endif
-#if defined(INET)
- AdapterAddrsSize = 0;
- if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, NULL, &AdapterAddrsSize)) != 0) {
- if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
- SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV4Addresses() sizing failed with error code %d and AdapterAddrsSize = %d\n", Err, AdapterAddrsSize);
- return (-1);
- }
- }
- /* Allocate memory from sizing information */
- if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) {
- SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n");
- return (-1);
- }
- /* Get actual adapter information */
- if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) {
- SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV4Addresses() failed with error code %d\n", Err);
- return (-1);
- }
- /* Enumerate through each returned adapter and save its information */
- for (pAdapt = pAdapterAddrs, count; pAdapt; pAdapt = pAdapt->Next, count++) {
- addr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
- ifa = (struct ifaddrs *)malloc(sizeof(struct ifaddrs));
- if ((addr == NULL) || (ifa == NULL)) {
- SCTPDBG(SCTP_DEBUG_USR, "Can't allocate memory\n");
- return (-1);
- }
- ifa->ifa_name = _strdup(pAdapt->AdapterName);
- ifa->ifa_flags = pAdapt->Flags;
- ifa->ifa_addr = (struct sockaddr *)addr;
- memcpy(addr, &pAdapt->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in));
- interfaces[count] = ifa;
- }
-#endif
-#if defined(INET6)
- if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
- AdapterAddrsSize = 0;
- if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, NULL, &AdapterAddrsSize)) != 0) {
- if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
- SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV6Addresses() sizing failed with error code %d AdapterAddrsSize = %d\n", Err, AdapterAddrsSize);
- return (-1);
- }
- }
- /* Allocate memory from sizing information */
- if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) {
- SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n");
- return (-1);
- }
- /* Get actual adapter information */
- if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) {
- SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV6Addresses() failed with error code %d\n", Err);
- return (-1);
- }
- /* Enumerate through each returned adapter and save its information */
- for (pAdapt = pAdapterAddrs, count; pAdapt; pAdapt = pAdapt->Next, count++) {
- addr6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
- ifa = (struct ifaddrs *)malloc(sizeof(struct ifaddrs));
- if ((addr6 == NULL) || (ifa == NULL)) {
- SCTPDBG(SCTP_DEBUG_USR, "Can't allocate memory\n");
- return (-1);
- }
- ifa->ifa_name = _strdup(pAdapt->AdapterName);
- ifa->ifa_flags = pAdapt->Flags;
- ifa->ifa_addr = (struct sockaddr *)addr6;
- memcpy(addr6, &pAdapt->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in6));
- interfaces[count] = ifa;
- }
- }
+ /*
+ * ularge.QuadPart is now the number of 100-nanosecond intervals
+ * since Jan 1 1970 00:00:00.
+ */
+#if defined(__MINGW32__)
+ tv->tv_sec = (long)(ularge.QuadPart / 10000000ULL);
+ tv->tv_usec = (long)((ularge.QuadPart % 10000000ULL) / 10ULL);
+#else
+ tv->tv_sec = (long)(ularge.QuadPart / 10000000UI64);
+ tv->tv_usec = (long)((ularge.QuadPart % 10000000UI64) / 10UI64);
#endif
- return (0);
}
int
diff --git a/netwerk/sctp/src/netinet/sctp_usrreq.c b/netwerk/sctp/src/netinet/sctp_usrreq.c
index 7ffd8e8c81..e5fba96717 100755
--- a/netwerk/sctp/src/netinet/sctp_usrreq.c
+++ b/netwerk/sctp/src/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.
@@ -30,13 +32,13 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 356270 2020-01-02 13:55:10Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 366750 2020-10-16 10:44:48Z tuexen $");
#endif
#include <netinet/sctp_os.h>
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/proc.h>
#endif
#include <netinet/sctp_pcb.h>
@@ -59,84 +61,49 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 356270 2020-01-02 13:55:10Z t
#else
#include <netinet/udp.h>
#endif
-
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <sys/eventhandler.h>
+#endif
#if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
#include <netinet/sctp_peeloff.h>
#endif /* HAVE_SCTP_PEELOFF_SOCKOPT */
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 7
-#endif
-
-extern struct sctp_cc_functions sctp_cc_functions[];
-extern struct sctp_ss_functions sctp_ss_functions[];
+extern const struct sctp_cc_functions sctp_cc_functions[];
+extern const struct sctp_ss_functions sctp_ss_functions[];
void
#if defined(__Userspace__)
sctp_init(uint16_t port,
int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
- void (*debug_printf)(const char *format, ...))
+ void (*debug_printf)(const char *format, ...), int start_threads)
#elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED)
#else
sctp_init(void)
#endif
{
-#if !defined(__Panda__) && !defined(__Userspace__)
+#if !defined(__Userspace__)
u_long sb_max_adj;
-#endif
-#if defined(__Userspace__)
-#if defined(__Userspace_os_Windows)
-#if defined(INET) || defined(INET6)
- WSADATA wsaData;
-
- if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
- SCTP_PRINTF("WSAStartup failed\n");
- exit (-1);
- }
-#endif
- InitializeConditionVariable(&accept_cond);
- InitializeCriticalSection(&accept_mtx);
#else
- pthread_cond_init(&accept_cond, NULL);
- pthread_mutex_init(&accept_mtx, NULL);
-#endif
+ init_random();
#endif
/* Initialize and modify the sysctled variables */
sctp_init_sysctls();
#if defined(__Userspace__)
-#if defined(__Userspace_os_Windows) || defined(__Userspace_os_NaCl)
- srand((unsigned int)time(NULL));
-#else
- srandom(getpid()); /* so inp->sctp_ep.random_numbers are truly random... */
-#endif
-#endif
-#if defined(__Panda__)
- sctp_sendspace = SB_MAX;
- sctp_recvspace = SB_MAX;
-
-#elif defined(__Userspace__)
- SCTP_BASE_SYSCTL(sctp_sendspace) = SB_MAX;
- SCTP_BASE_SYSCTL(sctp_recvspace) = SB_RAW;
SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port;
#else
-#if !defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
+ sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES));
+ SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj;
+#else
if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
-#endif
/*
* Allow a user to take no more than 1/2 the number of clusters or
- * the SB_MAX whichever is smaller for the send window.
+ * the SB_MAX, whichever is smaller, for the send window.
*/
-#if defined(__APPLE__)
- sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES));
-#else
sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
-#endif
-#if defined(__APPLE__)
- SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj;
-#else
SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
(((uint32_t)nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
#endif
@@ -150,7 +117,7 @@ sctp_init(void)
SCTP_BASE_VAR(first_time) = 0;
SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
#if defined(__Userspace__)
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#if defined(INET) || defined(INET6)
SCTP_BASE_VAR(userspace_route) = -1;
#endif
@@ -166,27 +133,49 @@ sctp_init(void)
SCTP_BASE_VAR(timer_thread_should_exit) = 0;
SCTP_BASE_VAR(conn_output) = conn_output;
SCTP_BASE_VAR(debug_printf) = debug_printf;
+ SCTP_BASE_VAR(crc32c_offloaded) = 0;
+ SCTP_BASE_VAR(iterator_thread_started) = 0;
+ SCTP_BASE_VAR(timer_thread_started) = 0;
#endif
- sctp_pcb_init();
#if defined(__Userspace__)
- sctp_start_timer();
+ sctp_pcb_init(start_threads);
+ if (start_threads) {
+ sctp_start_timer_thread();
+ }
+#else
+ sctp_pcb_init();
#endif
#if defined(SCTP_PACKET_LOGGING)
SCTP_BASE_VAR(packet_log_writers) = 0;
SCTP_BASE_VAR(packet_log_end) = 0;
- bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
+ memset(&SCTP_BASE_VAR(packet_log_buffer), 0, SCTP_PACKET_LOG_SIZE);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_BASE_VAR(sctp_main_timer_ticks) = 0;
sctp_start_main_timer();
timeout(sctp_delayed_startup, NULL, 1);
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_BASE_VAR(eh_tag) = EVENTHANDLER_REGISTER(rt_addrmsg,
+ sctp_addr_change_event_handler, NULL, EVENTHANDLER_PRI_FIRST);
+#endif
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#ifdef VIMAGE
+static void
+sctp_finish(void *unused __unused)
+{
+ EVENTHANDLER_DEREGISTER(rt_addrmsg, SCTP_BASE_VAR(eh_tag));
+ sctp_pcb_finish();
+}
+VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL);
+#endif
+#else
void
sctp_finish(void)
{
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
untimeout(sctp_delayed_startup, NULL);
sctp_over_udp_stop();
sctp_address_monitor_stop();
@@ -196,76 +185,17 @@ sctp_finish(void)
#if defined(INET) || defined(INET6)
recv_thread_destroy();
#endif
-#if !defined(__Userspace_os_Windows)
-#if defined(INET) || defined(INET6)
- if (SCTP_BASE_VAR(userspace_route) != -1) {
- pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL);
- }
-#endif
-#endif
-#ifdef INET
- if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
-#if defined(__Userspace_os_Windows)
- WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE);
- CloseHandle(SCTP_BASE_VAR(recvthreadraw));
-#else
- pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL);
-#endif
- }
- if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
-#if defined(__Userspace_os_Windows)
- WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE);
- CloseHandle(SCTP_BASE_VAR(recvthreadudp));
-#else
- pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL);
-#endif
- }
-#endif
-#ifdef INET6
- if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
-#if defined(__Userspace_os_Windows)
- WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE);
- CloseHandle(SCTP_BASE_VAR(recvthreadraw6));
-#else
- pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL);
-#endif
- }
- if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
-#if defined(__Userspace_os_Windows)
- WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE);
- CloseHandle(SCTP_BASE_VAR(recvthreadudp6));
-#else
- pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL);
-#endif
- }
-#endif
- SCTP_BASE_VAR(timer_thread_should_exit) = 1;
-#if defined(__Userspace_os_Windows)
- WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE);
- CloseHandle(SCTP_BASE_VAR(timer_thread));
-#else
- pthread_join(SCTP_BASE_VAR(timer_thread), NULL);
-#endif
+ sctp_stop_timer_thread();
#endif
sctp_pcb_finish();
-#if defined(__Userspace__)
-#if defined(__Userspace_os_Windows)
- DeleteConditionVariable(&accept_cond);
- DeleteCriticalSection(&accept_mtx);
-#else
- pthread_cond_destroy(&accept_cond);
- pthread_mutex_destroy(&accept_mtx);
-#endif
-#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
sctp_finish_sysctls();
-#if defined(INET) || defined(INET6)
- WSACleanup();
#endif
+#if defined(__Userspace__)
+ finish_random();
#endif
}
-
-
+#endif
void
sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
@@ -276,7 +206,7 @@ sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
/* Adjust that too */
stcb->asoc.smallest_mtu = nxtsz;
/* now off to subtract IP_DF flag if needed */
- overhead = IP_HDR_SIZE;
+ overhead = IP_HDR_SIZE + sizeof(struct sctphdr);
if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
}
@@ -302,11 +232,14 @@ sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
chk->whoTo->flight_size,
chk->book_size,
- (uintptr_t)chk->whoTo,
- chk->rec.data.TSN_seq);
+ (uint32_t)(uintptr_t)chk->whoTo,
+ chk->rec.data.tsn);
}
/* Clear any time so NO RTT is being done */
- chk->do_rtt = 0;
+ if (chk->do_rtt == 1) {
+ chk->do_rtt = 0;
+ chk->whoTo->rto_needed = 1;
+ }
}
}
}
@@ -314,160 +247,52 @@ sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
#ifdef INET
#if !defined(__Userspace__)
-#if defined(__Panda__) || defined(__Windows__)
-void
-#else
-static void
-#endif
-sctp_notify_mbuf(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- struct sctp_nets *net,
- struct ip *ip,
- struct sctphdr *sh)
-{
- struct icmp *icmph;
- int totsz, tmr_stopped = 0;
- uint16_t nxtsz;
-
- /* protection */
- if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
- (ip == NULL) || (sh == NULL)) {
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- return;
- }
- /* First job is to verify the vtag matches what I would send */
- if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
- sizeof(struct ip)));
- if (icmph->icmp_type != ICMP_UNREACH) {
- /* We only care about unreachable */
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
- /* not a unreachable message due to frag. */
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000
- totsz = ntohs(ip->ip_len);
-#else
- totsz = ip->ip_len;
-#endif
-
- nxtsz = ntohs(icmph->icmp_nextmtu);
- if (nxtsz == 0) {
- /*
- * old type router that does not tell us what the next size
- * mtu is. Rats we will have to guess (in a educated fashion
- * of course)
- */
- nxtsz = sctp_get_prev_mtu(totsz);
- }
- /* Stop any PMTU timer */
- if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
- tmr_stopped = 1;
- sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_1);
- }
- /* Adjust destination size limit */
- if (net->mtu > nxtsz) {
- net->mtu = nxtsz;
- if (net->port) {
- net->mtu -= sizeof(struct udphdr);
- }
- }
- /* now what about the ep? */
- if (stcb->asoc.smallest_mtu > nxtsz) {
- sctp_pathmtu_adjustment(stcb, nxtsz);
- }
- if (tmr_stopped)
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
-
- SCTP_TCB_UNLOCK(stcb);
-}
-
void
sctp_notify(struct sctp_inpcb *inp,
- struct ip *ip,
- struct sctphdr *sh,
- struct sockaddr *to,
- struct sctp_tcb *stcb,
- struct sctp_nets *net)
+ struct sctp_tcb *stcb,
+ struct sctp_nets *net,
+ uint8_t icmp_type,
+ uint8_t icmp_code,
+ uint16_t ip_len,
+ uint32_t next_mtu)
{
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
-
#endif
- struct icmp *icmph;
+ int timer_stopped;
- /* protection */
- if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
- (sh == NULL) || (to == NULL)) {
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- /* First job is to verify the vtag matches what I would send */
- if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
-
- icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
- sizeof(struct ip)));
- if (icmph->icmp_type != ICMP_UNREACH) {
+ if (icmp_type != ICMP_UNREACH) {
/* We only care about unreachable */
SCTP_TCB_UNLOCK(stcb);
return;
}
- if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
- (icmph->icmp_code == ICMP_UNREACH_HOST) ||
- (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
- (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
- (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
- (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
- (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
-#if defined(__Panda__)
- (icmph->icmp_code == ICMP_UNREACH_ADMIN)) {
-#elif defined(__Userspace_os_NetBSD)
- (icmph->icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
+ if ((icmp_code == ICMP_UNREACH_NET) ||
+ (icmp_code == ICMP_UNREACH_HOST) ||
+ (icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
+ (icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
+ (icmp_code == ICMP_UNREACH_ISOLATED) ||
+ (icmp_code == ICMP_UNREACH_NET_PROHIB) ||
+ (icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
+#if defined(__NetBSD__)
+ (icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
#else
- (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
+ (icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
#endif
-
- /*
- * Hmm reachablity problems we must examine closely. If its
- * not reachable, we may have lost a network. Or if there is
- * NO protocol at the other end named SCTP. well we consider
- * it a OOTB abort.
- */
+ /* Mark the net unreachable. */
if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* Ok that destination is NOT reachable */
+ /* OK, that destination is NOT reachable. */
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state &= ~SCTP_ADDR_PF;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
- stcb, 0,
- (void *)net, SCTP_SO_NOT_LOCKED);
+ stcb, 0,
+ (void *)net, SCTP_SO_NOT_LOCKED);
}
SCTP_TCB_UNLOCK(stcb);
- } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
- (icmph->icmp_code == ICMP_UNREACH_PORT)) {
- /*
- * Here the peer is either playing tricks on us,
- * including an address that belongs to someone who
- * does not support SCTP OR was a userland
- * implementation that shutdown and now is dead. In
- * either case treat it like a OOTB abort with no
- * TCB
- */
+ } else if ((icmp_code == ICMP_UNREACH_PROTOCOL) ||
+ (icmp_code == ICMP_UNREACH_PORT)) {
+ /* Treat it like an ABORT. */
sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -475,99 +300,196 @@ sctp_notify(struct sctp_inpcb *inp,
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/
#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) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ /* Find the next (smaller) MTU */
+ if (next_mtu == 0) {
+ /*
+ * Old type router that does not tell us what the next
+ * MTU is.
+ * Rats we will have to guess (in a educated fashion
+ * of course).
+ */
+ next_mtu = sctp_get_prev_mtu(ip_len);
+ }
+ /* Stop the PMTU timer. */
+ if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
+ timer_stopped = 1;
+ sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
+ } else {
+ timer_stopped = 0;
+ }
+ /* Update the path MTU. */
+ if (net->port) {
+ next_mtu -= sizeof(struct udphdr);
+ }
+ if (net->mtu > next_mtu) {
+ net->mtu = next_mtu;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (net->port) {
+ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
+ } else {
+ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
+ }
+#endif
+ }
+ /* Update the association MTU */
+ if (stcb->asoc.smallest_mtu > next_mtu) {
+ sctp_pathmtu_adjustment(stcb, next_mtu);
+ }
+ /* Finally, start the PMTU timer if it was running before. */
+ if (timer_stopped) {
+ sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
+ }
+ SCTP_TCB_UNLOCK(stcb);
} else {
SCTP_TCB_UNLOCK(stcb);
}
}
#endif
-#endif
-#ifdef INET
-#if !defined(__Panda__) && !defined(__Userspace__)
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
void
+#if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN)
+sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip, struct ifnet *ifp SCTP_UNUSED)
#else
-void *
+sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
#endif
-sctp_ctlinput(cmd, sa, vip)
- int cmd;
- struct sockaddr *sa;
- void *vip;
{
- struct ip *ip = vip;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct ip *outer_ip;
+#endif
+ struct ip *inner_ip;
struct sctphdr *sh;
- uint32_t vrf_id;
- /* FIX, for non-bsd is this right? */
- vrf_id = SCTP_DEFAULT_VRFID;
+ struct icmp *icmp;
+ struct sctp_inpcb *inp;
+ struct sctp_tcb *stcb;
+ struct sctp_nets *net;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct sctp_init_chunk *ch;
+#endif
+ struct sockaddr_in src, dst;
+
if (sa->sa_family != AF_INET ||
((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
return;
-#else
- return (NULL);
-#endif
}
if (PRC_IS_REDIRECT(cmd)) {
- ip = 0;
+ vip = NULL;
} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
return;
-#else
- return (NULL);
-#endif
}
- if (ip) {
- struct sctp_inpcb *inp = NULL;
- struct sctp_tcb *stcb = NULL;
- struct sctp_nets *net = NULL;
- struct sockaddr_in to, from;
-
- sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
- bzero(&to, sizeof(to));
- bzero(&from, sizeof(from));
- from.sin_family = to.sin_family = AF_INET;
+ if (vip != NULL) {
+ inner_ip = (struct ip *)vip;
+ icmp = (struct icmp *)((caddr_t)inner_ip -
+ (sizeof(struct icmp) - sizeof(struct ip)));
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
+#endif
+ sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
+ memset(&src, 0, sizeof(struct sockaddr_in));
+ src.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
- from.sin_len = to.sin_len = sizeof(to);
+ src.sin_len = sizeof(struct sockaddr_in);
#endif
- from.sin_port = sh->src_port;
- from.sin_addr = ip->ip_src;
- to.sin_port = sh->dest_port;
- to.sin_addr = ip->ip_dst;
-
+ src.sin_port = sh->src_port;
+ src.sin_addr = inner_ip->ip_src;
+ memset(&dst, 0, sizeof(struct sockaddr_in));
+ dst.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ dst.sin_len = sizeof(struct sockaddr_in);
+#endif
+ dst.sin_port = sh->dest_port;
+ dst.sin_addr = inner_ip->ip_dst;
/*
- * 'to' holds the dest of the packet that failed to be sent.
- * 'from' holds our local endpoint address. Thus we reverse
- * the to and the from in the lookup.
+ * 'dst' holds the dest of the packet that failed to be sent.
+ * 'src' holds our local endpoint address. Thus we reverse
+ * the dst and the src in the lookup.
*/
- stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
- (struct sockaddr *)&from,
- &inp, &net, 1, vrf_id);
- if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
- if (cmd != PRC_MSGSIZE) {
- sctp_notify(inp, ip, sh,
- (struct sockaddr *)&to, stcb,
- net);
+ inp = NULL;
+ net = NULL;
+ stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
+ (struct sockaddr *)&src,
+ &inp, &net, 1,
+ SCTP_DEFAULT_VRFID);
+ if ((stcb != NULL) &&
+ (net != NULL) &&
+ (inp != NULL)) {
+ /* Check the verification tag */
+ if (ntohl(sh->v_tag) != 0) {
+ /*
+ * This must be the verification tag used for
+ * sending out packets. We don't consider
+ * packets reflecting the verification tag.
+ */
+ if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
} else {
- /* handle possible ICMP size messages */
- sctp_notify_mbuf(inp, stcb, net, ip, sh);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ntohs(outer_ip->ip_len) >=
+ sizeof(struct ip) +
+ 8 + (inner_ip->ip_hl << 2) + 20) {
+ /*
+ * In this case we can check if we
+ * got an INIT chunk and if the
+ * initiate tag matches.
+ */
+ ch = (struct sctp_init_chunk *)(sh + 1);
+ if ((ch->ch.chunk_type != SCTP_INITIATION) ||
+ (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+#else
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+#endif
}
- } else {
-#if defined(__FreeBSD__) && __FreeBSD_version < 500000
- /*
- * XXX must be fixed for 5.x and higher, leave for
- * 4.x
- */
- if (PRC_IS_REDIRECT(cmd) && inp) {
- in_rtchange((struct inpcb *)inp,
- inetctlerrmap[cmd]);
+ sctp_notify(inp, stcb, net,
+ icmp->icmp_type,
+ icmp->icmp_code,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ ntohs(inner_ip->ip_len),
+#else
+ inner_ip->ip_len,
+#endif
+ (uint32_t)ntohs(icmp->icmp_nextmtu));
+#if defined(__Userspace__)
+ if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL)) {
+ struct socket *upcall_socket;
+
+ upcall_socket = stcb->sctp_socket;
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ if ((upcall_socket->so_upcall != NULL) &&
+ (upcall_socket->so_error != 0)) {
+ (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
+ }
+ ACCEPT_LOCK();
+ SOCK_LOCK(upcall_socket);
+ sorele(upcall_socket);
}
#endif
+ } else {
if ((stcb == NULL) && (inp != NULL)) {
/* reduce ref-count */
SCTP_INP_WLOCK(inp);
@@ -579,16 +501,12 @@ sctp_ctlinput(cmd, sa, vip)
}
}
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
return;
-#else
- return (NULL);
-#endif
}
#endif
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static int
sctp_getcred(SYSCTL_HANDLER_ARGS)
{
@@ -603,14 +521,8 @@ sctp_getcred(SYSCTL_HANDLER_ARGS)
/* FIX, for non-bsd is this right? */
vrf_id = SCTP_DEFAULT_VRFID;
-#if __FreeBSD_version > 602000
error = priv_check(req->td, PRIV_NETINET_GETCRED);
-#elif __FreeBSD_version >= 500000
- error = suser(req->td);
-#else
- error = suser(req->p);
-#endif
if (error)
return (error);
@@ -655,27 +567,31 @@ out:
return (error);
}
-SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
- 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
-#endif /* #if defined(__FreeBSD__) */
-
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred,
+ CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
+ 0, 0, sctp_getcred, "S,ucred",
+ "Get the ucred of a SCTP connection");
+#endif
#ifdef INET
-#if defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)
+#if defined(_WIN32) || defined(__Userspace__)
int
-#elif defined(__FreeBSD__) && __FreeBSD_version > 690000
+#elif defined(__FreeBSD__)
static void
#else
static int
#endif
sctp_abort(struct socket *so)
{
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
struct sctp_inpcb *inp;
uint32_t flags;
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
-#if defined(__FreeBSD__) && __FreeBSD_version > 690000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
return;
#else
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -683,6 +599,9 @@ sctp_abort(struct socket *so)
#endif
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_must_try_again:
flags = inp->sctp_flags;
#ifdef SCTP_LOG_CLOSING
@@ -702,7 +621,7 @@ sctp_abort(struct socket *so)
*/
SCTP_SB_CLEAR(so->so_rcv);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
so->so_usecount--;
#else
/* Now null out the reference, we are completely detached. */
@@ -715,23 +634,24 @@ sctp_abort(struct socket *so)
goto sctp_must_try_again;
}
}
-#if defined(__FreeBSD__) && __FreeBSD_version > 690000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
return;
#else
return (0);
#endif
}
-#if defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
int
#else
static int
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
-sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
-#elif defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
sctp_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
-#elif defined(__Windows__)
+#elif defined(__FreeBSD__)
+sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
+#elif defined(_WIN32)
sctp_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED)
#else
sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED)
@@ -740,15 +660,12 @@ sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED
struct sctp_inpcb *inp;
struct inpcb *ip_inp;
int error;
-#if !defined(__Panda__) && !defined(__Userspace__)
+#if !defined(__Userspace__)
uint32_t vrf_id = SCTP_DEFAULT_VRFID;
#endif
-#ifdef IPSEC
- uint32_t flags;
-#endif
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp != 0) {
+ if (inp != NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
@@ -768,51 +685,22 @@ sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED
ip_inp = &inp->ip_inp.inp;
ip_inp->inp_vflag |= INP_IPV4;
ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
-#ifdef IPSEC
-#if !(defined(__APPLE__))
- error = ipsec_init_policy(so, &ip_inp->inp_sp);
-#ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 17);
-#endif
- if (error != 0) {
- try_again:
- flags = inp->sctp_flags;
- if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
-#ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 15);
-#endif
- SCTP_INP_WUNLOCK(inp);
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
- SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
- } else {
- flags = inp->sctp_flags;
- if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
- goto try_again;
- } else {
- SCTP_INP_WUNLOCK(inp);
- }
- }
- return (error);
- }
-#endif
-#endif /* IPSEC */
SCTP_INP_WUNLOCK(inp);
return (0);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__Userspace__)
+int
+sctp_bind(struct socket *so, struct sockaddr *addr) {
+ void *p = NULL;
+#elif defined(__FreeBSD__)
static int
sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
{
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__APPLE__)
static int
sctp_bind(struct socket *so, struct sockaddr *addr, struct proc *p) {
-#elif defined(__Panda__) || defined(__Userspace__)
-int
-sctp_bind(struct socket *so, struct sockaddr *addr) {
- void *p = NULL;
-#elif defined(__Windows__)
+#elif defined(_WIN32)
static int
sctp_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) {
#else
@@ -904,10 +792,13 @@ sctpconn_bind(struct socket *so, struct sockaddr *addr)
}
#endif
-#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__)
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
void
sctp_close(struct socket *so)
{
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
struct sctp_inpcb *inp;
uint32_t flags;
@@ -918,6 +809,9 @@ sctp_close(struct socket *so)
/* Inform all the lower layer assoc that we
* are done.
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_must_try_again:
flags = inp->sctp_flags;
#ifdef SCTP_LOG_CLOSING
@@ -954,7 +848,7 @@ sctp_close(struct socket *so)
*/
SCTP_SB_CLEAR(so->so_rcv);
-#if !defined(__APPLE__)
+#if !(defined(__APPLE__) && !defined(__Userspace__))
/* Now null out the reference, we are completely detached. */
so->so_pcb = NULL;
#endif
@@ -965,12 +859,12 @@ sctp_close(struct socket *so)
goto sctp_must_try_again;
}
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
return;
}
-
#else
-
-
int
sctp_detach(struct socket *so)
{
@@ -979,7 +873,7 @@ sctp_detach(struct socket *so)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
-#if defined(__FreeBSD__) && __FreeBSD_version > 690000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
return;
#else
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -1020,7 +914,7 @@ sctp_detach(struct socket *so)
* here for the accounting/select.
*/
SCTP_SB_CLEAR(so->so_rcv);
-#if !defined(__APPLE__)
+#if !(defined(__APPLE__) && !defined(__Userspace__))
/* Now disconnect */
so->so_pcb = NULL;
#endif
@@ -1030,7 +924,7 @@ sctp_detach(struct socket *so)
goto sctp_must_try_again;
}
}
-#if defined(__FreeBSD__) && __FreeBSD_version > 690000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
return;
#else
return (0);
@@ -1041,9 +935,9 @@ sctp_detach(struct socket *so)
#if defined(__Userspace__)
/* __Userspace__ is not calling sctp_sendm */
#endif
-#if !(defined(__Panda__) || defined(__Windows__))
+#if !(defined(_WIN32) && !defined(__Userspace__))
int
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *p);
@@ -1052,9 +946,8 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct proc *p);
#endif
-
int
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *p)
{
@@ -1108,7 +1001,6 @@ connected_type:
/* now what about control */
if (control) {
if (inp->control) {
- SCTP_PRINTF("huh? control set?\n");
sctp_m_freem(inp->control);
inp->control = NULL;
}
@@ -1122,7 +1014,7 @@ connected_type:
inp->pkt_last = inp->pkt = m;
}
if (
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
/* FreeBSD uses a flag passed */
((flags & PRUS_MORETOCOME) == 0)
#else
@@ -1138,9 +1030,18 @@ connected_type:
* definitions) but this is not advisable. This code is used
* by FreeBSD when sending a file with sendfile() though.
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
int ret;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
inp->pkt = NULL;
inp->control = NULL;
return (ret);
@@ -1168,6 +1069,9 @@ sctp_disconnect(struct socket *so)
SCTP_INP_RUNLOCK(inp);
return (0);
} else {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
struct sctp_association *asoc;
struct sctp_tcb *stcb;
@@ -1185,6 +1089,9 @@ sctp_disconnect(struct socket *so)
SCTP_INP_RUNLOCK(inp);
return (0);
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
#if defined(__Userspace__)
if (((so->so_options & SCTP_SO_LINGER) &&
(so->so_linger == 0)) ||
@@ -1194,54 +1101,44 @@ sctp_disconnect(struct socket *so)
(so->so_linger == 0)) ||
(so->so_rcv.sb_cc > 0)) {
#endif
- if (SCTP_GET_STATE(asoc) !=
- SCTP_STATE_COOKIE_WAIT) {
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) {
/* Left with Data unread */
- struct mbuf *err;
-
- err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
- if (err) {
- /*
- * Fill in the user
- * initiated abort
- */
- struct sctp_paramhdr *ph;
-
- ph = mtod(err, struct sctp_paramhdr *);
- SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
- ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(SCTP_BUF_LEN(err));
- }
- sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
+ struct mbuf *op_err;
+
+ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
+ sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
}
SCTP_INP_RUNLOCK(inp);
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_3);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
/* No unlock tcb assoc is gone */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
return (0);
}
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->stream_queue_cnt == 0)) {
/* there is nothing queued to send, so done */
- if (asoc->locked_on_sending) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
goto abort_anyway;
}
- if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* only send SHUTDOWN 1st time thru */
struct sctp_nets *netp;
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
@@ -1250,9 +1147,9 @@ sctp_disconnect(struct socket *so)
}
sctp_send_shutdown(stcb,netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
+ stcb->sctp_ep, stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, netp);
+ stcb->sctp_ep, stcb, NULL);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
}
} else {
@@ -1266,27 +1163,10 @@ sctp_disconnect(struct socket *so)
* we will allow user data to be sent first
* and move to SHUTDOWN-PENDING
*/
- struct sctp_nets *netp;
- if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
- } else {
- netp = stcb->asoc.primary_destination;
- }
-
- asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
- netp);
- if (asoc->locked_on_sending) {
- /* Locked to send out the data */
- struct sctp_stream_queue_pending *sp;
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp == NULL) {
- SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
- asoc->locked_on_sending->stream_no);
- } else {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL);
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
}
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
@@ -1294,21 +1174,28 @@ sctp_disconnect(struct socket *so)
struct mbuf *op_err;
abort_anyway:
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_4;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
SCTP_INP_RUNLOCK(inp);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_5);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
return (0);
} else {
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
}
}
soisdisconnecting(so);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
SCTP_TCB_UNLOCK(stcb);
SCTP_INP_RUNLOCK(inp);
return (0);
@@ -1322,11 +1209,11 @@ sctp_disconnect(struct socket *so)
}
}
-#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
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
@@ -1347,7 +1234,7 @@ sctp_flush(struct socket *so, int how)
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
*/
@@ -1360,14 +1247,13 @@ sctp_flush(struct socket *so, int how)
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
*/
so->so_snd.sb_cc = 0;
so->so_snd.sb_mbcnt = 0;
so->so_snd.sb_mb = NULL;
-
}
return (0);
}
@@ -1388,25 +1274,31 @@ sctp_shutdown(struct socket *so)
if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
/* Restore the flags that the soshutdown took away. */
-#if (defined(__FreeBSD__) && __FreeBSD_version >= 502115) || defined(__Windows__)
+#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
SOCKBUF_LOCK(&so->so_rcv);
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);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
return (EOPNOTSUPP);
- }
- /*
- * Ok if we reach here its the TCP model and it is either a SHUT_WR
- * or SHUT_RDWR. This means we put the shutdown flag against it.
- */
- {
+ } else {
+ /*
+ * Ok, if we reach here its the TCP model and it is either
+ * a SHUT_WR or SHUT_RDWR.
+ * This means we put the shutdown flag against it.
+ */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
struct sctp_tcb *stcb;
struct sctp_association *asoc;
+ struct sctp_nets *netp;
if ((so->so_state &
(SS_ISCONNECTED|SS_ISCONNECTING|SS_ISDISCONNECTING)) == 0) {
@@ -1418,7 +1310,7 @@ sctp_shutdown(struct socket *so)
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
/*
- * Ok we hit the case that the shutdown call was
+ * Ok, we hit the case that the shutdown call was
* made after an abort or something. Nothing to do
* now.
*/
@@ -1427,64 +1319,51 @@ sctp_shutdown(struct socket *so)
}
SCTP_TCB_LOCK(stcb);
asoc = &stcb->asoc;
- if (TAILQ_EMPTY(&asoc->send_queue) &&
+ if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_INP_RUNLOCK(inp);
+ return (0);
+ }
+ if ((SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_ECHOED) &&
+ (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN)) {
+ /* If we are not in or before ESTABLISHED, there is
+ * no protocol action required.
+ */
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_INP_RUNLOCK(inp);
+ return (0);
+ }
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
+ if (stcb->asoc.alternate) {
+ netp = stcb->asoc.alternate;
+ } else {
+ netp = stcb->asoc.primary_destination;
+ }
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) &&
+ TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->stream_queue_cnt == 0)) {
- if (asoc->locked_on_sending) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
goto abort_anyway;
}
/* there is nothing queued to send, so I'm done... */
- if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
- /* only send SHUTDOWN the first time through */
- struct sctp_nets *netp;
-
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_stop_timers_for_shutdown(stcb);
- if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
- } else {
- netp = stcb->asoc.primary_destination;
- }
- sctp_send_shutdown(stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, netp);
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
- }
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
+ sctp_stop_timers_for_shutdown(stcb);
+ sctp_send_shutdown(stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
+ stcb->sctp_ep, stcb, netp);
} else {
/*
- * we still got (or just got) data to send, so set
- * SHUTDOWN_PENDING
+ * We still got (or just got) data to send, so set
+ * SHUTDOWN_PENDING.
*/
- struct sctp_nets *netp;
- if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
- } else {
- netp = stcb->asoc.primary_destination;
- }
-
- asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
- netp);
-
- if (asoc->locked_on_sending) {
- /* Locked to send out the data */
- struct sctp_stream_queue_pending *sp;
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp == NULL) {
- SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
- asoc->locked_on_sending->stream_no);
- } else {
- if ((sp->length == 0) && (sp-> msg_is_complete == 0)) {
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
- }
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
}
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
@@ -1492,19 +1371,26 @@ sctp_shutdown(struct socket *so)
struct mbuf *op_err;
abort_anyway:
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
+ SCTP_INP_RUNLOCK(inp);
sctp_abort_an_association(stcb->sctp_ep, stcb,
op_err, SCTP_SO_LOCKED);
- goto skip_unlock;
- } else {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
+ return (0);
}
}
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL);
+ /* XXX: Why do this in the case where we have still data queued? */
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
+ SCTP_INP_RUNLOCK(inp);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
+ return (0);
}
- skip_unlock:
- SCTP_INP_RUNLOCK(inp);
- return (0);
}
/*
@@ -1512,33 +1398,33 @@ sctp_shutdown(struct socket *so)
* returns 0 on success, 1 on error
*/
static uint32_t
-sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
+sctp_fill_user_address(struct sockaddr *dst, struct sockaddr *src)
{
#ifdef INET6
#if defined(SCTP_EMBEDDED_V6_SCOPE)
struct sockaddr_in6 lsa6;
- sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
+ src = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)src,
&lsa6);
#endif
#endif
#ifdef HAVE_SA_LEN
- memcpy(ss, sa, sa->sa_len);
+ memcpy(dst, src, src->sa_len);
#else
- switch (sa->sa_family) {
+ switch (src->sa_family) {
#ifdef INET
case AF_INET:
- memcpy(ss, sa, sizeof(struct sockaddr_in));
+ memcpy(dst, src, sizeof(struct sockaddr_in));
break;
#endif
#ifdef INET6
case AF_INET6:
- memcpy(ss, sa, sizeof(struct sockaddr_in6));
+ memcpy(dst, src, sizeof(struct sockaddr_in6));
break;
#endif
#if defined(__Userspace__)
case AF_CONN:
- memcpy(ss, sa, sizeof(struct sockaddr_conn));
+ memcpy(dst, src, sizeof(struct sockaddr_conn));
break;
#endif
default:
@@ -1549,17 +1435,12 @@ sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
return (0);
}
-
-
-/*
- * NOTE: assumes addr lock is held
- */
static size_t
sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- size_t limit,
- struct sockaddr_storage *sas,
- uint32_t vrf_id)
+ struct sctp_tcb *stcb,
+ size_t limit,
+ struct sockaddr *addr,
+ uint32_t vrf_id)
{
struct sctp_ifn *sctp_ifn;
struct sctp_ifa *sctp_ifa;
@@ -1576,8 +1457,9 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
#endif
struct sctp_vrf *vrf;
+ SCTP_IPI_ADDR_LOCK_ASSERT();
actual = 0;
- if (limit <= 0)
+ if (limit == 0)
return (actual);
if (stcb) {
@@ -1664,7 +1546,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
* is one of those we must skip it.
*/
if (sctp_is_addr_restricted(stcb,
- sctp_ifa)) {
+ sctp_ifa)) {
continue;
}
}
@@ -1682,7 +1564,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
*/
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -1694,22 +1576,25 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
}
#ifdef INET6
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
- in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
- ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
- sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
+ if (actual + sizeof(struct sockaddr_in6) > limit) {
+ return (actual);
+ }
+ in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)addr);
+ ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport;
+ addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
actual += sizeof(struct sockaddr_in6);
} else {
#endif
- memcpy(sas, sin, sizeof(*sin));
- ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
- sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
- actual += sizeof(*sin);
+ if (actual + sizeof(struct sockaddr_in) > limit) {
+ return (actual);
+ }
+ memcpy(addr, sin, sizeof(struct sockaddr_in));
+ ((struct sockaddr_in *)addr)->sin_port = inp->sctp_lport;
+ addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in));
+ actual += sizeof(struct sockaddr_in);
#ifdef INET6
}
#endif
- if (actual >= limit) {
- return (actual);
- }
} else {
continue;
}
@@ -1731,7 +1616,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
*/
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -1770,13 +1655,13 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
(IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
continue;
}
- memcpy(sas, sin6, sizeof(*sin6));
- ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
- sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
- actual += sizeof(*sin6);
- if (actual >= limit) {
+ if (actual + sizeof(struct sockaddr_in6) > limit) {
return (actual);
}
+ memcpy(addr, sin6, sizeof(struct sockaddr_in6));
+ ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport;
+ addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
+ actual += sizeof(struct sockaddr_in6);
} else {
continue;
}
@@ -1785,13 +1670,13 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
#if defined(__Userspace__)
case AF_CONN:
if (conn_addr_legal) {
- memcpy(sas, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn));
- ((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport;
- sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_conn));
- actual += sizeof(struct sockaddr_conn);
- if (actual >= limit) {
+ if (actual + sizeof(struct sockaddr_conn) > limit) {
return (actual);
}
+ memcpy(addr, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn));
+ ((struct sockaddr_conn *)addr)->sconn_port = inp->sctp_lport;
+ addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_conn));
+ actual += sizeof(struct sockaddr_conn);
} else {
continue;
}
@@ -1804,9 +1689,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
}
} else {
struct sctp_laddr *laddr;
-#ifndef HAVE_SA_LEN
- uint32_t sa_len = 0;
-#endif
+ size_t sa_len;
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (stcb) {
@@ -1814,59 +1697,58 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
continue;
}
}
- if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
- continue;
+#ifdef HAVE_SA_LEN
+ sa_len = laddr->ifa->address.sa.sa_len;
+#else
switch (laddr->ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
- ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
+ sa_len = sizeof(struct sockaddr_in);
break;
#endif
#ifdef INET6
case AF_INET6:
- ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
+ sa_len = sizeof(struct sockaddr_in6);
break;
#endif
#if defined(__Userspace__)
case AF_CONN:
- ((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport;
+ sa_len = sizeof(struct sockaddr_conn);
break;
#endif
default:
/* TSNH */
+ sa_len = 0;
break;
}
-#ifdef HAVE_SA_LEN
- sas = (struct sockaddr_storage *)((caddr_t)sas +
- laddr->ifa->address.sa.sa_len);
- actual += laddr->ifa->address.sa.sa_len;
-#else
+#endif
+ if (actual + sa_len > limit) {
+ return (actual);
+ }
+ if (sctp_fill_user_address(addr, &laddr->ifa->address.sa))
+ continue;
switch (laddr->ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
- sa_len = sizeof(struct sockaddr_in);
+ ((struct sockaddr_in *)addr)->sin_port = inp->sctp_lport;
break;
#endif
#ifdef INET6
case AF_INET6:
- sa_len = sizeof(struct sockaddr_in6);
+ ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport;
break;
#endif
#if defined(__Userspace__)
case AF_CONN:
- sa_len = sizeof(struct sockaddr_conn);
+ ((struct sockaddr_conn *)addr)->sconn_port = inp->sctp_lport;
break;
#endif
default:
/* TSNH */
break;
}
- sas = (struct sockaddr_storage *)((caddr_t)sas + sa_len);
+ addr = (struct sockaddr *)((caddr_t)addr + sa_len);
actual += sa_len;
-#endif
- if (actual >= limit) {
- return (actual);
- }
}
}
return (actual);
@@ -1876,7 +1758,7 @@ static size_t
sctp_fill_up_addresses(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
size_t limit,
- struct sockaddr_storage *sas)
+ struct sockaddr *addr)
{
size_t size = 0;
#ifdef SCTP_MVRF
@@ -1891,22 +1773,19 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp,
*/
/* fill up addresses for all VRFs on the endpoint */
for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) {
- size += sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
- inp->m_vrf_ids[id]);
- sas = (struct sockaddr_storage *)((caddr_t)sas + size);
+ size += sctp_fill_up_addresses_vrf(inp, stcb, limit, addr,
+ inp->m_vrf_ids[id]);
+ addr = (struct sockaddr *)((caddr_t)addr + size);
}
#else
/* fill up addresses for the endpoint's default vrf */
- size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
- inp->def_vrf_id);
+ size = sctp_fill_up_addresses_vrf(inp, stcb, limit, addr,
+ inp->def_vrf_id);
#endif
SCTP_IPI_ADDR_RUNLOCK();
return (size);
}
-/*
- * NOTE: assumes addr lock is held
- */
static int
sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
{
@@ -1920,6 +1799,7 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
* bound-all case a TCB may NOT include the loopback or other
* addresses as well.
*/
+ SCTP_IPI_ADDR_LOCK_ASSERT();
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
return (0);
@@ -2024,13 +1904,12 @@ static int
sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
size_t optsize, void *p, int delay)
{
- int error = 0;
+ int error;
int creat_lock_on = 0;
struct sctp_tcb *stcb = NULL;
struct sockaddr *sa;
- int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
+ unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
uint32_t vrf_id;
- int bad_addresses = 0;
sctp_assoc_t *a_id;
SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
@@ -2066,20 +1945,15 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
error = EFAULT;
goto out_now;
}
- totaddrp = (int *)optval;
+ totaddrp = (unsigned int *)optval;
totaddr = *totaddrp;
sa = (struct sockaddr *)(totaddrp + 1);
- stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
- if ((stcb != NULL) || bad_addresses) {
+ error = sctp_connectx_helper_find(inp, sa, totaddr, &num_v4, &num_v6, (unsigned int)(optsize - sizeof(int)));
+ if (error != 0) {
/* Already have or am bring up an association */
SCTP_ASOC_CREATE_UNLOCK(inp);
creat_lock_on = 0;
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- if (bad_addresses == 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- }
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
goto out_now;
}
#ifdef INET6
@@ -2090,10 +1964,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
(num_v4 > 0)) {
- struct in6pcb *inp6;
-
- inp6 = (struct in6pcb *)inp;
- if (SCTP_IPV6_V6ONLY(inp6)) {
+ if (SCTP_IPV6_V6ONLY(inp)) {
/*
* if IPV6_V6ONLY flag, ignore connections destined
* to a v4 addr or v4-mapped addr
@@ -2116,17 +1987,18 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
/* FIX ME: do we want to pass in a vrf on the connect call? */
vrf_id = inp->def_vrf_id;
-
/* We are GOOD to go */
stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
- (struct thread *)p
-#elif defined(__Windows__)
- (PKTHREAD)p
+ inp->sctp_ep.pre_open_stream_count,
+ inp->sctp_ep.port,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ (struct thread *)p,
+#elif defined(_WIN32) && !defined(__Userspace__)
+ (PKTHREAD)p,
#else
- (struct proc *)p
+ (struct proc *)p,
#endif
- );
+ SCTP_INITIALIZE_AUTH_PARAMS);
if (stcb == NULL) {
/* Gak! no memory */
goto out_now;
@@ -2136,7 +2008,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
/* Set the connected flag so we can queue data */
soisconnecting(so);
}
- SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
/* move to second address */
switch (sa->sa_family) {
#ifdef INET
@@ -2157,15 +2029,11 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error);
/* Fill in the return id */
if (error) {
- (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6);
goto out_now;
}
a_id = (sctp_assoc_t *)optval;
*a_id = sctp_get_associd(stcb);
- /* initialize authentication parameters for the assoc */
- sctp_initialize_auth_params(inp, stcb);
-
if (delay) {
/* doing delayed connection */
stcb->asoc.delayed_connection = 1;
@@ -2175,11 +2043,6 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
}
SCTP_TCB_UNLOCK(stcb);
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
- stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
- /* Set the connected flag so we can queue data */
- soisconnecting(so);
- }
out_now:
if (creat_lock_on) {
SCTP_ASOC_CREATE_UNLOCK(inp);
@@ -2195,20 +2058,19 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
stcb = LIST_FIRST(&inp->sctp_asoc_list); \
if (stcb) { \
SCTP_TCB_LOCK(stcb); \
- } \
+ } \
SCTP_INP_RUNLOCK(inp); \
} else if (assoc_id > SCTP_ALL_ASSOC) { \
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
if (stcb == NULL) { \
- 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; \
} \
} else { \
stcb = NULL; \
- } \
- }
-
+ } \
+}
#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
if (size < sizeof(type)) { \
@@ -2218,9 +2080,9 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
} else { \
destp = (type *)srcp; \
} \
- }
+}
-#if defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
int
#else
static int
@@ -2280,7 +2142,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
break;
case SCTP_AUTOCLOSE:
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
- val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
+ val = sctp_ticks_to_secs(inp->sctp_ep.auto_close_time);
else
val = 0;
break;
@@ -2356,6 +2218,38 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
*optsize = sizeof(uint32_t);
break;
}
+ case SCTP_INTERLEAVING_SUPPORTED:
+ {
+ struct sctp_assoc_value *av;
+
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+
+ if (stcb) {
+ av->assoc_value = stcb->asoc.idata_supported;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
+ SCTP_INP_RLOCK(inp);
+ if (inp->idata_supported) {
+ av->assoc_value = 1;
+ } else {
+ av->assoc_value = 0;
+ }
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
+ }
+ break;
+ }
case SCTP_CMT_ON_OFF:
{
struct sctp_assoc_value *av;
@@ -2368,7 +2262,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->sctp_cmt_on_off;
SCTP_INP_RUNLOCK(inp);
@@ -2394,7 +2289,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
SCTP_INP_RUNLOCK(inp);
@@ -2439,7 +2335,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
SCTP_INP_RUNLOCK(inp);
@@ -2512,8 +2409,15 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
uint32_t *value, cnt;
SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- cnt = 0;
SCTP_INP_RLOCK(inp);
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
+ /* Can't do this for a 1-1 socket */
+ error = EINVAL;
+ SCTP_INP_RUNLOCK(inp);
+ break;
+ }
+ cnt = 0;
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
cnt++;
}
@@ -2525,15 +2429,28 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
case SCTP_GET_ASSOC_ID_LIST:
{
struct sctp_assoc_ids *ids;
- unsigned int at, limit;
+ uint32_t at;
+ size_t limit;
SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
- at = 0;
- limit = (*optsize-sizeof(uint32_t))/ sizeof(sctp_assoc_t);
SCTP_INP_RLOCK(inp);
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
+ /* Can't do this for a 1-1 socket */
+ error = EINVAL;
+ SCTP_INP_RUNLOCK(inp);
+ break;
+ }
+ at = 0;
+ limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
if (at < limit) {
ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
+ if (at == 0) {
+ error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
} else {
error = EINVAL;
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@@ -2560,7 +2477,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->sctp_context;
SCTP_INP_RUNLOCK(inp);
@@ -2594,6 +2512,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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;
@@ -2650,9 +2569,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (sack->sack_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
- sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
+ sack->sack_delay = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
SCTP_INP_RUNLOCK(inp);
} else {
@@ -2686,20 +2606,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
}
case SCTP_MAX_BURST:
{
-#if defined(__FreeBSD__) && __FreeBSD_version < 900000
- uint8_t *value;
-
- SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize);
-
- SCTP_INP_RLOCK(inp);
- if (inp->sctp_ep.max_burst < 256) {
- *value = inp->sctp_ep.max_burst;
- } else {
- *value = 255;
- }
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(uint8_t);
-#else
struct sctp_assoc_value *av;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
@@ -2711,7 +2617,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->sctp_ep.max_burst;
SCTP_INP_RUNLOCK(inp);
@@ -2723,7 +2630,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
if (error == 0) {
*optsize = sizeof(struct sctp_assoc_value);
}
-#endif
break;
}
case SCTP_MAXSEG:
@@ -2740,7 +2646,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
ovh = SCTP_MED_OVERHEAD;
@@ -2900,7 +2807,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
*/
{
size_t cpsz, left;
- struct sockaddr_storage *sas;
+ struct sockaddr *addr;
struct sctp_nets *net;
struct sctp_getaddresses *saddr;
@@ -2908,9 +2815,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
if (stcb) {
- left = (*optsize) - sizeof(struct sctp_getaddresses);
- *optsize = sizeof(struct sctp_getaddresses);
- sas = (struct sockaddr_storage *)&saddr->addr[0];
+ left = *optsize - offsetof(struct sctp_getaddresses, addr);
+ *optsize = offsetof(struct sctp_getaddresses, addr);
+ addr = &saddr->addr[0].sa;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
switch (net->ro._l_addr.sa.sa_family) {
@@ -2953,22 +2860,22 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
(net->ro._l_addr.sa.sa_family == AF_INET)) {
/* Must map the address */
in6_sin_2_v4mapsin6(&net->ro._l_addr.sin,
- (struct sockaddr_in6 *)sas);
+ (struct sockaddr_in6 *)addr);
} else {
- memcpy(sas, &net->ro._l_addr, cpsz);
+ memcpy(addr, &net->ro._l_addr, cpsz);
}
#else
- memcpy(sas, &net->ro._l_addr, cpsz);
+ memcpy(addr, &net->ro._l_addr, cpsz);
#endif
- ((struct sockaddr_in *)sas)->sin_port = stcb->rport;
+ ((struct sockaddr_in *)addr)->sin_port = stcb->rport;
- sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
+ addr = (struct sockaddr *)((caddr_t)addr + cpsz);
left -= cpsz;
*optsize += cpsz;
}
SCTP_TCB_UNLOCK(stcb);
} else {
- 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;
@@ -2976,19 +2883,17 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
case SCTP_GET_LOCAL_ADDRESSES:
{
size_t limit, actual;
- struct sockaddr_storage *sas;
struct sctp_getaddresses *saddr;
SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
- sas = (struct sockaddr_storage *)&saddr->addr[0];
- limit = *optsize - sizeof(sctp_assoc_t);
- actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
+ limit = *optsize - offsetof(struct sctp_getaddresses, addr);
+ actual = sctp_fill_up_addresses(inp, stcb, limit, &saddr->addr[0].sa);
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
}
- *optsize = sizeof(struct sockaddr_storage) + actual;
+ *optsize = offsetof(struct sctp_getaddresses, addr) + actual;
break;
}
case SCTP_PEER_ADDR_PARAMS:
@@ -3086,16 +2991,28 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
/* Applies to the specific association */
paddrp->spp_flags = 0;
if (net != NULL) {
- int ovh;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MED_OVERHEAD;
- } else {
- ovh = SCTP_MED_V4_OVERHEAD;
- }
-
paddrp->spp_hbinterval = net->heart_beat_delay;
paddrp->spp_pathmaxrxt = net->failure_threshold;
- paddrp->spp_pathmtu = net->mtu - ovh;
+ paddrp->spp_pathmtu = net->mtu;
+ switch (net->ro._l_addr.sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ paddrp->spp_pathmtu -= SCTP_MIN_OVERHEAD;
+ break;
+#endif
+#if defined(__Userspace__)
+ case AF_CONN:
+ paddrp->spp_pathmtu -= sizeof(struct sctphdr);
+ break;
+#endif
+ default:
+ break;
+ }
/* get flags for HB */
if (net->dest_state & SCTP_ADDR_NOHB) {
paddrp->spp_flags |= SPP_HB_DISABLE;
@@ -3104,9 +3021,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
}
/* get flags for PMTU */
if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
- paddrp->spp_flags |= SPP_PMTUD_ENABLE;
- } else {
paddrp->spp_flags |= SPP_PMTUD_DISABLE;
+ } else {
+ paddrp->spp_flags |= SPP_PMTUD_ENABLE;
}
if (net->dscp & 0x01) {
paddrp->spp_dscp = net->dscp & 0xfc;
@@ -3125,7 +3042,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
* value
*/
paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
- paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
+ 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;
@@ -3154,11 +3071,12 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC))) {
/* Use endpoint defaults */
SCTP_INP_RLOCK(inp);
paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
- paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
+ paddrp->spp_hbinterval = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
/* get inp's default */
if (inp->sctp_ep.default_dscp & 0x01) {
@@ -3172,8 +3090,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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;
@@ -3256,13 +3173,32 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
paddri->spinfo_rto = net->RTO;
paddri->spinfo_assoc_id = sctp_get_associd(stcb);
paddri->spinfo_mtu = net->mtu;
+ switch (addr->sa_family) {
+#if defined(INET)
+ case AF_INET:
+ paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
+ break;
+#endif
+#if defined(INET6)
+ case AF_INET6:
+ paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD;
+ break;
+#endif
+#if defined(__Userspace__)
+ case AF_CONN:
+ paddri->spinfo_mtu -= sizeof(struct sctphdr);
+ break;
+#endif
+ default:
+ break;
+ }
SCTP_TCB_UNLOCK(stcb);
*optsize = sizeof(struct sctp_paddrinfo);
} else {
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;
@@ -3289,12 +3225,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
error = EINVAL;
break;
}
- /*
- * I think passing the state is fine since
- * sctp_constants.h will be available to the user
- * land.
- */
- sstat->sstat_state = stcb->asoc.state;
+ sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state);
sstat->sstat_assoc_id = sctp_get_associd(stcb);
sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
@@ -3304,46 +3235,83 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
*/
sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
stcb->asoc.cnt_on_all_streams);
-
-
sstat->sstat_instrms = stcb->asoc.streamincnt;
sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
+ net = stcb->asoc.primary_destination;
+ if (net != NULL) {
#ifdef HAVE_SA_LEN
- memcpy(&sstat->sstat_primary.spinfo_address,
- &stcb->asoc.primary_destination->ro._l_addr,
- ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
-#else
- if (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET) {
memcpy(&sstat->sstat_primary.spinfo_address,
- &stcb->asoc.primary_destination->ro._l_addr,
- sizeof(struct sockaddr_in));
+ &net->ro._l_addr,
+ ((struct sockaddr *)(&net->ro._l_addr))->sa_len);
+#else
+ switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
+#if defined(INET)
+ case AF_INET:
+ memcpy(&sstat->sstat_primary.spinfo_address,
+ &net->ro._l_addr,
+ sizeof(struct sockaddr_in));
+ break;
+#endif
+#if defined(INET6)
+ case AF_INET6:
+ memcpy(&sstat->sstat_primary.spinfo_address,
+ &net->ro._l_addr,
+ sizeof(struct sockaddr_in6));
+ break;
+#endif
+#if defined(__Userspace__)
+ case AF_CONN:
+ memcpy(&sstat->sstat_primary.spinfo_address,
+ &net->ro._l_addr,
+ sizeof(struct sockaddr_conn));
+ break;
+#endif
+ default:
+ break;
+ }
+#endif
+ ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
+ /*
+ * Again the user can get info from sctp_constants.h
+ * for what the state of the network is.
+ */
+ if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
+ /* It's unconfirmed */
+ sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
+ } else if (net->dest_state & SCTP_ADDR_REACHABLE) {
+ /* It's active */
+ sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
+ } else {
+ /* It's inactive */
+ sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
+ }
+ sstat->sstat_primary.spinfo_cwnd = net->cwnd;
+ sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
+ sstat->sstat_primary.spinfo_rto = net->RTO;
+ sstat->sstat_primary.spinfo_mtu = net->mtu;
+ switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
+#if defined(INET)
+ case AF_INET:
+ sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
+ break;
+#endif
+#if defined(INET6)
+ case AF_INET6:
+ 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;
+ }
} else {
- memcpy(&sstat->sstat_primary.spinfo_address,
- &stcb->asoc.primary_destination->ro._l_addr,
- sizeof(struct sockaddr_in6));
+ memset(&sstat->sstat_primary, 0, sizeof(struct sctp_paddrinfo));
}
-#endif
- net = stcb->asoc.primary_destination;
- ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
- /*
- * Again the user can get info from sctp_constants.h
- * for what the state of the network is.
- */
- if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
- /* It's unconfirmed */
- sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
- } else if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* It's active */
- sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
- } else {
- /* It's inactive */
- sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
- }
- sstat->sstat_primary.spinfo_cwnd = net->cwnd;
- sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
- sstat->sstat_primary.spinfo_rto = net->RTO;
- sstat->sstat_primary.spinfo_mtu = net->mtu;
sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
*optsize = sizeof(struct sctp_status);
@@ -3364,7 +3332,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (srto->srto_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
srto->srto_initial = inp->sctp_ep.initial_rto;
srto->srto_max = inp->sctp_ep.sctp_maxrto;
@@ -3411,7 +3380,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
if (stcb) {
- sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
+ sasoc->sasoc_cookie_life = sctp_ticks_to_msecs(stcb->asoc.cookie_life);
sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
@@ -3420,9 +3389,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
- sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
+ sasoc->sasoc_cookie_life = sctp_ticks_to_msecs(inp->sctp_ep.def_cookie_life);
sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
sasoc->sasoc_number_peer_destinations = 0;
sasoc->sasoc_peer_rwnd = 0;
@@ -3451,7 +3421,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
SCTP_INP_RUNLOCK(inp);
@@ -3576,7 +3547,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (scact->scact_assoc_id == SCTP_FUTURE_ASSOC))) {
/* get the endpoint active key */
SCTP_INP_RLOCK(inp);
scact->scact_keynumber = inp->sctp_ep.default_keyid;
@@ -3618,7 +3590,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC))) {
/* get off the endpoint */
SCTP_INP_RLOCK(inp);
chklist = inp->sctp_ep.local_auth_chunks;
@@ -3747,11 +3720,11 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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) ||
- (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (event->se_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
event->se_on = sctp_is_feature_on(inp, event_type);
SCTP_INP_RUNLOCK(inp);
@@ -3761,49 +3734,36 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
}
}
}
+ if (stcb != NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
if (error == 0) {
*optsize = sizeof(struct sctp_event);
}
break;
}
case SCTP_RECVRCVINFO:
- {
- int onoff;
-
if (*optsize < sizeof(int)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
} else {
SCTP_INP_RLOCK(inp);
- onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
+ *(int *)optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
SCTP_INP_RUNLOCK(inp);
- }
- if (error == 0) {
- /* return the option value */
- *(int *)optval = onoff;
*optsize = sizeof(int);
}
break;
- }
case SCTP_RECVNXTINFO:
- {
- int onoff;
-
if (*optsize < sizeof(int)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
} else {
SCTP_INP_RLOCK(inp);
- onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
+ *(int *)optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
SCTP_INP_RUNLOCK(inp);
- }
- if (error == 0) {
- /* return the option value */
- *(int *)optval = onoff;
*optsize = sizeof(int);
}
break;
- }
case SCTP_DEFAULT_SNDINFO:
{
struct sctp_sndinfo *info;
@@ -3821,7 +3781,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (info->snd_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
info->snd_sid = inp->def_send.sinfo_stream;
info->snd_flags = inp->def_send.sinfo_flags;
@@ -3853,7 +3814,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (info->pr_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
info->pr_value = inp->def_send.sinfo_timetolive;
@@ -3963,20 +3925,24 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
if (net != NULL) {
thlds->spt_pathmaxrxt = net->failure_threshold;
thlds->spt_pathpfthld = net->pf_threshold;
+ thlds->spt_pathcpthld = 0xffff;
} else {
thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
+ thlds->spt_pathcpthld = 0xffff;
}
thlds->spt_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC))) {
/* Use endpoint defaults */
SCTP_INP_RLOCK(inp);
thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
+ thlds->spt_pathcpthld = 0xffff;
SCTP_INP_RUNLOCK(inp);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -4089,7 +4055,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
encaps->sue_port = inp->sctp_ep.port;
SCTP_INP_RUNLOCK(inp);
@@ -4116,7 +4083,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->ecn_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4143,7 +4111,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->prsctp_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4170,7 +4139,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->auth_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4197,7 +4167,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->asconf_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4224,7 +4195,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->reconfig_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4251,7 +4223,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->nrsack_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4278,7 +4251,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->pktdrop_supported;
SCTP_INP_RUNLOCK(inp);
@@ -4305,7 +4279,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = (uint32_t)inp->local_strreset_support;
SCTP_INP_RUNLOCK(inp);
@@ -4350,12 +4325,16 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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:
@@ -4378,12 +4357,16 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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:
@@ -4399,7 +4382,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_RLOCK(inp);
av->assoc_value = inp->max_cwnd;
SCTP_INP_RUNLOCK(inp);
@@ -4424,7 +4408,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
return (error);
}
-#if defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
int
#else
static int
@@ -4439,13 +4423,11 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
uint32_t vrf_id;
if (optval == NULL) {
- SCTP_PRINTF("optval is NULL\n");
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
- SCTP_PRINTF("inp is NULL?\n");
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
@@ -4515,7 +4497,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
* The value is in ticks. Note this does not effect
* old associations, only new ones.
*/
- inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
+ inp->sctp_ep.auto_close_time = sctp_secs_to_ticks(*mopt);
break;
}
SCTP_INP_WLOCK(inp);
@@ -4580,6 +4562,43 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
}
+ case SCTP_INTERLEAVING_SUPPORTED:
+ {
+ struct sctp_assoc_value *av;
+
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+
+ if (stcb) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
+ SCTP_INP_WLOCK(inp);
+ if (av->assoc_value == 0) {
+ inp->idata_supported = 0;
+ } else {
+ if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
+ (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS))) {
+ inp->idata_supported = 1;
+ } else {
+ /* Must have Frag interleave and stream interleave on */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ SCTP_INP_WUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ break;
+ }
case SCTP_CMT_ON_OFF:
if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
struct sctp_assoc_value *av;
@@ -4597,14 +4616,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->sctp_cmt_on_off = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -4646,14 +4667,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -4678,7 +4701,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
if (stcb == NULL) {
- if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC)) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -4719,29 +4743,35 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
+ SCTP_TCB_SEND_LOCK(stcb);
stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
stcb->asoc.stream_scheduling_module = av->assoc_value;
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
+ SCTP_TCB_SEND_LOCK(stcb);
stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
stcb->asoc.stream_scheduling_module = av->assoc_value;
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
+ SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_TCB_UNLOCK(stcb);
}
SCTP_INP_RUNLOCK(inp);
@@ -4764,7 +4794,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- if (av->assoc_id == SCTP_CURRENT_ASSOC) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_CURRENT_ASSOC)) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -4802,14 +4833,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->sctp_context = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -4966,10 +4999,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
if (sack->sack_delay) {
- if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
- sack->sack_delay = SCTP_MAX_SACK_DELAY;
- if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
- sack->sack_delay = TICKS_TO_MSEC(1);
+ if (sack->sack_delay > SCTP_MAX_SACK_DELAY) {
+ error = EINVAL;
+ if (stcb != NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ break;
}
}
if (stcb) {
@@ -4983,19 +5018,21 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
- (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (sack->sack_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
if (sack->sack_delay) {
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = sctp_msecs_to_ticks(sack->sack_delay);
}
if (sack->sack_freq) {
inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
}
SCTP_INP_WUNLOCK(inp);
}
- if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
- (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (sack->sack_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5022,6 +5059,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
+ } else {
+ inp->auth_supported = 1;
}
SCTP_INP_WUNLOCK(inp);
break;
@@ -5038,7 +5077,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (sca->sca_keylength == 0) {
size = optsize - sizeof(struct sctp_authkey);
} else {
- if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
+ if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
size = sca->sca_keylength;
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -5080,8 +5119,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
- (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (sca->sca_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
shared_keys = &inp->sctp_ep.shared_keys;
/*
@@ -5115,8 +5155,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = sctp_insert_sharedkey(shared_keys, shared_key);
SCTP_INP_WUNLOCK(inp);
}
- if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
- (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (sca->sca_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5224,8 +5265,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
- (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (scact->scact_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -5233,8 +5275,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_INP_WUNLOCK(inp);
}
- if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
- (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (scact->scact_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5263,8 +5306,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
- (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (scdel->scact_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -5272,8 +5316,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_INP_WUNLOCK(inp);
}
- if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
- (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (scdel->scact_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5302,8 +5347,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
- (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (keyid->scact_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -5311,8 +5357,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_INP_WUNLOCK(inp);
}
- if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
- (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (keyid->scact_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5341,14 +5388,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->local_strreset_support = (uint8_t)av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5357,7 +5406,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_INP_RUNLOCK(inp);
}
-
}
break;
}
@@ -5370,7 +5418,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
if (stcb == NULL) {
- 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;
}
@@ -5383,24 +5431,36 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_TCB_UNLOCK(stcb);
break;
}
- if (sizeof(struct sctp_reset_streams) +
- strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
break;
}
- if (stcb->asoc.stream_reset_outstanding) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
+ if (sizeof(struct sctp_reset_streams) +
+ strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
+ error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
break;
}
if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
send_in = 1;
+ if (stcb->asoc.stream_reset_outstanding) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
+ error = EALREADY;
+ SCTP_TCB_UNLOCK(stcb);
+ break;
+ }
}
if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
send_out = 1;
}
+ if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
+ error = ENOMEM;
+ SCTP_TCB_UNLOCK(stcb);
+ break;
+ }
if ((send_in == 0) && (send_out == 0)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
@@ -5409,13 +5469,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
for (i = 0; i < strrst->srs_number_streams; i++) {
if ((send_in) &&
- (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
+ (strrst->srs_stream_list[i] >= stcb->asoc.streamincnt)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
if ((send_out) &&
- (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
+ (strrst->srs_stream_list[i] >= stcb->asoc.streamoutcnt)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
@@ -5425,11 +5485,44 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_TCB_UNLOCK(stcb);
break;
}
- error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
- strrst->srs_stream_list,
- send_out, send_in, 0, 0, 0, 0, 0);
-
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
+ if (send_out) {
+ int cnt;
+ uint16_t strm;
+ if (strrst->srs_number_streams) {
+ for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) {
+ strm = strrst->srs_stream_list[i];
+ if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) {
+ stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING;
+ cnt++;
+ }
+ }
+ } else {
+ /* Its all */
+ for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) {
+ stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING;
+ cnt++;
+ }
+ }
+ }
+ }
+ if (send_in) {
+ error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
+ strrst->srs_stream_list,
+ send_in, 0, 0, 0, 0, 0);
+ } else {
+ error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED);
+ }
+ if (error == 0) {
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
+ } else {
+ /*
+ * For outgoing streams don't report any problems in
+ * sending the request to the application.
+ * XXX: Double check resetting incoming streams.
+ */
+ error = 0;
+ }
SCTP_TCB_UNLOCK(stcb);
break;
}
@@ -5443,7 +5536,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
if (stcb == NULL) {
- 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;
}
@@ -5456,6 +5549,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_TCB_UNLOCK(stcb);
break;
}
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ SCTP_TCB_UNLOCK(stcb);
+ break;
+ }
if (stcb->asoc.stream_reset_outstanding) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
@@ -5496,7 +5595,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
goto skip_stuff;
}
}
- error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
+ error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
skip_stuff:
SCTP_TCB_UNLOCK(stcb);
@@ -5504,6 +5603,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
case SCTP_RESET_ASSOC:
{
+ int i;
uint32_t *value;
SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
@@ -5522,13 +5622,34 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_TCB_UNLOCK(stcb);
break;
}
+ if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ SCTP_TCB_UNLOCK(stcb);
+ break;
+ }
if (stcb->asoc.stream_reset_outstanding) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
SCTP_TCB_UNLOCK(stcb);
break;
}
- error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0);
+ /* Is there any data pending in the send or sent queues? */
+ if (!TAILQ_EMPTY(&stcb->asoc.send_queue) ||
+ !TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
+ busy_out:
+ error = EBUSY;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ SCTP_TCB_UNLOCK(stcb);
+ break;
+ }
+ /* Do any streams have data queued? */
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ goto busy_out;
+ }
+ }
+ error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
break;
@@ -5586,7 +5707,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
stcb->asoc.primary_destination,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_9);
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
} else {
/*
@@ -5601,15 +5722,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
case SCTP_MAX_BURST:
{
-#if defined(__FreeBSD__) && __FreeBSD_version < 900000
- uint8_t *burst;
-
- SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize);
-
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.max_burst = *burst;
- SCTP_INP_WUNLOCK(inp);
-#else
struct sctp_assoc_value *av;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
@@ -5621,14 +5733,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.max_burst = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5638,7 +5752,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_INP_RUNLOCK(inp);
}
}
-#endif
break;
}
case SCTP_MAXSEG:
@@ -5664,7 +5777,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
/* FIXME MT: I think this is not in tune with the API ID */
if (av->assoc_value) {
@@ -5869,14 +5983,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
- (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
SCTP_INP_WUNLOCK(inp);
}
- if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
- (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -5937,8 +6053,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if ((stcb != NULL) && (net == NULL)) {
#ifdef INET
if (addr->sa_family == AF_INET) {
-
struct sockaddr_in *sin;
+
sin = (struct sockaddr_in *)addr;
if (sin->sin_addr.s_addr != INADDR_ANY) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -6006,26 +6122,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (stcb != NULL) {
/************************TCB SPECIFIC SET ******************/
- /*
- * do we change the timer for HB, we run
- * only one?
- */
- int ovh = 0;
-
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MED_OVERHEAD;
- } else {
- ovh = SCTP_MED_V4_OVERHEAD;
- }
-
- /* network sets ? */
if (net != NULL) {
/************************NET SPECIFIC SET ******************/
if (paddrp->spp_flags & SPP_HB_DISABLE) {
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
!(net->dest_state & SCTP_ADDR_NOHB)) {
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
}
net->dest_state |= SCTP_ADDR_NOHB;
}
@@ -6036,23 +6139,43 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
net->heart_beat_delay = 0;
}
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
net->dest_state &= ~SCTP_ADDR_NOHB;
}
if (paddrp->spp_flags & SPP_HB_DEMAND) {
- /* on demand HB */
- sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
+ sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
+ sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
+ }
}
if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
}
net->dest_state |= SCTP_ADDR_NO_PMTUD;
- net->mtu = paddrp->spp_pathmtu + ovh;
+ net->mtu = paddrp->spp_pathmtu;
+ 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 (net->mtu < stcb->asoc.smallest_mtu) {
sctp_pathmtu_adjustment(stcb, net->mtu);
}
@@ -6073,7 +6196,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
(net->error_count > net->pf_threshold)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
@@ -6116,7 +6241,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
(net->error_count > net->pf_threshold)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
@@ -6152,7 +6279,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
net->dest_state &= ~SCTP_ADDR_NOHB;
}
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
}
sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
@@ -6162,7 +6289,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (!(net->dest_state & SCTP_ADDR_NOHB)) {
net->dest_state |= SCTP_ADDR_NOHB;
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ inp, stcb, net,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15);
}
}
}
@@ -6172,14 +6301,34 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16);
}
net->dest_state |= SCTP_ADDR_NO_PMTUD;
- net->mtu = paddrp->spp_pathmtu + ovh;
+ net->mtu = paddrp->spp_pathmtu;
+ 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 (net->mtu < stcb->asoc.smallest_mtu) {
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) {
@@ -6189,6 +6338,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
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) {
@@ -6217,7 +6367,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
/************************NO TCB, SET TO default stuff ******************/
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
/*
* For the TOS/FLOWLABEL stuff you set it
@@ -6232,22 +6383,24 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
else if (paddrp->spp_hbinterval != 0) {
if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
paddrp->spp_hbinterval= SCTP_MAX_HB_INTERVAL;
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(paddrp->spp_hbinterval);
}
if (paddrp->spp_flags & SPP_HB_ENABLE) {
if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
} else if (paddrp->spp_hbinterval) {
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(paddrp->spp_hbinterval);
}
sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
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) {
+ inp->sctp_ep.default_mtu = paddrp->spp_pathmtu;
sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
}
if (paddrp->spp_flags & SPP_DSCP) {
@@ -6303,7 +6456,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (srto->srto_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
if (srto->srto_initial)
new_init = srto->srto_initial;
@@ -6339,30 +6493,34 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
- if (sasoc->sasoc_cookie_life) {
+ if (sasoc->sasoc_cookie_life > 0) {
/* boundary check the cookie life */
- if (sasoc->sasoc_cookie_life < 1000)
- sasoc->sasoc_cookie_life = 1000;
+ if (sasoc->sasoc_cookie_life < SCTP_MIN_COOKIE_LIFE) {
+ sasoc->sasoc_cookie_life = SCTP_MIN_COOKIE_LIFE;
+ }
if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
}
}
if (stcb) {
- if (sasoc->sasoc_asocmaxrxt)
+ if (sasoc->sasoc_asocmaxrxt > 0) {
stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
- if (sasoc->sasoc_cookie_life) {
- stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
+ }
+ if (sasoc->sasoc_cookie_life > 0) {
+ stcb->asoc.cookie_life = sctp_msecs_to_ticks(sasoc->sasoc_cookie_life);
}
SCTP_TCB_UNLOCK(stcb);
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
- if (sasoc->sasoc_asocmaxrxt)
+ if (sasoc->sasoc_asocmaxrxt > 0) {
inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
- if (sasoc->sasoc_cookie_life) {
- inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
+ }
+ if (sasoc->sasoc_cookie_life > 0) {
+ inp->sctp_ep.def_cookie_life = sctp_msecs_to_ticks(sasoc->sasoc_cookie_life);
}
SCTP_INP_WUNLOCK(inp);
} else {
@@ -6438,16 +6596,23 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
if ((stcb != NULL) && (net != NULL)) {
- if ((net != stcb->asoc.primary_destination) &&
- (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
- /* Ok we need to set it */
- if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
- if ((stcb->asoc.alternate) &&
- (!(net->dest_state & SCTP_ADDR_PF)) &&
- (net->dest_state & SCTP_ADDR_REACHABLE)) {
- sctp_free_remote_addr(stcb->asoc.alternate);
- stcb->asoc.alternate = NULL;
+ if (net != stcb->asoc.primary_destination) {
+ if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
+ /* Ok we need to set it */
+ if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
+ if ((stcb->asoc.alternate) &&
+ (!(net->dest_state & SCTP_ADDR_PF)) &&
+ (net->dest_state & SCTP_ADDR_REACHABLE)) {
+ sctp_free_remote_addr(stcb->asoc.alternate);
+ stcb->asoc.alternate = NULL;
+ }
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
}
} else {
@@ -6465,19 +6630,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
#ifdef SCTP_MVRF
int i, fnd = 0;
#endif
-#if !defined(__Windows__) && !defined(__Userspace__)
+#if !defined(_WIN32) && !defined(__Userspace__)
#if defined(__APPLE__)
struct proc *proc;
#endif
-#ifdef __FreeBSD__
-#if __FreeBSD_version > 602000
+#if defined(__FreeBSD__)
error = priv_check(curthread,
PRIV_NETINET_RESERVEDPORT);
-#elif __FreeBSD_version >= 500000
- error = suser((struct thread *)p);
-#else
- error = suser(p);
-#endif
#elif defined(__APPLE__)
proc = (struct proc *)p;
if (p) {
@@ -6488,9 +6647,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
#else
error = suser(p, 0);
#endif
-#endif
if (error)
break;
+#endif
SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
/* SUPER USER CHECK? */
@@ -6554,7 +6713,11 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
+ continue;
+ }
+ if ((sctp_is_addr_restricted(stcb, laddr->ifa)) &&
+ (!sctp_is_addr_pending(stcb, laddr->ifa))) {
continue;
}
if (laddr->ifa == ifa) {
@@ -6567,7 +6730,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
goto out_of_it;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
} else {
switch (addr->sa_family) {
#ifdef INET
@@ -6611,6 +6774,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
out_of_it:
SCTP_TCB_UNLOCK(stcb);
} else {
@@ -6621,23 +6785,23 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
case SCTP_BINDX_ADD_ADDR:
{
- struct sctp_getaddresses *addrs;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+ struct sockaddr *sa;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct thread *td;
td = (struct thread *)p;
#endif
- SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
- optsize);
+ SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
#ifdef INET
- if (addrs->addr->sa_family == AF_INET) {
- if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
+ if (sa->sa_family == AF_INET) {
+ if (optsize < sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (td != NULL &&
+ (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)sa)->sin_addr)))) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
@@ -6645,48 +6809,49 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else
#endif
#ifdef INET6
- if (addrs->addr->sa_family == AF_INET6) {
- if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
+ if (sa->sa_family == AF_INET6) {
+ if (optsize < sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
- (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (td != NULL &&
+ (error = prison_local_ip6(td->td_ucred,
+ &(((struct sockaddr_in6 *)sa)->sin6_addr),
+ (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
}
#endif
} else
#endif
{
- error = EAFNOSUPPORT;
- break;
+ error = EAFNOSUPPORT;
+ break;
}
- sctp_bindx_add_address(so, inp, addrs->addr,
- addrs->sget_assoc_id, vrf_id,
- &error, p);
+ sctp_bindx_add_address(so, inp, sa, vrf_id, &error, p);
break;
}
case SCTP_BINDX_REM_ADDR:
{
- struct sctp_getaddresses *addrs;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+ struct sockaddr *sa;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
struct thread *td;
td = (struct thread *)p;
#endif
- SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
+ SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
#ifdef INET
- if (addrs->addr->sa_family == AF_INET) {
- if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
+ if (sa->sa_family == AF_INET) {
+ if (optsize < sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (td != NULL &&
+ (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)sa)->sin_addr)))) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
@@ -6694,16 +6859,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else
#endif
#ifdef INET6
- if (addrs->addr->sa_family == AF_INET6) {
- if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
+ if (sa->sa_family == AF_INET6) {
+ if (optsize < sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (td != NULL &&
(error = prison_local_ip6(td->td_ucred,
- &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
+ &(((struct sockaddr_in6 *)sa)->sin6_addr),
(SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
@@ -6715,12 +6880,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EAFNOSUPPORT;
break;
}
- sctp_bindx_delete_address(inp, addrs->addr,
- addrs->sget_assoc_id, vrf_id,
- &error);
+ sctp_bindx_delete_address(inp, sa, vrf_id, &error);
break;
}
-#ifdef __APPLE__
+#if defined(__APPLE__) && !defined(__Userspace__)
case SCTP_LISTEN_FIX:
/* only applies to one-to-many sockets */
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
@@ -6732,7 +6895,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
}
break;
-#endif /* __APPLE__ */
+#endif
case SCTP_EVENT:
{
struct sctp_event *event;
@@ -6812,8 +6975,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
* so return an error for sender dry events
*/
if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
- ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
- ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
+ (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
((event->se_assoc_id == SCTP_ALL_ASSOC) ||
(event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
@@ -6822,8 +6984,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
- (event->se_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (event->se_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
if (event->se_on) {
sctp_feature_on(inp, event_type);
@@ -6832,8 +6995,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_INP_WUNLOCK(inp);
}
- if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
- (event->se_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (event->se_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -6847,6 +7011,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_INP_RUNLOCK(inp);
}
}
+ } else {
+ if (stcb) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
}
break;
}
@@ -6902,8 +7070,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
- (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (info->snd_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->def_send.sinfo_stream = info->snd_sid;
policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
@@ -6913,8 +7082,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
inp->def_send.sinfo_context = info->snd_context;
SCTP_INP_WUNLOCK(inp);
}
- if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
- (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (info->snd_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -6941,6 +7111,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
if (info->pr_policy > SCTP_PR_SCTP_MAX) {
+ if (stcb) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
@@ -6953,16 +7126,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
- (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (info->pr_assoc_id == SCTP_ALL_ASSOC)))) {
SCTP_INP_WLOCK(inp);
inp->def_send.sinfo_flags &= 0xfff0;
inp->def_send.sinfo_flags |= info->pr_policy;
inp->def_send.sinfo_timetolive = info->pr_value;
SCTP_INP_WUNLOCK(inp);
}
- if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
- (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (info->pr_assoc_id == SCTP_ALL_ASSOC))) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
@@ -7024,8 +7199,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if ((stcb != NULL) && (net == NULL)) {
#ifdef INET
if (addr->sa_family == AF_INET) {
-
struct sockaddr_in *sin;
+
sin = (struct sockaddr_in *)addr;
if (sin->sin_addr.s_addr != INADDR_ANY) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -7068,6 +7243,14 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
break;
}
}
+ if (thlds->spt_pathcpthld != 0xffff) {
+ if (stcb != NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
if (stcb != NULL) {
if (net != NULL) {
net->failure_threshold = thlds->spt_pathmaxrxt;
@@ -7082,7 +7265,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
(net->error_count <= net->failure_threshold)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
@@ -7111,7 +7296,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
(net->error_count <= net->failure_threshold)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
+ stcb->sctp_ep, stcb, net,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
@@ -7134,7 +7321,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
@@ -7192,8 +7380,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if ((stcb != NULL) && (net == NULL)) {
#ifdef INET
if (addr->sa_family == AF_INET) {
-
struct sockaddr_in *sin;
+
sin = (struct sockaddr_in *)addr;
if (sin->sin_addr.s_addr != INADDR_ANY) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -7247,7 +7435,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.port = encaps->sue_port;
SCTP_INP_WUNLOCK(inp);
@@ -7272,7 +7461,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
if (av->assoc_value == 0) {
inp->ecn_supported = 0;
@@ -7301,7 +7491,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
if (av->assoc_value == 0) {
inp->prsctp_supported = 0;
@@ -7330,7 +7521,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
if ((av->assoc_value == 0) &&
(inp->asconf_supported == 1)) {
/* AUTH is required for ASCONF */
@@ -7366,7 +7558,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
if ((av->assoc_value != 0) &&
(inp->auth_supported == 0)) {
/* AUTH is required for ASCONF */
@@ -7410,7 +7603,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
if (av->assoc_value == 0) {
inp->reconfig_supported = 0;
@@ -7439,7 +7633,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
if (av->assoc_value == 0) {
inp->nrsack_supported = 0;
@@ -7468,7 +7663,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
if (av->assoc_value == 0) {
inp->pktdrop_supported = 0;
@@ -7508,7 +7704,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ (av->assoc_id == SCTP_FUTURE_ASSOC))) {
SCTP_INP_WLOCK(inp);
inp->max_cwnd = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
@@ -7527,15 +7724,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
return (error);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
int
sctp_ctloutput(struct socket *so, struct sockopt *sopt)
{
+#if defined(__FreeBSD__)
+ struct epoch_tracker et;
+ struct sctp_inpcb *inp;
+#endif
void *optval = NULL;
- size_t optsize = 0;
void *p;
+ size_t optsize = 0;
int error = 0;
+#if defined(__FreeBSD__)
+ if ((sopt->sopt_level == SOL_SOCKET) &&
+ (sopt->sopt_name == SO_SETFIB)) {
+ inp = (struct sctp_inpcb *)so->so_pcb;
+ if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
+ return (EINVAL);
+ }
+ SCTP_INP_WLOCK(inp);
+ inp->fibnum = so->so_fibnum;
+ SCTP_INP_WUNLOCK(inp);
+ return (0);
+ }
+#endif
if (sopt->sopt_level != IPPROTO_SCTP) {
/* wrong proto level... send back up to IP */
#ifdef INET6
@@ -7551,6 +7766,10 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
return (error);
}
optsize = sopt->sopt_valsize;
+ if (optsize > SCTP_SOCKET_OPTION_LIMIT) {
+ SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
+ return (ENOBUFS);
+ }
if (optsize) {
SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
if (optval == NULL) {
@@ -7563,13 +7782,19 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
goto out;
}
}
-#if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__Windows__)
+#if defined(__FreeBSD__) || defined(_WIN32)
p = (void *)sopt->sopt_td;
#else
p = (void *)sopt->sopt_p;
#endif
if (sopt->sopt_dir == SOPT_SET) {
+#if defined(__FreeBSD__)
+ NET_EPOCH_ENTER(et);
+#endif
error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
+#if defined(__FreeBSD__)
+ NET_EPOCH_EXIT(et);
+#endif
} else if (sopt->sopt_dir == SOPT_GET) {
error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
} else {
@@ -7588,21 +7813,20 @@ out:
#endif
#ifdef INET
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__Userspace__)
+int
+sctp_connect(struct socket *so, struct sockaddr *addr)
+{
+ void *p = NULL;
+#elif defined(__FreeBSD__)
static int
sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
{
-#else
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__APPLE__)
static int
sctp_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
{
-#elif defined(__Panda__) || defined(__Userspace__)
-int
-sctp_connect(struct socket *so, struct sockaddr *addr)
-{
- void *p = NULL;
-#elif defined(__Windows__)
+#elif defined(_WIN32)
static int
sctp_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p)
{
@@ -7613,6 +7837,8 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
struct sockaddr *addr = mtod(nam, struct sockaddr *);
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
#endif
#ifdef SCTP_MVRF
int i, fnd = 0;
@@ -7635,24 +7861,24 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
}
#if defined(__Userspace__)
- /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */
+ /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */
#endif
-#if !defined(__Windows__) && !defined(__Userspace_os_Linux) && !defined(__Userspace_os_Windows)
+#if !defined(_WIN32) && !defined(__linux__) && !defined(__EMSCRIPTEN__)
switch (addr->sa_family) {
#ifdef INET6
case AF_INET6:
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- struct sockaddr_in6 *sin6p;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct sockaddr_in6 *sin6;
#endif
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- sin6p = (struct sockaddr_in6 *)addr;
- if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ sin6 = (struct sockaddr_in6 *)addr;
+ if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6->sin6_addr)) != 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
return (error);
}
@@ -7663,19 +7889,19 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
#ifdef INET
case AF_INET:
{
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- struct sockaddr_in *sinp;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct sockaddr_in *sin;
#endif
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
if (addr->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
- sinp = (struct sockaddr_in *)addr;
- if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ sin = (struct sockaddr_in *)addr;
+ if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sin->sin_addr)) != 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
return (error);
}
@@ -7691,13 +7917,15 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
SCTP_INP_INCR_REF(inp);
SCTP_ASOC_CREATE_LOCK(inp);
create_lock_on = 1;
-
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(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
@@ -7777,7 +8005,10 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
}
#endif
/* We are GOOD to go */
- stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
+ stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
+ inp->sctp_ep.pre_open_stream_count,
+ inp->sctp_ep.port, p,
+ SCTP_INITIALIZE_AUTH_PARAMS);
if (stcb == NULL) {
/* Gak! no memory */
goto out_now;
@@ -7787,19 +8018,18 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
/* Set the connected flag so we can queue data */
soisconnecting(so);
}
- SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- /* initialize authentication parameters for the assoc */
- sctp_initialize_auth_params(inp, stcb);
-
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
out_now:
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
if (create_lock_on) {
SCTP_ASOC_CREATE_UNLOCK(inp);
}
-
SCTP_INP_DECR_REF(inp);
return (error);
}
@@ -7942,7 +8172,10 @@ sctpconn_connect(struct socket *so, struct sockaddr *addr)
}
#endif
/* We are GOOD to go */
- stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
+ stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
+ inp->sctp_ep.pre_open_stream_count,
+ inp->sctp_ep.port, p,
+ SCTP_INITIALIZE_AUTH_PARAMS);
if (stcb == NULL) {
/* Gak! no memory */
goto out_now;
@@ -7952,12 +8185,9 @@ sctpconn_connect(struct socket *so, struct sockaddr *addr)
/* Set the connected flag so we can queue data */
soisconnecting(so);
}
- SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- /* initialize authentication parameters for the assoc */
- sctp_initialize_auth_params(inp, stcb);
-
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
out_now:
@@ -7970,16 +8200,12 @@ sctpconn_connect(struct socket *so, struct sockaddr *addr)
}
#endif
int
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
-#if __FreeBSD_version >= 700000
+#if defined(__Userspace__)
+sctp_listen(struct socket *so, int backlog, struct proc *p)
+#elif defined(__FreeBSD__)
sctp_listen(struct socket *so, int backlog, struct thread *p)
-#else
-sctp_listen(struct socket *so, struct thread *p)
-#endif
-#elif defined(__Windows__)
+#elif defined(_WIN32)
sctp_listen(struct socket *so, int backlog, PKTHREAD p)
-#elif defined(__Userspace__)
-sctp_listen(struct socket *so, int backlog, struct proc *p)
#else
sctp_listen(struct socket *so, struct proc *p)
#endif
@@ -8036,7 +8262,7 @@ sctp_listen(struct socket *so, struct proc *p)
if (tinp && (tinp != inp) &&
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (tinp->sctp_socket->so_qlimit)) {
+ (SCTP_IS_LISTENING(tinp))) {
/* we have a listener already and its not this inp. */
SCTP_INP_DECR_REF(tinp);
return (EADDRINUSE);
@@ -8099,12 +8325,12 @@ sctp_listen(struct socket *so, struct proc *p)
if (tinp && (tinp != inp) &&
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (tinp->sctp_socket->so_qlimit)) {
+ (SCTP_IS_LISTENING(tinp))) {
/* we have a listener already and its not this inp. */
SCTP_INP_DECR_REF(tinp);
return (EADDRINUSE);
} else if (tinp) {
- SCTP_INP_DECR_REF(inp);
+ SCTP_INP_DECR_REF(tinp);
}
}
}
@@ -8114,8 +8340,8 @@ sctp_listen(struct socket *so, struct proc *p)
sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
}
#endif
+#if defined(__FreeBSD__) || defined(__Userspace__)
SOCK_LOCK(so);
-#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Userspace__)
error = solisten_proto_check(so);
SOCK_UNLOCK(so);
if (error) {
@@ -8153,17 +8379,18 @@ sctp_listen(struct socket *so, struct proc *p)
return (error);
}
}
- SOCK_LOCK(so);
-#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__) || defined(__Userspace__)
-#if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__)
- /* It appears for 7.0 and on, we must always call this. */
- solisten_proto(so, backlog);
-#else
+ SCTP_INP_WLOCK(inp);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) {
- solisten_proto(so);
+ SOCK_LOCK(so);
+ solisten_proto(so, backlog);
+ SOCK_UNLOCK(so);
}
+#elif defined(_WIN32) || defined(__Userspace__)
+ SOCK_LOCK(so);
+ solisten_proto(so, backlog);
#endif
-#endif
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
/* remove the ACCEPTCONN flag for one-to-many sockets */
#if defined(__Userspace__)
@@ -8172,43 +8399,33 @@ sctp_listen(struct socket *so, struct proc *p)
so->so_options &= ~SO_ACCEPTCONN;
#endif
}
-
-#if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__)
- if (backlog == 0) {
- /* turning off listen */
-#if defined(__Userspace__)
- so->so_options &= ~SCTP_SO_ACCEPTCONN;
-#else
- so->so_options &= ~SO_ACCEPTCONN;
+ SOCK_UNLOCK(so);
#endif
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
+ if (backlog > 0) {
+ inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
+ } else {
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING;
}
+#else
+ inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
#endif
- SOCK_UNLOCK(so);
+ SCTP_INP_WUNLOCK(inp);
return (error);
}
static int sctp_defered_wakeup_cnt = 0;
int
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
sctp_accept(struct socket *so, struct sockaddr **addr)
{
-#elif defined(__Panda__)
-sctp_accept(struct socket *so, struct sockaddr *addr, int *namelen,
- void *accept_info, int *accept_info_len)
-{
-#else
-sctp_accept(struct socket *so, struct mbuf *nam)
-{
- struct sockaddr *addr = mtod(nam, struct sockaddr *);
-#endif
struct sctp_tcb *stcb;
struct sctp_inpcb *inp;
union sctp_sockstore store;
#ifdef INET6
-#ifdef SCTP_KAME
+#if defined(SCTP_KAME) && defined(SCTP_EMBEDDED_V6_SCOPE)
int error;
-#endif /* SCTP_KAME */
+#endif
#endif
inp = (struct sctp_inpcb *)so->so_pcb;
@@ -8216,53 +8433,92 @@ sctp_accept(struct socket *so, struct mbuf *nam)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
- SCTP_INP_RLOCK(inp);
+ SCTP_INP_WLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_WUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
return (EOPNOTSUPP);
}
if (so->so_state & SS_ISDISCONNECTED) {
- SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_WUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
return (ECONNABORTED);
}
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
- SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_WUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
store = stcb->asoc.primary_destination->ro._l_addr;
- stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
- SCTP_TCB_UNLOCK(stcb);
+ SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
+ /* Wake any delayed sleep action */
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
+ SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
+ if (sowriteable(inp->sctp_socket)) {
+#if defined(__Userspace__)
+ /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */
+#endif
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
+ sowwakeup_locked(inp->sctp_socket);
+#else
+#if defined(__APPLE__)
+ /* socket is locked */
+#endif
+ sowwakeup(inp->sctp_socket);
+#endif
+ } else {
+ SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
+ }
+ }
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
+ SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
+ if (soreadable(inp->sctp_socket)) {
+ sctp_defered_wakeup_cnt++;
+#if defined(__Userspace__)
+ /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */
+#endif
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
+ sorwakeup_locked(inp->sctp_socket);
+#else
+#if defined(__APPLE__)
+ /* socket is locked */
+#endif
+ sorwakeup(inp->sctp_socket);
+#endif
+ } else {
+ SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
+ }
+ }
+ }
+ SCTP_INP_WUNLOCK(inp);
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19);
+ } else {
+ SCTP_TCB_UNLOCK(stcb);
+ }
switch (store.sa.sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
if (sin == NULL)
return (ENOMEM);
-#else
- sin = (struct sockaddr_in *)addr;
- bzero((caddr_t)sin, sizeof(*sin));
-#endif
sin->sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin->sin_len = sizeof(*sin);
#endif
sin->sin_port = store.sin.sin_port;
sin->sin_addr = store.sin.sin_addr;
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
*addr = (struct sockaddr *)sin;
-#elif !defined(__Panda__)
- SCTP_BUF_LEN(nam) = sizeof(*sin);
-#endif
break;
}
#endif
@@ -8271,14 +8527,9 @@ sctp_accept(struct socket *so, struct mbuf *nam)
{
struct sockaddr_in6 *sin6;
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
if (sin6 == NULL)
return (ENOMEM);
-#else
- sin6 = (struct sockaddr_in6 *)addr;
- bzero((caddr_t)sin6, sizeof(*sin6));
-#endif
sin6->sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
sin6->sin6_len = sizeof(*sin6);
@@ -8302,11 +8553,7 @@ sctp_accept(struct socket *so, struct mbuf *nam)
sin6->sin6_scope_id = 0; /* XXX */
#endif /* SCTP_KAME */
#endif /* SCTP_EMBEDDED_V6_SCOPE */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
*addr = (struct sockaddr *)sin6;
-#elif !defined(__Panda__)
- SCTP_BUF_LEN(nam) = sizeof(*sin6);
-#endif
break;
}
#endif
@@ -8333,72 +8580,15 @@ sctp_accept(struct socket *so, struct mbuf *nam)
/* TSNH */
break;
}
- /* Wake any delayed sleep action */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
- SCTP_INP_WUNLOCK(inp);
- SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
- if (sowriteable(inp->sctp_socket)) {
-#if defined(__Userspace__)
- /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */
-#endif
-#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
- sowwakeup_locked(inp->sctp_socket);
-#else
-#if defined(__APPLE__)
- /* socket is locked */
-#endif
- sowwakeup(inp->sctp_socket);
-#endif
- } else {
- SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
- }
- SCTP_INP_WLOCK(inp);
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
- SCTP_INP_WUNLOCK(inp);
- SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
- if (soreadable(inp->sctp_socket)) {
- sctp_defered_wakeup_cnt++;
-#if defined(__Userspace__)
- /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */
-#endif
-#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
- sorwakeup_locked(inp->sctp_socket);
-#else
-#if defined(__APPLE__)
- /* socket is locked */
-#endif
- sorwakeup(inp->sctp_socket);
-#endif
- } else {
- SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
- }
- SCTP_INP_WLOCK(inp);
- }
- SCTP_INP_WUNLOCK(inp);
- }
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- SCTP_TCB_LOCK(stcb);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_7);
- }
return (0);
}
#ifdef INET
int
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
{
struct sockaddr_in *sin;
-#elif defined(__Panda__)
-sctp_ingetaddr(struct socket *so, struct sockaddr *addr)
-{
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
#else
sctp_ingetaddr(struct socket *so, struct mbuf *nam)
{
@@ -8411,12 +8601,10 @@ sctp_ingetaddr(struct socket *so, struct mbuf *nam)
/*
* Do the malloc first in case it blocks.
*/
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
if (sin == NULL)
return (ENOMEM);
-#elif defined(__Panda__)
- bzero(sin, sizeof(*sin));
#else
SCTP_BUF_LEN(nam) = sizeof(*sin);
memset(sin, 0, sizeof(*sin));
@@ -8427,7 +8615,7 @@ sctp_ingetaddr(struct socket *so, struct mbuf *nam)
#endif
inp = (struct sctp_inpcb *)so->so_pcb;
if (!inp) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -8498,7 +8686,7 @@ sctp_ingetaddr(struct socket *so, struct mbuf *nam)
}
}
if (!fnd) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin);
#endif
SCTP_INP_RUNLOCK(inp);
@@ -8507,21 +8695,17 @@ sctp_ingetaddr(struct socket *so, struct mbuf *nam)
}
}
SCTP_INP_RUNLOCK(inp);
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
(*addr) = (struct sockaddr *)sin;
#endif
return (0);
}
int
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
sctp_peeraddr(struct socket *so, struct sockaddr **addr)
{
struct sockaddr_in *sin;
-#elif defined(__Panda__)
-sctp_peeraddr(struct socket *so, struct sockaddr *addr)
-{
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
#else
sctp_peeraddr(struct socket *so, struct mbuf *nam)
{
@@ -8535,12 +8719,10 @@ sctp_peeraddr(struct socket *so, struct mbuf *nam)
struct sctp_nets *net;
/* Do the malloc first in case it blocks. */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
if (sin == NULL)
return (ENOMEM);
-#elif defined(__Panda__)
- memset(sin, 0, sizeof(*sin));
#else
SCTP_BUF_LEN(nam) = sizeof(*sin);
memset(sin, 0, sizeof(*sin));
@@ -8554,7 +8736,7 @@ sctp_peeraddr(struct socket *so, struct mbuf *nam)
if ((inp == NULL) ||
((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
/* UDP type and listeners will drop out here */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
@@ -8567,7 +8749,7 @@ sctp_peeraddr(struct socket *so, struct mbuf *nam)
}
SCTP_INP_RUNLOCK(inp);
if (stcb == NULL) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -8586,19 +8768,19 @@ sctp_peeraddr(struct socket *so, struct mbuf *nam)
SCTP_TCB_UNLOCK(stcb);
if (!fnd) {
/* No IPv4 address */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
return (ENOENT);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
(*addr) = (struct sockaddr *)sin;
#endif
return (0);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
struct pr_usrreqs sctp_usrreqs = {
#if defined(__FreeBSD__)
.pru_abort = sctp_abort,
@@ -8607,15 +8789,10 @@ struct pr_usrreqs sctp_usrreqs = {
.pru_bind = sctp_bind,
.pru_connect = sctp_connect,
.pru_control = in_control,
-#if __FreeBSD_version >= 690000
.pru_close = sctp_close,
.pru_detach = sctp_close,
.pru_sopoll = sopoll_generic,
.pru_flush = sctp_flush,
-#else
- .pru_detach = sctp_detach,
- .pru_sopoll = sopoll,
-#endif
.pru_disconnect = sctp_disconnect,
.pru_listen = sctp_listen,
.pru_peeraddr = sctp_peeraddr,
@@ -8645,7 +8822,7 @@ struct pr_usrreqs sctp_usrreqs = {
.pru_sosend = sctp_sosend,
.pru_soreceive = sctp_soreceive,
.pru_sopoll = sopoll
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
sctp_abort,
sctp_accept,
sctp_attach,
@@ -8671,7 +8848,7 @@ struct pr_usrreqs sctp_usrreqs = {
sctp_close
#endif
};
-#elif !defined(__Panda__) && !defined(__Userspace__)
+#elif !defined(__Userspace__)
int
sctp_usrreq(so, req, m, nam, control)
struct socket *so;
@@ -8679,8 +8856,6 @@ sctp_usrreq(so, req, m, nam, control)
struct mbuf *m, *nam, *control;
{
struct proc *p = curproc;
- uint32_t vrf_id;
- struct sctp_vrf *vrf;
int error;
int family;
struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb;
@@ -8816,7 +8991,7 @@ register_recv_cb(struct socket *so,
}
int
-register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free))
+register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info))
{
struct sctp_inpcb *inp;
@@ -8850,4 +9025,23 @@ register_ulp_info (struct socket *so, void *ulp_info)
SCTP_INP_WUNLOCK(inp);
return (1);
}
+
+int
+retrieve_ulp_info (struct socket *so, void **pulp_info)
+{
+ struct sctp_inpcb *inp;
+
+ if (pulp_info == NULL) {
+ return (0);
+ }
+
+ inp = (struct sctp_inpcb *) so->so_pcb;
+ if (inp == NULL) {
+ return (0);
+ }
+ SCTP_INP_RLOCK(inp);
+ *pulp_info = inp->ulp_info;
+ SCTP_INP_RUNLOCK(inp);
+ return (1);
+}
#endif
diff --git a/netwerk/sctp/src/netinet/sctp_var.h b/netwerk/sctp/src/netinet/sctp_var.h
index fcc954ebdc..3cdfdfe76b 100755
--- a/netwerk/sctp/src/netinet/sctp_var.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 275427 2014-12-02 20:29:29Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_VAR_H_
@@ -42,11 +44,10 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 275427 2014-12-02 20:29:29Z tuex
#if defined(_KERNEL) || defined(__Userspace__)
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
extern struct pr_usrreqs sctp_usrreqs;
#endif
-
#define sctp_feature_on(inp, feature) (inp->sctp_features |= feature)
#define sctp_feature_off(inp, feature) (inp->sctp_features &= ~feature)
#define sctp_is_feature_on(inp, feature) ((inp->sctp_features & feature) == feature)
@@ -90,7 +91,7 @@ extern struct pr_usrreqs sctp_usrreqs;
#define sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > (sb)->sb_cc) ? (sctp_maxspace(sb) - (sb)->sb_cc) : 0))
-#define sctp_sbspace_sub(a,b) ((a > b) ? (a - b) : 0)
+#define sctp_sbspace_sub(a,b) (((a) > (b)) ? ((a) - (b)) : 0)
/*
* I tried to cache the readq entries at one point. But the reality
@@ -101,11 +102,19 @@ extern struct pr_usrreqs sctp_usrreqs;
* an mbuf cache as well so it is not really worth doing, at least
* right now :-D
*/
-
+#ifdef INVARIANTS
#define sctp_free_a_readq(_stcb, _readq) { \
+ if ((_readq)->on_strm_q) \
+ panic("On strm q stcb:%p readq:%p", (_stcb), (_readq)); \
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \
SCTP_DECR_READQ_COUNT(); \
}
+#else
+#define sctp_free_a_readq(_stcb, _readq) { \
+ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \
+ SCTP_DECR_READQ_COUNT(); \
+}
+#endif
#define sctp_alloc_a_readq(_stcb, _readq) { \
(_readq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_readq), struct sctp_queued_to_read); \
@@ -176,17 +185,11 @@ extern struct pr_usrreqs sctp_usrreqs;
} \
}
-#if defined(__FreeBSD__) && __FreeBSD_version > 500000
-
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#define sctp_free_remote_addr(__net) { \
if ((__net)) { \
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \
- (void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \
- (void)SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \
- if ((__net)->ro.ro_rt) { \
- RTFREE((__net)->ro.ro_rt); \
- (__net)->ro.ro_rt = NULL; \
- } \
+ RO_NHFREE(&(__net)->ro); \
if ((__net)->src_addr_selected) { \
sctp_free_ifa((__net)->ro._s_addr); \
(__net)->ro._s_addr = NULL; \
@@ -215,22 +218,17 @@ extern struct pr_usrreqs sctp_usrreqs;
atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \
atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \
if (stcb) { \
- atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \
+ atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \
} \
if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
SCTP_BUF_TYPE(m) != MT_OOBDATA) \
atomic_add_int(&(sb)->sb_ctl,SCTP_BUF_LEN((m))); \
}
-
#else /* FreeBSD Version <= 500000 or non-FreeBSD */
-
#define sctp_free_remote_addr(__net) { \
if ((__net)) { \
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \
- (void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \
- (void)SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \
- (void)SCTP_OS_TIMER_STOP(&(__net)->hb_timer.timer); \
if ((__net)->ro.ro_rt) { \
RTFREE((__net)->ro.ro_rt); \
(__net)->ro.ro_rt = NULL; \
@@ -247,31 +245,6 @@ extern struct pr_usrreqs sctp_usrreqs;
} \
}
-#if defined(__Panda__)
-#define sctp_sbfree(ctl, stcb, sb, m) { \
- if ((sb)->sb_cc >= (uint32_t)SCTP_BUF_LEN((m))) { \
- atomic_subtract_int(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
- } else { \
- (sb)->sb_cc = 0; \
- } \
- if (((ctl)->do_not_ref_stcb == 0) && stcb) { \
- if ((stcb)->asoc.sb_cc >= (uint32_t)SCTP_BUF_LEN((m))) { \
- atomic_subtract_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
- } else { \
- (stcb)->asoc.sb_cc = 0; \
- } \
- } \
-}
-
-#define sctp_sballoc(stcb, sb, m) { \
- atomic_add_int(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
- if (stcb) { \
- atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
- } \
-}
-
-#else
-
#define sctp_sbfree(ctl, stcb, sb, m) { \
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \
@@ -290,7 +263,6 @@ extern struct pr_usrreqs sctp_usrreqs;
} \
}
#endif
-#endif
#define sctp_ucount_incr(val) { \
val++; \
@@ -331,7 +303,7 @@ extern struct pr_usrreqs sctp_usrreqs;
if (stcb->asoc.fs_index > SCTP_FS_SPEC_LOG_SIZE) \
stcb->asoc.fs_index = 0;\
stcb->asoc.fslog[stcb->asoc.fs_index].total_flight = stcb->asoc.total_flight; \
- stcb->asoc.fslog[stcb->asoc.fs_index].tsn = tp1->rec.data.TSN_seq; \
+ stcb->asoc.fslog[stcb->asoc.fs_index].tsn = tp1->rec.data.tsn; \
stcb->asoc.fslog[stcb->asoc.fs_index].book = tp1->book_size; \
stcb->asoc.fslog[stcb->asoc.fs_index].sent = tp1->sent; \
stcb->asoc.fslog[stcb->asoc.fs_index].incr = 0; \
@@ -352,7 +324,7 @@ extern struct pr_usrreqs sctp_usrreqs;
if (stcb->asoc.fs_index > SCTP_FS_SPEC_LOG_SIZE) \
stcb->asoc.fs_index = 0;\
stcb->asoc.fslog[stcb->asoc.fs_index].total_flight = stcb->asoc.total_flight; \
- stcb->asoc.fslog[stcb->asoc.fs_index].tsn = tp1->rec.data.TSN_seq; \
+ stcb->asoc.fslog[stcb->asoc.fs_index].tsn = tp1->rec.data.tsn; \
stcb->asoc.fslog[stcb->asoc.fs_index].book = tp1->book_size; \
stcb->asoc.fslog[stcb->asoc.fs_index].sent = tp1->sent; \
stcb->asoc.fslog[stcb->asoc.fs_index].incr = 1; \
@@ -391,39 +363,30 @@ struct sctp_inpcb;
struct sctp_tcb;
struct sctphdr;
-
-#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__)
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
void sctp_close(struct socket *so);
#else
int sctp_detach(struct socket *so);
#endif
int sctp_disconnect(struct socket *so);
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
-#if defined(__FreeBSD__) && __FreeBSD_version < 902000
-void sctp_ctlinput __P((int, struct sockaddr *, void *));
-int sctp_ctloutput __P((struct socket *, struct sockopt *));
-#ifdef INET
-void sctp_input_with_port __P((struct mbuf *, int, uint16_t));
-void sctp_input __P((struct mbuf *, int));
-#endif
-void sctp_pathmtu_adjustment __P((struct sctp_tcb *, uint16_t));
+#if !defined(__Userspace__)
+#if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN)
+void sctp_ctlinput(int, struct sockaddr *, void *, struct ifnet * SCTP_UNUSED);
#else
void sctp_ctlinput(int, struct sockaddr *, void *);
+#endif
int sctp_ctloutput(struct socket *, struct sockopt *);
#ifdef INET
void sctp_input_with_port(struct mbuf *, int, uint16_t);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int sctp_input(struct mbuf **, int *, int);
#else
void sctp_input(struct mbuf *, int);
#endif
#endif
void sctp_pathmtu_adjustment(struct sctp_tcb *, uint16_t);
-#endif
#else
-#if defined(__Panda__)
-void sctp_input(pakhandle_type i_pak);
-#elif defined(__Userspace__)
+#if defined(__Userspace__)
void sctp_pathmtu_adjustment(struct sctp_tcb *, uint16_t);
#else
void sctp_input(struct mbuf *,...);
@@ -431,75 +394,49 @@ void sctp_input(struct mbuf *,...);
void *sctp_ctlinput(int, struct sockaddr *, void *);
int sctp_ctloutput(int, struct socket *, int, int, struct mbuf **);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 902000
-void sctp_drain __P((void));
-#else
void sctp_drain(void);
-#endif
#if defined(__Userspace__)
void sctp_init(uint16_t,
int (*)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
- void (*)(const char *, ...));
-#elif defined(__FreeBSD__) && __FreeBSD_version < 902000
-void sctp_init __P((void));
+ void (*)(const char *, ...), int start_threads);
#elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
void sctp_init(struct protosw *pp, struct domain *dp);
#else
void sctp_init(void);
+void sctp_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *,
+ uint8_t, uint8_t, uint16_t, uint32_t);
#endif
+#if !defined(__FreeBSD__) && !defined(__Userspace__)
void sctp_finish(void);
-#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
+#endif
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
int sctp_flush(struct socket *, int);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 902000
-int sctp_shutdown __P((struct socket *));
-void sctp_notify __P((struct sctp_inpcb *, struct ip *ip, struct sctphdr *,
- struct sockaddr *, struct sctp_tcb *,
- struct sctp_nets *));
-#else
int sctp_shutdown(struct socket *);
-void sctp_notify(struct sctp_inpcb *, struct ip *ip, struct sctphdr *,
- struct sockaddr *, struct sctp_tcb *,
- struct sctp_nets *);
-#endif
int sctp_bindx(struct socket *, int, struct sockaddr_storage *,
int, int, struct proc *);
/* can't use sctp_assoc_t here */
int sctp_peeloff(struct socket *, struct socket *, int, caddr_t, int *);
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
int sctp_ingetaddr(struct socket *, struct sockaddr **);
-#elif defined(__Panda__)
-int sctp_ingetaddr(struct socket *, struct sockaddr *);
#else
int sctp_ingetaddr(struct socket *, struct mbuf *);
#endif
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
int sctp_peeraddr(struct socket *, struct sockaddr **);
-#elif defined(__Panda__)
-int sctp_peeraddr(struct socket *, struct sockaddr *);
#else
int sctp_peeraddr(struct socket *, struct mbuf *);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
-#if __FreeBSD_version >= 700000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int sctp_listen(struct socket *, int, struct thread *);
-#else
-int sctp_listen(struct socket *, struct thread *);
-#endif
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
int sctp_listen(struct socket *, int, PKTHREAD);
#elif defined(__Userspace__)
int sctp_listen(struct socket *, int, struct proc *);
#else
int sctp_listen(struct socket *, struct proc *);
#endif
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
int sctp_accept(struct socket *, struct sockaddr **);
-#elif defined(__Panda__)
-int sctp_accept(struct socket *, struct sockaddr *, int *, void *, int *);
-#else
-int sctp_accept(struct socket *, struct mbuf *);
-#endif
#endif /* _KERNEL */
diff --git a/netwerk/sctp/src/netinet/sctputil.c b/netwerk/sctp/src/netinet/sctputil.c
index b72a20de37..41910ec49d 100755
--- a/netwerk/sctp/src/netinet/sctputil.c
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 280439 2015-03-24 14:51:46Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 366482 2020-10-06 11:08:52Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -49,24 +51,27 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 280439 2015-03-24 14:51:46Z tuex
#include <netinet/sctp_output.h>
#include <netinet/sctp_uio.h>
#include <netinet/sctp_timer.h>
-#include <netinet/sctp_indata.h>/* for sctp_deliver_data() */
+#include <netinet/sctp_indata.h>
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
#if defined(__Userspace__)
#include <netinet/sctp_constants.h>
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+#include <netinet/sctp_kdtrace.h>
+#if defined(INET6) || defined(INET)
+#include <netinet/tcp_var.h>
+#endif
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <sys/proc.h>
+#ifdef INET6
+#include <netinet/icmp6.h>
#endif
-
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 8
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
#if !defined(SCTP_LOCAL_TRACE_BUF)
#include "eventrace_netinet.h"
#include "sctputil.tmh" /* this is the file that will be auto generated */
@@ -77,13 +82,13 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 280439 2015-03-24 14:51:46Z tuex
#endif
#endif
-extern struct sctp_cc_functions sctp_cc_functions[];
-extern struct sctp_ss_functions sctp_ss_functions[];
+extern const struct sctp_cc_functions sctp_cc_functions[];
+extern const struct sctp_ss_functions sctp_ss_functions[];
void
sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.sb.stcb = stcb;
@@ -106,7 +111,7 @@ sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
void
sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.close.inp = (void *)inp;
@@ -132,7 +137,7 @@ sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
void
rto_logging(struct sctp_nets *net, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
memset(&sctp_clog, 0, sizeof(sctp_clog));
@@ -151,7 +156,7 @@ rto_logging(struct sctp_nets *net, int from)
void
sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.strlog.stcb = stcb;
@@ -173,7 +178,7 @@ sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16
void
sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.nagle.stcb = (void *)stcb;
@@ -194,7 +199,7 @@ sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
void
sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.sack.cumack = cumack;
@@ -215,7 +220,7 @@ sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps,
void
sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
memset(&sctp_clog, 0, sizeof(sctp_clog));
@@ -235,7 +240,7 @@ sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
void
sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
memset(&sctp_clog, 0, sizeof(sctp_clog));
@@ -256,7 +261,7 @@ sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int fr
void
sctp_log_mb(struct mbuf *m, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.mb.mp = m;
@@ -265,7 +270,7 @@ sctp_log_mb(struct mbuf *m, int from)
sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0);
if (SCTP_BUF_IS_EXTENDED(m)) {
sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
/* APPLE does not use a ref_cnt, but a forward/backward ref queue */
#else
sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m));
@@ -298,7 +303,7 @@ sctp_log_mbc(struct mbuf *m, int from)
void
sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
if (control == NULL) {
@@ -307,11 +312,11 @@ sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_rea
}
sctp_clog.x.strlog.stcb = control->stcb;
sctp_clog.x.strlog.n_tsn = control->sinfo_tsn;
- sctp_clog.x.strlog.n_sseq = control->sinfo_ssn;
+ sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid;
sctp_clog.x.strlog.strm = control->sinfo_stream;
if (poschk != NULL) {
sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn;
- sctp_clog.x.strlog.e_sseq = poschk->sinfo_ssn;
+ sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid;
} else {
sctp_clog.x.strlog.e_tsn = 0;
sctp_clog.x.strlog.e_sseq = 0;
@@ -329,7 +334,7 @@ sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_rea
void
sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.cwnd.net = net;
@@ -363,11 +368,11 @@ sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t
#endif
}
-#ifndef __APPLE__
+#if !defined(__APPLE__) && !defined(__Userspace__)
void
sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
memset(&sctp_clog, 0, sizeof(sctp_clog));
@@ -378,7 +383,7 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
sctp_clog.x.lock.sock = (void *) NULL;
}
sctp_clog.x.lock.inp = (void *) inp;
-#if (defined(__FreeBSD__) && __FreeBSD_version >= 503000) || (defined(__APPLE__))
+#if defined(__FreeBSD__)
if (stcb) {
sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx);
} else {
@@ -391,11 +396,7 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN;
sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN;
}
-#if (defined(__FreeBSD__) && __FreeBSD_version <= 602000)
- sctp_clog.x.lock.info_lock = mtx_owned(&SCTP_BASE_INFO(ipi_ep_mtx));
-#else
sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx));
-#endif
if (inp && (inp->sctp_socket)) {
sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
@@ -420,7 +421,7 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
void
sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
memset(&sctp_clog, 0, sizeof(sctp_clog));
@@ -449,7 +450,7 @@ sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int b
void
sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.rwnd.rwnd = peers_rwnd;
@@ -469,7 +470,7 @@ sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t ove
void
sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.rwnd.rwnd = peers_rwnd;
@@ -490,7 +491,7 @@ sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint3
static void
sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.mbcnt.total_queue_size = total_oq;
@@ -511,7 +512,7 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb
void
sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_MISC_EVENT,
from,
@@ -522,7 +523,7 @@ sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
void
sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.wake.stcb = (void *)stcb;
@@ -568,9 +569,9 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
}
void
-sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen)
+sctp_log_block(uint8_t from, struct sctp_association *asoc, ssize_t sendlen)
{
-#if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF)
+#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_cwnd_log sctp_clog;
sctp_clog.x.blk.onsb = asoc->total_output_queue_size;
@@ -579,7 +580,7 @@ sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen)
sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt;
sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue;
sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight/1024);
- sctp_clog.x.blk.sndlen = sendlen;
+ sctp_clog.x.blk.sndlen = (uint32_t)sendlen;
SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_BLOCK,
from,
@@ -759,7 +760,6 @@ sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stcb->asoc.total_flight, tot_out);
/* now corrective action */
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
-
tot_out = 0;
TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
if ((chk->whoTo == lnet) &&
@@ -795,6 +795,80 @@ sctp_audit_log(uint8_t ev, uint8_t fd)
#endif
/*
+ * The conversion from time to ticks and vice versa is done by rounding
+ * upwards. This way we can test in the code the time to be positive and
+ * know that this corresponds to a positive number of ticks.
+ */
+
+uint32_t
+sctp_msecs_to_ticks(uint32_t msecs)
+{
+ uint64_t temp;
+ uint32_t ticks;
+
+ if (hz == 1000) {
+ ticks = msecs;
+ } else {
+ temp = (((uint64_t)msecs * hz) + 999) / 1000;
+ if (temp > UINT32_MAX) {
+ ticks = UINT32_MAX;
+ } else {
+ ticks = (uint32_t)temp;
+ }
+ }
+ return (ticks);
+}
+
+uint32_t
+sctp_ticks_to_msecs(uint32_t ticks)
+{
+ uint64_t temp;
+ uint32_t msecs;
+
+ if (hz == 1000) {
+ msecs = ticks;
+ } else {
+ temp = (((uint64_t)ticks * 1000) + (hz - 1)) / hz;
+ if (temp > UINT32_MAX) {
+ msecs = UINT32_MAX;
+ } else {
+ msecs = (uint32_t)temp;
+ }
+ }
+ return (msecs);
+}
+
+uint32_t
+sctp_secs_to_ticks(uint32_t secs)
+{
+ uint64_t temp;
+ uint32_t ticks;
+
+ temp = (uint64_t)secs * hz;
+ if (temp > UINT32_MAX) {
+ ticks = UINT32_MAX;
+ } else {
+ ticks = (uint32_t)temp;
+ }
+ return (ticks);
+}
+
+uint32_t
+sctp_ticks_to_secs(uint32_t ticks)
+{
+ uint64_t temp;
+ uint32_t secs;
+
+ temp = ((uint64_t)ticks + (hz - 1)) / hz;
+ if (temp > UINT32_MAX) {
+ secs = UINT32_MAX;
+ } else {
+ secs = (uint32_t)temp;
+ }
+ return (secs);
+}
+
+/*
* sctp_stop_timers_for_shutdown() should be called
* when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT
* state to make sure that all timers are stopped.
@@ -802,25 +876,72 @@ sctp_audit_log(uint8_t ev, uint8_t fd)
void
sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
{
- struct sctp_association *asoc;
+ struct sctp_inpcb *inp;
struct sctp_nets *net;
- asoc = &stcb->asoc;
+ inp = stcb->sctp_ep;
- (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
- (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_12);
+ sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_13);
+ sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_14);
+ sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_15);
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_16);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_17);
+ }
+}
+
+void
+sctp_stop_association_timers(struct sctp_tcb *stcb, bool stop_assoc_kill_timer)
+{
+ struct sctp_inpcb *inp;
+ struct sctp_nets *net;
+
+ inp = stcb->sctp_ep;
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_18);
+ sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_19);
+ if (stop_assoc_kill_timer) {
+ sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_20);
+ }
+ sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_21);
+ sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_22);
+ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNGUARD, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_23);
+ /* Mobility adaptation */
+ sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_24);
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_25);
+ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_26);
+ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_27);
+ sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_28);
+ sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_29);
+ sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_30);
+ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_31);
}
}
/*
- * a list of sizes based on typical mtu's, used only if next hop size not
- * returned.
+ * A list of sizes based on typical mtu's, used only if next hop size not
+ * returned. These values MUST be multiples of 4 and MUST be ordered.
*/
static uint32_t sctp_mtu_sizes[] = {
68,
@@ -829,29 +950,32 @@ static uint32_t sctp_mtu_sizes[] = {
512,
544,
576,
- 1006,
+ 1004,
1492,
1500,
1536,
- 2002,
+ 2000,
2048,
4352,
4464,
- 8166,
- 17914,
+ 8168,
+ 17912,
32000,
- 65535
+ 65532
};
/*
- * Return the largest MTU smaller than val. If there is no
- * entry, just return val.
+ * Return the largest MTU in sctp_mtu_sizes smaller than val.
+ * If val is smaller than the minimum, just return the largest
+ * multiple of 4 smaller or equal to val.
+ * Ensure that the result is a multiple of 4.
*/
uint32_t
sctp_get_prev_mtu(uint32_t val)
{
uint32_t i;
+ val &= 0xfffffffc;
if (val <= sctp_mtu_sizes[0]) {
return (val);
}
@@ -860,12 +984,16 @@ sctp_get_prev_mtu(uint32_t val)
break;
}
}
+ KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0,
+ ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1));
return (sctp_mtu_sizes[i - 1]);
}
/*
- * Return the smallest MTU larger than val. If there is no
- * entry, just return val.
+ * Return the smallest MTU in sctp_mtu_sizes larger than val.
+ * If val is larger than the maximum, just return the largest multiple of 4 smaller
+ * or equal to val.
+ * Ensure that the result is a multiple of 4.
*/
uint32_t
sctp_get_next_mtu(uint32_t val)
@@ -873,8 +1001,11 @@ sctp_get_next_mtu(uint32_t val)
/* select another MTU that is just bigger than this one */
uint32_t i;
+ val &= 0xfffffffc;
for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
if (val < sctp_mtu_sizes[i]) {
+ KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0,
+ ("sctp_mtu_sizes[%u] not a multiple of 4", i));
return (sctp_mtu_sizes[i]);
}
}
@@ -894,9 +1025,15 @@ sctp_fill_random_store(struct sctp_pcb *m)
* numbers, but thats ok too since that is random as well :->
*/
m->store_at = 0;
+#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+ for (int i = 0; i < (int) (sizeof(m->random_store) / sizeof(m->random_store[0])); i++) {
+ m->random_store[i] = (uint8_t) rand();
+ }
+#else
(void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers,
sizeof(m->random_numbers), (uint8_t *)&m->random_counter,
sizeof(m->random_counter), (uint8_t *)m->random_store);
+#endif
m->random_counter++;
}
@@ -960,9 +1097,52 @@ sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int ch
return (x);
}
+int32_t
+sctp_map_assoc_state(int kernel_state)
+{
+ int32_t user_state;
+
+ if (kernel_state & SCTP_STATE_WAS_ABORTED) {
+ user_state = SCTP_CLOSED;
+ } else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) {
+ user_state = SCTP_SHUTDOWN_PENDING;
+ } else {
+ switch (kernel_state & SCTP_STATE_MASK) {
+ case SCTP_STATE_EMPTY:
+ user_state = SCTP_CLOSED;
+ break;
+ case SCTP_STATE_INUSE:
+ user_state = SCTP_CLOSED;
+ break;
+ case SCTP_STATE_COOKIE_WAIT:
+ user_state = SCTP_COOKIE_WAIT;
+ break;
+ case SCTP_STATE_COOKIE_ECHOED:
+ user_state = SCTP_COOKIE_ECHOED;
+ break;
+ case SCTP_STATE_OPEN:
+ user_state = SCTP_ESTABLISHED;
+ break;
+ case SCTP_STATE_SHUTDOWN_SENT:
+ user_state = SCTP_SHUTDOWN_SENT;
+ break;
+ case SCTP_STATE_SHUTDOWN_RECEIVED:
+ user_state = SCTP_SHUTDOWN_RECEIVED;
+ break;
+ case SCTP_STATE_SHUTDOWN_ACK_SENT:
+ user_state = SCTP_SHUTDOWN_ACK_SENT;
+ break;
+ default:
+ user_state = SCTP_CLOSED;
+ break;
+ }
+ }
+ return (user_state);
+}
+
int
sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- uint32_t override_tag, uint32_t vrf_id)
+ uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms)
{
struct sctp_association *asoc;
/*
@@ -983,10 +1163,10 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc = &stcb->asoc;
/* init all variables to a known value. */
- SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE);
+ SCTP_SET_STATE(stcb, SCTP_STATE_INUSE);
asoc->max_burst = inp->sctp_ep.max_burst;
asoc->fr_max_burst = inp->sctp_ep.fr_max_burst;
- asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
+ asoc->heart_beat_delay = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
asoc->cookie_life = inp->sctp_ep.def_cookie_life;
asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
asoc->ecn_supported = inp->ecn_supported;
@@ -996,6 +1176,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->reconfig_supported = inp->reconfig_supported;
asoc->nrsack_supported = inp->nrsack_supported;
asoc->pktdrop_supported = inp->pktdrop_supported;
+ asoc->idata_supported = inp->idata_supported;
asoc->sctp_cmt_pf = (uint8_t)0;
asoc->sctp_frag_point = inp->sctp_frag_point;
asoc->sctp_features = inp->sctp_features;
@@ -1059,6 +1240,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
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;
@@ -1069,7 +1251,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->context = inp->sctp_context;
asoc->local_strreset_support = inp->local_strreset_support;
asoc->def_send = inp->def_send;
- asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
+ asoc->delayed_ack = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
asoc->sack_freq = inp->sctp_ep.sctp_sack_freq;
asoc->pr_sctp_cnt = 0;
asoc->total_output_queue_size = 0;
@@ -1106,7 +1288,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->minrto = inp->sctp_ep.sctp_minrto;
asoc->maxrto = inp->sctp_ep.sctp_maxrto;
- asoc->locked_on_sending = NULL;
asoc->stream_locked_on = 0;
asoc->ecn_echo_cnt_onq = 0;
asoc->stream_locked = 0;
@@ -1134,7 +1315,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* that we request by default.
*/
asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
- inp->sctp_ep.pre_open_stream_count;
+ o_strms;
SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
asoc->streamoutcnt * sizeof(struct sctp_stream_out),
SCTP_M_STRMO);
@@ -1152,7 +1333,8 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* that were dropped must be notified to the upper layer as
* failed to send.
*/
- asoc->strmout[i].next_sequence_send = 0x0;
+ asoc->strmout[i].next_mid_ordered = 0;
+ asoc->strmout[i].next_mid_unordered = 0;
TAILQ_INIT(&asoc->strmout[i].outqueue);
asoc->strmout[i].chunks_on_queues = 0;
#if defined(SCTP_DETAILED_STR_STATS)
@@ -1164,9 +1346,10 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->strmout[i].abandoned_sent[0] = 0;
asoc->strmout[i].abandoned_unsent[0] = 0;
#endif
- asoc->strmout[i].stream_no = i;
+ asoc->strmout[i].sid = i;
asoc->strmout[i].last_msg_incomplete = 0;
- asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
+ asoc->strmout[i].state = SCTP_STREAM_OPENING;
+ asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL);
}
asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
@@ -1196,7 +1379,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
TAILQ_INIT(&asoc->asconf_send_queue);
TAILQ_INIT(&asoc->send_queue);
TAILQ_INIT(&asoc->sent_queue);
- TAILQ_INIT(&asoc->reasmqueue);
TAILQ_INIT(&asoc->resetHead);
asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
TAILQ_INIT(&asoc->asconf_queue);
@@ -1297,15 +1479,20 @@ sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
return (0);
}
-
static void
sctp_iterator_work(struct sctp_iterator *it)
{
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
+ struct sctp_inpcb *tinp;
int iteration_count = 0;
int inp_skip = 0;
int first_in = 1;
- struct sctp_inpcb *tinp;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
SCTP_INP_INFO_RLOCK();
SCTP_ITERATOR_LOCK();
sctp_it_ctl.cur_it = it;
@@ -1323,6 +1510,9 @@ done_with_iterator:
(*it->function_atend) (it->pointer, it->val);
}
SCTP_FREE(it, SCTP_M_ITER);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
return;
}
select_a_new_ep:
@@ -1332,7 +1522,7 @@ select_a_new_ep:
SCTP_INP_RLOCK(it->inp);
}
while (((it->pcb_flags) &&
- ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
+ ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
((it->pcb_features) &&
((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
/* endpoint flags or features don't match, so keep looking */
@@ -1342,6 +1532,7 @@ select_a_new_ep:
}
tinp = it->inp;
it->inp = LIST_NEXT(it->inp, sctp_list);
+ it->stcb = NULL;
SCTP_INP_RUNLOCK(tinp);
if (it->inp == NULL) {
goto done_with_iterator;
@@ -1390,7 +1581,7 @@ select_a_new_ep:
/* We won't be staying here */
SCTP_INP_DECR_REF(it->inp);
atomic_add_int(&it->stcb->asoc.refcnt, -1);
-#if !defined(__FreeBSD__)
+#if !(defined(__FreeBSD__) && !defined(__Userspace__))
if (sctp_it_ctl.iterator_flags &
SCTP_ITERATOR_MUST_EXIT) {
goto done_with_iterator;
@@ -1417,6 +1608,9 @@ select_a_new_ep:
atomic_add_int(&it->stcb->asoc.refcnt, -1);
iteration_count = 0;
}
+ KASSERT(it->inp == it->stcb->sctp_ep,
+ ("%s: stcb %p does not belong to inp %p, but inp %p",
+ __func__, it->stcb, it->inp, it->stcb->sctp_ep));
/* run function on this one */
(*it->function_assoc)(it->inp, it->stcb, it->pointer, it->val);
@@ -1449,6 +1643,7 @@ select_a_new_ep:
} else {
it->inp = LIST_NEXT(it->inp, sctp_list);
}
+ it->stcb = NULL;
if (it->inp == NULL) {
goto done_with_iterator;
}
@@ -1458,35 +1653,33 @@ select_a_new_ep:
void
sctp_iterator_worker(void)
{
- struct sctp_iterator *it, *nit;
+ struct sctp_iterator *it;
/* This function is called with the WQ lock in place */
-
sctp_it_ctl.iterator_running = 1;
- TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
+ while ((it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead)) != NULL) {
/* now lets work on this one */
TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_SET(it->vn);
#endif
sctp_iterator_work(it);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_RESTORE();
#endif
SCTP_IPI_ITERATOR_WQ_LOCK();
-#if !defined(__FreeBSD__)
+#if !defined(__FreeBSD__) && !defined(__Userspace__)
if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) {
break;
}
#endif
- /*sa_ignore FREED_MEMORY*/
+ /*sa_ignore FREED_MEMORY*/
}
sctp_it_ctl.iterator_running = 0;
return;
}
-
static void
sctp_handle_addr_wq(void)
{
@@ -1507,48 +1700,101 @@ sctp_handle_addr_wq(void)
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);
} else {
- (void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
- sctp_asconf_iterator_stcb,
- NULL, /* No ep end for boundall */
- SCTP_PCB_FLAGS_BOUNDALL,
- SCTP_PCB_ANY_FEATURES,
- SCTP_ASOC_ANY_STATE,
- (void *)asc, 0,
- sctp_asconf_iterator_end, NULL, 0);
+ int ret;
+
+ ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
+ sctp_asconf_iterator_stcb,
+ NULL, /* No ep end for boundall */
+ SCTP_PCB_FLAGS_BOUNDALL,
+ SCTP_PCB_ANY_FEATURES,
+ SCTP_ASOC_ANY_STATE,
+ (void *)asc, 0,
+ sctp_asconf_iterator_end, NULL, 0);
+ if (ret) {
+ SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n");
+ /* Freeing if we are stopping or put back on the addr_wq. */
+ if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
+ sctp_asconf_iterator_end(asc, 0);
+ } else {
+ LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
+ LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
+ }
+ SCTP_FREE(asc, SCTP_M_ASC_IT);
+ }
+ }
}
}
+/*-
+ * The following table shows which pointers for the inp, stcb, or net are
+ * stored for each timer after it was started.
+ *
+ *|Name |Timer |inp |stcb|net |
+ *|-----------------------------|-----------------------------|----|----|----|
+ *|SCTP_TIMER_TYPE_SEND |net->rxt_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_INIT |net->rxt_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_RECV |stcb->asoc.dack_timer |Yes |Yes |No |
+ *|SCTP_TIMER_TYPE_SHUTDOWN |net->rxt_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_HEARTBEAT |net->hb_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_COOKIE |net->rxt_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_NEWCOOKIE |inp->sctp_ep.signature_change|Yes |No |No |
+ *|SCTP_TIMER_TYPE_PATHMTURAISE |net->pmtu_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_SHUTDOWNACK |net->rxt_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_ASCONF |stcb->asoc.asconf_timer |Yes |Yes |Yes |
+ *|SCTP_TIMER_TYPE_SHUTDOWNGUARD|stcb->asoc.shut_guard_timer |Yes |Yes |No |
+ *|SCTP_TIMER_TYPE_AUTOCLOSE |stcb->asoc.autoclose_timer |Yes |Yes |No |
+ *|SCTP_TIMER_TYPE_STRRESET |stcb->asoc.strreset_timer |Yes |Yes |No |
+ *|SCTP_TIMER_TYPE_INPKILL |inp->sctp_ep.signature_change|Yes |No |No |
+ *|SCTP_TIMER_TYPE_ASOCKILL |stcb->asoc.strreset_timer |Yes |Yes |No |
+ *|SCTP_TIMER_TYPE_ADDR_WQ |SCTP_BASE_INFO(addr_wq_timer)|No |No |No |
+ *|SCTP_TIMER_TYPE_PRIM_DELETED |stcb->asoc.delete_prim_timer |Yes |Yes |No |
+ */
+
void
sctp_timeout_handler(void *t)
{
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
+ struct timeval tv;
struct sctp_inpcb *inp;
struct sctp_tcb *stcb;
struct sctp_nets *net;
struct sctp_timer *tmr;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct mbuf *op_err;
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
- int did_output, type;
+#if defined(__Userspace__)
+ struct socket *upcall_socket = NULL;
+#endif
+ int type;
+ int i, secret;
+ bool did_output, released_asoc_reference;
+ /*
+ * If inp, stcb or net are not NULL, then references to these were
+ * added when the timer was started, and must be released before this
+ * function returns.
+ */
tmr = (struct sctp_timer *)t;
inp = (struct sctp_inpcb *)tmr->ep;
stcb = (struct sctp_tcb *)tmr->tcb;
net = (struct sctp_nets *)tmr->net;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_SET((struct vnet *)tmr->vnet);
+ NET_EPOCH_ENTER(et);
#endif
- did_output = 1;
+ released_asoc_reference = false;
#ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xF0, (uint8_t) tmr->type);
@@ -1556,146 +1802,87 @@ sctp_timeout_handler(void *t)
#endif
/* sanity checks... */
- if (tmr->self != (void *)tmr) {
- /*
- * SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n",
- * (void *)tmr);
- */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
- }
+ KASSERT(tmr->self == NULL || tmr->self == tmr,
+ ("sctp_timeout_handler: tmr->self corrupted"));
+ KASSERT(SCTP_IS_TIMER_TYPE_VALID(tmr->type),
+ ("sctp_timeout_handler: invalid timer type %d", tmr->type));
+ type = tmr->type;
+ KASSERT(stcb == NULL || stcb->sctp_ep == inp,
+ ("sctp_timeout_handler of type %d: inp = %p, stcb->sctp_ep %p",
+ type, stcb, stcb->sctp_ep));
tmr->stopped_from = 0xa001;
- if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) {
- /*
- * SCTP_PRINTF("SCTP timer fired with invalid type: 0x%x\n",
- * tmr->type);
- */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
+ if ((stcb != NULL) && (stcb->asoc.state == SCTP_STATE_EMPTY)) {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d handler exiting due to CLOSED association.\n",
+ type);
+ goto out_decr;
}
tmr->stopped_from = 0xa002;
- if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) {
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
- }
- /* if this is an iterator timeout, get the struct and clear inp */
- tmr->stopped_from = 0xa003;
- type = tmr->type;
- if (inp) {
- SCTP_INP_INCR_REF(inp);
- if ((inp->sctp_socket == NULL) &&
- ((tmr->type != SCTP_TIMER_TYPE_INPKILL) &&
- (tmr->type != SCTP_TIMER_TYPE_INIT) &&
- (tmr->type != SCTP_TIMER_TYPE_SEND) &&
- (tmr->type != SCTP_TIMER_TYPE_RECV) &&
- (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) &&
- (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) &&
- (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) &&
- (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) &&
- (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))
- ) {
- SCTP_INP_DECR_REF(inp);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
- }
- }
- tmr->stopped_from = 0xa004;
- if (stcb) {
- atomic_add_int(&stcb->asoc.refcnt, 1);
- if (stcb->asoc.state == 0) {
- atomic_add_int(&stcb->asoc.refcnt, -1);
- if (inp) {
- SCTP_INP_DECR_REF(inp);
- }
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
- }
- }
- tmr->stopped_from = 0xa005;
- SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", tmr->type);
+ SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d goes off.\n", type);
if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
- if (inp) {
- SCTP_INP_DECR_REF(inp);
- }
- if (stcb) {
- atomic_add_int(&stcb->asoc.refcnt, -1);
- }
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d handler exiting due to not being active.\n",
+ type);
+ goto out_decr;
}
- tmr->stopped_from = 0xa006;
+ tmr->stopped_from = 0xa003;
if (stcb) {
SCTP_TCB_LOCK(stcb);
+ /*
+ * Release reference so that association can be freed if
+ * necessary below.
+ * This is safe now that we have acquired the lock.
+ */
atomic_add_int(&stcb->asoc.refcnt, -1);
- if ((tmr->type != SCTP_TIMER_TYPE_ASOCKILL) &&
- ((stcb->asoc.state == 0) ||
+ released_asoc_reference = true;
+ if ((type != SCTP_TIMER_TYPE_ASOCKILL) &&
+ ((stcb->asoc.state == SCTP_STATE_EMPTY) ||
(stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) {
- SCTP_TCB_UNLOCK(stcb);
- if (inp) {
- SCTP_INP_DECR_REF(inp);
- }
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
- CURVNET_RESTORE();
-#endif
- return;
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d handler exiting due to CLOSED association.\n",
+ type);
+ goto out;
}
+ } else if (inp != NULL) {
+ SCTP_INP_WLOCK(inp);
+ } else {
+ SCTP_WQ_ADDR_LOCK();
}
- /* record in stopped what t-o occured */
- tmr->stopped_from = tmr->type;
+ /* Record in stopped_from which timeout occurred. */
+ tmr->stopped_from = type;
/* mark as being serviced now */
if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
/*
* Callout has been rescheduled.
*/
- goto get_out;
+ goto out;
}
if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
/*
* Not active, so no action.
*/
- goto get_out;
+ goto out;
}
SCTP_OS_TIMER_DEACTIVATE(&tmr->timer);
+#if defined(__Userspace__)
+ if ((stcb != NULL) &&
+ !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL)) {
+ upcall_socket = stcb->sctp_socket;
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ }
+#endif
/* call the handler for the appropriate timer type */
- switch (tmr->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;
+ switch (type) {
case SCTP_TIMER_TYPE_SEND:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timodata);
stcb->asoc.timodata++;
stcb->asoc.num_send_timers_up--;
@@ -1713,65 +1900,72 @@ sctp_timeout_handler(void *t)
sctp_auditing(4, inp, stcb, net);
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
+ did_output = true;
if ((stcb->asoc.num_send_timers_up == 0) &&
(stcb->asoc.sent_queue_cnt > 0)) {
struct sctp_tmit_chunk *chk;
/*
- * safeguard. If there on some on the sent queue
+ * Safeguard. If there on some on the sent queue
* somewhere but no timers running something is
* wrong... so we start a timer on the first chunk
* on the send queue on whatever net it is sent to.
*/
- chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
- sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
- chk->whoTo);
+ TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
+ if (chk->whoTo != NULL) {
+ break;
+ }
+ }
+ if (chk != NULL) {
+ sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
+ }
}
break;
case SCTP_TIMER_TYPE_INIT:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timoinit);
stcb->asoc.timoinit++;
if (sctp_t1init_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
}
- /* We do output but not here */
- did_output = 0;
+ did_output = false;
break;
case SCTP_TIMER_TYPE_RECV:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timosack);
stcb->asoc.timosack++;
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
#ifdef SCTP_AUDITING_ENABLED
- sctp_auditing(4, inp, stcb, net);
+ sctp_auditing(4, inp, stcb, NULL);
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
+ did_output = true;
break;
case SCTP_TIMER_TYPE_SHUTDOWN:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timoshutdown);
+ stcb->asoc.timoshutdown++;
if (sctp_shutdown_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
}
- SCTP_STAT_INCR(sctps_timoshutdown);
- stcb->asoc.timoshutdown++;
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
+ did_output = true;
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
- if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timoheartbeat);
stcb->asoc.timoheartbeat++;
if (sctp_heartbeat_timer(inp, stcb, net)) {
@@ -1784,19 +1978,21 @@ sctp_timeout_handler(void *t)
if (!(net->dest_state & SCTP_ADDR_NOHB)) {
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
+ did_output = true;
+ } else {
+ did_output = false;
}
break;
case SCTP_TIMER_TYPE_COOKIE:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
-
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timocookie);
+ stcb->asoc.timocookie++;
if (sctp_cookie_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
}
- SCTP_STAT_INCR(sctps_timocookie);
- stcb->asoc.timocookie++;
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@@ -1805,47 +2001,42 @@ sctp_timeout_handler(void *t)
* respect to where from in chunk_output.
*/
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
+ did_output = true;
break;
case SCTP_TIMER_TYPE_NEWCOOKIE:
- {
- struct timeval tv;
- int i, secret;
- if (inp == NULL) {
- break;
- }
- 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;
- inp->sctp_ep.current_secret_number++;
- if (inp->sctp_ep.current_secret_number >=
- SCTP_HOW_MANY_SECRETS) {
- inp->sctp_ep.current_secret_number = 0;
- }
- secret = (int)inp->sctp_ep.current_secret_number;
- for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
- 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;
+ KASSERT(inp != NULL && stcb == NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timosecret);
+ (void)SCTP_GETTIME_TIMEVAL(&tv);
+ inp->sctp_ep.time_of_secret_change = tv.tv_sec;
+ inp->sctp_ep.last_secret_number =
+ inp->sctp_ep.current_secret_number;
+ inp->sctp_ep.current_secret_number++;
+ if (inp->sctp_ep.current_secret_number >=
+ SCTP_HOW_MANY_SECRETS) {
+ inp->sctp_ep.current_secret_number = 0;
+ }
+ secret = (int)inp->sctp_ep.current_secret_number;
+ for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
+ inp->sctp_ep.secret_key[secret][i] =
+ sctp_select_initial_TSN(&inp->sctp_ep);
+ }
+ sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL);
+ did_output = false;
break;
case SCTP_TIMER_TYPE_PATHMTURAISE:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timopathmtu);
sctp_pathmtu_timer(inp, stcb, net);
- did_output = 0;
+ did_output = false;
break;
case SCTP_TIMER_TYPE_SHUTDOWNACK:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
if (sctp_shutdownack_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
@@ -1856,67 +2047,87 @@ sctp_timeout_handler(void *t)
sctp_auditing(4, inp, stcb, net);
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
- break;
- case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
- SCTP_STAT_INCR(sctps_timoshutdownguard);
- sctp_abort_an_association(inp, stcb, NULL, SCTP_SO_NOT_LOCKED);
- /* no need to unlock on tcb its gone */
- goto out_decr;
-
- case SCTP_TIMER_TYPE_STRRESET:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
- if (sctp_strreset_timer(inp, stcb, net)) {
- /* no need to unlock on tcb its gone */
- goto out_decr;
- }
- SCTP_STAT_INCR(sctps_timostrmrst);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
+ did_output = true;
break;
case SCTP_TIMER_TYPE_ASCONF:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net != NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timoasconf);
if (sctp_asconf_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
}
- SCTP_STAT_INCR(sctps_timoasconf);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
+ did_output = true;
break;
- case SCTP_TIMER_TYPE_PRIM_DELETED:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
- sctp_delete_prim_timer(inp, stcb, net);
- SCTP_STAT_INCR(sctps_timodelprim);
- break;
-
+ case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
+ KASSERT(inp != NULL && stcb != NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timoshutdownguard);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Shutdown guard timer expired");
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ /* no need to unlock on tcb its gone */
+ goto out_decr;
case SCTP_TIMER_TYPE_AUTOCLOSE:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
+ KASSERT(inp != NULL && stcb != NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timoautoclose);
- sctp_autoclose_timer(inp, stcb, net);
+ sctp_autoclose_timer(inp, stcb);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
- did_output = 0;
+ did_output = true;
break;
- case SCTP_TIMER_TYPE_ASOCKILL:
- if ((stcb == NULL) || (inp == NULL)) {
- break;
+ case SCTP_TIMER_TYPE_STRRESET:
+ KASSERT(inp != NULL && stcb != NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timostrmrst);
+ if (sctp_strreset_timer(inp, stcb)) {
+ /* no need to unlock on tcb its gone */
+ goto out_decr;
}
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
+ did_output = true;
+ break;
+ case SCTP_TIMER_TYPE_INPKILL:
+ KASSERT(inp != NULL && stcb == NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timoinpkill);
+ /*
+ * special case, take away our increment since WE are the
+ * killer
+ */
+ sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_3);
+#if defined(__APPLE__) && !defined(__Userspace__)
+ SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 1);
+#endif
+ SCTP_INP_DECR_REF(inp);
+ SCTP_INP_WUNLOCK(inp);
+ sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
+ SCTP_CALLED_FROM_INPKILL_TIMER);
+#if defined(__APPLE__) && !defined(__Userspace__)
+ SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
+#endif
+ inp = NULL;
+ goto out_no_decr;
+ case SCTP_TIMER_TYPE_ASOCKILL:
+ KASSERT(inp != NULL && stcb != NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
SCTP_STAT_INCR(sctps_timoassockill);
/* Can we free it yet? */
SCTP_INP_DECR_REF(inp);
- sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL+SCTP_LOC_1);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -1924,8 +2135,9 @@ sctp_timeout_handler(void *t)
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL+SCTP_LOC_2);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
/*
@@ -1934,38 +2146,34 @@ sctp_timeout_handler(void *t)
*/
stcb = NULL;
goto out_no_decr;
- case SCTP_TIMER_TYPE_INPKILL:
- SCTP_STAT_INCR(sctps_timoinpkill);
- if (inp == NULL) {
- break;
- }
- /*
- * special case, take away our increment since WE are the
- * killer
- */
- SCTP_INP_DECR_REF(inp);
- sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL+SCTP_LOC_3);
-#if defined(__APPLE__)
- SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 1);
-#endif
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
- SCTP_CALLED_FROM_INPKILL_TIMER);
-#if defined(__APPLE__)
- SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
-#endif
- inp = NULL;
- goto out_no_decr;
- default:
- SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n",
- tmr->type);
+ case SCTP_TIMER_TYPE_ADDR_WQ:
+ KASSERT(inp == NULL && stcb == NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ sctp_handle_addr_wq();
+ did_output = true;
break;
+ case SCTP_TIMER_TYPE_PRIM_DELETED:
+ KASSERT(inp != NULL && stcb != NULL && net == NULL,
+ ("timeout of type %d: inp = %p, stcb = %p, net = %p",
+ type, inp, stcb, net));
+ SCTP_STAT_INCR(sctps_timodelprim);
+ sctp_delete_prim_timer(inp, stcb);
+ did_output = false;
+ break;
+ default:
+#ifdef INVARIANTS
+ panic("Unknown timer type %d", type);
+#else
+ goto out;
+#endif
}
#ifdef SCTP_AUDITING_ENABLED
- sctp_audit_log(0xF1, (uint8_t) tmr->type);
- if (inp)
+ sctp_audit_log(0xF1, (uint8_t) type);
+ if (inp != NULL)
sctp_auditing(5, inp, stcb, net);
#endif
- if ((did_output) && stcb) {
+ if (did_output && (stcb != NULL)) {
/*
* Now we need to clean up the control chunk chain if an
* ECNE is on it. It must be marked as UNSENT again so next
@@ -1975,294 +2183,449 @@ sctp_timeout_handler(void *t)
*/
sctp_fix_ecn_echo(&stcb->asoc);
}
-get_out:
- if (stcb) {
+out:
+ if (stcb != NULL) {
SCTP_TCB_UNLOCK(stcb);
+ } else if (inp != NULL) {
+ SCTP_INP_WUNLOCK(inp);
+ } else {
+ SCTP_WQ_ADDR_UNLOCK();
}
out_decr:
- if (inp) {
+#if defined(__Userspace__)
+ if (upcall_socket != NULL) {
+ if ((upcall_socket->so_upcall != NULL) &&
+ (upcall_socket->so_error != 0)) {
+ (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
+ }
+ ACCEPT_LOCK();
+ SOCK_LOCK(upcall_socket);
+ sorele(upcall_socket);
+ }
+#endif
+ /* These reference counts were incremented in sctp_timer_start(). */
+ if (inp != NULL) {
SCTP_INP_DECR_REF(inp);
}
-
+ if ((stcb != NULL) && !released_asoc_reference) {
+ atomic_add_int(&stcb->asoc.refcnt, -1);
+ }
+ if (net != NULL) {
+ sctp_free_remote_addr(net);
+ }
out_no_decr:
- SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n",
- type);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 801000
+ SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler finished.\n", type);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
CURVNET_RESTORE();
+ NET_EPOCH_EXIT(et);
#endif
}
+/*-
+ * The following table shows which parameters must be provided
+ * when calling sctp_timer_start(). For parameters not being
+ * provided, NULL must be used.
+ *
+ * |Name |inp |stcb|net |
+ * |-----------------------------|----|----|----|
+ * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No |
+ * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No |
+ * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No |
+ * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No |
+ *
+ */
+
void
sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net)
{
- uint32_t to_ticks;
struct sctp_timer *tmr;
+ uint32_t to_ticks;
+ uint32_t rndval, jitter;
- if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL))
- return;
-
+ KASSERT(stcb == NULL || stcb->sctp_ep == inp,
+ ("sctp_timer_start of type %d: inp = %p, stcb->sctp_ep %p",
+ t_type, stcb, stcb->sctp_ep));
tmr = NULL;
- if (stcb) {
+ if (stcb != NULL) {
SCTP_TCB_LOCK_ASSERT(stcb);
+ } else if (inp != NULL) {
+ SCTP_INP_WLOCK_ASSERT(inp);
+ } else {
+ SCTP_WQ_ADDR_LOCK_ASSERT();
+ }
+ if (stcb != NULL) {
+ /* Don't restart timer on association that's about to be killed. */
+ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) &&
+ (t_type != SCTP_TIMER_TYPE_ASOCKILL)) {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d not started: inp=%p, stcb=%p, net=%p (stcb deleted).\n",
+ t_type, inp, stcb, net);
+ return;
+ }
+ /* Don't restart timer on net that's been removed. */
+ if (net != NULL && (net->dest_state & SCTP_ADDR_BEING_DELETED)) {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d not started: inp=%p, stcb=%p, net=%p (net deleted).\n",
+ t_type, inp, stcb, net);
+ return;
+ }
}
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);
- to_ticks = SCTP_ADDRESS_TICK_DELAY;
- break;
case SCTP_TIMER_TYPE_SEND:
- /* Here we use the RTO timer */
- {
- int rto_val;
-
- if ((stcb == NULL) || (net == NULL)) {
- return;
- }
- tmr = &net->rxt_timer;
- if (net->RTO == 0) {
- rto_val = stcb->asoc.initial_rto;
- } else {
- rto_val = net->RTO;
- }
- to_ticks = MSEC_TO_TICKS(rto_val);
+ /* Here we use the RTO timer. */
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
+ return;
+#endif
+ }
+ tmr = &net->rxt_timer;
+ if (net->RTO == 0) {
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
+ } else {
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
}
break;
case SCTP_TIMER_TYPE_INIT:
/*
* Here we use the INIT timer default usually about 1
- * minute.
+ * second.
*/
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->rxt_timer;
if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
} else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
}
break;
case SCTP_TIMER_TYPE_RECV:
/*
- * Here we use the Delayed-Ack timer value from the inp
+ * Here we use the Delayed-Ack timer value from the inp,
* ususually about 200ms.
*/
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &stcb->asoc.dack_timer;
- to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack);
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.delayed_ack);
break;
case SCTP_TIMER_TYPE_SHUTDOWN:
/* Here we use the RTO of the destination. */
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
+ tmr = &net->rxt_timer;
if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
} else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
}
- tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
/*
- * the net is used here so that we can add in the RTO. Even
+ * The net is used here so that we can add in the RTO. Even
* though we use a different timer. We also add the HB timer
* PLUS a random jitter.
*/
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
+ }
+ if ((net->dest_state & SCTP_ADDR_NOHB) &&
+ !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n",
+ t_type, inp, stcb, net);
+ return;
+ }
+ tmr = &net->hb_timer;
+ if (net->RTO == 0) {
+ to_ticks = stcb->asoc.initial_rto;
} else {
- uint32_t rndval;
- uint32_t jitter;
-
- if ((net->dest_state & SCTP_ADDR_NOHB) &&
- !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
- return;
- }
- if (net->RTO == 0) {
- to_ticks = stcb->asoc.initial_rto;
- } else {
- to_ticks = net->RTO;
- }
- rndval = sctp_select_initial_TSN(&inp->sctp_ep);
- jitter = rndval % to_ticks;
- if (jitter >= (to_ticks >> 1)) {
- to_ticks = to_ticks + (jitter - (to_ticks >> 1));
- } else {
- to_ticks = to_ticks - jitter;
- }
- if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
- !(net->dest_state & SCTP_ADDR_PF)) {
- to_ticks += net->heart_beat_delay;
- }
- /*
- * Now we must convert the to_ticks that are now in
- * ms to ticks.
- */
- to_ticks = MSEC_TO_TICKS(to_ticks);
- tmr = &net->hb_timer;
+ to_ticks = net->RTO;
+ }
+ rndval = sctp_select_initial_TSN(&inp->sctp_ep);
+ jitter = rndval % to_ticks;
+ if (jitter >= (to_ticks >> 1)) {
+ to_ticks = to_ticks + (jitter - (to_ticks >> 1));
+ } else {
+ to_ticks = to_ticks - jitter;
+ }
+ if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
+ !(net->dest_state & SCTP_ADDR_PF)) {
+ to_ticks += net->heart_beat_delay;
}
+ /*
+ * Now we must convert the to_ticks that are now in
+ * ms to ticks.
+ */
+ to_ticks = sctp_msecs_to_ticks(to_ticks);
break;
case SCTP_TIMER_TYPE_COOKIE:
/*
* Here we can use the RTO timer from the network since one
- * RTT was compelete. If a retran happened then we will be
- * using the RTO initial value.
+ * RTT was complete. If a retransmission happened then we will
+ * be using the RTO initial value.
*/
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
+ tmr = &net->rxt_timer;
if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
} else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
}
- tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_NEWCOOKIE:
/*
- * nothing needed but the endpoint here ususually about 60
+ * Nothing needed but the endpoint here ususually about 60
* minutes.
*/
- tmr = &inp->sctp_ep.signature_change;
- to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
- break;
- case SCTP_TIMER_TYPE_ASOCKILL:
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- tmr = &stcb->asoc.strreset_timer;
- to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT);
- break;
- case SCTP_TIMER_TYPE_INPKILL:
- /*
- * The inp is setup to die. We re-use the signature_chage
- * timer since that has stopped and we are in the GONE
- * state.
- */
tmr = &inp->sctp_ep.signature_change;
- to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT);
+ to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
break;
case SCTP_TIMER_TYPE_PATHMTURAISE:
/*
- * Here we use the value found in the EP for PMTU ususually
+ * Here we use the value found in the EP for PMTUD, ususually
* about 10 minutes.
*/
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n",
+ t_type, inp, stcb, net);
return;
}
- to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
tmr = &net->pmtu_timer;
+ to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
break;
case SCTP_TIMER_TYPE_SHUTDOWNACK:
- /* Here we use the RTO of the destination */
- if ((stcb == NULL) || (net == NULL)) {
+ /* Here we use the RTO of the destination. */
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
+ tmr = &net->rxt_timer;
if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
} else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
+ }
+ break;
+ case SCTP_TIMER_TYPE_ASCONF:
+ /*
+ * Here the timer comes from the stcb but its value is from
+ * the net's RTO.
+ */
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
+ return;
+#endif
+ }
+ tmr = &stcb->asoc.asconf_timer;
+ if (net->RTO == 0) {
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
+ } else {
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
}
- tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
/*
* Here we use the endpoints shutdown guard timer usually
* about 3 minutes.
*/
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
tmr = &stcb->asoc.shut_guard_timer;
+ if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) {
+ if (stcb->asoc.maxrto < UINT32_MAX / 5) {
+ to_ticks = sctp_msecs_to_ticks(5 * stcb->asoc.maxrto);
+ } else {
+ to_ticks = sctp_msecs_to_ticks(UINT32_MAX);
+ }
+ } else {
+ to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
+ }
+ break;
+ case SCTP_TIMER_TYPE_AUTOCLOSE:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
+ return;
+#endif
+ }
+ tmr = &stcb->asoc.autoclose_timer;
+ to_ticks = stcb->asoc.sctp_autoclose_ticks;
break;
case SCTP_TIMER_TYPE_STRRESET:
/*
* Here the timer comes from the stcb but its value is from
* the net's RTO.
*/
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
+ tmr = &stcb->asoc.strreset_timer;
if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
} else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
+ to_ticks = sctp_msecs_to_ticks(net->RTO);
}
- tmr = &stcb->asoc.strreset_timer;
break;
- case SCTP_TIMER_TYPE_ASCONF:
+ case SCTP_TIMER_TYPE_INPKILL:
/*
- * Here the timer comes from the stcb but its value is from
- * the net's RTO.
+ * The inp is setup to die. We re-use the signature_chage
+ * timer since that has stopped and we are in the GONE
+ * state.
*/
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
- } else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
- }
- tmr = &stcb->asoc.asconf_timer;
+ tmr = &inp->sctp_ep.signature_change;
+ to_ticks = sctp_msecs_to_ticks(SCTP_INP_KILL_TIMEOUT);
break;
- case SCTP_TIMER_TYPE_PRIM_DELETED:
- if ((stcb == NULL) || (net != NULL)) {
+ case SCTP_TIMER_TYPE_ASOCKILL:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
- tmr = &stcb->asoc.delete_prim_timer;
+ tmr = &stcb->asoc.strreset_timer;
+ to_ticks = sctp_msecs_to_ticks(SCTP_ASOC_KILL_TIMEOUT);
break;
- case SCTP_TIMER_TYPE_AUTOCLOSE:
- if (stcb == NULL) {
+ case SCTP_TIMER_TYPE_ADDR_WQ:
+ if ((inp != NULL) || (stcb != NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- if (stcb->asoc.sctp_autoclose_ticks == 0) {
- /*
- * Really an error since stcb is NOT set to
- * autoclose
- */
+ /* Only 1 tick away :-) */
+ tmr = &SCTP_BASE_INFO(addr_wq_timer);
+ to_ticks = SCTP_ADDRESS_TICK_DELAY;
+ break;
+ case SCTP_TIMER_TYPE_PRIM_DELETED:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- to_ticks = stcb->asoc.sctp_autoclose_ticks;
- tmr = &stcb->asoc.autoclose_timer;
+ tmr = &stcb->asoc.delete_prim_timer;
+ to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto);
break;
default:
- SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
- __FUNCTION__, t_type);
- return;
- break;
- }
- if ((to_ticks <= 0) || (tmr == NULL)) {
- SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n",
- __FUNCTION__, t_type, to_ticks, (void *)tmr);
+#ifdef INVARIANTS
+ panic("Unknown timer type %d", t_type);
+#else
return;
+#endif
}
+ KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type));
+ KASSERT(to_ticks > 0, ("to_ticks == 0 for timer type %d", t_type));
if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
/*
- * we do NOT allow you to have it already running. if it is
- * we leave the current one up unchanged
+ * We do NOT allow you to have it already running. If it is,
+ * we leave the current one up unchanged.
*/
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d already running: inp=%p, stcb=%p, net=%p.\n",
+ t_type, inp, stcb, net);
return;
}
- /* At this point we can proceed */
+ /* At this point we can proceed. */
if (t_type == SCTP_TIMER_TYPE_SEND) {
stcb->asoc.num_send_timers_up++;
}
@@ -2270,161 +2633,301 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
tmr->type = t_type;
tmr->ep = (void *)inp;
tmr->tcb = (void *)stcb;
- tmr->net = (void *)net;
+ if (t_type == SCTP_TIMER_TYPE_STRRESET) {
+ tmr->net = NULL;
+ } else {
+ tmr->net = (void *)net;
+ }
tmr->self = (void *)tmr;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
tmr->vnet = (void *)curvnet;
#endif
-#ifndef __Panda__
tmr->ticks = sctp_get_tick_count();
-#endif
- (void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
+ if (SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr) == 0) {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d started: ticks=%u, inp=%p, stcb=%p, net=%p.\n",
+ t_type, to_ticks, inp, stcb, net);
+ /*
+ * If this is a newly scheduled callout, as opposed to a
+ * rescheduled one, increment relevant reference counts.
+ */
+ if (tmr->ep != NULL) {
+ SCTP_INP_INCR_REF(inp);
+ }
+ if (tmr->tcb != NULL) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ }
+ if (tmr->net != NULL) {
+ atomic_add_int(&net->ref_count, 1);
+ }
+ } else {
+ /*
+ * This should not happen, since we checked for pending
+ * above.
+ */
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d restarted: ticks=%u, inp=%p, stcb=%p, net=%p.\n",
+ t_type, to_ticks, inp, stcb, net);
+ }
return;
}
+/*-
+ * The following table shows which parameters must be provided
+ * when calling sctp_timer_stop(). For parameters not being
+ * provided, NULL must be used.
+ *
+ * |Name |inp |stcb|net |
+ * |-----------------------------|----|----|----|
+ * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No |
+ * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes |
+ * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No |
+ * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No |
+ * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No |
+ * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No |
+ *
+ */
+
void
sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net, uint32_t from)
{
struct sctp_timer *tmr;
- if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) &&
- (inp == NULL))
- return;
-
- tmr = NULL;
- if (stcb) {
+ KASSERT(stcb == NULL || stcb->sctp_ep == inp,
+ ("sctp_timer_stop of type %d: inp = %p, stcb->sctp_ep %p",
+ t_type, stcb, stcb->sctp_ep));
+ if (stcb != NULL) {
SCTP_TCB_LOCK_ASSERT(stcb);
+ } else if (inp != NULL) {
+ SCTP_INP_WLOCK_ASSERT(inp);
+ } else {
+ SCTP_WQ_ADDR_LOCK_ASSERT();
}
+ tmr = NULL;
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;
case SCTP_TIMER_TYPE_SEND:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_INIT:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_RECV:
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &stcb->asoc.dack_timer;
break;
case SCTP_TIMER_TYPE_SHUTDOWN:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->hb_timer;
break;
case SCTP_TIMER_TYPE_COOKIE:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_NEWCOOKIE:
- /* nothing needed but the endpoint here */
- tmr = &inp->sctp_ep.signature_change;
- /*
- * We re-use the newcookie timer for the INP kill timer. We
- * must assure that we do not kill it by accident.
- */
- break;
- case SCTP_TIMER_TYPE_ASOCKILL:
- /*
- * Stop the asoc kill timer.
- */
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- tmr = &stcb->asoc.strreset_timer;
- break;
-
- case SCTP_TIMER_TYPE_INPKILL:
- /*
- * The inp is setup to die. We re-use the signature_chage
- * timer since that has stopped and we are in the GONE
- * state.
- */
tmr = &inp->sctp_ep.signature_change;
break;
case SCTP_TIMER_TYPE_PATHMTURAISE:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->pmtu_timer;
break;
case SCTP_TIMER_TYPE_SHUTDOWNACK:
- if ((stcb == NULL) || (net == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &net->rxt_timer;
break;
+ case SCTP_TIMER_TYPE_ASCONF:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
+ return;
+#endif
+ }
+ tmr = &stcb->asoc.asconf_timer;
+ break;
case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &stcb->asoc.shut_guard_timer;
break;
+ case SCTP_TIMER_TYPE_AUTOCLOSE:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
+ return;
+#endif
+ }
+ tmr = &stcb->asoc.autoclose_timer;
+ break;
case SCTP_TIMER_TYPE_STRRESET:
- if (stcb == NULL) {
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
tmr = &stcb->asoc.strreset_timer;
break;
- case SCTP_TIMER_TYPE_ASCONF:
- if (stcb == NULL) {
+ case SCTP_TIMER_TYPE_INPKILL:
+ /*
+ * The inp is setup to die. We re-use the signature_chage
+ * timer since that has stopped and we are in the GONE
+ * state.
+ */
+ if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- tmr = &stcb->asoc.asconf_timer;
+ tmr = &inp->sctp_ep.signature_change;
break;
- case SCTP_TIMER_TYPE_PRIM_DELETED:
- if (stcb == NULL) {
+ case SCTP_TIMER_TYPE_ASOCKILL:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- tmr = &stcb->asoc.delete_prim_timer;
+ tmr = &stcb->asoc.strreset_timer;
break;
- case SCTP_TIMER_TYPE_AUTOCLOSE:
- if (stcb == NULL) {
+ case SCTP_TIMER_TYPE_ADDR_WQ:
+ if ((inp != NULL) || (stcb != NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
return;
+#endif
}
- tmr = &stcb->asoc.autoclose_timer;
+ tmr = &SCTP_BASE_INFO(addr_wq_timer);
break;
- default:
- SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
- __FUNCTION__, t_type);
+ case SCTP_TIMER_TYPE_PRIM_DELETED:
+ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
+#ifdef INVARIANTS
+ panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
+ t_type, inp, stcb, net);
+#else
+ return;
+#endif
+ }
+ tmr = &stcb->asoc.delete_prim_timer;
break;
- }
- if (tmr == NULL) {
+ default:
+#ifdef INVARIANTS
+ panic("Unknown timer type %d", t_type);
+#else
return;
+#endif
}
- if ((tmr->type != t_type) && tmr->type) {
+ KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type));
+ if ((tmr->type != SCTP_TIMER_TYPE_NONE) &&
+ (tmr->type != t_type)) {
/*
* Ok we have a timer that is under joint use. Cookie timer
* per chance with the SEND timer. We therefore are NOT
* running the timer that the caller wants stopped. So just
* return.
*/
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Shared timer type %d not running: inp=%p, stcb=%p, net=%p.\n",
+ t_type, inp, stcb, net);
return;
}
if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) {
@@ -2435,7 +2938,45 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
tmr->self = NULL;
tmr->stopped_from = from;
- (void)SCTP_OS_TIMER_STOP(&tmr->timer);
+ if (SCTP_OS_TIMER_STOP(&tmr->timer) == 1) {
+ KASSERT(tmr->ep == inp,
+ ("sctp_timer_stop of type %d: inp = %p, tmr->inp = %p",
+ t_type, inp, tmr->ep));
+ KASSERT(tmr->tcb == stcb,
+ ("sctp_timer_stop of type %d: stcb = %p, tmr->stcb = %p",
+ t_type, stcb, tmr->tcb));
+ KASSERT(((t_type == SCTP_TIMER_TYPE_ASCONF) && (tmr->net != NULL)) ||
+ ((t_type != SCTP_TIMER_TYPE_ASCONF) && (tmr->net == net)),
+ ("sctp_timer_stop of type %d: net = %p, tmr->net = %p",
+ t_type, net, tmr->net));
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d stopped: inp=%p, stcb=%p, net=%p.\n",
+ t_type, inp, stcb, net);
+ /*
+ * If the timer was actually stopped, decrement reference counts
+ * that were incremented in sctp_timer_start().
+ */
+ if (tmr->ep != NULL) {
+ SCTP_INP_DECR_REF(inp);
+ tmr->ep = NULL;
+ }
+ if (tmr->tcb != NULL) {
+ atomic_add_int(&stcb->asoc.refcnt, -1);
+ tmr->tcb = NULL;
+ }
+ if (tmr->net != NULL) {
+ /*
+ * Can't use net, since it doesn't work for
+ * SCTP_TIMER_TYPE_ASCONF.
+ */
+ sctp_free_remote_addr((struct sctp_nets *)tmr->net);
+ tmr->net = NULL;
+ }
+ } else {
+ SCTPDBG(SCTP_DEBUG_TIMER2,
+ "Timer type %d not stopped: inp=%p, stcb=%p, net=%p.\n",
+ t_type, inp, stcb, net);
+ }
return;
}
@@ -2484,39 +3025,26 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp,
}
}
-
/*
- * given an association and starting time of the current RTT period return
- * RTO in number of msecs net should point to the current network
+ * Given an association and starting time of the current RTT period, update
+ * RTO in number of msecs. net should point to the current network.
+ * Return 1, if an RTO update was performed, return 0 if no update was
+ * performed due to invalid starting point.
*/
-uint32_t
+int
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
- * period (in value1/value2) return RTO in number of msecs.
- */
- int32_t rtt; /* RTT in ms */
+ struct timeval now;
+ uint64_t rtt_us; /* RTT in us */
+ int32_t rtt; /* RTT in ms */
uint32_t new_rto;
int first_measure = 0;
- struct timeval now, then, *old;
-
- /* 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 */
/************************/
@@ -2526,10 +3054,19 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
} else {
(void)SCTP_GETTIME_TIMEVAL(&now);
}
+ if ((old->tv_sec > now.tv_sec) ||
+ ((old->tv_sec == now.tv_sec) && (old->tv_usec > now.tv_usec))) {
+ /* The starting point is in the future. */
+ return (0);
+ }
timevalsub(&now, old);
+ rtt_us = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec;
+ if (rtt_us > SCTP_RTO_UPPER_BOUND * 1000) {
+ /* The RTT is larger than a sane value. */
+ return (0);
+ }
/* store the current RTT in us */
- net->rtt = (uint64_t)1000000 * (uint64_t)now.tv_sec +
- (uint64_t)now.tv_usec;
+ net->rtt = rtt_us;
/* compute rtt in ms */
rtt = (int32_t)(net->rtt / 1000);
if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) {
@@ -2558,7 +3095,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
* Paper "Congestion Avoidance and Control", Annex A.
*
* (net->lastsa >> SCTP_RTT_SHIFT) is the srtt
- * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar
+ * (net->lastsv >> SCTP_RTT_VAR_SHIFT) is the rttvar
*/
if (net->RTO_measured) {
rtt -= (net->lastsa >> SCTP_RTT_SHIFT);
@@ -2599,8 +3136,8 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
if (new_rto > stcb->asoc.maxrto) {
new_rto = stcb->asoc.maxrto;
}
- /* we are now returning the RTO */
- return (new_rto);
+ net->RTO = new_rto;
+ return (1);
}
/*
@@ -2636,7 +3173,7 @@ sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t * in_ptr)
/* else, it spans more than one mbuf, so save a temp copy... */
while ((m != NULL) && (len > 0)) {
count = min(SCTP_BUF_LEN(m) - off, len);
- bcopy(mtod(m, caddr_t) + off, ptr, count);
+ memcpy(ptr, mtod(m, caddr_t) + off, count);
len -= count;
ptr += count;
off = 0;
@@ -2649,8 +3186,6 @@ sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t * in_ptr)
}
}
-
-
struct sctp_paramhdr *
sctp_get_next_param(struct mbuf *m,
int offset,
@@ -2662,7 +3197,6 @@ sctp_get_next_param(struct mbuf *m,
(uint8_t *) pull));
}
-
struct mbuf *
sctp_add_pad_tombuf(struct mbuf *m, int padlen)
{
@@ -2714,25 +3248,32 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
static void
sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
- uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked)
{
struct mbuf *m_notify;
struct sctp_assoc_change *sac;
struct sctp_queued_to_read *control;
- size_t notif_len, abort_len;
+ unsigned int notif_len;
+ uint16_t abort_len;
unsigned int i;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
+ if (stcb == NULL) {
+ return;
+ }
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
- notif_len = sizeof(struct sctp_assoc_change);
+ notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
if (abort != NULL) {
abort_len = ntohs(abort->ch.chunk_length);
+ /*
+ * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be
+ * contiguous.
+ */
+ if (abort_len > SCTP_CHUNK_BUFFER_SIZE) {
+ abort_len = SCTP_CHUNK_BUFFER_SIZE;
+ }
} else {
abort_len = 0;
}
@@ -2744,7 +3285,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
/* Retry with smaller value. */
- notif_len = sizeof(struct sctp_assoc_change);
+ notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
goto set_error;
@@ -2774,6 +3315,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
if (stcb->asoc.asconf_supported == 1) {
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
}
+ if (stcb->asoc.idata_supported == 1) {
+ sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING;
+ }
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
if (stcb->asoc.reconfig_supported == 1) {
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG;
@@ -2790,9 +3334,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
- control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
@@ -2811,7 +3355,7 @@ set_error:
((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
SOCK_LOCK(stcb->sctp_socket);
if (from_peer) {
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
+ if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
stcb->sctp_socket->so_error = ECONNREFUSED;
} else {
@@ -2819,8 +3363,8 @@ set_error:
stcb->sctp_socket->so_error = ECONNRESET;
}
} else {
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT);
stcb->sctp_socket->so_error = ETIMEDOUT;
} else {
@@ -2828,9 +3372,10 @@ set_error:
stcb->sctp_socket->so_error = ECONNABORTED;
}
}
+ SOCK_UNLOCK(stcb->sctp_socket);
}
/* Wake ANY sleepers */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(stcb->sctp_ep);
if (!so_locked) {
atomic_add_int(&stcb->asoc.refcnt, 1);
@@ -2847,15 +3392,11 @@ set_error:
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
-#if defined(__APPLE__)
socantrcvmore(stcb->sctp_socket);
-#else
- socantrcvmore_locked(stcb->sctp_socket);
-#endif
}
sorwakeup(stcb->sctp_socket);
sowwakeup(stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -2864,11 +3405,7 @@ set_error:
static void
sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
- struct sockaddr *sa, uint32_t error, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+ struct sockaddr *sa, uint32_t error, int so_locked)
{
struct mbuf *m_notify;
struct sctp_paddr_change *spc;
@@ -2967,20 +3504,16 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
so_locked);
}
-
static void
sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
- struct sctp_tmit_chunk *chk, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ struct sctp_tmit_chunk *chk, int so_locked)
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
struct sctp_send_failed_event *ssfe;
struct sctp_queued_to_read *control;
- int length;
+ struct sctp_chunkhdr *chkhdr;
+ int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len;
if ((stcb == NULL) ||
(sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
@@ -2990,69 +3523,84 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
}
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
- length = sizeof(struct sctp_send_failed_event);
+ notifhdr_len = sizeof(struct sctp_send_failed_event);
} else {
- length = sizeof(struct sctp_send_failed);
+ notifhdr_len = sizeof(struct sctp_send_failed);
}
- m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA);
+ m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL)
/* no space left */
return;
- SCTP_BUF_LEN(m_notify) = 0;
+ SCTP_BUF_LEN(m_notify) = notifhdr_len;
+ if (stcb->asoc.idata_supported) {
+ chkhdr_len = sizeof(struct sctp_idata_chunk);
+ } else {
+ chkhdr_len = sizeof(struct sctp_data_chunk);
+ }
+ /* Use some defaults in case we can't access the chunk header */
+ if (chk->send_size >= chkhdr_len) {
+ payload_len = chk->send_size - chkhdr_len;
+ } else {
+ payload_len = 0;
+ }
+ padding_len = 0;
+ if (chk->data != NULL) {
+ chkhdr = mtod(chk->data, struct sctp_chunkhdr *);
+ if (chkhdr != NULL) {
+ chk_len = ntohs(chkhdr->chunk_length);
+ if ((chk_len >= chkhdr_len) &&
+ (chk->send_size >= chk_len) &&
+ (chk->send_size - chk_len < 4)) {
+ padding_len = chk->send_size - chk_len;
+ payload_len = chk->send_size - chkhdr_len - padding_len;
+ }
+ }
+ }
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
ssfe = mtod(m_notify, struct sctp_send_failed_event *);
- memset(ssfe, 0, length);
+ memset(ssfe, 0, notifhdr_len);
ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
if (sent) {
ssfe->ssfe_flags = SCTP_DATA_SENT;
} else {
ssfe->ssfe_flags = SCTP_DATA_UNSENT;
}
- length += chk->send_size;
- length -= sizeof(struct sctp_data_chunk);
- ssfe->ssfe_length = length;
+ ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len);
ssfe->ssfe_error = error;
/* not exactly what the user sent in, but should be close :) */
- ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number;
+ ssfe->ssfe_info.snd_sid = chk->rec.data.sid;
ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags;
- ssfe->ssfe_info.snd_ppid = chk->rec.data.payloadtype;
+ ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid;
ssfe->ssfe_info.snd_context = chk->rec.data.context;
ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event);
} else {
ssf = mtod(m_notify, struct sctp_send_failed *);
- memset(ssf, 0, length);
+ memset(ssf, 0, notifhdr_len);
ssf->ssf_type = SCTP_SEND_FAILED;
if (sent) {
ssf->ssf_flags = SCTP_DATA_SENT;
} else {
ssf->ssf_flags = SCTP_DATA_UNSENT;
}
- length += chk->send_size;
- length -= sizeof(struct sctp_data_chunk);
- ssf->ssf_length = length;
+ ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len);
ssf->ssf_error = error;
/* not exactly what the user sent in, but should be close :) */
- bzero(&ssf->ssf_info, sizeof(ssf->ssf_info));
- ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
- ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
+ ssf->ssf_info.sinfo_stream = chk->rec.data.sid;
+ ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid;
ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
- ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
+ ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid;
ssf->ssf_info.sinfo_context = chk->rec.data.context;
ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
ssf->ssf_assoc_id = sctp_get_associd(stcb);
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
}
- if (chk->data) {
- /*
- * trim off the sctp chunk header(it should
- * be there)
- */
- if (chk->send_size >= sizeof(struct sctp_data_chunk)) {
- m_adj(chk->data, sizeof(struct sctp_data_chunk));
+ if (chk->data != NULL) {
+ /* Trim off the sctp chunk header (it should be there) */
+ if (chk->send_size == chkhdr_len + payload_len + padding_len) {
+ m_adj(chk->data, chkhdr_len);
+ m_adj(chk->data, -padding_len);
sctp_mbuf_crush(chk->data);
- chk->send_size -= sizeof(struct sctp_data_chunk);
+ chk->send_size -= (chkhdr_len + padding_len);
}
}
SCTP_BUF_NEXT(m_notify) = chk->data;
@@ -3076,7 +3624,10 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
sctp_m_freem(m_notify);
return;
}
+ control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
@@ -3084,20 +3635,15 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
so_locked);
}
-
static void
sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
- struct sctp_stream_queue_pending *sp, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ struct sctp_stream_queue_pending *sp, int so_locked)
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
struct sctp_send_failed_event *ssfe;
struct sctp_queued_to_read *control;
- int length;
+ int notifhdr_len;
if ((stcb == NULL) ||
(sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
@@ -3106,26 +3652,25 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
return;
}
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
- length = sizeof(struct sctp_send_failed_event);
+ notifhdr_len = sizeof(struct sctp_send_failed_event);
} else {
- length = sizeof(struct sctp_send_failed);
+ notifhdr_len = sizeof(struct sctp_send_failed);
}
- m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA);
+ m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
/* no space left */
return;
}
- SCTP_BUF_LEN(m_notify) = 0;
+ SCTP_BUF_LEN(m_notify) = notifhdr_len;
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
ssfe = mtod(m_notify, struct sctp_send_failed_event *);
- memset(ssfe, 0, length);
+ memset(ssfe, 0, notifhdr_len);
ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
ssfe->ssfe_flags = SCTP_DATA_UNSENT;
- length += sp->length;
- ssfe->ssfe_length = length;
+ ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length);
ssfe->ssfe_error = error;
/* not exactly what the user sent in, but should be close :) */
- ssfe->ssfe_info.snd_sid = sp->stream;
+ ssfe->ssfe_info.snd_sid = sp->sid;
if (sp->some_taken) {
ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG;
} else {
@@ -3135,17 +3680,15 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
ssfe->ssfe_info.snd_context = sp->context;
ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event);
} else {
ssf = mtod(m_notify, struct sctp_send_failed *);
- memset(ssf, 0, length);
+ memset(ssf, 0, notifhdr_len);
ssf->ssf_type = SCTP_SEND_FAILED;
ssf->ssf_flags = SCTP_DATA_UNSENT;
- length += sp->length;
- ssf->ssf_length = length;
+ ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length);
ssf->ssf_error = error;
/* not exactly what the user sent in, but should be close :) */
- ssf->ssf_info.sinfo_stream = sp->stream;
+ ssf->ssf_info.sinfo_stream = sp->sid;
ssf->ssf_info.sinfo_ssn = 0;
if (sp->some_taken) {
ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
@@ -3156,7 +3699,6 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
ssf->ssf_info.sinfo_context = sp->context;
ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
ssf->ssf_assoc_id = sctp_get_associd(stcb);
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
}
SCTP_BUF_NEXT(m_notify) = sp->data;
@@ -3180,14 +3722,15 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
sctp_m_freem(m_notify);
return;
}
+ control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
}
-
-
static void
sctp_notify_adaptation_layer(struct sctp_tcb *stcb)
{
@@ -3238,11 +3781,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb)
/* This always must be called with the read-queue LOCKED in the INP */
static void
sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
- uint32_t val, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ uint32_t val, int so_locked)
{
struct mbuf *m_notify;
struct sctp_pdapi_event *pdapi;
@@ -3283,12 +3822,10 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
- control->held_length = 0;
- control->length = 0;
sb = &stcb->sctp_socket->so_rcv;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
@@ -3297,7 +3834,6 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0);
}
- atomic_add_int(&control->length, SCTP_BUF_LEN(m_notify));
control->end_added = 1;
if (stcb->asoc.control_pdapi)
TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
@@ -3307,7 +3843,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
}
if (stcb->sctp_ep && stcb->sctp_socket) {
/* This should always be the case */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -3324,7 +3860,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
}
#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -3346,7 +3882,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/* mark socket closed for read/write and wakeup! */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -3361,7 +3897,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
}
#endif
socantsendmore(stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -3393,8 +3929,8 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3404,11 +3940,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
static void
sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
- int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ int so_locked)
{
struct mbuf *m_notify;
struct sctp_sender_dry_event *event;
@@ -3453,7 +3985,6 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
}
-
void
sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag)
{
@@ -3501,8 +4032,8 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3551,8 +4082,8 @@ sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3560,8 +4091,6 @@ sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
}
-
-
static void
sctp_notify_stream_reset(struct sctp_tcb *stcb,
int number_entries, uint16_t * list, int flag)
@@ -3617,8 +4146,8 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3626,14 +4155,14 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
}
-
static void
sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
{
struct mbuf *m_notify;
struct sctp_remote_error *sre;
struct sctp_queued_to_read *control;
- size_t notif_len, chunk_len;
+ unsigned int notif_len;
+ uint16_t chunk_len;
if ((stcb == NULL) ||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
@@ -3641,14 +4170,21 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro
}
if (chunk != NULL) {
chunk_len = ntohs(chunk->ch.chunk_length);
+ /*
+ * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be
+ * contiguous.
+ */
+ if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) {
+ chunk_len = SCTP_CHUNK_BUFFER_SIZE;
+ }
} else {
chunk_len = 0;
}
- notif_len = sizeof(struct sctp_remote_error) + chunk_len;
+ notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
/* Retry with smaller value. */
- notif_len = sizeof(struct sctp_remote_error);
+ notif_len = (unsigned int)sizeof(struct sctp_remote_error);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
return;
@@ -3672,26 +4208,21 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
- control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
} else {
sctp_m_freem(m_notify);
}
}
-
void
sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
- uint32_t error, void *data, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ uint32_t error, void *data, int so_locked)
{
if ((stcb == NULL) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
@@ -3700,22 +4231,22 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
/* If the socket is gone we are out of here */
return;
}
-#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__)
+#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) {
#else
if (stcb->sctp_socket->so_state & SS_CANTRCVMORE) {
#endif
return;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep));
} else {
sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep));
}
#endif
- if ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) ||
- (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) ||
(notification == SCTP_NOTIFY_INTERFACE_UP) ||
(notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) {
@@ -3804,16 +4335,16 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
break;
}
case SCTP_NOTIFY_ASSOC_LOC_ABORTED:
- if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
- ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked);
} else {
sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked);
}
break;
case SCTP_NOTIFY_ASSOC_REM_ABORTED:
- if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
- ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked);
} else {
sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked);
@@ -3886,17 +4417,13 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
break;
default:
SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
- __FUNCTION__, notification, notification);
+ __func__, notification, notification);
break;
} /* end switch */
}
void
-sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int so_locked)
{
struct sctp_association *asoc;
struct sctp_stream_out *outs;
@@ -3912,7 +4439,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
/* already being freed */
return;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep));
} else {
@@ -3925,19 +4452,16 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
return;
}
/* now through all the gunk freeing chunks */
- if (holds_lock == 0) {
- SCTP_TCB_SEND_LOCK(stcb);
- }
/* sent queue SHOULD be empty */
TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
asoc->sent_queue_cnt--;
if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
- if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
#endif
}
}
@@ -3957,11 +4481,11 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
asoc->send_queue_cnt--;
- if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
- asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+ if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
#ifdef INVARIANTS
} else {
- panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+ panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
#endif
}
if (chk->data != NULL) {
@@ -3980,10 +4504,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
/* For each stream */
outs = &asoc->strmout[i];
/* clean up any sends there */
- asoc->locked_on_sending = NULL;
TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
- asoc->stream_queue_cnt--;
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&outs->outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1);
sctp_free_spbufspace(stcb, asoc, sp);
if (sp->data) {
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
@@ -4004,24 +4528,16 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
/*sa_ignore FREED_MEMORY*/
}
}
-
- if (holds_lock == 0) {
- SCTP_TCB_SEND_UNLOCK(stcb);
- }
}
void
sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error,
- struct sctp_abort_chunk *abort, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ struct sctp_abort_chunk *abort, int so_locked)
{
if (stcb == NULL) {
return;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep));
} else {
@@ -4038,8 +4554,11 @@ sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
return;
}
+ SCTP_TCB_SEND_LOCK(stcb);
+ SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED);
/* Tell them we lost the asoc */
- sctp_report_all_outbound(stcb, error, 1, so_locked);
+ sctp_report_all_outbound(stcb, error, so_locked);
+ SCTP_TCB_SEND_UNLOCK(stcb);
if (from_peer) {
sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked);
} else {
@@ -4052,13 +4571,13 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct mbuf *m, int iphlen,
struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, struct mbuf *op_err,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
uint32_t vrf_id, uint16_t port)
{
uint32_t vtag;
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
@@ -4068,16 +4587,15 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
vrf_id = stcb->asoc.vrf_id;
}
sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
if (stcb != NULL) {
/* We have a TCB to abort, send notification too */
sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
- stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
/* Ok, now lets free it */
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4086,12 +4604,13 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL+SCTP_LOC_4);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -4161,20 +4680,16 @@ sctp_print_out_track_log(struct sctp_tcb *stcb)
void
sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct mbuf *op_err,
- int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-)
+ int so_locked)
{
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
so = SCTP_INP_SO(inp);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
} else {
@@ -4185,14 +4700,14 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* Got to have a TCB */
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
if (LIST_EMPTY(&inp->sctp_asoc_list)) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
SCTP_SOCKET_LOCK(so, 1);
}
#endif
sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
SCTP_CALLED_DIRECTLY_NOCMPSET);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -4200,14 +4715,12 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
}
return;
- } else {
- stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
}
/* notify the peer */
sctp_send_abort_tcb(stcb, op_err, so_locked);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
/* notify the ulp */
@@ -4218,7 +4731,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4227,8 +4740,9 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
atomic_subtract_int(&stcb->asoc.refcnt, 1);
}
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL+SCTP_LOC_5);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -4240,8 +4754,8 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, struct sctp_inpcb *inp,
struct mbuf *cause,
-#if defined(__FreeBSD__)
- uint8_t mflowtype, uint32_t mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
#endif
uint32_t vrf_id, uint16_t port)
{
@@ -4253,12 +4767,12 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
/* Generate a TO address for future reference */
if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
if (LIST_EMPTY(&inp->sctp_asoc_list)) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 1);
#endif
sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
SCTP_CALLED_DIRECTLY_NOCMPSET);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
#endif
}
@@ -4290,8 +4804,8 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
return;
case SCTP_SHUTDOWN_ACK:
sctp_send_shutdown_complete2(src, dst, sh,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
return;
@@ -4306,8 +4820,8 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
(contains_init_chunk == 0))) {
sctp_send_abort(m, iphlen, src, dst, sh, 0, cause,
-#if defined(__FreeBSD__)
- mflowtype, mflowid,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
}
@@ -4493,7 +5007,7 @@ void
sctp_print_address(struct sockaddr *sa)
{
#ifdef INET6
-#if defined(__FreeBSD__) && __FreeBSD_version >= 700000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
char ip6buf[INET6_ADDRSTRLEN];
#endif
#endif
@@ -4518,7 +5032,7 @@ sctp_print_address(struct sockaddr *sa)
ntohs(sin6->sin6_port),
sin6->sin6_scope_id);
#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 700000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n",
ip6_sprintf(ip6buf, &sin6->sin6_addr),
ntohs(sin6->sin6_port),
@@ -4576,20 +5090,15 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
struct sctp_queued_to_read *control, *nctl;
struct sctp_readhead tmp_queue;
struct mbuf *m;
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
int error = 0;
+#endif
old_so = old_inp->sctp_socket;
new_so = new_inp->sctp_socket;
TAILQ_INIT(&tmp_queue);
-#if defined(__FreeBSD__) && __FreeBSD_version < 700000
- SOCKBUF_LOCK(&(old_so->so_rcv));
-#endif
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
error = sblock(&old_so->so_rcv, waitflags);
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 700000
- SOCKBUF_UNLOCK(&(old_so->so_rcv));
-#endif
if (error) {
/* Gak, can't get sblock, we have a problem.
* data will be left stranded.. and we
@@ -4603,6 +5112,7 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
*/
return;
}
+#endif
/* lock the socket buffers */
SCTP_INP_READ_LOCK(old_inp);
TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) {
@@ -4626,19 +5136,13 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
}
SCTP_INP_READ_UNLOCK(old_inp);
/* Remove the sb-lock on the old socket */
-#if defined(__FreeBSD__) && __FreeBSD_version < 700000
- SOCKBUF_LOCK(&(old_so->so_rcv));
-#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sbunlock(&old_so->so_rcv, 1);
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sbunlock(&old_so->so_rcv);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 700000
- SOCKBUF_UNLOCK(&(old_so->so_rcv));
-#endif
/* Now we move them over to the new socket buffer */
SCTP_INP_READ_LOCK(new_inp);
TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) {
@@ -4659,17 +5163,151 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
}
void
+sctp_wakeup_the_read_socket(struct sctp_inpcb *inp,
+ struct sctp_tcb *stcb,
+ int so_locked
+#if !(defined(__APPLE__) && !defined(__Userspace__))
+ SCTP_UNUSED
+#endif
+)
+{
+ if ((inp != NULL) && (inp->sctp_socket != NULL)) {
+#if defined(__APPLE__) && !defined(__Userspace__)
+ 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;
+ }
+ }
+#endif
+ sctp_sorwakeup(inp, inp->sctp_socket);
+#if defined(__APPLE__) && !defined(__Userspace__)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
+ }
+}
+#if defined(__Userspace__)
+
+void
+sctp_invoke_recv_callback(struct sctp_inpcb *inp,
+ struct sctp_tcb *stcb,
+ struct sctp_queued_to_read *control,
+ int inp_read_lock_held)
+{
+ uint32_t pd_point, length;
+
+ if ((inp->recv_callback == NULL) ||
+ (stcb == NULL) ||
+ (stcb->sctp_socket == NULL)) {
+ return;
+ }
+
+ length = control->length;
+ if (stcb != NULL && stcb->sctp_socket != NULL) {
+ pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
+ stcb->sctp_ep->partial_delivery_point);
+ } else {
+ pd_point = inp->partial_delivery_point;
+ }
+ if ((control->end_added == 1) || (length >= pd_point)) {
+ struct socket *so;
+ struct mbuf *m;
+ char *buffer;
+ struct sctp_rcvinfo rcv;
+ union sctp_sockstore addr;
+ int flags;
+
+ if ((buffer = malloc(length)) == NULL) {
+ return;
+ }
+ if (inp_read_lock_held == 0) {
+ SCTP_INP_READ_LOCK(inp);
+ }
+ so = stcb->sctp_socket;
+ for (m = control->data; m; m = SCTP_BUF_NEXT(m)) {
+ sctp_sbfree(control, control->stcb, &so->so_rcv, m);
+ }
+ m_copydata(control->data, 0, length, buffer);
+ memset(&rcv, 0, sizeof(struct sctp_rcvinfo));
+ rcv.rcv_sid = control->sinfo_stream;
+ rcv.rcv_ssn = (uint16_t)control->mid;
+ rcv.rcv_flags = control->sinfo_flags;
+ rcv.rcv_ppid = control->sinfo_ppid;
+ rcv.rcv_tsn = control->sinfo_tsn;
+ rcv.rcv_cumtsn = control->sinfo_cumtsn;
+ rcv.rcv_context = control->sinfo_context;
+ rcv.rcv_assoc_id = control->sinfo_assoc_id;
+ memset(&addr, 0, sizeof(union sctp_sockstore));
+ switch (control->whoFrom->ro._l_addr.sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ addr.sin = control->whoFrom->ro._l_addr.sin;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ addr.sin6 = control->whoFrom->ro._l_addr.sin6;
+ break;
+#endif
+ case AF_CONN:
+ addr.sconn = control->whoFrom->ro._l_addr.sconn;
+ break;
+ default:
+ addr.sa = control->whoFrom->ro._l_addr.sa;
+ break;
+ }
+ flags = 0;
+ if (control->end_added == 1) {
+ flags |= MSG_EOR;
+ }
+ if (control->spec_flags & M_NOTIFICATION) {
+ flags |= MSG_NOTIFICATION;
+ }
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ control->tail_mbuf = NULL;
+ control->length = 0;
+ if (control->end_added) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
+ control->on_read_q = 0;
+ sctp_free_remote_addr(control->whoFrom);
+ control->whoFrom = NULL;
+ sctp_free_a_readq(stcb, control);
+ }
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ if (inp_read_lock_held == 0) {
+ SCTP_INP_READ_UNLOCK(inp);
+ }
+ inp->recv_callback(so, addr, buffer, length, rcv, flags, inp->ulp_info);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ }
+}
+#endif
+
+void
sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_queued_to_read *control,
struct sockbuf *sb,
int end,
int inp_read_lock_held,
- int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ int so_locked)
{
/*
* Here we must place the control on the end of the socket read
@@ -4685,7 +5323,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
#endif
return;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(inp));
} else {
@@ -4695,12 +5333,14 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
if (inp_read_lock_held == 0)
SCTP_INP_READ_LOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
- sctp_free_remote_addr(control->whoFrom);
- if (control->data) {
- sctp_m_freem(control->data);
- control->data = NULL;
+ if (!control->on_strm_q) {
+ sctp_free_remote_addr(control->whoFrom);
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_free_a_readq(stcb, control);
}
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
if (inp_read_lock_held == 0)
SCTP_INP_READ_UNLOCK(inp);
return;
@@ -4745,8 +5385,10 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
control->tail_mbuf = prev;
} else {
/* Everything got collapsed out?? */
- sctp_free_remote_addr(control->whoFrom);
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
+ if (!control->on_strm_q) {
+ sctp_free_remote_addr(control->whoFrom);
+ sctp_free_a_readq(stcb, control);
+ }
if (inp_read_lock_held == 0)
SCTP_INP_READ_UNLOCK(inp);
return;
@@ -4754,347 +5396,18 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
if (end) {
control->end_added = 1;
}
-#if defined(__Userspace__)
- if (inp->recv_callback) {
- if (inp_read_lock_held == 0)
- SCTP_INP_READ_UNLOCK(inp);
- if (control->end_added == 1) {
- struct socket *so;
- struct mbuf *m;
- char *buffer;
- struct sctp_rcvinfo rcv;
- union sctp_sockstore addr;
- int flags;
-
- if ((buffer = malloc(control->length)) == NULL) {
- return;
- }
- so = stcb->sctp_socket;
- for (m = control->data; m; m = SCTP_BUF_NEXT(m)) {
- sctp_sbfree(control, control->stcb, &so->so_rcv, m);
- }
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- m_copydata(control->data, 0, control->length, buffer);
- memset(&rcv, 0, sizeof(struct sctp_rcvinfo));
- rcv.rcv_sid = control->sinfo_stream;
- rcv.rcv_ssn = control->sinfo_ssn;
- rcv.rcv_flags = control->sinfo_flags;
- rcv.rcv_ppid = control->sinfo_ppid;
- rcv.rcv_tsn = control->sinfo_tsn;
- rcv.rcv_cumtsn = control->sinfo_cumtsn;
- rcv.rcv_context = control->sinfo_context;
- rcv.rcv_assoc_id = control->sinfo_assoc_id;
- memset(&addr, 0, sizeof(union sctp_sockstore));
- switch (control->whoFrom->ro._l_addr.sa.sa_family) {
-#ifdef INET
- case AF_INET:
- addr.sin = control->whoFrom->ro._l_addr.sin;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- addr.sin6 = control->whoFrom->ro._l_addr.sin6;
- break;
-#endif
- case AF_CONN:
- addr.sconn = control->whoFrom->ro._l_addr.sconn;
- break;
- default:
- addr.sa = control->whoFrom->ro._l_addr.sa;
- break;
- }
- flags = MSG_EOR;
- if (control->spec_flags & M_NOTIFICATION) {
- flags |= MSG_NOTIFICATION;
- }
- inp->recv_callback(so, addr, buffer, control->length, rcv, flags, inp->ulp_info);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- sctp_free_remote_addr(control->whoFrom);
- control->whoFrom = NULL;
- sctp_m_freem(control->data);
- control->data = NULL;
- control->length = 0;
- sctp_free_a_readq(stcb, control);
- }
- return;
- }
-#endif
TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
+ control->on_read_q = 1;
if (inp_read_lock_held == 0)
SCTP_INP_READ_UNLOCK(inp);
- if (inp && inp->sctp_socket) {
- 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;
-
- 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;
- }
- }
-#endif
- sctp_sorwakeup(inp, inp->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- if (!so_locked) {
- SCTP_SOCKET_UNLOCK(so, 1);
- }
-#endif
- }
- }
-}
-
-
-int
-sctp_append_to_readq(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- struct sctp_queued_to_read *control,
- struct mbuf *m,
- int end,
- int ctls_cumack,
- struct sockbuf *sb)
-{
- /*
- * A partial delivery API event is underway. OR we are appending on
- * the reassembly queue.
- *
- * If PDAPI this means we need to add m to the end of the data.
- * Increase the length in the control AND increment the sb_cc.
- * Otherwise sb is NULL and all we need to do is put it at the end
- * of the mbuf chain.
- */
- int len = 0;
- struct mbuf *mm, *tail = NULL, *prev = NULL;
-
- if (inp) {
- SCTP_INP_READ_LOCK(inp);
- }
- if (control == NULL) {
- get_out:
- if (inp) {
- SCTP_INP_READ_UNLOCK(inp);
- }
- return (-1);
- }
- if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) {
- SCTP_INP_READ_UNLOCK(inp);
- return (0);
- }
- if (control->end_added) {
- /* huh this one is complete? */
- goto get_out;
- }
- mm = m;
- if (mm == NULL) {
- goto get_out;
- }
-
- while (mm) {
- if (SCTP_BUF_LEN(mm) == 0) {
- /* Skip mbufs with NO lenght */
- if (prev == NULL) {
- /* First one */
- m = sctp_m_free(mm);
- mm = m;
- } else {
- SCTP_BUF_NEXT(prev) = sctp_m_free(mm);
- mm = SCTP_BUF_NEXT(prev);
- }
- continue;
- }
- prev = mm;
- len += SCTP_BUF_LEN(mm);
- if (sb) {
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
- sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(mm));
- }
- sctp_sballoc(stcb, sb, mm);
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
- sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0);
- }
- }
- mm = SCTP_BUF_NEXT(mm);
- }
- if (prev) {
- tail = prev;
- } else {
- /* Really there should always be a prev */
- if (m == NULL) {
- /* Huh nothing left? */
-#ifdef INVARIANTS
- panic("Nothing left to add?");
-#else
- goto get_out;
-#endif
- }
- tail = m;
- }
- if (control->tail_mbuf) {
- /* append */
- SCTP_BUF_NEXT(control->tail_mbuf) = m;
- control->tail_mbuf = tail;
- } else {
- /* nothing there */
-#ifdef INVARIANTS
- if (control->data != NULL) {
- panic("This should NOT happen");
- }
-#endif
- control->data = m;
- control->tail_mbuf = tail;
- }
- atomic_add_int(&control->length, len);
- if (end) {
- /* message is complete */
- if (stcb && (control == stcb->asoc.control_pdapi)) {
- stcb->asoc.control_pdapi = NULL;
- }
- control->held_length = 0;
- control->end_added = 1;
- }
- if (stcb == NULL) {
- control->do_not_ref_stcb = 1;
- }
- /*
- * When we are appending in partial delivery, the cum-ack is used
- * for the actual pd-api highest tsn on this mbuf. The true cum-ack
- * is populated in the outbound sinfo structure from the true cumack
- * if the association exists...
- */
- control->sinfo_tsn = control->sinfo_cumtsn = ctls_cumack;
#if defined(__Userspace__)
- if (inp->recv_callback) {
- uint32_t pd_point, length;
-
- length = control->length;
- if (stcb != NULL && stcb->sctp_socket != NULL) {
- pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
- stcb->sctp_ep->partial_delivery_point);
- } else {
- pd_point = inp->partial_delivery_point;
- }
- if ((control->end_added == 1) || (length >= pd_point)) {
- struct socket *so;
- char *buffer;
- struct sctp_rcvinfo rcv;
- union sctp_sockstore addr;
- int flags;
-
- if ((buffer = malloc(control->length)) == NULL) {
- return (-1);
- }
- so = stcb->sctp_socket;
- for (m = control->data; m; m = SCTP_BUF_NEXT(m)) {
- sctp_sbfree(control, control->stcb, &so->so_rcv, m);
- }
- m_copydata(control->data, 0, control->length, buffer);
- memset(&rcv, 0, sizeof(struct sctp_rcvinfo));
- rcv.rcv_sid = control->sinfo_stream;
- rcv.rcv_ssn = control->sinfo_ssn;
- rcv.rcv_flags = control->sinfo_flags;
- rcv.rcv_ppid = control->sinfo_ppid;
- rcv.rcv_tsn = control->sinfo_tsn;
- rcv.rcv_cumtsn = control->sinfo_cumtsn;
- rcv.rcv_context = control->sinfo_context;
- rcv.rcv_assoc_id = control->sinfo_assoc_id;
- memset(&addr, 0, sizeof(union sctp_sockstore));
- switch (control->whoFrom->ro._l_addr.sa.sa_family) {
-#ifdef INET
- case AF_INET:
- addr.sin = control->whoFrom->ro._l_addr.sin;
- break;
+ sctp_invoke_recv_callback(inp, stcb, control, inp_read_lock_held);
#endif
-#ifdef INET6
- case AF_INET6:
- addr.sin6 = control->whoFrom->ro._l_addr.sin6;
- break;
-#endif
- case AF_CONN:
- addr.sconn = control->whoFrom->ro._l_addr.sconn;
- break;
- default:
- addr.sa = control->whoFrom->ro._l_addr.sa;
- break;
- }
- flags = 0;
- if (control->end_added == 1) {
- flags |= MSG_EOR;
- }
- if (control->spec_flags & M_NOTIFICATION) {
- flags |= MSG_NOTIFICATION;
- }
- sctp_m_freem(control->data);
- control->data = NULL;
- control->tail_mbuf = NULL;
- control->length = 0;
- if (control->end_added) {
- sctp_free_remote_addr(control->whoFrom);
- control->whoFrom = NULL;
- sctp_free_a_readq(stcb, control);
- } else {
- control->some_taken = 1;
- }
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- inp->recv_callback(so, addr, buffer, length, rcv, flags, inp->ulp_info);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- }
- if (inp)
- SCTP_INP_READ_UNLOCK(inp);
- return (0);
- }
-#endif
- if (inp) {
- SCTP_INP_READ_UNLOCK(inp);
- }
if (inp && inp->sctp_socket) {
- 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;
-
- so = SCTP_INP_SO(inp);
- 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 (0);
- }
-#endif
- sctp_sorwakeup(inp, inp->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- SCTP_SOCKET_UNLOCK(so, 1);
-#endif
- }
+ sctp_wakeup_the_read_socket(inp, stcb, so_locked);
}
- return (0);
}
-
-
/*************HOLD THIS COMMENT FOR PATCH FILE OF
*************ALTERNATE ROUTING CODE
*/
@@ -5108,19 +5421,23 @@ sctp_generate_cause(uint16_t code, char *info)
{
struct mbuf *m;
struct sctp_gen_error_cause *cause;
- size_t info_len, len;
+ size_t info_len;
+ uint16_t len;
if ((code == 0) || (info == NULL)) {
return (NULL);
}
info_len = strlen(info);
- len = sizeof(struct sctp_paramhdr) + info_len;
+ if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) {
+ return (NULL);
+ }
+ len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len);
m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
if (m != NULL) {
SCTP_BUF_LEN(m) = len;
cause = mtod(m, struct sctp_gen_error_cause *);
cause->code = htons(code);
- cause->length = htons((uint16_t)len);
+ cause->length = htons(len);
memcpy(cause->info, info, info_len);
}
return (m);
@@ -5131,16 +5448,16 @@ sctp_generate_no_user_data_cause(uint32_t tsn)
{
struct mbuf *m;
struct sctp_error_no_user_data *no_user_data_cause;
- size_t len;
+ uint16_t len;
- len = sizeof(struct sctp_error_no_user_data);
+ len = (uint16_t)sizeof(struct sctp_error_no_user_data);
m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
if (m != NULL) {
SCTP_BUF_LEN(m) = len;
no_user_data_cause = mtod(m, struct sctp_error_no_user_data *);
no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA);
- no_user_data_cause->cause.length = htons((uint16_t)len);
- no_user_data_cause->tsn = tsn; /* tsn is passed in as NBO */
+ no_user_data_cause->cause.length = htons(len);
+ no_user_data_cause->tsn = htonl(tsn);
}
return (m);
}
@@ -5173,7 +5490,6 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
} else {
stcb->sctp_socket->so_snd.sb_cc = 0;
-
}
}
}
@@ -5182,43 +5498,40 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
- uint8_t sent, int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- )
+ uint8_t sent, int so_locked)
{
struct sctp_stream_out *strq;
struct sctp_tmit_chunk *chk = NULL, *tp2;
struct sctp_stream_queue_pending *sp;
- uint16_t stream = 0, seq = 0;
+ uint32_t mid;
+ uint16_t sid;
uint8_t foundeom = 0;
int ret_sz = 0;
int notdone;
int do_wakeup_routine = 0;
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep));
} else {
sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep));
}
#endif
- stream = tp1->rec.data.stream_number;
- seq = tp1->rec.data.stream_seq;
+ sid = tp1->rec.data.sid;
+ mid = tp1->rec.data.mid;
if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) {
stcb->asoc.abandoned_sent[0]++;
stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
- stcb->asoc.strmout[stream].abandoned_sent[0]++;
+ 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[stream].abandoned_unsent[0]++;
+ 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 {
@@ -5270,8 +5583,8 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
* sent queue.
*/
TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) {
- if ((tp1->rec.data.stream_number != stream) ||
- (tp1->rec.data.stream_seq != seq)) {
+ if ((tp1->rec.data.sid != sid) ||
+ (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) {
break;
}
/* save to chk in case we have some on stream out
@@ -5311,7 +5624,7 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
* is stuff left on the stream out queue.. yuck.
*/
SCTP_TCB_SEND_LOCK(stcb);
- strq = &stcb->asoc.strmout[stream];
+ strq = &stcb->asoc.strmout[sid];
sp = TAILQ_FIRST(&strq->outqueue);
if (sp != NULL) {
sp->discard_rest = 1;
@@ -5333,28 +5646,52 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
goto oh_well;
}
memset(chk, 0, sizeof(*chk));
- chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG;
+ chk->rec.data.rcv_flags = 0;
chk->sent = SCTP_FORWARD_TSN_SKIP;
chk->asoc = &stcb->asoc;
- chk->rec.data.stream_seq = strq->next_sequence_send;
- chk->rec.data.stream_number = sp->stream;
- chk->rec.data.payloadtype = sp->ppid;
+ if (stcb->asoc.idata_supported == 0) {
+ if (sp->sinfo_flags & SCTP_UNORDERED) {
+ chk->rec.data.mid = 0;
+ } else {
+ chk->rec.data.mid = strq->next_mid_ordered;
+ }
+ } else {
+ if (sp->sinfo_flags & SCTP_UNORDERED) {
+ chk->rec.data.mid = strq->next_mid_unordered;
+ } else {
+ chk->rec.data.mid = strq->next_mid_ordered;
+ }
+ }
+ chk->rec.data.sid = sp->sid;
+ chk->rec.data.ppid = sp->ppid;
chk->rec.data.context = sp->context;
chk->flags = sp->act_flags;
chk->whoTo = NULL;
-#if defined(__FreeBSD__) || defined(__Panda__)
- chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
#else
- chk->rec.data.TSN_seq = stcb->asoc.sending_seq++;
+ chk->rec.data.tsn = stcb->asoc.sending_seq++;
#endif
strq->chunks_on_queues++;
TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
stcb->asoc.sent_queue_cnt++;
stcb->asoc.pr_sctp_cnt++;
+ }
+ chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
+ if (sp->sinfo_flags & SCTP_UNORDERED) {
+ chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED;
+ }
+ if (stcb->asoc.idata_supported == 0) {
+ if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) {
+ strq->next_mid_ordered++;
+ }
} else {
- chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
+ if (sp->sinfo_flags & SCTP_UNORDERED) {
+ strq->next_mid_unordered++;
+ } else {
+ strq->next_mid_ordered++;
+ }
}
- strq->next_sequence_send++;
oh_well:
if (sp->data) {
/* Pull any data to free up the SB and
@@ -5374,7 +5711,7 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
SCTP_TCB_SEND_UNLOCK(stcb);
}
if (do_wakeup_routine) {
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -5392,7 +5729,7 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
}
#endif
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) && !defined(__Userspace__)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -5427,10 +5764,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
laddr->ifa->address.sin.sin_addr.s_addr) {
/* found him. */
- if (holds_lock == 0) {
- SCTP_INP_RUNLOCK(inp);
- }
- return (laddr->ifa);
break;
}
}
@@ -5440,10 +5773,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
&laddr->ifa->address.sin6)) {
/* found him. */
- if (holds_lock == 0) {
- SCTP_INP_RUNLOCK(inp);
- }
- return (laddr->ifa);
break;
}
}
@@ -5452,10 +5781,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
if (addr->sa_family == AF_CONN) {
if (((struct sockaddr_conn *)addr)->sconn_addr == laddr->ifa->address.sconn.sconn_addr) {
/* found him. */
- if (holds_lock == 0) {
- SCTP_INP_RUNLOCK(inp);
- }
- return (laddr->ifa);
break;
}
}
@@ -5464,7 +5789,11 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
if (holds_lock == 0) {
SCTP_INP_RUNLOCK(inp);
}
- return (NULL);
+ if (laddr != NULL) {
+ return (laddr->ifa);
+ } else {
+ return (NULL);
+ }
}
uint32_t
@@ -5487,7 +5816,7 @@ sctp_get_ifa_hash_val(struct sockaddr *addr)
uint32_t hash_of_addr;
sin6 = (struct sockaddr_in6 *)addr;
-#if !defined(__Windows__) && !defined(__Userspace_os_FreeBSD) && !defined(__Userspace_os_Darwin) && !defined(__Userspace_os_Windows)
+#if !defined(_WIN32) && !(defined(__FreeBSD__) && defined(__Userspace__)) && !defined(__APPLE__)
hash_of_addr = (sin6->sin6_addr.s6_addr32[0] +
sin6->sin6_addr.s6_addr32[1] +
sin6->sin6_addr.s6_addr32[2] +
@@ -5527,8 +5856,11 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
struct sctp_ifalist *hash_head;
uint32_t hash_of_addr;
- if (holds_lock == 0)
+ if (holds_lock == 0) {
SCTP_IPI_ADDR_RLOCK();
+ } else {
+ SCTP_IPI_ADDR_LOCK_ASSERT();
+ }
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
@@ -5559,9 +5891,6 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
sctp_ifap->address.sin.sin_addr.s_addr) {
/* found him. */
- if (holds_lock == 0)
- SCTP_IPI_ADDR_RUNLOCK();
- return (sctp_ifap);
break;
}
}
@@ -5571,9 +5900,6 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
&sctp_ifap->address.sin6)) {
/* found him. */
- if (holds_lock == 0)
- SCTP_IPI_ADDR_RUNLOCK();
- return (sctp_ifap);
break;
}
}
@@ -5582,9 +5908,6 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
if (addr->sa_family == AF_CONN) {
if (((struct sockaddr_conn *)addr)->sconn_addr == sctp_ifap->address.sconn.sconn_addr) {
/* found him. */
- if (holds_lock == 0)
- SCTP_IPI_ADDR_RUNLOCK();
- return (sctp_ifap);
break;
}
}
@@ -5592,7 +5915,7 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
}
if (holds_lock == 0)
SCTP_IPI_ADDR_RUNLOCK();
- return (NULL);
+ return (sctp_ifap);
}
static void
@@ -5600,6 +5923,9 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock,
uint32_t rwnd_req)
{
/* User pulled some data, do we need a rwnd update? */
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
int r_unlocked = 0;
uint32_t dif, rwnd;
struct socket *so = NULL;
@@ -5609,9 +5935,8 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock,
atomic_add_int(&stcb->asoc.refcnt, 1);
- if (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED |
- SCTP_STATE_SHUTDOWN_RECEIVED |
- SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
+ (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | SCTP_STATE_SHUTDOWN_RECEIVED))) {
/* Pre-check If we are freeing no update */
goto no_lock;
}
@@ -5656,12 +5981,19 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock,
goto out;
}
SCTP_STAT_INCR(sctps_wu_sacks_sent);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_send_sack(stcb, SCTP_SO_LOCKED);
sctp_chunk_output(stcb->sctp_ep, stcb,
SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
/* make sure no timer is running */
- sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL+SCTP_LOC_6);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_6);
SCTP_TCB_UNLOCK(stcb);
} else {
/* Update how much we have pending */
@@ -5697,8 +6029,9 @@ sctp_sorecvmsg(struct socket *so,
*
*/
struct sctp_inpcb *inp = NULL;
- int my_len = 0;
- int cp_len = 0, error = 0;
+ ssize_t my_len = 0;
+ ssize_t cp_len = 0;
+ int error = 0;
struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL;
struct mbuf *m = NULL;
struct sctp_tcb *stcb = NULL;
@@ -5707,15 +6040,15 @@ sctp_sorecvmsg(struct socket *so,
int out_flags = 0, in_flags = 0;
int block_allowed = 1;
uint32_t freed_so_far = 0;
- uint32_t copied_so_far = 0;
+ ssize_t copied_so_far = 0;
int in_eeor_mode = 0;
int no_rcv_needed = 0;
uint32_t rwnd_req = 0;
int hold_sblock = 0;
int hold_rlock = 0;
- int slen = 0;
+ ssize_t slen = 0;
uint32_t held_length = 0;
-#if defined(__FreeBSD__) && __FreeBSD_version >= 700000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
int sockbuf_lock = 0;
#endif
@@ -5731,7 +6064,7 @@ sctp_sorecvmsg(struct socket *so,
} else {
in_flags = 0;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
slen = uio->uio_resid;
#else
@@ -5751,7 +6084,7 @@ sctp_sorecvmsg(struct socket *so,
return (EINVAL);
}
if ((in_flags & (MSG_DONTWAIT
-#if defined(__FreeBSD__) && __FreeBSD_version > 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
| MSG_NBIO
#endif
)) ||
@@ -5770,7 +6103,7 @@ sctp_sorecvmsg(struct socket *so,
rwnd_req = SCTP_MIN_RWND;
in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
sctp_misc_ints(SCTP_SORECV_ENTER,
rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid);
@@ -5780,15 +6113,15 @@ sctp_sorecvmsg(struct socket *so,
#endif
#else
sctp_misc_ints(SCTP_SORECV_ENTER,
- rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid);
+ rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid);
#endif
}
-#if (defined(__FreeBSD__) && __FreeBSD_version < 700000) || defined(__Userspace__)
+#if defined(__Userspace__)
SOCKBUF_LOCK(&so->so_rcv);
hold_sblock = 1;
#endif
if (SCTP_BASE_SYSCTL(sctp_logging_level) &SCTP_RECV_RWND_LOGGING_ENABLE) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
sctp_misc_ints(SCTP_SORECV_ENTERPL,
rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
@@ -5798,38 +6131,33 @@ sctp_sorecvmsg(struct socket *so,
#endif
#else
sctp_misc_ints(SCTP_SORECV_ENTERPL,
- rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
+ rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid);
#endif
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags));
#endif
-
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
#endif
if (error) {
goto release_unlocked;
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 700000
- sockbuf_lock = 1;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ sockbuf_lock = 1;
#endif
restart:
-#if (defined(__FreeBSD__) && __FreeBSD_version < 700000) || defined(__Userspace__)
+#if defined(__Userspace__)
if (hold_sblock == 0) {
SOCKBUF_LOCK(&so->so_rcv);
hold_sblock = 1;
}
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sbunlock(&so->so_rcv, 1);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 700000
- sbunlock(&so->so_rcv);
-#endif
-
restart_nosblocks:
if (hold_sblock == 0) {
SOCKBUF_LOCK(&so->so_rcv);
@@ -5839,7 +6167,7 @@ sctp_sorecvmsg(struct socket *so,
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
goto out;
}
-#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__)
+#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
#else
if ((so->so_state & SS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
@@ -5857,8 +6185,14 @@ sctp_sorecvmsg(struct socket *so,
}
}
}
- if ((so->so_rcv.sb_cc <= held_length) && block_allowed) {
- /* we need to wait for data */
+ if (so->so_rcv.sb_cc <= held_length) {
+ if (so->so_error) {
+ error = so->so_error;
+ if ((in_flags & MSG_PEEK) == 0) {
+ so->so_error = 0;
+ }
+ goto out;
+ }
if ((so->so_rcv.sb_cc == 0) &&
((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
@@ -5884,57 +6218,26 @@ sctp_sorecvmsg(struct socket *so,
goto out;
}
}
- error = sbwait(&so->so_rcv);
- if (error) {
- goto out;
- }
- held_length = 0;
- goto restart_nosblocks;
- } else if (so->so_rcv.sb_cc == 0) {
- if (so->so_error) {
- error = so->so_error;
- if ((in_flags & MSG_PEEK) == 0)
- so->so_error = 0;
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
- /* For active open side clear flags for re-use
- * passive open is blocked by connect.
- */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) {
- /* You were aborted, passive side always hits here */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
- error = ECONNRESET;
- }
- so->so_state &= ~(SS_ISCONNECTING |
- SS_ISDISCONNECTING |
- SS_ISCONFIRMING |
- SS_ISCONNECTED);
- if (error == 0) {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
- error = ENOTCONN;
- }
- }
- goto out;
- }
+ if (block_allowed) {
+ error = sbwait(&so->so_rcv);
+ if (error) {
+ goto out;
}
+ held_length = 0;
+ goto restart_nosblocks;
+ } else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK);
error = EWOULDBLOCK;
+ goto out;
}
- goto out;
}
if (hold_sblock == 1) {
SOCKBUF_UNLOCK(&so->so_rcv);
hold_sblock = 0;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags));
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 700000
- error = sblock(&so->so_rcv, (block_allowed ? M_WAITOK : 0));
-#endif
/* we possibly have data we can read */
/*sa_ignore FREED_MEMORY*/
control = TAILQ_FIRST(&inp->read_queue);
@@ -6017,6 +6320,12 @@ sctp_sorecvmsg(struct socket *so,
sctp_m_free (control->aux_data);
control->aux_data = NULL;
}
+#ifdef INVARIANTS
+ if (control->on_strm_q) {
+ panic("About to free ctl:%p so:%p and its in %d",
+ control, so, control->on_strm_q);
+ }
+#endif
sctp_free_remote_addr(control->whoFrom);
sctp_free_a_readq(stcb, control);
if (hold_rlock) {
@@ -6077,20 +6386,16 @@ sctp_sorecvmsg(struct socket *so,
}
/* Clear the held length since there is something to read */
control->held_length = 0;
- if (hold_rlock) {
- SCTP_INP_READ_UNLOCK(inp);
- hold_rlock = 0;
- }
found_one:
/*
* If we reach here, control has a some data for us to read off.
* Note that stcb COULD be NULL.
*/
- control->some_taken++;
- if (hold_sblock) {
- SOCKBUF_UNLOCK(&so->so_rcv);
- hold_sblock = 0;
+ if (hold_rlock == 0) {
+ hold_rlock = 1;
+ SCTP_INP_READ_LOCK(inp);
}
+ control->some_taken++;
stcb = control->stcb;
if (stcb) {
if ((control->do_not_ref_stcb == 0) &&
@@ -6124,10 +6429,10 @@ sctp_sorecvmsg(struct socket *so,
* we then will go to the sctp_user_rcvd() that will
* not lock until it KNOWs it MUST send a WUP-SACK.
*/
- freed_so_far = stcb->freed_by_sorcv_sincelast;
+ freed_so_far = (uint32_t)stcb->freed_by_sorcv_sincelast;
stcb->freed_by_sorcv_sincelast = 0;
}
- }
+ }
if (stcb &&
((control->spec_flags & M_NOTIFICATION) == 0) &&
control->do_not_ref_stcb == 0) {
@@ -6135,8 +6440,16 @@ sctp_sorecvmsg(struct socket *so,
}
/* First lets get off the sinfo and sockaddr info */
- if ((sinfo) && filling_sinfo) {
- memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo));
+ if ((sinfo != NULL) && (filling_sinfo != 0)) {
+ sinfo->sinfo_stream = control->sinfo_stream;
+ sinfo->sinfo_ssn = (uint16_t)control->mid;
+ sinfo->sinfo_flags = control->sinfo_flags;
+ sinfo->sinfo_ppid = control->sinfo_ppid;
+ sinfo->sinfo_context =control->sinfo_context;
+ sinfo->sinfo_timetolive = control->sinfo_timetolive;
+ sinfo->sinfo_tsn = control->sinfo_tsn;
+ sinfo->sinfo_cumtsn = control->sinfo_cumtsn;
+ sinfo->sinfo_assoc_id = control->sinfo_assoc_id;
nxt = TAILQ_NEXT(control, next);
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
@@ -6144,20 +6457,20 @@ sctp_sorecvmsg(struct socket *so,
s_extra = (struct sctp_extrcvinfo *)sinfo;
if ((nxt) &&
(nxt->length)) {
- s_extra->sreinfo_next_flags = SCTP_NEXT_MSG_AVAIL;
+ s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL;
if (nxt->sinfo_flags & SCTP_UNORDERED) {
- s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
+ s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
}
if (nxt->spec_flags & M_NOTIFICATION) {
- s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
+ s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
}
- s_extra->sreinfo_next_aid = nxt->sinfo_assoc_id;
- s_extra->sreinfo_next_length = nxt->length;
- s_extra->sreinfo_next_ppid = nxt->sinfo_ppid;
- s_extra->sreinfo_next_stream = nxt->sinfo_stream;
+ s_extra->serinfo_next_aid = nxt->sinfo_assoc_id;
+ s_extra->serinfo_next_length = nxt->length;
+ s_extra->serinfo_next_ppid = nxt->sinfo_ppid;
+ s_extra->serinfo_next_stream = nxt->sinfo_stream;
if (nxt->tail_mbuf != NULL) {
if (nxt->end_added) {
- s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
+ s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
}
}
} else {
@@ -6166,11 +6479,11 @@ sctp_sorecvmsg(struct socket *so,
* that is on the control's structure :-D
*/
nxt = NULL;
- s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG;
- s_extra->sreinfo_next_aid = 0;
- s_extra->sreinfo_next_length = 0;
- s_extra->sreinfo_next_ppid = 0;
- s_extra->sreinfo_next_stream = 0;
+ s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
+ s_extra->serinfo_next_aid = 0;
+ s_extra->serinfo_next_length = 0;
+ s_extra->serinfo_next_ppid = 0;
+ s_extra->serinfo_next_stream = 0;
}
}
/*
@@ -6201,7 +6514,7 @@ sctp_sorecvmsg(struct socket *so,
entry = &inp->readlog[index];
entry->vtag = control->sinfo_assoc_id;
entry->strm = control->sinfo_stream;
- entry->seq = control->sinfo_ssn;
+ entry->seq = (uint16_t)control->mid;
entry->sz = control->length;
entry->flgs = control->sinfo_flags;
}
@@ -6261,6 +6574,14 @@ sctp_sorecvmsg(struct socket *so,
#endif
#endif
}
+ if (hold_rlock) {
+ SCTP_INP_READ_UNLOCK(inp);
+ hold_rlock = 0;
+ }
+ if (hold_sblock) {
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ hold_sblock = 0;
+ }
/* now copy out what data we can */
if (mp == NULL) {
/* copy out each mbuf in the chain up to length */
@@ -6268,16 +6589,16 @@ sctp_sorecvmsg(struct socket *so,
m = control->data;
while (m) {
/* Move out all we can */
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
- cp_len = (int)uio->uio_resid;
+ cp_len = uio->uio_resid;
#else
- cp_len = (int)uio_resid(uio);
+ cp_len = uio_resid(uio);
#endif
#else
- cp_len = (int)uio->uio_resid;
+ cp_len = uio->uio_resid;
#endif
- my_len = (int)SCTP_BUF_LEN(m);
+ my_len = SCTP_BUF_LEN(m);
if (cp_len > my_len) {
/* not enough in this buf */
cp_len = my_len;
@@ -6286,12 +6607,12 @@ sctp_sorecvmsg(struct socket *so,
SCTP_INP_READ_UNLOCK(inp);
hold_rlock = 0;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 0);
#endif
if (cp_len > 0)
- error = uiomove(mtod(m, char *), cp_len, uio);
-#if defined(__APPLE__)
+ error = uiomove(mtod(m, char *), (int)cp_len, uio);
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(so, 0);
#endif
/* re-read */
@@ -6307,15 +6628,8 @@ sctp_sorecvmsg(struct socket *so,
/* error we are out of here */
goto release;
}
- if ((SCTP_BUF_NEXT(m) == NULL) &&
- (cp_len >= SCTP_BUF_LEN(m)) &&
- ((control->end_added == 0) ||
- (control->end_added &&
- (TAILQ_NEXT(control, next) == NULL)))
- ) {
- SCTP_INP_READ_LOCK(inp);
- hold_rlock = 1;
- }
+ SCTP_INP_READ_LOCK(inp);
+ hold_rlock = 1;
if (cp_len == SCTP_BUF_LEN(m)) {
if ((SCTP_BUF_NEXT(m)== NULL) &&
(control->end_added)) {
@@ -6345,7 +6659,7 @@ sctp_sorecvmsg(struct socket *so,
control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0);
}
copied_so_far += cp_len;
- freed_so_far += cp_len;
+ freed_so_far += (uint32_t)cp_len;
freed_so_far += MSIZE;
atomic_subtract_int(&control->length, cp_len);
control->data = sctp_m_free(m);
@@ -6353,7 +6667,7 @@ sctp_sorecvmsg(struct socket *so,
/* been through it all, must hold sb lock ok to null tail */
if (control->data == NULL) {
#ifdef INVARIANTS
-#if !defined(__APPLE__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if ((control->end_added == 0) ||
(TAILQ_NEXT(control, next) == NULL)) {
/* If the end is not added, OR the
@@ -6380,9 +6694,9 @@ sctp_sorecvmsg(struct socket *so,
}
if ((in_flags & MSG_PEEK) == 0) {
SCTP_BUF_RESV_UF(m, cp_len);
- SCTP_BUF_LEN(m) -= cp_len;
+ SCTP_BUF_LEN(m) -= (int)cp_len;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
- sctp_sblog(&so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE, cp_len);
+ sctp_sblog(&so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE, (int)cp_len);
}
atomic_subtract_int(&so->so_rcv.sb_cc, cp_len);
if ((control->do_not_ref_stcb == 0) &&
@@ -6390,7 +6704,7 @@ sctp_sorecvmsg(struct socket *so,
atomic_subtract_int(&stcb->asoc.sb_cc, cp_len);
}
copied_so_far += cp_len;
- freed_so_far += cp_len;
+ freed_so_far += (uint32_t)cp_len;
freed_so_far += MSIZE;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(&so->so_rcv, control->do_not_ref_stcb?NULL:stcb,
@@ -6401,7 +6715,7 @@ sctp_sorecvmsg(struct socket *so,
copied_so_far += cp_len;
}
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) {
#else
@@ -6436,17 +6750,9 @@ sctp_sorecvmsg(struct socket *so,
#endif
}
done_with_control:
- if (TAILQ_NEXT(control, next) == NULL) {
- /* If we don't have a next we need a
- * lock, if there is a next interrupt
- * is filling ahead of us and we don't
- * need a lock to remove this guy
- * (which is the head of the queue).
- */
- if (hold_rlock == 0) {
- SCTP_INP_READ_LOCK(inp);
- hold_rlock = 1;
- }
+ if (hold_rlock == 0) {
+ SCTP_INP_READ_LOCK(inp);
+ hold_rlock = 1;
}
TAILQ_REMOVE(&inp->read_queue, control, next);
/* Add back any hiddend data */
@@ -6462,6 +6768,12 @@ sctp_sorecvmsg(struct socket *so,
no_rcv_needed = control->do_not_ref_stcb;
sctp_free_remote_addr(control->whoFrom);
control->data = NULL;
+#ifdef INVARIANTS
+ if (control->on_strm_q) {
+ panic("About to free ctl:%p so:%p and its in %d",
+ control, so, control->on_strm_q);
+ }
+#endif
sctp_free_a_readq(stcb, control);
control = NULL;
if ((freed_so_far >= rwnd_req) &&
@@ -6489,7 +6801,7 @@ sctp_sorecvmsg(struct socket *so,
if (out_flags & MSG_EOR) {
goto release;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
if ((uio->uio_resid == 0) ||
#else
@@ -6499,7 +6811,7 @@ sctp_sorecvmsg(struct socket *so,
if ((uio->uio_resid == 0) ||
#endif
((in_eeor_mode) &&
- (copied_so_far >= (uint32_t)max(so->so_rcv.sb_lowat, 1)))) {
+ (copied_so_far >= max(so->so_rcv.sb_lowat, 1)))) {
goto release;
}
/*
@@ -6527,7 +6839,7 @@ sctp_sorecvmsg(struct socket *so,
sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
}
wait_some_more:
-#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__)
+#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
goto release;
}
@@ -6552,13 +6864,13 @@ sctp_sorecvmsg(struct socket *so,
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) {
goto release;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sbunlock(&so->so_rcv, 1);
#endif
if (so->so_rcv.sb_cc <= control->held_length) {
error = sbwait(&so->so_rcv);
if (error) {
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
goto release;
#else
goto release_unlocked;
@@ -6566,7 +6878,7 @@ sctp_sorecvmsg(struct socket *so,
}
control->held_length = 0;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags));
#endif
if (hold_sblock) {
@@ -6638,7 +6950,7 @@ sctp_sorecvmsg(struct socket *so,
if (control->spec_flags & M_NOTIFICATION) {
out_flags |= MSG_NOTIFICATION;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
uio->uio_resid = control->length;
#else
@@ -6655,7 +6967,7 @@ sctp_sorecvmsg(struct socket *so,
control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
}
sctp_sbfree(control, stcb, &so->so_rcv, m);
- freed_so_far += SCTP_BUF_LEN(m);
+ freed_so_far += (uint32_t)SCTP_BUF_LEN(m);
freed_so_far += MSIZE;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(&so->so_rcv,
@@ -6675,7 +6987,7 @@ sctp_sorecvmsg(struct socket *so,
SCTP_INP_READ_UNLOCK(inp);
hold_rlock = 0;
}
-#if (defined(__FreeBSD__) && __FreeBSD_version < 700000) || defined(__Userspace__)
+#if defined(__Userspace__)
if (hold_sblock == 0) {
SOCKBUF_LOCK(&so->so_rcv);
hold_sblock = 1;
@@ -6686,16 +6998,14 @@ sctp_sorecvmsg(struct socket *so,
hold_sblock = 0;
}
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
sbunlock(&so->so_rcv, 1);
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sbunlock(&so->so_rcv);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 700000
sockbuf_lock = 0;
#endif
-#endif
release_unlocked:
if (hold_sblock) {
@@ -6719,7 +7029,7 @@ sctp_sorecvmsg(struct socket *so,
sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) {
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
- s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG;
+ s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
}
if (hold_rlock == 1) {
SCTP_INP_READ_UNLOCK(inp);
@@ -6727,7 +7037,7 @@ sctp_sorecvmsg(struct socket *so,
if (hold_sblock) {
SOCKBUF_UNLOCK(&so->so_rcv);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 700000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (sockbuf_lock) {
sbunlock(&so->so_rcv);
}
@@ -6748,36 +7058,36 @@ sctp_sorecvmsg(struct socket *so,
goto stage_left;
#endif
}
- atomic_add_int(&stcb->asoc.refcnt, -1);
/* Save the value back for next time */
stcb->freed_by_sorcv_sincelast = freed_so_far;
+ atomic_add_int(&stcb->asoc.refcnt, -1);
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) &SCTP_RECV_RWND_LOGGING_ENABLE) {
if (stcb) {
sctp_misc_ints(SCTP_SORECV_DONE,
freed_so_far,
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
((uio) ? (slen - uio->uio_resid) : slen),
#else
((uio) ? (slen - uio_resid(uio)) : slen),
#endif
#else
- ((uio) ? (slen - uio->uio_resid) : slen),
+ (uint32_t)((uio) ? (slen - uio->uio_resid) : slen),
#endif
stcb->asoc.my_rwnd,
so->so_rcv.sb_cc);
} else {
sctp_misc_ints(SCTP_SORECV_DONE,
freed_so_far,
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
#if defined(APPLE_LEOPARD)
((uio) ? (slen - uio->uio_resid) : slen),
#else
((uio) ? (slen - uio_resid(uio)) : slen),
#endif
#else
- ((uio) ? (slen - uio->uio_resid) : slen),
+ (uint32_t)((uio) ? (slen - uio->uio_resid) : slen),
#endif
0,
so->so_rcv.sb_cc);
@@ -6790,7 +7100,6 @@ sctp_sorecvmsg(struct socket *so,
return (error);
}
-
#ifdef SCTP_MBUF_LOGGING
struct mbuf *
sctp_m_free(struct mbuf *m)
@@ -6801,7 +7110,8 @@ sctp_m_free(struct mbuf *m)
return (m_free(m));
}
-void sctp_m_freem(struct mbuf *mb)
+void
+sctp_m_freem(struct mbuf *mb)
{
while (mb != NULL)
mb = sctp_m_free(mb);
@@ -6818,7 +7128,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
struct sctp_ifa *ifa;
struct sctp_laddr *wi;
- ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
if (ifa == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
return (EADDRNOTAVAIL);
@@ -6833,7 +7143,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
}
/* Now incr the count and int wi structure */
SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
+ memset(wi, 0, sizeof(*wi));
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
wi->ifa = ifa;
wi->action = SCTP_SET_PRIM_ADDR;
@@ -6846,18 +7156,17 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
* 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);
}
#if defined(__Userspace__)
/* no sctp_soreceive for __Userspace__ now */
#endif
-
#if !defined(__Userspace__)
int
sctp_soreceive( struct socket *so,
@@ -6872,6 +7181,7 @@ sctp_soreceive( struct socket *so,
struct sockaddr *from;
struct sctp_extrcvinfo sinfo;
int filling_sinfo = 1;
+ int flags;
struct sctp_inpcb *inp;
inp = (struct sctp_inpcb *)so->so_pcb;
@@ -6898,21 +7208,30 @@ sctp_soreceive( struct socket *so,
fromlen = 0;
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_LOCK(so, 1);
#endif
if (filling_sinfo) {
memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo));
}
- error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, flagsp,
+ if (flagsp != NULL) {
+ flags = *flagsp;
+ } else {
+ flags = 0;
+ }
+ error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags,
(struct sctp_sndrcvinfo *)&sinfo, filling_sinfo);
+ if (flagsp != NULL) {
+ *flagsp = flags;
+ }
if (controlp != NULL) {
/* copy back the sinfo in a CMSG format */
- if (filling_sinfo)
+ if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) {
*controlp = sctp_build_ctl_nchunk(inp,
(struct sctp_sndrcvinfo *)&sinfo);
- else
+ } else {
*controlp = NULL;
+ }
}
if (psa) {
/* copy back the address info */
@@ -6921,7 +7240,7 @@ sctp_soreceive( struct socket *so,
#else
if (from) {
#endif
-#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__)
+#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
*psa = sodupsockaddr(from, M_NOWAIT);
#else
*psa = dup_sockaddr(from, mp0 == 0);
@@ -6930,14 +7249,13 @@ sctp_soreceive( struct socket *so,
*psa = NULL;
}
}
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
return (error);
}
-
-#if (defined(__FreeBSD__) && __FreeBSD_version < 603000) || defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
/*
* General routine to allocate a hash table with control of memory flags.
* is in 7.0 and beyond for sure :-)
@@ -6984,7 +7302,6 @@ sctp_hashinit_flags(int elements, struct malloc_type *type,
return (hashtbl);
}
#endif
-
#else /* __Userspace__ ifdef above sctp_soreceive */
/*
* __Userspace__ Defining sctp_hashinit_flags() and sctp_hashdestroy() for userland.
@@ -7035,7 +7352,6 @@ sctp_hashinit_flags(int elements, struct malloc_type *type,
return (hashtbl);
}
-
void
sctp_hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
{
@@ -7050,7 +7366,6 @@ sctp_hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
FREE(hashtbl, type);
}
-
void
sctp_hashfreedestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
{
@@ -7075,10 +7390,7 @@ sctp_hashfreedestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
FREE(hashtbl, type);
}
-
#endif
-
-
int
sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
int totaddr, int *error)
@@ -7108,14 +7420,18 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
(sin->sin_addr.s_addr == INADDR_BROADCAST) ||
IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_7);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_7);
*error = EINVAL;
goto out_now;
}
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
+ SCTP_DONOT_SETSCOPE,
+ SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_7);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_8);
*error = ENOBUFS;
goto out_now;
}
@@ -7129,14 +7445,18 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_8);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_9);
*error = EINVAL;
goto out_now;
}
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
+ SCTP_DONOT_SETSCOPE,
+ SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_8);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_10);
*error = ENOBUFS;
goto out_now;
}
@@ -7145,11 +7465,14 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
#endif
#if defined(__Userspace__)
case AF_CONN:
- incr = sizeof(struct sockaddr_in6);
- if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ incr = sizeof(struct sockaddr_conn);
+ if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
+ SCTP_DONOT_SETSCOPE,
+ SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_8);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTPUTIL + SCTP_LOC_11);
*error = ENOBUFS;
goto out_now;
}
@@ -7165,33 +7488,37 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
return (added);
}
-struct sctp_tcb *
+int
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
- int *totaddr, int *num_v4, int *num_v6, int *error,
- int limit, int *bad_addr)
+ unsigned int totaddr,
+ unsigned int *num_v4, unsigned int *num_v6,
+ unsigned int limit)
{
struct sockaddr *sa;
- struct sctp_tcb *stcb = NULL;
- size_t incr, at, i;
- at = incr = 0;
- sa = addr;
+ struct sctp_tcb *stcb;
+ unsigned int incr, at, i;
- *error = *num_v6 = *num_v4 = 0;
+ at = 0;
+ sa = addr;
+ *num_v6 = *num_v4 = 0;
/* account and validate addresses */
- for (i = 0; i < (size_t)*totaddr; i++) {
+ if (totaddr == 0) {
+ return (EINVAL);
+ }
+ for (i = 0; i < totaddr; i++) {
+ if (at + sizeof(struct sockaddr) > limit) {
+ return (EINVAL);
+ }
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
- (*num_v4) += 1;
- incr = sizeof(struct sockaddr_in);
+ incr = (unsigned int)sizeof(struct sockaddr_in);
#ifdef HAVE_SA_LEN
if (sa->sa_len != incr) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ return (EINVAL);
}
#endif
+ (*num_v4) += 1;
break;
#endif
#ifdef INET6
@@ -7202,47 +7529,36 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
sin6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
/* Must be non-mapped for connectx */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ return (EINVAL);
}
- (*num_v6) += 1;
- incr = sizeof(struct sockaddr_in6);
+ incr = (unsigned int)sizeof(struct sockaddr_in6);
#ifdef HAVE_SA_LEN
if (sa->sa_len != incr) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ return (EINVAL);
}
#endif
+ (*num_v6) += 1;
break;
}
#endif
default:
- *totaddr = i;
- /* we are done */
- break;
+ return (EINVAL);
}
- if (i == (size_t)*totaddr) {
- break;
+ if ((at + incr) > limit) {
+ return (EINVAL);
}
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
if (stcb != NULL) {
- /* Already have or am bring up an association */
- return (stcb);
+ SCTP_TCB_UNLOCK(stcb);
+ return (EALREADY);
} else {
SCTP_INP_DECR_REF(inp);
}
- if ((at + incr) > (size_t)limit) {
- *totaddr = i;
- break;
- }
+ at += incr;
sa = (struct sockaddr *)((caddr_t)sa + incr);
}
- return ((struct sctp_tcb *)NULL);
+ return (0);
}
/*
@@ -7251,16 +7567,24 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
*/
void
sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
- struct sockaddr *sa, sctp_assoc_t assoc_id,
- uint32_t vrf_id, int *error, void *p)
+ struct sockaddr *sa, uint32_t vrf_id, int *error,
+ void *p)
{
- struct sockaddr *addr_touse;
#if defined(INET) && defined(INET6)
struct sockaddr_in sin;
#endif
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+#ifdef INET
+ struct sockaddr_in *sinp;
+#endif
+ struct sockaddr *addr_to_use;
+ struct sctp_inpcb *lep;
#ifdef SCTP_MVRF
- int i, fnd = 0;
+ int i;
#endif
+ uint16_t port;
/* see if we're bound all already! */
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
@@ -7272,23 +7596,18 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
/* Is the VRF one we have */
for (i = 0; i < inp->num_vrfs; i++) {
if (vrf_id == inp->m_vrf_ids[i]) {
- fnd = 1;
break;
}
}
- if (!fnd) {
+ if (i == inp->num_vrfs) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
#endif
- addr_touse = sa;
+ switch (sa->sa_family) {
#ifdef INET6
- if (sa->sa_family == AF_INET6) {
-#ifdef INET
- struct sockaddr_in6 *sin6;
-
-#endif
+ case AF_INET6:
#ifdef HAVE_SA_LEN
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -7302,8 +7621,9 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
*error = EINVAL;
return;
}
+ sin6 = (struct sockaddr_in6 *)sa;
+ port = sin6->sin6_port;
#ifdef INET
- sin6 = (struct sockaddr_in6 *)addr_touse;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
@@ -7313,13 +7633,17 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
return;
}
in6_sin6_2_sin(&sin, sin6);
- addr_touse = (struct sockaddr *)&sin;
+ addr_to_use = (struct sockaddr *)&sin;
+ } else {
+ addr_to_use = sa;
}
+#else
+ addr_to_use = sa;
#endif
- }
+ break;
#endif
#ifdef INET
- if (sa->sa_family == AF_INET) {
+ case AF_INET:
#ifdef HAVE_SA_LEN
if (sa->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -7334,10 +7658,18 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
*error = EINVAL;
return;
}
- }
+ sinp = (struct sockaddr_in *)sa;
+ port = sinp->sin_port;
+ addr_to_use = sa;
+ break;
#endif
+ default:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ *error = EINVAL;
+ return;
+ }
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
-#if !(defined(__Panda__) || defined(__Windows__))
+#if !(defined(_WIN32) || defined(__Userspace__))
if (p == NULL) {
/* Can't get proc for Net/Open BSD */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -7345,58 +7677,25 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
return;
}
#endif
- *error = sctp_inpcb_bind(so, addr_touse, NULL, p);
+ *error = sctp_inpcb_bind(so, addr_to_use, NULL, p);
return;
}
- /*
- * No locks required here since bind and mgmt_ep_sa
- * all do their own locking. If we do something for
- * the FIX: below we may need to lock in that case.
- */
- if (assoc_id == 0) {
+ /* Validate the incoming port. */
+ if ((port != 0) && (port != inp->sctp_lport)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ *error = EINVAL;
+ return;
+ }
+ lep = sctp_pcb_findep(addr_to_use, 1, 0, vrf_id);
+ if (lep == NULL) {
/* add the address */
- struct sctp_inpcb *lep;
- struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse;
-
- /* validate the incoming port */
- if ((lsin->sin_port != 0) &&
- (lsin->sin_port != inp->sctp_lport)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- return;
- } else {
- /* user specified 0 port, set it to existing port */
- lsin->sin_port = inp->sctp_lport;
- }
-
- lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id);
- if (lep != NULL) {
- /*
- * We must decrement the refcount
- * since we have the ep already and
- * are binding. No remove going on
- * here.
- */
- SCTP_INP_DECR_REF(lep);
- }
- if (lep == inp) {
- /* already bound to it.. ok */
- return;
- } else if (lep == NULL) {
- ((struct sockaddr_in *)addr_touse)->sin_port = 0;
- *error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
- SCTP_ADD_IP_ADDRESS,
- vrf_id, NULL);
- } else {
+ *error = sctp_addr_mgmt_ep_sa(inp, addr_to_use,
+ SCTP_ADD_IP_ADDRESS, vrf_id);
+ } else {
+ if (lep != inp) {
*error = EADDRINUSE;
}
- if (*error)
- return;
- } else {
- /*
- * FIX: decide whether we allow assoc based
- * bindx
- */
+ SCTP_INP_DECR_REF(lep);
}
}
@@ -7406,15 +7705,15 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
*/
void
sctp_bindx_delete_address(struct sctp_inpcb *inp,
- struct sockaddr *sa, sctp_assoc_t assoc_id,
- uint32_t vrf_id, int *error)
+ struct sockaddr *sa, uint32_t vrf_id, int *error)
{
- struct sockaddr *addr_touse;
+ struct sockaddr *addr_to_use;
#if defined(INET) && defined(INET6)
+ struct sockaddr_in6 *sin6;
struct sockaddr_in sin;
#endif
#ifdef SCTP_MVRF
- int i, fnd = 0;
+ int i;
#endif
/* see if we're bound all already! */
@@ -7427,23 +7726,18 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
/* Is the VRF one we have */
for (i = 0; i < inp->num_vrfs; i++) {
if (vrf_id == inp->m_vrf_ids[i]) {
- fnd = 1;
break;
}
}
- if (!fnd) {
+ if (i == inp->num_vrfs) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
#endif
- addr_touse = sa;
+ switch (sa->sa_family) {
#ifdef INET6
- if (sa->sa_family == AF_INET6) {
-#ifdef INET
- struct sockaddr_in6 *sin6;
-#endif
-
+ case AF_INET6:
#ifdef HAVE_SA_LEN
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -7458,7 +7752,7 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
return;
}
#ifdef INET
- sin6 = (struct sockaddr_in6 *)addr_touse;
+ sin6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
@@ -7468,13 +7762,17 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
return;
}
in6_sin6_2_sin(&sin, sin6);
- addr_touse = (struct sockaddr *)&sin;
+ addr_to_use = (struct sockaddr *)&sin;
+ } else {
+ addr_to_use = sa;
}
+#else
+ addr_to_use = sa;
#endif
- }
+ break;
#endif
#ifdef INET
- if (sa->sa_family == AF_INET) {
+ case AF_INET:
#ifdef HAVE_SA_LEN
if (sa->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -7489,24 +7787,17 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
*error = EINVAL;
return;
}
- }
+ addr_to_use = sa;
+ break;
#endif
- /*
- * No lock required mgmt_ep_sa does its own locking.
- * If the FIX: below is ever changed we may need to
- * lock before calling association level binding.
- */
- if (assoc_id == 0) {
- /* delete the address */
- *error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
- SCTP_DEL_IP_ADDRESS,
- vrf_id, NULL);
- } else {
- /*
- * FIX: decide whether we allow assoc based
- * bindx
- */
+ default:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ *error = EINVAL;
+ return;
}
+ /* No lock required mgmt_ep_sa does its own locking. */
+ *error = sctp_addr_mgmt_ep_sa(inp, addr_to_use, SCTP_DEL_IP_ADDRESS,
+ vrf_id);
}
/*
@@ -7520,7 +7811,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
#if defined(INET)
int ipv4_local_scope, ipv4_addr_legal;
#endif
-#if defined (INET6)
+#if defined(INET6)
int local_scope, site_scope, ipv6_addr_legal;
#endif
#if defined(__Userspace__)
@@ -7576,7 +7867,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
/* skip unspecified addrs */
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin->sin_addr) != 0) {
continue;
@@ -7605,7 +7896,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
continue;
}
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
&sin6->sin6_addr) != 0) {
continue;
@@ -7687,7 +7978,7 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_
{
uint32_t saveindex, newindex;
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
if (SCTP_BASE_SYSCTL(sctp_log) == NULL) {
return;
}
@@ -7734,10 +8025,9 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_
}
#endif
-#if defined(__FreeBSD__)
-#if __FreeBSD_version >= 800044
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static void
-sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored,
+sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp,
const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED)
{
struct ip *iph;
@@ -7783,15 +8073,23 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored,
for (last = m; last->m_next; last = last->m_next);
last->m_next = sp;
m->m_pkthdr.len += sp->m_pkthdr.len;
+ /*
+ * The CSUM_DATA_VALID flags indicates that the HW checked the
+ * UDP checksum and it was valid.
+ * Since CSUM_DATA_VALID == CSUM_SCTP_VALID this would imply that
+ * the HW also verified the SCTP checksum. Therefore, clear the bit.
+ */
+ SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
+ "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n",
+ m->m_pkthdr.len,
+ if_name(m->m_pkthdr.rcvif),
+ (int)m->m_pkthdr.csum_flags, CSUM_BITS);
+ m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID;
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
-#if __FreeBSD_version >= 1000000
iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr));
-#else
- iph->ip_len -= sizeof(struct udphdr);
-#endif
sctp_input_with_port(m, off, port);
break;
#endif
@@ -7810,6 +8108,310 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored,
out:
m_freem(m);
}
+
+#ifdef INET
+static void
+sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED)
+{
+ struct ip *outer_ip, *inner_ip;
+ struct sctphdr *sh;
+ struct icmp *icmp;
+ struct udphdr *udp;
+ struct sctp_inpcb *inp;
+ struct sctp_tcb *stcb;
+ struct sctp_nets *net;
+ struct sctp_init_chunk *ch;
+ struct sockaddr_in src, dst;
+ uint8_t type, code;
+
+ inner_ip = (struct ip *)vip;
+ icmp = (struct icmp *)((caddr_t)inner_ip -
+ (sizeof(struct icmp) - sizeof(struct ip)));
+ outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
+ if (ntohs(outer_ip->ip_len) <
+ sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) {
+ return;
+ }
+ udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
+ sh = (struct sctphdr *)(udp + 1);
+ memset(&src, 0, sizeof(struct sockaddr_in));
+ src.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ src.sin_len = sizeof(struct sockaddr_in);
+#endif
+ src.sin_port = sh->src_port;
+ src.sin_addr = inner_ip->ip_src;
+ memset(&dst, 0, sizeof(struct sockaddr_in));
+ dst.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+ dst.sin_len = sizeof(struct sockaddr_in);
+#endif
+ dst.sin_port = sh->dest_port;
+ dst.sin_addr = inner_ip->ip_dst;
+ /*
+ * 'dst' holds the dest of the packet that failed to be sent.
+ * 'src' holds our local endpoint address. Thus we reverse
+ * the dst and the src in the lookup.
+ */
+ inp = NULL;
+ net = NULL;
+ stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
+ (struct sockaddr *)&src,
+ &inp, &net, 1,
+ SCTP_DEFAULT_VRFID);
+ if ((stcb != NULL) &&
+ (net != NULL) &&
+ (inp != NULL)) {
+ /* Check the UDP port numbers */
+ if ((udp->uh_dport != net->port) ||
+ (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ /* Check the verification tag */
+ if (ntohl(sh->v_tag) != 0) {
+ /*
+ * This must be the verification tag used
+ * for sending out packets. We don't
+ * consider packets reflecting the
+ * verification tag.
+ */
+ if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+ if (ntohs(outer_ip->ip_len) >=
+ sizeof(struct ip) +
+ 8 + (inner_ip->ip_hl << 2) + 8 + 20) {
+ /*
+ * In this case we can check if we
+ * got an INIT chunk and if the
+ * initiate tag matches.
+ */
+ ch = (struct sctp_init_chunk *)(sh + 1);
+ if ((ch->ch.chunk_type != SCTP_INITIATION) ||
+ (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ }
+ type = icmp->icmp_type;
+ code = icmp->icmp_code;
+ if ((type == ICMP_UNREACH) &&
+ (code == ICMP_UNREACH_PORT)) {
+ code = ICMP_UNREACH_PROTOCOL;
+ }
+ sctp_notify(inp, stcb, net, type, code,
+ ntohs(inner_ip->ip_len),
+ (uint32_t)ntohs(icmp->icmp_nextmtu));
+#if defined(__Userspace__)
+ if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL)) {
+ struct socket *upcall_socket;
+
+ upcall_socket = stcb->sctp_socket;
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ if ((upcall_socket->so_upcall != NULL) &&
+ (upcall_socket->so_error != 0)) {
+ (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
+ }
+ ACCEPT_LOCK();
+ SOCK_LOCK(upcall_socket);
+ sorele(upcall_socket);
+ }
+#endif
+ } else {
+ if ((stcb == NULL) && (inp != NULL)) {
+ /* reduce ref-count */
+ SCTP_INP_WLOCK(inp);
+ SCTP_INP_DECR_REF(inp);
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if (stcb) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ }
+ return;
+}
+#endif
+
+#ifdef INET6
+static void
+sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED)
+{
+ struct ip6ctlparam *ip6cp;
+ struct sctp_inpcb *inp;
+ struct sctp_tcb *stcb;
+ struct sctp_nets *net;
+ struct sctphdr sh;
+ struct udphdr udp;
+ struct sockaddr_in6 src, dst;
+ uint8_t type, code;
+
+ ip6cp = (struct ip6ctlparam *)d;
+ /*
+ * XXX: We assume that when IPV6 is non NULL, M and OFF are
+ * valid.
+ */
+ if (ip6cp->ip6c_m == NULL) {
+ return;
+ }
+ /* Check if we can safely examine the ports and the
+ * verification tag of the SCTP common header.
+ */
+ if (ip6cp->ip6c_m->m_pkthdr.len <
+ ip6cp->ip6c_off + sizeof(struct udphdr)+ offsetof(struct sctphdr, checksum)) {
+ return;
+ }
+ /* Copy out the UDP header. */
+ memset(&udp, 0, sizeof(struct udphdr));
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off,
+ sizeof(struct udphdr),
+ (caddr_t)&udp);
+ /* Copy out the port numbers and the verification tag. */
+ memset(&sh, 0, sizeof(struct sctphdr));
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off + sizeof(struct udphdr),
+ sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
+ (caddr_t)&sh);
+ memset(&src, 0, sizeof(struct sockaddr_in6));
+ src.sin6_family = AF_INET6;
+#ifdef HAVE_SIN6_LEN
+ src.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ src.sin6_port = sh.src_port;
+ src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
+ return;
+ }
+#endif
+ memset(&dst, 0, sizeof(struct sockaddr_in6));
+ dst.sin6_family = AF_INET6;
+#ifdef HAVE_SIN6_LEN
+ dst.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ dst.sin6_port = sh.dest_port;
+ dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
+ return;
+ }
+#endif
+ inp = NULL;
+ net = NULL;
+ stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
+ (struct sockaddr *)&src,
+ &inp, &net, 1, SCTP_DEFAULT_VRFID);
+ if ((stcb != NULL) &&
+ (net != NULL) &&
+ (inp != NULL)) {
+ /* Check the UDP port numbers */
+ if ((udp.uh_dport != net->port) ||
+ (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ /* Check the verification tag */
+ if (ntohl(sh.v_tag) != 0) {
+ /*
+ * This must be the verification tag used for
+ * sending out packets. We don't consider
+ * packets reflecting the verification tag.
+ */
+ if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ if (ip6cp->ip6c_m->m_pkthdr.len >=
+ ip6cp->ip6c_off + sizeof(struct udphdr) +
+ sizeof(struct sctphdr) +
+ sizeof(struct sctp_chunkhdr) +
+ offsetof(struct sctp_init, a_rwnd)) {
+ /*
+ * In this case we can check if we
+ * got an INIT chunk and if the
+ * initiate tag matches.
+ */
+ uint32_t initiate_tag;
+ uint8_t chunk_type;
+
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off +
+ sizeof(struct udphdr) +
+ sizeof(struct sctphdr),
+ sizeof(uint8_t),
+ (caddr_t)&chunk_type);
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off +
+ sizeof(struct udphdr) +
+ sizeof(struct sctphdr) +
+ sizeof(struct sctp_chunkhdr),
+ sizeof(uint32_t),
+ (caddr_t)&initiate_tag);
+ if ((chunk_type != SCTP_INITIATION) ||
+ (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+#else
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+#endif
+ }
+ type = ip6cp->ip6c_icmp6->icmp6_type;
+ code = ip6cp->ip6c_icmp6->icmp6_code;
+ if ((type == ICMP6_DST_UNREACH) &&
+ (code == ICMP6_DST_UNREACH_NOPORT)) {
+ type = ICMP6_PARAM_PROB;
+ code = ICMP6_PARAMPROB_NEXTHEADER;
+ }
+ sctp6_notify(inp, stcb, net, type, code,
+ ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
+#if defined(__Userspace__)
+ if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL)) {
+ struct socket *upcall_socket;
+
+ upcall_socket = stcb->sctp_socket;
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ if ((upcall_socket->so_upcall != NULL) &&
+ (upcall_socket->so_error != 0)) {
+ (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
+ }
+ ACCEPT_LOCK();
+ SOCK_LOCK(upcall_socket);
+ sorele(upcall_socket);
+ }
+#endif
+ } else {
+ if ((stcb == NULL) && (inp != NULL)) {
+ /* reduce inp's ref-count */
+ SCTP_INP_WLOCK(inp);
+ SCTP_INP_DECR_REF(inp);
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if (stcb) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ }
+}
#endif
void
@@ -7835,7 +8437,6 @@ sctp_over_udp_stop(void)
int
sctp_over_udp_start(void)
{
-#if __FreeBSD_version >= 800044
uint16_t port;
int ret;
#ifdef INET
@@ -7873,7 +8474,9 @@ sctp_over_udp_start(void)
}
/* Call the special UDP hook. */
if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket),
- sctp_recv_udp_tunneled_packet, NULL))) {
+ sctp_recv_udp_tunneled_packet,
+ sctp_recv_icmp_tunneled_packet,
+ NULL))) {
sctp_over_udp_stop();
return (ret);
}
@@ -7897,7 +8500,9 @@ sctp_over_udp_start(void)
}
/* Call the special UDP hook. */
if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket),
- sctp_recv_udp_tunneled_packet, NULL))) {
+ sctp_recv_udp_tunneled_packet,
+ sctp_recv_icmp6_tunneled_packet,
+ NULL))) {
sctp_over_udp_stop();
return (ret);
}
@@ -7913,8 +8518,138 @@ sctp_over_udp_start(void)
}
#endif
return (0);
-#else
- return (ENOTSUP);
+}
+#endif
+
+/*
+ * sctp_min_mtu ()returns the minimum of all non-zero arguments.
+ * If all arguments are zero, zero is returned.
+ */
+uint32_t
+sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3)
+{
+ if (mtu1 > 0) {
+ if (mtu2 > 0) {
+ if (mtu3 > 0) {
+ return (min(mtu1, min(mtu2, mtu3)));
+ } else {
+ return (min(mtu1, mtu2));
+ }
+ } else {
+ if (mtu3 > 0) {
+ return (min(mtu1, mtu3));
+ } else {
+ return (mtu1);
+ }
+ }
+ } else {
+ if (mtu2 > 0) {
+ if (mtu3 > 0) {
+ return (min(mtu2, mtu3));
+ } else {
+ return (mtu2);
+ }
+ } else {
+ return (mtu3);
+ }
+ }
+}
+
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+void
+sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu)
+{
+ struct in_conninfo inc;
+
+ memset(&inc, 0, sizeof(struct in_conninfo));
+ inc.inc_fibnum = fibnum;
+ switch (addr->sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ inc.inc_faddr = addr->sin.sin_addr;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ inc.inc_flags |= INC_ISIPV6;
+ inc.inc6_faddr = addr->sin6.sin6_addr;
+ break;
#endif
+ default:
+ return;
+ }
+ tcp_hc_updatemtu(&inc, (u_long)mtu);
}
+
+uint32_t
+sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum)
+{
+ struct in_conninfo inc;
+
+ memset(&inc, 0, sizeof(struct in_conninfo));
+ inc.inc_fibnum = fibnum;
+ switch (addr->sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ inc.inc_faddr = addr->sin.sin_addr;
+ break;
#endif
+#ifdef INET6
+ case AF_INET6:
+ inc.inc_flags |= INC_ISIPV6;
+ inc.inc6_faddr = addr->sin6.sin6_addr;
+ break;
+#endif
+ default:
+ return (0);
+ }
+ return ((uint32_t)tcp_hc_getmtu(&inc));
+}
+#endif
+
+void
+sctp_set_state(struct sctp_tcb *stcb, int new_state)
+{
+#if defined(KDTRACE_HOOKS)
+ int old_state = stcb->asoc.state;
+#endif
+
+ KASSERT((new_state & ~SCTP_STATE_MASK) == 0,
+ ("sctp_set_state: Can't set substate (new_state = %x)",
+ new_state));
+ stcb->asoc.state = (stcb->asoc.state & ~SCTP_STATE_MASK) | new_state;
+ if ((new_state == SCTP_STATE_SHUTDOWN_RECEIVED) ||
+ (new_state == SCTP_STATE_SHUTDOWN_SENT) ||
+ (new_state == SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
+ }
+#if defined(KDTRACE_HOOKS)
+ if (((old_state & SCTP_STATE_MASK) != new_state) &&
+ !(((old_state & SCTP_STATE_MASK) == SCTP_STATE_EMPTY) &&
+ (new_state == SCTP_STATE_INUSE))) {
+ SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state);
+ }
+#endif
+}
+
+void
+sctp_add_substate(struct sctp_tcb *stcb, int substate)
+{
+#if defined(KDTRACE_HOOKS)
+ int old_state = stcb->asoc.state;
+#endif
+
+ KASSERT((substate & SCTP_STATE_MASK) == 0,
+ ("sctp_add_substate: Can't set state (substate = %x)",
+ substate));
+ stcb->asoc.state |= substate;
+#if defined(KDTRACE_HOOKS)
+ if (((substate & SCTP_STATE_ABOUT_TO_BE_FREED) &&
+ ((old_state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) ||
+ ((substate & SCTP_STATE_SHUTDOWN_PENDING) &&
+ ((old_state & SCTP_STATE_SHUTDOWN_PENDING) == 0))) {
+ SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state);
+ }
+#endif
+}
+
diff --git a/netwerk/sctp/src/netinet/sctputil.h b/netwerk/sctp/src/netinet/sctputil.h
index cca915bb45..14aaf530a1 100755
--- a/netwerk/sctp/src/netinet/sctputil.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 276914 2015-01-10 20:49:57Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 365071 2020-09-01 21:19:14Z mjg $");
#endif
#ifndef _NETINET_SCTP_UTIL_H_
@@ -55,17 +57,19 @@ void sctp_m_freem(struct mbuf *m);
#define sctp_m_freem m_freem
#endif
-#if defined(SCTP_LOCAL_TRACE_BUF) || defined(__APPLE__)
+#if defined(SCTP_LOCAL_TRACE_BUF)
void
sctp_log_trace(uint32_t fr, const char *str SCTP_UNUSED, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f);
#endif
#define sctp_get_associd(stcb) ((sctp_assoc_t)stcb->asoc.assoc_id)
-
/*
* Function prototypes
*/
+int32_t
+sctp_map_assoc_state(int);
+
uint32_t
sctp_get_ifa_hash_val(struct sockaddr *addr);
@@ -79,7 +83,7 @@ uint32_t sctp_select_initial_TSN(struct sctp_pcb *);
uint32_t sctp_select_a_tag(struct sctp_inpcb *, uint16_t lport, uint16_t rport, int);
-int sctp_init_asoc(struct sctp_inpcb *, struct sctp_tcb *, uint32_t, uint32_t);
+int sctp_init_asoc(struct sctp_inpcb *, struct sctp_tcb *, uint32_t, uint32_t, uint16_t);
void sctp_fill_random_store(struct sctp_pcb *);
@@ -89,6 +93,14 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin,
void
sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag);
+/*
+ * NOTE: sctp_timer_start() will increment the reference count of any relevant
+ * structure the timer is referencing, in order to prevent a race condition
+ * between the timer executing and the structure being freed.
+ *
+ * When the timer fires or sctp_timer_stop() is called, these references are
+ * removed.
+ */
void
sctp_timer_start(int, struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
@@ -104,27 +116,28 @@ void
sctp_mtu_size_reset(struct sctp_inpcb *, struct sctp_association *, uint32_t);
void
-sctp_add_to_readq(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- struct sctp_queued_to_read *control,
- struct sockbuf *sb,
- int end,
- int inpread_locked,
+sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
int so_locked
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+#if !(defined(__APPLE__) && !defined(__Userspace__))
SCTP_UNUSED
#endif
- );
+);
-int
-sctp_append_to_readq(struct sctp_inpcb *inp,
+#if defined(__Userspace__)
+void sctp_invoke_recv_callback(struct sctp_inpcb *,
+ struct sctp_tcb *,
+ struct sctp_queued_to_read *,
+ int);
+
+#endif
+void
+sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_queued_to_read *control,
- struct mbuf *m,
+ struct sockbuf *sb,
int end,
- int new_cumack,
- struct sockbuf *sb);
-
+ int inpread_locked,
+ int so_locked);
void sctp_iterator_worker(void);
@@ -134,9 +147,9 @@ uint32_t sctp_get_next_mtu(uint32_t);
void
sctp_timeout_handler(void *);
-uint32_t
+int
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 *);
@@ -152,70 +165,55 @@ sctp_add_pad_tombuf(struct mbuf *, int);
struct mbuf *
sctp_pad_lastmbuf(struct mbuf *, int, struct mbuf *);
-void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- );
+void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *, int);
void
sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
struct sctp_inpcb *new_inp,
struct sctp_tcb *stcb, int waitflags);
-
void sctp_stop_timers_for_shutdown(struct sctp_tcb *);
-void sctp_report_all_outbound(struct sctp_tcb *, uint16_t, int, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- );
+/* Stop all timers for association and remote addresses. */
+void sctp_stop_association_timers(struct sctp_tcb *, bool);
+
+void sctp_report_all_outbound(struct sctp_tcb *, uint16_t, int);
int sctp_expand_mapping_array(struct sctp_association *, uint32_t);
void sctp_abort_notification(struct sctp_tcb *, uint8_t, uint16_t,
- struct sctp_abort_chunk *, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
- );
+ struct sctp_abort_chunk *, int);
/* We abort responding to an IP packet for some reason */
void
sctp_abort_association(struct sctp_inpcb *, struct sctp_tcb *, struct mbuf *,
int, struct sockaddr *, struct sockaddr *,
struct sctphdr *, struct mbuf *,
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t, uint32_t,
#endif
uint32_t, uint16_t);
-
/* We choose to abort via user input */
void
sctp_abort_an_association(struct sctp_inpcb *, struct sctp_tcb *,
- struct mbuf *, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-);
+ struct mbuf *, int);
void sctp_handle_ootb(struct mbuf *, int, int,
struct sockaddr *, struct sockaddr *,
struct sctphdr *, struct sctp_inpcb *,
struct mbuf *,
-#if defined(__FreeBSD__)
- uint8_t, uint32_t,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ uint8_t, uint32_t, uint16_t,
#endif
uint32_t, uint16_t);
int sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
int totaddr, int *error);
-struct sctp_tcb *
-sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
- int *totaddr, int *num_v4, int *num_v6, int *error, int limit, int *bad_addr);
+int
+sctp_connectx_helper_find(struct sctp_inpcb *, struct sockaddr *,
+ unsigned int, unsigned int *, unsigned int *, unsigned int);
int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
#ifdef INET6
@@ -266,21 +264,16 @@ void sctp_print_address(struct sockaddr *);
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *, struct sctp_tmit_chunk *,
- uint8_t, int
-#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
- SCTP_UNUSED
-#endif
-);
+ uint8_t, int);
struct mbuf *sctp_generate_cause(uint16_t, char *);
struct mbuf *sctp_generate_no_user_data_cause(uint32_t);
void sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
- struct sockaddr *sa, sctp_assoc_t assoc_id,
- uint32_t vrf_id, int *error, void *p);
-void sctp_bindx_delete_address(struct sctp_inpcb *inp,
- struct sockaddr *sa, sctp_assoc_t assoc_id,
- uint32_t vrf_id, int *error);
+ struct sockaddr *sa, uint32_t vrf_id, int *error,
+ void *p);
+void sctp_bindx_delete_address(struct sctp_inpcb *inp, struct sockaddr *sa,
+ uint32_t vrf_id, int *error);
int sctp_local_addr_count(struct sctp_tcb *stcb);
@@ -342,11 +335,11 @@ do { \
} while (0)
/* functions to start/stop udp tunneling */
-#if defined(__APPLE__) || defined(__FreeBSD__)
+#if (defined(__APPLE__) || defined(__FreeBSD__)) && !defined(__Userspace__)
void sctp_over_udp_stop(void);
int sctp_over_udp_start(void);
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
void sctp_over_udp_restart(void);
#endif
@@ -368,7 +361,6 @@ void sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t, uint16_t, uint16_t,
void sctp_log_nagle_event(struct sctp_tcb *stcb, int action);
-
#ifdef SCTP_MBUF_LOGGING
void
sctp_log_mb(struct mbuf *m, int from);
@@ -392,7 +384,7 @@ void sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc
void sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from);
void sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *, int, int, uint8_t);
-void sctp_log_block(uint8_t, struct sctp_association *, int);
+void sctp_log_block(uint8_t, struct sctp_association *, ssize_t);
void sctp_log_rwnd(uint8_t, uint32_t, uint32_t, uint32_t);
void sctp_log_rwnd_set(uint8_t, uint32_t, uint32_t, uint32_t, uint32_t);
int sctp_fill_stat_log(void *, size_t *);
@@ -402,7 +394,6 @@ void sctp_log_map(uint32_t, uint32_t, uint32_t, int);
void sctp_print_mapping_array(struct sctp_association *asoc);
void sctp_clr_stat_log(void);
-
#ifdef SCTP_AUDITING_ENABLED
void
sctp_auditing(int, struct sctp_inpcb *, struct sctp_tcb *,
@@ -410,5 +401,17 @@ sctp_auditing(int, struct sctp_inpcb *, struct sctp_tcb *,
void sctp_audit_log(uint8_t, uint8_t);
#endif
+uint32_t sctp_min_mtu(uint32_t, uint32_t, uint32_t);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+void sctp_hc_set_mtu(union sctp_sockstore *, uint16_t, uint32_t);
+uint32_t sctp_hc_get_mtu(union sctp_sockstore *, uint16_t);
+#endif
+void sctp_set_state(struct sctp_tcb *, int);
+void sctp_add_substate(struct sctp_tcb *, int);
+uint32_t sctp_ticks_to_msecs(uint32_t);
+uint32_t sctp_msecs_to_ticks(uint32_t);
+uint32_t sctp_ticks_to_secs(uint32_t);
+uint32_t sctp_secs_to_ticks(uint32_t);
+
#endif /* _KERNEL */
#endif
diff --git a/netwerk/sctp/src/netinet6/sctp6_usrreq.c b/netwerk/sctp/src/netinet6/sctp6_usrreq.c
index 4adb671966..5a931dd5a2 100644
--- a/netwerk/sctp/src/netinet6/sctp6_usrreq.c
+++ b/netwerk/sctp/src/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.
@@ -30,22 +32,20 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 276914 2015-01-10 20:49:57Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 365071 2020-09-01 21:19:14Z mjg $");
#endif
#include <netinet/sctp_os.h>
#ifdef INET6
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/proc.h>
#endif
#include <netinet/sctp_pcb.h>
#include <netinet/sctp_header.h>
#include <netinet/sctp_var.h>
-#ifdef INET6
#include <netinet6/sctp6_var.h>
-#endif
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_output.h>
#include <netinet/sctp_uio.h>
@@ -58,24 +58,11 @@ __FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 276914 2015-01-10 20:49:57Z
#include <netinet/sctp_output.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_crc32.h>
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
+#include <netinet/icmp6.h>
#include <netinet/udp.h>
#endif
-
-#if defined(__APPLE__)
-#define APPLE_FILE_NO 9
-#endif
-#ifdef IPSEC
-#include <netipsec/ipsec.h>
-#ifdef INET6
-#include <netipsec/ipsec6.h>
-#endif /* INET6 */
-#endif /* IPSEC */
-
-#if !defined(__Userspace__)
-extern struct protosw inetsw[];
-#endif
-#if defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
int ip6_v6only=0;
#endif
#if defined(__Userspace__)
@@ -83,16 +70,16 @@ int ip6_v6only=0;
void
in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
{
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
uint32_t temp;
#endif
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
#ifdef HAVE_SIN_LEN
sin->sin_len = sizeof(struct sockaddr_in);
#endif
sin->sin_family = AF_INET;
sin->sin_port = sin6->sin6_port;
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
temp = sin6->sin6_addr.s6_addr16[7];
temp = temp << 16;
temp = temp | sin6->sin6_addr.s6_addr16[6];
@@ -115,23 +102,23 @@ in6_sin6_2_sin_in_sock(struct sockaddr *nam)
}
void
-in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
+in6_sin_2_v4mapsin6(const struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
{
- bzero(sin6, sizeof(struct sockaddr_in6));
- sin6->sin6_family = AF_INET6;
+ memset(sin6, 0, sizeof(struct sockaddr_in6));
+ sin6->sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
sin6->sin6_len = sizeof(struct sockaddr_in6);
#endif
sin6->sin6_port = sin->sin_port;
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
((uint32_t *)&sin6->sin6_addr)[0] = 0;
((uint32_t *)&sin6->sin6_addr)[1] = 0;
((uint32_t *)&sin6->sin6_addr)[2] = htonl(0xffff);
((uint32_t *)&sin6->sin6_addr)[3] = sin->sin_addr.s_addr;
#else
- sin6->sin6_addr.s6_addr32[0] = 0;
+ sin6->sin6_addr.s6_addr32[0] = 0;
sin6->sin6_addr.s6_addr32[1] = 0;
- sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
+ sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
#endif
}
@@ -142,8 +129,6 @@ in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
int
#if defined(__APPLE__) || defined(__FreeBSD__)
sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port)
-#elif defined( __Panda__)
-sctp6_input(pakhandle_type *i_pak)
#else
sctp6_input(struct mbuf **i_pak, int *offp, int proto)
#endif
@@ -157,32 +142,22 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
struct sctphdr *sh;
struct sctp_chunkhdr *ch;
int length, offset;
-#if !defined(SCTP_WITH_NO_CSUM)
uint8_t compute_crc;
-#endif
#if defined(__FreeBSD__)
uint32_t mflowid;
uint8_t mflowtype;
+ uint16_t fibnum;
#endif
-#if !(defined(__APPLE__) || defined (__FreeBSD__))
+#if !(defined(__APPLE__) || defined(__FreeBSD__))
uint16_t port = 0;
#endif
-#if defined(__Panda__)
- /* This is Evil, but its the only way to make panda work right. */
- iphlen = sizeof(struct ip6_hdr);
-#else
iphlen = *offp;
-#endif
if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
SCTP_RELEASE_PKT(*i_pak);
return (IPPROTO_DONE);
}
m = SCTP_HEADER_TO_CHAIN(*i_pak);
-#ifdef __Panda__
- SCTP_DETACH_HEADER_FROM_CHAIN(*i_pak);
- (void)SCTP_RELEASE_HEADER(*i_pak);
-#endif
#ifdef SCTP_MBUF_LOGGING
/* Log in any input mbufs */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
@@ -195,25 +170,11 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
}
#endif
#if defined(__FreeBSD__)
-#if __FreeBSD_version > 1000049
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
m->m_pkthdr.len,
if_name(m->m_pkthdr.rcvif),
(int)m->m_pkthdr.csum_flags, CSUM_BITS);
-#elif __FreeBSD_version >= 800000
- SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
- "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
- m->m_pkthdr.len,
- if_name(m->m_pkthdr.rcvif),
- m->m_pkthdr.csum_flags);
-#else
- SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
- "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
- m->m_pkthdr.len,
- m->m_pkthdr.rcvif->if_xname,
- m->m_pkthdr.csum_flags);
-#endif
#endif
#if defined(__APPLE__)
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
@@ -223,7 +184,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
m->m_pkthdr.rcvif->if_unit,
m->m_pkthdr.csum_flags);
#endif
-#if defined(__Windows__)
+#if defined(_WIN32) && !defined(__Userspace__)
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
m->m_pkthdr.len,
@@ -233,18 +194,21 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
#if defined(__FreeBSD__)
mflowid = m->m_pkthdr.flowid;
mflowtype = M_HASHTYPE_GET(m);
- #endif
+ fibnum = M_GETFIB(m);
+#endif
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
/* Get IP, SCTP, and first chunk header together in the first mbuf. */
offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
- ip6 = mtod(m, struct ip6_hdr *);
- IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
- (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
- if (sh == NULL) {
- SCTP_STAT_INCR(sctps_hdrops);
- return (IPPROTO_DONE);
+ if (m->m_len < offset) {
+ m = m_pullup(m, offset);
+ if (m == NULL) {
+ SCTP_STAT_INCR(sctps_hdrops);
+ return (IPPROTO_DONE);
+ }
}
+ ip6 = mtod(m, struct ip6_hdr *);
+ sh = (struct sctphdr *)(mtod(m, caddr_t) + iphlen);
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
offset -= sizeof(struct sctp_chunkhdr);
memset(&src, 0, sizeof(struct sockaddr_in6));
@@ -296,10 +260,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
goto out;
}
ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_recvnocrc);
-#else
-#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
+#if defined(__FreeBSD__)
if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
SCTP_STAT_INCR(sctps_recvhwcrc);
compute_crc = 0;
@@ -307,24 +268,21 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
#else
if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
(IN6_ARE_ADDR_EQUAL(&src.sin6_addr, &dst.sin6_addr))) {
- SCTP_STAT_INCR(sctps_recvnocrc);
+ SCTP_STAT_INCR(sctps_recvhwcrc);
compute_crc = 0;
} else {
#endif
SCTP_STAT_INCR(sctps_recvswcrc);
compute_crc = 1;
}
-#endif
sctp_common_input_processing(&m, iphlen, offset, length,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
compute_crc,
-#endif
ecn_bits,
#if defined(__FreeBSD__)
- mflowtype, mflowid,
+ mflowtype, mflowid, fibnum,
#endif
vrf_id, port);
out:
@@ -341,7 +299,6 @@ sctp6_input(struct mbuf **i_pak, int *offp)
return (sctp6_input_with_port(i_pak, offp, 0));
}
#endif
-
#if defined(__FreeBSD__)
int
sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
@@ -350,277 +307,274 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
}
#endif
-#if defined(__Panda__)
void
-#else
-static void
-#endif
-sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6,
- struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net)
+sctp6_notify(struct sctp_inpcb *inp,
+ struct sctp_tcb *stcb,
+ struct sctp_nets *net,
+ uint8_t icmp6_type,
+ uint8_t icmp6_code,
+ uint32_t next_mtu)
{
- uint32_t nxtsz;
-
- if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
- (icmp6 == NULL) || (sh == NULL)) {
- goto out;
- }
- /* First do we even look at it? */
- if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
- goto out;
-
- if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
- /* not PACKET TO BIG */
- goto out;
- }
- /*
- * ok we need to look closely. We could even get smarter and look at
- * anyone that we sent to in case we get a different ICMP that tells
- * us there is no way to reach a host, but for this impl, all we
- * care about is MTU discovery.
- */
- nxtsz = ntohl(icmp6->icmp6_mtu);
- /* Stop any PMTU timer */
- sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ+SCTP_LOC_1);
-
- /* Adjust destination size limit */
- if (net->mtu > nxtsz) {
- net->mtu = nxtsz;
- if (net->port) {
- net->mtu -= sizeof(struct udphdr);
- }
- }
- /* now what about the ep? */
- if (stcb->asoc.smallest_mtu > nxtsz) {
- struct sctp_tmit_chunk *chk;
-
- /* Adjust that too */
- stcb->asoc.smallest_mtu = nxtsz;
- /* now off to subtract IP_DF flag if needed */
-
- TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
- if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
- chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
- }
- }
- TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
- if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
- /*
- * For this guy we also mark for immediate
- * resend since we sent to big of chunk
- */
- chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
- if (chk->sent != SCTP_DATAGRAM_RESEND)
- stcb->asoc.sent_queue_retran_cnt++;
- chk->sent = SCTP_DATAGRAM_RESEND;
- chk->rec.data.doing_fast_retransmit = 0;
-
- chk->sent = SCTP_DATAGRAM_RESEND;
- /* Clear any time so NO RTT is being done */
- chk->sent_rcv_time.tv_sec = 0;
- chk->sent_rcv_time.tv_usec = 0;
- stcb->asoc.total_flight -= chk->send_size;
- net->flight_size -= chk->send_size;
+#if defined(__APPLE__)
+ struct socket *so;
+#endif
+ int timer_stopped;
+
+ switch (icmp6_type) {
+ case ICMP6_DST_UNREACH:
+ if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) ||
+ (icmp6_code == ICMP6_DST_UNREACH_ADMIN) ||
+ (icmp6_code == ICMP6_DST_UNREACH_BEYONDSCOPE) ||
+ (icmp6_code == ICMP6_DST_UNREACH_ADDR)) {
+ /* Mark the net unreachable. */
+ if (net->dest_state & SCTP_ADDR_REACHABLE) {
+ /* Ok that destination is not reachable */
+ net->dest_state &= ~SCTP_ADDR_REACHABLE;
+ net->dest_state &= ~SCTP_ADDR_PF;
+ sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
+ stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
}
}
- }
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
-out:
- if (stcb) {
SCTP_TCB_UNLOCK(stcb);
- }
-}
+ break;
+ case ICMP6_PARAM_PROB:
+ /* Treat it like an ABORT. */
+ if (icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) {
+ sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
+#if defined(__APPLE__)
+ so = SCTP_INP_SO(inp);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
-
-
-void
-sctp6_notify(struct sctp_inpcb *inp,
- struct icmp6_hdr *icmph,
- struct sctphdr *sh,
- struct sockaddr *to,
- struct sctp_tcb *stcb,
- struct sctp_nets *net)
-{
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- struct socket *so;
-
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
+#if defined(__APPLE__)
+ SCTP_SOCKET_UNLOCK(so, 1);
#endif
-
- /* protection */
- if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
- (sh == NULL) || (to == NULL)) {
- if (stcb)
+ } else {
SCTP_TCB_UNLOCK(stcb);
- return;
- }
- /* First job is to verify the vtag matches what I would send */
- if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- if (icmph->icmp6_type != ICMP_UNREACH) {
- /* We only care about unreachable */
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
- (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
- (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
- (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
- (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
- (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
- (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
-#if defined(__Panda__)
- (icmph->icmp6_code == ICMP_UNREACH_ADMIN)) {
-#elif defined(__Userspace_os_NetBSD)
- (icmph->icmp6_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
-#else
- (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
+ }
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
+ 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,
+ SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
+ } else {
+ timer_stopped = 0;
+ }
+ /* Update the path MTU. */
+ if (net->port) {
+ next_mtu -= sizeof(struct udphdr);
+ }
+ if (net->mtu > next_mtu) {
+ net->mtu = next_mtu;
+#if defined(__FreeBSD__)
+ if (net->port) {
+ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
+ } else {
+ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
+ }
#endif
-
- /*
- * Hmm reachablity problems we must examine closely. If its
- * not reachable, we may have lost a network. Or if there is
- * NO protocol at the other end named SCTP. well we consider
- * it a OOTB abort.
- */
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* Ok that destination is NOT reachable */
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- net->dest_state &= ~SCTP_ADDR_PF;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
- stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
+ }
+ /* Update the association MTU */
+ if (stcb->asoc.smallest_mtu > next_mtu) {
+ sctp_pathmtu_adjustment(stcb, next_mtu);
+ }
+ /* Finally, start the PMTU timer if it was running before. */
+ if (timer_stopped) {
+ sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
}
SCTP_TCB_UNLOCK(stcb);
- } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
- (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
- /*
- * Here the peer is either playing tricks on us,
- * including an address that belongs to someone who
- * does not support SCTP OR was a userland
- * implementation that shutdown and now is dead. In
- * either case treat it like a OOTB abort with no
- * TCB
- */
- sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- so = SCTP_INP_SO(inp);
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
-#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2);
-#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- SCTP_SOCKET_UNLOCK(so, 1);
- /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/
-#endif
- /* no need to unlock here, since the TCB is gone */
- } else {
+ break;
+ default:
SCTP_TCB_UNLOCK(stcb);
+ break;
}
}
-
-
-#if !defined(__Panda__) && !defined(__Userspace__)
void
+#if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN)
+sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d, struct ifnet *ifp SCTP_UNUSED)
+#else
sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
+#endif
{
+ struct ip6ctlparam *ip6cp;
+ struct sctp_inpcb *inp;
+ struct sctp_tcb *stcb;
+ struct sctp_nets *net;
struct sctphdr sh;
- struct ip6ctlparam *ip6cp = NULL;
- uint32_t vrf_id;
-
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
- vrf_id = SCTP_DEFAULT_VRFID;
-#endif
+ struct sockaddr_in6 src, dst;
#ifdef HAVE_SA_LEN
if (pktdst->sa_family != AF_INET6 ||
- pktdst->sa_len != sizeof(struct sockaddr_in6))
+ pktdst->sa_len != sizeof(struct sockaddr_in6)) {
#else
- if (pktdst->sa_family != AF_INET6)
+ if (pktdst->sa_family != AF_INET6) {
#endif
return;
+ }
- if ((unsigned)cmd >= PRC_NCMDS)
+ if ((unsigned)cmd >= PRC_NCMDS) {
return;
+ }
if (PRC_IS_REDIRECT(cmd)) {
d = NULL;
} else if (inet6ctlerrmap[cmd] == 0) {
return;
}
- /* if the parameter is from icmp6, decode it. */
+ /* If the parameter is from icmp6, decode it. */
if (d != NULL) {
ip6cp = (struct ip6ctlparam *)d;
} else {
ip6cp = (struct ip6ctlparam *)NULL;
}
- if (ip6cp) {
+ if (ip6cp != NULL) {
/*
* XXX: We assume that when IPV6 is non NULL, M and OFF are
* valid.
*/
- /* check if we can safely examine src and dst ports */
- struct sctp_inpcb *inp = NULL;
- struct sctp_tcb *stcb = NULL;
- struct sctp_nets *net = NULL;
- struct sockaddr_in6 final;
+ if (ip6cp->ip6c_m == NULL) {
+ return;
+ }
- if (ip6cp->ip6c_m == NULL)
+ /* Check if we can safely examine the ports and the
+ * verification tag of the SCTP common header.
+ */
+ if (ip6cp->ip6c_m->m_pkthdr.len <
+ (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) {
return;
+ }
- bzero(&sh, sizeof(sh));
- bzero(&final, sizeof(final));
- inp = NULL;
- net = NULL;
- m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
- (caddr_t)&sh);
- ip6cp->ip6c_src->sin6_port = sh.src_port;
+ /* Copy out the port numbers and the verification tag. */
+ memset(&sh, 0, sizeof(sh));
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off,
+ sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
+ (caddr_t)&sh);
+ memset(&src, 0, sizeof(struct sockaddr_in6));
+ src.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
- final.sin6_len = sizeof(final);
+ src.sin6_len = sizeof(struct sockaddr_in6);
#endif
- final.sin6_family = AF_INET6;
-#if defined(__FreeBSD__) && __FreeBSD_cc_version < 440000
- final.sin6_addr = *ip6cp->ip6c_finaldst;
-#else
- final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
-#endif /* __FreeBSD_cc_version */
- final.sin6_port = sh.dest_port;
- stcb = sctp_findassociation_addr_sa((struct sockaddr *)&final,
- (struct sockaddr *)ip6cp->ip6c_src,
- &inp, &net, 1, vrf_id);
- /* inp's ref-count increased && stcb locked */
- if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
- if (cmd == PRC_MSGSIZE) {
- sctp6_notify_mbuf(inp,
- ip6cp->ip6c_icmp6,
- &sh,
- stcb,
- net);
- /* inp's ref-count reduced && stcb unlocked */
+ src.sin6_port = sh.src_port;
+ src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
+#if defined(__FreeBSD__)
+ if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
+ return;
+ }
+#endif
+ memset(&dst, 0, sizeof(struct sockaddr_in6));
+ dst.sin6_family = AF_INET6;
+#ifdef HAVE_SIN6_LEN
+ dst.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ dst.sin6_port = sh.dest_port;
+ dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
+#if defined(__FreeBSD__)
+ if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
+ return;
+ }
+#endif
+ inp = NULL;
+ net = NULL;
+ stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
+ (struct sockaddr *)&src,
+ &inp, &net, 1, SCTP_DEFAULT_VRFID);
+ if ((stcb != NULL) &&
+ (net != NULL) &&
+ (inp != NULL)) {
+ /* Check the verification tag */
+ if (ntohl(sh.v_tag) != 0) {
+ /*
+ * This must be the verification tag used for
+ * sending out packets. We don't consider
+ * packets reflecting the verification tag.
+ */
+ if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
} else {
- sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
- (struct sockaddr *)&final,
- stcb, net);
- /* inp's ref-count reduced && stcb unlocked */
+#if defined(__FreeBSD__)
+ if (ip6cp->ip6c_m->m_pkthdr.len >=
+ ip6cp->ip6c_off + sizeof(struct sctphdr) +
+ sizeof(struct sctp_chunkhdr) +
+ offsetof(struct sctp_init, a_rwnd)) {
+ /*
+ * In this case we can check if we
+ * got an INIT chunk and if the
+ * initiate tag matches.
+ */
+ uint32_t initiate_tag;
+ uint8_t chunk_type;
+
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off +
+ sizeof(struct sctphdr),
+ sizeof(uint8_t),
+ (caddr_t)&chunk_type);
+ m_copydata(ip6cp->ip6c_m,
+ ip6cp->ip6c_off +
+ sizeof(struct sctphdr) +
+ sizeof(struct sctp_chunkhdr),
+ sizeof(uint32_t),
+ (caddr_t)&initiate_tag);
+ if ((chunk_type != SCTP_INITIATION) ||
+ (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+#else
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+#endif
}
- } else {
-#if !defined(__Windows__)
- if (PRC_IS_REDIRECT(cmd) && inp) {
- in6_rtchange((struct in6pcb *)inp,
- inet6ctlerrmap[cmd]);
+ sctp6_notify(inp, stcb, net,
+ ip6cp->ip6c_icmp6->icmp6_type,
+ ip6cp->ip6c_icmp6->icmp6_code,
+ ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
+#if defined(__Userspace__)
+ if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) &&
+ (stcb->sctp_socket != NULL) {
+ struct socket *upcall_socket;
+
+ upcall_socket = stcb->sctp_socket;
+ SOCK_LOCK(upcall_socket);
+ soref(upcall_socket);
+ SOCK_UNLOCK(upcall_socket);
+ if ((upcall_socket->so_upcall != NULL) &&
+ (upcall_socket->so_error != 0)) {
+ (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
+ }
+ ACCEPT_LOCK();
+ SOCK_LOCK(upcall_socket);
+ sorele(upcall_socket);
}
#endif
- if (inp) {
+ } else {
+ if ((stcb == NULL) && (inp != NULL)) {
/* reduce inp's ref-count */
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
}
- if (stcb)
+ if (stcb) {
SCTP_TCB_UNLOCK(stcb);
+ }
}
}
}
@@ -630,7 +584,7 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
* this routine can probably be collasped into the one in sctp_userreq.c
* since they do the same thing and now we lookup with a sockaddr
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
static int
sctp6_getcred(SYSCTL_HANDLER_ARGS)
{
@@ -642,16 +596,10 @@ sctp6_getcred(SYSCTL_HANDLER_ARGS)
int error;
uint32_t vrf_id;
-#if defined(__FreeBSD__) || defined(__APPLE__)
vrf_id = SCTP_DEFAULT_VRFID;
-#else
- vrf_id = panda_get_vrf_from_call(); /* from connectx call? */
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_version > 602000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
error = priv_check(req->td, PRIV_NETINET_GETCRED);
-#elif defined(__FreeBSD__) && __FreeBSD_version >= 500000
- error = suser(req->td);
#else
error = suser(req->p);
#endif
@@ -709,31 +657,36 @@ out:
SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
0, 0,
sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
-
#endif
/* This is the same as the sctp_abort() could be made common */
-#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__)
-static void
-#elif defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
int
+#elif defined(__FreeBSD__) || defined(_WIN32)
+static void
#else
static int
#endif
sctp6_abort(struct socket *so)
{
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
struct sctp_inpcb *inp;
uint32_t flags;
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
-#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__)
+#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
return;
#else
return (EINVAL);
#endif
}
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_must_try_again:
flags = inp->sctp_flags;
#ifdef SCTP_LOG_CLOSING
@@ -752,7 +705,7 @@ sctp6_abort(struct socket *so)
* here for the accounting/select.
*/
SCTP_SB_CLEAR(so->so_rcv);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
so->so_usecount--;
#else
/* Now null out the reference, we are completely detached. */
@@ -765,20 +718,21 @@ sctp6_abort(struct socket *so)
goto sctp_must_try_again;
}
}
-#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__)
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
return;
#else
return (0);
#endif
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
-static int
-sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
-#elif defined(__Panda__) || defined(__Userspace__)
+#if defined(__Userspace__)
int
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
-#elif defined(__Windows__)
+#elif defined(__FreeBSD__)
+static int
+sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
+#elif defined(_WIN32)
static int
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED)
#else
@@ -786,10 +740,9 @@ static int
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED)
#endif
{
- struct in6pcb *inp6;
int error;
struct sctp_inpcb *inp;
-#if !defined(__Panda__) && !defined(__Userspace__)
+#if !defined(__Userspace__)
uint32_t vrf_id = SCTP_DEFAULT_VRFID;
#endif
@@ -810,46 +763,35 @@ sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSE
inp = (struct sctp_inpcb *)so->so_pcb;
SCTP_INP_WLOCK(inp);
inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */
- inp6 = (struct in6pcb *)inp;
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
- inp6->inp_vflag |= INP_IPV6;
-#else
- inp->inp_vflag |= INP_IPV6;
-#endif
-#if !defined(__Panda__)
- inp6->in6p_hops = -1; /* use kernel default */
- inp6->in6p_cksum = -1; /* just to be sure */
-#endif
+ inp->ip_inp.inp.inp_vflag |= INP_IPV6;
+ inp->ip_inp.inp.in6p_hops = -1; /* use kernel default */
+ inp->ip_inp.inp.in6p_cksum = -1; /* just to be sure */
#ifdef INET
/*
* XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
* socket as well, because the socket may be bound to an IPv6
* wildcard address, which may match an IPv4-mapped IPv6 address.
*/
- inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
+ inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
#endif
- /*
- * Hmm what about the IPSEC stuff that is missing here but in
- * sctp_attach()?
- */
SCTP_INP_WUNLOCK(inp);
return (0);
}
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__Userspace__)
+int
+sctp6_bind(struct socket *so, struct sockaddr *addr, void * p)
+{
+#elif defined(__FreeBSD__)
static int
sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
{
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__APPLE__)
static int
sctp6_bind(struct socket *so, struct sockaddr *addr, struct proc *p)
{
-#elif defined(__Panda__) || defined(__Userspace__)
-int
-sctp6_bind(struct socket *so, struct sockaddr *addr, void * p)
-{
-#elif defined(__Windows__)
+#elif defined(_WIN32)
static int
sctp6_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p)
{
@@ -861,8 +803,8 @@ sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
#endif
struct sctp_inpcb *inp;
- struct in6pcb *inp6;
int error;
+ u_char vflagsav;
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
@@ -870,7 +812,7 @@ sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
return (EINVAL);
}
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
if (addr) {
switch (addr->sa_family) {
#ifdef INET
@@ -899,26 +841,16 @@ sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
}
}
#endif
- inp6 = (struct in6pcb *)inp;
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
- inp6->inp_vflag &= ~INP_IPV4;
- inp6->inp_vflag |= INP_IPV6;
-#else
- inp->inp_vflag &= ~INP_IPV4;
- inp->inp_vflag |= INP_IPV6;
-#endif
- if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
+ vflagsav = inp->ip_inp.inp.inp_vflag;
+ inp->ip_inp.inp.inp_vflag &= ~INP_IPV4;
+ inp->ip_inp.inp.inp_vflag |= INP_IPV6;
+ if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp) == 0)) {
switch (addr->sa_family) {
#ifdef INET
case AF_INET:
/* binding v4 addr to v6 socket, so reset flags */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
- inp6->inp_vflag |= INP_IPV4;
- inp6->inp_vflag &= ~INP_IPV6;
-#else
- inp->inp_vflag |= INP_IPV4;
- inp->inp_vflag &= ~INP_IPV6;
-#endif
+ inp->ip_inp.inp.inp_vflag |= INP_IPV4;
+ inp->ip_inp.inp.inp_vflag &= ~INP_IPV6;
break;
#endif
#ifdef INET6
@@ -929,26 +861,17 @@ sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
sin6_p = (struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
- inp6->inp_vflag |= INP_IPV4;
-#else
- inp->inp_vflag |= INP_IPV4;
-#endif
+ inp->ip_inp.inp.inp_vflag |= INP_IPV4;
}
#ifdef INET
if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
struct sockaddr_in sin;
in6_sin6_2_sin(&sin, sin6_p);
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
- inp6->inp_vflag |= INP_IPV4;
- inp6->inp_vflag &= ~INP_IPV6;
-#else
- inp->inp_vflag |= INP_IPV4;
- inp->inp_vflag &= ~INP_IPV6;
-#endif
+ inp->ip_inp.inp.inp_vflag |= INP_IPV4;
+ inp->ip_inp.inp.inp_vflag &= ~INP_IPV6;
error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
- return (error);
+ goto out;
}
#endif
break;
@@ -965,7 +888,8 @@ sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
if (addr->sa_family == AF_INET) {
/* can't bind v4 addr to v6 only socket! */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
#endif
sin6_p = (struct sockaddr_in6 *)addr;
@@ -974,15 +898,18 @@ sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
/* can't bind v4-mapped addrs either! */
/* NOTE: we don't support SIIT */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
}
error = sctp_inpcb_bind(so, addr, NULL, p);
+out:
+ if (error != 0)
+ inp->ip_inp.inp.inp_vflag = vflagsav;
return (error);
}
-
-#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__)
+#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
#if !defined(__Userspace__)
static void
#else
@@ -996,9 +923,7 @@ sctp6_close(struct socket *so)
/* This could be made common with sctp_detach() since they are identical */
#else
-#if !defined(__Panda__)
static
-#endif
int
sctp6_detach(struct socket *so)
{
@@ -1012,7 +937,7 @@ sctp6_detach(struct socket *so)
#endif
-#if !defined(__Panda__) && !defined(__Userspace__)
+#if !defined(__Userspace__)
static
#endif
int
@@ -1021,25 +946,22 @@ sctp6_disconnect(struct socket *so)
return (sctp_disconnect(so));
}
-
int
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__FreeBSD__) && !defined(__Userspace__)
sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *p);
-
#else
sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct proc *p);
-
#endif
-#if !defined(__Panda__) && !defined(__Windows__) && !defined(__Userspace__)
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if !defined(_WIN32) && !defined(__Userspace__)
+#if defined(__FreeBSD__)
static int
sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *p)
{
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__APPLE__)
static int
sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct proc *p)
@@ -1052,7 +974,6 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL;
#endif
struct sctp_inpcb *inp;
- struct in6pcb *inp6;
#ifdef INET
struct sockaddr_in6 *sin6;
@@ -1069,7 +990,6 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
- inp6 = (struct in6pcb *)inp;
/*
* For the TCP model we may get a NULL addr, if we are a connected
* socket thats ok.
@@ -1089,7 +1009,7 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
}
#ifdef INET
sin6 = (struct sockaddr_in6 *)addr;
- if (SCTP_IPV6_V6ONLY(inp6)) {
+ if (SCTP_IPV6_V6ONLY(inp)) {
/*
* if IPV6_V6ONLY flag, we discard datagrams destined to a
* v4 addr or v4-mapped addr
@@ -1129,7 +1049,7 @@ connected_type:
inp->pkt_last = inp->pkt = m;
}
if (
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
/* FreeBSD and MacOSX uses a flag passed */
((flags & PRUS_MORETOCOME) == 0)
#else
@@ -1144,9 +1064,18 @@ connected_type:
* optionaly switch back to this code (by changing back the
* defininitions but this is not advisable.
*/
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
int ret;
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
inp->pkt = NULL;
inp->control = NULL;
return (ret);
@@ -1156,46 +1085,41 @@ connected_type:
}
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#if defined(__Userspace__)
+int
+sctp6_connect(struct socket *so, struct sockaddr *addr)
+{
+ void *p = NULL;
+#elif defined(__FreeBSD__)
static int
sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
{
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__APPLE__)
static int
sctp6_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
{
-#elif defined(__Panda__)
-int
-sctp6_connect(struct socket *so, struct sockaddr *addr, void *p)
-{
-#elif defined(__Windows__)
+#elif defined(_WIN32)
static int
sctp6_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p)
{
-#elif defined(__Userspace__)
-int
-sctp6_connect(struct socket *so, struct sockaddr *addr)
-{
- void *p = NULL;
#else
static int
sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
{
struct sockaddr *addr = mtod(nam, struct sockaddr *);
#endif
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ struct epoch_tracker et;
+#endif
uint32_t vrf_id;
int error = 0;
struct sctp_inpcb *inp;
struct sctp_tcb *stcb;
#ifdef INET
- struct in6pcb *inp6;
struct sockaddr_in6 *sin6;
union sctp_sockstore store;
#endif
-#ifdef INET
- inp6 = (struct in6pcb *)so->so_pcb;
-#endif
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
@@ -1206,7 +1130,7 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
-#if !defined(__Windows__)
+#if !(defined(_WIN32) && !defined(__Userspace__))
switch (addr->sa_family) {
#ifdef INET
case AF_INET:
@@ -1259,7 +1183,7 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
}
#ifdef INET
sin6 = (struct sockaddr_in6 *)addr;
- if (SCTP_IPV6_V6ONLY(inp6)) {
+ if (SCTP_IPV6_V6ONLY(inp)) {
/*
* if IPV6_V6ONLY flag, ignore connections destined to a v4
* addr or v4-mapped addr
@@ -1287,7 +1211,7 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
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 {
@@ -1311,7 +1235,10 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
return (EALREADY);
}
/* We are GOOD to go */
- stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
+ stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
+ inp->sctp_ep.pre_open_stream_count,
+ inp->sctp_ep.port, p,
+ SCTP_INITIALIZE_AUTH_PARAMS);
SCTP_ASOC_CREATE_UNLOCK(inp);
if (stcb == NULL) {
/* Gak! no memory */
@@ -1322,26 +1249,24 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
/* Set the connected flag so we can queue data */
soisconnecting(so);
}
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
-
- /* initialize authentication parameters for the assoc */
- sctp_initialize_auth_params(inp, stcb);
-
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_ENTER(et);
+#endif
sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ NET_EPOCH_EXIT(et);
+#endif
return (error);
}
static int
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
sctp6_getaddr(struct socket *so, struct sockaddr **addr)
{
struct sockaddr_in6 *sin6;
-#elif defined(__Panda__)
-sctp6_getaddr(struct socket *so, struct sockaddr *addr)
-{
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
#else
sctp6_getaddr(struct socket *so, struct mbuf *nam)
{
@@ -1351,22 +1276,20 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
uint32_t vrf_id;
struct sctp_ifa *sctp_ifa;
-#ifdef SCTP_KAME
+#if defined(SCTP_KAME) && defined(SCTP_EMBEDDED_V6_SCOPE)
int error;
-#endif /* SCTP_KAME */
+#endif
/*
* Do the malloc first in case it blocks.
*/
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
if (sin6 == NULL)
return (ENOMEM);
-#elif defined(__Panda__)
- bzero(sin6, sizeof(*sin6));
#else
SCTP_BUF_LEN(nam) = sizeof(*sin6);
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
#endif
sin6->sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
@@ -1375,7 +1298,7 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin6);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
@@ -1392,7 +1315,12 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
int fnd;
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
- goto notConn6;
+ SCTP_INP_RUNLOCK(inp);
+#if !defined(__Userspace__)
+ SCTP_FREE_SONAME(sin6);
+#endif
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
+ return (ENOENT);
}
fnd = 0;
sin_a6 = NULL;
@@ -1409,7 +1337,12 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
}
if ((!fnd) || (sin_a6 == NULL)) {
/* punt */
- goto notConn6;
+ SCTP_INP_RUNLOCK(inp);
+#if !defined(__Userspace__)
+ SCTP_FREE_SONAME(sin6);
+#endif
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
+ return (ENOENT);
}
vrf_id = inp->def_vrf_id;
sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id);
@@ -1418,7 +1351,6 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
}
} else {
/* For the bound all case you get back 0 */
- notConn6:
memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
}
} else {
@@ -1437,7 +1369,7 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
}
}
if (!fnd) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin6);
#endif
SCTP_INP_RUNLOCK(inp);
@@ -1461,21 +1393,17 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam)
sin6->sin6_scope_id = 0; /* XXX */
#endif /* SCTP_KAME */
#endif /* SCTP_EMBEDDED_V6_SCOPE */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
(*addr) = (struct sockaddr *)sin6;
#endif
return (0);
}
static int
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
{
struct sockaddr_in6 *sin6;
-#elif defined(__Panda__)
-sctp6_peeraddr(struct socket *so, struct sockaddr *addr)
-{
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
#else
sctp6_peeraddr(struct socket *so, struct mbuf *nam)
{
@@ -1491,12 +1419,10 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam)
#endif
/* Do the malloc first in case it blocks. */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
if (sin6 == NULL)
return (ENOMEM);
-#elif defined(__Panda__)
- memset(sin6, 0, sizeof(*sin6));
#else
SCTP_BUF_LEN(nam) = sizeof(*sin6);
memset(sin6, 0, sizeof(*sin6));
@@ -1510,7 +1436,7 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam)
if ((inp == NULL) ||
((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
/* UDP type and listeners will drop out here */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin6);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
@@ -1523,7 +1449,7 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam)
}
SCTP_INP_RUNLOCK(inp);
if (stcb == NULL) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin6);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
@@ -1542,7 +1468,7 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam)
SCTP_TCB_UNLOCK(stcb);
if (!fnd) {
/* No IPv4 address */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin6);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
@@ -1551,7 +1477,7 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam)
#ifdef SCTP_EMBEDDED_V6_SCOPE
#ifdef SCTP_KAME
if ((error = sa6_recoverscope(sin6)) != 0) {
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SCTP_FREE_SONAME(sin6);
#endif
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error);
@@ -1561,24 +1487,16 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam)
in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
#endif /* SCTP_KAME */
#endif /* SCTP_EMBEDDED_V6_SCOPE */
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
*addr = (struct sockaddr *)sin6;
#endif
return (0);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
static int
sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
{
-#ifdef INET
- struct sockaddr *addr;
-#endif
-#elif defined(__Panda__)
-int
-sctp6_in6getaddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen)
-{
- struct sockaddr *addr = nam;
#elif defined(__Userspace__)
int
sctp6_in6getaddr(struct socket *so, struct mbuf *nam)
@@ -1594,10 +1512,10 @@ sctp6_in6getaddr(struct socket *so, struct mbuf *nam)
struct sockaddr *addr = mtod(nam, struct sockaddr *);
#endif
#endif
- struct in6pcb *inp6 = sotoin6pcb(so);
+ struct inpcb *inp = sotoinpcb(so);
int error;
- if (inp6 == NULL) {
+ if (inp == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
@@ -1606,42 +1524,40 @@ sctp6_in6getaddr(struct socket *so, struct mbuf *nam)
error = sctp6_getaddr(so, nam);
#ifdef INET
if (error) {
+#if !defined(__Userspace__)
+ struct sockaddr_in6 *sin6;
+#else
+ struct sockaddr_in6 sin6;
+#endif
+
/* try v4 next if v6 failed */
error = sctp_ingetaddr(so, nam);
if (error) {
return (error);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
- addr = *nam;
-#endif
- /* if I'm V6ONLY, convert it to v4-mapped */
- if (SCTP_IPV6_V6ONLY(inp6)) {
- struct sockaddr_in6 sin6;
-
- in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
- memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
+#if !defined(__Userspace__)
+ SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
+ if (sin6 == NULL) {
+ SCTP_FREE_SONAME(*nam);
+ return (ENOMEM);
}
- }
+ in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
+ SCTP_FREE_SONAME(*nam);
+ *nam = (struct sockaddr *)sin6;
+#else
+ in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
+ SCTP_BUF_LEN(nam) = sizeof(struct sockaddr_in6);
+ memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
#endif
-#if defined(__Panda__)
- *namelen = nam->sa_len;
+ }
#endif
return (error);
}
-
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
static int
sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
{
-#ifdef INET
- struct sockaddr *addr;
-#endif
-#elif defined(__Panda__)
-int
-sctp6_getpeeraddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen)
-{
- struct sockaddr *addr = (struct sockaddr *)nam;
#elif defined(__Userspace__)
int
sctp6_getpeeraddr(struct socket *so, struct mbuf *nam)
@@ -1659,10 +1575,10 @@ sctp6_getpeeraddr(struct socket *so, struct mbuf *nam)
#endif
#endif
- struct in6pcb *inp6 = sotoin6pcb(so);
+ struct inpcb *inp = sotoinpcb(so);
int error;
- if (inp6 == NULL) {
+ if (inp == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
@@ -1671,30 +1587,37 @@ sctp6_getpeeraddr(struct socket *so, struct mbuf *nam)
error = sctp6_peeraddr(so, nam);
#ifdef INET
if (error) {
+#if !defined(__Userspace__)
+ struct sockaddr_in6 *sin6;
+#else
+ struct sockaddr_in6 sin6;
+#endif
+
/* try v4 next if v6 failed */
error = sctp_peeraddr(so, nam);
if (error) {
return (error);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
- addr = *nam;
-#endif
- /* if I'm V6ONLY, convert it to v4-mapped */
- if (SCTP_IPV6_V6ONLY(inp6)) {
- struct sockaddr_in6 sin6;
-
- in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
- memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
+#if !defined(__Userspace__)
+ SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
+ if (sin6 == NULL) {
+ SCTP_FREE_SONAME(*nam);
+ return (ENOMEM);
}
- }
+ in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
+ SCTP_FREE_SONAME(*nam);
+ *nam = (struct sockaddr *)sin6;
+#else
+ in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
+ SCTP_BUF_LEN(nam) = sizeof(struct sockaddr_in6);
+ memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
#endif
-#if defined(__Panda__)
- *namelen = nam->sa_len;
+ }
#endif
return (error);
}
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
struct pr_usrreqs sctp6_usrreqs = {
#if defined(__FreeBSD__)
.pru_abort = sctp6_abort,
@@ -1703,15 +1626,10 @@ struct pr_usrreqs sctp6_usrreqs = {
.pru_bind = sctp6_bind,
.pru_connect = sctp6_connect,
.pru_control = in6_control,
-#if __FreeBSD_version >= 690000
.pru_close = sctp6_close,
.pru_detach = sctp6_close,
.pru_sopoll = sopoll_generic,
.pru_flush = sctp_flush,
-#else
- .pru_detach = sctp6_detach,
- .pru_sopoll = sopoll,
-#endif
.pru_disconnect = sctp6_disconnect,
.pru_listen = sctp_listen,
.pru_peeraddr = sctp6_getpeeraddr,
@@ -1720,7 +1638,7 @@ struct pr_usrreqs sctp6_usrreqs = {
.pru_sockaddr = sctp6_in6getaddr,
.pru_sosend = sctp_sosend,
.pru_soreceive = sctp_soreceive
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !defined(__Userspace__)
.pru_abort = sctp6_abort,
.pru_accept = sctp_accept,
.pru_attach = sctp6_attach,
@@ -1741,7 +1659,7 @@ struct pr_usrreqs sctp6_usrreqs = {
.pru_sosend = sctp_sosend,
.pru_soreceive = sctp_soreceive,
.pru_sopoll = sopoll
-#elif defined(__Windows__)
+#elif defined(_WIN32) && !defined(__Userspace__)
sctp6_abort,
sctp_accept,
sctp6_attach,
@@ -1768,7 +1686,7 @@ struct pr_usrreqs sctp6_usrreqs = {
#endif
};
-#elif !defined(__Panda__) && !defined(__Userspace__)
+#elif !defined(__Userspace__)
int
sctp6_usrreq(so, req, m, nam, control, p)
struct socket *so;
@@ -1776,22 +1694,22 @@ sctp6_usrreq(so, req, m, nam, control, p)
struct mbuf *m, *nam, *control;
struct proc *p;
{
- int s;
- int error = 0;
+ int error;
int family;
- uint32_t vrf_id;
+
family = so->so_proto->pr_domain->dom_family;
if (req == PRU_CONTROL) {
switch (family) {
case PF_INET:
error = in_control(so, (long)m, (caddr_t)nam,
- (struct ifnet *)control
- );
+ (struct ifnet *)control);
+ break;
#ifdef INET6
case PF_INET6:
error = in6_control(so, (long)m, (caddr_t)nam,
(struct ifnet *)control, p);
+ break;
#endif
default:
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT);
@@ -1875,6 +1793,7 @@ sctp6_usrreq(so, req, m, nam, control, p)
error = 0;
break;
default:
+ error = 0;
break;
}
return (error);
diff --git a/netwerk/sctp/src/netinet6/sctp6_var.h b/netwerk/sctp/src/netinet6/sctp6_var.h
index 3402bc08cd..56a6c3af3d 100755
--- a/netwerk/sctp/src/netinet6/sctp6_var.h
+++ b/netwerk/sctp/src/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.
@@ -30,9 +32,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_var.h 243186 2012-11-17 20:04:04Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_var.h 317457 2017-04-26 19:26:40Z tuexen $");
#endif
#ifndef _NETINET6_SCTP6_VAR_H_
@@ -42,47 +44,38 @@ __FBSDID("$FreeBSD: head/sys/netinet6/sctp6_var.h 243186 2012-11-17 20:04:04Z tu
#ifdef INET
extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *);
extern void in6_sin6_2_sin_in_sock(struct sockaddr *);
-extern void in6_sin_2_v4mapsin6(struct sockaddr_in *, struct sockaddr_in6 *);
+extern void in6_sin_2_v4mapsin6(const struct sockaddr_in *, struct sockaddr_in6 *);
#endif
#endif
#if defined(_KERNEL)
-#if defined(__FreeBSD__) || (__APPLE__) || defined(__Windows__)
+#if !defined(__Userspace__)
SYSCTL_DECL(_net_inet6_sctp6);
extern struct pr_usrreqs sctp6_usrreqs;
#else
int sctp6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *);
#endif
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__Userspace__)
int sctp6_input(struct mbuf **, int *);
int sctp6_input_with_port(struct mbuf **, int *, uint16_t);
-#elif defined(__Panda__)
-int sctp6_input (pakhandle_type *);
-#elif defined(__FreeBSD__) && __FreeBSD_version < 902000
-int sctp6_input __P((struct mbuf **, int *, int));
-int sctp6_input_with_port __P((struct mbuf **, int *, uint16_t));
#else
int sctp6_input(struct mbuf **, int *, int);
int sctp6_input_with_port(struct mbuf **, int *, uint16_t);
#endif
-#if defined(__FreeBSD__) && __FreeBSD_version < 902000
-int sctp6_output
-__P((struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
- struct mbuf *, struct proc *));
-void sctp6_ctlinput __P((int, struct sockaddr *, void *));
-#else
int sctp6_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, struct proc *);
+#if defined(__APPLE__) && !defined(__Userspace__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN)
+void sctp6_ctlinput(int, struct sockaddr *, void *, struct ifnet * SCTP_UNUSED);
+#else
void sctp6_ctlinput(int, struct sockaddr *, void *);
#endif
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#if !((defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__))
extern void in6_sin_2_v4mapsin6(struct sockaddr_in *, struct sockaddr_in6 *);
extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *);
extern void in6_sin6_2_sin_in_sock(struct sockaddr *);
#endif
-extern void sctp6_notify(struct sctp_inpcb *, struct icmp6_hdr *,
- struct sctphdr *, struct sockaddr *,
- struct sctp_tcb *, struct sctp_nets *);
+void sctp6_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *,
+ uint8_t, uint8_t, uint32_t);
#endif
#endif
diff --git a/netwerk/sctp/src/user_atomic.h b/netwerk/sctp/src/user_atomic.h
index 33659cd226..6a59587efc 100755
--- a/netwerk/sctp/src/user_atomic.h
+++ b/netwerk/sctp/src/user_atomic.h
@@ -42,8 +42,8 @@
#include <stdio.h>
#include <sys/types.h>
-#if defined(__Userspace_os_Darwin) || defined (__Userspace_os_Windows)
-#if defined (__Userspace_os_Windows)
+#if defined(__APPLE__) || defined(_WIN32)
+#if defined(_WIN32)
#define atomic_add_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val)
#define atomic_fetchadd_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val)
#define atomic_subtract_int(addr, val) InterlockedExchangeAdd((LPLONG)addr,-((LONG)val))
@@ -76,11 +76,11 @@
*addr = 0; \
} \
}
-#if defined(__Userspace_os_Windows)
-static void atomic_init() {} /* empty when we are not using atomic_mtx */
-#else
-static inline void atomic_init() {} /* empty when we are not using atomic_mtx */
#endif
+#if defined(_WIN32)
+static void atomic_init(void) {} /* empty when we are not using atomic_mtx */
+#else
+static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */
#endif
#else
@@ -132,7 +132,7 @@ static inline void atomic_init() {} /* empty when we are not using atomic_mtx */
} \
}
#endif
-static inline void atomic_init() {} /* empty when we are not using atomic_mtx */
+static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */
#endif
#if 0 /* using libatomic_ops */
@@ -173,7 +173,7 @@ static inline void atomic_init() {} /* empty when we are not using atomic_mtx */
extern userland_mutex_t atomic_mtx;
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
static inline void atomic_init() {
InitializeCriticalSection(&atomic_mtx);
}
@@ -188,16 +188,31 @@ static inline void atomic_unlock() {
}
#else
static inline void atomic_init() {
- (void)pthread_mutex_init(&atomic_mtx, NULL);
+ pthread_mutexattr_t mutex_attr;
+
+ pthread_mutexattr_init(&mutex_attr);
+#ifdef INVARIANTS
+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
+#endif
+ pthread_mutex_init(&accept_mtx, &mutex_attr);
+ pthread_mutexattr_destroy(&mutex_attr);
}
static inline void atomic_destroy() {
(void)pthread_mutex_destroy(&atomic_mtx);
}
static inline void atomic_lock() {
+#ifdef INVARIANTS
+ KASSERT(pthread_mutex_lock(&atomic_mtx) == 0, ("atomic_lock: atomic_mtx already locked"))
+#else
(void)pthread_mutex_lock(&atomic_mtx);
+#endif
}
static inline void atomic_unlock() {
+#ifdef INVARIANTS
+ KASSERT(pthread_mutex_unlock(&atomic_mtx) == 0, ("atomic_unlock: atomic_mtx not locked"))
+#else
(void)pthread_mutex_unlock(&atomic_mtx);
+#endif
}
#endif
/*
diff --git a/netwerk/sctp/src/user_environment.c b/netwerk/sctp/src/user_environment.c
index 6830a2368b..1887718911 100755
--- a/netwerk/sctp/src/user_environment.c
+++ b/netwerk/sctp/src/user_environment.c
@@ -30,18 +30,23 @@
/* __Userspace__ */
-#include <stdlib.h>
-#if !defined (__Userspace_os_Windows)
+#if defined(_WIN32)
+#if !defined(_CRT_RAND_S) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+#define _CRT_RAND_S
+#endif
+#else
#include <stdint.h>
#include <netinet/sctp_os_userspace.h>
#endif
+#ifdef INVARIANTS
+#include <netinet/sctp_pcb.h>
+#endif
#include <user_environment.h>
#include <sys/types.h>
/* #include <sys/param.h> defines MIN */
#if !defined(MIN)
#define MIN(arg1,arg2) ((arg1) < (arg2) ? (arg1) : (arg2))
#endif
-#include <string.h>
#define uHZ 1000
@@ -60,37 +65,320 @@ u_short ip_id = 0; /*__Userspace__ TODO Should it be initialized to zero? */
*/
userland_mutex_t atomic_mtx;
-/* Source: /usr/src/sys/dev/random/harvest.c */
-static int read_random_phony(void *, int);
+/* 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(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+#include <string.h>
-static int (*read_func)(void *, int) = read_random_phony;
+void
+init_random(void)
+{
+ return;
+}
-/* Userland-visible version of read_random */
-int
-read_random(void *buf, int count)
+void
+read_random(void *buf, size_t size)
{
- return ((*read_func)(buf, count));
+ memset(buf, 'A', size);
+ return;
}
-/* 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).
+void
+finish_random(void)
+{
+ return;
+}
+/* This define can be used to optionally use OpenSSL's random number utility,
+ * which is capable of bypassing the chromium sandbox which normally would
+ * prevent opening files, including /dev/urandom.
*/
-static int
-read_random_phony(void *buf, int count)
+#elif defined(SCTP_USE_OPENSSL_RAND)
+#include <openssl/rand.h>
+
+/* Requiring BoringSSL because it guarantees that RAND_bytes will succeed. */
+#ifndef OPENSSL_IS_BORINGSSL
+#error Only BoringSSL is supported with SCTP_USE_OPENSSL_RAND.
+#endif
+
+void
+init_random(void)
+{
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ RAND_bytes((uint8_t *)buf, size);
+ return;
+}
+
+void
+finish_random(void)
+{
+ return;
+}
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__Bitrig__)
+#include <stdlib.h>
+
+void
+init_random(void)
+{
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ arc4random_buf(buf, size);
+ return;
+}
+
+void
+finish_random(void)
+{
+ return;
+}
+#elif defined(_WIN32)
+#include <stdlib.h>
+
+void
+init_random(void)
+{
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
{
- uint32_t randval;
- int size, i;
+ unsigned int randval;
+ size_t position, remaining;
- /* srandom() is called in kern/init_main.c:proc0_post() */
+ position = 0;
+ while (position < size) {
+ if (rand_s(&randval) == 0) {
+ remaining = MIN(size - position, sizeof(unsigned int));
+ memcpy((char *)buf + position, &randval, remaining);
+ position += sizeof(unsigned int);
+ }
+ }
+ return;
+}
+
+void
+finish_random(void)
+{
+ return;
+}
+#elif (defined(__ANDROID__) && (__ANDROID_API__ < 28)) || defined(__EMSCRIPTEN__)
+#include <fcntl.h>
+
+static int fd = -1;
+
+void
+init_random(void)
+{
+ fd = open("/dev/urandom", O_RDONLY);
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ size_t position;
+ ssize_t n;
- /* Fill buf[] with random(9) output */
- for (i = 0; i < count; i+= (int)sizeof(uint32_t)) {
- randval = random();
- size = MIN(count - i, (int)sizeof(uint32_t));
- memcpy(&((char *)buf)[i], &randval, (size_t)size);
+ position = 0;
+ while (position < size) {
+ n = read(fd, (char *)buf + position, size - position);
+ if (n > 0) {
+ position += n;
+ }
}
+ return;
+}
- return (count);
+void
+finish_random(void)
+{
+ close(fd);
+ return;
}
+#elif defined(__ANDROID__) && (__ANDROID_API__ >= 28)
+#include <sys/random.h>
+void
+init_random(void)
+{
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ size_t position;
+ ssize_t n;
+
+ position = 0;
+ while (position < size) {
+ n = getrandom((char *)buf + position, size - position, 0);
+ if (n > 0) {
+ position += n;
+ }
+ }
+ return;
+}
+
+void
+finish_random(void)
+{
+ return;
+}
+#elif defined(__linux__)
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+void __msan_unpoison(void *, size_t);
+#endif
+#endif
+
+#ifdef __NR_getrandom
+#if !defined(GRND_NONBLOCK)
+#define GRND_NONBLOCK 1
+#endif
+static int getrandom_available = 0;
+#endif
+static int fd = -1;
+
+void
+init_random(void)
+{
+#ifdef __NR_getrandom
+ char dummy;
+ ssize_t n = syscall(__NR_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
+ if (n > 0 || errno == EINTR || errno == EAGAIN) {
+ /* Either getrandom succeeded, was interrupted or is waiting for entropy;
+ * all of which mean the syscall is available.
+ */
+ getrandom_available = 1;
+ } else {
+#ifdef INVARIANTS
+ if (errno != ENOSYS) {
+ panic("getrandom syscall returned unexpected error: %d", errno);
+ }
+#endif
+ /* If the syscall isn't available, fall back to /dev/urandom. */
+#endif
+ fd = open("/dev/urandom", O_RDONLY);
+#ifdef __NR_getrandom
+ }
+#endif
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ size_t position;
+ ssize_t n;
+
+ position = 0;
+ while (position < size) {
+#ifdef __NR_getrandom
+ if (getrandom_available) {
+ /* Using syscall directly because getrandom isn't present in glibc < 2.25.
+ */
+ n = syscall(__NR_getrandom, (char *)buf + position, size - position, 0);
+ if (n > 0) {
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+ /* Need to do this because MSan doesn't realize that syscall has
+ * initialized the output buffer.
+ */
+ __msan_unpoison(buf + position, n);
+#endif
+#endif
+ position += n;
+ } else if (errno != EINTR && errno != EAGAIN) {
+#ifdef INVARIANTS
+ panic("getrandom syscall returned unexpected error: %d", errno);
+#endif
+ }
+ } else
+#endif /* __NR_getrandom */
+ {
+ n = read(fd, (char *)buf + position, size - position);
+ if (n > 0) {
+ position += n;
+ }
+ }
+ }
+ return;
+}
+
+void
+finish_random(void)
+{
+ if (fd != -1) {
+ close(fd);
+ }
+ return;
+}
+#elif defined(__Fuchsia__)
+#include <zircon/syscalls.h>
+
+void
+init_random(void)
+{
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ zx_cprng_draw(buf, size);
+ return;
+}
+
+void
+finish_random(void)
+{
+ return;
+}
+#elif defined(__native_client__)
+#include <nacl/nacl_random.h>
+
+void
+init_random(void)
+{
+ return;
+}
+
+void
+read_random(void *buf, size_t size)
+{
+ size_t position;
+ size_t n;
+
+ position = 0;
+ while (position < size) {
+ if (nacl_secure_random((char *)buf + position, size - position, &n) == 0)
+ position += n;
+ }
+ }
+ return;
+}
+
+void
+finish_random(void)
+{
+ return;
+}
+#else
+#error "Unknown platform. Please provide platform specific RNG."
+#endif
diff --git a/netwerk/sctp/src/user_environment.h b/netwerk/sctp/src/user_environment.h
index 6de9d9a5a3..a545accba0 100755
--- a/netwerk/sctp/src/user_environment.h
+++ b/netwerk/sctp/src/user_environment.h
@@ -33,12 +33,12 @@
/* __Userspace__ */
#include <sys/types.h>
-#ifdef __Userspace_os_FreeBSD
+#ifdef __FreeBSD__
#ifndef _SYS_MUTEX_H_
#include <sys/mutex.h>
#endif
#endif
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
#include "netinet/sctp_os_userspace.h"
#endif
@@ -54,7 +54,7 @@ extern int maxsockets;
extern int hz;
-/* The following two ints define a range of available ephermal ports. */
+/* The following two ints define a range of available ephemeral ports. */
extern int ipport_firstauto, ipport_lastauto;
/* nmbclusters is used in sctp_usrreq.c (e.g., sctp_init). In the FreeBSD kernel,
@@ -62,12 +62,14 @@ extern int ipport_firstauto, ipport_lastauto;
*/
extern int nmbclusters;
-#if !defined (__Userspace_os_Windows)
-#define min(a,b) ((a)>(b)?(b):(a))
-#define max(a,b) ((a)>(b)?(a):(b))
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#define min(a,b) (((a)>(b))?(b):(a))
+#define max(a,b) (((a)>(b))?(a):(b))
#endif
-extern int read_random(void *buf, int count);
+void init_random(void);
+void read_random(void *, size_t);
+void finish_random(void);
/* errno's may differ per OS. errno.h now included in sctp_os_userspace.h */
/* Source: /usr/src/sys/sys/errno.h */
@@ -82,23 +84,34 @@ extern int read_random(void *buf, int count);
/* Source ip_output.c. extern'd in ip_var.h */
extern u_short ip_id;
-#if defined(__Userspace_os_Linux)
+#if defined(__linux__)
#define IPV6_VERSION 0x60
#endif
+
#if defined(INVARIANTS)
-#define panic(args...) \
- do { \
- SCTP_PRINTF(args);\
- exit(1); \
-} while (0)
+#include <stdlib.h>
+
+#if defined(_WIN32)
+static inline void __declspec(noreturn)
+#else
+static inline void __attribute__((__noreturn__))
#endif
+terminate_non_graceful(void) {
+ abort();
+}
+
+#define panic(...) \
+ do { \
+ SCTP_PRINTF("%s(): ", __func__); \
+ SCTP_PRINTF(__VA_ARGS__); \
+ SCTP_PRINTF("\n"); \
+ terminate_non_graceful(); \
+} while (0)
-#if defined(INVARIANTS)
#define KASSERT(cond, args) \
do { \
if (!(cond)) { \
- printf args ;\
- exit(1); \
+ panic args ; \
} \
} while (0)
#else
diff --git a/netwerk/sctp/src/user_inpcb.h b/netwerk/sctp/src/user_inpcb.h
index c557cd0a13..2e6e9334ea 100755
--- a/netwerk/sctp/src/user_inpcb.h
+++ b/netwerk/sctp/src/user_inpcb.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -35,8 +35,6 @@
#include <user_route.h> /* was <net/route.h> */
-#define in6pcb inpcb /* for KAME src sync over BSD*'s */
-#define in6p_sp inp_sp /* for KAME src sync over BSD*'s */
struct inpcbpolicy;
/*
@@ -56,7 +54,7 @@ LIST_HEAD(inpcbporthead, inpcbport);
* the following structure.
*/
struct in_addr_4in6 {
- u_int32_t ia46_pad32[3];
+ uint32_t ia46_pad32[3];
struct in_addr ia46_addr4;
};
@@ -65,8 +63,8 @@ struct in_addr_4in6 {
* some extra padding to accomplish this.
*/
struct in_endpoints {
- u_int16_t ie_fport; /* foreign port */
- u_int16_t ie_lport; /* local port */
+ uint16_t ie_fport; /* foreign port */
+ uint16_t ie_lport; /* local port */
/* protocol dependent part, local and foreign addr */
union {
/* foreign host table entry */
@@ -89,13 +87,13 @@ struct in_endpoints {
* references.
*/
struct in_conninfo {
- u_int8_t inc_flags;
- u_int8_t inc_len;
- u_int16_t inc_pad; /* XXX alignment for in_endpoints */
+ uint8_t inc_flags;
+ uint8_t inc_len;
+ uint16_t inc_pad; /* XXX alignment for in_endpoints */
/* protocol dependent part */
struct in_endpoints inc_ie;
};
-#define inc_isipv6 inc_flags /* temp compatability */
+#define inc_isipv6 inc_flags /* temp compatibility */
#define inc_fport inc_ie.ie_fport
#define inc_lport inc_ie.ie_lport
#define inc_faddr inc_ie.ie_faddr
@@ -112,7 +110,7 @@ struct inpcb {
struct inpcbinfo *inp_pcbinfo; /* PCB list info */
struct socket *inp_socket; /* back pointer to socket */
- u_int32_t inp_flow;
+ uint32_t inp_flow;
int inp_flags; /* generic IP/datagram flags */
u_char inp_vflag; /* IP version flag (v4/v6) */
@@ -326,13 +324,11 @@ struct inpcbinfo {
#define INPLOOKUP_WILDCARD 1
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)
-#define sotoin6pcb(so) sotoinpcb(so) /* for KAME src sync over BSD*'s */
#define INP_SOCKAF(so) so->so_proto->pr_domain->dom_family
#define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af)
-/* #ifdef _KERNEL */
extern int ipport_reservedhigh;
extern int ipport_reservedlow;
extern int ipport_lowfirstauto;
@@ -373,6 +369,5 @@ void ipport_tick(void *xtp);
*/
void db_print_inpcb(struct inpcb *inp, const char *name, int indent);
-/* #endif _KERNEL */
#endif /* !_NETINET_IN_PCB_H_ */
diff --git a/netwerk/sctp/src/user_ip6_var.h b/netwerk/sctp/src/user_ip6_var.h
index f5e4a60e4f..b970fb8fa5 100755
--- a/netwerk/sctp/src/user_ip6_var.h
+++ b/netwerk/sctp/src/user_ip6_var.h
@@ -39,7 +39,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -60,16 +60,16 @@
#ifndef _USER_IP6_VAR_H_
#define _USER_IP6_VAR_H_
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
struct ip6_hdr {
union {
struct ip6_hdrctl {
- u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */
- u_int16_t ip6_un1_plen; /* payload length */
- u_int8_t ip6_un1_nxt; /* next header */
- u_int8_t ip6_un1_hlim; /* hop limit */
+ uint32_t ip6_un1_flow; /* 20 bits of flow-ID */
+ uint16_t ip6_un1_plen; /* payload length */
+ uint8_t ip6_un1_nxt; /* next header */
+ uint8_t ip6_un1_hlim; /* hop limit */
} ip6_un1;
- u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
+ uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
@@ -84,18 +84,16 @@ struct ip6_hdr {
#define IPV6_VERSION 0x60
#endif
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#define s6_addr16 u.Word
#endif
-#if !defined(__Userspace_os_Windows)
-#if !defined(__Userspace_os_Linux)
+#if !defined(_WIN32) && !defined(__linux__) && !defined(__EMSCRIPTEN__)
#define s6_addr8 __u6_addr.__u6_addr8
#define s6_addr16 __u6_addr.__u6_addr16
#define s6_addr32 __u6_addr.__u6_addr32
#endif
-#endif
-#if !defined(__Userspace_os_FreeBSD) && !defined(__Userspace_os_OpenBSD) && !defined(__Userspace_os_DragonFly)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
struct route_in6 {
struct rtentry *ro_rt;
struct llentry *ro_lle;
diff --git a/netwerk/sctp/src/user_ip_icmp.h b/netwerk/sctp/src/user_ip_icmp.h
index e713417da8..a993411a17 100755
--- a/netwerk/sctp/src/user_ip_icmp.h
+++ b/netwerk/sctp/src/user_ip_icmp.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -40,8 +40,8 @@
* Internal of an ICMP Router Advertisement
*/
struct icmp_ra_addr {
- u_int32_t ira_addr;
- u_int32_t ira_preference;
+ uint32_t ira_addr;
+ uint32_t ira_preference;
};
/*
@@ -53,19 +53,19 @@ struct icmphdr {
u_short icmp_cksum; /* ones complement cksum of struct */
};
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#pragma pack (push, 1)
struct icmp6_hdr {
- u_int8_t icmp6_type;
- u_int8_t icmp6_code;
- u_int16_t icmp6_cksum;
+ uint8_t icmp6_type;
+ uint8_t icmp6_code;
+ uint16_t icmp6_cksum;
union {
- u_int32_t icmp6_un_data32[1];
- u_int16_t icmp6_un_data16[2];
- u_int8_t icmp6_un_data8[4];
+ uint32_t icmp6_un_data32[1];
+ uint16_t icmp6_un_data16[2];
+ uint8_t icmp6_un_data8[4];
} icmp6_dataun;
};
-#pragma pack()
+#pragma pack(pop)
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
#define icmp6_mtu icmp6_data32[0]
@@ -98,7 +98,7 @@ struct icmp {
struct ih_rtradv {
u_char irt_num_addrs;
u_char irt_wpa;
- u_int16_t irt_lifetime;
+ uint16_t irt_lifetime;
} ih_rtradv;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
@@ -126,7 +126,7 @@ struct icmp {
/* options and then 64 bits of data */
} id_ip;
struct icmp_ra_addr id_radv;
- u_int32_t id_mask;
+ uint32_t id_mask;
char id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
diff --git a/netwerk/sctp/src/user_malloc.h b/netwerk/sctp/src/user_malloc.h
index 4ea954898e..c588e094af 100755
--- a/netwerk/sctp/src/user_malloc.h
+++ b/netwerk/sctp/src/user_malloc.h
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -37,11 +37,11 @@
/*__Userspace__*/
#include <stdlib.h>
#include <sys/types.h>
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <strings.h>
#include <stdint.h>
#else
-#if defined(_MSC_VER) && _MSC_VER >= 1600
+#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ >= 1400)
#include <stdint.h>
#elif defined(SCTP_STDINT_INCLUDE)
#include SCTP_STDINT_INCLUDE
@@ -195,72 +195,9 @@ Start copy: Copied code for __Userspace__ */
#define MALLOC(space, cast, size, type, flags) \
((space) = (cast)malloc((u_long)(size))); \
do { \
- if(flags & M_ZERO) { \
+ if (flags & M_ZERO) { \
memset(space,0,size); \
} \
} while (0);
-
-/* End copy: Copied code for __Userspace__ */
-
-#if 0
-#ifdef _KERNEL
-#define MALLOC_DEFINE(type, shortdesc, longdesc) \
- struct malloc_type type[1] = { \
- { NULL, 0, 0, 0, 0, 0, M_MAGIC, shortdesc, NULL, NULL, \
- NULL, 0, NULL, NULL, 0, 0 } \
- }; \
- SYSINIT(type##_init, SI_SUB_KMEM, SI_ORDER_SECOND, malloc_init, \
- type); \
- SYSUNINIT(type##_uninit, SI_SUB_KMEM, SI_ORDER_ANY, \
- malloc_uninit, type)
-
-
-#define MALLOC_DECLARE(type) \
- extern struct malloc_type type[1]
-
-MALLOC_DECLARE(M_CACHE);
-MALLOC_DECLARE(M_DEVBUF);
-MALLOC_DECLARE(M_TEMP);
-
-MALLOC_DECLARE(M_IP6OPT); /* for INET6 */
-MALLOC_DECLARE(M_IP6NDP); /* for INET6 */
-
-/*
- * Deprecated macro versions of not-quite-malloc() and free().
- */
-#define MALLOC(space, cast, size, type, flags) \
- ((space) = (cast)malloc((u_long)(size), (type), (flags)))
-#define FREE(addr, type) free((addr), (type))
-
-/*
- * XXX this should be declared in <sys/uio.h>, but that tends to fail
- * because <sys/uio.h> is included in a header before the source file
- * has a chance to include <sys/malloc.h> to get MALLOC_DECLARE() defined.
- */
-MALLOC_DECLARE(M_IOV);
-
-extern struct mtx malloc_mtx;
-
-/* XXX struct malloc_type is unused for contig*(). */
-void contigfree(void *addr, unsigned long size, struct malloc_type *type);
-void *contigmalloc(unsigned long size, struct malloc_type *type, int flags,
- vm_paddr_t low, vm_paddr_t high, unsigned long alignment,
- unsigned long boundary);
-void free(void *addr, struct malloc_type *type);
-void *malloc(unsigned long size, struct malloc_type *type, int flags);
-void malloc_init(void *);
-int malloc_last_fail(void);
-void malloc_type_allocated(struct malloc_type *type, unsigned long size);
-void malloc_type_freed(struct malloc_type *type, unsigned long size);
-void malloc_uninit(void *);
-void *realloc(void *addr, unsigned long size, struct malloc_type *type,
- int flags);
-void *reallocf(void *addr, unsigned long size, struct malloc_type *type,
- int flags);
-
-
-#endif /* _KERNEL */
-#endif
-
#endif /* !_SYS_MALLOC_H_ */
diff --git a/netwerk/sctp/src/user_mbuf.c b/netwerk/sctp/src/user_mbuf.c
index de8f0fbc8c..57b532bb71 100755
--- a/netwerk/sctp/src/user_mbuf.c
+++ b/netwerk/sctp/src/user_mbuf.c
@@ -46,7 +46,6 @@
#include "user_atomic.h"
#include "netinet/sctp_pcb.h"
-struct mbstat mbstat;
#define KIPC_MAX_LINKHDR 4 /* int: max length of link header (see sys/sysclt.h) */
#define KIPC_MAX_PROTOHDR 5 /* int: max length of network header (see sys/sysclt.h)*/
int max_linkhdr = KIPC_MAX_LINKHDR;
@@ -121,7 +120,7 @@ m_get(int how, short type)
mbuf_mb_args.type = type;
#endif
/* Mbuf master zone, zone_mbuf, has already been
- * created in mbuf_init() */
+ * created in mbuf_initialize() */
mret = SCTP_ZONE_GET(zone_mbuf, struct mbuf);
#if defined(SCTP_SIMPLE_ALLOCATOR)
mb_ctor_mbuf(mret, &mbuf_mb_args, 0);
@@ -204,59 +203,59 @@ m_free(struct mbuf *m)
}
-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)
{
caddr_t mclust_ret;
#if defined(SCTP_SIMPLE_ALLOCATOR)
- struct clust_args clust_mb_args;
+ struct clust_args clust_mb_args_l;
#endif
if (m->m_flags & M_EXT) {
SCTPDBG(SCTP_DEBUG_USR, "%s: %p mbuf already has cluster\n", __func__, (void *)m);
}
m->m_ext.ext_buf = (char *)NULL;
#if defined(SCTP_SIMPLE_ALLOCATOR)
- clust_mb_args.parent_mbuf = m;
+ clust_mb_args_l.parent_mbuf = m;
#endif
mclust_ret = SCTP_ZONE_GET(zone_clust, char);
#if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_ctor_clust(mclust_ret, &clust_mb_args, 0);
+ mb_ctor_clust(mclust_ret, &clust_mb_args_l, 0);
#endif
/*mclust_ret = umem_cache_alloc(zone_clust, UMEM_DEFAULT);*/
/*
@@ -272,9 +271,9 @@ m_clget(struct mbuf *m, int how)
mclust_ret = SCTP_ZONE_GET(zone_clust, char);
#endif
/*mclust_ret = umem_cache_alloc(zone_clust, UMEM_DEFAULT);*/
- if (NULL == mclust_ret) {
- SCTPDBG(SCTP_DEBUG_USR, "Memory allocation failure in %s\n", __func__);
- }
+ /* if (NULL == mclust_ret) { */
+ SCTPDBG(SCTP_DEBUG_USR, "Memory allocation failure in %s\n", __func__);
+ /* } */
}
#if USING_MBUF_CONSTRUCTOR
@@ -286,6 +285,166 @@ m_clget(struct mbuf *m, int how)
#endif
}
+struct mbuf *
+m_getm2(struct mbuf *m, int len, int how, short type, int flags, int allonebuf)
+{
+ struct mbuf *mb, *nm = NULL, *mtail = NULL;
+ int size, mbuf_threshold, space_needed = len;
+
+ KASSERT(len >= 0, ("%s: len is < 0", __func__));
+
+ /* Validate flags. */
+ flags &= (M_PKTHDR | M_EOR);
+
+ /* Packet header mbuf must be first in chain. */
+ if ((flags & M_PKTHDR) && m != NULL) {
+ flags &= ~M_PKTHDR;
+ }
+
+ if (allonebuf == 0)
+ mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count);
+ else
+ mbuf_threshold = 1;
+
+ /* Loop and append maximum sized mbufs to the chain tail. */
+ while (len > 0) {
+ if ((!allonebuf && len >= MCLBYTES) || (len > (int)(((mbuf_threshold - 1) * MLEN) + MHLEN))) {
+ mb = m_gethdr(how, type);
+ MCLGET(mb, how);
+ size = MCLBYTES;
+ /* SCTP_BUF_LEN(mb) = MCLBYTES; */
+ } else if (flags & M_PKTHDR) {
+ mb = m_gethdr(how, type);
+ if (len < MHLEN) {
+ size = len;
+ } else {
+ size = MHLEN;
+ }
+ } else {
+ mb = m_get(how, type);
+ if (len < MLEN) {
+ size = len;
+ } else {
+ size = MLEN;
+ }
+ }
+
+ /* Fail the whole operation if one mbuf can't be allocated. */
+ if (mb == NULL) {
+ if (nm != NULL)
+ m_freem(nm);
+ return (NULL);
+ }
+
+ if (allonebuf != 0 && size < space_needed) {
+ m_freem(mb);
+ return (NULL);
+ }
+
+ /* Book keeping. */
+ len -= size;
+ if (mtail != NULL)
+ mtail->m_next = mb;
+ else
+ nm = mb;
+ mtail = mb;
+ flags &= ~M_PKTHDR; /* Only valid on the first mbuf. */
+ }
+ if (flags & M_EOR) {
+ mtail->m_flags |= M_EOR; /* Only valid on the last mbuf. */
+ }
+
+ /* If mbuf was supplied, append new chain to the end of it. */
+ if (m != NULL) {
+ for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);
+ mtail->m_next = nm;
+ mtail->m_flags &= ~M_EOR;
+ } else {
+ m = nm;
+ }
+
+ return (m);
+}
+
+/*
+ * Copy the contents of uio into a properly sized mbuf chain.
+ */
+struct mbuf *
+m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
+{
+ struct mbuf *m, *mb;
+ int error, length;
+ ssize_t total;
+ int progress = 0;
+
+ /*
+ * len can be zero or an arbitrary large value bound by
+ * the total data supplied by the uio.
+ */
+ if (len > 0)
+ total = min(uio->uio_resid, len);
+ else
+ total = uio->uio_resid;
+ /*
+ * The smallest unit returned by m_getm2() is a single mbuf
+ * with pkthdr. We can't align past it.
+ */
+ if (align >= MHLEN)
+ return (NULL);
+ /*
+ * Give us the full allocation or nothing.
+ * If len is zero return the smallest empty mbuf.
+ */
+ m = m_getm2(NULL, (int)max(total + align, 1), how, MT_DATA, flags, 0);
+ if (m == NULL)
+ return (NULL);
+ m->m_data += align;
+
+ /* Fill all mbufs with uio data and update header information. */
+ for (mb = m; mb != NULL; mb = mb->m_next) {
+ length = (int)min(M_TRAILINGSPACE(mb), total - progress);
+ error = uiomove(mtod(mb, void *), length, uio);
+ if (error) {
+ m_freem(m);
+ return (NULL);
+ }
+
+ mb->m_len = length;
+ progress += length;
+ if (flags & M_PKTHDR)
+ m->m_pkthdr.len += length;
+ }
+ KASSERT(progress == total, ("%s: progress != total", __func__));
+
+ return (m);
+}
+
+u_int
+m_length(struct mbuf *m0, struct mbuf **last)
+{
+ struct mbuf *m;
+ u_int len;
+
+ len = 0;
+ for (m = m0; m != NULL; m = m->m_next) {
+ len += m->m_len;
+ if (m->m_next == NULL)
+ break;
+ }
+ if (last != NULL)
+ *last = m;
+ return (len);
+}
+
+struct mbuf *
+m_last(struct mbuf *m)
+{
+ while (m->m_next) {
+ m = m->m_next;
+ }
+ return (m);
+}
+
/*
* Unlink a tag from the list of tags associated with an mbuf.
*/
@@ -313,7 +472,7 @@ m_tag_free(struct m_tag *t)
* XXX probably should be called m_tag_init, but that was already taken.
*/
static __inline void
-m_tag_setup(struct m_tag *t, u_int32_t cookie, int type, int len)
+m_tag_setup(struct m_tag *t, uint32_t cookie, int type, int len)
{
t->m_tag_id = type;
@@ -327,12 +486,8 @@ m_tag_setup(struct m_tag *t, u_int32_t cookie, int type, int len)
/************ End functions to substitute umem_cache_alloc and umem_cache_free **************/
-/* __Userspace__
- * TODO: mbuf_init must be called in the initialization routines
- * of userspace stack.
- */
void
-mbuf_init(void *dummy)
+mbuf_initialize(void *dummy)
{
/*
@@ -351,7 +506,7 @@ mbuf_init(void *dummy)
#else
zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0,
mb_ctor_mbuf, mb_dtor_mbuf, NULL,
- NUULL,
+ NULL,
NULL, 0);
#endif
/*zone_ext_refcnt = umem_cache_create(MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int), 0,
@@ -380,26 +535,6 @@ mbuf_init(void *dummy)
*
*/
-
- /*
- * [Re]set counters and local statistics knobs.
- *
- */
-
- mbstat.m_mbufs = 0;
- mbstat.m_mclusts = 0;
- mbstat.m_drain = 0;
- mbstat.m_msize = MSIZE;
- mbstat.m_mclbytes = MCLBYTES;
- mbstat.m_minclsize = MINCLSIZE;
- mbstat.m_mlen = MLEN;
- mbstat.m_mhlen = MHLEN;
- mbstat.m_numtypes = MT_NTYPES;
-
- mbstat.m_mcfail = mbstat.m_mpfail = 0;
- mbstat.sf_iocnt = 0;
- mbstat.sf_allocwait = mbstat.sf_allocfail = 0;
-
}
@@ -732,11 +867,10 @@ m_pullup(struct mbuf *n, int len)
if (n->m_flags & M_PKTHDR)
M_MOVE_PKTHDR(m, n);
}
- space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
+ space = (int)(&m->m_dat[MLEN] - (m->m_data + m->m_len));
do {
count = min(min(max(len, max_protohdr), space), n->m_len);
- bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
- (u_int)count);
+ memcpy(mtod(m, caddr_t) + m->m_len,mtod(n, caddr_t), (u_int)count);
len -= count;
m->m_len += count;
n->m_len -= count;
@@ -754,7 +888,6 @@ m_pullup(struct mbuf *n, int len)
return (m);
bad:
m_freem(n);
- mbstat.m_mpfail++; /* XXX: No consistency. */
return (NULL);
}
@@ -890,19 +1023,17 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
* easy cases first.
* we need to use m_copydata() to get data from <n->m_next, 0>.
*/
- if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
- && writable) {
+ if ((off == 0 || offp) && (M_TRAILINGSPACE(n) >= tlen) && writable) {
m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
n->m_len += tlen;
m_adj(n->m_next, tlen);
goto ok;
}
- if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
- && writable) {
+ if ((off == 0 || offp) && (M_LEADINGSPACE(n->m_next) >= hlen) && writable) {
n->m_next->m_data -= hlen;
n->m_next->m_len += hlen;
- bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
+ memcpy( mtod(n->m_next, caddr_t), mtod(n, caddr_t) + off,hlen);
n->m_len -= hlen;
n = n->m_next;
off = 0;
@@ -924,7 +1055,7 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
}
/* get hlen from <n, off> into <o, 0> */
o->m_len = hlen;
- bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
+ memcpy(mtod(o, caddr_t), mtod(n, caddr_t) + off, hlen);
n->m_len -= hlen;
/* get tlen from <n->m_next, 0> into <o, hlen> */
m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
@@ -992,7 +1123,13 @@ m_copym(struct mbuf *m, int off0, int len, int wait)
KASSERT(off >= 0, ("m_copym, negative off %d", off));
KASSERT(len >= 0, ("m_copym, negative len %d", len));
+ KASSERT(m != NULL, ("m_copym, m is NULL"));
+#if !defined(INVARIANTS)
+ if (m == NULL) {
+ return (NULL);
+ }
+#endif
if (off == 0 && m->m_flags & M_PKTHDR)
copyhdr = 1;
while (off > 0) {
@@ -1030,21 +1167,17 @@ m_copym(struct mbuf *m, int off0, int len, int wait)
n->m_data = m->m_data + off;
mb_dupcl(n, m);
} else
- bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
- (u_int)n->m_len);
+ memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off, (u_int)n->m_len);
if (len != M_COPYALL)
len -= n->m_len;
off = 0;
m = m->m_next;
np = &n->m_next;
}
- if (top == NULL)
- mbstat.m_mcfail++; /* XXX: No consistency. */
return (top);
nospace:
m_freem(top);
- mbstat.m_mcfail++; /* XXX: No consistency. */
return (NULL);
}
@@ -1080,6 +1213,8 @@ int
m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how)
{
+ KASSERT(to, ("m_dup_pkthdr: to is NULL"));
+ KASSERT(from, ("m_dup_pkthdr: from is NULL"));
to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT);
if ((to->m_flags & M_EXT) == 0)
to->m_data = to->m_pktdat;
@@ -1098,13 +1233,13 @@ m_tag_copy(struct m_tag *t, int how)
p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how);
if (p == NULL)
return (NULL);
- bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
+ memcpy(p + 1, t + 1, t->m_tag_len); /* Copy the data */
return p;
}
/* Get a packet tag structure along with specified data following. */
struct m_tag *
-m_tag_alloc(u_int32_t cookie, int type, int len, int wait)
+m_tag_alloc(uint32_t cookie, int type, int len, int wait)
{
struct m_tag *t;
@@ -1146,7 +1281,7 @@ m_copyback(struct mbuf *m0, int off, int len, caddr_t cp)
n = m_get(M_NOWAIT, m->m_type);
if (n == NULL)
goto out;
- bzero(mtod(n, caddr_t), MLEN);
+ memset(mtod(n, caddr_t), 0, MLEN);
n->m_len = min(MLEN, len + off);
m->m_next = n;
}
@@ -1154,7 +1289,7 @@ m_copyback(struct mbuf *m0, int off, int len, caddr_t cp)
}
while (len > 0) {
mlen = min (m->m_len - off, len);
- bcopy(cp, off + mtod(m, caddr_t), (u_int)mlen);
+ memcpy(off + mtod(m, caddr_t), cp, (u_int)mlen);
cp += mlen;
len -= mlen;
mlen += off;
@@ -1198,7 +1333,7 @@ m_prepend(struct mbuf *m, int len, int how)
M_MOVE_PKTHDR(mn, m);
mn->m_next = m;
m = mn;
- if(m->m_flags & M_PKTHDR) {
+ if (m->m_flags & M_PKTHDR) {
if (len < MHLEN)
MH_ALIGN(m, len);
} else {
@@ -1230,7 +1365,7 @@ m_copydata(const struct mbuf *m, int off, int len, caddr_t cp)
while (len > 0) {
KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain"));
count = min(m->m_len - off, len);
- bcopy(mtod(m, caddr_t) + off, cp, count);
+ memcpy(cp, mtod(m, caddr_t) + off, count);
len -= count;
cp += count;
off = 0;
@@ -1257,7 +1392,7 @@ m_cat(struct mbuf *m, struct mbuf *n)
return;
}
/* splat the data from one into the other */
- bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, (u_int)n->m_len);
+ memcpy(mtod(m, caddr_t) + m->m_len, mtod(n, caddr_t), (u_int)n->m_len);
m->m_len += n->m_len;
n = m_free(n);
}
@@ -1400,7 +1535,7 @@ extpacket:
n->m_data = m->m_data + len;
mb_dupcl(n, m);
} else {
- bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
+ memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + len, remain);
}
n->m_len = remain;
m->m_len = len;
@@ -1421,7 +1556,7 @@ pack_send_buffer(caddr_t buffer, struct mbuf* mb){
do {
count_to_copy = mb->m_len;
- bcopy(mtod(mb, caddr_t), buffer+offset, count_to_copy);
+ memcpy(buffer+offset, mtod(mb, caddr_t), count_to_copy);
offset += count_to_copy;
total_count_copied += count_to_copy;
mb = mb->m_next;
diff --git a/netwerk/sctp/src/user_mbuf.h b/netwerk/sctp/src/user_mbuf.h
index f3717407e1..c11b38c9cb 100755
--- a/netwerk/sctp/src/user_mbuf.h
+++ b/netwerk/sctp/src/user_mbuf.h
@@ -55,10 +55,13 @@ struct mbuf * m_gethdr(int how, short type);
struct mbuf * m_get(int how, short type);
struct mbuf * m_free(struct mbuf *m);
void m_clget(struct mbuf *m, int how);
-
+struct mbuf * m_getm2(struct mbuf *m, int len, int how, short type, int flags, int allonebuf);
+struct mbuf *m_uiotombuf(struct uio *uio, int how, int len, int align, int flags);
+u_int m_length(struct mbuf *m0, struct mbuf **last);
+struct mbuf *m_last(struct mbuf *m);
/* mbuf initialization function */
-void mbuf_init(void *);
+void mbuf_initialize(void *);
#define M_MOVE_PKTHDR(to, from) m_move_pkthdr((to), (from))
#define MGET(m, how, type) ((m) = m_get((how), (type)))
@@ -107,7 +110,7 @@ void m_cat(struct mbuf *m, struct mbuf *n);
void m_adj(struct mbuf *, int);
void mb_free_ext(struct mbuf *);
void m_freem(struct mbuf *);
-struct m_tag *m_tag_alloc(u_int32_t, int, int, int);
+struct m_tag *m_tag_alloc(uint32_t, int, int, int);
struct mbuf *m_copym(struct mbuf *, int, int, int);
void m_copyback(struct mbuf *, int, int, caddr_t);
struct mbuf *m_pullup(struct mbuf *, int);
@@ -126,35 +129,6 @@ void m_copydata(const struct mbuf *, int, int, caddr_t);
a non-initialized mbuf */
/*
- * General mbuf allocator statistics structure.
- * __Userspace__ mbstat may be useful for gathering statistics.
- * In the kernel many of these statistics are no longer used as
- * they track allocator statistics through kernel UMA's built in statistics mechanism.
- */
-struct mbstat {
- u_long m_mbufs; /* XXX */
- u_long m_mclusts; /* XXX */
-
- u_long m_drain; /* times drained protocols for space */
- u_long m_mcfail; /* XXX: times m_copym failed */
- u_long m_mpfail; /* XXX: times m_pullup failed */
- u_long m_msize; /* length of an mbuf */
- u_long m_mclbytes; /* length of an mbuf cluster */
- u_long m_minclsize; /* min length of data to allocate a cluster */
- u_long m_mlen; /* length of data in an mbuf */
- u_long m_mhlen; /* length of data in a header mbuf */
-
- /* Number of mbtypes (gives # elems in mbtypes[] array: */
- short m_numtypes;
-
- /* XXX: Sendfile stats should eventually move to their own struct */
- u_long sf_iocnt; /* times sendfile had to do disk I/O */
- u_long sf_allocfail; /* times sfbuf allocation failed */
- u_long sf_allocwait; /* times sfbuf allocation had to wait */
-};
-
-
-/*
* Mbufs are of a single size, MSIZE (sys/param.h), which includes overhead.
* An mbuf may add a single "mbuf cluster" of size MCLBYTES (also in
* sys/param.h), which has no additional overhead and is used instead of the
@@ -187,9 +161,9 @@ struct m_hdr {
*/
struct m_tag {
SLIST_ENTRY(m_tag) m_tag_link; /* List of packet tags */
- u_int16_t m_tag_id; /* Tag ID */
- u_int16_t m_tag_len; /* Length of data */
- u_int32_t m_tag_cookie; /* ABI/Module ID */
+ uint16_t m_tag_id; /* Tag ID */
+ uint16_t m_tag_len; /* Length of data */
+ uint32_t m_tag_cookie; /* ABI/Module ID */
void (*m_tag_free)(struct m_tag *);
};
@@ -204,8 +178,8 @@ struct pkthdr {
/* variables for hardware checksum */
int csum_flags; /* flags regarding checksum */
int csum_data; /* data field used by csum routines */
- u_int16_t tso_segsz; /* TSO segment size */
- u_int16_t ether_vtag; /* Ethernet 802.1p+q vlan tag */
+ uint16_t tso_segsz; /* TSO segment size */
+ uint16_t ether_vtag; /* Ethernet 802.1p+q vlan tag */
SLIST_HEAD(packet_tags, m_tag) tags; /* list of packet tags */
};
@@ -267,7 +241,6 @@ struct mbuf {
#define M_PROTO3 0x0040 /* protocol-specific */
#define M_PROTO4 0x0080 /* protocol-specific */
#define M_PROTO5 0x0100 /* protocol-specific */
-#define M_SKIP_FIREWALL 0x4000 /* skip firewall processing */
#define M_FREELIST 0x8000 /* mbuf is on the free list */
@@ -275,7 +248,7 @@ struct mbuf {
* Flags copied when copying m_pkthdr.
*/
#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_RDONLY|M_PROTO1|M_PROTO1|M_PROTO2|\
- M_PROTO3|M_PROTO4|M_PROTO5|M_SKIP_FIREWALL|\
+ M_PROTO3|M_PROTO4|M_PROTO5|\
M_BCAST|M_MCAST|M_FRAG|M_FIRSTFRAG|M_LASTFRAG|\
M_VLANTAG|M_PROMISC)
@@ -350,9 +323,6 @@ void m_tag_free_default(struct m_tag *);
extern int max_linkhdr; /* Largest link-level header */
extern int max_protohdr; /* Size of largest protocol layer header. See user_mbuf.c */
-extern struct mbstat mbstat; /* General mbuf stats/infos */
-
-
/*
* Evaluate TRUE if it's safe to write to the mbuf m's data region (this can
* be both the local data payload, or an external buffer area, depending on
@@ -371,9 +341,9 @@ extern struct mbstat mbstat; /* General mbuf stats/infos */
* of checking writability of the mbuf data area rests solely with the caller.
*/
#define M_LEADINGSPACE(m) \
- ((m)->m_flags & M_EXT ? \
+ (((m)->m_flags & M_EXT) ? \
(M_WRITABLE(m) ? (m)->m_data - (m)->m_ext.ext_buf : 0): \
- (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \
+ ((m)->m_flags & M_PKTHDR)? (m)->m_data - (m)->m_pktdat : \
(m)->m_data - (m)->m_dat)
/*
@@ -383,7 +353,7 @@ extern struct mbstat mbstat; /* General mbuf stats/infos */
* of checking writability of the mbuf data area rests solely with the caller.
*/
#define M_TRAILINGSPACE(m) \
- ((m)->m_flags & M_EXT ? \
+ (((m)->m_flags & M_EXT) ? \
(M_WRITABLE(m) ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size \
- ((m)->m_data + (m)->m_len) : 0) : \
&(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len))
@@ -435,4 +405,9 @@ extern struct mbstat mbstat; /* General mbuf stats/infos */
(m)->m_data += (MHLEN - (len)) & ~(sizeof(long) - 1); \
} while (0)
+#define M_SIZE(m) \
+ (((m)->m_flags & M_EXT) ? (m)->m_ext.ext_size : \
+ ((m)->m_flags & M_PKTHDR) ? MHLEN : \
+ MLEN)
+
#endif
diff --git a/netwerk/sctp/src/user_queue.h b/netwerk/sctp/src/user_queue.h
index 44f8994902..fcd368bdd2 100755
--- a/netwerk/sctp/src/user_queue.h
+++ b/netwerk/sctp/src/user_queue.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -144,8 +144,8 @@ struct name { \
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
-#if defined (__Userspace_os_Windows)
-#if defined (SLIST_ENTRY)
+#if defined(_WIN32)
+#if defined(SLIST_ENTRY)
#undef SLIST_ENTRY
#endif
#endif
diff --git a/netwerk/sctp/src/user_recv_thread.c b/netwerk/sctp/src/user_recv_thread.c
index 7b2ff58464..bb436cd20d 100755
--- a/netwerk/sctp/src/user_recv_thread.c
+++ b/netwerk/sctp/src/user_recv_thread.c
@@ -30,12 +30,12 @@
#if defined(INET) || defined(INET6)
#include <sys/types.h>
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
-#if !defined(__Userspace_os_DragonFly) && !defined(__Userspace_os_FreeBSD) && !defined(__Userspace_os_NetBSD)
+#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
#include <sys/uio.h>
#else
#include <user_ip6_var.h>
@@ -46,7 +46,7 @@
#include <netinet/sctp_pcb.h>
#include <netinet/sctp_input.h>
#if 0
-#if defined(__Userspace_os_Linux)
+#if defined(__linux__)
#include <linux/netlink.h>
#ifdef HAVE_LINUX_IF_ADDR_H
#include <linux/if_addr.h>
@@ -56,23 +56,26 @@
#endif
#endif
#endif
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
#include <net/route.h>
#endif
/* local macros and datatypes used to get IP addresses system independently */
-#if !defined(IP_PKTINFO ) && ! defined(IP_RECVDSTADDR)
+#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR)
# error "Can't determine socket option to use to get UDP IP"
#endif
void recv_thread_destroy(void);
-#define MAXLEN_MBUF_CHAIN 32 /* What should this value be? */
+
+#define MAXLEN_MBUF_CHAIN 128
+
#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
+
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
#define NEXT_SA(ap) ap = (struct sockaddr *) \
((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (uint32_t)) : sizeof(uint32_t)))
#endif
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
static void
sctp_get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
@@ -92,51 +95,36 @@ static void
sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa)
{
int rc;
- struct ifaddrs *ifa, *found_ifa = NULL;
+ struct ifaddrs *ifa, *ifas;
/* handle only the types we want */
if ((type != RTM_NEWADDR) && (type != RTM_DELADDR)) {
return;
}
- rc = getifaddrs(&g_interfaces);
+ rc = getifaddrs(&ifas);
if (rc != 0) {
return;
}
- for (ifa = g_interfaces; ifa; ifa = ifa->ifa_next) {
+ for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
if (index == if_nametoindex(ifa->ifa_name)) {
- found_ifa = ifa;
break;
}
}
- if (found_ifa == NULL) {
+ if (ifa == NULL) {
+ freeifaddrs(ifas);
return;
}
- switch (sa->sa_family) {
-#ifdef INET
- case AF_INET:
- ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in));
- memcpy(ifa->ifa_addr, sa, sizeof(struct sockaddr_in));
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in6));
- memcpy(ifa->ifa_addr, sa, sizeof(struct sockaddr_in6));
- break;
-#endif
- default:
- SCTPDBG(SCTP_DEBUG_USR, "Address family %d not supported.\n", sa->sa_family);
- }
-
/* relay the appropriate address change to the base code */
if (type == RTM_NEWADDR) {
- (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, ifa, if_nametoindex(ifa->ifa_name),
+ (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID,
+ NULL,
+ if_nametoindex(ifa->ifa_name),
0,
ifa->ifa_name,
- (void *)ifa,
- ifa->ifa_addr,
+ NULL,
+ sa,
0,
1);
} else {
@@ -144,6 +132,7 @@ sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa
if_nametoindex(ifa->ifa_name),
ifa->ifa_name);
}
+ freeifaddrs(ifas);
}
static void *
@@ -154,8 +143,10 @@ recv_function_route(void *arg)
char rt_buffer[1024];
struct sockaddr *sa, *rti_info[RTAX_MAX];
+ sctp_userspace_set_threadname("SCTP addr mon");
+
while (1) {
- bzero(rt_buffer, sizeof(rt_buffer));
+ memset(rt_buffer, 0, sizeof(rt_buffer));
ret = recv(SCTP_BASE_VAR(userspace_route), rt_buffer, sizeof(rt_buffer), 0);
if (ret > 0) {
@@ -176,7 +167,7 @@ recv_function_route(void *arg)
}
}
if (ret < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
break;
@@ -223,7 +214,7 @@ recv_function_route(void *arg)
len = recvmsg(SCTP_BASE_VAR(userspace_route), &msg, 0);
if (len < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
break;
@@ -237,7 +228,7 @@ recv_function_route(void *arg)
if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) {
rtmsg = (struct ifaddrmsg *)NLMSG_DATA(nh);
rtatp = (struct rtattr *)IFA_RTA(rtmsg);
- if(rtatp->rta_type == IFA_ADDRESS) {
+ if (rtatp->rta_type == IFA_ADDRESS) {
inp = (struct in_addr *)RTA_DATA(rtatp);
switch (rtmsg->ifa_family) {
#ifdef INET
@@ -279,33 +270,34 @@ recv_function_raw(void *arg)
struct sctphdr *sh;
uint16_t port;
int offset, ecn = 0;
-#if !defined(SCTP_WITH_NO_CSUM)
int compute_crc = 1;
-#endif
struct sctp_chunkhdr *ch;
struct sockaddr_in src, dst;
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
+ unsigned int ncounter;
struct msghdr msg;
struct iovec recv_iovec[MAXLEN_MBUF_CHAIN];
#else
WSABUF recv_iovec[MAXLEN_MBUF_CHAIN];
int nResult, m_ErrorCode;
DWORD flags;
+ DWORD ncounter;
struct sockaddr_in from;
int fromlen;
#endif
-
/*Initially the entire set of mbufs is to be allocated.
to_fill indicates this amount. */
int to_fill = MAXLEN_MBUF_CHAIN;
/* iovlen is the size of each mbuf in the chain */
- int i, n, ncounter = 0;
- int iovlen = MCLBYTES;
+ int i, n;
+ unsigned int iovlen = MCLBYTES;
int want_ext = (iovlen > MLEN)? 1 : 0;
int want_header = 0;
-
- bzero((void *)&src, sizeof(struct sockaddr_in));
- bzero((void *)&dst, sizeof(struct sockaddr_in));
+
+ sctp_userspace_set_threadname("SCTP/IP4 rcv");
+
+ memset(&src, 0, sizeof(struct sockaddr_in));
+ memset(&dst, 0, sizeof(struct sockaddr_in));
recvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
@@ -316,7 +308,7 @@ recv_function_raw(void *arg)
Have tried both sending and receiving
*/
recvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
recv_iovec[i].iov_base = (caddr_t)recvmbuf[i]->m_data;
recv_iovec[i].iov_len = iovlen;
#else
@@ -325,25 +317,23 @@ recv_function_raw(void *arg)
#endif
}
to_fill = 0;
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
flags = 0;
ncounter = 0;
fromlen = sizeof(struct sockaddr_in);
- bzero((void *)&from, sizeof(struct sockaddr_in));
+ memset(&from, 0, sizeof(struct sockaddr_in));
- nResult = WSARecvFrom(SCTP_BASE_VAR(userspace_rawsctp), recv_iovec, MAXLEN_MBUF_CHAIN, (LPDWORD)&ncounter, (LPDWORD)&flags, (struct sockaddr*)&from, &fromlen, NULL, NULL);
+ nResult = WSARecvFrom(SCTP_BASE_VAR(userspace_rawsctp), recv_iovec, MAXLEN_MBUF_CHAIN, &ncounter, &flags, (struct sockaddr *)&from, &fromlen, NULL, NULL);
if (nResult != 0) {
m_ErrorCode = WSAGetLastError();
- if (m_ErrorCode == WSAETIMEDOUT) {
- continue;
- }
if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
break;
}
+ continue;
}
n = ncounter;
#else
- bzero((void *)&msg, sizeof(struct msghdr));
+ memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = recv_iovec;
@@ -352,7 +342,7 @@ recv_function_raw(void *arg)
msg.msg_controllen = 0;
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0);
if (n < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
break;
@@ -363,33 +353,40 @@ recv_function_raw(void *arg)
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
- if (n <= iovlen) {
+ if ((unsigned int)n <= iovlen) {
SCTP_BUF_LEN(recvmbuf[0]) = n;
(to_fill)++;
} else {
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);
}
-
+
+ offset = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ if (SCTP_BUF_LEN(recvmbuf[0]) < offset) {
+ if ((recvmbuf[0] = m_pullup(recvmbuf[0], offset)) == NULL) {
+ SCTP_STAT_INCR(sctps_hdrops);
+ continue;
+ }
+ }
iphdr = mtod(recvmbuf[0], struct ip *);
sh = (struct sctphdr *)((caddr_t)iphdr + sizeof(struct ip));
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
- offset = sizeof(struct ip) + sizeof(struct sctphdr);
-
+ offset -= sizeof(struct sctp_chunkhdr);
+
if (iphdr->ip_tos != 0) {
- ecn = iphdr->ip_tos & 0x02;
+ ecn = iphdr->ip_tos & 0x03;
}
-
+
dst.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
dst.sin_len = sizeof(struct sockaddr_in);
@@ -403,36 +400,35 @@ recv_function_raw(void *arg)
#endif
src.sin_addr = iphdr->ip_src;
src.sin_port = sh->src_port;
-
+
/* SCTP does not allow broadcasts or multicasts */
if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
- return (NULL);
+ m_freem(recvmbuf[0]);
+ continue;
}
if (SCTP_IS_IT_BROADCAST(dst.sin_addr, recvmbuf[0])) {
- return (NULL);
+ m_freem(recvmbuf[0]);
+ continue;
}
port = 0;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_recvnocrc);
-#else
- if (src.sin_addr.s_addr == dst.sin_addr.s_addr) {
+ if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ ((IN4_ISLOOPBACK_ADDRESS(&src.sin_addr) &&
+ IN4_ISLOOPBACK_ADDRESS(&dst.sin_addr)) ||
+ (src.sin_addr.s_addr == dst.sin_addr.s_addr))) {
compute_crc = 0;
- SCTP_STAT_INCR(sctps_recvnocrc);
+ SCTP_STAT_INCR(sctps_recvhwcrc);
} else {
SCTP_STAT_INCR(sctps_recvswcrc);
}
-#endif
SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset);
- sctp_common_input_processing(&recvmbuf[0], sizeof(struct ip), offset, n,
+ sctp_common_input_processing(&recvmbuf[0], sizeof(struct ip), offset, n,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
compute_crc,
-#endif
ecn,
SCTP_DEFAULT_VRFID, port);
if (recvmbuf[0]) {
@@ -444,6 +440,7 @@ recv_function_raw(void *arg)
}
/* free the array itself */
free(recvmbuf);
+ SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP4 rcv\n", __func__);
return (NULL);
}
#endif
@@ -453,7 +450,8 @@ static void *
recv_function_raw6(void *arg)
{
struct mbuf **recvmbuf6;
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
+ unsigned int ncounter = 0;
struct iovec recv_iovec[MAXLEN_MBUF_CHAIN];
struct msghdr msg;
struct cmsghdr *cmsgptr;
@@ -461,9 +459,8 @@ recv_function_raw6(void *arg)
#else
WSABUF recv_iovec[MAXLEN_MBUF_CHAIN];
int nResult, m_ErrorCode;
- DWORD flags;
+ DWORD ncounter = 0;
struct sockaddr_in6 from;
- int fromlen;
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
LPFN_WSARECVMSG WSARecvMsg;
WSACMSGHDR *cmsgptr;
@@ -474,19 +471,18 @@ recv_function_raw6(void *arg)
struct sctphdr *sh;
int offset;
struct sctp_chunkhdr *ch;
-
/*Initially the entire set of mbufs is to be allocated.
to_fill indicates this amount. */
int to_fill = MAXLEN_MBUF_CHAIN;
/* iovlen is the size of each mbuf in the chain */
- int i, n, ncounter = 0;
-#if !defined(SCTP_WITH_NO_CSUM)
+ int i, n;
int compute_crc = 1;
-#endif
- int iovlen = MCLBYTES;
+ unsigned int iovlen = MCLBYTES;
int want_ext = (iovlen > MLEN)? 1 : 0;
int want_header = 0;
+ sctp_userspace_set_threadname("SCTP/IP6 rcv");
+
recvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
for (;;) {
@@ -496,7 +492,7 @@ recv_function_raw6(void *arg)
Have tried both sending and receiving
*/
recvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
recv_iovec[i].iov_base = (caddr_t)recvmbuf6[i]->m_data;
recv_iovec[i].iov_len = iovlen;
#else
@@ -505,11 +501,9 @@ recv_function_raw6(void *arg)
#endif
}
to_fill = 0;
-#if defined(__Userspace_os_Windows)
- flags = 0;
+#if defined(_WIN32)
ncounter = 0;
- fromlen = sizeof(struct sockaddr_in6);
- bzero((void *)&from, sizeof(struct sockaddr_in6));
+ memset(&from, 0, sizeof(struct sockaddr_in6));
nResult = WSAIoctl(SCTP_BASE_VAR(userspace_rawsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
&WSARecvMsg, sizeof WSARecvMsg,
@@ -526,28 +520,28 @@ recv_function_raw6(void *arg)
}
if (nResult != 0) {
m_ErrorCode = WSAGetLastError();
- if (m_ErrorCode == WSAETIMEDOUT)
- continue;
- if (m_ErrorCode == WSAENOTSOCK || m_ErrorCode == WSAEINTR)
+ if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
break;
+ }
+ continue;
}
n = ncounter;
#else
- bzero((void *)&msg, sizeof(struct msghdr));
- bzero((void *)&src, sizeof(struct sockaddr_in6));
- bzero((void *)&dst, sizeof(struct sockaddr_in6));
- bzero((void *)cmsgbuf, CMSG_SPACE(sizeof (struct in6_pktinfo)));
+ memset(&msg, 0, sizeof(struct msghdr));
+ memset(&src, 0, sizeof(struct sockaddr_in6));
+ memset(&dst, 0, sizeof(struct sockaddr_in6));
+ memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo)));
msg.msg_name = (void *)&src;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = recv_iovec;
msg.msg_iovlen = MAXLEN_MBUF_CHAIN;
msg.msg_control = (void *)cmsgbuf;
- msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof (struct in6_pktinfo));
+ msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo));
msg.msg_flags = 0;
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, 0);
if (n < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
break;
@@ -558,20 +552,20 @@ recv_function_raw6(void *arg)
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
- if (n <= iovlen) {
+ if ((unsigned int)n <= iovlen) {
SCTP_BUF_LEN(recvmbuf6[0]) = n;
(to_fill)++;
} else {
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);
}
@@ -586,9 +580,22 @@ recv_function_raw6(void *arg)
}
}
+ /* SCTP does not allow broadcasts or multicasts */
+ if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) {
+ m_freem(recvmbuf6[0]);
+ continue;
+ }
+
+ offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ if (SCTP_BUF_LEN(recvmbuf6[0]) < offset) {
+ if ((recvmbuf6[0] = m_pullup(recvmbuf6[0], offset)) == NULL) {
+ SCTP_STAT_INCR(sctps_hdrops);
+ continue;
+ }
+ }
sh = mtod(recvmbuf6[0], struct sctphdr *);
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
- offset = sizeof(struct sctphdr);
+ offset -= sizeof(struct sctp_chunkhdr);
dst.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
@@ -601,25 +608,20 @@ recv_function_raw6(void *arg)
src.sin6_len = sizeof(struct sockaddr_in6);
#endif
src.sin6_port = sh->src_port;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_recvnocrc);
-#else
- if (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0) {
+ if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) {
compute_crc = 0;
- SCTP_STAT_INCR(sctps_recvnocrc);
+ SCTP_STAT_INCR(sctps_recvhwcrc);
} else {
SCTP_STAT_INCR(sctps_recvswcrc);
}
-#endif
SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset);
- sctp_common_input_processing(&recvmbuf6[0], 0, offset, n,
+ sctp_common_input_processing(&recvmbuf6[0], 0, offset, n,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
compute_crc,
-#endif
0,
SCTP_DEFAULT_VRFID, 0);
if (recvmbuf6[0]) {
@@ -631,6 +633,7 @@ recv_function_raw6(void *arg)
}
/* free the array itself */
free(recvmbuf6);
+ SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP6 rcv\n", __func__);
return (NULL);
}
#endif
@@ -644,8 +647,8 @@ recv_function_udp(void *arg)
to_fill indicates this amount. */
int to_fill = MAXLEN_MBUF_CHAIN;
/* iovlen is the size of each mbuf in the chain */
- int i, n, ncounter, offset;
- int iovlen = MCLBYTES;
+ int i, n, offset;
+ unsigned int iovlen = MCLBYTES;
int want_ext = (iovlen > MLEN)? 1 : 0;
int want_header = 0;
struct sctphdr *sh;
@@ -657,10 +660,9 @@ recv_function_udp(void *arg)
#else
char cmsgbuf[CMSG_SPACE(sizeof(struct in_addr))];
#endif
-#if !defined(SCTP_WITH_NO_CSUM)
int compute_crc = 1;
-#endif
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
+ unsigned int ncounter;
struct iovec iov[MAXLEN_MBUF_CHAIN];
struct msghdr msg;
struct cmsghdr *cmsgptr;
@@ -672,8 +674,11 @@ recv_function_udp(void *arg)
WSAMSG msg;
int nResult, m_ErrorCode;
WSACMSGHDR *cmsgptr;
+ DWORD ncounter;
#endif
+ sctp_userspace_set_threadname("SCTP/UDP/IP4 rcv");
+
udprecvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
while (1) {
@@ -683,7 +688,7 @@ recv_function_udp(void *arg)
Have tried both sending and receiving
*/
udprecvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
iov[i].iov_base = (caddr_t)udprecvmbuf[i]->m_data;
iov[i].iov_len = iovlen;
#else
@@ -692,16 +697,16 @@ recv_function_udp(void *arg)
#endif
}
to_fill = 0;
-#if !defined(__Userspace_os_Windows)
- bzero((void *)&msg, sizeof(struct msghdr));
+#if !defined(_WIN32)
+ memset(&msg, 0, sizeof(struct msghdr));
#else
- bzero((void *)&msg, sizeof(WSAMSG));
+ memset(&msg, 0, sizeof(WSAMSG));
#endif
- bzero((void *)&src, sizeof(struct sockaddr_in));
- bzero((void *)&dst, sizeof(struct sockaddr_in));
- bzero((void *)cmsgbuf, sizeof(cmsgbuf));
+ memset(&src, 0, sizeof(struct sockaddr_in));
+ memset(&dst, 0, sizeof(struct sockaddr_in));
+ memset(cmsgbuf, 0, sizeof(cmsgbuf));
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
msg.msg_name = (void *)&src;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_iov = iov;
@@ -712,7 +717,7 @@ recv_function_udp(void *arg)
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0);
if (n < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
break;
@@ -735,12 +740,10 @@ recv_function_udp(void *arg)
}
if (nResult != 0) {
m_ErrorCode = WSAGetLastError();
- if (m_ErrorCode == WSAETIMEDOUT) {
- continue;
- }
if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
break;
}
+ continue;
}
n = ncounter;
#endif
@@ -748,20 +751,20 @@ recv_function_udp(void *arg)
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
- if (n <= iovlen) {
+ if ((unsigned int)n <= iovlen) {
SCTP_BUF_LEN(udprecvmbuf[0]) = n;
(to_fill)++;
} else {
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);
}
@@ -796,38 +799,42 @@ recv_function_udp(void *arg)
/* SCTP does not allow broadcasts or multicasts */
if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
- return (NULL);
+ m_freem(udprecvmbuf[0]);
+ continue;
}
if (SCTP_IS_IT_BROADCAST(dst.sin_addr, udprecvmbuf[0])) {
- return (NULL);
+ m_freem(udprecvmbuf[0]);
+ continue;
}
- /*offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);*/
+ offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ if (SCTP_BUF_LEN(udprecvmbuf[0]) < offset) {
+ if ((udprecvmbuf[0] = m_pullup(udprecvmbuf[0], offset)) == NULL) {
+ SCTP_STAT_INCR(sctps_hdrops);
+ continue;
+ }
+ }
sh = mtod(udprecvmbuf[0], struct sctphdr *);
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
- offset = sizeof(struct sctphdr);
+ offset -= sizeof(struct sctp_chunkhdr);
+
port = src.sin_port;
src.sin_port = sh->src_port;
dst.sin_port = sh->dest_port;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_recvnocrc);
-#else
- if (src.sin_addr.s_addr == dst.sin_addr.s_addr) {
+ if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (src.sin_addr.s_addr == dst.sin_addr.s_addr)) {
compute_crc = 0;
- SCTP_STAT_INCR(sctps_recvnocrc);
+ SCTP_STAT_INCR(sctps_recvhwcrc);
} else {
SCTP_STAT_INCR(sctps_recvswcrc);
}
-#endif
SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset);
- sctp_common_input_processing(&udprecvmbuf[0], 0, offset, n,
+ sctp_common_input_processing(&udprecvmbuf[0], 0, offset, n,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
compute_crc,
-#endif
0,
SCTP_DEFAULT_VRFID, port);
if (udprecvmbuf[0]) {
@@ -839,6 +846,7 @@ recv_function_udp(void *arg)
}
/* free the array itself */
free(udprecvmbuf);
+ SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP4 rcv\n", __func__);
return (NULL);
}
#endif
@@ -852,8 +860,8 @@ recv_function_udp6(void *arg)
to_fill indicates this amount. */
int to_fill = MAXLEN_MBUF_CHAIN;
/* iovlen is the size of each mbuf in the chain */
- int i, n, ncounter, offset;
- int iovlen = MCLBYTES;
+ int i, n, offset;
+ unsigned int iovlen = MCLBYTES;
int want_ext = (iovlen > MLEN)? 1 : 0;
int want_header = 0;
struct sockaddr_in6 src, dst;
@@ -861,13 +869,12 @@ recv_function_udp6(void *arg)
uint16_t port;
struct sctp_chunkhdr *ch;
char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
-#if !defined(SCTP_WITH_NO_CSUM)
int compute_crc = 1;
-#endif
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
struct iovec iov[MAXLEN_MBUF_CHAIN];
struct msghdr msg;
struct cmsghdr *cmsgptr;
+ unsigned int ncounter;
#else
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
LPFN_WSARECVMSG WSARecvMsg;
@@ -876,8 +883,11 @@ recv_function_udp6(void *arg)
WSAMSG msg;
int nResult, m_ErrorCode;
WSACMSGHDR *cmsgptr;
+ DWORD ncounter;
#endif
+ sctp_userspace_set_threadname("SCTP/UDP/IP6 rcv");
+
udprecvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
while (1) {
for (i = 0; i < to_fill; i++) {
@@ -886,7 +896,7 @@ recv_function_udp6(void *arg)
Have tried both sending and receiving
*/
udprecvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
iov[i].iov_base = (caddr_t)udprecvmbuf6[i]->m_data;
iov[i].iov_len = iovlen;
#else
@@ -896,27 +906,27 @@ recv_function_udp6(void *arg)
}
to_fill = 0;
-#if !defined(__Userspace_os_Windows)
- bzero((void *)&msg, sizeof(struct msghdr));
+#if !defined(_WIN32)
+ memset(&msg, 0, sizeof(struct msghdr));
#else
- bzero((void *)&msg, sizeof(WSAMSG));
+ memset(&msg, 0, sizeof(WSAMSG));
#endif
- bzero((void *)&src, sizeof(struct sockaddr_in6));
- bzero((void *)&dst, sizeof(struct sockaddr_in6));
- bzero((void *)cmsgbuf, CMSG_SPACE(sizeof (struct in6_pktinfo)));
+ memset(&src, 0, sizeof(struct sockaddr_in6));
+ memset(&dst, 0, sizeof(struct sockaddr_in6));
+ memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo)));
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
msg.msg_name = (void *)&src;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = iov;
msg.msg_iovlen = MAXLEN_MBUF_CHAIN;
msg.msg_control = (void *)cmsgbuf;
- msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof (struct in6_pktinfo));
+ msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo));
msg.msg_flags = 0;
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, 0);
if (n < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
break;
@@ -943,12 +953,10 @@ recv_function_udp6(void *arg)
}
if (nResult != 0) {
m_ErrorCode = WSAGetLastError();
- if (m_ErrorCode == WSAETIMEDOUT) {
- continue;
- }
if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
break;
}
+ continue;
}
n = ncounter;
#endif
@@ -956,20 +964,20 @@ recv_function_udp6(void *arg)
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
- if (n <= iovlen) {
+ if ((unsigned int)n <= iovlen) {
SCTP_BUF_LEN(udprecvmbuf6[0]) = n;
(to_fill)++;
} else {
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);
}
@@ -990,35 +998,38 @@ recv_function_udp6(void *arg)
/* SCTP does not allow broadcasts or multicasts */
if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) {
- return (NULL);
+ m_freem(udprecvmbuf6[0]);
+ continue;
+ }
+
+ offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ if (SCTP_BUF_LEN(udprecvmbuf6[0]) < offset) {
+ if ((udprecvmbuf6[0] = m_pullup(udprecvmbuf6[0], offset)) == NULL) {
+ SCTP_STAT_INCR(sctps_hdrops);
+ continue;
+ }
}
-
sh = mtod(udprecvmbuf6[0], struct sctphdr *);
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
- offset = sizeof(struct sctphdr);
-
+ offset -= sizeof(struct sctp_chunkhdr);
+
port = src.sin6_port;
src.sin6_port = sh->src_port;
dst.sin6_port = sh->dest_port;
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_recvnocrc);
-#else
- if ((memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) {
+ if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) {
compute_crc = 0;
- SCTP_STAT_INCR(sctps_recvnocrc);
+ SCTP_STAT_INCR(sctps_recvhwcrc);
} else {
SCTP_STAT_INCR(sctps_recvswcrc);
}
-#endif
SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", (int)sizeof(struct sctphdr));
- sctp_common_input_processing(&udprecvmbuf6[0], 0, offset, n,
+ sctp_common_input_processing(&udprecvmbuf6[0], 0, offset, n,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
compute_crc,
-#endif
0,
SCTP_DEFAULT_VRFID, port);
if (udprecvmbuf6[0]) {
@@ -1030,17 +1041,23 @@ recv_function_udp6(void *arg)
}
/* free the array itself */
free(udprecvmbuf6);
+ SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP6 rcv\n", __func__);
return (NULL);
}
#endif
+#if defined(_WIN32)
+static void
+setReceiveBufferSize(SOCKET sfd, int new_size)
+#else
static void
setReceiveBufferSize(int sfd, int new_size)
+#endif
{
int ch = new_size;
if (setsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)&ch, sizeof(ch)) < 0) {
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", errno);
@@ -1049,13 +1066,18 @@ setReceiveBufferSize(int sfd, int new_size)
return;
}
+#if defined(_WIN32)
+static void
+setSendBufferSize(SOCKET sfd, int new_size)
+#else
static void
setSendBufferSize(int sfd, int new_size)
+#endif
{
int ch = new_size;
if (setsockopt (sfd, SOL_SOCKET, SO_SNDBUF, (void*)&ch, sizeof(ch)) < 0) {
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", errno);
@@ -1078,17 +1100,18 @@ recv_thread_init(void)
#if defined(INET) || defined(INET6)
const int on = 1;
#endif
-#if !defined(__Userspace_os_Windows)
+#if !defined(_WIN32)
struct timeval timeout;
+ memset(&timeout, 0, sizeof(struct timeval));
timeout.tv_sec = (SOCKET_TIMEOUT / 1000);
timeout.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
#else
unsigned int timeout = SOCKET_TIMEOUT; /* Timeout in milliseconds */
#endif
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
if (SCTP_BASE_VAR(userspace_route) == -1) {
- if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) < 0) {
+ if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d).\n", errno);
}
#if 0
@@ -1115,7 +1138,7 @@ recv_thread_init(void)
if (SCTP_BASE_VAR(userspace_route) != -1) {
if (setsockopt(SCTP_BASE_VAR(userspace_route), SOL_SOCKET, SO_RCVTIMEO,(const void*)&timeout, sizeof(struct timeval)) < 0) {
SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on routing socket (errno = %d).\n", errno);
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
closesocket(SCTP_BASE_VAR(userspace_route));
#else
close(SCTP_BASE_VAR(userspace_route));
@@ -1127,8 +1150,8 @@ recv_thread_init(void)
#endif
#if defined(INET)
if (SCTP_BASE_VAR(userspace_rawsctp) == -1) {
- if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) < 0) {
-#if defined(__Userspace_os_Windows)
+ if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) == -1) {
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", errno);
@@ -1136,7 +1159,7 @@ recv_thread_init(void)
} else {
/* complete setting up the raw SCTP socket */
if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), IPPROTO_IP, IP_HDRINCL,(const void*)&hdrincl, sizeof(int)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp));
#else
@@ -1145,7 +1168,7 @@ recv_thread_init(void)
#endif
SCTP_BASE_VAR(userspace_rawsctp) = -1;
} else if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp));
#else
@@ -1162,7 +1185,7 @@ recv_thread_init(void)
addr_ipv4.sin_port = htons(0);
addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(SCTP_BASE_VAR(userspace_rawsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp));
#else
@@ -1177,9 +1200,9 @@ recv_thread_init(void)
}
}
}
- if (SCTP_BASE_VAR(userspace_udpsctp) == -1) {
- if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-#if defined(__Userspace_os_Windows)
+ if ((SCTP_BASE_VAR(userspace_udpsctp) == -1) && (SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) != 0)) {
+ if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", errno);
@@ -1190,7 +1213,7 @@ recv_thread_init(void)
#else
if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_RECVDSTADDR, (const void *)&on, (int)sizeof(int)) < 0) {
#endif
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
#if defined(IP_PKTINFO)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
#else
@@ -1207,7 +1230,7 @@ recv_thread_init(void)
#endif
SCTP_BASE_VAR(userspace_udpsctp) = -1;
} else if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_udpsctp));
#else
@@ -1224,7 +1247,7 @@ recv_thread_init(void)
addr_ipv4.sin_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(SCTP_BASE_VAR(userspace_udpsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_udpsctp));
#else
@@ -1242,8 +1265,8 @@ recv_thread_init(void)
#endif
#if defined(INET6)
if (SCTP_BASE_VAR(userspace_rawsctp6) == -1) {
- if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) < 0) {
-#if defined(__Userspace_os_Windows)
+ if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) == -1) {
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", errno);
@@ -1252,7 +1275,7 @@ recv_thread_init(void)
/* complete setting up the raw SCTP socket */
#if defined(IPV6_RECVPKTINFO)
if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, sizeof(on)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
#else
@@ -1263,7 +1286,7 @@ recv_thread_init(void)
} else {
#else
if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_PKTINFO,(const void*)&on, sizeof(on)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
#else
@@ -1274,14 +1297,14 @@ recv_thread_init(void)
} else {
#endif
if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&on, (socklen_t)sizeof(on)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", errno);
#endif
}
if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
#else
@@ -1298,7 +1321,7 @@ recv_thread_init(void)
addr_ipv6.sin6_port = htons(0);
addr_ipv6.sin6_addr = in6addr_any;
if (bind(SCTP_BASE_VAR(userspace_rawsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
#else
@@ -1314,9 +1337,9 @@ recv_thread_init(void)
}
}
}
- if (SCTP_BASE_VAR(userspace_udpsctp6) == -1) {
- if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-#if defined(__Userspace_os_Windows)
+ if ((SCTP_BASE_VAR(userspace_udpsctp6) == -1) && (SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) != 0)) {
+ if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
@@ -1324,7 +1347,7 @@ recv_thread_init(void)
}
#if defined(IPV6_RECVPKTINFO)
if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, (int)sizeof(int)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
#else
@@ -1335,7 +1358,7 @@ recv_thread_init(void)
} else {
#else
if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
#else
@@ -1346,14 +1369,14 @@ recv_thread_init(void)
} else {
#endif
if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, (socklen_t)sizeof(on)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
#else
SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
#endif
}
if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
#else
@@ -1369,8 +1392,8 @@ recv_thread_init(void)
addr_ipv6.sin6_family = AF_INET6;
addr_ipv6.sin6_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
addr_ipv6.sin6_addr = in6addr_any;
- if (bind(SCTP_BASE_VAR(userspace_udpsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) {
-#if defined(__Userspace_os_Windows)
+ if (bind(SCTP_BASE_VAR(userspace_udpsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) {
+#if defined(_WIN32)
SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
#else
@@ -1386,13 +1409,12 @@ recv_thread_init(void)
}
}
#endif
-#if !defined(__Userspace_os_Windows)
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
#if defined(INET) || defined(INET6)
if (SCTP_BASE_VAR(userspace_route) != -1) {
int rc;
- if ((rc = pthread_create(&SCTP_BASE_VAR(recvthreadroute), NULL, &recv_function_route, NULL))) {
+ if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadroute), &recv_function_route))) {
SCTPDBG(SCTP_DEBUG_USR, "Can't start routing thread (%d).\n", rc);
close(SCTP_BASE_VAR(userspace_route));
SCTP_BASE_VAR(userspace_route) = -1;
@@ -1404,18 +1426,26 @@ recv_thread_init(void)
if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
int rc;
- if ((rc = pthread_create(&SCTP_BASE_VAR(recvthreadraw), NULL, &recv_function_raw, NULL))) {
+ if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw), &recv_function_raw))) {
SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv4 recv thread (%d).\n", rc);
+#if defined(_WIN32)
+ closesocket(SCTP_BASE_VAR(userspace_rawsctp));
+#else
close(SCTP_BASE_VAR(userspace_rawsctp));
+#endif
SCTP_BASE_VAR(userspace_rawsctp) = -1;
}
}
if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
int rc;
- if ((rc = pthread_create(&SCTP_BASE_VAR(recvthreadudp), NULL, &recv_function_udp, NULL))) {
+ if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp), &recv_function_udp))) {
SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv4 recv thread (%d).\n", rc);
+#if defined(_WIN32)
+ closesocket(SCTP_BASE_VAR(userspace_udpsctp));
+#else
close(SCTP_BASE_VAR(userspace_udpsctp));
+#endif
SCTP_BASE_VAR(userspace_udpsctp) = -1;
}
}
@@ -1424,97 +1454,92 @@ recv_thread_init(void)
if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
int rc;
- if ((rc = pthread_create(&SCTP_BASE_VAR(recvthreadraw6), NULL, &recv_function_raw6, NULL))) {
+ if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw6), &recv_function_raw6))) {
SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv6 recv thread (%d).\n", rc);
+#if defined(_WIN32)
+ closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
+#else
close(SCTP_BASE_VAR(userspace_rawsctp6));
+#endif
SCTP_BASE_VAR(userspace_rawsctp6) = -1;
}
}
if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
int rc;
- if ((rc = pthread_create(&SCTP_BASE_VAR(recvthreadudp6), NULL, &recv_function_udp6, NULL))) {
+ if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp6), &recv_function_udp6))) {
SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv6 recv thread (%d).\n", rc);
- close(SCTP_BASE_VAR(userspace_udpsctp6));
- SCTP_BASE_VAR(userspace_udpsctp6) = -1;
- }
- }
-#endif
+#if defined(_WIN32)
+ closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
#else
-#if defined(INET)
- if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
- if ((SCTP_BASE_VAR(recvthreadraw) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&recv_function_raw, NULL, 0, NULL)) == NULL) {
- SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv4 recv thread.\n");
- closesocket(SCTP_BASE_VAR(userspace_rawsctp));
- SCTP_BASE_VAR(userspace_rawsctp) = -1;
- }
- }
- if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
- if ((SCTP_BASE_VAR(recvthreadudp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&recv_function_udp, NULL, 0, NULL)) == NULL) {
- SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv4 recv thread.\n");
- closesocket(SCTP_BASE_VAR(userspace_udpsctp));
- SCTP_BASE_VAR(userspace_udpsctp) = -1;
- }
- }
+ close(SCTP_BASE_VAR(userspace_udpsctp6));
#endif
-#if defined(INET6)
- if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
- if ((SCTP_BASE_VAR(recvthreadraw6) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&recv_function_raw6, NULL, 0, NULL)) == NULL) {
- SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv6 recv thread.\n");
- closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
- SCTP_BASE_VAR(userspace_rawsctp6) = -1;
- }
- }
- if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
- if ((SCTP_BASE_VAR(recvthreadudp6) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&recv_function_udp6, NULL, 0, NULL)) == NULL) {
- SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv6 recv thread.\n");
- closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
SCTP_BASE_VAR(userspace_udpsctp6) = -1;
}
}
#endif
-#endif
}
void
recv_thread_destroy(void)
{
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
#if defined(INET) || defined(INET6)
if (SCTP_BASE_VAR(userspace_route) != -1) {
close(SCTP_BASE_VAR(userspace_route));
+ pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL);
}
#endif
#endif
#if defined(INET)
if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
closesocket(SCTP_BASE_VAR(userspace_rawsctp));
+ SCTP_BASE_VAR(userspace_rawsctp) = -1;
+ WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE);
+ CloseHandle(SCTP_BASE_VAR(recvthreadraw));
#else
close(SCTP_BASE_VAR(userspace_rawsctp));
+ SCTP_BASE_VAR(userspace_rawsctp) = -1;
+ pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL);
#endif
}
if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
closesocket(SCTP_BASE_VAR(userspace_udpsctp));
+ SCTP_BASE_VAR(userspace_udpsctp) = -1;
+ WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE);
+ CloseHandle(SCTP_BASE_VAR(recvthreadudp));
#else
close(SCTP_BASE_VAR(userspace_udpsctp));
+ SCTP_BASE_VAR(userspace_udpsctp) = -1;
+ pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL);
#endif
}
#endif
#if defined(INET6)
if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
+ SCTP_BASE_VAR(userspace_rawsctp6) = -1;
+ WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE);
+ CloseHandle(SCTP_BASE_VAR(recvthreadraw6));
#else
close(SCTP_BASE_VAR(userspace_rawsctp6));
+ SCTP_BASE_VAR(userspace_rawsctp6) = -1;
+ pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL);
#endif
}
if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
+ SCTP_BASE_VAR(userspace_udpsctp6) = -1;
closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
+ WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE);
+ CloseHandle(SCTP_BASE_VAR(recvthreadudp6));
#else
close(SCTP_BASE_VAR(userspace_udpsctp6));
+ SCTP_BASE_VAR(userspace_udpsctp6) = -1;
+ pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL);
#endif
}
#endif
diff --git a/netwerk/sctp/src/user_route.h b/netwerk/sctp/src/user_route.h
index 82b07d769a..4abf2eac98 100755
--- a/netwerk/sctp/src/user_route.h
+++ b/netwerk/sctp/src/user_route.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/netwerk/sctp/src/user_socket.c b/netwerk/sctp/src/user_socket.c
index 7134001fe7..513a5a9a40 100755
--- a/netwerk/sctp/src/user_socket.c
+++ b/netwerk/sctp/src/user_socket.c
@@ -39,13 +39,18 @@
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_input.h>
#include <netinet/sctp_peeloff.h>
+#include <netinet/sctp_callout.h>
+#include <netinet/sctp_crc32.h>
#ifdef INET6
#include <netinet6/sctp6_var.h>
#endif
-#if defined(__Userspace_os_Linux)
+#if defined(__FreeBSD__)
+#include <sys/param.h>
+#endif
+#if defined(__linux__)
#define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */
#endif
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
#if defined INET || defined INET6
#include <netinet/udp.h>
#endif
@@ -67,17 +72,54 @@ MALLOC_DEFINE(M_SONAME, "sctp_soname", "sctp soname");
/* Prototypes */
extern int sctp_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio,
struct mbuf *top, struct mbuf *control, int flags,
- /* proc is a dummy in __Userspace__ and will not be passed to sctp_lower_sosend */ struct proc *p);
+ /* proc is a dummy in __Userspace__ and will not be passed to sctp_lower_sosend */
+ struct proc *p);
extern int sctp_attach(struct socket *so, int proto, uint32_t vrf_id);
extern int sctpconn_attach(struct socket *so, int proto, uint32_t vrf_id);
+static void init_sync(void) {
+#if defined(_WIN32)
+#if defined(INET) || defined(INET6)
+ WSADATA wsaData;
+
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
+ SCTP_PRINTF("WSAStartup failed\n");
+ exit (-1);
+ }
+#endif
+ InitializeConditionVariable(&accept_cond);
+ InitializeCriticalSection(&accept_mtx);
+#else
+ pthread_mutexattr_t mutex_attr;
+
+ pthread_mutexattr_init(&mutex_attr);
+#ifdef INVARIANTS
+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
+#endif
+ pthread_mutex_init(&accept_mtx, &mutex_attr);
+ pthread_mutexattr_destroy(&mutex_attr);
+ pthread_cond_init(&accept_cond, NULL);
+#endif
+}
+
void
usrsctp_init(uint16_t port,
int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
void (*debug_printf)(const char *format, ...))
{
- sctp_init(port, conn_output, debug_printf);
+ init_sync();
+ sctp_init(port, conn_output, debug_printf, 1);
+}
+
+
+void
+usrsctp_init_nothreads(uint16_t port,
+ int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
+ void (*debug_printf)(const char *format, ...))
+{
+ init_sync();
+ sctp_init(port, conn_output, debug_printf, 0);
}
@@ -127,28 +169,17 @@ socantsendmore(struct socket *so)
int
sbwait(struct sockbuf *sb)
{
-#if defined(__Userspace__) /* __Userspace__ */
-
SOCKBUF_LOCK_ASSERT(sb);
sb->sb_flags |= SB_WAIT;
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
if (SleepConditionVariableCS(&(sb->sb_cond), &(sb->sb_mtx), INFINITE))
- return 0;
+ return (0);
else
- return -1;
+ return (-1);
#else
return (pthread_cond_wait(&(sb->sb_cond), &(sb->sb_mtx)));
#endif
-
-#else
- SOCKBUF_LOCK_ASSERT(sb);
-
- sb->sb_flags |= SB_WAIT;
- return (msleep(&sb->sb_cc, &sb->sb_mtx,
- (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
- sb->sb_timeo));
-#endif
}
@@ -274,11 +305,9 @@ sofree(struct socket *so)
/* Taken from /src/sys/kern/uipc_socket.c */
-int
-soabort(so)
- struct socket *so;
+void
+soabort(struct socket *so)
{
- int error;
#if defined(INET6)
struct sctp_inpcb *inp;
#endif
@@ -286,24 +315,18 @@ soabort(so)
#if defined(INET6)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- error = sctp6_abort(so);
+ sctp6_abort(so);
} else {
#if defined(INET)
- error = sctp_abort(so);
-#else
- error = EAFNOSUPPORT;
+ sctp_abort(so);
#endif
}
#elif defined(INET)
- error = sctp_abort(so);
-#else
- error = EAFNOSUPPORT;
+ sctp_abort(so);
#endif
- if (error) {
- sofree(so);
- return error;
- }
- return (0);
+ ACCEPT_LOCK();
+ SOCK_LOCK(so);
+ sofree(so);
}
@@ -327,21 +350,21 @@ void
soisdisconnecting(struct socket *so)
{
- /*
- * Note: This code assumes that SOCK_LOCK(so) and
- * SOCKBUF_LOCK(&so->so_rcv) are the same.
- */
- SOCKBUF_LOCK(&so->so_rcv);
- so->so_state &= ~SS_ISCONNECTING;
- so->so_state |= SS_ISDISCONNECTING;
- so->so_rcv.sb_state |= SBS_CANTRCVMORE;
- sorwakeup_locked(so);
- SOCKBUF_LOCK(&so->so_snd);
- so->so_snd.sb_state |= SBS_CANTSENDMORE;
- sowwakeup_locked(so);
- wakeup("dummy",so);
- /* requires 2 args but this was in orig */
- /* wakeup(&so->so_timeo); */
+ /*
+ * Note: This code assumes that SOCK_LOCK(so) and
+ * SOCKBUF_LOCK(&so->so_rcv) are the same.
+ */
+ SOCKBUF_LOCK(&so->so_rcv);
+ so->so_state &= ~SS_ISCONNECTING;
+ so->so_state |= SS_ISDISCONNECTING;
+ so->so_rcv.sb_state |= SBS_CANTRCVMORE;
+ sorwakeup_locked(so);
+ SOCKBUF_LOCK(&so->so_snd);
+ so->so_snd.sb_state |= SBS_CANTSENDMORE;
+ sowwakeup_locked(so);
+ wakeup("dummy",so);
+ /* requires 2 args but this was in orig */
+ /* wakeup(&so->so_timeo); */
}
@@ -357,12 +380,10 @@ soisdisconnecting(struct socket *so)
* timeo identifier.
*/
void
-wakeup(ident, so)
- void *ident;
- struct socket *so;
+wakeup(void *ident, struct socket *so)
{
SOCK_LOCK(so);
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
WakeAllConditionVariable(&(so)->timeo_cond);
#else
pthread_cond_broadcast(&(so)->timeo_cond);
@@ -377,8 +398,7 @@ wakeup(ident, so)
* swapped out.
*/
void
-wakeup_one(ident)
- void *ident;
+wakeup_one(void *ident)
{
/* __Userspace__ Check: We are using accept_cond for wakeup_one.
It seems that wakeup_one is only called within
@@ -389,7 +409,7 @@ wakeup_one(ident)
subsidiary sockets.
*/
ACCEPT_LOCK();
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
WakeAllConditionVariable(&accept_cond);
#else
pthread_cond_broadcast(&accept_cond);
@@ -509,7 +529,7 @@ sonewconn(struct socket *head, int connstatus)
/*
* Keep removing sockets from the head until there's room for
* us to insert on the tail. In pre-locking revisions, this
- * was a simple if(), but as we could be racing with other
+ * was a simple if (), but as we could be racing with other
* threads and soabort() requires dropping locks, we must
* loop waiting for the condition to be true.
*/
@@ -537,39 +557,17 @@ sonewconn(struct socket *head, int connstatus)
}
-/* From /src/sys/sys/sysproto.h */
-struct sctp_generic_sendmsg_args {
- int sd;
- caddr_t msg;
- int mlen;
- caddr_t to;
- socklen_t tolen; /* was __socklen_t */
- struct sctp_sndrcvinfo * sinfo;
- int flags;
-};
-
-struct sctp_generic_recvmsg_args {
- int sd;
- struct iovec *iov;
- int iovlen;
- struct sockaddr *from;
- socklen_t *fromlenaddr; /* was __socklen_t */
- struct sctp_sndrcvinfo *sinfo;
- int *msg_flags;
-};
-
-
/*
Source: /src/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c
*/
static __inline__ int
-copy_to_user(void *dst, void *src, int len) {
+copy_to_user(void *dst, void *src, size_t len) {
memcpy(dst, src, len);
return 0;
}
static __inline__ int
-copy_from_user(void *dst, void *src, int len) {
+copy_from_user(void *dst, void *src, size_t len) {
memcpy(dst, src, len);
return 0;
}
@@ -613,7 +611,7 @@ int
uiomove(void *cp, int n, struct uio *uio)
{
struct iovec *iov;
- int cnt;
+ size_t cnt;
int error = 0;
if ((uio->uio_rw != UIO_READ) &&
@@ -629,7 +627,7 @@ uiomove(void *cp, int n, struct uio *uio)
uio->uio_iovcnt--;
continue;
}
- if (cnt > n)
+ if (cnt > (size_t)n)
cnt = n;
switch (uio->uio_segflg) {
@@ -645,17 +643,17 @@ uiomove(void *cp, int n, struct uio *uio)
case UIO_SYSSPACE:
if (uio->uio_rw == UIO_READ)
- bcopy(cp, iov->iov_base, cnt);
+ memcpy(iov->iov_base, cp, cnt);
else
- bcopy(iov->iov_base, cp, cnt);
+ memcpy(cp, iov->iov_base, cnt);
break;
}
iov->iov_base = (char *)iov->iov_base + cnt;
iov->iov_len -= cnt;
uio->uio_resid -= cnt;
- uio->uio_offset += cnt;
+ uio->uio_offset += (off_t)cnt;
cp = (char *)cp + cnt;
- n -= cnt;
+ n -= (int)cnt;
}
out:
return (error);
@@ -664,10 +662,7 @@ out:
/* Source: src/sys/kern/uipc_syscalls.c */
int
-getsockaddr(namp, uaddr, len)
- struct sockaddr **namp;
- caddr_t uaddr;
- size_t len;
+getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)
{
struct sockaddr *sa;
int error;
@@ -689,6 +684,52 @@ getsockaddr(namp, uaddr, len)
return (error);
}
+int
+usrsctp_getsockopt(struct socket *so, int level, int option_name,
+ void *option_value, socklen_t *option_len);
+
+sctp_assoc_t
+usrsctp_getassocid(struct socket *sock, struct sockaddr *sa)
+{
+ struct sctp_paddrinfo sp;
+ socklen_t siz;
+#ifndef HAVE_SA_LEN
+ size_t sa_len;
+#endif
+
+ /* First get the assoc id */
+ siz = sizeof(sp);
+ memset(&sp, 0, sizeof(sp));
+#ifdef HAVE_SA_LEN
+ memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len);
+#else
+ switch (sa->sa_family) {
+#ifdef INET
+ case AF_INET:
+ sa_len = sizeof(struct sockaddr_in);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ sa_len = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case AF_CONN:
+ sa_len = sizeof(struct sockaddr_conn);
+ break;
+ default:
+ sa_len = 0;
+ break;
+ }
+ memcpy((caddr_t)&sp.spinfo_address, sa, sa_len);
+#endif
+ if (usrsctp_getsockopt(sock, IPPROTO_SCTP, SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) {
+ /* We depend on the fact that 0 can never be returned */
+ return ((sctp_assoc_t) 0);
+ }
+ return (sp.spinfo_assoc_id);
+}
+
/* Taken from /src/lib/libc/net/sctp_sys_calls.c
* and modified for __Userspace__
@@ -700,11 +741,11 @@ userspace_sctp_sendmsg(struct socket *so,
size_t len,
struct sockaddr *to,
socklen_t tolen,
- u_int32_t ppid,
- u_int32_t flags,
- u_int16_t stream_no,
- u_int32_t timetolive,
- u_int32_t context)
+ uint32_t ppid,
+ uint32_t flags,
+ uint16_t stream_no,
+ uint32_t timetolive,
+ uint32_t context)
{
struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo;
struct uio auio;
@@ -720,7 +761,7 @@ userspace_sctp_sendmsg(struct socket *so,
/* Perform error checks on destination (to) */
- if (tolen > SOCK_MAXADDRLEN){
+ if (tolen > SOCK_MAXADDRLEN) {
errno = ENAMETOOLONG;
return (-1);
}
@@ -729,6 +770,10 @@ userspace_sctp_sendmsg(struct socket *so,
errno = EINVAL;
return (-1);
}
+ if (data == NULL) {
+ errno = EFAULT;
+ return (-1);
+ }
/* Adding the following as part of defensive programming, in case the application
does not do it when preparing the destination address.*/
#ifdef HAVE_SA_LEN
@@ -770,12 +815,18 @@ usrsctp_sendv(struct socket *so,
struct uio auio;
struct iovec iov[1];
int use_sinfo;
+ sctp_assoc_t *assoc_id;
if (so == NULL) {
errno = EBADF;
return (-1);
}
+ if (data == NULL) {
+ errno = EFAULT;
+ return (-1);
+ }
memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ assoc_id = NULL;
use_sinfo = 0;
switch (infotype) {
case SCTP_SENDV_NOINFO:
@@ -794,6 +845,7 @@ usrsctp_sendv(struct socket *so,
sinfo.sinfo_ppid = ((struct sctp_sndinfo *)info)->snd_ppid;
sinfo.sinfo_context = ((struct sctp_sndinfo *)info)->snd_context;
sinfo.sinfo_assoc_id = ((struct sctp_sndinfo *)info)->snd_assoc_id;
+ assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
use_sinfo = 1;
break;
case SCTP_SENDV_PRINFO:
@@ -820,6 +872,7 @@ usrsctp_sendv(struct socket *so,
sinfo.sinfo_ppid = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_ppid;
sinfo.sinfo_context = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_context;
sinfo.sinfo_assoc_id = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id;
+ assoc_id = &(((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id);
} else {
sinfo.sinfo_flags = 0;
sinfo.sinfo_stream = 0;
@@ -856,6 +909,9 @@ usrsctp_sendv(struct socket *so,
auio.uio_resid = len;
errno = sctp_lower_sosend(so, to, &auio, NULL, NULL, flags, use_sinfo ? &sinfo : NULL);
if (errno == 0) {
+ if ((to != NULL) && (assoc_id != NULL)) {
+ *assoc_id = usrsctp_getassocid(so, to);
+ }
return (len - auio.uio_resid);
} else {
return (-1);
@@ -869,59 +925,58 @@ userspace_sctp_sendmbuf(struct socket *so,
size_t len,
struct sockaddr *to,
socklen_t tolen,
- u_int32_t ppid,
- u_int32_t flags,
- u_int16_t stream_no,
- u_int32_t timetolive,
- u_int32_t context)
-{
-
- struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo;
- /* struct uio auio;
- struct iovec iov[1]; */
- int error = 0;
- int uflags = 0;
- int retvalsendmsg;
-
- sinfo->sinfo_ppid = ppid;
- sinfo->sinfo_flags = flags;
- sinfo->sinfo_stream = stream_no;
- sinfo->sinfo_timetolive = timetolive;
- sinfo->sinfo_context = context;
- sinfo->sinfo_assoc_id = 0;
-
- /* Perform error checks on destination (to) */
- if (tolen > SOCK_MAXADDRLEN){
- error = (ENAMETOOLONG);
- goto sendmsg_return;
- }
- if (tolen < (socklen_t)offsetof(struct sockaddr, sa_data)){
- error = (EINVAL);
- goto sendmsg_return;
- }
- /* Adding the following as part of defensive programming, in case the application
- does not do it when preparing the destination address.*/
+ uint32_t ppid,
+ uint32_t flags,
+ uint16_t stream_no,
+ uint32_t timetolive,
+ uint32_t context)
+{
+
+ struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo;
+ /* struct uio auio;
+ struct iovec iov[1]; */
+ int error = 0;
+ int uflags = 0;
+ ssize_t retval;
+
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_flags = flags;
+ sinfo->sinfo_stream = stream_no;
+ sinfo->sinfo_timetolive = timetolive;
+ sinfo->sinfo_context = context;
+ sinfo->sinfo_assoc_id = 0;
+
+ /* Perform error checks on destination (to) */
+ if (tolen > SOCK_MAXADDRLEN){
+ error = (ENAMETOOLONG);
+ goto sendmsg_return;
+ }
+ if (tolen < (socklen_t)offsetof(struct sockaddr, sa_data)){
+ error = (EINVAL);
+ goto sendmsg_return;
+ }
+ /* Adding the following as part of defensive programming, in case the application
+ does not do it when preparing the destination address.*/
#ifdef HAVE_SA_LEN
- to->sa_len = tolen;
+ to->sa_len = tolen;
#endif
- error = sctp_lower_sosend(so, to, NULL/*uio*/,
- (struct mbuf *)mbufdata, (struct mbuf *)NULL,
- uflags, sinfo);
+ error = sctp_lower_sosend(so, to, NULL/*uio*/,
+ (struct mbuf *)mbufdata, (struct mbuf *)NULL,
+ uflags, sinfo);
sendmsg_return:
- /* TODO: Needs a condition for non-blocking when error is EWOULDBLOCK */
- if (0 == error)
- retvalsendmsg = len;
- else if(error == EWOULDBLOCK) {
- errno = EWOULDBLOCK;
- retvalsendmsg = (-1);
- } else {
- SCTP_PRINTF("%s: error = %d\n", __func__, error);
- errno = error;
- retvalsendmsg = (-1);
- }
- return retvalsendmsg;
-
+ /* TODO: Needs a condition for non-blocking when error is EWOULDBLOCK */
+ if (0 == error)
+ retval = len;
+ else if (error == EWOULDBLOCK) {
+ errno = EWOULDBLOCK;
+ retval = -1;
+ } else {
+ SCTP_PRINTF("%s: error = %d\n", __func__, error);
+ errno = error;
+ retval = -1;
+ }
+ return (retval);
}
@@ -946,7 +1001,8 @@ userspace_sctp_recvmsg(struct socket *so,
struct iovec *tiov;
int iovlen = 1;
int error = 0;
- int ulen, i, retval;
+ ssize_t ulen;
+ int i;
socklen_t fromlen;
iov[0].iov_base = dbuf;
@@ -977,9 +1033,9 @@ userspace_sctp_recvmsg(struct socket *so,
(struct sctp_sndrcvinfo *)sinfo, 1);
if (error) {
- if (auio.uio_resid != (int)ulen &&
+ if ((auio.uio_resid != ulen) &&
(error == EINTR ||
-#if !defined(__Userspace_os_NetBSD)
+#if !defined(__NetBSD__)
error == ERESTART ||
#endif
error == EWOULDBLOCK)) {
@@ -1009,10 +1065,9 @@ userspace_sctp_recvmsg(struct socket *so,
*fromlenp = fromlen;
}
}
- if (error == 0){
+ if (error == 0) {
/* ready return value */
- retval = (int)ulen - auio.uio_resid;
- return (retval);
+ return (ulen - auio.uio_resid);
} else {
SCTP_PRINTF("%s: error = %d\n", __func__, error);
return (-1);
@@ -1034,7 +1089,8 @@ usrsctp_recvv(struct socket *so,
struct iovec iov[SCTP_SMALL_IOVEC_SIZE];
struct iovec *tiov;
int iovlen = 1;
- int ulen, i;
+ ssize_t ulen;
+ int i;
socklen_t fromlen;
struct sctp_rcvinfo *rcv;
struct sctp_recvv_rn *rn;
@@ -1070,15 +1126,18 @@ usrsctp_recvv(struct socket *so,
from, fromlen, msg_flags,
(struct sctp_sndrcvinfo *)&seinfo, 1);
if (errno) {
- if (auio.uio_resid != (int)ulen &&
+ if ((auio.uio_resid != ulen) &&
(errno == EINTR ||
-#if !defined(__Userspace_os_NetBSD)
+#if !defined(__NetBSD__)
errno == ERESTART ||
#endif
errno == EWOULDBLOCK)) {
errno = 0;
}
}
+ if (errno != 0) {
+ goto out;
+ }
if ((*msg_flags & MSG_NOTIFICATION) == 0) {
struct sctp_inpcb *inp;
@@ -1130,7 +1189,10 @@ usrsctp_recvv(struct socket *so,
*infolen = 0;
}
}
- if ((fromlenp != NULL) && (fromlen > 0) && (from != NULL)) {
+ if ((fromlenp != NULL) &&
+ (fromlen > 0) &&
+ (from != NULL) &&
+ (ulen > auio.uio_resid)) {
switch (from->sa_family) {
#if defined(INET)
case AF_INET:
@@ -1153,9 +1215,10 @@ usrsctp_recvv(struct socket *so,
*fromlenp = fromlen;
}
}
+out:
if (errno == 0) {
/* ready return value */
- return ((int)ulen - auio.uio_resid);
+ return (ulen - auio.uio_resid);
} else {
return (-1);
}
@@ -1164,7 +1227,6 @@ usrsctp_recvv(struct socket *so,
-#if defined(__Userspace__)
/* Taken from /src/sys/kern/uipc_socket.c
* and modified for __Userspace__
* socreate returns a socket. The socket should be
@@ -1235,74 +1297,6 @@ socreate(int dom, struct socket **aso, int type, int proto)
*aso = so;
return (0);
}
-#else
-/* The kernel version for reference is below. The #else
- should be removed once the __Userspace__
- version is tested.
- * socreate returns a socket with a ref count of 1. The socket should be
- * closed with soclose().
- */
-int
-socreate(int dom, struct socket **aso, int type, int proto,
- struct ucred *cred, struct thread *td)
-{
- struct protosw *prp;
- struct socket *so;
- int error;
-
- if (proto)
- prp = pffindproto(dom, proto, type);
- else
- prp = pffindtype(dom, type);
-
- if (prp == NULL || prp->pr_usrreqs->pru_attach == NULL ||
- prp->pr_usrreqs->pru_attach == pru_attach_notsupp)
- return (EPROTONOSUPPORT);
-
- if (jailed(cred) && jail_socket_unixiproute_only &&
- prp->pr_domain->dom_family != PF_LOCAL &&
- prp->pr_domain->dom_family != PF_INET &&
- prp->pr_domain->dom_family != PF_ROUTE) {
- return (EPROTONOSUPPORT);
- }
-
- if (prp->pr_type != type)
- return (EPROTOTYPE);
- so = soalloc();
- if (so == NULL)
- return (ENOBUFS);
-
- TAILQ_INIT(&so->so_incomp);
- TAILQ_INIT(&so->so_comp);
- so->so_type = type;
- so->so_cred = crhold(cred);
- so->so_proto = prp;
-#ifdef MAC
- mac_create_socket(cred, so);
-#endif
- knlist_init(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv),
- NULL, NULL, NULL);
- knlist_init(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd),
- NULL, NULL, NULL);
- so->so_count = 1;
- /*
- * Auto-sizing of socket buffers is managed by the protocols and
- * the appropriate flags must be set in the pru_attach function.
- */
- error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
- if (error) {
- KASSERT(so->so_count == 1, ("socreate: so_count %d",
- so->so_count));
- so->so_count = 0;
- sodealloc(so);
- return (error);
- }
- *aso = so;
- return (0);
-}
-#endif
-
-
/* Taken from /src/sys/kern/uipc_syscalls.c
@@ -1330,13 +1324,13 @@ struct socket *
usrsctp_socket(int domain, int type, int protocol,
int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info),
- int (*send_cb)(struct socket *sock, uint32_t sb_free),
+ int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info),
uint32_t sb_threshold,
void *ulp_info)
{
- struct socket *so;
+ struct socket *so = NULL;
- if ((protocol = IPPROTO_SCTP) && (SCTP_BASE_VAR(sctp_pcb_initialized) == 0)) {
+ if ((protocol == IPPROTO_SCTP) && (SCTP_BASE_VAR(sctp_pcb_initialized) == 0)) {
errno = EPROTONOSUPPORT;
return (NULL);
}
@@ -1397,7 +1391,6 @@ sbreserve(struct sockbuf *sb, u_long cc, struct socket *so)
return (error);
}
-#if defined(__Userspace__)
int
soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
{
@@ -1427,45 +1420,12 @@ soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
SOCKBUF_UNLOCK(&so->so_snd);
return (ENOBUFS);
}
-#else /* kernel version for reference */
-int
-soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
-{
- struct thread *td = curthread;
-
- SOCKBUF_LOCK(&so->so_snd);
- SOCKBUF_LOCK(&so->so_rcv);
- if (sbreserve_locked(&so->so_snd, sndcc, so, td) == 0)
- goto bad;
- if (sbreserve_locked(&so->so_rcv, rcvcc, so, td) == 0)
- goto bad2;
- if (so->so_rcv.sb_lowat == 0)
- so->so_rcv.sb_lowat = 1;
- if (so->so_snd.sb_lowat == 0)
- so->so_snd.sb_lowat = MCLBYTES;
- if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
- so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
- SOCKBUF_UNLOCK(&so->so_rcv);
- SOCKBUF_UNLOCK(&so->so_snd);
- return (0);
-bad2:
- sbrelease_locked(&so->so_snd, so);
-bad:
- SOCKBUF_UNLOCK(&so->so_rcv);
- SOCKBUF_UNLOCK(&so->so_snd);
- return (ENOBUFS);
-}
-#endif
-
-
-
/* Taken from /src/sys/kern/uipc_sockbuf.c
* and modified for __Userspace__
*/
-#if defined(__Userspace__)
void
sowakeup(struct socket *so, struct sockbuf *sb)
{
@@ -1475,53 +1435,14 @@ sowakeup(struct socket *so, struct sockbuf *sb)
sb->sb_flags &= ~SB_SEL;
if (sb->sb_flags & SB_WAIT) {
sb->sb_flags &= ~SB_WAIT;
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
WakeAllConditionVariable(&(sb)->sb_cond);
#else
pthread_cond_broadcast(&(sb)->sb_cond);
#endif
}
SOCKBUF_UNLOCK(sb);
- /*__Userspace__ what todo about so_upcall?*/
-
-}
-#else /* kernel version for reference */
-/*
- * Wakeup processes waiting on a socket buffer. Do asynchronous notification
- * via SIGIO if the socket has the SS_ASYNC flag set.
- *
- * Called with the socket buffer lock held; will release the lock by the end
- * of the function. This allows the caller to acquire the socket buffer lock
- * while testing for the need for various sorts of wakeup and hold it through
- * to the point where it's no longer required. We currently hold the lock
- * through calls out to other subsystems (with the exception of kqueue), and
- * then release it to avoid lock order issues. It's not clear that's
- * correct.
- */
-void
-sowakeup(struct socket *so, struct sockbuf *sb)
-{
-
- SOCKBUF_LOCK_ASSERT(sb);
-
- selwakeuppri(&sb->sb_sel, PSOCK);
- sb->sb_flags &= ~SB_SEL;
- if (sb->sb_flags & SB_WAIT) {
- sb->sb_flags &= ~SB_WAIT;
- wakeup(&sb->sb_cc);
- }
- KNOTE_LOCKED(&sb->sb_sel.si_note, 0);
- SOCKBUF_UNLOCK(sb);
- if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
- pgsigio(&so->so_sigio, SIGIO, 0);
- if (sb->sb_flags & SB_UPCALL)
- (*so->so_upcall)(so, so->so_upcallarg, M_NOWAIT);
- if (sb->sb_flags & SB_AIO)
- aio_swake(so, sb);
- mtx_assert(SOCKBUF_MTX(sb), MA_NOTOWNED);
}
-#endif
-
/* Taken from /src/sys/kern/uipc_socket.c
@@ -1693,7 +1614,7 @@ user_accept(struct socket *head, struct sockaddr **name, socklen_t *namelen, st
head->so_error = ECONNABORTED;
break;
}
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
if (SleepConditionVariableCS(&accept_cond, &accept_mtx, INFINITE))
error = 0;
else
@@ -1851,7 +1772,7 @@ accept1(struct socket *so, struct sockaddr *aname, socklen_t *anamelen, struct s
struct socket *
usrsctp_accept(struct socket *so, struct sockaddr *aname, socklen_t *anamelen)
{
- struct socket *accept_return_sock;
+ struct socket *accept_return_sock = NULL;
errno = accept1(so, aname, anamelen, &accept_return_sock);
if (errno) {
@@ -2014,7 +1935,7 @@ int user_connect(struct socket *so, struct sockaddr *sa)
SOCK_LOCK(so);
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
if (SleepConditionVariableCS(SOCK_COND(so), SOCK_MTX(so), INFINITE))
error = 0;
else
@@ -2023,7 +1944,7 @@ int user_connect(struct socket *so, struct sockaddr *sa)
error = pthread_cond_wait(SOCK_COND(so), SOCK_MTX(so));
#endif
if (error) {
-#if defined(__Userspace_os_NetBSD)
+#if defined(__NetBSD__)
if (error == EINTR) {
#else
if (error == EINTR || error == ERESTART) {
@@ -2043,7 +1964,7 @@ bad:
if (!interrupted) {
so->so_state &= ~SS_ISCONNECTING;
}
-#if !defined(__Userspace_os_NetBSD)
+#if !defined(__NetBSD__)
if (error == ERESTART) {
error = EINTR;
}
@@ -2054,7 +1975,7 @@ done1:
int usrsctp_connect(struct socket *so, struct sockaddr *name, int namelen)
{
- struct sockaddr *sa;
+ struct sockaddr *sa = NULL;
errno = getsockaddr(&sa, (caddr_t)name, namelen);
if (errno)
@@ -2153,6 +2074,16 @@ usrsctp_finish(void)
return (-1);
}
sctp_finish();
+#if defined(_WIN32)
+ DeleteConditionVariable(&accept_cond);
+ DeleteCriticalSection(&accept_mtx);
+#if defined(INET) || defined(INET6)
+ WSACleanup();
+#endif
+#else
+ pthread_cond_destroy(&accept_cond);
+ pthread_mutex_destroy(&accept_mtx);
+#endif
return (0);
}
@@ -2314,6 +2245,20 @@ usrsctp_getsockopt(struct socket *so, int level, int option_name,
*option_len = (socklen_t)sizeof(struct linger);
return (0);
}
+ break;
+ case SO_ERROR:
+ if (*option_len < (socklen_t)sizeof(int)) {
+ errno = EINVAL;
+ return (-1);
+ } else {
+ int *intval;
+
+ intval = (int *)option_value;
+ *intval = so->so_error;
+ *option_len = (socklen_t)sizeof(int);
+ return (0);
+ }
+ break;
default:
errno = EINVAL;
return (-1);
@@ -2345,15 +2290,136 @@ userspace_getsockopt(struct socket *so, int level, int option_name,
}
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));
}
+
+int
+usrsctp_get_ulpinfo(struct socket *so, void **pulp_info)
+{
+ return (retrieve_ulp_info(so, pulp_info));
+}
+
int
usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
{
- struct sctp_getaddresses *gaddrs;
struct sockaddr *sa;
#ifdef INET
struct sockaddr_in *sin;
@@ -2362,9 +2428,9 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
struct sockaddr_in6 *sin6;
#endif
int i;
- size_t argsz;
#if defined(INET) || defined(INET6)
- uint16_t sport = 0;
+ uint16_t sport;
+ bool fix_port;
#endif
/* validate the flags */
@@ -2378,6 +2444,10 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
errno = EINVAL;
return (-1);
}
+#if defined(INET) || defined(INET6)
+ sport = 0;
+ fix_port = false;
+#endif
/* First pre-screen the addresses */
sa = addrs;
for (i = 0; i < addrcnt; i++) {
@@ -2402,6 +2472,7 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
} else {
/* save off the port */
sport = sin->sin_port;
+ fix_port = (i > 0);
}
}
#ifndef HAVE_SA_LEN
@@ -2429,6 +2500,7 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
} else {
/* save off the port */
sport = sin6->sin6_port;
+ fix_port = (i > 0);
}
}
#ifndef HAVE_SA_LEN
@@ -2445,23 +2517,30 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
#endif
}
- argsz = sizeof(struct sctp_getaddresses) +
- sizeof(struct sockaddr_storage);
- if ((gaddrs = (struct sctp_getaddresses *)malloc(argsz)) == NULL) {
- errno = ENOMEM;
- return (-1);
- }
sa = addrs;
for (i = 0; i < addrcnt; i++) {
#ifndef HAVE_SA_LEN
size_t sa_len;
+
#endif
- memset(gaddrs, 0, argsz);
- gaddrs->sget_assoc_id = 0;
#ifdef HAVE_SA_LEN
- memcpy(gaddrs->addr, sa, sa->sa_len);
- if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, gaddrs, (socklen_t)argsz) != 0) {
- free(gaddrs);
+#if defined(INET) || defined(INET6)
+ if (fix_port) {
+ switch (sa->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ((struct sockaddr_in *)sa)->sin_port = sport;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sa)->sin6_port = sport;
+ break;
+#endif
+ }
+ }
+#endif
+ if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, sa, sa->sa_len) != 0) {
return (-1);
}
sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
@@ -2481,38 +2560,33 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
sa_len = 0;
break;
}
- memcpy(gaddrs->addr, sa, sa_len);
/*
* Now, if there was a port mentioned, assure that the
* first address has that port to make sure it fails or
* succeeds correctly.
*/
#if defined(INET) || defined(INET6)
- if ((i == 0) && (sport != 0)) {
- switch (gaddrs->addr->sa_family) {
+ if (fix_port) {
+ switch (sa->sa_family) {
#ifdef INET
case AF_INET:
- sin = (struct sockaddr_in *)gaddrs->addr;
- sin->sin_port = sport;
+ ((struct sockaddr_in *)sa)->sin_port = sport;
break;
#endif
#ifdef INET6
case AF_INET6:
- sin6 = (struct sockaddr_in6 *)gaddrs->addr;
- sin6->sin6_port = sport;
+ ((struct sockaddr_in6 *)sa)->sin6_port = sport;
break;
#endif
}
}
#endif
- if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, gaddrs, (socklen_t)argsz) != 0) {
- free(gaddrs);
+ if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, sa, (socklen_t)sa_len) != 0) {
return (-1);
}
sa = (struct sockaddr *)((caddr_t)sa + sa_len);
#endif
}
- free(gaddrs);
return (0);
}
@@ -2548,9 +2622,13 @@ usrsctp_connectx(struct socket *so,
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
@@ -2564,18 +2642,30 @@ usrsctp_connectx(struct socket *so,
#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;
@@ -2584,18 +2674,8 @@ usrsctp_connectx(struct socket *so,
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);
@@ -2642,9 +2722,9 @@ usrsctp_getpaddrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs)
free(addrs);
return (-1);
}
- *raddrs = (struct sockaddr *)&addrs->addr[0];
+ *raddrs = &addrs->addr[0].sa;
cnt = 0;
- sa = (struct sockaddr *)&addrs->addr[0];
+ sa = &addrs->addr[0].sa;
lim = (caddr_t)addrs + opt_len;
#ifdef HAVE_SA_LEN
while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
@@ -2681,7 +2761,7 @@ usrsctp_freepaddrs(struct sockaddr *addrs)
/* Take away the hidden association id */
void *fr_addr;
- fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
+ fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr));
/* Now free it */
free(fr_addr);
}
@@ -2710,9 +2790,7 @@ usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs)
errno = ENOTCONN;
return (-1);
}
- opt_len = (socklen_t)(size_of_addresses +
- sizeof(struct sockaddr_storage) +
- sizeof(struct sctp_getaddresses));
+ opt_len = (socklen_t)(size_of_addresses + sizeof(struct sctp_getaddresses));
addrs = calloc(1, (size_t)opt_len);
if (addrs == NULL) {
errno = ENOMEM;
@@ -2725,9 +2803,9 @@ usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs)
errno = ENOMEM;
return (-1);
}
- *raddrs = (struct sockaddr *)&addrs->addr[0];
+ *raddrs = &addrs->addr[0].sa;
cnt = 0;
- sa = (struct sockaddr *)&addrs->addr[0];
+ sa = &addrs->addr[0].sa;
lim = (caddr_t)addrs + opt_len;
#ifdef HAVE_SA_LEN
while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
@@ -2764,7 +2842,7 @@ usrsctp_freeladdrs(struct sockaddr *addrs)
/* Take away the hidden association id */
void *fr_addr;
- fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
+ fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr));
/* Now free it */
free(fr_addr);
}
@@ -2778,18 +2856,14 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
struct mbuf *m;
struct mbuf *m_orig;
int iovcnt;
- int send_len;
int len;
int send_count;
struct ip *ip;
struct udphdr *udp;
-#if !defined (__Userspace_os_Windows)
- int res;
-#endif
struct sockaddr_in dst;
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
WSAMSG win_msg_hdr;
- int win_sent_len;
+ DWORD win_sent_len;
WSABUF send_iovec[MAXLEN_MBUF_CHAIN];
WSABUF winbuf;
#else
@@ -2833,10 +2907,9 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n");
}
/* TODO need to worry about ro->ro_dst as in ip_output? */
-#if defined(__Userspace_os_Linux) || defined (__Userspace_os_Windows)
+#if defined(__linux__) || defined(_WIN32) || (defined(__FreeBSD__) && (__FreeBSD_version >= 1100030))
/* need to put certain fields into network order for Linux */
ip->ip_len = htons(ip->ip_len);
- ip->ip_off = 0;
#endif
}
@@ -2857,10 +2930,9 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
m_adj(m, sizeof(struct ip) + sizeof(struct udphdr));
}
- send_len = SCTP_HEADER_LEN(m); /* length of entire packet */
send_count = 0;
for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) {
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
send_iovec[iovcnt].iov_base = (caddr_t)m->m_data;
send_iovec[iovcnt].iov_len = SCTP_BUF_LEN(m);
send_count += send_iovec[iovcnt].iov_len;
@@ -2876,7 +2948,7 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
goto free_mbuf;
}
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
msg_hdr.msg_name = (struct sockaddr *) &dst;
msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
msg_hdr.msg_iov = send_iovec;
@@ -2885,13 +2957,13 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
msg_hdr.msg_controllen = 0;
msg_hdr.msg_flags = 0;
- if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) > -1)) {
- if ((res = sendmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg_hdr, MSG_DONTWAIT)) != send_len) {
+ if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) != -1)) {
+ if (sendmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg_hdr, MSG_DONTWAIT) < 0) {
*result = errno;
}
}
- if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) > -1)) {
- if ((res = sendmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg_hdr, MSG_DONTWAIT)) != send_len) {
+ if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) != -1)) {
+ if (sendmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg_hdr, MSG_DONTWAIT) < 0) {
*result = errno;
}
}
@@ -2905,18 +2977,14 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
win_msg_hdr.Control = winbuf;
win_msg_hdr.dwFlags = 0;
- if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) > -1)) {
+ if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) != -1)) {
if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
*result = WSAGetLastError();
- } else if (win_sent_len != send_len) {
- *result = WSAGetLastError();
}
}
- if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) > -1)) {
+ if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) != -1)) {
if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
*result = WSAGetLastError();
- } else if (win_sent_len != send_len) {
- *result = WSAGetLastError();
}
}
#endif
@@ -2925,7 +2993,7 @@ free_mbuf:
}
#endif
-#if defined (INET6)
+#if defined(INET6)
void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
struct route_in6 *ro, void *stcb,
uint32_t vrf_id)
@@ -2933,18 +3001,14 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
struct mbuf *m;
struct mbuf *m_orig;
int iovcnt;
- int send_len;
int len;
int send_count;
struct ip6_hdr *ip6;
struct udphdr *udp;
-#if !defined (__Userspace_os_Windows)
- int res;
-#endif
struct sockaddr_in6 dst;
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
WSAMSG win_msg_hdr;
- int win_sent_len;
+ DWORD win_sent_len;
WSABUF send_iovec[MAXLEN_MBUF_CHAIN];
WSABUF winbuf;
#else
@@ -2990,10 +3054,6 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n");
}
/* TODO need to worry about ro->ro_dst as in ip_output? */
-#if defined(__Userspace_os_Linux) || defined (__Userspace_os_Windows)
- /* need to put certain fields into network order for Linux */
- ip6->ip6_plen = htons(ip6->ip6_plen);
-#endif
}
memset((void *)&dst, 0, sizeof(struct sockaddr_in6));
@@ -3016,10 +3076,9 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
m_adj(m, sizeof(struct ip6_hdr));
}
- send_len = SCTP_HEADER_LEN(m); /* length of entire packet */
send_count = 0;
for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) {
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
send_iovec[iovcnt].iov_base = (caddr_t)m->m_data;
send_iovec[iovcnt].iov_len = SCTP_BUF_LEN(m);
send_count += send_iovec[iovcnt].iov_len;
@@ -3034,7 +3093,7 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
goto free_mbuf;
}
-#if !defined (__Userspace_os_Windows)
+#if !defined(_WIN32)
msg_hdr.msg_name = (struct sockaddr *) &dst;
msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
msg_hdr.msg_iov = send_iovec;
@@ -3043,13 +3102,13 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
msg_hdr.msg_controllen = 0;
msg_hdr.msg_flags = 0;
- if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) > -1)) {
- if ((res = sendmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg_hdr, MSG_DONTWAIT)) != send_len) {
+ if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) != -1)) {
+ if (sendmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg_hdr, MSG_DONTWAIT)< 0) {
*result = errno;
}
}
- if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) > -1)) {
- if ((res = sendmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg_hdr, MSG_DONTWAIT)) != send_len) {
+ if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) != -1)) {
+ if (sendmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg_hdr, MSG_DONTWAIT) < 0) {
*result = errno;
}
}
@@ -3063,18 +3122,14 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
win_msg_hdr.Control = winbuf;
win_msg_hdr.dwFlags = 0;
- if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) > -1)) {
+ if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) != -1)) {
if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
*result = WSAGetLastError();
- } else if (win_sent_len != send_len) {
- *result = WSAGetLastError();
}
}
- if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) > -1)) {
+ if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) != -1)) {
if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
*result = WSAGetLastError();
- } else if (win_sent_len != send_len) {
- *result = WSAGetLastError();
}
}
#endif
@@ -3130,16 +3185,15 @@ usrsctp_deregister_address(void *addr)
#define TRAILER "# SCTP_PACKET\n"
char *
-usrsctp_dumppacket(void *buf, size_t len, int outbound)
+usrsctp_dumppacket(const void *buf, size_t len, int outbound)
{
size_t i, pos;
char *dump_buf, *packet;
+ struct tm t;
#ifdef _WIN32
struct timeb tb;
- struct tm t;
#else
struct timeval tv;
- struct tm *t;
time_t sec;
#endif
@@ -3153,19 +3207,34 @@ usrsctp_dumppacket(void *buf, size_t len, int outbound)
#ifdef _WIN32
ftime(&tb);
localtime_s(&t, &tb.time);
- _snprintf_s(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_LENGTH, PREAMBLE_FORMAT,
- outbound ? 'O' : 'I',
- t.tm_hour, t.tm_min, t.tm_sec, (long)(1000 * tb.millitm));
+#if defined(__MINGW32__)
+ if (snprintf(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_FORMAT,
+ outbound ? 'O' : 'I',
+ t.tm_hour, t.tm_min, t.tm_sec, (long)(1000 * tb.millitm)) < 0) {
+ free(dump_buf);
+ return (NULL);
+ }
+#else
+ if (_snprintf_s(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_LENGTH, PREAMBLE_FORMAT,
+ outbound ? 'O' : 'I',
+ t.tm_hour, t.tm_min, t.tm_sec, (long)(1000 * tb.millitm)) < 0) {
+ free(dump_buf);
+ return (NULL);
+ }
+#endif
#else
gettimeofday(&tv, NULL);
sec = (time_t)tv.tv_sec;
- t = localtime((const time_t *)&sec);
- snprintf(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_FORMAT,
- outbound ? 'O' : 'I',
- t->tm_hour, t->tm_min, t->tm_sec, (long)tv.tv_usec);
+ localtime_r((const time_t *)&sec, &t);
+ if (snprintf(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_FORMAT,
+ outbound ? 'O' : 'I',
+ t.tm_hour, t.tm_min, t.tm_sec, (long)tv.tv_usec) < 0) {
+ free(dump_buf);
+ return (NULL);
+ }
#endif
pos += PREAMBLE_LENGTH;
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
strncpy_s(dump_buf + pos, strlen(HEADER) + 1, HEADER, strlen(HEADER));
#else
strcpy(dump_buf + pos, HEADER);
@@ -3182,7 +3251,7 @@ usrsctp_dumppacket(void *buf, size_t len, int outbound)
dump_buf[pos++] = low < 10 ? '0' + low : 'a' + (low - 10);
dump_buf[pos++] = ' ';
}
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
strncpy_s(dump_buf + pos, strlen(TRAILER) + 1, TRAILER, strlen(TRAILER));
#else
strcpy(dump_buf + pos, TRAILER);
@@ -3199,12 +3268,36 @@ usrsctp_freedumpbuffer(char *buf)
}
void
+usrsctp_enable_crc32c_offload(void)
+{
+ SCTP_BASE_VAR(crc32c_offloaded) = 1;
+}
+
+void
+usrsctp_disable_crc32c_offload(void)
+{
+ SCTP_BASE_VAR(crc32c_offloaded) = 0;
+}
+
+/* Compute the CRC32C in network byte order */
+uint32_t
+usrsctp_crc32c(void *buffer, size_t length)
+{
+ uint32_t base = 0xffffffff;
+
+ base = calculate_crc32c(0xffffffff, (unsigned char *)buffer, (unsigned int) length);
+ base = sctp_finalize_crc32c(base);
+ return (base);
+}
+
+void
usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bits)
{
struct sockaddr_conn src, dst;
- struct mbuf *m;
+ struct mbuf *m, *mm;
struct sctphdr *sh;
struct sctp_chunkhdr *ch;
+ int remaining, offset;
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
@@ -3220,27 +3313,37 @@ usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bit
dst.sconn_len = sizeof(struct sockaddr_conn);
#endif
dst.sconn_addr = addr;
- if ((m = sctp_get_mbuf_for_msg(length, 1, M_NOWAIT, 0, MT_DATA)) == NULL) {
+ if ((m = sctp_get_mbuf_for_msg((unsigned int)length, 1, M_NOWAIT, 0, MT_DATA)) == NULL) {
return;
}
- m_copyback(m, 0, length, (caddr_t)buffer);
- if (SCTP_BUF_LEN(m) < (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) {
- if ((m = m_pullup(m, sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) == NULL) {
+ /* Set the lengths fields of the mbuf chain.
+ * This is expected by m_copyback().
+ */
+ remaining = (int)length;
+ for (mm = m; mm != NULL; mm = mm->m_next) {
+ mm->m_len = min((int)M_SIZE(mm), remaining);
+ m->m_pkthdr.len += mm->m_len;
+ remaining -= mm->m_len;
+ }
+ KASSERT(remaining == 0, ("usrsctp_conninput: %zu bytes left", remaining));
+ m_copyback(m, 0, (int)length, (caddr_t)buffer);
+ offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ if (SCTP_BUF_LEN(m) < offset) {
+ if ((m = m_pullup(m, offset)) == NULL) {
SCTP_STAT_INCR(sctps_hdrops);
return;
}
}
- sh = mtod(m, struct sctphdr *);;
+ sh = mtod(m, struct sctphdr *);
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
+ offset -= sizeof(struct sctp_chunkhdr);
src.sconn_port = sh->src_port;
dst.sconn_port = sh->dest_port;
- sctp_common_input_processing(&m, 0, sizeof(struct sctphdr), length,
+ sctp_common_input_processing(&m, 0, offset, (int)length,
(struct sockaddr *)&src,
(struct sockaddr *)&dst,
sh, ch,
-#if !defined(SCTP_WITH_NO_CSUM)
- 1,
-#endif
+ SCTP_BASE_VAR(crc32c_offloaded) == 1 ? 0 : 1,
ecn_bits,
SCTP_DEFAULT_VRFID, 0);
if (m) {
@@ -3249,87 +3352,159 @@ usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bit
return;
}
+void usrsctp_handle_timers(uint32_t elapsed_milliseconds)
+{
+ sctp_handle_tick(sctp_msecs_to_ticks(elapsed_milliseconds));
+}
+
+int
+usrsctp_get_events(struct socket *so)
+{
+ int events = 0;
+
+ if (so == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ SOCK_LOCK(so);
+ if (soreadable(so)) {
+ events |= SCTP_EVENT_READ;
+ }
+ if (sowriteable(so)) {
+ events |= SCTP_EVENT_WRITE;
+ }
+ if (so->so_error) {
+ events |= SCTP_EVENT_ERROR;
+ }
+ SOCK_UNLOCK(so);
+
+ return events;
+}
+
+int
+usrsctp_set_upcall(struct socket *so, void (*upcall)(struct socket *, void *, int), void *arg)
+{
+ if (so == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ SOCK_LOCK(so);
+ so->so_upcall = upcall;
+ so->so_upcallarg = arg;
+ so->so_snd.sb_flags |= SB_UPCALL;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ SOCK_UNLOCK(so);
-#define USRSCTP_SYSCTL_SET_DEF(__field) \
-void usrsctp_sysctl_set_ ## __field(uint32_t value) { \
- SCTP_BASE_SYSCTL(__field) = value; \
-}
-
-USRSCTP_SYSCTL_SET_DEF(sctp_sendspace)
-USRSCTP_SYSCTL_SET_DEF(sctp_recvspace)
-USRSCTP_SYSCTL_SET_DEF(sctp_auto_asconf)
-USRSCTP_SYSCTL_SET_DEF(sctp_multiple_asconfs)
-USRSCTP_SYSCTL_SET_DEF(sctp_ecn_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_pr_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_auth_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_asconf_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_reconfig_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_nrsack_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_pktdrop_enable)
-USRSCTP_SYSCTL_SET_DEF(sctp_strict_sacks)
-#if !defined(SCTP_WITH_NO_CSUM)
-USRSCTP_SYSCTL_SET_DEF(sctp_no_csum_on_loopback)
-#endif
-USRSCTP_SYSCTL_SET_DEF(sctp_peer_chunk_oh)
-USRSCTP_SYSCTL_SET_DEF(sctp_max_burst_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_max_chunks_on_queue)
-USRSCTP_SYSCTL_SET_DEF(sctp_hashtblsize)
-USRSCTP_SYSCTL_SET_DEF(sctp_pcbtblsize)
-USRSCTP_SYSCTL_SET_DEF(sctp_min_split_point)
-USRSCTP_SYSCTL_SET_DEF(sctp_chunkscale)
-USRSCTP_SYSCTL_SET_DEF(sctp_delayed_sack_time_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_sack_freq_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_system_free_resc_limit)
-USRSCTP_SYSCTL_SET_DEF(sctp_asoc_free_resc_limit)
-USRSCTP_SYSCTL_SET_DEF(sctp_heartbeat_interval_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_pmtu_raise_time_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_shutdown_guard_time_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_secret_lifetime_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_rto_max_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_rto_min_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_rto_initial_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_init_rto_max_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_valid_cookie_life_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_init_rtx_max_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_assoc_rtx_max_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_path_rtx_max_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_add_more_threshold)
-USRSCTP_SYSCTL_SET_DEF(sctp_nr_outgoing_streams_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_cmt_on_off)
-USRSCTP_SYSCTL_SET_DEF(sctp_cmt_use_dac)
-USRSCTP_SYSCTL_SET_DEF(sctp_use_cwnd_based_maxburst)
-USRSCTP_SYSCTL_SET_DEF(sctp_nat_friendly)
-USRSCTP_SYSCTL_SET_DEF(sctp_L2_abc_variable)
-USRSCTP_SYSCTL_SET_DEF(sctp_mbuf_threshold_count)
-USRSCTP_SYSCTL_SET_DEF(sctp_do_drain)
-USRSCTP_SYSCTL_SET_DEF(sctp_hb_maxburst)
-USRSCTP_SYSCTL_SET_DEF(sctp_abort_if_one_2_one_hits_limit)
-USRSCTP_SYSCTL_SET_DEF(sctp_strict_data_order)
-USRSCTP_SYSCTL_SET_DEF(sctp_min_residual)
-USRSCTP_SYSCTL_SET_DEF(sctp_max_retran_chunk)
-USRSCTP_SYSCTL_SET_DEF(sctp_logging_level)
-USRSCTP_SYSCTL_SET_DEF(sctp_default_cc_module)
-USRSCTP_SYSCTL_SET_DEF(sctp_default_frag_interleave)
-USRSCTP_SYSCTL_SET_DEF(sctp_mobility_base)
-USRSCTP_SYSCTL_SET_DEF(sctp_mobility_fasthandoff)
-USRSCTP_SYSCTL_SET_DEF(sctp_inits_include_nat_friendly)
-USRSCTP_SYSCTL_SET_DEF(sctp_udp_tunneling_port)
-USRSCTP_SYSCTL_SET_DEF(sctp_enable_sack_immediately)
-USRSCTP_SYSCTL_SET_DEF(sctp_vtag_time_wait)
-USRSCTP_SYSCTL_SET_DEF(sctp_blackhole)
-USRSCTP_SYSCTL_SET_DEF(sctp_diag_info_code)
-USRSCTP_SYSCTL_SET_DEF(sctp_fr_max_burst_default)
-USRSCTP_SYSCTL_SET_DEF(sctp_path_pf_threshold)
-USRSCTP_SYSCTL_SET_DEF(sctp_default_ss_module)
-USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_bw)
-USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_rtt)
-USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_eqret)
-USRSCTP_SYSCTL_SET_DEF(sctp_steady_step)
-USRSCTP_SYSCTL_SET_DEF(sctp_use_dccc_ecn)
-USRSCTP_SYSCTL_SET_DEF(sctp_buffer_splitting)
-USRSCTP_SYSCTL_SET_DEF(sctp_initial_cwnd)
+ return (0);
+}
+
+#define USRSCTP_TUNABLE_SET_DEF(__field, __prefix) \
+int usrsctp_tunable_set_ ## __field(uint32_t value) \
+{ \
+ if ((value < __prefix##_MIN) || \
+ (value > __prefix##_MAX)) { \
+ errno = EINVAL; \
+ return (-1); \
+ } else { \
+ SCTP_BASE_SYSCTL(__field) = value; \
+ return (0); \
+ } \
+}
+
+USRSCTP_TUNABLE_SET_DEF(sctp_hashtblsize, SCTPCTL_TCBHASHSIZE)
+USRSCTP_TUNABLE_SET_DEF(sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE)
+USRSCTP_TUNABLE_SET_DEF(sctp_chunkscale, SCTPCTL_CHUNKSCALE)
+
+#define USRSCTP_SYSCTL_SET_DEF(__field, __prefix) \
+int usrsctp_sysctl_set_ ## __field(uint32_t value) \
+{ \
+ if ((value < __prefix##_MIN) || \
+ (value > __prefix##_MAX)) { \
+ errno = EINVAL; \
+ return (-1); \
+ } else { \
+ SCTP_BASE_SYSCTL(__field) = value; \
+ return (0); \
+ } \
+}
+
+#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+USRSCTP_SYSCTL_SET_DEF(sctp_sendspace, SCTPCTL_MAXDGRAM)
+USRSCTP_SYSCTL_SET_DEF(sctp_recvspace, SCTPCTL_RECVSPACE)
+USRSCTP_SYSCTL_SET_DEF(sctp_auto_asconf, SCTPCTL_AUTOASCONF)
+USRSCTP_SYSCTL_SET_DEF(sctp_ecn_enable, SCTPCTL_ECN_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_pr_enable, SCTPCTL_PR_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_auth_enable, SCTPCTL_AUTH_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_asconf_enable, SCTPCTL_ASCONF_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_reconfig_enable, SCTPCTL_RECONFIG_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_nrsack_enable, SCTPCTL_NRSACK_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_pktdrop_enable, SCTPCTL_PKTDROP_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM)
+USRSCTP_SYSCTL_SET_DEF(sctp_peer_chunk_oh, SCTPCTL_PEER_CHKOH)
+USRSCTP_SYSCTL_SET_DEF(sctp_max_burst_default, SCTPCTL_MAXBURST)
+USRSCTP_SYSCTL_SET_DEF(sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS)
+USRSCTP_SYSCTL_SET_DEF(sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT)
+USRSCTP_SYSCTL_SET_DEF(sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME)
+USRSCTP_SYSCTL_SET_DEF(sctp_sack_freq_default, SCTPCTL_SACK_FREQ)
+USRSCTP_SYSCTL_SET_DEF(sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE)
+USRSCTP_SYSCTL_SET_DEF(sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE)
+USRSCTP_SYSCTL_SET_DEF(sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL)
+USRSCTP_SYSCTL_SET_DEF(sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME)
+USRSCTP_SYSCTL_SET_DEF(sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME)
+USRSCTP_SYSCTL_SET_DEF(sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME)
+USRSCTP_SYSCTL_SET_DEF(sctp_rto_max_default, SCTPCTL_RTO_MAX)
+USRSCTP_SYSCTL_SET_DEF(sctp_rto_min_default, SCTPCTL_RTO_MIN)
+USRSCTP_SYSCTL_SET_DEF(sctp_rto_initial_default, SCTPCTL_RTO_INITIAL)
+USRSCTP_SYSCTL_SET_DEF(sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX)
+USRSCTP_SYSCTL_SET_DEF(sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE)
+USRSCTP_SYSCTL_SET_DEF(sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX)
+USRSCTP_SYSCTL_SET_DEF(sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX)
+USRSCTP_SYSCTL_SET_DEF(sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX)
+USRSCTP_SYSCTL_SET_DEF(sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT)
+USRSCTP_SYSCTL_SET_DEF(sctp_nr_incoming_streams_default, SCTPCTL_INCOMING_STREAMS)
+USRSCTP_SYSCTL_SET_DEF(sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS)
+USRSCTP_SYSCTL_SET_DEF(sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF)
+USRSCTP_SYSCTL_SET_DEF(sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC)
+USRSCTP_SYSCTL_SET_DEF(sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST)
+USRSCTP_SYSCTL_SET_DEF(sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY)
+USRSCTP_SYSCTL_SET_DEF(sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR)
+USRSCTP_SYSCTL_SET_DEF(sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS)
+USRSCTP_SYSCTL_SET_DEF(sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN)
+USRSCTP_SYSCTL_SET_DEF(sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST)
+USRSCTP_SYSCTL_SET_DEF(sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT)
+USRSCTP_SYSCTL_SET_DEF(sctp_min_residual, SCTPCTL_MIN_RESIDUAL)
+USRSCTP_SYSCTL_SET_DEF(sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK)
+USRSCTP_SYSCTL_SET_DEF(sctp_logging_level, SCTPCTL_LOGGING_LEVEL)
+USRSCTP_SYSCTL_SET_DEF(sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE)
+USRSCTP_SYSCTL_SET_DEF(sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE)
+USRSCTP_SYSCTL_SET_DEF(sctp_mobility_base, SCTPCTL_MOBILITY_BASE)
+USRSCTP_SYSCTL_SET_DEF(sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF)
+USRSCTP_SYSCTL_SET_DEF(sctp_inits_include_nat_friendly, SCTPCTL_NAT_FRIENDLY_INITS)
+USRSCTP_SYSCTL_SET_DEF(sctp_udp_tunneling_port, SCTPCTL_UDP_TUNNELING_PORT)
+USRSCTP_SYSCTL_SET_DEF(sctp_enable_sack_immediately, SCTPCTL_SACK_IMMEDIATELY_ENABLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_vtag_time_wait, SCTPCTL_TIME_WAIT)
+USRSCTP_SYSCTL_SET_DEF(sctp_blackhole, SCTPCTL_BLACKHOLE)
+USRSCTP_SYSCTL_SET_DEF(sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE)
+USRSCTP_SYSCTL_SET_DEF(sctp_fr_max_burst_default, SCTPCTL_FRMAXBURST)
+USRSCTP_SYSCTL_SET_DEF(sctp_path_pf_threshold, SCTPCTL_PATH_PF_THRESHOLD)
+USRSCTP_SYSCTL_SET_DEF(sctp_default_ss_module, SCTPCTL_DEFAULT_SS_MODULE)
+USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_bw, SCTPCTL_RTTVAR_BW)
+USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_rtt, SCTPCTL_RTTVAR_RTT)
+USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_eqret, SCTPCTL_RTTVAR_EQRET)
+USRSCTP_SYSCTL_SET_DEF(sctp_steady_step, SCTPCTL_RTTVAR_STEADYS)
+USRSCTP_SYSCTL_SET_DEF(sctp_use_dccc_ecn, SCTPCTL_RTTVAR_DCCCECN)
+USRSCTP_SYSCTL_SET_DEF(sctp_buffer_splitting, SCTPCTL_BUFFER_SPLITTING)
+USRSCTP_SYSCTL_SET_DEF(sctp_initial_cwnd, SCTPCTL_INITIAL_CWND)
#ifdef SCTP_DEBUG
-USRSCTP_SYSCTL_SET_DEF(sctp_debug_on)
+USRSCTP_SYSCTL_SET_DEF(sctp_debug_on, SCTPCTL_DEBUG)
+#endif
+#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__)
+#pragma GCC diagnostic pop
#endif
#define USRSCTP_SYSCTL_GET_DEF(__field) \
@@ -3348,10 +3523,7 @@ USRSCTP_SYSCTL_GET_DEF(sctp_asconf_enable)
USRSCTP_SYSCTL_GET_DEF(sctp_reconfig_enable)
USRSCTP_SYSCTL_GET_DEF(sctp_nrsack_enable)
USRSCTP_SYSCTL_GET_DEF(sctp_pktdrop_enable)
-USRSCTP_SYSCTL_GET_DEF(sctp_strict_sacks)
-#if !defined(SCTP_WITH_NO_CSUM)
USRSCTP_SYSCTL_GET_DEF(sctp_no_csum_on_loopback)
-#endif
USRSCTP_SYSCTL_GET_DEF(sctp_peer_chunk_oh)
USRSCTP_SYSCTL_GET_DEF(sctp_max_burst_default)
USRSCTP_SYSCTL_GET_DEF(sctp_max_chunks_on_queue)
@@ -3376,6 +3548,7 @@ USRSCTP_SYSCTL_GET_DEF(sctp_init_rtx_max_default)
USRSCTP_SYSCTL_GET_DEF(sctp_assoc_rtx_max_default)
USRSCTP_SYSCTL_GET_DEF(sctp_path_rtx_max_default)
USRSCTP_SYSCTL_GET_DEF(sctp_add_more_threshold)
+USRSCTP_SYSCTL_GET_DEF(sctp_nr_incoming_streams_default)
USRSCTP_SYSCTL_GET_DEF(sctp_nr_outgoing_streams_default)
USRSCTP_SYSCTL_GET_DEF(sctp_cmt_on_off)
USRSCTP_SYSCTL_GET_DEF(sctp_cmt_use_dac)
@@ -3386,7 +3559,6 @@ USRSCTP_SYSCTL_GET_DEF(sctp_mbuf_threshold_count)
USRSCTP_SYSCTL_GET_DEF(sctp_do_drain)
USRSCTP_SYSCTL_GET_DEF(sctp_hb_maxburst)
USRSCTP_SYSCTL_GET_DEF(sctp_abort_if_one_2_one_hits_limit)
-USRSCTP_SYSCTL_GET_DEF(sctp_strict_data_order)
USRSCTP_SYSCTL_GET_DEF(sctp_min_residual)
USRSCTP_SYSCTL_GET_DEF(sctp_max_retran_chunk)
USRSCTP_SYSCTL_GET_DEF(sctp_logging_level)
diff --git a/netwerk/sctp/src/user_socketvar.h b/netwerk/sctp/src/user_socketvar.h
index 5c3d9eee7c..e8eccc7fb1 100755
--- a/netwerk/sctp/src/user_socketvar.h
+++ b/netwerk/sctp/src/user_socketvar.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -33,7 +33,7 @@
#ifndef _USER_SOCKETVAR_H_
#define _USER_SOCKETVAR_H_
-#if defined(__Userspace_os_Darwin)
+#if defined(__APPLE__)
#include <sys/types.h>
#include <unistd.h>
#endif
@@ -42,7 +42,7 @@
/* #include <sys/_lock.h> was 0 byte file */
/* #include <sys/_mutex.h> was 0 byte file */
/* #include <sys/_sx.h> */ /*__Userspace__ alternative?*/
-#if !defined(__Userspace_os_DragonFly) && !defined(__Userspace_os_FreeBSD) && !defined(__Userspace_os_NetBSD) && !defined(__Userspace_os_Windows) && !defined(__Userspace_os_NaCl)
+#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(_WIN32) && !defined(__native_client__)
#include <sys/uio.h>
#endif
#define SOCK_MAXADDRLEN 255
@@ -54,16 +54,16 @@
#define SS_CANTRCVMORE 0x020
#define SS_CANTSENDMORE 0x010
-#if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_OpenBSD) || defined (__Userspace_os_Windows) || defined(__Userspace_os_NaCl)
+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(_WIN32) || defined(__native_client__)
#define UIO_MAXIOV 1024
#define ERESTART (-1)
#endif
-#if !defined(__Userspace_os_Darwin) && !defined(__Userspace_os_NetBSD) && !defined(__Userspace_os_OpenBSD)
+#if !defined(__APPLE__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
enum uio_rw { UIO_READ, UIO_WRITE };
#endif
-#if !defined(__Userspace_os_NetBSD) && !defined(__Userspace_os_OpenBSD)
+#if !defined(__NetBSD__) && !defined(__OpenBSD__)
/* Segment flag values. */
enum uio_seg {
UIO_USERSPACE, /* from user data space */
@@ -72,7 +72,7 @@ enum uio_seg {
#endif
struct proc {
- int stub; /* struct proc is a dummy for __Userspace__ */
+ int stub; /* struct proc is a dummy for __Userspace__ */
};
MALLOC_DECLARE(M_ACCF);
@@ -83,12 +83,12 @@ MALLOC_DECLARE(M_SONAME);
* Removing struct thread *uio_td; owner field
*/
struct uio {
- struct iovec *uio_iov; /* scatter/gather list */
- int uio_iovcnt; /* length of scatter/gather list */
- off_t uio_offset; /* offset in target object */
- int uio_resid; /* remaining bytes to process */
- enum uio_seg uio_segflg; /* address space */
- enum uio_rw uio_rw; /* operation */
+ struct iovec *uio_iov; /* scatter/gather list */
+ int uio_iovcnt; /* length of scatter/gather list */
+ off_t uio_offset; /* offset in target object */
+ ssize_t uio_resid; /* remaining bytes to process */
+ enum uio_seg uio_segflg; /* address space */
+ enum uio_rw uio_rw; /* operation */
};
@@ -100,9 +100,11 @@ struct uio {
* handle on protocol and pointer to protocol
* private data and error information.
*/
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
#define AF_ROUTE 17
+#if !defined(__MINGW32__)
typedef __int32 pid_t;
+#endif
typedef unsigned __int32 uid_t;
enum sigType {
SIGNAL = 0,
@@ -235,7 +237,7 @@ struct socket {
* avoid defining a lock order between listen and accept sockets
* until such time as it proves to be a good idea.
*/
-#if defined(__Userspace_os_Windows)
+#if defined(_WIN32)
extern userland_mutex_t accept_mtx;
extern userland_cond_t accept_cond;
#define ACCEPT_LOCK_ASSERT()
@@ -248,14 +250,21 @@ extern userland_cond_t accept_cond;
#define ACCEPT_UNLOCK_ASSERT()
#else
extern userland_mutex_t accept_mtx;
+
extern userland_cond_t accept_cond;
-#define ACCEPT_LOCK_ASSERT() KASSERT(pthread_mutex_trylock(&accept_mtx) == EBUSY, ("%s: accept_mtx not locked", __func__))
-#define ACCEPT_LOCK() (void)pthread_mutex_lock(&accept_mtx)
-#define ACCEPT_UNLOCK() (void)pthread_mutex_unlock(&accept_mtx)
-#define ACCEPT_UNLOCK_ASSERT() do{ \
- KASSERT(pthread_mutex_trylock(&accept_mtx) == 0, ("%s: accept_mtx locked", __func__)); \
- (void)pthread_mutex_unlock(&accept_mtx); \
-} while (0)
+#ifdef INVARIANTS
+#define ACCEPT_LOCK() KASSERT(pthread_mutex_lock(&accept_mtx) == 0, ("%s: accept_mtx already locked", __func__))
+#define ACCEPT_UNLOCK() KASSERT(pthread_mutex_unlock(&accept_mtx) == 0, ("%s: accept_mtx not locked", __func__))
+#else
+#define ACCEPT_LOCK() (void)pthread_mutex_lock(&accept_mtx)
+#define ACCEPT_UNLOCK() (void)pthread_mutex_unlock(&accept_mtx)
+#endif
+#define ACCEPT_LOCK_ASSERT() \
+ KASSERT(pthread_mutex_trylock(&accept_mtx) == EBUSY, ("%s: accept_mtx not locked", __func__))
+#define ACCEPT_UNLOCK_ASSERT() do { \
+ KASSERT(pthread_mutex_trylock(&accept_mtx) == 0, ("%s: accept_mtx locked", __func__)); \
+ (void)pthread_mutex_unlock(&accept_mtx); \
+ } while (0)
#endif
/*
@@ -263,7 +272,7 @@ extern userland_cond_t accept_cond;
* buffer.
*/
#define SOCKBUF_MTX(_sb) (&(_sb)->sb_mtx)
-#if defined (__Userspace_os_Windows)
+#if defined(_WIN32)
#define SOCKBUF_LOCK_INIT(_sb, _name) \
InitializeCriticalSection(SOCKBUF_MTX(_sb))
#define SOCKBUF_LOCK_DESTROY(_sb) DeleteCriticalSection(SOCKBUF_MTX(_sb))
@@ -273,8 +282,19 @@ extern userland_cond_t accept_cond;
#define SOCK_COND_DESTROY(_so) DeleteConditionVariable((&(_so)->timeo_cond))
#define SOCK_COND(_so) (&(_so)->timeo_cond)
#else
+#ifdef INVARIANTS
+#define SOCKBUF_LOCK_INIT(_sb, _name) do { \
+ pthread_mutexattr_t mutex_attr; \
+ \
+ pthread_mutexattr_init(&mutex_attr); \
+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK); \
+ pthread_mutex_init(SOCKBUF_MTX(_sb), &mutex_attr); \
+ pthread_mutexattr_destroy(&mutex_attr); \
+} while (0)
+#else
#define SOCKBUF_LOCK_INIT(_sb, _name) \
pthread_mutex_init(SOCKBUF_MTX(_sb), NULL)
+#endif
#define SOCKBUF_LOCK_DESTROY(_sb) pthread_mutex_destroy(SOCKBUF_MTX(_sb))
#define SOCKBUF_COND_INIT(_sb) pthread_cond_init((&(_sb)->sb_cond), NULL)
#define SOCKBUF_COND_DESTROY(_sb) pthread_cond_destroy((&(_sb)->sb_cond))
@@ -347,338 +367,11 @@ extern userland_cond_t accept_cond;
#define SQ_COMP 0x1000 /* unaccepted, complete connection */
/*
- * Externalized form of struct socket used by the sysctl(3) interface.
- */
-struct xsocket {
- size_t xso_len; /* length of this structure */
- struct socket *xso_so; /* makes a convenient handle sometimes */
- short so_type;
- short so_options;
- short so_linger;
- short so_state;
- caddr_t so_pcb; /* another convenient handle */
- int xso_protocol;
- int xso_family;
- u_short so_qlen;
- u_short so_incqlen;
- u_short so_qlimit;
- short so_timeo;
- u_short so_error;
- pid_t so_pgid;
- u_long so_oobmark;
- struct xsockbuf {
- u_int sb_cc;
- u_int sb_hiwat;
- u_int sb_mbcnt;
- u_int sb_mbmax;
- int sb_lowat;
- int sb_timeo;
- short sb_flags;
- } so_rcv, so_snd;
- uid_t so_uid; /* XXX */
-};
-
-#if defined(_KERNEL)
-
-
-/*
- * Macros for sockets and socket buffering.
- */
-
-/*
- * Do we need to notify the other side when I/O is possible?
- */
-#define sb_notify(sb) (((sb)->sb_flags & (SB_WAIT | SB_SEL | SB_ASYNC | \
- SB_UPCALL | SB_AIO | SB_KNOTE)) != 0)
-
-/*
- * How much space is there in a socket buffer (so->so_snd or so->so_rcv)?
- * This is problematical if the fields are unsigned, as the space might
- * still be negative (cc > hiwat or mbcnt > mbmax). Should detect
- * overflow and return 0. Should use "lmin" but it doesn't exist now.
- */
-#define sbspace(sb) \
- ((long) imin((int)((sb)->sb_hiwat - (sb)->sb_cc), \
- (int)((sb)->sb_mbmax - (sb)->sb_mbcnt)))
-
-/* do we have to send all at once on a socket? */
-#define sosendallatonce(so) \
- ((so)->so_proto->pr_flags & PR_ATOMIC)
-
-/* can we read something from so? */
-#define soreadable(so) \
- ((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \
- ((so)->so_rcv.sb_state & SBS_CANTRCVMORE) || \
- !TAILQ_EMPTY(&(so)->so_comp) || (so)->so_error)
-
-/* can we write something to so? */
-#define sowriteable(so) \
- ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat && \
- (((so)->so_state&SS_ISCONNECTED) || \
- ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0)) || \
- ((so)->so_snd.sb_state & SBS_CANTSENDMORE) || \
- (so)->so_error)
-
-/* adjust counters in sb reflecting allocation of m */
-#define sballoc(sb, m) { \
- (sb)->sb_cc += (m)->m_len; \
- if ((m)->m_type != MT_DATA && (m)->m_type != MT_OOBDATA) \
- (sb)->sb_ctl += (m)->m_len; \
- (sb)->sb_mbcnt += MSIZE; \
- if ((m)->m_flags & M_EXT) \
- (sb)->sb_mbcnt += (m)->m_ext.ext_size; \
-}
-
-/* adjust counters in sb reflecting freeing of m */
-#define sbfree(sb, m) { \
- (sb)->sb_cc -= (m)->m_len; \
- if ((m)->m_type != MT_DATA && (m)->m_type != MT_OOBDATA) \
- (sb)->sb_ctl -= (m)->m_len; \
- (sb)->sb_mbcnt -= MSIZE; \
- if ((m)->m_flags & M_EXT) \
- (sb)->sb_mbcnt -= (m)->m_ext.ext_size; \
- if ((sb)->sb_sndptr == (m)) { \
- (sb)->sb_sndptr = NULL; \
- (sb)->sb_sndptroff = 0; \
- } \
- if ((sb)->sb_sndptroff != 0) \
- (sb)->sb_sndptroff -= (m)->m_len; \
-}
-
-/*
- * soref()/sorele() ref-count the socket structure. Note that you must
- * still explicitly close the socket, but the last ref count will free
- * the structure.
+ * Socket event flags
*/
-#define soref(so) do { \
- SOCK_LOCK_ASSERT(so); \
- ++(so)->so_count; \
-} while (0)
-
-#define sorele(so) do { \
- ACCEPT_LOCK_ASSERT(); \
- SOCK_LOCK_ASSERT(so); \
- KASSERT((so)->so_count > 0, ("sorele")); \
- if (--(so)->so_count == 0) \
- sofree(so); \
- else { \
- SOCK_UNLOCK(so); \
- ACCEPT_UNLOCK(); \
- } \
-} while (0)
-
-#define sotryfree(so) do { \
- ACCEPT_LOCK_ASSERT(); \
- SOCK_LOCK_ASSERT(so); \
- if ((so)->so_count == 0) \
- sofree(so); \
- else { \
- SOCK_UNLOCK(so); \
- ACCEPT_UNLOCK(); \
- } \
-} while(0)
-
-/*
- * In sorwakeup() and sowwakeup(), acquire the socket buffer lock to
- * avoid a non-atomic test-and-wakeup. However, sowakeup is
- * responsible for releasing the lock if it is called. We unlock only
- * if we don't call into sowakeup. If any code is introduced that
- * directly invokes the underlying sowakeup() primitives, it must
- * maintain the same semantics.
- */
-#define sorwakeup_locked(so) do { \
- SOCKBUF_LOCK_ASSERT(&(so)->so_rcv); \
- if (sb_notify(&(so)->so_rcv)) \
- sowakeup((so), &(so)->so_rcv); \
- else \
- SOCKBUF_UNLOCK(&(so)->so_rcv); \
-} while (0)
-
-#define sorwakeup(so) do { \
- SOCKBUF_LOCK(&(so)->so_rcv); \
- sorwakeup_locked(so); \
-} while (0)
-
-#define sowwakeup_locked(so) do { \
- SOCKBUF_LOCK_ASSERT(&(so)->so_snd); \
- if (sb_notify(&(so)->so_snd)) \
- sowakeup((so), &(so)->so_snd); \
- else \
- SOCKBUF_UNLOCK(&(so)->so_snd); \
-} while (0)
-
-#define sowwakeup(so) do { \
- SOCKBUF_LOCK(&(so)->so_snd); \
- sowwakeup_locked(so); \
-} while (0)
-
-/*
- * Argument structure for sosetopt et seq. This is in the KERNEL
- * section because it will never be visible to user code.
- */
-enum sopt_dir { SOPT_GET, SOPT_SET };
-struct sockopt {
- enum sopt_dir sopt_dir; /* is this a get or a set? */
- int sopt_level; /* second arg of [gs]etsockopt */
- int sopt_name; /* third arg of [gs]etsockopt */
- void *sopt_val; /* fourth arg of [gs]etsockopt */
- size_t sopt_valsize; /* (almost) fifth arg of [gs]etsockopt */
- struct thread *sopt_td; /* calling thread or null if kernel */
-};
-
-struct accept_filter {
- char accf_name[16];
- void (*accf_callback)
- (struct socket *so, void *arg, int waitflag);
- void * (*accf_create)
- (struct socket *so, char *arg);
- void (*accf_destroy)
- (struct socket *so);
- SLIST_ENTRY(accept_filter) accf_next;
-};
-
-extern int maxsockets;
-extern u_long sb_max;
-extern struct uma_zone *socket_zone;
-extern so_gen_t so_gencnt;
-
-struct mbuf;
-struct sockaddr;
-struct ucred;
-struct uio;
-
-/*
- * From uipc_socket and friends
- */
-int do_getopt_accept_filter(struct socket *so, struct sockopt *sopt);
-int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt);
-int so_setsockopt(struct socket *so, int level, int optname,
- void *optval, size_t optlen);
-int sockargs(struct mbuf **mp, caddr_t buf, int buflen, int type);
-int getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len);
-void sbappend(struct sockbuf *sb, struct mbuf *m);
-void sbappend_locked(struct sockbuf *sb, struct mbuf *m);
-void sbappendstream(struct sockbuf *sb, struct mbuf *m);
-void sbappendstream_locked(struct sockbuf *sb, struct mbuf *m);
-int sbappendaddr(struct sockbuf *sb, const struct sockaddr *asa,
- struct mbuf *m0, struct mbuf *control);
-int sbappendaddr_locked(struct sockbuf *sb, const struct sockaddr *asa,
- struct mbuf *m0, struct mbuf *control);
-int sbappendcontrol(struct sockbuf *sb, struct mbuf *m0,
- struct mbuf *control);
-int sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
- struct mbuf *control);
-void sbappendrecord(struct sockbuf *sb, struct mbuf *m0);
-void sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0);
-void sbcheck(struct sockbuf *sb);
-void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n);
-struct mbuf *
- sbcreatecontrol(caddr_t p, int size, int type, int level);
-void sbdestroy(struct sockbuf *sb, struct socket *so);
-void sbdrop(struct sockbuf *sb, int len);
-void sbdrop_locked(struct sockbuf *sb, int len);
-void sbdroprecord(struct sockbuf *sb);
-void sbdroprecord_locked(struct sockbuf *sb);
-void sbflush(struct sockbuf *sb);
-void sbflush_locked(struct sockbuf *sb);
-void sbrelease(struct sockbuf *sb, struct socket *so);
-void sbrelease_locked(struct sockbuf *sb, struct socket *so);
-int sbreserve(struct sockbuf *sb, u_long cc, struct socket *so,
- struct thread *td);
-int sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so,
- struct thread *td);
-struct mbuf *
- sbsndptr(struct sockbuf *sb, u_int off, u_int len, u_int *moff);
-void sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb);
-int sbwait(struct sockbuf *sb);
-int sblock(struct sockbuf *sb, int flags);
-void sbunlock(struct sockbuf *sb);
-void soabort(struct socket *so);
-int soaccept(struct socket *so, struct sockaddr **nam);
-int socheckuid(struct socket *so, uid_t uid);
-int sobind(struct socket *so, struct sockaddr *nam, struct thread *td);
-void socantrcvmore(struct socket *so);
-void socantrcvmore_locked(struct socket *so);
-void socantsendmore(struct socket *so);
-void socantsendmore_locked(struct socket *so);
-int soclose(struct socket *so);
-int soconnect(struct socket *so, struct sockaddr *nam, struct thread *td);
-int soconnect2(struct socket *so1, struct socket *so2);
-int socow_setup(struct mbuf *m0, struct uio *uio);
-int socreate(int dom, struct socket **aso, int type, int proto,
- struct ucred *cred, struct thread *td);
-int sodisconnect(struct socket *so);
-struct sockaddr *sodupsockaddr(const struct sockaddr *sa, int mflags);
-void sofree(struct socket *so);
-int sogetopt(struct socket *so, struct sockopt *sopt);
-void sohasoutofband(struct socket *so);
-void soisconnected(struct socket *so);
-void soisconnecting(struct socket *so);
-void soisdisconnected(struct socket *so);
-void soisdisconnecting(struct socket *so);
-int solisten(struct socket *so, int backlog, struct thread *td);
-void solisten_proto(struct socket *so, int backlog);
-int solisten_proto_check(struct socket *so);
-struct socket *
- sonewconn(struct socket *head, int connstatus);
-int sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen);
-int sooptcopyout(struct sockopt *sopt, const void *buf, size_t len);
-
-/* XXX; prepare mbuf for (__FreeBSD__ < 3) routines. */
-int soopt_getm(struct sockopt *sopt, struct mbuf **mp);
-int soopt_mcopyin(struct sockopt *sopt, struct mbuf *m);
-int soopt_mcopyout(struct sockopt *sopt, struct mbuf *m);
-
-int sopoll(struct socket *so, int events, struct ucred *active_cred,
- struct thread *td);
-int sopoll_generic(struct socket *so, int events,
- struct ucred *active_cred, struct thread *td);
-int soreceive(struct socket *so, struct sockaddr **paddr, struct uio *uio,
- struct mbuf **mp0, struct mbuf **controlp, int *flagsp);
-int soreceive_generic(struct socket *so, struct sockaddr **paddr,
- struct uio *uio, struct mbuf **mp0, struct mbuf **controlp,
- int *flagsp);
-int soreserve(struct socket *so, u_long sndcc, u_long rcvcc);
-void sorflush(struct socket *so);
-int sosend(struct socket *so, struct sockaddr *addr, struct uio *uio,
- struct mbuf *top, struct mbuf *control, int flags,
- struct thread *td);
-int sosend_dgram(struct socket *so, struct sockaddr *addr,
- struct uio *uio, struct mbuf *top, struct mbuf *control,
- int flags, struct thread *td);
-int sosend_generic(struct socket *so, struct sockaddr *addr,
- struct uio *uio, struct mbuf *top, struct mbuf *control,
- int flags, struct thread *td);
-int sosetopt(struct socket *so, struct sockopt *sopt);
-int soshutdown(struct socket *so, int how);
-void sotoxsocket(struct socket *so, struct xsocket *xso);
-void sowakeup(struct socket *so, struct sockbuf *sb);
-
-#ifdef SOCKBUF_DEBUG
-void sblastrecordchk(struct sockbuf *, const char *, int);
-#define SBLASTRECORDCHK(sb) sblastrecordchk((sb), __FILE__, __LINE__)
-
-void sblastmbufchk(struct sockbuf *, const char *, int);
-#define SBLASTMBUFCHK(sb) sblastmbufchk((sb), __FILE__, __LINE__)
-#else
-#define SBLASTRECORDCHK(sb) /* nothing */
-#define SBLASTMBUFCHK(sb) /* nothing */
-#endif /* SOCKBUF_DEBUG */
-
-/*
- * Accept filter functions (duh).
- */
-int accept_filt_add(struct accept_filter *filt);
-int accept_filt_del(char *name);
-struct accept_filter *accept_filt_get(char *name);
-#ifdef ACCEPT_FILTER_MOD
-#ifdef SYSCTL_DECL
-SYSCTL_DECL(_net_inet_accf);
-#endif
-int accept_filt_generic_mod_event(module_t mod, int event, void *data);
-#endif
-
-#endif /* _KERNEL */
+#define SCTP_EVENT_READ 0x0001 /* socket is readable */
+#define SCTP_EVENT_WRITE 0x0002 /* socket is writeable */
+#define SCTP_EVENT_ERROR 0x0004 /* socket has an error state */
/*-------------------------------------------------------------*/
@@ -690,7 +383,6 @@ int accept_filt_generic_mod_event(module_t mod, int event, void *data);
* above into, avoiding having to port the entire thing at once...
* For function prototypes, the full bodies are in user_socket.c .
*/
-#if defined(__Userspace__)
/* ---------------------------------------------------------- */
/* --- function prototypes (implemented in user_socket.c) --- */
@@ -701,6 +393,7 @@ void soisconnected(struct socket *so);
struct socket * sonewconn(struct socket *head, int connstatus);
void socantrcvmore(struct socket *so);
void socantsendmore(struct socket *so);
+void sofree(struct socket *so);
@@ -764,9 +457,7 @@ extern int sctp_listen(struct socket *so, int backlog, struct proc *p);
extern void socantrcvmore_locked(struct socket *so);
extern int sctp_bind(struct socket *so, struct sockaddr *addr);
extern int sctp6_bind(struct socket *so, struct sockaddr *addr, void *proc);
-#if defined(__Userspace__)
extern int sctpconn_bind(struct socket *so, struct sockaddr *addr);
-#endif
extern int sctp_accept(struct socket *so, struct sockaddr **addr);
extern int sctp_attach(struct socket *so, int proto, uint32_t vrf_id);
extern int sctp6_attach(struct socket *so, int proto, uint32_t vrf_id);
@@ -785,9 +476,7 @@ extern int soconnect(struct socket *so, struct sockaddr *nam);
extern int sctp_disconnect(struct socket *so);
extern int sctp_connect(struct socket *so, struct sockaddr *addr);
extern int sctp6_connect(struct socket *so, struct sockaddr *addr);
-#if defined(__Userspace__)
extern int sctpconn_connect(struct socket *so, struct sockaddr *addr);
-#endif
extern void sctp_finish(void);
/* ------------------------------------------------ */
@@ -835,8 +524,4 @@ extern void sctp_finish(void);
sowwakeup_locked(so); \
} while (0)
-
-
-#endif /* __Userspace__ */
-
#endif /* !_SYS_SOCKETVAR_H_ */
diff --git a/netwerk/sctp/src/user_uma.h b/netwerk/sctp/src/user_uma.h
index 1bdefdb809..59d71fff42 100755
--- a/netwerk/sctp/src/user_uma.h
+++ b/netwerk/sctp/src/user_uma.h
@@ -46,11 +46,11 @@ typedef struct uma_zone * uma_zone_t;
typedef struct uma_keg * uma_keg_t;
struct uma_cache {
- int stub; /* TODO __Userspace__ */
+ int stub; /* TODO __Userspace__ */
};
struct uma_keg {
- int stub; /* TODO __Userspace__ */
+ int stub; /* TODO __Userspace__ */
};
struct uma_zone {
@@ -83,16 +83,14 @@ struct uma_zone {
/* Prototype */
uma_zone_t
uma_zcreate(char *name, size_t size, uma_ctor ctor, uma_dtor dtor,
- uma_init uminit, uma_fini fini, int align, u_int32_t flags);
+ uma_init uminit, uma_fini fini, int align, uint32_t flags);
#define uma_zone_set_max(zone, number) /* stub TODO __Userspace__ */
uma_zone_t
uma_zcreate(char *name, size_t size, uma_ctor ctor, uma_dtor dtor,
- uma_init uminit, uma_fini fini, int align, u_int32_t flags)
-{
- return NULL; /* stub TODO __Userspace__. Also place implementation in a separate .c file */
-
+ uma_init uminit, uma_fini fini, int align, uint32_t flags) {
+ return NULL; /* stub TODO __Userspace__. Also place implementation in a separate .c file */
}
#endif
diff --git a/netwerk/sctp/src/usrsctp.h b/netwerk/sctp/src/usrsctp.h
index afd46562d4..b7192904e4 100644
--- a/netwerk/sctp/src/usrsctp.h
+++ b/netwerk/sctp/src/usrsctp.h
@@ -67,11 +67,21 @@ extern "C" {
#define uint8_t unsigned __int8
#define uint16_t unsigned __int16
#define uint32_t unsigned __int32
+#define uint64_t unsigned __int64
#define int16_t __int16
#define int32_t __int32
#endif
-#define ssize_t __int64
+#ifndef ssize_t
+#ifdef _WIN64
+#define ssize_t __int64
+#elif defined _WIN32
+#define ssize_t int
+#else
+#error "Unknown platform!"
+#endif
+#endif
+
#define MSG_EOR 0x8
#ifndef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
@@ -86,6 +96,25 @@ extern "C" {
typedef uint32_t sctp_assoc_t;
+#if defined(_WIN32) && defined(_MSC_VER)
+#pragma pack (push, 1)
+#define SCTP_PACKED
+#else
+#define SCTP_PACKED __attribute__((packed))
+#endif
+
+struct sctp_common_header {
+ uint16_t source_port;
+ uint16_t destination_port;
+ uint32_t verification_tag;
+ uint32_t crc32c;
+} SCTP_PACKED;
+
+#if defined(_WIN32) && defined(_MSC_VER)
+#pragma pack(pop)
+#endif
+#undef SCTP_PACKED
+
#define AF_CONN 123
/* The definition of struct sockaddr_conn MUST be in
* tune with other sockaddr_* structures.
@@ -107,12 +136,8 @@ struct sockaddr_conn {
#endif
union sctp_sockstore {
-#if defined(INET)
struct sockaddr_in sin;
-#endif
-#if defined(INET6)
struct sockaddr_in6 sin6;
-#endif
struct sockaddr_conn sconn;
struct sockaddr sa;
};
@@ -121,6 +146,10 @@ union sctp_sockstore {
#define SCTP_CURRENT_ASSOC 1
#define SCTP_ALL_ASSOC 2
+#define SCTP_EVENT_READ 0x0001
+#define SCTP_EVENT_WRITE 0x0002
+#define SCTP_EVENT_ERROR 0x0004
+
/*** Structures and definitions to use the socket API ***/
#define SCTP_ALIGN_RESV_PAD 92
@@ -252,12 +281,13 @@ struct sctp_assoc_change {
#define SCTP_CANT_STR_ASSOC 0x0005
/* sac_info values */
-#define SCTP_ASSOC_SUPPORTS_PR 0x01
-#define SCTP_ASSOC_SUPPORTS_AUTH 0x02
-#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03
-#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04
-#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05
-#define SCTP_ASSOC_SUPPORTS_MAX 0x05
+#define SCTP_ASSOC_SUPPORTS_PR 0x01
+#define SCTP_ASSOC_SUPPORTS_AUTH 0x02
+#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03
+#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04
+#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05
+#define SCTP_ASSOC_SUPPORTS_INTERLEAVING 0x06
+#define SCTP_ASSOC_SUPPORTS_MAX 0x06
/* Address event */
struct sctp_paddr_change {
@@ -286,7 +316,7 @@ struct sctp_remote_error {
uint32_t sre_length;
uint16_t sre_error;
sctp_assoc_t sre_assoc_id;
- uint8_t sre_data[4];
+ uint8_t sre_data[];
};
/* shutdown event */
@@ -451,6 +481,8 @@ struct sctp_event_subscribe {
/* Flags that go into the sinfo->sinfo_flags field */
+#define SCTP_DATA_LAST_FRAG 0x0001 /* tail part of the message could not be sent */
+#define SCTP_DATA_NOT_FRAG 0x0003 /* complete message could not be sent */
#define SCTP_NOTIFICATION 0x0010 /* next message is a notification */
#define SCTP_COMPLETE 0x0020 /* next message is complete */
#define SCTP_EOF 0x0100 /* Start shutdown procedures */
@@ -520,9 +552,21 @@ struct sctp_event_subscribe {
#define SCTP_DEFAULT_SNDINFO 0x00000021
#define SCTP_DEFAULT_PRINFO 0x00000022
#define SCTP_REMOTE_UDP_ENCAPS_PORT 0x00000024
+#define SCTP_ECN_SUPPORTED 0x00000025
+#define SCTP_PR_SUPPORTED 0x00000026
+#define SCTP_AUTH_SUPPORTED 0x00000027
+#define SCTP_ASCONF_SUPPORTED 0x00000028
+#define SCTP_RECONFIG_SUPPORTED 0x00000029
+#define SCTP_NRSACK_SUPPORTED 0x00000030
+#define SCTP_PKTDROP_SUPPORTED 0x00000031
+#define SCTP_MAX_CWND 0x00000032
#define SCTP_ENABLE_STREAM_RESET 0x00000900 /* struct sctp_assoc_value */
+/* Pluggable Stream Scheduling Socket option */
+#define SCTP_PLUGGABLE_SS 0x00001203
+#define SCTP_SS_VALUE 0x00001204
+
/*
* read-only options
*/
@@ -533,6 +577,9 @@ struct sctp_event_subscribe {
#define SCTP_LOCAL_AUTH_CHUNKS 0x00000103
#define SCTP_GET_ASSOC_NUMBER 0x00000104
#define SCTP_GET_ASSOC_ID_LIST 0x00000105
+#define SCTP_TIMEOUTS 0x00000106
+#define SCTP_PR_STREAM_STATUS 0x00000107
+#define SCTP_PR_ASSOC_STATUS 0x00000108
/*
* write-only options
@@ -778,6 +825,12 @@ struct sctp_cc_option {
struct sctp_assoc_value aid_value;
};
+struct sctp_stream_value {
+ sctp_assoc_t assoc_id;
+ uint16_t stream_id;
+ uint16_t stream_value;
+};
+
struct sctp_timeouts {
sctp_assoc_t stimo_assoc_id;
uint32_t stimo_init;
@@ -789,6 +842,13 @@ struct sctp_timeouts {
uint32_t stimo_shutdownack;
};
+struct sctp_prstatus {
+ sctp_assoc_t sprstat_assoc_id;
+ uint16_t sprstat_sid;
+ uint16_t sprstat_policy;
+ uint64_t sprstat_abandoned_unsent;
+ uint64_t sprstat_abandoned_sent;
+};
/* Standard TCP Congestion Control */
#define SCTP_CC_RFC2581 0x00000000
@@ -835,11 +895,16 @@ usrsctp_init(uint16_t,
int (*)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
void (*)(const char *format, ...));
+void
+usrsctp_init_nothreads(uint16_t,
+ int (*)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
+ void (*)(const char *format, ...));
+
struct socket *
usrsctp_socket(int domain, int type, int protocol,
int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info),
- int (*send_cb)(struct socket *sock, uint32_t sb_free),
+ int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info),
uint32_t sb_threshold,
void *ulp_info);
@@ -858,6 +923,13 @@ usrsctp_getsockopt(struct socket *so,
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);
@@ -934,6 +1006,9 @@ usrsctp_connectx(struct socket *so,
void
usrsctp_close(struct socket *so);
+sctp_assoc_t
+usrsctp_getassocid(struct socket *, struct sockaddr *);
+
int
usrsctp_finish(void);
@@ -958,17 +1033,49 @@ usrsctp_deregister_address(void *);
int
usrsctp_set_ulpinfo(struct socket *, void *);
+int
+usrsctp_get_ulpinfo(struct socket *, void **);
+
+int
+usrsctp_set_upcall(struct socket *so,
+ void (*upcall)(struct socket *, void *, int),
+ void *arg);
+
+int
+usrsctp_get_events(struct socket *so);
+
+
+void
+usrsctp_handle_timers(uint32_t elapsed_milliseconds);
+
#define SCTP_DUMP_OUTBOUND 1
#define SCTP_DUMP_INBOUND 0
char *
-usrsctp_dumppacket(void *, size_t, int);
+usrsctp_dumppacket(const void *, size_t, int);
void
usrsctp_freedumpbuffer(char *);
-#define USRSCTP_SYSCTL_DECL(__field) \
-void usrsctp_sysctl_set_ ## __field(uint32_t value);\
+void
+usrsctp_enable_crc32c_offload(void);
+
+void
+usrsctp_disable_crc32c_offload(void);
+
+uint32_t
+usrsctp_crc32c(void *, size_t);
+
+#define USRSCTP_TUNABLE_DECL(__field) \
+int usrsctp_tunable_set_ ## __field(uint32_t value);\
+uint32_t usrsctp_sysctl_get_ ## __field(void);
+
+USRSCTP_TUNABLE_DECL(sctp_hashtblsize)
+USRSCTP_TUNABLE_DECL(sctp_pcbtblsize)
+USRSCTP_TUNABLE_DECL(sctp_chunkscale)
+
+#define USRSCTP_SYSCTL_DECL(__field) \
+int usrsctp_sysctl_set_ ## __field(uint32_t value);\
uint32_t usrsctp_sysctl_get_ ## __field(void);
USRSCTP_SYSCTL_DECL(sctp_sendspace)
@@ -982,17 +1089,11 @@ USRSCTP_SYSCTL_DECL(sctp_asconf_enable)
USRSCTP_SYSCTL_DECL(sctp_reconfig_enable)
USRSCTP_SYSCTL_DECL(sctp_nrsack_enable)
USRSCTP_SYSCTL_DECL(sctp_pktdrop_enable)
-USRSCTP_SYSCTL_DECL(sctp_strict_sacks)
-#if !defined(SCTP_WITH_NO_CSUM)
USRSCTP_SYSCTL_DECL(sctp_no_csum_on_loopback)
-#endif
USRSCTP_SYSCTL_DECL(sctp_peer_chunk_oh)
USRSCTP_SYSCTL_DECL(sctp_max_burst_default)
USRSCTP_SYSCTL_DECL(sctp_max_chunks_on_queue)
-USRSCTP_SYSCTL_DECL(sctp_hashtblsize)
-USRSCTP_SYSCTL_DECL(sctp_pcbtblsize)
USRSCTP_SYSCTL_DECL(sctp_min_split_point)
-USRSCTP_SYSCTL_DECL(sctp_chunkscale)
USRSCTP_SYSCTL_DECL(sctp_delayed_sack_time_default)
USRSCTP_SYSCTL_DECL(sctp_sack_freq_default)
USRSCTP_SYSCTL_DECL(sctp_system_free_resc_limit)
@@ -1021,7 +1122,6 @@ USRSCTP_SYSCTL_DECL(sctp_mbuf_threshold_count)
USRSCTP_SYSCTL_DECL(sctp_do_drain)
USRSCTP_SYSCTL_DECL(sctp_hb_maxburst)
USRSCTP_SYSCTL_DECL(sctp_abort_if_one_2_one_hits_limit)
-USRSCTP_SYSCTL_DECL(sctp_strict_data_order)
USRSCTP_SYSCTL_DECL(sctp_min_residual)
USRSCTP_SYSCTL_DECL(sctp_max_retran_chunk)
USRSCTP_SYSCTL_DECL(sctp_logging_level)
@@ -1034,6 +1134,7 @@ USRSCTP_SYSCTL_DECL(sctp_udp_tunneling_port)
USRSCTP_SYSCTL_DECL(sctp_enable_sack_immediately)
USRSCTP_SYSCTL_DECL(sctp_vtag_time_wait)
USRSCTP_SYSCTL_DECL(sctp_blackhole)
+USRSCTP_SYSCTL_DECL(sctp_sendall_limit)
USRSCTP_SYSCTL_DECL(sctp_diag_info_code)
USRSCTP_SYSCTL_DECL(sctp_fr_max_burst_default)
USRSCTP_SYSCTL_DECL(sctp_path_pf_threshold)
@@ -1099,7 +1200,7 @@ struct sctpstat {
uint32_t sctps_recvauthfailed; /* total number of auth failed */
uint32_t sctps_recvexpress; /* total fast path receives all one chunk */
uint32_t sctps_recvexpressm; /* total fast path multi-part data */
- uint32_t sctps_recvnocrc;
+ uint32_t sctps_recv_spare; /* formerly sctps_recvnocrc */
uint32_t sctps_recvswcrc;
uint32_t sctps_recvhwcrc;
@@ -1116,7 +1217,7 @@ struct sctpstat {
uint32_t sctps_sendecne; /* total output ECNE chunks */
uint32_t sctps_sendauth; /* total output AUTH chunks FIXME */
uint32_t sctps_senderrors; /* ip_output error counter */
- uint32_t sctps_sendnocrc;
+ uint32_t sctps_send_spare; /* formerly sctps_sendnocrc */
uint32_t sctps_sendswcrc;
uint32_t sctps_sendhwcrc;
/* PCKDROPREP statistics: */
diff --git a/netwerk/sctp/update_sctp.sh b/netwerk/sctp/update_sctp.sh
deleted file mode 100755
index 4a49cfaacb..0000000000
--- a/netwerk/sctp/update_sctp.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# assume $1 is the directory with a SVN checkout of the libsctp source
-#
-# sctp usrlib source is available (via svn) at:
-# svn co https://sctp-refimpl.googlecode.com/svn/trunk sctpSVN
-#
-# also assumes we've made *NO* changes to the SCTP sources! If we do, we have to merge by
-# hand after this process, or use a more complex one.
-#
-# For example, one could update an sctp library import head, and merge back to default. Or keep a
-# separate repo with this in it, and pull from there to m-c and merge.
-if [ "$1" ] ; then
- export date=`date`
- export revision=`(cd $1; svnversion -n)`
-
- cp $1/KERN/usrsctp/usrsctplib/*.c $1/KERN/usrsctp/usrsctplib/*.h netwerk/sctp/src
- cp $1/KERN/usrsctp/usrsctplib/netinet/*.c $1/KERN/usrsctp/usrsctplib/netinet/*.h netwerk/sctp/src/netinet
- cp $1/KERN/usrsctp/usrsctplib/netinet6/*.c $1/KERN/usrsctp/usrsctplib/netinet6/*.h netwerk/sctp/src/netinet6
-
- hg addremove netwerk/sctp/src --include "**.c" --include "**.h" --similarity 90
-
- echo "sctp updated to version $revision from SVN on $date" >> netwerk/sctp/sctp_update.log
- echo "sctp updated to version $revision from SVN on $date"
- echo "WARNING: reapply any local patches!"
-else
- echo "usage: $0 path_to_sctpSVN_directory"
- echo "run from the root of your m-c clone"
-fi