diff options
Diffstat (limited to 'netwerk/sctp/src')
61 files changed, 15003 insertions, 13228 deletions
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, ¶m_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, ¶m_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, ¬ification, 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, ¬ification, 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, ¶ms, 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, ¶ms, 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, ¶m, 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, ¶m_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, ¶m_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)); + ¶m_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, ¶m_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, ¶m_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: */ |