From 467ae4e4c0f04947cf3240cbfb4966df08c98b6a Mon Sep 17 00:00:00 2001 From: Basilisk-Dev Date: Wed, 18 Feb 2026 18:34:57 -0500 Subject: [PATCH 1/4] Issue #2925 - Upgrade usrsctp library to latest version --- netwerk/sctp/sctp_update.log | 1 + netwerk/sctp/src/README.sctp | 4 +- netwerk/sctp/src/netinet/sctp.h | 29 +- netwerk/sctp/src/netinet/sctp_asconf.c | 52 +- netwerk/sctp/src/netinet/sctp_asconf.h | 5 - netwerk/sctp/src/netinet/sctp_auth.c | 49 +- netwerk/sctp/src/netinet/sctp_auth.h | 7 +- netwerk/sctp/src/netinet/sctp_bsd_addr.c | 78 +- netwerk/sctp/src/netinet/sctp_bsd_addr.h | 5 - netwerk/sctp/src/netinet/sctp_callout.c | 2 +- netwerk/sctp/src/netinet/sctp_callout.h | 5 - netwerk/sctp/src/netinet/sctp_cc_functions.c | 277 +-- netwerk/sctp/src/netinet/sctp_constants.h | 36 +- netwerk/sctp/src/netinet/sctp_crc32.c | 74 +- netwerk/sctp/src/netinet/sctp_crc32.h | 9 +- netwerk/sctp/src/netinet/sctp_header.h | 19 +- netwerk/sctp/src/netinet/sctp_indata.c | 177 +- netwerk/sctp/src/netinet/sctp_indata.h | 5 - netwerk/sctp/src/netinet/sctp_input.c | 1260 +++++----- netwerk/sctp/src/netinet/sctp_input.h | 5 - .../sctp/src/netinet/sctp_lock_userspace.h | 18 +- netwerk/sctp/src/netinet/sctp_os.h | 5 - netwerk/sctp/src/netinet/sctp_os_userspace.h | 37 +- netwerk/sctp/src/netinet/sctp_output.c | 2178 +++++++++-------- netwerk/sctp/src/netinet/sctp_output.h | 11 +- netwerk/sctp/src/netinet/sctp_pcb.c | 1235 +++++----- netwerk/sctp/src/netinet/sctp_pcb.h | 107 +- netwerk/sctp/src/netinet/sctp_peeloff.c | 6 - netwerk/sctp/src/netinet/sctp_peeloff.h | 5 - netwerk/sctp/src/netinet/sctp_process_lock.h | 228 +- netwerk/sctp/src/netinet/sctp_sha1.h | 6 - netwerk/sctp/src/netinet/sctp_ss_functions.c | 553 +++-- netwerk/sctp/src/netinet/sctp_structs.h | 120 +- netwerk/sctp/src/netinet/sctp_sysctl.c | 266 +- netwerk/sctp/src/netinet/sctp_sysctl.h | 17 +- netwerk/sctp/src/netinet/sctp_timer.c | 195 +- netwerk/sctp/src/netinet/sctp_timer.h | 5 - netwerk/sctp/src/netinet/sctp_uio.h | 17 +- netwerk/sctp/src/netinet/sctp_userspace.c | 107 +- netwerk/sctp/src/netinet/sctp_usrreq.c | 1299 +++++----- netwerk/sctp/src/netinet/sctp_var.h | 34 +- netwerk/sctp/src/netinet/sctputil.c | 873 ++++--- netwerk/sctp/src/netinet/sctputil.h | 54 +- netwerk/sctp/src/netinet6/sctp6_usrreq.c | 521 ++-- netwerk/sctp/src/netinet6/sctp6_var.h | 15 +- netwerk/sctp/src/user_environment.c | 2 +- netwerk/sctp/src/user_mbuf.c | 45 +- netwerk/sctp/src/user_mbuf.h | 11 +- netwerk/sctp/src/user_recv_thread.c | 44 +- netwerk/sctp/src/user_socket.c | 81 +- netwerk/sctp/src/user_socketvar.h | 12 +- netwerk/sctp/src/usrsctp.h | 26 +- 52 files changed, 5148 insertions(+), 5084 deletions(-) diff --git a/netwerk/sctp/sctp_update.log b/netwerk/sctp/sctp_update.log index f994dcd7bd..532c069064 100644 --- a/netwerk/sctp/sctp_update.log +++ b/netwerk/sctp/sctp_update.log @@ -17,3 +17,4 @@ sctp updated to version 8815 from SVN on Tue Mar 4 08:50:51 EST 2014 sctp updated to version 9168 from SVN on Tue Mar 3 12:11:40 EST 2015 sctp updated to version 9209 from SVN on Tue Mar 24 18:11:59 EDT 2015 sctp updated to version 0.9.5.0 from https://github.com/sctplab/usrsctp/releases/tag/0.9.5.0 on Sat Aug 26 21:54:00 EDT 2023 +sctp updated to commit fd070e05a7474f38c7fecdf4d4b6005d2547ee00 from https://github.com/sctplab/usrsctp/commit/fd070e05a7474f38c7fecdf4d4b6005d2547ee00 on Wed Feb 18 18:05:35 EST 2026 diff --git a/netwerk/sctp/src/README.sctp b/netwerk/sctp/src/README.sctp index 8e54cc03e5..35f5811171 100644 --- a/netwerk/sctp/src/README.sctp +++ b/netwerk/sctp/src/README.sctp @@ -1,5 +1,5 @@ -This code is imported from the usrsctp library. The current code is version -0.9.5.0. +This code is imported from the usrsctp library. The current code is based on +master commit fd070e05a7474f38c7fecdf4d4b6005d2547ee00 (2025-10-16). The project is accessed on GitHub at the following location: diff --git a/netwerk/sctp/src/netinet/sctp.h b/netwerk/sctp/src/netinet/sctp.h index f0dc35ad56..cef07e0e59 100644 --- a/netwerk/sctp/src/netinet/sctp.h +++ b/netwerk/sctp/src/netinet/sctp.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 366750 2020-10-16 10:44:48Z tuexen $"); -#endif - #ifndef _NETINET_SCTP_H_ #define _NETINET_SCTP_H_ @@ -139,6 +134,7 @@ struct sctp_paramhdr { #define SCTP_NRSACK_SUPPORTED 0x00000030 #define SCTP_PKTDROP_SUPPORTED 0x00000031 #define SCTP_MAX_CWND 0x00000032 +#define SCTP_ACCEPT_ZERO_CHECKSUM 0x00000033 /* * read-only options @@ -198,8 +194,11 @@ struct sctp_paramhdr { /* JRS - Pluggable Congestion Control Socket option */ #define SCTP_PLUGGABLE_CC 0x00001202 /* RS - Pluggable Stream Scheduling Socket option */ -#define SCTP_PLUGGABLE_SS 0x00001203 -#define SCTP_SS_VALUE 0x00001204 +#define SCTP_STREAM_SCHEDULER 0x00001203 +#define SCTP_STREAM_SCHEDULER_VALUE 0x00001204 +/* The next two are for backwards compatibility. */ +#define SCTP_PLUGGABLE_SS SCTP_STREAM_SCHEDULER +#define SCTP_SS_VALUE SCTP_STREAM_SCHEDULER_VALUE #define SCTP_CC_OPTION 0x00001205 /* Options for CC modules */ /* For I-DATA */ #define SCTP_INTERLEAVING_SUPPORTED 0x00001206 @@ -322,15 +321,21 @@ struct sctp_paramhdr { /* Default simple round-robin */ #define SCTP_SS_DEFAULT 0x00000000 /* Real round-robin */ -#define SCTP_SS_ROUND_ROBIN 0x00000001 +#define SCTP_SS_RR 0x00000001 /* Real round-robin per packet */ -#define SCTP_SS_ROUND_ROBIN_PACKET 0x00000002 +#define SCTP_SS_RR_PKT 0x00000002 /* Priority */ -#define SCTP_SS_PRIORITY 0x00000003 +#define SCTP_SS_PRIO 0x00000003 /* Fair Bandwidth */ -#define SCTP_SS_FAIR_BANDWITH 0x00000004 +#define SCTP_SS_FB 0x00000004 /* First-come, first-serve */ -#define SCTP_SS_FIRST_COME 0x00000005 +#define SCTP_SS_FCFS 0x00000005 +/* The next five are for backwards compatibility. */ +#define SCTP_SS_ROUND_ROBIN SCTP_SS_RR +#define SCTP_SS_ROUND_ROBIN_PACKET SCTP_SS_RR_PKT +#define SCTP_SS_PRIORITY SCTP_SS_PRIO +#define SCTP_SS_FAIR_BANDWITH SCTP_SS_FB +#define SCTP_SS_FIRST_COME SCTP_SS_FCFS /* fragment interleave constants * setting must be one of these or diff --git a/netwerk/sctp/src/netinet/sctp_asconf.c b/netwerk/sctp/src/netinet/sctp_asconf.c index cd2944389f..d1825e73ed 100644 --- a/netwerk/sctp/src/netinet/sctp_asconf.c +++ b/netwerk/sctp/src/netinet/sctp_asconf.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - #include #include #include @@ -555,8 +550,8 @@ sctp_process_asconf_set_primary(struct sockaddr *src, /* notify upper layer */ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED); if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) && - (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) && - (stcb->asoc.alternate)) { + ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF) == 0) && + (stcb->asoc.alternate != NULL)) { sctp_free_remote_addr(stcb->asoc.alternate); stcb->asoc.alternate = NULL; } @@ -1132,7 +1127,7 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa) return; } - /* Multiple local addresses exsist in the association. */ + /* Multiple local addresses exist in the association. */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { /* clear any cached route and source address */ #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -1352,13 +1347,13 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, #ifdef SCTP_DEBUG if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) { if (type == SCTP_ADD_IP_ADDRESS) { - SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: "); + SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); } else if (type == SCTP_DEL_IP_ADDRESS) { - SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: "); + SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); } else { - SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: "); + SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); } } @@ -1738,7 +1733,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset, SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n"); 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_no_unlock = 1; return; } @@ -1986,7 +1981,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sin6 = &ifa->address.sin6; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecifed addresses */ + /* we skip unspecified addresses */ return; } if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { @@ -2017,7 +2012,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sin = &ifa->address.sin; if (sin->sin_addr.s_addr == 0) { - /* we skip unspecifed addresses */ + /* we skip unspecified addresses */ return; } if (stcb->asoc.scope.ipv4_local_scope == 0 && @@ -2172,7 +2167,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } sin6 = &ifa->address.sin6; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecifed addresses */ + /* we skip unspecified addresses */ continue; } #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -2206,7 +2201,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sin = &ifa->address.sin; if (sin->sin_addr.s_addr == 0) { - /* we skip unspecifed addresses */ + /* we skip unspecified addresses */ continue; } #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -2237,7 +2232,6 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; else continue; - break; } if (type == SCTP_ADD_IP_ADDRESS) { @@ -2495,7 +2489,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked) sin = &sctp_ifa->address.sin; if (sin->sin_addr.s_addr == 0) { - /* skip unspecifed addresses */ + /* skip unspecified addresses */ continue; } #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -2529,7 +2523,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked) sin6 = &sctp_ifa->address.sin6; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecifed addresses */ + /* we skip unspecified addresses */ continue; } #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -2599,7 +2593,7 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) struct sctp_asconf_chunk *acp; struct sctp_asconf_paramhdr *aph; struct sctp_asconf_addr_param *aap; - uint32_t p_length; + uint32_t p_length, overhead; uint32_t correlation_id = 1; /* 0 is reserved... */ caddr_t ptr, lookup_ptr; uint8_t lookup_used = 0; @@ -2612,6 +2606,20 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) if (aa == NULL) return (NULL); + /* Consider IP header and SCTP common header. */ + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + overhead = SCTP_MIN_OVERHEAD; + } else { + overhead = SCTP_MIN_V4_OVERHEAD; + } + /* Consider ASONF chunk. */ + overhead += sizeof(struct sctp_asconf_chunk); + /* Consider AUTH chunk. */ + overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); + if (stcb->asoc.smallest_mtu <= overhead) { + /* MTU too small. */ + return (NULL); + } /* * get a chunk header mbuf and a cluster for the asconf params since * it's simpler to fill in the asconf chunk header lookup address on @@ -2653,7 +2661,7 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) /* get the parameter length */ p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length); /* will it fit in current chunk? */ - if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu) || + if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu - overhead) || (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) { /* won't fit, so we're done with this chunk */ break; @@ -3376,7 +3384,7 @@ out: 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_type = SCTP_DEL_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); diff --git a/netwerk/sctp/src/netinet/sctp_asconf.h b/netwerk/sctp/src/netinet/sctp_asconf.h index 3868949208..a7429aeca4 100644 --- a/netwerk/sctp/src/netinet/sctp_asconf.h +++ b/netwerk/sctp/src/netinet/sctp_asconf.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_ASCONF_H_ #define _NETINET_SCTP_ASCONF_H_ diff --git a/netwerk/sctp/src/netinet/sctp_auth.c b/netwerk/sctp/src/netinet/sctp_auth.c index 9281e07803..6fc3807cc1 100644 --- a/netwerk/sctp/src/netinet/sctp_auth.c +++ b/netwerk/sctp/src/netinet/sctp_auth.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #include #include #include @@ -580,7 +575,7 @@ sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked) 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); + 0, &key_id, so_locked); SCTPDBG(SCTP_DEBUG_AUTH2, "%s: stcb %p key %u no longer used, %d\n", __func__, (void *)stcb, key_id, skey->refcount); @@ -1339,8 +1334,8 @@ sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid) /* are there other refcount holders on the key? */ if (skey->refcount == 1) { /* no other users, send a notification for this key */ - sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, keyid, 0, - SCTP_SO_LOCKED); + sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, 0, &keyid, + SCTP_SO_LOCKED); } /* mark the key as deactivated */ @@ -1684,15 +1679,10 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth, return (-1); } /* generate a notification if this is a new key id */ - if (stcb->asoc.authinfo.recv_keyid != shared_key_id) - /* - * sctp_ulp_notify(SCTP_NOTIFY_AUTH_NEW_KEY, stcb, - * shared_key_id, (void - * *)stcb->asoc.authinfo.recv_keyid); - */ - sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, - shared_key_id, stcb->asoc.authinfo.recv_keyid, - SCTP_SO_NOT_LOCKED); + if (stcb->asoc.authinfo.recv_keyid != shared_key_id) { + sctp_ulp_notify(SCTP_NOTIFY_AUTH_NEW_KEY, stcb, 0, + &shared_key_id, SCTP_SO_NOT_LOCKED); + } /* compute a new recv assoc key and cache it */ if (stcb->asoc.authinfo.recv_key != NULL) sctp_free_key(stcb->asoc.authinfo.recv_key); @@ -1735,27 +1725,22 @@ 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) + uint16_t keyid, int so_locked) { struct mbuf *m_notify; struct sctp_authkey_event *auth; struct sctp_queued_to_read *control; - if ((stcb == NULL) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) - ) { - /* If the socket is gone we are out of here */ - return; - } + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_AUTHEVNT)) /* event not enabled */ return; m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_authkey_event), - 0, M_NOWAIT, 1, MT_HEADER); + 0, M_NOWAIT, 1, MT_HEADER); if (m_notify == NULL) /* no space left */ return; @@ -1767,7 +1752,12 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication, auth->auth_flags = 0; auth->auth_length = sizeof(*auth); auth->auth_keynumber = keyid; - auth->auth_altkeynumber = alt_keyid; + /* XXXMT: The following is BSD specific. */ + if (indication == SCTP_AUTH_NEW_KEY) { + auth->auth_altkeynumber = stcb->asoc.authinfo.recv_keyid; + } else { + auth->auth_altkeynumber = 0; + } auth->auth_indication = indication; auth->auth_assoc_id = sctp_get_associd(stcb); @@ -1787,7 +1777,8 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication, /* 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); + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } /*- diff --git a/netwerk/sctp/src/netinet/sctp_auth.h b/netwerk/sctp/src/netinet/sctp_auth.h index d43ada90da..00682ae78e 100644 --- a/netwerk/sctp/src/netinet/sctp_auth.h +++ b/netwerk/sctp/src/netinet/sctp_auth.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_AUTH_H_ #define _NETINET_SCTP_AUTH_H_ @@ -199,7 +194,7 @@ extern struct mbuf *sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end, extern int sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *ch, struct mbuf *m, uint32_t offset); extern void sctp_notify_authentication(struct sctp_tcb *stcb, - uint32_t indication, uint16_t keyid, uint16_t alt_keyid, int so_locked); + uint32_t indication, uint16_t keyid, int so_locked); extern int sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit); extern void sctp_initialize_auth_params(struct sctp_inpcb *inp, diff --git a/netwerk/sctp/src/netinet/sctp_bsd_addr.c b/netwerk/sctp/src/netinet/sctp_bsd_addr.c index dbdefd4f90..3e0df08f13 100644 --- a/netwerk/sctp/src/netinet/sctp_bsd_addr.c +++ b/netwerk/sctp/src/netinet/sctp_bsd_addr.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 366426 2020-10-04 15:37:34Z tuexen $"); -#endif - #include #include #include @@ -50,8 +45,7 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 366426 2020-10-04 15:37:34Z #include #include #include - -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) && !defined(__Userspace__) #include #endif @@ -79,8 +73,8 @@ MALLOC_DEFINE(SCTP_M_MCORE, "sctp_mcore", "sctp mcore queue"); /* 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) { @@ -130,7 +124,7 @@ sctp_iterator_thread(void *v SCTP_UNUSED) #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) { @@ -139,7 +133,7 @@ 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); @@ -150,14 +144,14 @@ sctp_iterator_thread(void *v SCTP_UNUSED) 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; @@ -196,7 +190,7 @@ sctp_startup_iterator(void) kproc_create(sctp_iterator_thread, (void *)NULL, &sctp_it_ctl.thread_proc, - RFPROC, + 0, SCTP_KTHREAD_PAGES, SCTP_KTRHEAD_NAME); #elif defined(__APPLE__) @@ -252,7 +246,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) { @@ -278,7 +272,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: @@ -294,21 +288,29 @@ sctp_is_desired_interface_type(struct ifnet *ifn) return (result); } #endif - #if defined(__APPLE__) && !defined(__Userspace__) + int sctp_is_vmware_interface(struct ifnet *ifn) { return (strncmp(ifnet_name(ifn), "vmnet", 5) == 0); } + #endif -#if defined(_WIN32) +#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; @@ -334,8 +336,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); - if (pAdapterAddrs) - GlobalFree(pAdapterAddrs); + FREE(pAdapterAddrs); return; } /* Enumerate through each returned adapter and save its information */ @@ -360,8 +361,7 @@ sctp_init_ifns_for_vrf(int vrfid) } } } - if (pAdapterAddrs) - GlobalFree(pAdapterAddrs); + FREE(pAdapterAddrs); #endif #ifdef INET6 AdapterAddrsSize = 0; @@ -381,8 +381,7 @@ 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); - if (pAdapterAddrs) - GlobalFree(pAdapterAddrs); + FREE(pAdapterAddrs); return; } /* Enumerate through each returned adapter and save its information */ @@ -404,8 +403,7 @@ sctp_init_ifns_for_vrf(int vrfid) } } } - if (pAdapterAddrs) - GlobalFree(pAdapterAddrs); + FREE(pAdapterAddrs); #endif } #elif defined(__Userspace__) @@ -445,7 +443,7 @@ sctp_init_ifns_for_vrf(int vrfid) #if defined(INET6) if ((ifa->ifa_addr->sa_family == AF_INET6) && IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecifed addresses */ + /* skip unspecified addresses */ continue; } #endif @@ -473,7 +471,6 @@ sctp_init_ifns_for_vrf(int vrfid) #endif } #endif - #if defined(__APPLE__) && !defined(__Userspace__) static void sctp_init_ifns_for_vrf(int vrfid) @@ -519,7 +516,7 @@ sctp_init_ifns_for_vrf(int vrfid) } if (ifa->ifa_addr->sa_family == AF_INET6) { if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecifed addresses */ + /* skip unspecified addresses */ continue; } } else { @@ -552,7 +549,6 @@ sctp_init_ifns_for_vrf(int vrfid) ifnet_list_free(ifnetlist); } #endif - #if defined(__FreeBSD__) && !defined(__Userspace__) static void sctp_init_ifns_for_vrf(int vrfid) @@ -573,7 +569,7 @@ sctp_init_ifns_for_vrf(int vrfid) IFNET_RLOCK(); NET_EPOCH_ENTER(et); - CK_TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) { + CK_STAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { if (sctp_is_desired_interface_type(ifn) == 0) { /* non desired type */ continue; @@ -593,7 +589,7 @@ sctp_init_ifns_for_vrf(int vrfid) #ifdef INET6 case AF_INET6: if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecifed addresses */ + /* skip unspecified addresses */ continue; } break; @@ -698,7 +694,7 @@ sctp_addr_change(struct ifaddr *ifa, int cmd) case AF_INET6: ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags; if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecifed addresses */ + /* skip unspecified addresses */ return; } break; @@ -717,12 +713,11 @@ sctp_addr_change(struct ifaddr *ifa, int cmd) (void *)ifa, ifa->ifa_addr, ifa_flags, 1); } else { sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, + (void *)ifa->ifa_ifp, #if defined(__APPLE__) && !defined(__Userspace__) - ifnet_index(ifa->ifa_ifp), - ifnet_name(ifa->ifa_ifp)); + ifnet_index(ifa->ifa_ifp)); #else - ifa->ifa_ifp->if_index, - ifa->ifa_ifp->if_xname); + ifa->ifa_ifp->if_index); #endif /* We don't bump refcount here so when it completes @@ -773,9 +768,9 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, struct mbuf *m = NULL; #if defined(__FreeBSD__) || defined(__Userspace__) #if defined(__Userspace__) - m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0, allonebuf); + 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); + m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); #endif if (m == NULL) { /* bad, no memory */ @@ -948,11 +943,10 @@ sctp_copy_out_packet_log(uint8_t *target, int length) * start copying up to length bytes out. * We return the number of bytes copied. */ - int tocopy, this_copy; + int this_copy; int *lenat; int did_delay = 0; - tocopy = length; if (length < (int)(2 * sizeof(int))) { /* not enough room */ return (0); @@ -980,7 +974,7 @@ sctp_copy_out_packet_log(uint8_t *target, int length) memcpy((void *)lenat, (void *)SCTP_BASE_VAR(packet_log_buffer), this_copy); if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), - SCTP_PKTLOG_WRITERS_NEED_LOCK); + SCTP_PKTLOG_WRITERS_NEED_LOCK); } SCTP_IP_PKTLOG_UNLOCK(); return (this_copy + sizeof(int)); diff --git a/netwerk/sctp/src/netinet/sctp_bsd_addr.h b/netwerk/sctp/src/netinet/sctp_bsd_addr.h index d6ab91b5b5..5e8549eec5 100644 --- a/netwerk/sctp/src/netinet/sctp_bsd_addr.h +++ b/netwerk/sctp/src/netinet/sctp_bsd_addr.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_BSD_ADDR_H_ #define _NETINET_SCTP_BSD_ADDR_H_ diff --git a/netwerk/sctp/src/netinet/sctp_callout.c b/netwerk/sctp/src/netinet/sctp_callout.c index 4c9be7568b..ee6cd4cddd 100644 --- a/netwerk/sctp/src/netinet/sctp_callout.c +++ b/netwerk/sctp/src/netinet/sctp_callout.c @@ -136,7 +136,7 @@ sctp_os_timer_stop(sctp_os_timer_t *c) /* * Don't attempt to delete a callout that's not on the queue. */ - if (!(c->c_flags & SCTP_CALLOUT_PENDING)) { + if ((c->c_flags & SCTP_CALLOUT_PENDING) == 0) { c->c_flags &= ~SCTP_CALLOUT_ACTIVE; SCTP_TIMERQ_UNLOCK(); return (0); diff --git a/netwerk/sctp/src/netinet/sctp_callout.h b/netwerk/sctp/src/netinet/sctp_callout.h index 81fd8530d1..2a78e414fb 100644 --- a/netwerk/sctp/src/netinet/sctp_callout.h +++ b/netwerk/sctp/src/netinet/sctp_callout.h @@ -30,11 +30,6 @@ * SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - #ifndef _NETINET_SCTP_CALLOUT_ #define _NETINET_SCTP_CALLOUT_ diff --git a/netwerk/sctp/src/netinet/sctp_cc_functions.c b/netwerk/sctp/src/netinet/sctp_cc_functions.c index 57bcdaaa5a..77193d8f9d 100644 --- a/netwerk/sctp/src/netinet/sctp_cc_functions.c +++ b/netwerk/sctp/src/netinet/sctp_cc_functions.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 366517 2020-10-07 15:22:48Z tuexen $"); -#endif - #include #include #include @@ -54,10 +49,20 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 366517 2020-10-07 15:22 #include #endif +#if defined(_WIN32) && defined(__MINGW32__) +#include +#endif + #define SHIFT_MPTCP_MULTI_N 40 #define SHIFT_MPTCP_MULTI_Z 16 #define SHIFT_MPTCP_MULTI 8 +#ifdef KDTRACE_HOOKS +#define __dtrace +#else +#define __dtrace __unused +#endif + static void sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net) { @@ -103,8 +108,8 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) net->ssthresh = assoc->peers_rwnd; #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); + stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, + 0, net->cwnd); #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE|SCTP_CWND_LOGGING_ENABLE)) { @@ -197,8 +202,8 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, sctp_enforce_cwnd_limit(asoc, net); #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); + stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, + old_cwnd, net->cwnd); #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), @@ -261,7 +266,7 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb #endif { #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t oth, probepoint; + uint64_t oth __dtrace, probepoint __dtrace; #endif #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -277,11 +282,11 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb /* Probe point 5 */ probepoint |= ((5 << 16) | 1); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { if (net->cc_mod.rtcc.last_step_state == 5) @@ -300,11 +305,11 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + oth, + probepoint); #endif if (net->cwnd > (4 * net->mtu)) { net->cwnd -= net->mtu; @@ -326,11 +331,11 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb /* Probe point 6 */ probepoint |= ((6 << 16) | 0); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if (net->cc_mod.rtcc.steady_step) { #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -340,11 +345,11 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + oth, + probepoint); #endif if ((net->cc_mod.rtcc.last_step_state == 5) && (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) { @@ -372,11 +377,11 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb /* Probe point 7 */ probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { if (net->cc_mod.rtcc.last_step_state == 5) @@ -416,7 +421,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #endif { #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t oth, probepoint; + uint64_t oth __dtrace, probepoint __dtrace; #endif /* Bandwidth decreased.*/ @@ -433,11 +438,11 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ /* PROBE POINT 1 */ probepoint |= ((1 << 16) | 1); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if (net->cc_mod.rtcc.ret_from_eq) { /* Switch over to CA if we are less aggressive */ @@ -450,11 +455,11 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ /* Probe point 2 */ probepoint |= ((2 << 16) | 0); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif /* Someone else - fight for more? */ if (net->cc_mod.rtcc.steady_step) { @@ -465,10 +470,10 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + oth, probepoint); #endif /* Did we voluntarily give up some? if so take @@ -490,11 +495,11 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ /* Probe point 3 */ probepoint |= ((3 << 16) | 0); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if (net->cc_mod.rtcc.steady_step) { #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -504,11 +509,11 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + oth, + probepoint); #endif if ((net->cc_mod.rtcc.vol_reduce) && (inst_ind != SCTP_INST_GAINING)) { @@ -526,11 +531,11 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ /* Probe point 4 */ probepoint |= ((4 << 16) | 0); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if (net->cc_mod.rtcc.steady_step) { #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -540,11 +545,11 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + oth, + probepoint); #endif if ((net->cc_mod.rtcc.vol_reduce) && (inst_ind != SCTP_INST_GAINING)) { @@ -575,7 +580,7 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #endif { #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t oth, probepoint; + uint64_t oth __dtrace, probepoint __dtrace; #endif /* BW increased, so update and @@ -588,11 +593,11 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ /* PROBE POINT 0 */ probepoint = (((uint64_t)net->cwnd) << 32); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif if (net->cc_mod.rtcc.steady_step) { #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -602,11 +607,11 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | nbw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + oth, + probepoint); #endif net->cc_mod.rtcc.last_step_state = 0; net->cc_mod.rtcc.step_cnt = 0; @@ -626,7 +631,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) { uint64_t bw_offset, rtt_offset; #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t probepoint, rtt, vtag; + uint64_t probepoint __dtrace, rtt, vtag; #endif uint64_t bytes_for_this_rtt, inst_bw; uint64_t div, inst_off; @@ -713,11 +718,11 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) } #if defined(__FreeBSD__) && !defined(__Userspace__) SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((nbw << 32) | inst_bw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), - net->flight_size, - probepoint); + vtag, + ((nbw << 32) | inst_bw), + ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), + net->flight_size, + probepoint); #endif } else { /* No rtt measurement, use last one */ @@ -762,9 +767,9 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, { struct sctp_nets *net; #if defined(__FreeBSD__) && !defined(__Userspace__) - int old_cwnd; + int old_cwnd __dtrace; #endif - uint32_t t_ssthresh, t_cwnd, incr; + uint32_t t_ssthresh, incr; uint64_t t_ucwnd_sbw; uint64_t t_path_mptcp; uint64_t mptcp_like_alpha; @@ -773,7 +778,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, /* MT FIXME: Don't compute this over and over again */ t_ssthresh = 0; - t_cwnd = 0; t_ucwnd_sbw = 0; t_path_mptcp = 0; mptcp_like_alpha = 1; @@ -783,7 +787,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, max_path = 0; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { t_ssthresh += net->ssthresh; - t_cwnd += net->cwnd; /* lastsa>>3; we don't need to devide ...*/ srtt = net->lastsa; if (srtt > 0) { @@ -877,7 +880,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, } } else { #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t vtag, probepoint; + uint64_t vtag __dtrace, probepoint __dtrace; probepoint = (((uint64_t)net->cwnd) << 32); probepoint |= ((0xa << 16) | 0); @@ -886,11 +889,11 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, (stcb->rport); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - nbw, - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + nbw, + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif net->cc_mod.rtcc.lbw = nbw; net->cc_mod.rtcc.lbw_rtt = net->rtt; @@ -986,10 +989,10 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, } #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); + stcb->asoc.my_vtag, + ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), + net, + old_cwnd, net->cwnd); #endif } else { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { @@ -1050,10 +1053,10 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, sctp_enforce_cwnd_limit(asoc, net); #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); + stcb->asoc.my_vtag, + ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), + net, + old_cwnd, net->cwnd); #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { sctp_log_cwnd(stcb, net, net->mtu, @@ -1084,15 +1087,15 @@ sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_n #endif { #if defined(__FreeBSD__) && !defined(__Userspace__) - int old_cwnd; + int old_cwnd __dtrace; old_cwnd = net->cwnd; #endif net->cwnd = net->mtu; #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); + stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, + old_cwnd, net->cwnd); #endif SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", (void *)net, net->cwnd); @@ -1163,10 +1166,10 @@ sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) net->partial_bytes_acked = 0; #if defined(__FreeBSD__) && !defined(__Userspace__) SDT_PROBE5(sctp, cwnd, net, to, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); + stcb->asoc.my_vtag, + ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), + net, + old_cwnd, net->cwnd); #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); @@ -1217,10 +1220,10 @@ sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets * net->cwnd = net->ssthresh; #if defined(__FreeBSD__) && !defined(__Userspace__) SDT_PROBE5(sctp, cwnd, net, ecn, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); + stcb->asoc.my_vtag, + ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), + net, + old_cwnd, net->cwnd); #endif 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); @@ -1338,10 +1341,10 @@ sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, /* log only changes */ #if defined(__FreeBSD__) && !defined(__Userspace__) SDT_PROBE5(sctp, cwnd, net, pd, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); + stcb->asoc.my_vtag, + ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), + net, + old_cwnd, net->cwnd); #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), @@ -1363,10 +1366,10 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb, sctp_enforce_cwnd_limit(&stcb->asoc, net); #if defined(__FreeBSD__) && !defined(__Userspace__) SDT_PROBE5(sctp, cwnd, net, bl, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); + stcb->asoc.my_vtag, + ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), + net, + old_cwnd, net->cwnd); #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); @@ -1414,7 +1417,7 @@ sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net) { if (net->cc_mod.rtcc.tls_needs_set > 0) { - /* We had a bw measurment going on */ + /* We had a bw measurement going on */ struct timeval ltls; SCTP_GETPTIME_TIMEVAL(<ls); timevalsub(<ls, &net->cc_mod.rtcc.tls); @@ -1427,7 +1430,7 @@ sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, struct sctp_nets *net) { #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t vtag, probepoint; + uint64_t vtag __dtrace, probepoint __dtrace; #endif if (net->cc_mod.rtcc.lbw) { @@ -1439,11 +1442,11 @@ sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, /* Probe point 8 */ probepoint |= ((8 << 16) | 0); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | 0), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); + vtag, + ((net->cc_mod.rtcc.lbw << 32) | 0), + ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), + net->flight_size, + probepoint); #endif net->cc_mod.rtcc.lbw_rtt = 0; net->cc_mod.rtcc.cwnd_at_bw_set = 0; @@ -1488,7 +1491,7 @@ sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) { #if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t vtag, probepoint; + uint64_t vtag __dtrace, probepoint __dtrace; #endif sctp_set_initial_cc_param(stcb, net); @@ -1500,11 +1503,11 @@ sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - 0, - 0, - 0, - probepoint); + vtag, + 0, + 0, + 0, + probepoint); #endif net->cc_mod.rtcc.lbw_rtt = 0; net->cc_mod.rtcc.cwnd_at_bw_set = 0; diff --git a/netwerk/sctp/src/netinet/sctp_constants.h b/netwerk/sctp/src/netinet/sctp_constants.h index b8e2f2d581..69953e9b9e 100644 --- a/netwerk/sctp/src/netinet/sctp_constants.h +++ b/netwerk/sctp/src/netinet/sctp_constants.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__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_ @@ -419,7 +414,7 @@ extern void getwintimeofday(struct timeval *tv); /*************0x8000 series*************/ #define SCTP_ECN_CAPABLE 0x8000 - +#define SCTP_ZERO_CHECKSUM_ACCEPTABLE 0x8001 /* RFC 4895 */ #define SCTP_RANDOM 0x8002 #define SCTP_CHUNK_LIST 0x8003 @@ -610,7 +605,7 @@ extern void getwintimeofday(struct timeval *tv); #define SCTP_RTO_UPPER_BOUND (60000) /* 60 sec in ms */ #define SCTP_RTO_LOWER_BOUND (1000) /* 1 sec is ms */ -#define SCTP_RTO_INITIAL (3000) /* 3 sec in ms */ +#define SCTP_RTO_INITIAL (1000) /* 1 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 */ @@ -691,8 +686,6 @@ extern void getwintimeofday(struct timeval *tv); /* amount peer is obligated to have in rwnd or I will abort */ #define SCTP_MIN_RWND 1500 -#define SCTP_DEFAULT_MAXSEGMENT 65535 - #define SCTP_CHUNK_BUFFER_SIZE 512 #define SCTP_PARAM_BUFFER_SIZE 512 @@ -729,11 +722,14 @@ extern void getwintimeofday(struct timeval *tv); #define SCTP_NOTIFY_STR_RESET_FAILED_IN 20 #define SCTP_NOTIFY_STR_RESET_DENIED_OUT 21 #define SCTP_NOTIFY_STR_RESET_DENIED_IN 22 -#define SCTP_NOTIFY_AUTH_NEW_KEY 23 -#define SCTP_NOTIFY_AUTH_FREE_KEY 24 -#define SCTP_NOTIFY_NO_PEER_AUTH 25 -#define SCTP_NOTIFY_SENDER_DRY 26 -#define SCTP_NOTIFY_REMOTE_ERROR 27 +#define SCTP_NOTIFY_STR_RESET_ADD 23 +#define SCTP_NOTIFY_STR_RESET_TSN 24 +#define SCTP_NOTIFY_AUTH_NEW_KEY 25 +#define SCTP_NOTIFY_AUTH_FREE_KEY 26 +#define SCTP_NOTIFY_NO_PEER_AUTH 27 +#define SCTP_NOTIFY_SENDER_DRY 28 +#define SCTP_NOTIFY_REMOTE_ERROR 29 +#define SCTP_NOTIFY_ASSOC_TIMEDOUT 30 /* This is the value for messages that are NOT completely * copied down where we will start to split the message. @@ -1005,7 +1001,7 @@ extern void getwintimeofday(struct timeval *tv); #define sctp_sowwakeup(inp, so) \ do { \ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEOUTPUT; \ + sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEOUTPUT); \ } else { \ sowwakeup(so); \ } \ @@ -1015,8 +1011,8 @@ do { \ #define sctp_sowwakeup_locked(inp, so) \ do { \ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ + sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEOUTPUT); \ SOCKBUF_UNLOCK(&((so)->so_snd)); \ - inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEOUTPUT; \ } else { \ sowwakeup_locked(so); \ } \ @@ -1025,8 +1021,8 @@ do { \ #define sctp_sowwakeup_locked(inp, so) \ do { \ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ + sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEOUTPUT); \ SOCKBUF_UNLOCK(&((so)->so_snd)); \ - inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEOUTPUT; \ } else { \ sowwakeup(so); \ } \ @@ -1036,7 +1032,7 @@ do { \ #define sctp_sorwakeup(inp, so) \ do { \ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEINPUT; \ + sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEINPUT); \ } else { \ sorwakeup(so); \ } \ @@ -1046,7 +1042,7 @@ do { \ #define sctp_sorwakeup_locked(inp, so) \ do { \ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEINPUT; \ + sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEINPUT); \ SOCKBUF_UNLOCK(&((so)->so_rcv)); \ } else { \ sorwakeup_locked(so); \ @@ -1057,7 +1053,7 @@ do { \ #define sctp_sorwakeup_locked(inp, so) \ do { \ if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - inp->sctp_flags |= SCTP_PCB_FLAGS_WAKEINPUT; \ + sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEINPUT); \ 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 0b5a06e067..0370fb1381 100644 --- a/netwerk/sctp/src/netinet/sctp_crc32.c +++ b/netwerk/sctp/src/netinet/sctp_crc32.c @@ -34,8 +34,6 @@ #if defined(__FreeBSD__) && !defined(__Userspace__) #include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.c 362498 2020-06-22 14:36:14Z tuexen $"); - #include "opt_sctp.h" #include @@ -733,31 +731,34 @@ static uint32_t #endif sctp_finalize_crc32c(uint32_t crc32c) { - uint32_t result; #if BYTE_ORDER == BIG_ENDIAN - uint8_t byte0, byte1, byte2, byte3; + uint32_t byte0, byte1, byte2, byte3; #endif - /* Complement the result */ - result = ~crc32c; #if BYTE_ORDER == BIG_ENDIAN /* - * 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. + * For BIG-ENDIAN platforms, the result is in LITTLE-ENDIAN byte order. + * For LITTLE-ENDIAN platforms, the result is in in BIG-ENDIAN byte + * order. So for BIG-ENDIAN platforms the bytes must be swapped to + * return the result always in network byte order (aka BIG-ENDIAN). */ - byte0 = result & 0x000000ff; - byte1 = (result >> 8) & 0x000000ff; - byte2 = (result >> 16) & 0x000000ff; - byte3 = (result >> 24) & 0x000000ff; + byte0 = crc32c & 0x000000ff; + byte1 = (crc32c >> 8) & 0x000000ff; + byte2 = (crc32c >> 16) & 0x000000ff; + byte3 = (crc32c >> 24) & 0x000000ff; crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); -#else - /* - * For LITTLE ENDIAN platforms the result is in already in network - * byte order. - */ - crc32c = result; #endif - return (crc32c); + return (~crc32c); +} + +static int +sctp_calculate_cksum_cb(void *arg, void *data, u_int len) +{ + uint32_t *basep; + + basep = arg; + *basep = calculate_crc32c(*basep, data, len); + return (0); } /* @@ -767,32 +768,19 @@ sctp_finalize_crc32c(uint32_t crc32c) * it is compiled on a kernel with SCTP support. */ uint32_t -sctp_calculate_cksum(struct mbuf *m, uint32_t offset) +sctp_calculate_cksum(struct mbuf *m, int32_t offset) { - uint32_t base = 0xffffffff; + uint32_t base; + int len; - while (offset > 0) { - KASSERT(m != NULL, ("sctp_calculate_cksum, offset > length of mbuf chain")); - if (offset < (uint32_t)m->m_len) { - break; - } - 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); + M_ASSERTPKTHDR(m); + KASSERT(offset < m->m_pkthdr.len, + ("%s: invalid offset %u into mbuf %p", __func__, offset, m)); + + base = 0xffffffff; + len = m->m_pkthdr.len - offset; + (void)m_apply(m, offset, len, sctp_calculate_cksum_cb, &base); + return (sctp_finalize_crc32c(base)); } #if defined(__FreeBSD__) && !defined(__Userspace__) diff --git a/netwerk/sctp/src/netinet/sctp_crc32.h b/netwerk/sctp/src/netinet/sctp_crc32.h index 5e76ff21bf..e8315dc345 100644 --- a/netwerk/sctp/src/netinet/sctp_crc32.h +++ b/netwerk/sctp/src/netinet/sctp_crc32.h @@ -32,16 +32,11 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__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) -uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t); +uint32_t sctp_calculate_cksum(struct mbuf *, int32_t); #if defined(__FreeBSD__) && !defined(__Userspace__) #if defined(SCTP) || defined(SCTP_SUPPORT) void sctp_delayed_cksum(struct mbuf *, uint32_t offset); @@ -51,6 +46,6 @@ void sctp_delayed_cksum(struct mbuf *, uint32_t offset); #if defined(__Userspace__) 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); +uint32_t sctp_calculate_cksum(struct mbuf *, int32_t); #endif #endif /* __crc32c_h__ */ diff --git a/netwerk/sctp/src/netinet/sctp_header.h b/netwerk/sctp/src/netinet/sctp_header.h index 9226a9ef99..7a5ab643c0 100644 --- a/netwerk/sctp/src/netinet/sctp_header.h +++ b/netwerk/sctp/src/netinet/sctp_header.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__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_ @@ -98,7 +93,7 @@ struct sctp_supported_addr_param { /* heartbeat info parameter */ struct sctp_heartbeat_info_param { struct sctp_paramhdr ph; - uint32_t time_value_1; + time_t time_value_1; uint32_t time_value_2; uint32_t random_value1; uint32_t random_value2; @@ -193,9 +188,9 @@ struct sctp_init { #define SCTP_IDENTIFICATION_SIZE 16 #define SCTP_ADDRESS_SIZE 4 #if defined(__Userspace__) -#define SCTP_RESERVE_SPACE 5 +#define SCTP_RESERVE_SPACE 4 #else -#define SCTP_RESERVE_SPACE 6 +#define SCTP_RESERVE_SPACE 5 #endif /* state cookie header */ struct sctp_state_cookie { /* this is our definition... */ @@ -226,6 +221,7 @@ struct sctp_state_cookie { /* this is our definition... */ uint8_t ipv4_scope; /* IPv4 private addr scope */ uint8_t loopback_scope; /* loopback scope information */ + uint8_t rcv_edmid; /* copy of the inp value */ uint8_t reserved[SCTP_RESERVE_SPACE]; /* Align to 64 bits */ /* * at the end is tacked on the INIT chunk and the INIT-ACK chunk @@ -538,6 +534,13 @@ struct sctp_auth_chunk { uint8_t hmac[]; } SCTP_PACKED; +/* Zero checksum support draft-ietf-tsvwg-sctp-zero-checksum */ + +struct sctp_zero_checksum_acceptable { + struct sctp_paramhdr ph; + uint32_t edmid; +} 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 diff --git a/netwerk/sctp/src/netinet/sctp_indata.c b/netwerk/sctp/src/netinet/sctp_indata.c index 3bce9e99a6..b94772438e 100644 --- a/netwerk/sctp/src/netinet/sctp_indata.c +++ b/netwerk/sctp/src/netinet/sctp_indata.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 367520 2020-11-09 13:12:07Z tuexen $"); -#endif - #include #if defined(__FreeBSD__) && !defined(__Userspace__) #include @@ -58,6 +53,9 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 367520 2020-11-09 13:12:07Z t #if defined(__FreeBSD__) && !defined(__Userspace__) #include #endif +#if defined(_WIN32) && defined(__MINGW32__) +#include +#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 @@ -462,7 +460,7 @@ sctp_abort_in_reasm(struct sctp_tcb *stcb, 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, oper, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; } @@ -514,7 +512,7 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, * with TSN 1? If the peer is doing some sort of funky TSN/SSN * assignment this could happen... and I don't see how this would be * a violation. So for now I am undecided an will leave the sort by - * SSN alone. Maybe a hybred approach is the answer + * SSN alone. Maybe a hybrid approach is the answer * */ struct sctp_queued_to_read *at; @@ -550,7 +548,7 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, } 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; } @@ -657,7 +655,7 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; } } @@ -783,21 +781,6 @@ sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queu 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; - } -} - static int sctp_handle_old_unordered_data(struct sctp_tcb *stcb, struct sctp_association *asoc, @@ -838,7 +821,7 @@ restart: } 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); + sctp_add_chk_to_control(control, strm, stcb, asoc, chk, inp_read_lock_held); fsn++; cnt_added++; chk = NULL; @@ -927,7 +910,7 @@ restart: } if (cnt_added && strm->pd_api_started) { #if defined(__Userspace__) - sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, SCTP_READ_LOCK_NOT_HELD); + 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); } @@ -993,7 +976,7 @@ sctp_inject_old_unordered_data(struct sctp_tcb *stcb, * 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 + * We are completely 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. */ @@ -1311,16 +1294,18 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control, * data from the chk onto the control and free * up the chunk resources. */ - uint32_t added=0; - int i_locked = 0; + uint32_t added = 0; + bool i_locked = false; - 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->on_read_q) { + if (hold_rlock == 0) { + /* Its being pd-api'd so we must do some locks. */ + SCTP_INP_READ_LOCK(stcb->sctp_ep); + i_locked = true; + } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { + goto out; + } } if (control->data == NULL) { control->data = chk->data; @@ -1368,6 +1353,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control, control->end_added = 1; control->last_frag_seen = 1; } +out: if (i_locked) { SCTP_INP_READ_UNLOCK(stcb->sctp_ep); } @@ -1377,7 +1363,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control, /* * 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 + * queue, see if anything 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. */ @@ -1755,7 +1741,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, */ 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); } @@ -1821,7 +1807,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, * receiver. Send peer an ABORT! */ op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); } @@ -1893,7 +1879,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); } @@ -1925,7 +1911,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, SCTP_SNPRINTF(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid); goto err_out; } else { - if ((tsn == control->fsn_included + 1) && + if ((control->first_frag_seen) && + (tsn == control->fsn_included + 1) && (control->end_added == 0)) { SCTP_SNPRINTF(msg, sizeof(msg), "Illegal message sequence, missing end for MID: %8.8x", @@ -1946,7 +1933,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, * When we have NO room in the rwnd we check to make sure * the reader is doing its job... */ - if (stcb->sctp_socket->so_rcv.sb_cc) { + if (SCTP_SBAVAIL(&stcb->sctp_socket->so_rcv) > 0) { /* some to read, wake-up */ #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; @@ -2040,7 +2027,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, } op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); } @@ -2758,7 +2745,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 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); + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return (2); } if ((asoc->idata_supported == 0) && @@ -2769,7 +2756,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 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); + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return (2); } if ((ch->chunk_type == SCTP_DATA) || @@ -2794,7 +2781,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, chk_length); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); 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); + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return (2); } #ifdef SCTP_AUDITING_ENABLED @@ -2861,7 +2848,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 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); + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return (2); } default: @@ -2880,7 +2867,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, 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); + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return (2); } if (ch->chunk_type & 0x40) { @@ -3320,7 +3307,6 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_tmit_chunk *tp1; int strike_flag = 0; struct timeval now; - int tot_retrans = 0; uint32_t sending_seq; struct sctp_nets *net; int num_dests_sacked = 0; @@ -3401,7 +3387,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, */ if (tp1->whoTo && tp1->whoTo->saw_newack == 0) { /* - * No new acks were receieved for data sent to this + * No new acks were received for data sent to this * dest. Therefore, according to the SFR algo for * CMT, no data sent to this dest can be marked for * FR using this SACK. @@ -3412,7 +3398,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->whoTo->this_sack_highest_newack) && !(accum_moved && asoc->fast_retran_loss_recovery)) { /* - * CMT: New acks were receieved for data sent to + * CMT: New acks were received for data sent to * this dest. But no new acks were seen for data * sent after tp1. Therefore, according to the SFR * algo for CMT, tp1 cannot be marked for FR using @@ -3691,7 +3677,6 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, } tp1->rec.data.doing_fast_retransmit = 1; - tot_retrans++; /* mark the sending seq for possible subsequent FR's */ /* * SCTP_PRINTF("Marking TSN for FR new value %x\n", @@ -3792,7 +3777,7 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb, * Now is this one marked for resend and its time is * now up? */ -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) +#if !(defined(__FreeBSD__) && !defined(__Userspace__)) if (timercmp(&now, &tp1->rec.data.timetodrop, >)) { #else if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { @@ -3874,13 +3859,13 @@ sctp_fs_audit(struct sctp_association *asoc) if ((inflight > 0) || (inbetween > 0)) { #ifdef INVARIANTS - panic("Flight size-express incorrect? \n"); + panic("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d", + inflight, inbetween, resend, above, acked); #else 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", - inflight, inbetween, resend, above, acked); + inflight, inbetween, resend, above, acked); ret = 1; #endif } @@ -4005,7 +3990,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return; } asoc->this_sack_highest_gap = cumack; @@ -4204,7 +4189,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, * is optional. */ net->error_count = 0; - if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { /* addr came good */ net->dest_state |= SCTP_ADDR_REACHABLE; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, @@ -4349,7 +4334,7 @@ again: /* 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return; } if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && @@ -4470,7 +4455,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, * old sack, if so discard. 2) If there is nothing left in the send * queue (cum-ack is equal to last acked) then you have a duplicate * too, update any rwnd change and verify no timers are running. - * then return. 3) Process any new consequtive data i.e. cum-ack + * then return. 3) Process any new consecutive data i.e. cum-ack * moved process these first and note that it moved. 4) Process any * sack blocks. 5) Drop any acked from the queue. 6) Check for any * revoked blocks and mark. 7) Update the cwnd. 8) Nothing left, @@ -4564,7 +4549,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return; } /**********************/ @@ -4607,7 +4592,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, * We init netAckSz and netAckSz2 to 0. These are used to track 2 * things. The total byte count acked is tracked in netAckSz AND * netAck2 is used to track the total bytes acked that are un- - * amibguious and were never retransmitted. We track these on a per + * ambiguous and were never retransmitted. We track these on a per * destination address basis. */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { @@ -4984,7 +4969,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, * is optional. */ net->error_count = 0; - if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { /* addr came good */ net->dest_state |= SCTP_ADDR_REACHABLE; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, @@ -5067,7 +5052,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /* 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return; } if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && @@ -5312,13 +5297,17 @@ 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 *control, *ncontrol; struct sctp_association *asoc; uint32_t mid; int need_reasm_check = 0; + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + asoc = &stcb->asoc; mid = strmin->last_mid_delivered; /* @@ -5328,7 +5317,7 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) { if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) { /* this is deliverable now */ - if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + 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); @@ -5356,11 +5345,9 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, /* 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); + 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 */ @@ -5426,10 +5413,9 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, 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); + 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 { @@ -5452,8 +5438,8 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, static void sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, - struct sctp_association *asoc, struct sctp_stream_in *strm, - struct sctp_queued_to_read *control, int ordered, uint32_t cumtsn) + 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; @@ -5465,6 +5451,11 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, * delivery function... to see if it can be delivered... But * for now we just dump everything on the queue. */ + + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + if (!asoc->idata_supported && !ordered && control->first_frag_seen && SCTP_TSN_GT(control->fsn_included, cumtsn)) { @@ -5495,17 +5486,30 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); } if (!TAILQ_EMPTY(&control->reasm)) { - /* This has to be old data, unordered */ + KASSERT(!asoc->idata_supported, + ("Reassembly queue not empty for I-DATA")); + KASSERT(!ordered, + ("Reassembly queue not empty for ordered data")); if (control->data) { sctp_m_freem(control->data); control->data = NULL; } - sctp_reset_a_control(control, stcb->sctp_ep, cumtsn); + control->fsn_included = 0xffffffff; + control->first_frag_seen = 0; + control->last_frag_seen = 0; + if (control->on_read_q) { + /* + * We have to purge it from there, + * hopefully this will work :-) + */ + TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next); + control->on_read_q = 0; + } 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); + chk, SCTP_READ_LOCK_HELD); } sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD); return; @@ -5564,9 +5568,8 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, 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_queued_to_read *control, *ncontrol, *sv; + struct sctp_queued_to_read *control, *ncontrol; asoc = &stcb->asoc; if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) { @@ -5605,7 +5608,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, 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_37; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); return; } SCTP_STAT_INCR(sctps_fwdtsn_map_over); @@ -5744,9 +5747,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, 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; control->end_added = 1; if (control->on_strm_q == SCTP_ON_ORDERED) { TAILQ_REMOVE(&strm->inqueue, control, next_instrm); @@ -5769,13 +5770,11 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, #endif } control->on_strm_q = 0; - stcb->asoc.control_pdapi = control; sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, stcb, SCTP_PARTIAL_DELIVERY_ABORTED, - (void *)&str_seq, - SCTP_SO_NOT_LOCKED); - stcb->asoc.control_pdapi = sv; + (void *)control, + SCTP_SO_NOT_LOCKED); break; } else if ((control->sinfo_stream == sid) && SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) { diff --git a/netwerk/sctp/src/netinet/sctp_indata.h b/netwerk/sctp/src/netinet/sctp_indata.h index 651493b917..523d4f6d34 100644 --- a/netwerk/sctp/src/netinet/sctp_indata.h +++ b/netwerk/sctp/src/netinet/sctp_indata.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_INDATA_H_ #define _NETINET_SCTP_INDATA_H_ diff --git a/netwerk/sctp/src/netinet/sctp_input.c b/netwerk/sctp/src/netinet/sctp_input.c index 517189fb6a..97561ee46e 100644 --- a/netwerk/sctp/src/netinet/sctp_input.c +++ b/netwerk/sctp/src/netinet/sctp_input.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 368622 2020-12-13 23:51:51Z tuexen $"); -#endif - #include #include #include @@ -62,6 +57,9 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 368622 2020-12-13 23:51:51Z tu #if defined(__FreeBSD__) && !defined(__Userspace__) #include #endif +#if defined(_WIN32) && defined(__MINGW32__) +#include +#endif static void sctp_stop_all_cookie_timers(struct sctp_tcb *stcb) @@ -94,7 +92,7 @@ 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, struct sctp_nets *net, int *abort_no_unlock, + struct sctp_tcb *stcb, struct sctp_nets *net, #if defined(__FreeBSD__) && !defined(__Userspace__) uint8_t mflowtype, uint32_t mflowid, #endif @@ -108,66 +106,21 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, if (stcb == NULL) { SCTP_INP_RLOCK(inp); } - /* validate length */ - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - if (stcb) - *abort_no_unlock = 1; - goto outnow; - } - /* validate parameters */ + /* Validate parameters */ init = &cp->init; - if (init->initiate_tag == 0) { - /* 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - if (stcb) - *abort_no_unlock = 1; + if (ntohl(init->initiate_tag) == 0) { goto outnow; } - if (ntohl(init->a_rwnd) < SCTP_MIN_RWND) { - /* 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - if (stcb) - *abort_no_unlock = 1; - goto outnow; - } - if (init->num_inbound_streams == 0) { + if ((ntohl(init->a_rwnd) < SCTP_MIN_RWND) || + (ntohs(init->num_inbound_streams) == 0) || + (ntohs(init->num_outbound_streams) == 0)) { /* 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, + sctp_send_abort(m, iphlen, src, dst, sh, init->initiate_tag, op_err, #if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, + mflowtype, mflowid, inp->fibnum, #endif - vrf_id, port); - if (stcb) - *abort_no_unlock = 1; - goto outnow; - } - if (init->num_outbound_streams == 0) { - /* 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - if (stcb) - *abort_no_unlock = 1; + vrf_id, port); goto outnow; } if (sctp_validate_init_auth_params(m, offset + sizeof(*cp), @@ -175,13 +128,11 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, /* auth parameter(s) error... send abort */ 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, + sctp_send_abort(m, iphlen, src, dst, sh, init->initiate_tag, op_err, #if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, + mflowtype, mflowid, inp->fibnum, #endif - vrf_id, port); - if (stcb) - *abort_no_unlock = 1; + vrf_id, port); goto outnow; } /* We are only accepting if we have a listening socket.*/ @@ -244,13 +195,14 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) struct sctp_stream_queue_pending *sp; struct sctp_association *asoc; + SCTP_TCB_LOCK_ASSERT(stcb); + /* 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 */ for (i = 0; i < stcb->asoc.streamoutcnt; i++) { @@ -260,7 +212,7 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) continue; } if ((sp->msg_is_complete) && - (sp->length == 0) && + (sp->length == 0) && (sp->sender_all_done)) { /* We are doing differed cleanup. Last * time through when we took all the data @@ -276,7 +228,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); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, &asoc->strmout[i], sp); if (sp->net) { sctp_free_remote_addr(sp->net); sp->net = NULL; @@ -297,7 +249,6 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) } } } - SCTP_TCB_SEND_UNLOCK(stcb); return (unsent_data); } @@ -309,6 +260,8 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) struct sctp_nets *lnet; unsigned int i; + SCTP_TCB_LOCK_ASSERT(stcb); + init = &cp->init; asoc = &stcb->asoc; /* save off parameters */ @@ -326,7 +279,6 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) } } } - SCTP_TCB_SEND_LOCK(stcb); if (asoc->pre_open_streams > ntohs(init->num_inbound_streams)) { unsigned int newcnt; struct sctp_stream_out *outs; @@ -365,7 +317,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { atomic_subtract_int(&stcb->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); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp); sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 0, sp, SCTP_SO_NOT_LOCKED); if (sp->data) { @@ -386,7 +338,6 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) /* cut back the count */ asoc->pre_open_streams = newcnt; } - SCTP_TCB_SEND_UNLOCK(stcb); asoc->streamoutcnt = asoc->pre_open_streams; if (asoc->strmout) { for (i = 0; i < asoc->streamoutcnt; i++) { @@ -474,10 +425,15 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, op_err = sctp_arethere_unrecognized_parameters(m, (offset + sizeof(struct sctp_init_chunk)), &abort_flag, (struct sctp_chunkhdr *)cp, - &nat_friendly, &cookie_found); + &nat_friendly, &cookie_found, NULL); if (abort_flag) { /* Send an abort and notify peer */ - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + 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 (-1); } @@ -503,37 +459,45 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, cause->type[0] = htons(SCTP_STATE_COOKIE); } sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, + src, dst, sh, op_err, #if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, + mflowtype, mflowid, #endif - vrf_id, net->port); + 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 (sctp_process_init((struct sctp_init_chunk *)cp, stcb) < 0) { if (op_err != NULL) { sctp_m_freem(op_err); } - return (retval); + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); + SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); + 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 (-1); } 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, stcb->asoc.port))) { + offset + sizeof(struct sctp_init_chunk), + initack_limit, src, dst, NULL, stcb->asoc.port)) < 0) { 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, - "Load addresses from INIT causes an abort %d\n", - retval); + "Load addresses from INIT causes an abort %d\n", + retval); sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, src, dst, sh, op_err, #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -568,12 +532,10 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, SCTP_FROM_SCTP_INPUT, __LINE__); } - stcb->asoc.overall_error_count = 0; - net->error_count = 0; /* * Cancel the INIT timer, We do this first before queueing the - * cookie. We always cancel at the primary to assue that we are + * cookie. We always cancel at the primary to assume that we are * canceling the timer started by the INIT which always goes to the * primary. */ @@ -581,8 +543,12 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); /* calculate the RTO */ - sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, - SCTP_RTT_FROM_NON_DATA); + if (asoc->overall_error_count == 0) { + sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, + SCTP_RTT_FROM_NON_DATA); + } + stcb->asoc.overall_error_count = 0; + net->error_count = 0; #if defined(__Userspace__) if (stcb->sctp_ep->recv_callback) { if (stcb->sctp_socket) { @@ -725,7 +691,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, /* Now lets do a RTO with this */ sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, SCTP_RTT_FROM_NON_DATA); - if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) { + if ((r_net->dest_state & SCTP_ADDR_REACHABLE) == 0) { r_net->dest_state |= SCTP_ADDR_REACHABLE; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); @@ -784,7 +750,6 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) 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(); @@ -793,6 +758,7 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) } else { return (0); } + new_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1); if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { /* generate a new vtag and send init */ LIST_REMOVE(stcb, sctp_asocs); @@ -885,7 +851,7 @@ sctp_handle_abort(struct sctp_abort_chunk *abort, 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); + sctp_abort_notification(stcb, true, false, error, abort, SCTP_SO_NOT_LOCKED); /* free the tcb */ SCTP_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || @@ -942,22 +908,51 @@ sctp_start_net_timers(struct sctp_tcb *stcb) } } +static void +sctp_check_data_from_peer(struct sctp_tcb *stcb, int *abort_flag) +{ + char msg[SCTP_DIAG_INFO_LEN]; + struct sctp_association *asoc; + struct mbuf *op_err; + unsigned int i; + + *abort_flag = 0; + asoc = &stcb->asoc; + if (SCTP_TSN_GT(asoc->highest_tsn_inside_map, asoc->cumulative_tsn) || + SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn)) { + SCTP_SNPRINTF(msg, sizeof(msg), "Missing TSN"); + *abort_flag = 1; + } + if (!*abort_flag) { + for (i = 0; i < asoc->streamincnt; i++) { + if (!TAILQ_EMPTY(&asoc->strmin[i].inqueue) || + !TAILQ_EMPTY(&asoc->strmin[i].uno_inqueue)) { + SCTP_SNPRINTF(msg, sizeof(msg), "Missing user data"); + *abort_flag = 1; + break; + } + } + } + if (*abort_flag) { + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INPUT + SCTP_LOC_9; + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); + } +} + 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; int old_state; #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; #endif - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown: handling SHUTDOWN\n"); + SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_shutdown: handling SHUTDOWN\n"); if (stcb == NULL) return; - asoc = &stcb->asoc; if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { return; @@ -971,56 +966,10 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, 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(__Userspace__) - 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->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - if (stcb->sctp_socket) { - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif + sctp_check_data_from_peer(stcb, abort_flag); + if (*abort_flag) { + return; } - /* goto SHUTDOWN_RECEIVED state to block new requests */ if (stcb->sctp_socket) { if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) && @@ -1030,7 +979,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, sctp_ulp_notify(SCTP_NOTIFY_PEER_SHUTDOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); /* reset time */ - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); + (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); } } if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) { @@ -1044,8 +993,8 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, /* Now is there unsent data on a stream somewhere? */ some_on_streamwheel = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED); - if (!TAILQ_EMPTY(&asoc->send_queue) || - !TAILQ_EMPTY(&asoc->sent_queue) || + if (!TAILQ_EMPTY(&stcb->asoc.send_queue) || + !TAILQ_EMPTY(&stcb->asoc.sent_queue) || some_on_streamwheel) { /* By returning we will push more data out */ return; @@ -1074,18 +1023,18 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, struct sctp_tcb *stcb, struct sctp_nets *net) { - struct sctp_association *asoc; + int abort_flag; #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; so = SCTP_INP_SO(stcb->sctp_ep); #endif SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown_ack: handling SHUTDOWN ACK\n"); - if (stcb == NULL) + "sctp_handle_shutdown_ack: handling SHUTDOWN ACK\n"); + if (stcb == NULL) { return; + } - asoc = &stcb->asoc; /* process according to association state */ if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { @@ -1100,35 +1049,13 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, SCTP_TCB_UNLOCK(stcb); return; } - if (asoc->control_pdapi) { - /* With a normal shutdown - * we assume the end of last record. - */ - SCTP_INP_READ_LOCK(stcb->sctp_ep); - 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(__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); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif + sctp_check_data_from_peer(stcb, &abort_flag); + if (abort_flag) { + return; } #ifdef INVARIANTS - if (!TAILQ_EMPTY(&asoc->send_queue) || - !TAILQ_EMPTY(&asoc->sent_queue) || + 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-ACK"); } @@ -1142,7 +1069,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, if (stcb->sctp_socket) { if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - stcb->sctp_socket->so_snd.sb_cc = 0; + SCTP_SB_CLEAR(stcb->sctp_socket->so_snd); } sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); } @@ -1156,7 +1083,7 @@ 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_11); + SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); #if defined(__APPLE__) && !defined(__Userspace__) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -1291,18 +1218,13 @@ sctp_handle_error(struct sctp_chunkhdr *ch, */ if ((cause_length >= sizeof(struct sctp_error_stale_cookie)) && (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { + struct timeval now; struct sctp_error_stale_cookie *stale_cookie; + uint64_t stale_time; - 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 (asoc->stale_cookie_count > asoc->max_init_times) { + sctp_abort_notification(stcb, false, true, 0, NULL, SCTP_SO_NOT_LOCKED); #if defined(__APPLE__) && !defined(__Userspace__) so = SCTP_INP_SO(stcb->sctp_ep); atomic_add_int(&stcb->asoc.refcnt, 1); @@ -1312,16 +1234,41 @@ 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_12); + 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 */ + stale_cookie = (struct sctp_error_stale_cookie *)cause; + stale_time = ntohl(stale_cookie->stale_time); + if (stale_time == 0) { + /* Use an RTT as an approximation. */ + (void)SCTP_GETTIME_TIMEVAL(&now); + timevalsub(&now, &asoc->time_entered); + stale_time = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec; + if (stale_time == 0) { + stale_time = 1; + } + } + /* + * stale_time is in usec, convert it to msec. + * Round upwards, to ensure that it is non-zero. + */ + stale_time = (stale_time + 999) / 1000; + /* Double it, to be more robust on RTX. */ + stale_time = 2 * stale_time; + asoc->cookie_preserve_req = (uint32_t)stale_time; + if (asoc->overall_error_count == 0) { + sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, + SCTP_RTT_FROM_NON_DATA); + } + asoc->overall_error_count = 0; + /* Blast back to INIT state */ sctp_toss_old_cookies(stcb, &stcb->asoc); - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); sctp_stop_all_cookie_timers(stcb); + SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); + (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); } break; @@ -1420,73 +1367,25 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, "sctp_handle_init_ack: TCB is null\n"); return (-1); } - if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_ack_chunk)) { - /* Invalid length */ - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - init_ack = &cp->init; - /* validate parameters */ - if (init_ack->initiate_tag == 0) { - /* protocol error... send an abort */ - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - if (ntohl(init_ack->a_rwnd) < SCTP_MIN_RWND) { - /* protocol error... send an abort */ - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - if (init_ack->num_inbound_streams == 0) { - /* protocol error... send an abort */ - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - if (init_ack->num_outbound_streams == 0) { - /* protocol error... send an abort */ - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - /* process according to association state... */ - switch (SCTP_GET_STATE(stcb)) { - case SCTP_STATE_COOKIE_WAIT: - /* this is the expected state for this chunk */ - /* process the INIT-ACK parameters */ + /* Only process the INIT-ACK chunk in COOKIE WAIT state.*/ + if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { + init_ack = &cp->init; + /* Validate parameters. */ + if ((ntohl(init_ack->initiate_tag) == 0) || + (ntohl(init_ack->a_rwnd) < SCTP_MIN_RWND) || + (ntohs(init_ack->num_inbound_streams) == 0) || + (ntohs(init_ack->num_outbound_streams) == 0)) { + /* One of the mandatory parameters is illegal. */ + 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__) && !defined(__Userspace__) + mflowtype, mflowid, + #endif + vrf_id, net->port); + *abort_no_unlock = 1; + return (-1); + } if (stcb->asoc.primary_destination->dest_state & SCTP_ADDR_UNCONFIRMED) { /* @@ -1509,49 +1408,35 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, /* error in parsing parameters */ return (-1); } - /* update our state */ + /* Update our state. */ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to COOKIE-ECHOED state\n"); SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_ECHOED); - /* reset the RTO calc */ + /* Reset the RTO calculation. */ 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_FROM_SCTP_INPUT, + __LINE__); } stcb->asoc.overall_error_count = 0; (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); /* - * collapse the init timer back in case of a exponential - * backoff + * Collapse the init timer back in case of a exponential + * backoff. */ sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep, stcb, net); /* - * the send at the end of the inbound data processing will - * cause the cookie to be sent + * The output routine at the end of the inbound data processing + * will cause the cookie to be sent. */ - break; - case SCTP_STATE_SHUTDOWN_SENT: - /* incorrect state... discard */ - break; - case SCTP_STATE_COOKIE_ECHOED: - /* incorrect state... discard */ - break; - case SCTP_STATE_OPEN: - /* incorrect state... discard */ - break; - case SCTP_STATE_EMPTY: - case SCTP_STATE_INUSE: - default: - /* incorrect state... discard */ + SCTPDBG(SCTP_DEBUG_INPUT1, "Leaving handle-init-ack end\n"); + return (0); + } else { return (-1); - break; } - SCTPDBG(SCTP_DEBUG_INPUT1, "Leaving handle-init-ack end\n"); - return (0); } static struct sctp_tcb * @@ -1594,7 +1479,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, 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; @@ -1624,6 +1508,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, vrf_id, net->port); if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 2; + SCTP_TCB_UNLOCK(stcb); return (NULL); } /* @@ -1638,9 +1523,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, (uint8_t *) & init_buf); if (init_cp == NULL) { /* could not pull a INIT chunk in cookie */ + SCTP_TCB_UNLOCK(stcb); return (NULL); } if (init_cp->ch.chunk_type != SCTP_INITIATION) { + SCTP_TCB_UNLOCK(stcb); return (NULL); } /* @@ -1653,9 +1540,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, (uint8_t *) & initack_buf); if (initack_cp == NULL) { /* could not pull INIT-ACK chunk in cookie */ + SCTP_TCB_UNLOCK(stcb); return (NULL); } if (initack_cp->ch.chunk_type != SCTP_INITIATION_ACK) { + SCTP_TCB_UNLOCK(stcb); return (NULL); } if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && @@ -1681,6 +1570,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, */ if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 17; + SCTP_TCB_UNLOCK(stcb); return (NULL); } switch (SCTP_GET_STATE(stcb)) { @@ -1693,10 +1583,17 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, * have the right seq no's. */ /* First we must process the INIT !! */ - retval = sctp_process_init(init_cp, stcb); - if (retval < 0) { + if (sctp_process_init(init_cp, stcb) < 0) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 3; + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); + SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); + 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); return (NULL); } /* we have already processed the INIT so no problem */ @@ -1713,10 +1610,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); 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_STAT_INCR_GAUGE32(sctps_currestab); sctp_stop_all_cookie_timers(stcb); if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -1731,16 +1624,16 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, * init/init-ack/cookie done before the * init-ack came back.. */ - stcb->sctp_ep->sctp_flags |= - SCTP_PCB_FLAGS_CONNECTED; + sctp_pcb_add_flags(stcb->sctp_ep, 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); SCTP_SOCKET_LOCK(so, 1); SCTP_TCB_LOCK(stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { + SCTP_TCB_UNLOCK(stcb); SCTP_SOCKET_UNLOCK(so, 1); return (NULL); } @@ -1752,16 +1645,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } /* notify upper layer */ *notification = SCTP_NOTIFY_ASSOC_UP; - /* - * 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; - 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, @@ -1776,16 +1660,22 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, break; } /* end switch */ sctp_stop_all_cookie_timers(stcb); - /* - * We ignore the return code here.. not sure if we should - * somehow abort.. but we do have an existing asoc. This - * 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, stcb->asoc.port)) { + if ((retval = sctp_load_addresses_from_init(stcb, m, + init_offset + sizeof(struct sctp_init_chunk), + initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 4; + op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), + "Problem with address parameters"); + SCTPDBG(SCTP_DEBUG_INPUT1, + "Load addresses from INIT causes an abort %d\n", + retval); + 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); return (NULL); } /* respond with a COOKIE-ACK */ @@ -1805,12 +1695,13 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, */ if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 6; + SCTP_TCB_UNLOCK(stcb); return (NULL); } /* If nat support, and the below and stcb is established, * send back a ABORT(colliding state) if we are established. */ - if ((SCTP_GET_STATE(stcb) == 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) || @@ -1830,6 +1721,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, mflowtype, mflowid, inp->fibnum, #endif vrf_id, port); + SCTP_TCB_UNLOCK(stcb); return (NULL); } if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && @@ -1845,7 +1737,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, * generator returned the same vtag when we * first sent our INIT-ACK and when we later sent * our INIT. The side with the seq numbers that are - * different will be the one that normnally would + * different will be the one that normally would * have hit case C. This in effect "extends" our vtags * in this collision case to be 64 bits. The same collision * could occur aka you get both vtag and seq number the @@ -1859,6 +1751,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 7; + SCTP_TCB_UNLOCK(stcb); return (NULL); } if (how_indx < sizeof(asoc->cookie_how)) @@ -1901,17 +1794,35 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } } /* process the INIT info (peer's info) */ - retval = sctp_process_init(init_cp, stcb); - if (retval < 0) { + if (sctp_process_init(init_cp, stcb) < 0) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 9; + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); + SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); + 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); return (NULL); } - if (sctp_load_addresses_from_init(stcb, m, - init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src, stcb->asoc.port)) { + if ((retval = sctp_load_addresses_from_init(stcb, m, + init_offset + sizeof(struct sctp_init_chunk), + initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 10; + op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), + "Problem with address parameters"); + SCTPDBG(SCTP_DEBUG_INPUT1, + "Load addresses from INIT causes an abort %d\n", + retval); + 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); return (NULL); } if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || @@ -1924,15 +1835,16 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; #endif - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; + sctp_pcb_add_flags(stcb->sctp_ep, 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); SCTP_SOCKET_LOCK(so, 1); SCTP_TCB_LOCK(stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { + SCTP_TCB_UNLOCK(stcb); SCTP_SOCKET_UNLOCK(so, 1); return (NULL); } @@ -1953,10 +1865,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); } 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_toss_old_cookies(stcb, asoc); sctp_send_cookie_ack(stcb); @@ -1985,19 +1893,25 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, #endif if (asoc->peer_supports_nat) { + struct sctp_tcb *local_stcb; + /* This is a gross gross hack. * Just call the cookie_new code since we * are allowing a duplicate association. * I hope this works... */ - return (sctp_process_cookie_new(m, iphlen, offset, src, dst, - sh, cookie, cookie_len, - inp, netp, init_src,notification, - auth_skipped, auth_offset, auth_len, + local_stcb = sctp_process_cookie_new(m, iphlen, offset, src, dst, + sh, cookie, cookie_len, + inp, netp, init_src,notification, + auth_skipped, auth_offset, auth_len, #if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, + mflowtype, mflowid, #endif - vrf_id, port)); + vrf_id, port); + if (local_stcb == NULL) { + SCTP_TCB_UNLOCK(stcb); + } + return (local_stcb); } /* * case A in Section 5.2.4 Table 2: XXMM (peer restarted) @@ -2005,11 +1919,7 @@ 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_16); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); - + sctp_stop_association_timers(stcb, false); /* notify upper layer */ *notification = SCTP_NOTIFY_ASSOC_RESTART; atomic_add_int(&stcb->asoc.refcnt, 1); @@ -2025,8 +1935,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); } else if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) { /* move to OPEN state, if not in SHUTDOWN_SENT */ @@ -2042,6 +1950,10 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, asoc->str_reset_seq_in = asoc->init_seq_number; asoc->advanced_peer_ack_point = asoc->last_acked_seq; asoc->send_sack = 1; + asoc->data_pkts_seen = 0; + asoc->last_data_chunk_from = NULL; + asoc->last_control_chunk_from = NULL; + asoc->last_net_cmt_send_started = NULL; if (asoc->mapping_array) { memset(asoc->mapping_array, 0, asoc->mapping_array_size); @@ -2058,10 +1970,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_INP_INFO_WLOCK(); SCTP_INP_WLOCK(stcb->sctp_ep); SCTP_TCB_LOCK(stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); /* send up all the data */ - SCTP_TCB_SEND_LOCK(stcb); - 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; @@ -2074,9 +1984,9 @@ 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].sid = 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; } TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) { @@ -2106,6 +2016,9 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); SCTP_DECR_CHK_COUNT(); } + asoc->ctrl_queue_cnt = 0; + asoc->str_reset = NULL; + asoc->stream_reset_outstanding = 0; TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); if (chk->data) { @@ -2129,6 +2042,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), aack); } + asoc->rcv_edmid = cookie->rcv_edmid; /* process the INIT-ACK info (my info) */ asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); @@ -2145,7 +2059,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, */ LIST_INSERT_HEAD(head, stcb, sctp_asocs); - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_INP_WUNLOCK(stcb->sctp_ep); SCTP_INP_INFO_WUNLOCK(); #if defined(__APPLE__) && !defined(__Userspace__) @@ -2154,11 +2067,17 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, asoc->total_flight = 0; asoc->total_flight_count = 0; /* process the INIT info (peer's info) */ - retval = sctp_process_init(init_cp, stcb); - if (retval < 0) { + if (sctp_process_init(init_cp, stcb) < 0) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 13; - + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); + SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); + 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); return (NULL); } /* @@ -2167,26 +2086,38 @@ 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, stcb->asoc.port)) { + if ((retval = sctp_load_addresses_from_init(stcb, m, + init_offset + sizeof(struct sctp_init_chunk), + initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 14; - + op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), + "Problem with address parameters"); + SCTPDBG(SCTP_DEBUG_INPUT1, + "Load addresses from INIT causes an abort %d\n", + retval); + 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); return (NULL); } /* respond with a COOKIE-ACK */ - sctp_stop_all_cookie_timers(stcb); - sctp_toss_old_cookies(stcb, asoc); sctp_send_cookie_ack(stcb); if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 15; - + if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE) && + (asoc->sctp_autoclose_ticks > 0)) { + sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); + } return (stcb); } if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 16; /* all other cases... */ + SCTP_TCB_UNLOCK(stcb); return (NULL); } @@ -2215,7 +2146,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, union sctp_sockstore store; struct sctp_association *asoc; int init_offset, initack_offset, initack_limit; - int retval; int error = 0; uint8_t auth_chunk_buf[SCTP_CHUNK_BUFFER_SIZE]; #if defined(__APPLE__) && !defined(__Userspace__) @@ -2269,7 +2199,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, /* * now that we know the INIT/INIT-ACK are in place, create a new TCB - * and popluate + * and populate */ /* @@ -2279,7 +2209,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, * 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, + ntohl(initack_cp->init.initiate_tag), + ntohl(initack_cp->init.initial_tsn), vrf_id, ntohs(initack_cp->init.num_outbound_streams), port, #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -2348,20 +2279,12 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, #endif return (NULL); } + asoc->rcv_edmid = cookie->rcv_edmid; /* 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->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; /* process the INIT info (peer's info) */ - retval = sctp_process_init(init_cp, stcb); - if (retval < 0) { + if (sctp_process_init(init_cp, stcb) < 0) { #if defined(__APPLE__) && !defined(__Userspace__) atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(stcb); @@ -2378,8 +2301,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, } /* load all addresses */ if (sctp_load_addresses_from_init(stcb, m, - init_offset + sizeof(struct sctp_init_chunk), initack_offset, - src, dst, init_src, port)) { + init_offset + sizeof(struct sctp_init_chunk), + initack_offset, src, dst, init_src, port) < 0) { #if defined(__APPLE__) && !defined(__Userspace__) atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(stcb); @@ -2497,10 +2420,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, /* 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); @@ -2517,8 +2436,10 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, * INIT/INIT-ACK/COOKIE arrived. But of course then it * should have went to the other code.. not here.. oh well.. * a bit of protection is worth having.. + * + * XXXMJ unlocked */ - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; + sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_CONNECTED); #if defined(__APPLE__) && !defined(__Userspace__) atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(stcb); @@ -2550,17 +2471,11 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); *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); @@ -2585,7 +2500,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, SCTP_BASE_INFO(hashasocmark))]; LIST_FOREACH(stcb, head, sctp_asocs) { - if ((stcb->asoc.my_vtag == tag) && (stcb->rport == rport) && (inp == stcb->sctp_ep)) { + if ((stcb->asoc.my_vtag == tag) && (stcb->rport == rport) && (inp == stcb->sctp_ep)) { -- SEND ABORT - TRY AGAIN -- } } @@ -2706,17 +2621,24 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* * compute the signature/digest for the cookie */ - ep = &(*inp_p)->sctp_ep; - l_inp = *inp_p; - if (l_stcb) { + if (l_stcb != NULL) { + atomic_add_int(&l_stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(l_stcb); } + l_inp = *inp_p; SCTP_INP_RLOCK(l_inp); - if (l_stcb) { + if (l_stcb != NULL) { SCTP_TCB_LOCK(l_stcb); + atomic_subtract_int(&l_stcb->asoc.refcnt, 1); } + if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { + SCTP_INP_RUNLOCK(l_inp); + sctp_m_freem(m_sig); + return (NULL); + } + ep = &(*inp_p)->sctp_ep; /* which cookie is it? */ - if ((cookie->time_entered.tv_sec < (long)ep->time_of_secret_change) && + if ((cookie->time_entered.tv_sec < ep->time_of_secret_change) && (ep->current_secret_number != ep->last_secret_number)) { /* it's the old cookie */ (void)sctp_hmac_m(SCTP_HMAC, @@ -2739,7 +2661,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* compare the received digest with the computed digest */ 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) && + if ((cookie->time_entered.tv_sec == ep->time_of_secret_change) && (ep->current_secret_number != ep->last_secret_number)) { /* compute digest with old */ (void)sctp_hmac_m(SCTP_HMAC, @@ -2835,10 +2757,10 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, if ((uint32_t)diff.tv_sec > UINT32_MAX / 1000000) { staleness = UINT32_MAX; } else { - staleness = diff.tv_sec * 1000000; + staleness = (uint32_t)diff.tv_sec * 1000000; } if (UINT32_MAX - staleness >= (uint32_t)diff.tv_usec) { - staleness += diff.tv_usec; + staleness += (uint32_t)diff.tv_usec; } else { staleness = UINT32_MAX; } @@ -2956,12 +2878,15 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, had_a_existing_tcb = 1; *stcb = sctp_process_cookie_existing(m, iphlen, offset, src, dst, sh, - cookie, cookie_len, *inp_p, *stcb, netp, to, - ¬ification, auth_skipped, auth_offset, auth_len, + cookie, cookie_len, *inp_p, *stcb, netp, to, + ¬ification, auth_skipped, auth_offset, auth_len, #if defined(__FreeBSD__) && !defined(__Userspace__) mflowtype, mflowid, #endif vrf_id, port); + if (*stcb == NULL) { + *locked_tcb = NULL; + } } if (*stcb == NULL) { @@ -3104,7 +3029,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, 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; inp->recv_callback = (*inp_p)->recv_callback; @@ -3217,18 +3141,14 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, SCTP_FROM_SCTP_INPUT, __LINE__); } - asoc->overall_error_count = 0; sctp_stop_all_cookie_timers(stcb); + sctp_toss_old_cookies(stcb, asoc); /* process according to association state */ 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(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, NULL); - } /* update RTO */ SCTP_STAT_INCR_COUNTER32(sctps_activeestab); SCTP_STAT_INCR_GAUGE32(sctps_currestab); @@ -3236,6 +3156,12 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, SCTP_RTT_FROM_NON_DATA); } + /* + * Since we did not send a HB make sure we don't double + * things. + */ + asoc->overall_error_count = 0; + net->hb_responded = 1; (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) || @@ -3244,7 +3170,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, struct socket *so; #endif - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; + sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_CONNECTED); #if defined(__APPLE__) && !defined(__Userspace__) so = SCTP_INP_SO(stcb->sctp_ep); atomic_add_int(&stcb->asoc.refcnt, 1); @@ -3260,11 +3186,21 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, SCTP_SOCKET_UNLOCK(so, 1); #endif } - /* - * since we did not send a HB make sure we don't double - * things - */ - net->hb_responded = 1; + + if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && + TAILQ_EMPTY(&asoc->send_queue) && + TAILQ_EMPTY(&asoc->sent_queue) && + (asoc->stream_queue_cnt == 0)) { + SCTP_STAT_DECR_GAUGE32(sctps_currestab); + 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, NULL); + sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); + } if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { /* We don't need to do the asconf thing, @@ -3300,8 +3236,6 @@ 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); /* Restart the timer if we have pending data */ TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { if (chk->whoTo != NULL) { @@ -3326,10 +3260,6 @@ sctp_handle_ecn_echo(struct sctp_ecne_chunk *cp, unsigned int pkt_cnt; len = ntohs(cp->ch.chunk_length); - if ((len != sizeof(struct sctp_ecne_chunk)) && - (len != sizeof(struct old_sctp_ecne_chunk))) { - return; - } if (len == sizeof(struct old_sctp_ecne_chunk)) { /* Its the old format */ memcpy(&bkup, cp, sizeof(struct old_sctp_ecne_chunk)); @@ -3847,19 +3777,16 @@ sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chu int len, clen; asoc = &stcb->asoc; - if (TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { + chk = asoc->str_reset; + if (TAILQ_EMPTY(&asoc->control_send_queue) || + (chk == NULL)) { asoc->stream_reset_outstanding = 0; return (NULL); } - if (stcb->asoc.str_reset == NULL) { - asoc->stream_reset_outstanding = 0; - return (NULL); - } - chk = stcb->asoc.str_reset; if (chk->data == NULL) { return (NULL); } - if (bchk) { + if (bchk != NULL) { /* he wants a copy of the chk pointer */ *bchk = chk; } @@ -3985,23 +3912,19 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb, asoc->strmout[i].state = SCTP_STREAM_OPEN; } asoc->streamoutcnt += num_stream; - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_DENIED); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD, stcb, SCTP_STREAM_CHANGE_DENIED, NULL, SCTP_SO_NOT_LOCKED); } else { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_FAILED); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD, stcb, SCTP_STREAM_CHANGE_FAILED, NULL, SCTP_SO_NOT_LOCKED); } } else if (type == SCTP_STR_RESET_ADD_IN_STREAMS) { if (asoc->stream_reset_outstanding) asoc->stream_reset_outstanding--; if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_DENIED); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD, stcb, SCTP_STREAM_CHANGE_DENIED, NULL, SCTP_SO_NOT_LOCKED); } else if (action != SCTP_STREAM_RESET_RESULT_PERFORMED) { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_FAILED); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD, stcb, SCTP_STREAM_CHANGE_DENIED, NULL, SCTP_SO_NOT_LOCKED); } } else if (type == SCTP_STR_RESET_TSN_REQUEST) { /** @@ -4046,13 +3969,11 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb, sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL); sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL); - sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_TSN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), - SCTP_ASSOC_RESET_DENIED); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_TSN, stcb, SCTP_ASSOC_RESET_DENIED, NULL, SCTP_SO_NOT_LOCKED); } else { - sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), - SCTP_ASSOC_RESET_FAILED); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_TSN, stcb, SCTP_ASSOC_RESET_FAILED, NULL, SCTP_SO_NOT_LOCKED); } } /* get rid of the request and get the request flags */ @@ -4086,7 +4007,7 @@ sctp_handle_str_reset_request_in(struct sctp_tcb *stcb, seq = ntohl(req->request_seq); if (asoc->str_reset_seq_in == seq) { asoc->last_reset_action[1] = asoc->last_reset_action[0]; - if (!(asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ)) { + if ((asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ) == 0) { asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; } else if (trunc) { /* Can't do it, since they exceeded our buffer size */ @@ -4152,7 +4073,7 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb, seq = ntohl(req->request_seq); if (asoc->str_reset_seq_in == seq) { asoc->last_reset_action[1] = stcb->asoc.last_reset_action[0]; - if (!(asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { + if ((asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ) == 0) { asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; } else { fwdtsn.ch.chunk_length = htons(sizeof(struct sctp_forward_tsn_chunk)); @@ -4181,7 +4102,7 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb, sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL); sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL); asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - sctp_notify_stream_reset_tsn(stcb, asoc->sending_seq, (asoc->mapping_array_base_tsn + 1), 0); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_TSN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); } sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0], asoc->last_sending_seq[0], asoc->last_base_tsnsent[0]); @@ -4224,7 +4145,7 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb, /* move the reset action back one */ asoc->last_reset_action[1] = asoc->last_reset_action[0]; - if (!(asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ)) { + if ((asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ) == 0) { asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; } else if (trunc) { asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; @@ -4296,7 +4217,7 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch if (asoc->str_reset_seq_in == seq) { num_stream += stcb->asoc.streamincnt; stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0]; - if (!(asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { + if ((asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ) == 0) { asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; } else if ((num_stream > stcb->asoc.max_inbound_streams) || (num_stream > 0xffff)) { @@ -4347,7 +4268,7 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch /* update the size */ stcb->asoc.streamincnt = num_stream; stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0); + sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); } sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); asoc->str_reset_seq_in++; @@ -4387,7 +4308,7 @@ sctp_handle_str_reset_add_out_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk /* Now what would be the new total? */ if (asoc->str_reset_seq_in == seq) { stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0]; - if (!(asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { + if ((asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ) == 0) { asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; } else if (stcb->asoc.stream_reset_outstanding) { /* We must reject it we have something pending */ @@ -4603,7 +4524,7 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, * Handle a router or endpoints report of a packet loss, there are two ways * to handle this, either we get the whole packet and must disect it * ourselves (possibly with truncation and or corruption) or it is a summary - * from a middle box that did the disectting for us. + * from a middle box that did the disecting for us. */ static void sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp, @@ -4706,6 +4627,8 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp, SCTP_STAT_INCR(sctps_pdrpmbda); } } else { + desc.tsn_ifany = htonl(0); + memset(desc.data_bytes, 0, SCTP_NUM_DB_TO_VERIFY); if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) { SCTP_STAT_INCR(sctps_pdrpmbct); } @@ -4798,6 +4721,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, int ret; int abort_no_unlock = 0; int ecne_seen = 0; + int abort_flag; /* * How big should this be, and should it be alloc'd? Lets try the * d-mtu-ceiling for now (2k) and that should hopefully work ... @@ -4962,29 +4886,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, } return (NULL); } - } else if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { - if (vtag_in != asoc->my_vtag) { - /* - * this could be a stale SHUTDOWN-ACK or the - * peer never got the SHUTDOWN-COMPLETE and - * is still hung; we have started a new asoc - * but it won't complete until the shutdown - * is completed - */ - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - 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__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - return (NULL); - } } else { /* for all other chunks, vtag must match */ if (vtag_in != asoc->my_vtag) { @@ -5047,10 +4948,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, chunk_buf); if (ch == NULL) { *offset = length; - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return (NULL); + return (stcb); } num_chunks++; @@ -5084,34 +4982,36 @@ 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))) { - /* RFC 4960 requires that no ABORT is sent */ + /* + * RFC 4960bis requires stopping the + * processing of the packet. + */ + *offset = length; + return (stcb); + } + /* Honor our resource limit. */ + if (chk_length > SCTP_LARGEST_INIT_ACCEPTED) { + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); + sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err, +#if defined(__FreeBSD__) && !defined(__Userspace__) + mflowtype, mflowid, inp->fibnum, +#endif + vrf_id, port); *offset = length; if (stcb != NULL) { SCTP_TCB_UNLOCK(stcb); } return (NULL); } - /* Honor our resource limit. */ - if (chk_length > SCTP_LARGEST_INIT_ACCEPTED) { - 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__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - *offset = length; - return (NULL); - } sctp_handle_init(m, iphlen, *offset, src, dst, sh, (struct sctp_init_chunk *)ch, inp, - stcb, *netp, &abort_no_unlock, + stcb, *netp, #if defined(__FreeBSD__) && !defined(__Userspace__) mflowtype, mflowid, #endif vrf_id, port); *offset = length; - if ((!abort_no_unlock) && (stcb != NULL)) { + if (stcb != NULL) { SCTP_TCB_UNLOCK(stcb); } return (NULL); @@ -5296,20 +5196,19 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) { SCTP_STAT_INCR(sctps_recvheartbeat); sctp_send_heartbeat_ack(stcb, m, *offset, - chk_length, *netp); + chk_length, *netp); } break; case SCTP_HEARTBEAT_ACK: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT_ACK\n"); if ((stcb == NULL) || (chk_length != sizeof(struct sctp_heartbeat_chunk))) { /* Its not ours */ - *offset = length; - return (stcb); + break; } SCTP_STAT_INCR(sctps_recvheartbeatack); if ((netp != NULL) && (*netp != NULL)) { sctp_handle_heartbeat_ack((struct sctp_heartbeat_chunk *)ch, - stcb, *netp); + stcb, *netp); } break; case SCTP_ABORT_ASSOCIATION: @@ -5330,14 +5229,12 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN, stcb %p\n", (void *)stcb); if ((stcb == NULL) || (chk_length != sizeof(struct sctp_shutdown_chunk))) { - *offset = length; - return (stcb); + break; } if ((netp != NULL) && (*netp != NULL)) { - int abort_flag = 0; - + abort_flag = 0; sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch, - stcb, *netp, &abort_flag); + stcb, *netp, &abort_flag); if (abort_flag) { *offset = length; return (NULL); @@ -5346,11 +5243,12 @@ 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 != NULL) && (netp != NULL) && (*netp != NULL)) { + if ((chk_length == sizeof(struct sctp_shutdown_ack_chunk)) && + (stcb != NULL) && (netp != NULL) && (*netp != NULL)) { sctp_handle_shutdown_ack((struct sctp_shutdown_ack_chunk *)ch, stcb, *netp); + *offset = length; + return (NULL); } - *offset = length; - return (NULL); break; case SCTP_OPERATION_ERROR: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_OP_ERR\n"); @@ -5395,7 +5293,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, */ if ((stcb == NULL) && (!SCTP_IS_LISTENING(inp) || - (!(inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && + (((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) && #if defined(__FreeBSD__) && !defined(__Userspace__) inp->sctp_socket->sol_qlen >= inp->sctp_socket->sol_qlimit))) { #else @@ -5418,6 +5316,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, struct sctp_inpcb *linp; struct sctp_tmit_chunk *chk; + if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | + SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { + goto abend; + } + if (stcb) { linp = NULL; } else { @@ -5426,11 +5329,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, 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)) { - SCTP_ASOC_CREATE_UNLOCK(linp); - goto abend; - } } if (netp != NULL) { @@ -5494,7 +5392,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, case SCTP_COOKIE_ACK: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_COOKIE_ACK, stcb %p\n", (void *)stcb); if ((stcb == NULL) || chk_length != sizeof(struct sctp_cookie_ack_chunk)) { - return (stcb); + break; } if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ @@ -5524,26 +5422,30 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, break; case SCTP_ECN_ECHO: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_ECHO\n"); - if ((stcb == NULL) || (chk_length != sizeof(struct sctp_ecne_chunk))) { - /* Its not ours */ - *offset = length; - return (stcb); + if (stcb == NULL) { + break; } if (stcb->asoc.ecn_supported == 0) { goto unknown_chunk; } + if ((chk_length != sizeof(struct sctp_ecne_chunk)) && + (chk_length != sizeof(struct old_sctp_ecne_chunk))) { + break; + } 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"); - if ((stcb == NULL) || (chk_length != sizeof(struct sctp_cwr_chunk))) { - *offset = length; - return (stcb); + if (stcb == NULL) { + break; } if (stcb->asoc.ecn_supported == 0) { goto unknown_chunk; } + if (chk_length != sizeof(struct sctp_cwr_chunk)) { + break; + } sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb, *netp); break; case SCTP_SHUTDOWN_COMPLETE: @@ -5554,12 +5456,13 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, *offset = length; return (stcb); } - if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) { + if ((chk_length == sizeof(struct sctp_shutdown_complete_chunk)) && + (stcb != NULL) && (netp != NULL) && (*netp != NULL)) { sctp_handle_shutdown_complete((struct sctp_shutdown_complete_chunk *)ch, - stcb, *netp); + stcb, *netp); + *offset = length; + return (NULL); } - *offset = length; - return (NULL); break; case SCTP_ASCONF: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n"); @@ -5568,32 +5471,33 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, goto unknown_chunk; } sctp_handle_asconf(m, *offset, src, - (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0); + (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0); asconf_cnt++; } break; case SCTP_ASCONF_ACK: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF_ACK\n"); - if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) { - /* Its not ours */ - *offset = length; - return (stcb); + if (stcb == NULL) { + break; } - if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) { - if (stcb->asoc.asconf_supported == 0) { - goto unknown_chunk; - } + if (stcb->asoc.asconf_supported == 0) { + goto unknown_chunk; + } + if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) { + break; + } + if ((netp != NULL) && (*netp != 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__); + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); } stcb->asoc.overall_error_count = 0; sctp_handle_asconf_ack(m, *offset, - (struct sctp_asconf_ack_chunk *)ch, stcb, *netp, &abort_no_unlock); + (struct sctp_asconf_ack_chunk *)ch, stcb, *netp, &abort_no_unlock); if (abort_no_unlock) return (NULL); } @@ -5602,72 +5506,70 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, 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 */ - *offset = length; - return (stcb); + if (stcb == NULL) { + break; } - - if (stcb != NULL) { - int abort_flag = 0; - - if (stcb->asoc.prsctp_supported == 0) { - goto unknown_chunk; + if (stcb->asoc.prsctp_supported == 0) { + goto unknown_chunk; + } + if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) { + break; + } + 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"); } - 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 */ + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + sctp_abort_an_association(inp, stcb, op_err, false, 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(__Userspace__) - 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); + 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_INPUT + SCTP_LOC_31); + (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); + 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); - } + *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; + abort_flag = 0; + sctp_handle_forward_tsn(stcb, + (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset); + if (abort_flag) { + *offset = length; + return (NULL); } break; case SCTP_STREAM_RESET: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_STREAM_RESET\n"); - if ((stcb == NULL) || (chk_length < sizeof(struct sctp_stream_reset_tsn_req))) { - /* Its not ours */ - *offset = length; - return (stcb); + if (stcb == NULL) { + break; } if (stcb->asoc.reconfig_supported == 0) { goto unknown_chunk; } + if (chk_length < sizeof(struct sctp_stream_reset_tsn_req)) { + break; + } if (sctp_handle_stream_reset(stcb, m, *offset, ch)) { /* stop processing */ *offset = length; @@ -5676,20 +5578,19 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, break; case SCTP_PACKET_DROPPED: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_PACKET_DROPPED\n"); - /* re-get it all please */ - if (chk_length < sizeof(struct sctp_pktdrop_chunk)) { - /* Its not ours */ - *offset = length; - return (stcb); + if (stcb == NULL) { + break; } - - if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) { - if (stcb->asoc.pktdrop_supported == 0) { - goto unknown_chunk; - } + if (stcb->asoc.pktdrop_supported == 0) { + goto unknown_chunk; + } + if (chk_length < sizeof(struct sctp_pktdrop_chunk)) { + break; + } + if ((netp != NULL) && (*netp != NULL)) { sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch, - stcb, *netp, - min(chk_length, contiguous)); + stcb, *netp, + min(chk_length, contiguous)); } break; case SCTP_AUTHENTICATION: @@ -5702,21 +5603,21 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, auth_skipped = 1; } /* skip this chunk (temporarily) */ - goto next_chunk; + break; } if (stcb->asoc.auth_supported == 0) { goto unknown_chunk; } if ((chk_length < (sizeof(struct sctp_auth_chunk))) || (chk_length > (sizeof(struct sctp_auth_chunk) + - SCTP_AUTH_DIGEST_LEN_MAX))) { + SCTP_AUTH_DIGEST_LEN_MAX))) { /* Its not ours */ *offset = length; return (stcb); } if (got_auth == 1) { /* skip this chunk... it's already auth'd */ - goto next_chunk; + break; } got_auth = 1; if (sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch, m, *offset)) { @@ -5777,7 +5678,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, break; } ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_chunkhdr), chunk_buf); + sizeof(struct sctp_chunkhdr), chunk_buf); if (ch == NULL) { *offset = length; return (stcb); @@ -5804,78 +5705,141 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt #endif uint32_t vrf_id, uint16_t port) { - uint32_t high_tsn; - int fwd_tsn_seen = 0, data_processed = 0; - struct mbuf *m = *mm, *op_err; char msg[SCTP_DIAG_INFO_LEN]; - int un_sent; - int cnt_ctrl_ready = 0; + struct mbuf *m = *mm, *op_err; 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 + uint32_t high_tsn; + uint32_t cksum_in_hdr; + int un_sent; + int cnt_ctrl_ready = 0; + int fwd_tsn_seen = 0, data_processed = 0; + bool cksum_validated, stcb_looked_up; SCTP_STAT_INCR(sctps_recvdatagrams); #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xE0, 1); sctp_auditing(0, inp, stcb, net); #endif - if (compute_crc != 0) { - uint32_t check, calc_check; - check = sh->checksum; - sh->checksum = 0; - calc_check = sctp_calculate_cksum(m, iphlen); - sh->checksum = check; - if (calc_check != check) { - SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", - calc_check, check, (void *)m, length, iphlen); - stcb = sctp_findassociation_addr(m, offset, src, dst, - sh, ch, &inp, &net, vrf_id); -#if defined(INET) || defined(INET6) - if ((ch->chunk_type != SCTP_INITIATION) && - (net != NULL) && (net->port != port)) { - if (net->port == 0) { - /* UDP encapsulation turned on. */ - net->mtu -= sizeof(struct udphdr); - if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu); + stcb_looked_up = false; + if (compute_crc != 0) { + cksum_validated = false; + cksum_in_hdr = sh->checksum; + if (cksum_in_hdr != htonl(0)) { + uint32_t cksum_calculated; + +validate_cksum: + sh->checksum = 0; + cksum_calculated = sctp_calculate_cksum(m, iphlen); + sh->checksum = cksum_in_hdr; + if (cksum_calculated != cksum_in_hdr) { + if (stcb_looked_up) { + /* + * The packet has a zero checksum, which + * is not the correct CRC, no stcb has + * been found or an stcb has been found + * but an incorrect zero checksum is not + * acceptable. + */ + KASSERT(cksum_in_hdr == htonl(0), + ("cksum in header not zero: %x", + ntohl(cksum_in_hdr))); + if ((inp == NULL) && + (SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum) == 1)) { + /* + * This is an OOTB packet, + * depending on the sysctl + * variable, pretend that the + * checksum is acceptable, + * to allow an appropriate + * response (ABORT, for examlpe) + * to be sent. + */ + KASSERT(stcb == NULL, + ("stcb is %p", stcb)); + SCTP_STAT_INCR(sctps_recvzerocrc); + goto cksum_validated; } - } else if (port == 0) { - /* UDP encapsulation turned off. */ - net->mtu += sizeof(struct udphdr); - /* XXX Update smallest_mtu */ + } else { + stcb = sctp_findassociation_addr(m, offset, src, dst, + sh, ch, &inp, &net, vrf_id); + } + SCTPDBG(SCTP_DEBUG_INPUT1, "Bad cksum in SCTP packet:%x calculated:%x m:%p mlen:%d iphlen:%d\n", + ntohl(cksum_in_hdr), ntohl(cksum_calculated), (void *)m, length, iphlen); +#if defined(INET) || defined(INET6) + if ((ch->chunk_type != SCTP_INITIATION) && + (net != NULL) && (net->port != port)) { + if (net->port == 0) { + /* UDP encapsulation turned on. */ + net->mtu -= sizeof(struct udphdr); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu, true); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ + net->mtu += sizeof(struct udphdr); + /* XXX Update smallest_mtu */ + } + net->port = port; } - net->port = port; - } #endif #if defined(__FreeBSD__) && !defined(__Userspace__) - if (net != NULL) { - net->flowtype = mflowtype; - net->flowid = mflowid; - } - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); + 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); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); - } else if ((inp != NULL) && (stcb == NULL)) { - inp_decr = inp; + if ((inp != NULL) && (stcb != NULL)) { + if (stcb->asoc.pktdrop_supported) { + sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1); + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); + } + } else if ((inp != NULL) && (stcb == NULL)) { + inp_decr = inp; + } + SCTP_STAT_INCR(sctps_badsum); + SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); + goto out; + } else { + cksum_validated = true; } - SCTP_STAT_INCR(sctps_badsum); - SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); - goto out; + } + KASSERT(cksum_validated || cksum_in_hdr == htonl(0), + ("cksum 0x%08x not zero and not validated", ntohl(cksum_in_hdr))); + if (!cksum_validated) { + stcb = sctp_findassociation_addr(m, offset, src, dst, + sh, ch, &inp, &net, vrf_id); + stcb_looked_up = true; + if (stcb == NULL) { + goto validate_cksum; + } + if (stcb->asoc.rcv_edmid == SCTP_EDMID_NONE) { + goto validate_cksum; + } + KASSERT(stcb->asoc.rcv_edmid == SCTP_EDMID_LOWER_LAYER_DTLS, + ("Unexpected EDMID %u", stcb->asoc.rcv_edmid)); + SCTP_STAT_INCR(sctps_recvzerocrc); } } +cksum_validated: /* Destination port of 0 is illegal, based on RFC4960. */ - if (sh->dest_port == 0) { + if (sh->dest_port == htons(0)) { SCTP_STAT_INCR(sctps_hdrops); + if ((stcb == NULL) && (inp != NULL)) { + inp_decr = inp; + } goto out; } - stcb = sctp_findassociation_addr(m, offset, src, dst, - sh, ch, &inp, &net, vrf_id); + if (!stcb_looked_up) { + stcb = sctp_findassociation_addr(m, offset, src, dst, + sh, ch, &inp, &net, vrf_id); + } #if defined(INET) || defined(INET6) if ((ch->chunk_type != SCTP_INITIATION) && (net != NULL) && (net->port != port)) { @@ -5883,7 +5847,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt /* UDP encapsulation turned on. */ net->mtu -= sizeof(struct udphdr); if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu); + sctp_pathmtu_adjustment(stcb, net->mtu, true); } } else if (port == 0) { /* UDP encapsulation turned off. */ @@ -5900,16 +5864,15 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt } #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__) && !defined(__Userspace__) + SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) { goto out; } #endif if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { + SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks); sctp_send_shutdown_complete2(src, dst, sh, #if defined(__FreeBSD__) && !defined(__Userspace__) mflowtype, mflowid, fibnum, @@ -5918,6 +5881,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt goto out; } if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { + SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks); goto out; } if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) { @@ -5973,7 +5937,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt } #if defined(__Userspace__) if ((stcb != NULL) && - !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) && + ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && (stcb->sctp_socket != NULL)) { if (stcb->sctp_socket->so_head != NULL) { upcall_socket = stcb->sctp_socket->so_head; @@ -6007,7 +5971,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt /* UDP encapsulation turned on. */ net->mtu -= sizeof(struct udphdr); if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu); + sctp_pathmtu_adjustment(stcb, net->mtu, true); } } else if (port == 0) { /* UDP encapsulation turned off. */ @@ -6076,7 +6040,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt } #if defined(__Userspace__) if ((upcall_socket == NULL) && - !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) && + ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && (stcb->sctp_socket != NULL)) { if (stcb->sctp_socket->so_head != NULL) { upcall_socket = stcb->sctp_socket->so_head; @@ -6381,7 +6345,11 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) } ecn_bits = ip->ip_tos; #if defined(__FreeBSD__) && !defined(__Userspace__) - if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { + if (m->m_pkthdr.csum_flags & (CSUM_SCTP_VALID | CSUM_IP_SCTP)) { + /* + * Packet with CSUM_IP_SCTP were sent from local host using + * checksum offloading. Checksum not required. + */ SCTP_STAT_INCR(sctps_recvhwcrc); compute_crc = 0; } else { diff --git a/netwerk/sctp/src/netinet/sctp_input.h b/netwerk/sctp/src/netinet/sctp_input.h index 47ae2127be..acb2097316 100644 --- a/netwerk/sctp/src/netinet/sctp_input.h +++ b/netwerk/sctp/src/netinet/sctp_input.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_INPUT_H_ #define _NETINET_SCTP_INPUT_H_ diff --git a/netwerk/sctp/src/netinet/sctp_lock_userspace.h b/netwerk/sctp/src/netinet/sctp_lock_userspace.h index 0aed34770a..16c4a33979 100644 --- a/netwerk/sctp/src/netinet/sctp_lock_userspace.h +++ b/netwerk/sctp/src/netinet/sctp_lock_userspace.h @@ -33,11 +33,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - #ifndef _NETINET_SCTP_LOCK_EMPTY_H_ #define _NETINET_SCTP_LOCK_EMPTY_H_ @@ -63,6 +58,9 @@ __FBSDID("$FreeBSD$"); #define SCTP_INP_INFO_TRYLOCK() 1 #define SCTP_INP_INFO_RUNLOCK() #define SCTP_INP_INFO_WUNLOCK() +#define SCTP_INP_INFO_LOCK_ASSERT() +#define SCTP_INP_INFO_RLOCK_ASSERT() +#define SCTP_INP_INFO_WLOCK_ASSERT() #define SCTP_WQ_ADDR_INIT() #define SCTP_WQ_ADDR_DESTROY() @@ -89,10 +87,11 @@ __FBSDID("$FreeBSD$"); #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_INIT(_inp) +#define SCTP_INP_READ_LOCK_DESTROY(_inp) #define SCTP_INP_READ_LOCK(_inp) #define SCTP_INP_READ_UNLOCK(_inp) +#define SCTP_INP_READ_LOCK_ASSERT(_inp) #define SCTP_INP_LOCK_INIT(_inp) #define SCTP_ASOC_CREATE_LOCK_INIT(_inp) @@ -111,11 +110,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */ -#define SCTP_TCB_SEND_LOCK_INIT(_tcb) -#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) -#define SCTP_TCB_SEND_LOCK(_tcb) -#define SCTP_TCB_SEND_UNLOCK(_tcb) - #define SCTP_INP_INCR_REF(_inp) #define SCTP_INP_DECR_REF(_inp) diff --git a/netwerk/sctp/src/netinet/sctp_os.h b/netwerk/sctp/src/netinet/sctp_os.h index 0e03ce9e59..0a12db9bcb 100644 --- a/netwerk/sctp/src/netinet/sctp_os.h +++ b/netwerk/sctp/src/netinet/sctp_os.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_os.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_OS_H_ #define _NETINET_SCTP_OS_H_ diff --git a/netwerk/sctp/src/netinet/sctp_os_userspace.h b/netwerk/sctp/src/netinet/sctp_os_userspace.h index c055362fa5..fbafb4e74c 100644 --- a/netwerk/sctp/src/netinet/sctp_os_userspace.h +++ b/netwerk/sctp/src/netinet/sctp_os_userspace.h @@ -49,6 +49,7 @@ #include #include "user_environment.h" typedef CRITICAL_SECTION userland_mutex_t; +typedef CRITICAL_SECTION userland_rwlock_t; #if WINVER < 0x0600 enum { C_SIGNAL = 0, @@ -274,6 +275,12 @@ typedef char* caddr_t; #define SCTP_GET_IF_INDEX_FROM_ROUTE(ro) 1 /* compiles... TODO use routing socket to determine */ +#if defined(__APPLE__) && defined(__POWERPC__) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#endif + #define BIG_ENDIAN 1 #define LITTLE_ENDIAN 0 #ifdef WORDS_BIGENDIAN @@ -288,6 +295,7 @@ typedef char* caddr_t; #include #endif typedef pthread_mutex_t userland_mutex_t; +typedef pthread_rwlock_t userland_rwlock_t; typedef pthread_cond_t userland_cond_t; typedef pthread_t userland_thread_t; #endif @@ -517,8 +525,6 @@ struct sx {int dummy;}; #endif #if defined(__FreeBSD__) #include -#include -/* #include was a 0 byte file */ #include #endif #endif /* INET6 */ @@ -877,14 +883,12 @@ static inline void sctp_userspace_rtfree(sctp_rtentry_t *rt) /*************************/ /* MTU */ /*************************/ -int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af); +int sctp_userspace_get_mtu_from_ifn(uint32_t if_index); -#define SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index, af) sctp_userspace_get_mtu_from_ifn(ifn_index, af) +#define SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index) sctp_userspace_get_mtu_from_ifn(ifn_index) #define SCTP_GATHER_MTU_FROM_ROUTE(sctp_ifa, sa, rt) ((rt != NULL) ? rt->rt_rmx.rmx_mtu : 0) -#define SCTP_GATHER_MTU_FROM_INTFC(sctp_ifn) sctp_userspace_get_mtu_from_ifn(if_nametoindex(((struct ifaddrs *) (sctp_ifn))->ifa_name), AF_INET) - #define SCTP_SET_MTU_OF_ROUTE(sa, rt, mtu) do { \ if (rt != NULL) \ rt->rt_rmx.rmx_mtu = mtu; \ @@ -956,6 +960,16 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af); /* wakeup a socket */ #define SCTP_SOWAKEUP(so) wakeup(&(so)->so_timeo, so) +/* number of bytes ready to read */ +#define SCTP_SBAVAIL(sb) (sb)->sb_cc +#define SCTP_SB_INCR(sb, incr) \ +{ \ + atomic_add_int(&(sb)->sb_cc, incr); \ +} +#define SCTP_SB_DECR(sb, decr) \ +{ \ + SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, (int)(decr)); \ +} /* clear the socket buffer state */ #define SCTP_SB_CLEAR(sb) \ (sb).sb_cc = 0; \ @@ -1035,13 +1049,13 @@ extern void sctp_userspace_ip_output(int *result, struct mbuf *o_pak, sctp_route_t *ro, void *stcb, uint32_t vrf_id); -#define SCTP_IP_OUTPUT(result, o_pak, ro, stcb, vrf_id) sctp_userspace_ip_output(&result, o_pak, ro, stcb, vrf_id); +#define SCTP_IP_OUTPUT(result, o_pak, ro, inp, vrf_id) sctp_userspace_ip_output(&result, o_pak, ro, inp, vrf_id); #if defined(INET6) extern void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, struct route_in6 *ro, void *stcb, uint32_t vrf_id); -#define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, stcb, vrf_id) sctp_userspace_ip6_output(&result, o_pak, ro, stcb, vrf_id); +#define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, inp, vrf_id) sctp_userspace_ip6_output(&result, o_pak, ro, inp, vrf_id); #endif @@ -1133,6 +1147,13 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int a #define SCTP_IS_LISTENING(inp) ((inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) != 0) +static inline bool +in_broadcast(struct in_addr in) +{ + return (in.s_addr == htonl(INADDR_BROADCAST) || + in.s_addr == htonl(INADDR_ANY)); +} + #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); diff --git a/netwerk/sctp/src/netinet/sctp_output.c b/netwerk/sctp/src/netinet/sctp_output.c index 6a7dff99c2..16f9cbbf32 100644 --- a/netwerk/sctp/src/netinet/sctp_output.c +++ b/netwerk/sctp/src/netinet/sctp_output.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - #include #if defined(__FreeBSD__) && !defined(__Userspace__) #include @@ -79,6 +74,9 @@ __FBSDID("$FreeBSD$"); #if defined(__Userspace__) && defined(INET6) #include #endif +#if defined(_WIN32) && defined(__MINGW32__) +#include +#endif #if defined(__APPLE__) && !defined(__Userspace__) #if !(defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)) #define SCTP_MAX_LINKHDR 16 @@ -1939,7 +1937,7 @@ sctp_is_address_in_scope(struct sctp_ifa *ifa, /* ok to use deprecated addresses? */ sin6 = &ifa->address.sin6; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* skip unspecifed addresses */ + /* skip unspecified addresses */ return (0); } if ( /* (local_scope == 0) && */ @@ -2915,8 +2913,7 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, #ifdef INET6 if (stcb && fam == AF_INET6 && sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { - if (sctp_v6src_match_nexthop(&sifa->address.sin6, ro) - == 0) { + if (sctp_v6src_match_nexthop(&sifa->address.sin6, ro) == 0) { continue; } } @@ -3399,7 +3396,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp, * have the best source. * - If not we must rotate amongst the addresses. * - * Cavets and issues + * Caveats and issues * * Do we need to pay attention to scope. We can have a private address * or a global address we are sourcing or sending to. So if we draw @@ -3552,7 +3549,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp, return (answer); } -static int +static bool sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) { #if defined(_WIN32) @@ -3564,13 +3561,13 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) struct sctp_prinfo prinfo; struct sctp_authinfo authinfo; int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; - int found; + bool found; /* * Independent of how many mbufs, find the c_type inside the control * structure and copy out the data. */ - found = 0; + found = false; tot_len = SCTP_BUF_LEN(control); for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { rem_len = tot_len - off; @@ -3609,7 +3606,7 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) struct sctp_sndrcvinfo *sndrcvinfo; sndrcvinfo = (struct sctp_sndrcvinfo *)data; - if (found == 0) { + if (!found) { if (cpsize < sizeof(struct sctp_sndrcvinfo)) { return (found); } @@ -3650,7 +3647,7 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) default: return (found); } - found = 1; + found = true; } } } @@ -3736,9 +3733,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.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); stcb->asoc.strmout[i].chunks_on_queues = 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; @@ -3748,10 +3744,11 @@ 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].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.strmout[i].state = SCTP_STREAM_OPENING; - stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); } } break; @@ -3768,8 +3765,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er #endif sin.sin_port = stcb->rport; 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) || + if (in_broadcast(sin.sin_addr) || IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { *error = EINVAL; return (1); @@ -3802,8 +3798,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er #ifdef INET if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { in6_sin6_2_sin(&sin, &sin6); - if ((sin.sin_addr.s_addr == INADDR_ANY) || - (sin.sin_addr.s_addr == INADDR_BROADCAST) || + if (in_broadcast(sin.sin_addr) || IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { *error = EINVAL; return (1); @@ -4091,7 +4086,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #if defined(__FreeBSD__) && !defined(__Userspace__) uint8_t mflowtype, uint32_t mflowid, #endif -int so_locked) + bool use_zero_crc, + int so_locked) /* nofragment_flag to tell if IP_DF should be set (IPv4 only) */ { /** @@ -4222,7 +4218,7 @@ int so_locked) ip->ip_id = htons(SCTP_IP_ID(inp)++); #elif defined(__FreeBSD__) /* FreeBSD has a function for ip_id's */ - ip_fillid(ip); + ip_fillid(ip, V_ip_random_id); #elif defined(__APPLE__) #if RANDOM_IP_ID ip->ip_id = ip_randomid(); @@ -4391,8 +4387,12 @@ int so_locked) } SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { - sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); + if (use_zero_crc) { + SCTP_STAT_INCR(sctps_sendzerocrc); + } else { + sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); + } #if !defined(__Userspace__) #if defined(__FreeBSD__) if (V_udp_cksum) { @@ -4403,19 +4403,23 @@ int so_locked) #endif #endif } else { -#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); -#else - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && (stcb->asoc.scope.loopback_scope))) { - sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip)); - SCTP_STAT_INCR(sctps_sendswcrc); + if (use_zero_crc) { + SCTP_STAT_INCR(sctps_sendzerocrc); } else { +#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); - } +#else + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && (stcb->asoc.scope.loopback_scope))) { + sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip)); + SCTP_STAT_INCR(sctps_sendswcrc); + } else { + SCTP_STAT_INCR(sctps_sendhwcrc); + } #endif + } } #ifdef SCTP_PACKET_LOGGING if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) @@ -4431,7 +4435,7 @@ int so_locked) #if defined(__FreeBSD__) && !defined(__Userspace__) SCTP_PROBE5(send, NULL, stcb, ip, stcb, sctphdr); #endif - SCTP_IP_OUTPUT(ret, o_pak, ro, stcb, vrf_id); + SCTP_IP_OUTPUT(ret, o_pak, ro, inp, vrf_id); #if defined(__APPLE__) && !defined(__Userspace__) if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { atomic_add_int(&stcb->asoc.refcnt, 1); @@ -4481,10 +4485,10 @@ int so_locked) 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 ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { + sctp_pathmtu_adjustment(stcb, mtu, true); + } } } #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -4534,7 +4538,7 @@ int so_locked) * This means especially, that it is not set at the * SCTP layer. So use the value from the IP layer. */ -#if defined(__APPLE__) && !defined(__Userspace__) && (!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 inpcb *)inp)->inp_flow); @@ -4611,7 +4615,7 @@ int so_locked) * This means especially, that it is not set at the * SCTP layer. So use the value from the IP layer. */ -#if defined(__APPLE__) && !defined(__Userspace__) && (!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 inpcb *)inp)->inp_flow) >> 20) & 0xff; @@ -4899,9 +4903,9 @@ int so_locked) #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); + SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, &ifp, inp, vrf_id); #else - SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, NULL, stcb, vrf_id); + SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, NULL, inp, vrf_id); #endif #if defined(__APPLE__) && !defined(__Userspace__) if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { @@ -4971,24 +4975,22 @@ int so_locked) 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 ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { + sctp_pathmtu_adjustment(stcb, mtu, false); + } } } } #if !defined(__Userspace__) - else if (ifp) { + else if (ifp != NULL) { #if defined(_WIN32) #define ND_IFINFO(ifp) (ifp) #define linkmtu if_mtu #endif - if (ND_IFINFO(ifp)->linkmtu && + if ((ND_IFINFO(ifp)->linkmtu > 0) && (stcb->asoc.smallest_mtu > ND_IFINFO(ifp)->linkmtu)) { - sctp_mtu_size_reset(inp, - &stcb->asoc, - ND_IFINFO(ifp)->linkmtu); + sctp_pathmtu_adjustment(stcb, ND_IFINFO(ifp)->linkmtu, false); } } #endif @@ -5016,12 +5018,15 @@ int so_locked) SCTP_BUF_NEXT(newm) = m; m = newm; packet_length = sctp_calculate_len(m); + m->m_pkthdr.len = packet_length; sctphdr = mtod(m, struct sctphdr *); sctphdr->src_port = src_port; sctphdr->dest_port = dest_port; sctphdr->v_tag = v_tag; sctphdr->checksum = 0; - if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { + if (use_zero_crc) { + SCTP_STAT_INCR(sctps_sendzerocrc); + } else if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { sctphdr->checksum = sctp_calculate_cksum(m, 0); SCTP_STAT_INCR(sctps_sendswcrc); } else { @@ -5063,6 +5068,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked) struct sctp_init_chunk *init; struct sctp_supported_addr_param *sup_addr; struct sctp_adaptation_layer_indication *ali; + struct sctp_zero_checksum_acceptable *zero_chksum; struct sctp_supported_chunk_types_param *pr_supported; struct sctp_paramhdr *ph; int cnt_inits_to = 0; @@ -5162,6 +5168,16 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked) chunk_len += parameter_len; } + /* Zero checksum acceptable parameter */ + if (stcb->asoc.rcv_edmid != SCTP_EDMID_NONE) { + parameter_len = (uint16_t)sizeof(struct sctp_zero_checksum_acceptable); + zero_chksum = (struct sctp_zero_checksum_acceptable *)(mtod(m, caddr_t) + chunk_len); + zero_chksum->ph.param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE); + zero_chksum->ph.param_length = htons(parameter_len); + zero_chksum->edmid = htonl(stcb->asoc.rcv_edmid); + chunk_len += parameter_len; + } + /* Add NAT friendly parameter. */ if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); @@ -5337,7 +5353,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked) #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif - so_locked))) { + false, so_locked))) { SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error); if (error == ENOBUFS) { stcb->asoc.ifp_had_enobuf = 1; @@ -5355,7 +5371,8 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, int param_offset, int *abort_processing, struct sctp_chunkhdr *cp, int *nat_friendly, - int *cookie_found) + int *cookie_found, + uint32_t *edmid) { /* * Given a mbuf containing an INIT or INIT-ACK with the param_offset @@ -5371,8 +5388,8 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, * hoped that this routine may be reused in the future by new * features. */ + struct sctp_zero_checksum_acceptable zero_chksum, *zero_chksum_p; struct sctp_paramhdr *phdr, params; - struct mbuf *mat, *m_tmp, *op_err, *op_err_last; int at, limit, pad_needed; uint16_t ptype, plen, padded_size; @@ -5381,6 +5398,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, if (cookie_found != NULL) { *cookie_found = 0; } + if (edmid != NULL) { + *edmid = SCTP_EDMID_NONE; + } mat = in_initpkt; limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk); at = param_offset; @@ -5436,6 +5456,22 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, } at += padded_size; break; + case SCTP_ZERO_CHECKSUM_ACCEPTABLE: + if (padded_size != sizeof(struct sctp_zero_checksum_acceptable)) { + SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error checksum acceptable %d\n", plen); + goto invalid_size; + } + if (edmid != NULL) { + phdr = sctp_get_next_param(mat, at, + (struct sctp_paramhdr *)&zero_chksum, + sizeof(struct sctp_zero_checksum_acceptable)); + if (phdr != NULL) { + zero_chksum_p = (struct sctp_zero_checksum_acceptable *)phdr; + *edmid = ntohl(zero_chksum_p->edmid); + } + } + at += padded_size; + break; case SCTP_RANDOM: if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) { SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error random %d\n", plen); @@ -5476,11 +5512,16 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, at += padded_size; break; case SCTP_HAS_NAT_SUPPORT: + if (padded_size != sizeof(struct sctp_paramhdr)) { + SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error nat support %d\n", plen); + goto invalid_size; + } *nat_friendly = 1; - /* fall through */ + at += padded_size; + break; case SCTP_PRSCTP_SUPPORTED: if (padded_size != sizeof(struct sctp_paramhdr)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error prsctp/nat support %d\n", plen); + SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error prsctp %d\n", plen); goto invalid_size; } at += padded_size; @@ -5682,24 +5723,23 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, return (op_err); } -static int +/* + * Given a INIT chunk, look through the parameters to verify that there + * are no new addresses. + * Return true, if there is a new address or there is a problem parsing + the parameters. Provide an optional error cause used when sending an ABORT. + * Return false, if there are no new addresses and there is no problem in + parameter processing. + */ +static bool sctp_are_there_new_addresses(struct sctp_association *asoc, - struct mbuf *in_initpkt, int offset, struct sockaddr *src) + struct mbuf *in_initpkt, int offset, int limit, struct sockaddr *src, + struct mbuf **op_err) { - /* - * Given a INIT packet, look through the packet to verify that there - * are NO new addresses. As we go through the parameters add reports - * of any un-understood parameters that require an error. Also we - * must return (1) to drop the packet if we see a un-understood - * parameter that tells us to drop the chunk. - */ struct sockaddr *sa_touse; struct sockaddr *sa; struct sctp_paramhdr *phdr, params; - uint16_t ptype, plen; - uint8_t fnd; struct sctp_nets *net; - int check_src; #ifdef INET struct sockaddr_in sin4, *sa4; #endif @@ -5709,7 +5749,10 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, #if defined(__Userspace__) struct sockaddr_conn *sac; #endif + uint16_t ptype, plen; + bool fnd, check_src; + *op_err = NULL; #ifdef INET memset(&sin4, 0, sizeof(sin4)); sin4.sin_family = AF_INET; @@ -5725,26 +5768,26 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, #endif #endif /* First what about the src address of the pkt ? */ - check_src = 0; + check_src = false; switch (src->sa_family) { #ifdef INET case AF_INET: if (asoc->scope.ipv4_addr_legal) { - check_src = 1; + check_src = true; } break; #endif #ifdef INET6 case AF_INET6: if (asoc->scope.ipv6_addr_legal) { - check_src = 1; + check_src = true; } break; #endif #if defined(__Userspace__) case AF_CONN: if (asoc->scope.conn_addr_legal) { - check_src = 1; + check_src = true; } break; #endif @@ -5753,7 +5796,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, break; } if (check_src) { - fnd = 0; + fnd = false; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sa = (struct sockaddr *)&net->ro._l_addr; if (sa->sa_family == src->sa_family) { @@ -5764,7 +5807,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, sa4 = (struct sockaddr_in *)sa; src4 = (struct sockaddr_in *)src; if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) { - fnd = 1; + fnd = true; break; } } @@ -5776,7 +5819,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, sa6 = (struct sockaddr_in6 *)sa; src6 = (struct sockaddr_in6 *)src; if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) { - fnd = 1; + fnd = true; break; } } @@ -5788,16 +5831,22 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, sac = (struct sockaddr_conn *)sa; srcc = (struct sockaddr_conn *)src; if (sac->sconn_addr == srcc->sconn_addr) { - fnd = 1; + fnd = true; break; } } #endif } } - if (fnd == 0) { - /* New address added! no need to look further. */ - return (1); + if (!fnd) { + /* + * If sending an ABORT in case of an additional address, + * don't use 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"); + return (true); } } /* Ok so far lets munge through the rest of the packet */ @@ -5807,6 +5856,14 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, sa_touse = NULL; ptype = ntohs(phdr->param_type); plen = ntohs(phdr->param_length); + if (offset + plen > limit) { + *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Partial parameter"); + return (true); + } + if (plen < sizeof(struct sctp_paramhdr)) { + *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length too small"); + return (true); + } switch (ptype) { #ifdef INET case SCTP_IPV4_ADDRESS: @@ -5814,12 +5871,14 @@ 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); + *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length illegal"); + return (true); } phdr = sctp_get_next_param(in_initpkt, offset, (struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf)); if (phdr == NULL) { - return (1); + *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); + return (true); } if (asoc->scope.ipv4_addr_legal) { p4 = (struct sctp_ipv4addr_param *)phdr; @@ -5835,12 +5894,14 @@ 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); + *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length illegal"); + return (true); } phdr = sctp_get_next_param(in_initpkt, offset, (struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf)); if (phdr == NULL) { - return (1); + *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); + return (true); } if (asoc->scope.ipv6_addr_legal) { p6 = (struct sctp_ipv6addr_param *)phdr; @@ -5857,7 +5918,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, } if (sa_touse) { /* ok, sa_touse points to one to check */ - fnd = 0; + fnd = false; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sa = (struct sockaddr *)&net->ro._l_addr; if (sa->sa_family != sa_touse->sa_family) { @@ -5868,7 +5929,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, sa4 = (struct sockaddr_in *)sa; if (sa4->sin_addr.s_addr == sin4.sin_addr.s_addr) { - fnd = 1; + fnd = true; break; } } @@ -5878,21 +5939,31 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, sa6 = (struct sockaddr_in6 *)sa; if (SCTP6_ARE_ADDR_EQUAL( sa6, &sin6)) { - fnd = 1; + fnd = true; break; } } #endif } if (!fnd) { - /* New addr added! no need to look further */ - return (1); + /* + * If sending an ABORT in case of an additional + * address, don't use 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"); + return (true); } } offset += SCTP_SIZE32(plen); + if (offset >= limit) { + break; + } phdr = sctp_get_next_param(in_initpkt, offset, ¶ms, sizeof(params)); } - return (0); + return (false); } /* @@ -5908,7 +5979,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, struct sctp_init_chunk *init_chk, #if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, + uint8_t mflowtype, uint32_t mflowid, #endif uint32_t vrf_id, uint16_t port) { @@ -5916,6 +5987,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err; struct sctp_init_ack_chunk *initack; struct sctp_adaptation_layer_indication *ali; + struct sctp_zero_checksum_acceptable *zero_chksum; struct sctp_supported_chunk_types_param *pr_supported; struct sctp_paramhdr *ph; union sctp_sockstore *over_addr; @@ -5946,7 +6018,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int nat_friendly = 0; int error; struct socket *so; + uint32_t edmid; uint16_t num_ext, chunk_len, padding_len, parameter_len; + bool use_zero_crc; if (stcb) { asoc = &stcb->asoc; @@ -5955,16 +6029,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } if ((asoc != NULL) && (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT)) { - if (sctp_are_there_new_addresses(asoc, init_pkt, offset, src)) { + if (sctp_are_there_new_addresses(asoc, init_pkt, offset, offset + ntohs(init_chk->ch.chunk_length), src, &op_err)) { /* * 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, @@ -5996,7 +6064,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, (offset + sizeof(struct sctp_init_chunk)), &abort_flag, (struct sctp_chunkhdr *)init_chk, - &nat_friendly, NULL); + &nat_friendly, NULL, &edmid); if (abort_flag) { do_a_abort: if (op_err == NULL) { @@ -6105,7 +6173,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* scope_id is only for v6 */ stc.scope_id = 0; if ((IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) || - (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))){ + (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))) { stc.ipv4_scope = 1; } /* Must use the address in this case */ @@ -6309,6 +6377,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #endif } } + if (asoc != NULL) { + stc.rcv_edmid = asoc->rcv_edmid; + } else { + stc.rcv_edmid = inp->rcv_edmid; + } /* Now lets put the SCTP header in place */ initack = mtod(m, struct sctp_init_ack_chunk *); /* Save it off for quick ref */ @@ -6337,8 +6410,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, atomic_add_int(&asoc->refcnt, 1); SCTP_TCB_UNLOCK(stcb); new_tag: + SCTP_INP_INFO_RLOCK(); vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); - if ((asoc->peer_supports_nat) && (vtag == asoc->my_vtag)) { + SCTP_INP_INFO_RUNLOCK(); + if ((asoc->peer_supports_nat) && (vtag == asoc->my_vtag)) { /* Got a duplicate vtag on some guy behind a nat * make sure we don't use it. */ @@ -6349,11 +6424,13 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, itsn = sctp_select_initial_TSN(&inp->sctp_ep); initack->init.initial_tsn = htonl(itsn); SCTP_TCB_LOCK(stcb); - atomic_add_int(&asoc->refcnt, -1); + atomic_subtract_int(&asoc->refcnt, 1); } else { SCTP_INP_INCR_REF(inp); SCTP_INP_RUNLOCK(inp); + SCTP_INP_INFO_RLOCK(); vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); + SCTP_INP_INFO_RUNLOCK(); initack->init.initiate_tag = htonl(vtag); /* get a TSN to use too */ initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); @@ -6427,6 +6504,21 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, chunk_len += parameter_len; } + /* Zero checksum acceptable parameter */ + if (((asoc != NULL) && (asoc->rcv_edmid != SCTP_EDMID_NONE)) || + ((asoc == NULL) && (inp->rcv_edmid != SCTP_EDMID_NONE))) { + parameter_len = (uint16_t)sizeof(struct sctp_zero_checksum_acceptable); + zero_chksum = (struct sctp_zero_checksum_acceptable *)(mtod(m, caddr_t) + chunk_len); + zero_chksum->ph.param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE); + zero_chksum->ph.param_length = htons(parameter_len); + if (asoc != NULL) { + zero_chksum->edmid = htonl(asoc->rcv_edmid); + } else { + zero_chksum->edmid = htonl(inp->rcv_edmid); + } + chunk_len += parameter_len; + } + /* Add NAT friendly parameter */ if (nat_friendly) { parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); @@ -6652,6 +6744,12 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, over_addr = NULL; } + if (asoc != NULL) { + use_zero_crc = (asoc->rcv_edmid != SCTP_EDMID_NONE) && (asoc->rcv_edmid == edmid); + } else { + use_zero_crc = (inp->rcv_edmid != SCTP_EDMID_NONE) && (inp->rcv_edmid == edmid); + } + 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, @@ -6659,6 +6757,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #if defined(__FreeBSD__) && !defined(__Userspace__) mflowtype, mflowid, #endif + use_zero_crc, SCTP_SO_NOT_LOCKED))) { SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error); if (error == ENOBUFS) { @@ -6678,7 +6777,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, static void sctp_prune_prsctp(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_sndrcvinfo *srcv, + struct sctp_nonpad_sndrcvinfo *srcv, int dataout) { int freed_spc = 0; @@ -6756,51 +6855,57 @@ sctp_prune_prsctp(struct sctp_tcb *stcb, } /* if enabled in asoc */ } -int -sctp_get_frag_point(struct sctp_tcb *stcb, - struct sctp_association *asoc) +uint32_t +sctp_get_frag_point(struct sctp_tcb *stcb) { - int siz, ovh; + struct sctp_association *asoc; + uint32_t frag_point, overhead; - /* - * For endpoints that have both v6 and v4 addresses we must reserve - * room for the ipv6 header, for those that are only dealing with V4 - * we use a larger frag point. - */ + asoc = &stcb->asoc; + /* Consider IP header and SCTP common header. */ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MIN_OVERHEAD; + overhead = SCTP_MIN_OVERHEAD; } else { #if defined(__Userspace__) if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - ovh = sizeof(struct sctphdr); + overhead = sizeof(struct sctphdr); } else { - ovh = SCTP_MIN_V4_OVERHEAD; + overhead = SCTP_MIN_V4_OVERHEAD; } #else - ovh = SCTP_MIN_V4_OVERHEAD; + overhead = 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 - siz = (stcb->asoc.sctp_frag_point - ovh); - /* - * if (siz > (MCLBYTES-sizeof(struct sctp_data_chunk))) { - */ - /* A data chunk MUST fit in a cluster */ - /* siz = (MCLBYTES - sizeof(struct sctp_data_chunk)); */ - /* } */ - - /* adjust for an AUTH chunk if DATA requires auth */ - if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) - siz -= sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - - if (siz % 4) { - /* make it an even word boundary please */ - siz -= (siz % 4); + /* Consider DATA/IDATA chunk header and AUTH header, if needed. */ + if (asoc->idata_supported) { + overhead += sizeof(struct sctp_idata_chunk); + if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) { + overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); + } + } else { + overhead += sizeof(struct sctp_data_chunk); + if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) { + overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); + } } - return (siz); + KASSERT(overhead % 4 == 0, + ("overhead (%u) not a multiple of 4", overhead)); + /* Consider padding. */ + if (asoc->smallest_mtu % 4 > 0) { + overhead += (asoc->smallest_mtu % 4); + } + KASSERT(asoc->smallest_mtu > overhead, + ("Association MTU (%u) too small for overhead (%u)", + asoc->smallest_mtu, overhead)); + frag_point = asoc->smallest_mtu - overhead; + KASSERT(frag_point % 4 == 0, + ("frag_point (%u) not a multiple of 4", frag_point)); + /* Honor MAXSEG socket option. */ + if ((asoc->sctp_frag_point > 0) && + (asoc->sctp_frag_point < frag_point)) { + frag_point = asoc->sctp_frag_point; + } + return (frag_point); } static void @@ -6864,13 +6969,15 @@ static int sctp_msg_append(struct sctp_tcb *stcb, struct sctp_nets *net, struct mbuf *m, - struct sctp_sndrcvinfo *srcv, int hold_stcb_lock) + struct sctp_nonpad_sndrcvinfo *srcv) { int error = 0; struct mbuf *at; struct sctp_stream_queue_pending *sp = NULL; struct sctp_stream_out *strm; + SCTP_TCB_LOCK_ASSERT(stcb); + /* Given an mbuf chain, put it * into the association send queue and * place it on the wheel @@ -6887,15 +6994,26 @@ sctp_msg_append(struct sctp_tcb *stcb, error = EINVAL; goto out_now; } - strm = &stcb->asoc.strmout[srcv->sinfo_stream]; + if ((stcb->asoc.strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPEN) && + (stcb->asoc.strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPENING)) { + /* + * Can't queue any data while stream reset is underway. + */ + if (stcb->asoc.strmout[srcv->sinfo_stream].state > SCTP_STREAM_OPEN) { + error = EAGAIN; + } else { + error = EINVAL; + } + goto out_now; + } /* Now can we send this? */ 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); - error = ECONNRESET; + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EPIPE); + error = EPIPE; goto out_now; } sctp_alloc_a_strmoq(stcb, sp); @@ -6942,17 +7060,12 @@ sctp_msg_append(struct sctp_tcb *stcb, sctp_auth_key_acquire(stcb, sp->auth_keyid); sp->holds_key_ref = 1; } - if (hold_stcb_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + strm = &stcb->asoc.strmout[srcv->sinfo_stream]; sctp_snd_sb_alloc(stcb, sp->length); atomic_add_int(&stcb->asoc.stream_queue_cnt, 1); TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc, strm, sp, 1); + stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc, strm, sp); m = NULL; - if (hold_stcb_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } out_now: if (m) { sctp_m_freem(m); @@ -7115,7 +7228,8 @@ 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); + struct timeval *now, int *now_filled, + uint32_t frag_point, int so_locked); static void sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, @@ -7165,7 +7279,9 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, } else { m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); - SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr); + if (m != NULL) { + SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr); + } } if (m != NULL) { struct sctp_paramhdr *ph; @@ -7178,7 +7294,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, * dis-appearing on us. */ atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_abort_an_association(inp, stcb, m, SCTP_SO_NOT_LOCKED); + sctp_abort_an_association(inp, stcb, m, false, SCTP_SO_NOT_LOCKED); /* sctp_abort_an_association calls sctp_free_asoc() * free association will NOT free it since we * incremented the refcnt .. we do this to prevent @@ -7191,12 +7307,11 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, * must relock.. to unlock in the iterator timer :-0 */ SCTP_TCB_LOCK(stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); goto no_chunk_output; } else { - if (m) { - ret = sctp_msg_append(stcb, net, m, - &ca->sndrcv, 1); + if (m != NULL) { + ret = sctp_msg_append(stcb, net, m, &ca->sndrcv); } asoc = &stcb->asoc; if (ca->sndrcv.sinfo_flags & SCTP_EOF) { @@ -7219,7 +7334,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, sctp_stop_timers_for_shutdown(stcb); sctp_send_shutdown(stcb, net); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - net); + net); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL); added_control = 1; @@ -7256,12 +7371,10 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, msg); atomic_add_int(&stcb->asoc.refcnt, 1); sctp_abort_an_association(stcb->sctp_ep, stcb, - op_err, SCTP_SO_NOT_LOCKED); - atomic_add_int(&stcb->asoc.refcnt, -1); + op_err, false, SCTP_SO_NOT_LOCKED); + atomic_subtract_int(&stcb->asoc.refcnt, 1); goto no_chunk_output; } - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - NULL); } } } @@ -7277,13 +7390,13 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, if (do_chunk_output) sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED); else if (added_control) { - int num_out, reason, now_filled = 0; struct timeval now; - int frag_point; + int num_out, reason, now_filled = 0; - frag_point = sctp_get_frag_point(stcb, &stcb->asoc); (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_NOT_LOCKED); + &reason, 1, 1, &now, &now_filled, + sctp_get_frag_point(stcb), + SCTP_SO_NOT_LOCKED); } no_chunk_output: if (ret) { @@ -7311,7 +7424,9 @@ sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED) /* now free everything */ if (ca->inp) { /* Lets clear the flag to allow others to run. */ + SCTP_INP_WLOCK(ca->inp); ca->inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; + SCTP_INP_WUNLOCK(ca->inp); } sctp_m_freem(ca->m); SCTP_FREE(ca, SCTP_M_COPYAL); @@ -7361,24 +7476,30 @@ sctp_copy_out_all(struct uio *uio, ssize_t len) static int sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, - struct sctp_sndrcvinfo *srcv) + struct sctp_nonpad_sndrcvinfo *srcv) { - int ret; struct sctp_copy_all *ca; + struct mbuf *mat; + ssize_t sndlen; + int ret; - if (inp->sctp_flags & SCTP_PCB_FLAGS_SND_ITERATOR_UP) { - /* There is another. */ - return (EBUSY); - } + if (uio != NULL) { #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) - if (uio->uio_resid > SCTP_BASE_SYSCTL(sctp_sendall_limit)) { + sndlen = uio->uio_resid; #else - if (uio_resid(uio) > SCTP_BASE_SYSCTL(sctp_sendall_limit)) { + sndlen = uio_resid(uio); #endif #else - if (uio->uio_resid > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) { + sndlen = uio->uio_resid; #endif + } else { + sndlen = 0; + for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { + sndlen += SCTP_BUF_LEN(mat); + } + } + if (sndlen > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) { /* You must not be larger than the limit! */ return (EMSGSIZE); } @@ -7390,27 +7511,28 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, return (ENOMEM); } memset(ca, 0, sizeof(struct sctp_copy_all)); - ca->inp = inp; - if (srcv) { + if (srcv != NULL) { memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo)); } + /* Serialize. */ + SCTP_INP_WLOCK(inp); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SND_ITERATOR_UP) != 0) { + SCTP_INP_WUNLOCK(inp); + sctp_m_freem(m); + SCTP_FREE(ca, SCTP_M_COPYAL); + return (EBUSY); + } + inp->sctp_flags |= SCTP_PCB_FLAGS_SND_ITERATOR_UP; + SCTP_INP_WUNLOCK(inp); /* * take off the sendall flag, it would be bad if we failed to do * this :-0 */ ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL; /* get length and mbuf chain */ - if (uio) { -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - ca->sndlen = uio->uio_resid; -#else - ca->sndlen = uio_resid(uio); -#endif -#else - ca->sndlen = uio->uio_resid; -#endif + ca->sndlen = sndlen; + if (uio != NULL) { #if defined(__APPLE__) && !defined(__Userspace__) SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 0); #endif @@ -7420,26 +7542,25 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, #endif if (ca->m == NULL) { SCTP_FREE(ca, SCTP_M_COPYAL); + sctp_m_freem(m); + SCTP_INP_WLOCK(inp); + inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; + SCTP_INP_WUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } } else { - /* Gather the length of the send */ - struct mbuf *mat; - - ca->sndlen = 0; - for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { - ca->sndlen += SCTP_BUF_LEN(mat); - } + ca->m = m; } - 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_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES, + SCTP_ASOC_ANY_STATE, + (void *)ca, 0, + sctp_sendall_completes, inp, 1); + if (ret != 0) { + SCTP_INP_WLOCK(inp); inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; + SCTP_INP_WUNLOCK(inp); SCTP_FREE(ca, SCTP_M_COPYAL); SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); return (EFAULT); @@ -7511,7 +7632,7 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb, if (i > 0) { /* * Any chunk NOT 0 you zap the time chunk 0 gets - * zapped or set based on if a RTO measurment is + * zapped or set based on if a RTO measurement is * needed. */ data_list[i]->do_rtt = 0; @@ -7667,7 +7788,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, uint32_t length, } if ((length <= space_left) || ((length - space_left) < SCTP_BASE_SYSCTL(sctp_min_residual))) { - /* Sub-optimial residual don't split in non-eeor mode. */ + /* Sub-optimal residual don't split in non-eeor mode. */ return (0); } /* If we reach here length is larger @@ -7684,6 +7805,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, uint32_t length, static uint32_t sctp_move_to_outqueue(struct sctp_tcb *stcb, + struct sctp_nets *net, struct sctp_stream_out *strq, uint32_t space_left, uint32_t frag_point, @@ -7702,7 +7824,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, int leading; uint8_t rcv_flags = 0; uint8_t some_taken; - uint8_t send_lock_up = 0; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; @@ -7710,10 +7831,6 @@ one_more_time: /*sa_ignore FREED_MEMORY*/ sp = TAILQ_FIRST(&strq->outqueue); if (sp == NULL) { - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } sp = TAILQ_FIRST(&strq->outqueue); if (sp) { goto one_more_time; @@ -7727,10 +7844,6 @@ one_more_time: strq->last_msg_incomplete = 0; } to_move = 0; - if (send_lock_up) { - SCTP_TCB_SEND_UNLOCK(stcb); - send_lock_up = 0; - } goto out_of; } if ((sp->msg_is_complete) && (sp->length == 0)) { @@ -7741,20 +7854,15 @@ one_more_time: */ if ((sp->put_last_out == 0) && (sp->discard_rest == 0)) { SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n"); - SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n", + SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", sp->sender_all_done, sp->length, sp->msg_is_complete, - sp->put_last_out, - send_lock_up); - } - if ((TAILQ_NEXT(sp, next) == NULL) && (send_lock_up == 0)) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; + sp->put_last_out); } 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); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp); if ((strq->state == SCTP_STREAM_RESET_PENDING) && (strq->chunks_on_queues == 0) && TAILQ_EMPTY(&strq->outqueue)) { @@ -7769,11 +7877,6 @@ one_more_time: sp->data = NULL; } sctp_free_a_strmoq(stcb, sp, so_locked); - /* we can't be locked to it */ - if (send_lock_up) { - SCTP_TCB_SEND_UNLOCK(stcb); - send_lock_up = 0; - } /* back to get the next msg */ goto one_more_time; } else { @@ -7792,16 +7895,12 @@ one_more_time: to_move = 0; goto out_of; } else if (sp->discard_rest) { - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } /* Whack down the size */ atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length); 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); + SCTP_SB_DECR(&stcb->sctp_socket->so_snd, sp->length); } if (sp->data) { sctp_m_freem(sp->data); @@ -7816,7 +7915,6 @@ one_more_time: } } some_taken = sp->some_taken; -re_look: length = sp->length; if (sp->msg_is_complete) { /* The message is complete */ @@ -7841,28 +7939,9 @@ re_look: } } else { 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 - * is expanding during the compare. - */ - uint32_t llen; - - llen = length; - if (to_move >= llen) { - to_move = llen; - if (send_lock_up == 0) { - /*- - * We are taking all of an incomplete msg - * thus we need a send lock. - */ - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - if (sp->msg_is_complete) { - /* the sender finished the msg */ - goto re_look; - } - } + if (to_move > 0) { + if (to_move >= length) { + to_move = length; } if (sp->some_taken == 0) { rcv_flags |= SCTP_DATA_FIRST_FRAG; @@ -7900,10 +7979,6 @@ re_look: if (to_move >= length) { /* we think we can steal the whole thing */ - if ((sp->sender_all_done == 0) && (send_lock_up == 0)) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } if (to_move < sp->length) { /* bail, it changed */ goto dont_do_it; @@ -7934,7 +8009,7 @@ re_look: /* Now lets work our way down and compact it */ m = sp->data; while (m && (SCTP_BUF_LEN(m) == 0)) { - sp->data = SCTP_BUF_NEXT(m); + sp->data = SCTP_BUF_NEXT(m); SCTP_BUF_NEXT(m) = NULL; if (sp->tail_mbuf == m) { /*- @@ -7943,7 +8018,7 @@ re_look: * than the sp->length. */ #ifdef INVARIANTS - panic("Huh, freing tail? - TSNH"); + panic("Huh, freeing tail? - TSNH"); #else SCTP_PRINTF("Huh, freeing tail? - TSNH\n"); sp->tail_mbuf = sp->data = NULL; @@ -7995,10 +8070,6 @@ re_look: * all the data if there is no leading space, so we * must put the data back and restore. */ - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } if (sp->data == NULL) { /* unsteal the data */ sp->data = chk->data; @@ -8028,7 +8099,7 @@ re_look: if (chk->data == NULL) { /* HELP, TSNH since we assured it would not above? */ #ifdef INVARIANTS - panic("prepend failes HELP?"); + panic("prepend fails HELP?"); #else SCTP_PRINTF("prepend fails HELP?\n"); sctp_free_a_chunk(stcb, chk, so_locked); @@ -8088,6 +8159,7 @@ re_look: sctp_auth_key_acquire(stcb, chk->auth_keyid); chk->holds_key_ref = 1; } + stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, to_move); #if defined(__FreeBSD__) && !defined(__Userspace__) chk->rec.data.tsn = atomic_fetchadd_int(&asoc->sending_seq, 1); #else @@ -8109,8 +8181,8 @@ re_look: * earlier in previous loop prior to padding. */ -#ifdef SCTP_ASOCLOG_OF_TSNS SCTP_TCB_LOCK_ASSERT(stcb); +#ifdef SCTP_ASOCLOG_OF_TSNS if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) { asoc->tsn_out_at = 0; asoc->tsn_out_wrapped = 1; @@ -8168,20 +8240,15 @@ re_look: /* All done pull and kill the message */ 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", + SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", sp->sender_all_done, sp->length, sp->msg_is_complete, - sp->put_last_out, - send_lock_up); - } - if ((send_lock_up == 0) && (TAILQ_NEXT(sp, next) == NULL)) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; + sp->put_last_out); } 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); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp); if ((strq->state == SCTP_STREAM_RESET_PENDING) && (strq->chunks_on_queues == 0) && TAILQ_EMPTY(&strq->outqueue)) { @@ -8202,15 +8269,13 @@ re_look: TAILQ_INSERT_TAIL(&asoc->send_queue, chk, sctp_next); asoc->send_queue_cnt++; out_of: - if (send_lock_up) { - SCTP_TCB_SEND_UNLOCK(stcb); - } 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) +sctp_fill_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, + uint32_t frag_point, int eeor_mode, int *quit_now, + int so_locked) { struct sctp_association *asoc; struct sctp_stream_out *strq; @@ -8250,9 +8315,9 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, 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); + moved = sctp_move_to_outqueue(stcb, net, strq, space_left, + frag_point, &giveup, eeor_mode, + &bail, so_locked); if ((giveup != 0) || (bail != 0)) { break; } @@ -8329,12 +8394,13 @@ sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net) int sctp_med_chunk_output(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_association *asoc, - int *num_out, - int *reason_code, - int control_only, int from_where, - struct timeval *now, int *now_filled, int frag_point, int so_locked) + struct sctp_tcb *stcb, + struct sctp_association *asoc, + int *num_out, + int *reason_code, + int control_only, int from_where, + struct timeval *now, int *now_filled, + uint32_t frag_point, int so_locked) { /** * Ok this is the generic chunk service queue. we must do the @@ -8342,10 +8408,10 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, * - 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 + * only applies 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 + * formulate 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; @@ -8370,6 +8436,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, /* JRS 5/14/07 - Add flag for whether a heartbeat is sent to the destination. */ int quit_now = 0; + bool use_zero_crc; #if defined(__APPLE__) && !defined(__Userspace__) if (so_locked) { @@ -8473,11 +8540,11 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, net->window_probe = 0; if ((net != stcb->asoc.alternate) && ((net->dest_state & SCTP_ADDR_PF) || - (!(net->dest_state & SCTP_ADDR_REACHABLE)) || + ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) || (net->dest_state & SCTP_ADDR_UNCONFIRMED))) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { sctp_log_cwnd(stcb, net, 1, - SCTP_CWND_LOG_FILL_OUTQ_CALLED); + SCTP_CWND_LOG_FILL_OUTQ_CALLED); } continue; } @@ -8489,7 +8556,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, /* skip this network, no room - can't fill */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { sctp_log_cwnd(stcb, net, 3, - SCTP_CWND_LOG_FILL_OUTQ_CALLED); + SCTP_CWND_LOG_FILL_OUTQ_CALLED); } continue; } @@ -8545,7 +8612,7 @@ again_one_more_time: /* how much can we send? */ /* SCTPDBG("Examine for sending net:%x\n", (uint32_t)net); */ if (old_start_at && (old_start_at == net)) { - /* through list ocmpletely. */ + /* through list completely. */ break; } tsns_sent = 0xa; @@ -8746,7 +8813,7 @@ again_one_more_time: #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif - so_locked))) { + false, so_locked))) { /* error, we could not output */ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (from_where == 0) { @@ -8765,6 +8832,7 @@ again_one_more_time: */ sctp_move_chunks_from_net(stcb, net); } + asconf = 0; *reason_code = 7; break; } else { @@ -8778,6 +8846,7 @@ again_one_more_time: outchain = endoutchain = NULL; auth = NULL; auth_offset = 0; + asconf = 0; if (!no_out_cnt) *num_out += ctl_cnt; /* recalc a clean slate and setup */ @@ -8983,8 +9052,17 @@ again_one_more_time: * flight size since this little guy * is a control only packet. */ + switch (asoc->snd_edmid) { + case SCTP_EDMID_LOWER_LAYER_DTLS: + use_zero_crc = true; + break; + default: + use_zero_crc = false; + break; + } if (asconf) { sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net); + use_zero_crc = false; /* * do NOT clear the asconf * flag as it is used to do @@ -8994,6 +9072,7 @@ again_one_more_time: } if (cookie) { sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); + use_zero_crc = false; cookie = 0; } /* Only HB or ASCONF advances time */ @@ -9017,7 +9096,7 @@ again_one_more_time: #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif - so_locked))) { + use_zero_crc, so_locked))) { /* error, we could not output */ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (from_where == 0) { @@ -9035,6 +9114,7 @@ again_one_more_time: */ sctp_move_chunks_from_net(stcb, net); } + asconf = 0; *reason_code = 7; break; } else { @@ -9048,6 +9128,7 @@ again_one_more_time: outchain = endoutchain = NULL; auth = NULL; auth_offset = 0; + asconf = 0; if (!no_out_cnt) *num_out += ctl_cnt; /* recalc a clean slate and setup */ @@ -9249,7 +9330,7 @@ again_one_more_time: SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } - /* upate our MTU size */ + /* update our MTU size */ /* Do clear IP_DF ? */ if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { no_fragmentflg = 0; @@ -9312,10 +9393,19 @@ again_one_more_time: no_data_fill: /* Is there something to send for this destination? */ if (outchain) { + switch (asoc->snd_edmid) { + case SCTP_EDMID_LOWER_LAYER_DTLS: + use_zero_crc = true; + break; + default: + use_zero_crc = false; + break; + } /* We may need to start a control timer or two */ if (asconf) { sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net); + use_zero_crc = false; /* * do NOT clear the asconf flag as it is used * to do appropriate source address selection. @@ -9323,6 +9413,7 @@ again_one_more_time: } if (cookie) { sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); + use_zero_crc = false; cookie = 0; } /* must start a send timer if data is being sent */ @@ -9359,6 +9450,7 @@ again_one_more_time: #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif + use_zero_crc, so_locked))) { /* error, we could not output */ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); @@ -9376,6 +9468,7 @@ again_one_more_time: */ sctp_move_chunks_from_net(stcb, net); } + asconf = 0; *reason_code = 6; /*- * I add this line to be paranoid. As far as @@ -9391,6 +9484,7 @@ again_one_more_time: endoutchain = NULL; auth = NULL; auth_offset = 0; + asconf = 0; if (!no_out_cnt) { *num_out += (ctl_cnt + bundle_at); } @@ -9970,7 +10064,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, struct mbuf *m, *endofchain; struct sctp_nets *net = NULL; uint32_t tsns_sent = 0; - int no_fragmentflg, bundle_at, cnt_thru; + int no_fragmentflg, bundle_at; unsigned int mtu; int error, i, one_chunk, fwd_tsn, ctl_cnt, tmr_started; struct sctp_auth_chunk *auth = NULL; @@ -9979,6 +10073,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, int override_ok = 1; int data_auth_reqd = 0; uint32_t dmtu = 0; + bool use_zero_crc; #if defined(__APPLE__) && !defined(__Userspace__) if (so_locked) { @@ -10046,14 +10141,25 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, } } one_chunk = 0; - cnt_thru = 0; /* do we have control chunks to retransmit? */ if (m != NULL) { /* Start a timer no matter if we succeed or fail */ + switch (asoc->snd_edmid) { + case SCTP_EDMID_LOWER_LAYER_DTLS: + use_zero_crc = true; + break; + default: + use_zero_crc = false; + break; + } 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) + use_zero_crc = false; + } else if (chk->rec.chunk_id.id == SCTP_ASCONF) { + /* XXXMT: Can this happen? */ sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo); + use_zero_crc = false; + } chk->snd_count++; /* update our count */ if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo, (struct sockaddr *)&chk->whoTo->ro._l_addr, m, @@ -10064,6 +10170,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif + use_zero_crc, so_locked))) { SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (error == ENOBUFS) { @@ -10130,7 +10237,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, msg); atomic_add_int(&stcb->asoc.refcnt, 1); sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, - so_locked); + false, so_locked); SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); return (SCTP_RETRAN_EXIT); @@ -10249,7 +10356,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { no_fragmentflg = 0; } - /* upate our MTU size */ + /* update our MTU size */ if (mtu > (chk->send_size + dmtu)) mtu -= (chk->send_size + dmtu); else @@ -10306,7 +10413,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, if (fwd->flags & CHUNK_FLAGS_FRAGMENT_OK) { no_fragmentflg = 0; } - /* upate our MTU size */ + /* update our MTU size */ if (mtu > (fwd->send_size + dmtu)) mtu -= (fwd->send_size + dmtu); else @@ -10335,6 +10442,14 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); tmr_started = 1; } + switch (asoc->snd_edmid) { + case SCTP_EDMID_LOWER_LAYER_DTLS: + use_zero_crc = true; + break; + default: + use_zero_crc = false; + break; + } /* Now lets send it, if there is anything to send :> */ if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, m, @@ -10345,6 +10460,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif + use_zero_crc, so_locked))) { /* error, we could not output */ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); @@ -10368,7 +10484,6 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, /* (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time); */ /* For auto-close */ - cnt_thru++; if (*now_filled == 0) { (void)SCTP_GETTIME_TIMEVAL(&asoc->time_last_sent); *now = asoc->time_last_sent; @@ -10411,7 +10526,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, * also double the output queue size, since this * get shrunk when we free by this amount. */ - atomic_add_int(&((asoc)->total_output_queue_size),data_list[i]->book_size); + 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) { @@ -10521,7 +10636,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, * 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 + * go ahead and formulate and send the low level chunks. Making sure * to combine any control in the control chunk queue also. */ struct sctp_association *asoc; @@ -10531,7 +10646,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, struct timeval now; int now_filled = 0; int nagle_on; - int frag_point = sctp_get_frag_point(stcb, &stcb->asoc); + uint32_t frag_point = sctp_get_frag_point(stcb); int un_sent = 0; int fr_done; unsigned int tot_frs = 0; @@ -10582,13 +10697,13 @@ do_it_again: */ if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { /*- - * Special hook for handling cookiess discarded + * Special hook for handling cookies discarded * by peer that carried data. Send cookie-ack only * and then the next call with get the retran's. */ (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, - from_where, - &now, &now_filled, frag_point, so_locked); + from_where, + &now, &now_filled, frag_point, so_locked); return; } else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) { /* if its not from a HB then do it */ @@ -10612,8 +10727,8 @@ do_it_again: * if queued too. */ (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, - from_where, - &now, &now_filled, frag_point, so_locked); + from_where, + &now, &now_filled, frag_point, so_locked); #ifdef SCTP_AUDITING_ENABLED sctp_auditing(8, inp, stcb, NULL); #endif @@ -10640,7 +10755,7 @@ do_it_again: #endif /* Push out any control */ (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, from_where, - &now, &now_filled, frag_point, so_locked); + &now, &now_filled, frag_point, so_locked); return; } if ((asoc->fr_max_burst > 0) && (tot_frs >= asoc->fr_max_burst)) { @@ -10657,7 +10772,7 @@ do_it_again: #endif /* Check for bad destinations, if they exist move chunks around. */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { /*- * if possible move things off of this address we * still may send below due to the dormant state but @@ -10696,8 +10811,8 @@ do_it_again: burst_cnt = 0; do { error = sctp_med_chunk_output(inp, stcb, asoc, &num_out, - &reason_code, 0, from_where, - &now, &now_filled, frag_point, so_locked); + &reason_code, 0, from_where, + &now, &now_filled, frag_point, so_locked); if (error) { SCTPDBG(SCTP_DEBUG_OUTPUT1, "Error %d was returned from med-c-op\n", error); if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { @@ -10774,7 +10889,7 @@ do_it_again: sctp_fix_ecn_echo(asoc); if (stcb->asoc.trigger_reset) { - if (sctp_send_stream_reset_out_if_possible(stcb, so_locked) == 0) { + if (sctp_send_stream_reset_out_if_possible(stcb, so_locked) == 0) { goto do_it_again; } } @@ -10998,7 +11113,7 @@ sctp_fill_in_rest: /*- * 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 + * inefficient 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 @@ -11127,7 +11242,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked) a_chk->sent = SCTP_DATAGRAM_UNSENT; a_chk->whoTo = NULL; - if (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE)) { + if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) == 0) { /*- * Ok, the destination for the SACK is unreachable, lets see if * we can select an alternate to asoc->last_data_chunk_from @@ -11441,6 +11556,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked) uint32_t auth_offset = 0; int error; uint16_t cause_len, chunk_len, padding_len; + bool use_zero_crc; #if defined(__APPLE__) && !defined(__Userspace__) if (so_locked) { @@ -11462,6 +11578,14 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked) } else { m_out = NULL; } + switch (stcb->asoc.snd_edmid) { + case SCTP_EDMID_LOWER_LAYER_DTLS: + use_zero_crc = true; + break; + default: + use_zero_crc = false; + break; + } m_abort = sctp_get_mbuf_for_msg(sizeof(struct sctp_abort_chunk), 0, M_NOWAIT, 1, MT_HEADER); if (m_abort == NULL) { if (m_out) { @@ -11526,6 +11650,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked) #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif + use_zero_crc, so_locked))) { SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (error == ENOBUFS) { @@ -11549,6 +11674,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb, uint32_t vtag; int error; uint8_t flags; + bool use_zero_crc; m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER); if (m_shutdown_comp == NULL) { @@ -11562,6 +11688,14 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb, flags = 0; vtag = stcb->asoc.peer_vtag; } + switch (stcb->asoc.snd_edmid) { + case SCTP_EDMID_LOWER_LAYER_DTLS: + use_zero_crc = true; + break; + default: + use_zero_crc = false; + break; + } shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *); shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; shutdown_complete->ch.chunk_flags = flags; @@ -11576,6 +11710,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb, #if defined(__FreeBSD__) && !defined(__Userspace__) 0, 0, #endif + use_zero_crc, SCTP_SO_NOT_LOCKED))) { SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (error == ENOBUFS) { @@ -11724,7 +11859,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, #if defined(__Userspace__) ip->ip_id = htons(ip_id++); #elif defined(__FreeBSD__) - ip_fillid(ip); + ip_fillid(ip, V_ip_random_id); #elif defined(__APPLE__) #if RANDOM_IP_ID ip->ip_id = ip_randomid(); @@ -11939,7 +12074,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, sconn = (struct sockaddr_conn *)src; if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { - shout->checksum = sctp_calculate_cksum(mout, 0); + shout->checksum = sctp_calculate_cksum(o_pak, 0); SCTP_STAT_INCR(sctps_sendswcrc); } else { SCTP_STAT_INCR(sctps_sendhwcrc); @@ -11951,13 +12086,13 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, #endif /* Don't alloc/free for each packet */ if ((buffer = malloc(len)) != NULL) { - m_copydata(mout, 0, len, buffer); + m_copydata(o_pak, 0, len, buffer); ret = SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, len, 0, 0); free(buffer); } else { ret = ENOMEM; } - sctp_m_freem(mout); + sctp_m_freem(o_pak); break; } #endif @@ -12334,7 +12469,7 @@ jump_out: drp->current_onq = htonl(asoc->size_on_reasm_queue + asoc->size_on_all_streams + asoc->my_rwnd_control_len + - stcb->sctp_socket->so_rcv.sb_cc); + SCTP_SBAVAIL(&stcb->sctp_socket->so_rcv)); } else { /*- * If my rwnd is 0, possibly from mbuf depletion as well as @@ -12385,7 +12520,7 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u chk->rec.chunk_id.id = SCTP_ECN_CWR; chk->rec.chunk_id.can_take_data = 1; chk->flags = 0; - chk->asoc = &stcb->asoc; + chk->asoc = asoc; chk->send_size = sizeof(struct sctp_cwr_chunk); chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); if (chk->data == NULL) { @@ -12403,7 +12538,7 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u cwr->ch.chunk_flags = override; cwr->ch.chunk_length = htons(sizeof(struct sctp_cwr_chunk)); cwr->tsn = htonl(high_tsn); - TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); + TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); asoc->ctrl_queue_cnt++; } @@ -12824,6 +12959,8 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, int can_send_out_req=0; uint32_t seq; + SCTP_TCB_LOCK_ASSERT(stcb); + asoc = &stcb->asoc; if (asoc->stream_reset_outstanding) { /*- @@ -12892,7 +13029,8 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, seq = stcb->asoc.str_reset_seq_out; 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)); + + 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++; @@ -12924,19 +13062,27 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, /* Ok now we proceed with copying the old out stuff and * initializing the new stuff. */ - SCTP_TCB_SEND_LOCK(stcb); - stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1); + stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, false); for (i = 0; i < stcb->asoc.streamoutcnt; i++) { TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); + /* 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]); stcb->asoc.strmout[i].chunks_on_queues = oldstream[i].chunks_on_queues; +#if defined(SCTP_DETAILED_STR_STATS) + for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { + stcb->asoc.strmout[i].abandoned_sent[j] = oldstream[i].abandoned_sent[j]; + stcb->asoc.strmout[i].abandoned_unsent[j] = oldstream[i].abandoned_unsent[j]; + } +#else + stcb->asoc.strmout[i].abandoned_sent[0] = oldstream[i].abandoned_sent[0]; + stcb->asoc.strmout[i].abandoned_unsent[0] = oldstream[i].abandoned_unsent[0]; +#endif 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].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); @@ -12944,7 +13090,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, } } /* now the new streams */ - stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); + stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + adding_o); i++) { TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); stcb->asoc.strmout[i].chunks_on_queues = 0; @@ -12966,7 +13112,6 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, } stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o; SCTP_FREE(oldstream, SCTP_M_STRMO); - SCTP_TCB_SEND_UNLOCK(stcb); } skip_stuff: if ((add_stream & 1) && (adding_o > 0)) { @@ -13057,8 +13202,9 @@ sctp_copy_resume(struct uio *uio, m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0, (M_PKTHDR | (user_marks_eor ? M_EOR : 0))); if (m == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - *error = ENOBUFS; + /* The only possible error is EFAULT. */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); + *error = EFAULT; } else { *sndout = m_length(m, NULL); *new_tail = m_last(m); @@ -13087,7 +13233,7 @@ sctp_copy_resume(struct uio *uio, cancpy = (int)M_TRAILINGSPACE(head); willcpy = min(cancpy, left); *error = uiomove(mtod(head, caddr_t), willcpy, uio); - if (*error) { + if (*error != 0) { sctp_m_freem(head); return (NULL); } @@ -13110,11 +13256,10 @@ sctp_copy_resume(struct uio *uio, cancpy = (int)M_TRAILINGSPACE(m); willcpy = min(cancpy, left); *error = uiomove(mtod(m, caddr_t), willcpy, uio); - if (*error) { + if (*error != 0) { sctp_m_freem(head); *new_tail = NULL; - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); - *error = EFAULT; + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, *error); return (NULL); } SCTP_BUF_LEN(m) = willcpy; @@ -13135,13 +13280,12 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, int resv_upfront) { #if defined(__FreeBSD__) || defined(__Userspace__) - sp->data = m_uiotombuf(uio, M_WAITOK, sp->length, - resv_upfront, 0); + 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); + /* The only possible error is EFAULT. */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); + return (EFAULT); } - sp->tail_mbuf = m_last(sp->data); return (0); #else @@ -13202,7 +13346,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, static struct sctp_stream_queue_pending * sctp_copy_it_in(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_sndrcvinfo *srcv, + struct sctp_nonpad_sndrcvinfo *srcv, struct uio *uio, struct sctp_nets *net, ssize_t max_send_len, @@ -13217,20 +13361,10 @@ sctp_copy_it_in(struct sctp_tcb *stcb, * sb is locked however. When data is copied the protocol processing * should be enabled since this is a slower operation... */ - struct sctp_stream_queue_pending *sp = NULL; + struct sctp_stream_queue_pending *sp; int resv_in_first; *error = 0; - /* Now can we send this? */ - 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); - *error = ECONNRESET; - goto out_now; - } sctp_alloc_a_strmoq(stcb, sp); if (sp == NULL) { SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); @@ -13245,7 +13379,6 @@ sctp_copy_it_in(struct sctp_tcb *stcb, sp->context = srcv->sinfo_context; sp->fsn = 0; (void)SCTP_GETTIME_TIMEVAL(&sp->ts); - sp->sid = srcv->sinfo_stream; #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) @@ -13326,13 +13459,13 @@ sctp_sosend(struct socket *so, struct mbuf *top, struct mbuf *control, #if defined(__APPLE__) && !defined(__Userspace__) - int flags + int flags) #else int flags, #if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p + struct thread *p) #elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p + PKTHREAD p) #else #if defined(__Userspace__) /* @@ -13340,52 +13473,59 @@ sctp_sosend(struct socket *so, * to sctp_lower_sosend */ #endif - struct proc *p + struct proc *p) #endif #endif -) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct proc *p = current_proc(); -#endif - int error, use_sndinfo = 0; struct sctp_sndrcvinfo sndrcvninfo; - struct sockaddr *addr_to_use; #if defined(INET) && defined(INET6) struct sockaddr_in sin; #endif - + struct sockaddr *addr_to_use; #if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 1); + struct proc *p = current_proc(); #endif - if (control) { + int error; + bool use_sndinfo; + + if (control != NULL) { /* process cmsg snd/rcv info (maybe a assoc-id) */ - if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control, - sizeof(sndrcvninfo))) { - /* got one */ - use_sndinfo = 1; - } + use_sndinfo = sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control, sizeof(sndrcvninfo)); + } else { + use_sndinfo = false; } - addr_to_use = addr; #if defined(INET) && defined(INET6) - if ((addr) && (addr->sa_family == AF_INET6)) { + if ((addr != NULL) && (addr->sa_family == AF_INET6)) { struct sockaddr_in6 *sin6; +#ifdef HAVE_SA_LEN + if (addr->sa_len != sizeof(struct sockaddr_in6)) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); + return (EINVAL); + } +#endif sin6 = (struct sockaddr_in6 *)addr; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { in6_sin6_2_sin(&sin, sin6); addr_to_use = (struct sockaddr *)&sin; + } else { + addr_to_use = addr; } + } else { + addr_to_use = addr; } +#else + addr_to_use = addr; #endif - error = sctp_lower_sosend(so, addr_to_use, uio, top, - control, - flags, - use_sndinfo ? &sndrcvninfo: NULL -#if !defined(__Userspace__) - , p +#if defined(__APPLE__) && !defined(__Userspace__) + SCTP_SOCKET_LOCK(so, 1); +#endif + error = sctp_lower_sosend(so, addr_to_use, uio, top, control, flags, +#if defined(__Userspace__) + use_sndinfo ? &sndrcvninfo : NULL); +#else + use_sndinfo ? &sndrcvninfo : NULL, p); #endif - ); #if defined(__APPLE__) && !defined(__Userspace__) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -13396,123 +13536,72 @@ int sctp_lower_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, - struct mbuf *i_pak, + struct mbuf *top, struct mbuf *control, int flags, - struct sctp_sndrcvinfo *srcv -#if !defined(__Userspace__) - , -#if defined(__FreeBSD__) - struct thread *p -#elif defined(_WIN32) - PKTHREAD p +#if defined(__Userspace__) + struct sctp_sndrcvinfo *srcv) #else - struct proc *p + struct sctp_sndrcvinfo *srcv, +#if defined(__FreeBSD__) + struct thread *p) +#elif defined(_WIN32) + PKTHREAD p) +#else + struct proc *p) #endif #endif - ) { + struct sctp_nonpad_sndrcvinfo sndrcvninfo_buf; #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; - int queue_only = 0, queue_only_for_init = 0; - int free_cnt_applied = 0; - int un_sent; - int now_filled = 0; - unsigned int inqueue_bytes = 0; + struct timeval now; struct sctp_block_entry be; struct sctp_inpcb *inp; struct sctp_tcb *stcb = NULL; - struct timeval now; struct sctp_nets *net; struct sctp_association *asoc; struct sctp_inpcb *t_inp; - int user_marks_eor; - int create_lock_applied = 0; - int nagle_applies = 0; - int some_on_control = 0; - int got_all_of_the_send = 0; - int hold_tcblock = 0; - int non_blocking = 0; + struct sctp_nonpad_sndrcvinfo *sndrcvninfo; + ssize_t sndlen = 0, max_len, local_add_more; ssize_t local_soresv = 0; + sctp_assoc_t sinfo_assoc_id; + int user_marks_eor; + int nagle_applies = 0; + int error; + int queue_only = 0, queue_only_for_init = 0; + int un_sent; + int now_filled = 0; + unsigned int inqueue_bytes = 0; uint16_t port; uint16_t sinfo_flags; - sctp_assoc_t sinfo_assoc_id; + uint16_t sinfo_stream; + bool create_lock_applied = false; + bool free_cnt_applied = false; + bool some_on_control; + bool got_all_of_the_send = false; + bool non_blocking = false; error = 0; net = NULL; stcb = NULL; - asoc = NULL; #if defined(__APPLE__) && !defined(__Userspace__) sctp_lock_assert(so); #endif - t_inp = inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); + if ((uio == NULL) && (top == NULL)) { error = EINVAL; - if (i_pak) { - SCTP_RELEASE_PKT(i_pak); - } - return (error); - } - if ((uio == NULL) && (i_pak == NULL)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } - 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__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if (uio->uio_resid < 0) { -#else - if (uio_resid(uio) < 0) { -#endif -#else - if (uio->uio_resid < 0) { -#endif - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - sndlen = uio->uio_resid; -#else - sndlen = uio_resid(uio); -#endif -#else - sndlen = uio->uio_resid; -#endif - } else { - top = SCTP_HEADER_TO_CHAIN(i_pak); - sndlen = SCTP_HEADER_LEN(i_pak); - } - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n", - (void *)addr, - sndlen); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - SCTP_IS_LISTENING(inp)) { - /* The listener can NOT send */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); - error = ENOTCONN; goto out_unlocked; } - /** - * Pre-screen address, if one is given the sin-len - * must be set correctly! - */ - if (addr) { + if (addr != NULL) { union sctp_sockstore *raddr = (union sctp_sockstore *)addr; + switch (raddr->sa.sa_family) { #ifdef INET case AF_INET: #ifdef HAVE_SIN_LEN if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -13524,7 +13613,6 @@ sctp_lower_sosend(struct socket *so, case AF_INET6: #ifdef HAVE_SIN6_LEN if (raddr->sin6.sin6_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -13536,7 +13624,6 @@ sctp_lower_sosend(struct socket *so, case AF_CONN: #ifdef HAVE_SCONN_LEN if (raddr->sconn.sconn_len != sizeof(struct sockaddr_conn)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -13545,25 +13632,76 @@ sctp_lower_sosend(struct socket *so, break; #endif default: - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAFNOSUPPORT); error = EAFNOSUPPORT; goto out_unlocked; } - } else + } else { port = 0; - - if (srcv) { - sinfo_flags = srcv->sinfo_flags; - sinfo_assoc_id = srcv->sinfo_assoc_id; - if (INVALID_SINFO_FLAG(sinfo_flags) || - PR_SCTP_INVALID_POLICY(sinfo_flags)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + } + if (uio != NULL) { +#if defined(__APPLE__) && !defined(__Userspace__) +#if defined(APPLE_LEOPARD) + if (uio->uio_resid < 0) { +#else + if (uio_resid(uio) < 0) { +#endif +#else + if (uio->uio_resid < 0) { +#endif error = EINVAL; goto out_unlocked; } - if (srcv->sinfo_flags) - SCTP_STAT_INCR(sctps_sends_with_flags); +#if defined(__APPLE__) && !defined(__Userspace__) +#if defined(APPLE_LEOPARD) + sndlen = uio->uio_resid; +#else + sndlen = uio_resid(uio); +#endif +#else + sndlen = uio->uio_resid; +#endif } else { + sndlen = SCTP_HEADER_LEN(top); + } + SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n", + (void *)addr, sndlen); + + t_inp = inp = (struct sctp_inpcb *)so->so_pcb; + if (inp == NULL) { + error = EINVAL; + goto out_unlocked; + } + user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); + if ((uio == NULL) && (user_marks_eor != 0)) { + /*- + * We do not support eeor mode for + * sending with mbuf chains (like sendfile). + */ + error = EINVAL; + goto out_unlocked; + } + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && + SCTP_IS_LISTENING(inp)) { + /* The listener can NOT send. */ + error = EINVAL; + goto out_unlocked; + } + atomic_add_int(&inp->total_sends, 1); + + if (srcv != NULL) { + sndrcvninfo = (struct sctp_nonpad_sndrcvinfo *)srcv; + sinfo_assoc_id = sndrcvninfo->sinfo_assoc_id; + sinfo_flags = sndrcvninfo->sinfo_flags; + if (INVALID_SINFO_FLAG(sinfo_flags) || + PR_SCTP_INVALID_POLICY(sinfo_flags)) { + error = EINVAL; + goto out_unlocked; + } + if (sinfo_flags != 0) { + SCTP_STAT_INCR(sctps_sends_with_flags); + } + } else { + sndrcvninfo = NULL; sinfo_flags = inp->def_send.sinfo_flags; sinfo_assoc_id = inp->def_send.sinfo_assoc_id; } @@ -13575,64 +13713,69 @@ sctp_lower_sosend(struct socket *so, sinfo_flags |= SCTP_EOF; } #endif - if (sinfo_flags & SCTP_SENDALL) { - /* its a sendall */ - error = sctp_sendall(inp, uio, top, srcv); - top = NULL; - goto out_unlocked; - } if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } - /* now we must find the assoc */ + SCTP_INP_RLOCK(inp); + if ((sinfo_flags & SCTP_SENDALL) && + (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { + SCTP_INP_RUNLOCK(inp); + error = sctp_sendall(inp, uio, top, sndrcvninfo); + top = NULL; + goto out_unlocked; + } + /* Now we must find the association. */ if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_INP_RLOCK(inp); stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb) { + if (stcb != NULL) { SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; } SCTP_INP_RUNLOCK(inp); - } else if (sinfo_assoc_id) { - stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1); + } else if (sinfo_assoc_id > SCTP_ALL_ASSOC) { + stcb = sctp_findasoc_ep_asocid_locked(inp, sinfo_assoc_id, 1); + SCTP_INP_RUNLOCK(inp); if (stcb != NULL) { - hold_tcblock = 1; + SCTP_TCB_LOCK_ASSERT(stcb); } - } else if (addr) { + } else if (addr != NULL) { /*- * Since we did not use findep we must * increment it, and if we don't find a tcb * decrement it. */ - SCTP_INP_WLOCK(inp); SCTP_INP_INCR_REF(inp); - SCTP_INP_WUNLOCK(inp); + SCTP_INP_RUNLOCK(inp); stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); if (stcb == NULL) { SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); } else { - hold_tcblock = 1; + SCTP_TCB_LOCK_ASSERT(stcb); } + } else { + SCTP_INP_RUNLOCK(inp); } - if ((stcb == NULL) && (addr)) { + +#ifdef INVARIANTS + if (stcb != NULL) { + SCTP_TCB_LOCK_ASSERT(stcb); + } +#endif + + if ((stcb == NULL) && (addr != NULL)) { /* Possible implicit send? */ SCTP_ASOC_CREATE_LOCK(inp); - create_lock_applied = 1; + create_lock_applied = true; if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - /* Should I really unlock ? */ - 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)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -13651,20 +13794,20 @@ sctp_lower_sosend(struct socket *so, SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); } else { - hold_tcblock = 1; + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_ASOC_CREATE_UNLOCK(inp); + create_lock_applied = false; } - if (error) { + if (error != 0) { goto out_unlocked; } if (t_inp != inp) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); error = ENOTCONN; goto out_unlocked; } } if (stcb == NULL) { if (addr == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } else { @@ -13674,57 +13817,43 @@ sctp_lower_sosend(struct socket *so, if ((sinfo_flags & SCTP_ABORT) || ((sinfo_flags & SCTP_EOF) && (sndlen == 0))) { /*- - * User asks to abort a non-existant assoc, - * or EOF a non-existant assoc with no data + * User asks to abort a non-existent assoc, + * or EOF a non-existent assoc with no data */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } /* get an asoc/stcb struct */ vrf_id = inp->def_vrf_id; -#ifdef INVARIANTS - if (create_lock_applied == 0) { - panic("Error, should hold create lock and I don't?"); - } -#endif - stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, + KASSERT(create_lock_applied, ("create_lock_applied is false")); + stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, + inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, #if !defined(__Userspace__) - p, + p, #else - (struct proc *)NULL, + (struct proc *)NULL, #endif - SCTP_INITIALIZE_AUTH_PARAMS); + SCTP_INITIALIZE_AUTH_PARAMS); if (stcb == NULL) { - /* Error is setup for us in the call */ + /* error is setup for us in the call. */ + KASSERT(error != 0, ("error is 0 although stcb is NULL")); goto out_unlocked; } - 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); - } - hold_tcblock = 1; - if (create_lock_applied) { - SCTP_ASOC_CREATE_UNLOCK(inp); - create_lock_applied = 0; - } else { - SCTP_PRINTF("Huh-3? create lock should have been on??\n"); - } + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_ASOC_CREATE_UNLOCK(inp); + create_lock_applied = false; /* Turn on queue only flag to prevent data from being sent */ queue_only = 1; - asoc = &stcb->asoc; SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); - - if (control) { + (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); + if (control != NULL) { if (sctp_process_cmsgs_for_init(stcb, control, &error)) { - sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); - hold_tcblock = 0; stcb = NULL; + KASSERT(error != 0, + ("error is 0 although sctp_process_cmsgs_for_init() indicated an error")); goto out_unlocked; } } @@ -13737,11 +13866,35 @@ sctp_lower_sosend(struct socket *so, * change it BEFORE we append the message. */ } - } else - asoc = &stcb->asoc; - if (srcv == NULL) { - srcv = (struct sctp_sndrcvinfo *)&asoc->def_send; - sinfo_flags = srcv->sinfo_flags; + } + + KASSERT(!create_lock_applied, ("create_lock_applied is true")); + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + + asoc = &stcb->asoc; + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out_unlocked; + } + if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || + (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { + queue_only = 1; + } + /* Keep the stcb from being freed under our feet. */ + atomic_add_int(&asoc->refcnt, 1); + free_cnt_applied = true; + if (sndrcvninfo == NULL) { + /* Use a local copy to have a consistent view. */ + sndrcvninfo_buf = asoc->def_send; + sndrcvninfo = &sndrcvninfo_buf; + sinfo_flags = sndrcvninfo->sinfo_flags; #if defined(__FreeBSD__) && !defined(__Userspace__) if (flags & MSG_EOR) { sinfo_flags |= SCTP_EOR; @@ -13751,234 +13904,99 @@ sctp_lower_sosend(struct socket *so, } #endif } - if (sinfo_flags & SCTP_ADDR_OVER) { - if (addr) - net = sctp_findnet(stcb, addr); - else - net = NULL; - if ((net == NULL) || - ((port != 0) && (port != stcb->rport))) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } - } else { - if (stcb->asoc.alternate) { - net = stcb->asoc.alternate; - } else { - net = stcb->asoc.primary_destination; - } - } - atomic_add_int(&stcb->total_sends, 1); - /* Keep the stcb from being freed under our feet */ - atomic_add_int(&asoc->refcnt, 1); - free_cnt_applied = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { - if (sndlen > (ssize_t)asoc->smallest_mtu) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); - error = EMSGSIZE; - goto out_unlocked; - } - } -#if defined(__Userspace__) - if (inp->recv_callback) { - non_blocking = 1; - } -#endif - if (SCTP_SO_IS_NBIO(so) -#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 * 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 > (ssize_t)SCTP_SB_LIMIT_SND(so)) - error = EMSGSIZE; - else - error = EWOULDBLOCK; - goto out_unlocked; - } - stcb->asoc.sb_send_resv += (uint32_t)sndlen; - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = 0; - } else { - atomic_add_int(&stcb->asoc.sb_send_resv, sndlen); - } - local_soresv = sndlen; - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); - error = ECONNRESET; - goto out_unlocked; - } - if (create_lock_applied) { - SCTP_ASOC_CREATE_UNLOCK(inp); - create_lock_applied = 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[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. - */ - 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(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - queue_only = 1; - } - /* we are now done with all control */ - if (control) { - sctp_m_freem(control); - control = NULL; - } - 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 (sinfo_flags & SCTP_ABORT) { - ; - } else { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); - error = ECONNRESET; - goto out_unlocked; - } - } - /* Ok, we will attempt a msgsnd :> */ -#if !(defined(_WIN32) || defined(__Userspace__)) - if (p) { -#if defined(__FreeBSD__) - p->td_ru.ru_msgsnd++; -#else - p->p_stats->p_ru.ru_msgsnd++; -#endif - } -#endif /* Are we aborting? */ if (sinfo_flags & SCTP_ABORT) { struct mbuf *mm; + struct sctp_paramhdr *ph; ssize_t tot_demand, tot_out = 0, max_out; SCTP_STAT_INCR(sctps_sends_with_abort); 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); + /* It has to be up before we abort. */ error = EINVAL; - goto out; + goto out_unlocked; } - if (hold_tcblock) { - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = 0; - } - if (top) { - struct mbuf *cntm = NULL; + /* How big is the user initiated abort? */ + if (top != NULL) { + struct mbuf *cntm; - mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_WAITOK, 1, MT_DATA); if (sndlen != 0) { for (cntm = top; cntm; cntm = SCTP_BUF_NEXT(cntm)) { tot_out += SCTP_BUF_LEN(cntm); } } + mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); } else { /* Must fit in a MTU */ tot_out = sndlen; tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); if (tot_demand > SCTP_DEFAULT_ADD_MORE) { - /* To big */ - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); error = EMSGSIZE; - goto out; + goto out_unlocked; } - mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_WAITOK, 1, MT_DATA); + mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_NOWAIT, 1, MT_DATA); } if (mm == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); error = ENOMEM; - goto out; + goto out_unlocked; } max_out = asoc->smallest_mtu - sizeof(struct sctp_paramhdr); max_out -= sizeof(struct sctp_abort_msg); if (tot_out > max_out) { tot_out = max_out; } - if (mm) { - struct sctp_paramhdr *ph; - - /* 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((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out)); - ph++; - SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr)); - if (top == NULL) { + ph = mtod(mm, struct sctp_paramhdr *); + ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); + ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out)); + ph++; + SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr)); + if (top == NULL) { + SCTP_TCB_UNLOCK(stcb); #if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 0); + SCTP_SOCKET_UNLOCK(so, 0); #endif - error = uiomove((caddr_t)ph, (int)tot_out, uio); + error = uiomove((caddr_t)ph, (int)tot_out, uio); #if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 0); + SCTP_SOCKET_LOCK(so, 0); #endif - if (error) { - /*- - * Here if we can't get his data we - * still abort we just don't get to - * send the users note :-0 - */ - sctp_m_freem(mm); - mm = NULL; - } - } else { - if (sndlen != 0) { - SCTP_BUF_NEXT(mm) = top; + SCTP_TCB_LOCK(stcb); + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + sctp_m_freem(mm); + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ + error = ECONNRESET; + } else { + error = ENOTCONN; } + goto out_unlocked; + } + if (error != 0) { + /*- + * Here if we can't get his data we + * still abort we just don't get to + * send the users note :-0 + */ + sctp_m_freem(mm); + mm = NULL; + error = 0; + } + } else { + if (sndlen != 0) { + SCTP_BUF_NEXT(mm) = top; } } - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - } - atomic_add_int(&stcb->asoc.refcnt, -1); - free_cnt_applied = 0; + atomic_subtract_int(&asoc->refcnt, 1); + free_cnt_applied = false; /* 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); + sctp_abort_an_association(stcb->sctp_ep, stcb, mm, false, 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; /* In this case top is already chained to mm * avoid double free, since we free it below if @@ -13990,43 +14008,134 @@ sctp_lower_sosend(struct socket *so, } goto out_unlocked; } + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + + if (sinfo_flags & SCTP_ADDR_OVER) { + if (addr != NULL) { + net = sctp_findnet(stcb, addr); + } else { + net = NULL; + } + if ((net == NULL) || + ((port != 0) && (port != stcb->rport))) { + error = EINVAL; + goto out_unlocked; + } + } else { + if (asoc->alternate != NULL) { + net = asoc->alternate; + } else { + net = asoc->primary_destination; + } + } + if (sndlen == 0) { + if (sinfo_flags & SCTP_EOF) { + got_all_of_the_send = true; + goto dataless_eof; + } else { + error = EINVAL; + goto out_unlocked; + } + } + if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { + if (sndlen > (ssize_t)asoc->smallest_mtu) { + error = EMSGSIZE; + goto out_unlocked; + } + } + sinfo_stream = sndrcvninfo->sinfo_stream; + /* Is the stream no. valid? */ + if (sinfo_stream >= asoc->streamoutcnt) { + /* Invalid stream number */ + error = EINVAL; + goto out_unlocked; + } + if ((asoc->strmout[sinfo_stream].state != SCTP_STREAM_OPEN) && + (asoc->strmout[sinfo_stream].state != SCTP_STREAM_OPENING)) { + /* + * Can't queue any data while stream reset is underway. + */ + if (asoc->strmout[sinfo_stream].state > SCTP_STREAM_OPEN) { + error = EAGAIN; + } else { + error = EINVAL; + } + goto out_unlocked; + } + atomic_add_int(&stcb->total_sends, 1); +#if defined(__Userspace__) + if (inp->recv_callback != NULL) { + non_blocking = true; + } +#endif +#if defined(__FreeBSD__) && !defined(__Userspace__) + if (SCTP_SO_IS_NBIO(so) || (flags & (MSG_NBIO | MSG_DONTWAIT)) != 0) { +#else + if (SCTP_SO_IS_NBIO(so)) { +#endif + non_blocking = true; + } + if (non_blocking) { + ssize_t amount; + + inqueue_bytes = asoc->total_output_queue_size - (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 + asoc->sb_send_resv)) || + (asoc->chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { + if ((sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so)) && + (user_marks_eor == 0)) { + error = EMSGSIZE; + } else { + error = EWOULDBLOCK; + } + goto out_unlocked; + } + } + atomic_add_int(&asoc->sb_send_resv, (int)sndlen); + local_soresv = sndlen; + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + + /* Ok, we will attempt a msgsnd :> */ +#if !(defined(_WIN32) || defined(__Userspace__)) + if (p != NULL) { +#if defined(__FreeBSD__) + p->td_ru.ru_msgsnd++; +#else + p->p_stats->p_ru.ru_msgsnd++; +#endif + } +#endif /* Calculate the maximum we can send */ - inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + inqueue_bytes = asoc->total_output_queue_size - (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 (hold_tcblock) { - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = 0; - } - if (asoc->strmout == NULL) { - /* huh? software error */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); - error = EFAULT; - goto out_unlocked; - } - /* Unless E_EOR mode is on, we must make a send FIT in one call. */ if ((user_marks_eor == 0) && (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); + /* It will NEVER fit. */ error = EMSGSIZE; goto out_unlocked; } - if ((uio == NULL) && user_marks_eor) { - /*- - * We do not support eeor mode for - * sending with mbuf chains (like sendfile). - */ - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } - - if (user_marks_eor) { + if (user_marks_eor != 0) { local_add_more = (ssize_t)min(SCTP_SB_LIMIT_SND(so), SCTP_BASE_SYSCTL(sctp_add_more_threshold)); } else { /*- @@ -14035,25 +14144,23 @@ sctp_lower_sosend(struct socket *so, */ local_add_more = sndlen; } - len = 0; if (non_blocking) { goto skip_preblock; } - if (((max_len <= local_add_more) && - ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) || + if (((max_len <= 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 ! */ + ((asoc->chunks_on_out_queue + asoc->stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { + /* No room right now! */ + inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); SOCKBUF_LOCK(&so->so_snd); - 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))) { + ((asoc->stream_queue_cnt + 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, - stcb->asoc.stream_queue_cnt, - stcb->asoc.chunks_on_out_queue, + asoc->stream_queue_cnt, + asoc->chunks_on_out_queue, SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)); if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, asoc, sndlen); @@ -14062,31 +14169,45 @@ sctp_lower_sosend(struct socket *so, #if !(defined(_WIN32) && !defined(__Userspace__)) stcb->block_entry = &be; #endif + SCTP_TCB_UNLOCK(stcb); +#if defined(__FreeBSD__) && !defined(__Userspace__) + error = sbwait(so, SO_SND); +#else error = sbwait(&so->so_snd); - stcb->block_entry = NULL; - if (error || so->so_error || be.error) { - if (error == 0) { - if (so->so_error) - error = so->so_error; - if (be.error) { - error = be.error; - } +#endif + if (error == 0) { + if (so->so_error != 0) { + error = so->so_error; + } + if (be.error != 0) { + error = be.error; + } + } + SOCKBUF_UNLOCK(&so->so_snd); + SCTP_TCB_LOCK(stcb); + stcb->block_entry = NULL; + if (error != 0) { + goto out_unlocked; + } + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ + error = ECONNRESET; + } else { + error = ENOTCONN; } - SOCKBUF_UNLOCK(&so->so_snd); goto out_unlocked; } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, - asoc, stcb->asoc.total_output_queue_size); + asoc, 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 * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + SOCKBUF_LOCK(&so->so_snd); } if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { - max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; + max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; } else { max_len = 0; } @@ -14094,48 +14215,76 @@ sctp_lower_sosend(struct socket *so, } skip_preblock: - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - goto out_unlocked; - } + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + #if defined(__APPLE__) && !defined(__Userspace__) error = sblock(&so->so_snd, SBLOCKWAIT(flags)); + if (error != 0) { + goto out_unlocked; + } #endif /* sndlen covers for mbuf case * uio_resid covers for the non-mbuf case * NOTE: uio will be null when top/mbuf is passed */ - if (sndlen == 0) { - if (sinfo_flags & SCTP_EOF) { - got_all_of_the_send = 1; - goto dataless_eof; - } else { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out; - } - } if (top == NULL) { struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strm; uint32_t sndout; - SCTP_TCB_SEND_LOCK(stcb); if ((asoc->stream_locked) && - (asoc->stream_locked_on != srcv->sinfo_stream)) { - SCTP_TCB_SEND_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + (asoc->stream_locked_on != sinfo_stream)) { error = EINVAL; goto out; } - strm = &stcb->asoc.strmout[srcv->sinfo_stream]; + strm = &asoc->strmout[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 (error) { + SCTP_TCB_UNLOCK(stcb); + sp = sctp_copy_it_in(stcb, asoc, sndrcvninfo, uio, net, max_len, user_marks_eor, &error); + SCTP_TCB_LOCK(stcb); + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } goto out; } - SCTP_TCB_SEND_LOCK(stcb); + if (error != 0) { + goto out; + } + /* + * Reject the sending of a new user message, if the + * association is about to be shut down. + */ + 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 (sp->data != 0) { + sctp_m_freem(sp->data); + sp->data = NULL; + sp->tail_mbuf = NULL; + sp->length = 0; + } + if (sp->net != NULL) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; + } + sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); + error = EPIPE; + goto out_unlocked; + } + /* The out streams might be reallocated. */ + strm = &asoc->strmout[sinfo_stream]; if (sp->msg_is_complete) { strm->last_msg_incomplete = 0; asoc->stream_locked = 0; @@ -14144,9 +14293,9 @@ skip_preblock: * case of an interrupt. */ strm->last_msg_incomplete = 1; - if (stcb->asoc.idata_supported == 0) { + if (asoc->idata_supported == 0) { asoc->stream_locked = 1; - asoc->stream_locked_on = srcv->sinfo_stream; + asoc->stream_locked_on = sinfo_stream; } sp->sender_all_done = 0; } @@ -14157,7 +14306,7 @@ skip_preblock: } sp->processing = 1; TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp, 1); + asoc->ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp); } else { sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); if (sp == NULL) { @@ -14170,16 +14319,21 @@ skip_preblock: #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); + if (sp->processing != 0) { error = EINVAL; goto out; } else { sp->processing = 1; } } - SCTP_TCB_SEND_UNLOCK(stcb); + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) while (uio->uio_resid > 0) { @@ -14192,32 +14346,29 @@ skip_preblock: /* How much room do we have? */ struct mbuf *new_tail, *mm; - 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) + inqueue_bytes = asoc->total_output_queue_size - (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 + } else { max_len = 0; - + } 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))) || + ((max_len > 0 ) && (SCTP_SB_LIMIT_SND(so) < SCTP_BASE_SYSCTL(sctp_add_more_threshold))) || #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) - (uio->uio_resid && (uio->uio_resid <= max_len))) { + (uio->uio_resid <= max_len)) { #else - (uio_resid(uio) && (uio_resid(uio) <= max_len))) { + (uio_resid(uio) <= max_len)) { #endif #else - (uio->uio_resid && (uio->uio_resid <= max_len))) { + (uio->uio_resid <= max_len)) { #endif - sndout = 0; - new_tail = NULL; - if (hold_tcblock) { - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = 0; - } + SCTP_TCB_UNLOCK(stcb); #if defined(__APPLE__) && !defined(__Userspace__) SCTP_SOCKET_UNLOCK(so, 0); #endif + sndout = 0; + new_tail = NULL; #if defined(__FreeBSD__) || defined(__Userspace__) mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail); #else @@ -14226,46 +14377,41 @@ skip_preblock: #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) || - (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) { - /* we need to get out. + SCTP_TCB_LOCK(stcb); + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + /* We need to get out. * Peer probably aborted. */ sctp_m_freem(mm); - if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ error = ECONNRESET; + } else { + error = ENOTCONN; } - SCTP_TCB_SEND_UNLOCK(stcb); goto out; } - if (sp->tail_mbuf) { - /* tack it to the end */ - SCTP_BUF_NEXT(sp->tail_mbuf) = mm; - sp->tail_mbuf = new_tail; - } else { - /* A stolen mbuf */ - sp->data = mm; - sp->tail_mbuf = new_tail; + if ((mm == NULL) || (error != 0)) { + if (mm != NULL) { + sctp_m_freem(mm); + } + if (sp != NULL) { + sp->processing = 0; + } + goto out; } + /* Update the mbuf and count */ + if (sp->tail_mbuf != NULL) { + /* Tack it to the end. */ + SCTP_BUF_NEXT(sp->tail_mbuf) = mm; + } else { + /* A stolen mbuf. */ + sp->data = mm; + } + sp->tail_mbuf = new_tail; sctp_snd_sb_alloc(stcb, sndout); atomic_add_int(&sp->length, sndout); - len += sndout; if (sinfo_flags & SCTP_SACK_IMMEDIATELY) { sp->sinfo_flags |= SCTP_SACK_IMMEDIATELY; } @@ -14287,8 +14433,15 @@ skip_preblock: } else { sp->msg_is_complete = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); } + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) if (uio->uio_resid == 0) { @@ -14304,12 +14457,8 @@ skip_preblock: /* PR-SCTP? */ if ((asoc->prsctp_supported) && (asoc->sent_queue_cnt_removeable > 0)) { /* This is ugly but we must assure locking order */ - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; - } - 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)); + sctp_prune_prsctp(stcb, asoc, sndrcvninfo, (int)sndlen); + inqueue_bytes = asoc->total_output_queue_size - (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 @@ -14317,25 +14466,17 @@ skip_preblock: if (max_len > 0) { continue; } - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = 0; } /* 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 */ if (queue_only_for_init) { - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; - } if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { /* a collision took us forward? */ queue_only = 0; @@ -14362,11 +14503,11 @@ skip_preblock: } asoc->ifp_had_enobuf = 0; } - un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight; + un_sent = asoc->total_output_queue_size - 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))) { + (asoc->total_flight > 0) && + (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && + (un_sent < (int)(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 @@ -14387,13 +14528,14 @@ skip_preblock: } 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, - stcb->asoc.total_flight, - stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count); + nagle_applies, un_sent); + sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size, + asoc->total_flight, + asoc->chunks_on_out_queue, asoc->total_flight_count); } - if (queue_only_for_init) + if (queue_only_for_init) { queue_only_for_init = 0; + } if ((queue_only == 0) && (nagle_applies == 0)) { /*- * need to start chunk output @@ -14405,27 +14547,12 @@ skip_preblock: #if defined(__FreeBSD__) && !defined(__Userspace__) NET_EPOCH_ENTER(et); #endif - if (hold_tcblock == 0) { - if (SCTP_TCB_TRYLOCK(stcb)) { - hold_tcblock = 1; - sctp_chunk_output(inp, - stcb, - SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } - } else { - sctp_chunk_output(inp, - stcb, - SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } + sctp_chunk_output(inp, stcb, + SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); #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); /*- * This is a bit strange, but I think it will * work. The total_output_queue_size is locked and @@ -14440,81 +14567,93 @@ skip_preblock: * size we KNOW we will get to sleep safely with the * wakeup flag in place. */ - inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + SOCKBUF_LOCK(&so->so_snd); if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes + - min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) { + 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__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio->uio_resid); + asoc, uio->uio_resid); #else sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio_resid(uio)); + asoc, uio_resid(uio)); #endif #else sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio->uio_resid); + asoc, uio->uio_resid); #endif } be.error = 0; #if !(defined(_WIN32) && !defined(__Userspace__)) stcb->block_entry = &be; #endif + SCTP_TCB_UNLOCK(stcb); #if defined(__APPLE__) && !defined(__Userspace__) sbunlock(&so->so_snd, 1); #endif +#if defined(__FreeBSD__) && !defined(__Userspace__) + error = sbwait(so, SO_SND); +#else error = sbwait(&so->so_snd); +#endif + if (error == 0) { + if (so->so_error != 0) + error = so->so_error; + if (be.error != 0) { + error = be.error; + } + } + SOCKBUF_UNLOCK(&so->so_snd); + SCTP_TCB_LOCK(stcb); stcb->block_entry = NULL; - - if (error || so->so_error || be.error) { - if (error == 0) { - if (so->so_error) - error = so->so_error; - if (be.error) { - error = be.error; - } + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out_unlocked; + } + if (error != 0) { + if (sp != NULL) { + sp->processing = 0; } - 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__) && !defined(__Userspace__) error = sblock(&so->so_snd, SBLOCKWAIT(flags)); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, - asoc, stcb->asoc.total_output_queue_size); + if (error != 0) { + goto out_unlocked; } +#endif + } else { + SOCKBUF_UNLOCK(&so->so_snd); } - SOCKBUF_UNLOCK(&so->so_snd); - 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 (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { + sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, + asoc, asoc->total_output_queue_size); } - 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) { + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + + /* The out streams might be reallocated. */ + strm = &asoc->strmout[sinfo_stream]; + if (sp != NULL) { if (sp->msg_is_complete == 0) { strm->last_msg_incomplete = 1; - if (stcb->asoc.idata_supported == 0) { + if (asoc->idata_supported == 0) { asoc->stream_locked = 1; - asoc->stream_locked_on = srcv->sinfo_stream; + asoc->stream_locked_on = sinfo_stream; } } else { sp->sender_all_done = 1; @@ -14527,7 +14666,6 @@ skip_preblock: strm->last_msg_incomplete = 0; asoc->stream_locked = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) if (uio->uio_resid == 0) { @@ -14537,29 +14675,31 @@ skip_preblock: #else if (uio->uio_resid == 0) { #endif - got_all_of_the_send = 1; + got_all_of_the_send = true; } } else { - /* We send in a 0, since we do NOT have any locks */ - error = sctp_msg_append(stcb, net, top, srcv, 0); + error = sctp_msg_append(stcb, net, top, sndrcvninfo); top = NULL; - if (sinfo_flags & SCTP_EOF) { - got_all_of_the_send = 1; + if ((sinfo_flags & SCTP_EOF) != 0) { + got_all_of_the_send = true; } } - if (error) { + if (error != 0) { goto out; } + dataless_eof: + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + /* EOF thing ? */ - if ((sinfo_flags & SCTP_EOF) && - (got_all_of_the_send == 1)) { + if ((sinfo_flags & SCTP_EOF) && got_all_of_the_send) { SCTP_STAT_INCR(sctps_sends_with_eof); error = 0; - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; - } if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) { @@ -14578,10 +14718,10 @@ dataless_eof: } SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); sctp_stop_timers_for_shutdown(stcb); - if (stcb->asoc.alternate) { - netp = stcb->asoc.alternate; + if (asoc->alternate != NULL) { + netp = asoc->alternate; } else { - netp = stcb->asoc.primary_destination; + netp = asoc->primary_destination; } sctp_send_shutdown(stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, @@ -14603,10 +14743,6 @@ dataless_eof: 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->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); } @@ -14619,8 +14755,8 @@ dataless_eof: abort_anyway: if (free_cnt_applied) { - atomic_add_int(&stcb->asoc.refcnt, -1); - free_cnt_applied = 0; + atomic_subtract_int(&asoc->refcnt, 1); + free_cnt_applied = false; } SCTP_SNPRINTF(msg, sizeof(msg), "%s:%d at %s", __FILE__, __LINE__, __func__); @@ -14630,30 +14766,29 @@ dataless_eof: NET_EPOCH_ENTER(et); #endif sctp_abort_an_association(stcb->sctp_ep, stcb, - op_err, SCTP_SO_LOCKED); + op_err, false, 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; + error = ECONNABORTED; goto out; } - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - NULL); sctp_feature_off(inp, SCTP_PCB_FLAGS_NODELAY); } } } + skip_out_eof: - if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { - some_on_control = 1; - } + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + + some_on_control = !TAILQ_EMPTY(&asoc->control_send_queue); if (queue_only_for_init) { - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; - } if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { /* a collision took us forward? */ queue_only = 0; @@ -14669,8 +14804,16 @@ skip_out_eof: queue_only = 1; } } + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + if ((net->flight_size > net->cwnd) && - (stcb->asoc.sctp_cmt_on_off == 0)) { + (asoc->sctp_cmt_on_off == 0)) { SCTP_STAT_INCR(sctps_send_cwnd_avoid); queue_only = 1; } else if (asoc->ifp_had_enobuf) { @@ -14680,11 +14823,11 @@ skip_out_eof: } asoc->ifp_had_enobuf = 0; } - un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight; + un_sent = asoc->total_output_queue_size - 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))) { + (asoc->total_flight > 0) && + (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && + (un_sent < (int)(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 @@ -14706,89 +14849,76 @@ skip_out_eof: 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, - stcb->asoc.total_flight, - stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count); + sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size, + asoc->total_flight, + asoc->chunks_on_out_queue, asoc->total_flight_count); } + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + #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) { - /* If there is activity recv'ing sacks no need to send */ - if (SCTP_TCB_TRYLOCK(stcb)) { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - hold_tcblock = 1; - } - } else { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } + if ((queue_only == 0) && (nagle_applies == 0) && (asoc->peers_rwnd && un_sent)) { + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); } else if ((queue_only == 0) && - (stcb->asoc.peers_rwnd == 0) && - (stcb->asoc.total_flight == 0)) { + (asoc->peers_rwnd == 0) && + (asoc->total_flight == 0)) { /* We get to have a probe outstanding */ - if (hold_tcblock == 0) { - hold_tcblock = 1; - SCTP_TCB_LOCK(stcb); - } sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); } else if (some_on_control) { - int num_out, reason, frag_point; + int num_out, reason; /* Here we do control only */ - if (hold_tcblock == 0) { - hold_tcblock = 1; - SCTP_TCB_LOCK(stcb); - } - frag_point = sctp_get_frag_point(stcb, &stcb->asoc); - (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED); + (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, + &reason, 1, 1, &now, &now_filled, + sctp_get_frag_point(stcb), + 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); + queue_only, asoc->peers_rwnd, un_sent, + asoc->total_flight, asoc->chunks_on_out_queue, + asoc->total_output_queue_size, error); + + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); out: #if defined(__APPLE__) && !defined(__Userspace__) sbunlock(&so->so_snd, 1); #endif out_unlocked: - - if (local_soresv && stcb) { - atomic_subtract_int(&stcb->asoc.sb_send_resv, sndlen); - } if (create_lock_applied) { SCTP_ASOC_CREATE_UNLOCK(inp); } - if ((stcb) && hold_tcblock) { + if (stcb != NULL) { + if (local_soresv) { + atomic_subtract_int(&asoc->sb_send_resv, (int)sndlen); + } + if (free_cnt_applied) { + atomic_subtract_int(&asoc->refcnt, 1); + } SCTP_TCB_UNLOCK(stcb); } - if (stcb && free_cnt_applied) { - atomic_add_int(&stcb->asoc.refcnt, -1); - } -#ifdef INVARIANTS -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (stcb) { - if (mtx_owned(&stcb->tcb_mtx)) { - panic("Leaving with tcb mtx owned?"); - } - if (mtx_owned(&stcb->tcb_send_mtx)) { - panic("Leaving with tcb send mtx owned?"); - } - } -#endif -#endif - if (top) { + if (top != NULL) { sctp_m_freem(top); } - if (control) { + if (control != NULL) { sctp_m_freem(control); } + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error); return (error); } @@ -14945,9 +15075,9 @@ sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro) mask = (struct sockaddr_in *)(ifa->ifa_netmask); sin = &sifa->address.sin; srcnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); - SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: src address is "); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "match_nexthop4: src address is "); SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa); - SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", srcnetaddr.s_addr); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "network address is %x\n", srcnetaddr.s_addr); #if defined(__FreeBSD__) sin = &ro->ro_nh->gw4_sa; @@ -14955,13 +15085,13 @@ sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro) 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 "); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "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); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "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 dad10e00a7..a51a92a85e 100644 --- a/netwerk/sctp/src/netinet/sctp_output.h +++ b/netwerk/sctp/src/netinet/sctp_output.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 366114 2020-09-24 12:26:06Z tuexen $"); -#endif - #ifndef _NETINET_SCTP_OUTPUT_H_ #define _NETINET_SCTP_OUTPUT_H_ @@ -89,7 +84,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *, struct mbuf * sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *, - struct sctp_chunkhdr *, int *, int *); + struct sctp_chunkhdr *, int *, int *, + uint32_t *); + void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *); int @@ -124,7 +121,7 @@ void sctp_send_asconf(struct sctp_tcb *, struct sctp_nets *, int addr_locked); void sctp_send_asconf_ack(struct sctp_tcb *); -int sctp_get_frag_point(struct sctp_tcb *, struct sctp_association *); +uint32_t sctp_get_frag_point(struct sctp_tcb *); void sctp_toss_old_cookies(struct sctp_tcb *, struct sctp_association *); diff --git a/netwerk/sctp/src/netinet/sctp_pcb.c b/netwerk/sctp/src/netinet/sctp_pcb.c index 89a66bce87..e8ef38ec37 100644 --- a/netwerk/sctp/src/netinet/sctp_pcb.c +++ b/netwerk/sctp/src/netinet/sctp_pcb.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 366483 2020-10-06 11:29:08Z tuexen $"); -#endif - #include #if defined(__FreeBSD__) && !defined(__Userspace__) #include @@ -256,20 +251,18 @@ sctp_find_ifn(void *ifn, uint32_t ifn_index) struct sctp_ifn *sctp_ifnp; struct sctp_ifnlist *hash_ifn_head; - /* We assume the lock is held for the addresses - * if that's wrong problems could occur :-) - */ SCTP_IPI_ADDR_LOCK_ASSERT(); +#if defined(__FreeBSD__) && !defined(__Userspace__) + KASSERT(ifn != NULL, ("sctp_find_ifn(NULL, %u) called", ifn_index)); +#endif 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) { - return (sctp_ifnp); - } - if (sctp_ifnp->ifn_p && ifn && (sctp_ifnp->ifn_p == ifn)) { - return (sctp_ifnp); + if (sctp_ifnp->ifn_index == ifn_index && + sctp_ifnp->ifn_p == ifn) { + break; } } - return (NULL); + return (sctp_ifnp); } struct sctp_vrf * @@ -291,10 +284,10 @@ void sctp_free_vrf(struct sctp_vrf *vrf) { if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&vrf->refcount)) { - if (vrf->vrf_addr_hash) { - SCTP_HASH_FREE(vrf->vrf_addr_hash, vrf->vrf_addr_hashmark); - vrf->vrf_addr_hash = NULL; - } + if (vrf->vrf_addr_hash) { + SCTP_HASH_FREE(vrf->vrf_addr_hash, vrf->vrf_addr_hashmark); + vrf->vrf_addr_hash = NULL; + } /* We zero'd the count */ LIST_REMOVE(vrf, next_vrf); SCTP_FREE(vrf, SCTP_M_VRF); @@ -302,7 +295,7 @@ sctp_free_vrf(struct sctp_vrf *vrf) } } -void +static void sctp_free_ifn(struct sctp_ifn *sctp_ifnp) { if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&sctp_ifnp->refcount)) { @@ -315,17 +308,6 @@ sctp_free_ifn(struct sctp_ifn *sctp_ifnp) } } -void -sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu) -{ - struct sctp_ifn *sctp_ifnp; - - sctp_ifnp = sctp_find_ifn((void *)NULL, ifn_index); - if (sctp_ifnp != NULL) { - sctp_ifnp->ifn_mtu = mtu; - } -} - void sctp_free_ifa(struct sctp_ifa *sctp_ifap) { @@ -340,123 +322,30 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap) } static void -sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock) +sctp_delete_ifn(struct sctp_ifn *sctp_ifnp) { - struct sctp_ifn *found; - found = sctp_find_ifn(sctp_ifnp->ifn_p, sctp_ifnp->ifn_index); - if (found == NULL) { + SCTP_IPI_ADDR_WLOCK_ASSERT(); + if (sctp_find_ifn(sctp_ifnp->ifn_p, sctp_ifnp->ifn_index) == NULL) { /* Not in the list.. sorry */ return; } - 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); - 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) -{ - struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap; - - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(vrf_id); - 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) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find sctp_ifap for address\n"); - goto out; - } - if (sctp_ifap->ifn_p == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n"); - goto out; - } - if (if_name) { - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) != 0) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFN %s of IFA not the same as %s\n", - sctp_ifap->ifn_p->ifn_name, if_name); - goto out; - } - } else { - if (sctp_ifap->ifn_p->ifn_index != ifn_index) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n", - sctp_ifap->ifn_p->ifn_index, ifn_index); - goto out; - } - } - - sctp_ifap->localifa_flags &= (~SCTP_ADDR_VALID); - sctp_ifap->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; - out: - 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) -{ - struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap; - - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(vrf_id); - 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) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find sctp_ifap for address\n"); - goto out; - } - if (sctp_ifap->ifn_p == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n"); - goto out; - } - if (if_name) { - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) != 0) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFN %s of IFA not the same as %s\n", - sctp_ifap->ifn_p->ifn_name, if_name); - goto out; - } - } else { - if (sctp_ifap->ifn_p->ifn_index != ifn_index) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n", - sctp_ifap->ifn_p->ifn_index, ifn_index); - goto out; - } - } - - sctp_ifap->localifa_flags &= (~SCTP_ADDR_IFA_UNUSEABLE); - sctp_ifap->localifa_flags |= SCTP_ADDR_VALID; - out: - SCTP_IPI_ADDR_RUNLOCK(); -} - /*- * Add an ifa to an ifn. * Register the interface as necessary. - * NOTE: ADDR write lock MUST be held. */ static void sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap) { int ifa_af; + SCTP_IPI_ADDR_WLOCK_ASSERT(); LIST_INSERT_HEAD(&sctp_ifnp->ifalist, sctp_ifap, next_ifa); sctp_ifap->ifn_p = sctp_ifnp; atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); @@ -487,11 +376,11 @@ sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap) * Remove an ifa from its ifn. * If no more addresses exist, remove the ifn too. Otherwise, re-register * the interface based on the remaining address families left. - * NOTE: ADDR write lock MUST be held. */ static void sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap) { + SCTP_IPI_ADDR_WLOCK_ASSERT(); LIST_REMOVE(sctp_ifap, next_ifa); if (sctp_ifap->ifn_p) { /* update address counts */ @@ -513,7 +402,7 @@ sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap) if (LIST_EMPTY(&sctp_ifap->ifn_p->ifalist)) { /* remove the ifn, possibly freeing it */ - sctp_delete_ifn(sctp_ifap->ifn_p, SCTP_ADDR_LOCKED); + sctp_delete_ifn(sctp_ifap->ifn_p); } else { /* re-register address family type, if needed */ if ((sctp_ifap->ifn_p->num_v6 == 0) && @@ -532,9 +421,9 @@ 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, - struct sockaddr *addr, uint32_t ifa_flags, - int dynamic_add) + uint32_t ifn_type, const char *if_name, void *ifa, + struct sockaddr *addr, uint32_t ifa_flags, + int dynamic_add) { struct sctp_vrf *vrf; struct sctp_ifn *sctp_ifnp, *new_sctp_ifnp; @@ -542,7 +431,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, struct sctp_ifalist *hash_addr_head; struct sctp_ifnlist *hash_ifn_head; uint32_t hash_of_addr; - int new_ifn_af = 0; #ifdef SCTP_DEBUG SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: adding address: ", vrf_id); @@ -594,7 +482,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifnp->refcount = 0; sctp_ifnp->vrf = vrf; atomic_add_int(&vrf->refcount, 1); - sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index, addr->sa_family); + sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index); if (if_name != NULL) { SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", if_name); } else { @@ -605,59 +493,64 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, 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); - new_ifn_af = 1; } sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); - if (sctp_ifap) { - /* Hmm, it already exists? */ - if ((sctp_ifap->ifn_p) && - (sctp_ifap->ifn_p->ifn_index == ifn_index)) { - SCTPDBG(SCTP_DEBUG_PCB4, "Using existing ifn %s (0x%x) for ifa %p\n", - sctp_ifap->ifn_p->ifn_name, ifn_index, - (void *)sctp_ifap); - if (new_ifn_af) { - /* Remove the created one that we don't want */ - sctp_delete_ifn(sctp_ifnp, SCTP_ADDR_LOCKED); - } - if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) { - /* easy to solve, just switch back to active */ - SCTPDBG(SCTP_DEBUG_PCB4, "Clearing deleted ifa flag\n"); - sctp_ifap->localifa_flags = SCTP_ADDR_VALID; - sctp_ifap->ifn_p = sctp_ifnp; - atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); - } - 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) { + if (sctp_ifap != NULL) { + /* The address being added is already or still known. */ + if (sctp_ifap->ifn_p != NULL) { + if (sctp_ifap->ifn_p->ifn_index == ifn_index && + sctp_ifap->ifn_p->ifn_p == ifn) { + SCTPDBG(SCTP_DEBUG_PCB4, + "Using existing ifn %s (0x%x) for ifa %p\n", + sctp_ifap->ifn_p->ifn_name, ifn_index, + (void *)sctp_ifap); + if (new_sctp_ifnp == NULL) { + /* Remove the created one not used. */ + sctp_delete_ifn(sctp_ifnp); + } + if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) { + /* Switch back to active. */ + SCTPDBG(SCTP_DEBUG_PCB4, + "Clearing deleted ifa flag\n"); + sctp_ifap->localifa_flags = SCTP_ADDR_VALID; + sctp_ifap->ifn_p = sctp_ifnp; + atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); + } + } else { /* * The last IFN gets the address, remove the - * old one + * old one. */ - SCTPDBG(SCTP_DEBUG_PCB4, "Moving ifa %p from %s (0x%x) to %s (0x%x)\n", - (void *)sctp_ifap, sctp_ifap->ifn_p->ifn_name, - sctp_ifap->ifn_p->ifn_index, if_name, - ifn_index); + SCTPDBG(SCTP_DEBUG_PCB4, + "Moving ifa %p from %s (0x%x) to %s (0x%x)\n", + (void *)sctp_ifap, + sctp_ifap->ifn_p->ifn_name, + sctp_ifap->ifn_p->ifn_index, if_name, + ifn_index); /* remove the address from the old ifn */ sctp_remove_ifa_from_ifn(sctp_ifap); /* move the address over to the new ifn */ sctp_add_ifa_to_ifn(sctp_ifnp, sctp_ifap); - goto exit_stage_left; - } else { - /* repair ifnp which was NULL ? */ - sctp_ifap->localifa_flags = SCTP_ADDR_VALID; - SCTPDBG(SCTP_DEBUG_PCB4, "Repairing ifn %p for ifa %p\n", - (void *)sctp_ifnp, (void *)sctp_ifap); - sctp_add_ifa_to_ifn(sctp_ifnp, sctp_ifap); } - goto exit_stage_left; + } else { + /* Repair ifn_p, which was NULL... */ + sctp_ifap->localifa_flags = SCTP_ADDR_VALID; + SCTPDBG(SCTP_DEBUG_PCB4, + "Repairing ifn %p for ifa %p\n", + (void *)sctp_ifnp, (void *)sctp_ifap); + sctp_add_ifa_to_ifn(sctp_ifnp, sctp_ifap); } + 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); } + KASSERT(sctp_ifnp != NULL, + ("sctp_add_addr_to_vrf: sctp_ifnp == NULL")); + KASSERT(sctp_ifap == NULL, + ("sctp_add_addr_to_vrf: sctp_ifap (%p) != NULL", sctp_ifap)); sctp_ifap = new_sctp_ifap; memset(sctp_ifap, 0, sizeof(struct sctp_ifa)); sctp_ifap->ifn_p = sctp_ifnp; @@ -706,8 +599,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifap->src_is_priv = 1; } sctp_ifnp->num_v4++; - if (new_ifn_af) - new_ifn_af = AF_INET; + if (new_sctp_ifnp == NULL) + sctp_ifnp->registered_af = AF_INET; break; } #endif @@ -726,19 +619,18 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifap->src_is_priv = 1; } sctp_ifnp->num_v6++; - if (new_ifn_af) - new_ifn_af = AF_INET6; + if (new_sctp_ifnp == NULL) + sctp_ifnp->registered_af = AF_INET6; break; } #endif #if defined(__Userspace__) case AF_CONN: - if (new_ifn_af) - new_ifn_af = AF_CONN; + if (new_sctp_ifnp == NULL) + sctp_ifnp->registered_af = AF_CONN; break; #endif default: - new_ifn_af = 0; break; } hash_of_addr = sctp_get_ifa_hash_val(&sctp_ifap->address.sa); @@ -754,9 +646,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifnp->ifa_count++; vrf->total_ifa_count++; atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifas), 1); - if (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); @@ -777,8 +666,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, */ SCTPDBG(SCTP_DEBUG_PCB4, "Lost an address change?\n"); /* Opps, must decrement the count */ - sctp_del_addr_from_vrf(vrf_id, addr, ifn_index, - if_name); + sctp_del_addr_from_vrf(vrf_id, addr, ifn, ifn_index); return (NULL); } SCTP_INCR_LADDR_COUNT(); @@ -803,16 +691,17 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, void sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, - uint32_t ifn_index, const char *if_name) + void *ifn, uint32_t ifn_index) { struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap = NULL; + struct sctp_ifa *sctp_ifap; SCTP_IPI_ADDR_WLOCK(); vrf = sctp_find_vrf(vrf_id); if (vrf == NULL) { SCTPDBG(SCTP_DEBUG_PCB4, "Can't find vrf_id 0x%x\n", vrf_id); - goto out_now; + SCTP_IPI_ADDR_WUNLOCK(); + return; } #ifdef SCTP_DEBUG @@ -820,31 +709,15 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr); #endif sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); - if (sctp_ifap) { + if (sctp_ifap != NULL) { /* Validate the delete */ if (sctp_ifap->ifn_p) { - int valid = 0; - /*- - * The name has priority over the ifn_index - * if its given. - */ - if (if_name) { - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) == 0) { - /* They match its a correct delete */ - valid = 1; - } - } - if (!valid) { - /* last ditch check ifn_index */ - if (ifn_index == sctp_ifap->ifn_p->ifn_index) { - valid = 1; - } - } - if (!valid) { - SCTPDBG(SCTP_DEBUG_PCB4, "ifn:%d ifname:%s does not match addresses\n", - ifn_index, ((if_name == NULL) ? "NULL" : if_name)); - SCTPDBG(SCTP_DEBUG_PCB4, "ifn:%d ifname:%s - ignoring delete\n", - sctp_ifap->ifn_p->ifn_index, sctp_ifap->ifn_p->ifn_name); + if (ifn_index != sctp_ifap->ifn_p->ifn_index || + ifn != sctp_ifap->ifn_p->ifn_p) { + SCTPDBG(SCTP_DEBUG_PCB4, "ifn:%d (%p) ifname:%s - ignoring delete\n", + sctp_ifap->ifn_p->ifn_index, + sctp_ifap->ifn_p->ifn_p, + sctp_ifap->ifn_p->ifn_name); SCTP_IPI_ADDR_WUNLOCK(); return; } @@ -866,13 +739,12 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, else { SCTPDBG(SCTP_DEBUG_PCB4, "Del Addr-ifn:%d Could not find address:", ifn_index); - SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr); + SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr); } #endif - out_now: SCTP_IPI_ADDR_WUNLOCK(); - if (sctp_ifap) { + if (sctp_ifap != NULL) { struct sctp_laddr *wi; wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); @@ -1813,10 +1685,6 @@ sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int struct sctp_tcb *stcb; uint32_t id; - if (inp == NULL) { - SCTP_PRINTF("TSNH ep_associd\n"); - return (NULL); - } if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { SCTP_PRINTF("TSNH ep_associd0\n"); return (NULL); @@ -2175,6 +2043,9 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp) struct sctppcbhead *head; struct sctp_inpcb *tinp, *ninp; + SCTP_INP_INFO_WLOCK_ASSERT(); + SCTP_INP_WLOCK_ASSERT(inp); + if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) { /* only works with port reuse on */ return (-1); @@ -2182,8 +2053,7 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp) if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { return (0); } - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_WLOCK(); + SCTP_INP_WUNLOCK(inp); head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(inp->sctp_lport, SCTP_BASE_INFO(hashmark))]; /* Kick out all non-listeners to the TCP hash */ @@ -2213,9 +2083,6 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp) inp->sctp_flags &= ~SCTP_PCB_FLAGS_IN_TCPPOOL; head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(inp->sctp_lport, SCTP_BASE_INFO(hashmark))]; LIST_INSERT_HEAD(head, inp, sctp_hash); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_RLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); return (0); } @@ -2791,7 +2658,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) #endif inp->sctp_associd_counter = 1; inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; - inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; + inp->sctp_frag_point = 0; inp->max_cwnd = 0; inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); inp->ecn_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_ecn_enable); @@ -2802,6 +2669,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) 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; + inp->rcv_edmid = SCTP_EDMID_NONE; #if defined(__FreeBSD__) && !defined(__Userspace__) inp->fibnum = so->so_fibnum; @@ -2922,9 +2790,10 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) SCTP_INP_INFO_WLOCK(); SCTP_INP_LOCK_INIT(inp); #if defined(__FreeBSD__) && !defined(__Userspace__) - INP_LOCK_INIT(&inp->ip_inp.inp, "inp", "sctpinp"); + rw_init_flags(&inp->ip_inp.inp.inp_lock, "sctpinp", + RW_RECURSE | RW_DUPOK); #endif - SCTP_INP_READ_INIT(inp); + SCTP_INP_READ_LOCK_INIT(inp); SCTP_ASOC_CREATE_LOCK_INIT(inp); /* lock the new ep */ SCTP_INP_WLOCK(inp); @@ -3055,6 +2924,25 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); +#if defined(__FreeBSD__) && !defined(__Userspace__) +#ifdef INET6 + if (old_inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + new_inp->ip_inp.inp.inp_flags |= old_inp->ip_inp.inp.inp_flags & INP_CONTROLOPTS; + if (old_inp->ip_inp.inp.in6p_outputopts) { + new_inp->ip_inp.inp.in6p_outputopts = ip6_copypktopts(old_inp->ip_inp.inp.in6p_outputopts, M_NOWAIT); + } + } +#endif +#if defined(INET) && defined(INET6) + else +#endif +#ifdef INET + { + new_inp->ip_inp.inp.inp_ip_tos = old_inp->ip_inp.inp.inp_ip_tos; + new_inp->ip_inp.inp.inp_ip_ttl = old_inp->ip_inp.inp.inp_ip_ttl; + } +#endif +#endif new_inp->sctp_ep.time_of_secret_change = old_inp->sctp_ep.time_of_secret_change; memcpy(new_inp->sctp_ep.secret_key, old_inp->sctp_ep.secret_key, @@ -3236,22 +3124,27 @@ sctp_remove_laddr(struct sctp_laddr *laddr) 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 */ +/* + * Bind the socket, with the PCB and global info locks held. Note, if a + * socket address is specified, the PCB lock may be dropped and re-acquired. + * + * sctp_ifap is used to bypass normal local address validation checks. + */ int #if defined(__FreeBSD__) && !defined(__Userspace__) -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, struct thread *p) +sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, struct thread *td) #elif defined(_WIN32) && !defined(__Userspace__) -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, PKTHREAD p) +sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, PKTHREAD p) #else -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, struct proc *p) +sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, struct proc *p) #endif { /* bind a ep to a socket address */ struct sctppcbhead *head; - struct sctp_inpcb *inp, *inp_tmp; + struct sctp_inpcb *inp_tmp; #if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) struct inpcb *ip_inp; #endif @@ -3264,12 +3157,20 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, int error; uint32_t vrf_id; +#if defined(__FreeBSD__) && !defined(__Userspace__) + KASSERT(td != NULL, ("%s: null thread", __func__)); + +#endif + error = 0; lport = 0; bindall = 1; - inp = (struct sctp_inpcb *)so->so_pcb; #if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) - ip_inp = (struct inpcb *)so->so_pcb; + ip_inp = &inp->ip_inp.inp; #endif + + SCTP_INP_INFO_WLOCK_ASSERT(); + SCTP_INP_WLOCK_ASSERT(inp); + #ifdef SCTP_DEBUG if (addr) { SCTPDBG(SCTP_DEBUG_PCB1, "Bind called port: %d\n", @@ -3279,16 +3180,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, } #endif if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { + error = EINVAL; /* already did a bind, subsequent binds NOT allowed ! */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INVARIANTS - if (p == NULL) - panic("null proc/thread"); -#endif -#endif if (addr != NULL) { switch (addr->sa_family) { #ifdef INET @@ -3298,13 +3194,15 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, /* IPV6_V6ONLY socket? */ if (SCTP_IPV6_V6ONLY(inp)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #ifdef HAVE_SA_LEN if (addr->sa_len != sizeof(*sin)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #endif @@ -3315,9 +3213,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, * For LOOPBACK the prison_local_ip4() call will transmute the ip address * to the proper value. */ - if (p && (error = prison_local_ip4(p->td_ucred, &sin->sin_addr)) != 0) { + if ((error = prison_local_ip4(td->td_ucred, &sin->sin_addr)) != 0) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - return (error); + goto out; } #endif if (sin->sin_addr.s_addr != INADDR_ANY) { @@ -3333,11 +3231,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)addr; - #ifdef HAVE_SA_LEN if (addr->sa_len != sizeof(*sin6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #endif lport = sin6->sin6_port; @@ -3346,10 +3244,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, * For LOOPBACK the prison_local_ip6() call will transmute the ipv6 address * to the proper value. */ - if (p && (error = prison_local_ip6(p->td_ucred, &sin6->sin6_addr, + if ((error = prison_local_ip6(td->td_ucred, &sin6->sin6_addr, (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - return (error); + goto out; } #endif if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { @@ -3358,8 +3256,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, /* KAME hack: embed scopeid */ #if defined(SCTP_KAME) if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #elif defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) @@ -3367,19 +3266,22 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, #else if (in6_embedscope(&sin6->sin6_addr, sin6, ip_inp, NULL, NULL) != 0) { #endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #elif defined(__FreeBSD__) && !defined(__Userspace__) error = scope6_check_id(sin6, MODULE_GLOBAL(ip6_use_defzone)); if (error != 0) { + error = EINVAL; SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - return (error); + goto out; } #else if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #endif #endif /* SCTP_EMBEDDED_V6_SCOPE */ @@ -3398,8 +3300,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, #ifdef HAVE_SA_LEN if (addr->sa_len != sizeof(struct sockaddr_conn)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #endif sconn = (struct sockaddr_conn *)addr; @@ -3411,17 +3314,14 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, } #endif default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EAFNOSUPPORT); - return (EAFNOSUPPORT); + error = EAFNOSUPPORT; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } } - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); /* Setup a vrf_id to be the default for the non-bind-all case. */ vrf_id = inp->def_vrf_id; - /* increase our count due to the unlock we do */ - SCTP_INP_INCR_REF(inp); if (lport) { /* * Did the caller specify a port? if so we must see if an ep @@ -3429,25 +3329,21 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, */ /* got to be root to get at low ports */ #if !(defined(_WIN32) && !defined(__Userspace__)) - if (ntohs(lport) < IPPORT_RESERVED) { - if ((p != NULL) && ((error = + if (ntohs(lport) < IPPORT_RESERVED && #if defined(__FreeBSD__) && !defined(__Userspace__) - priv_check(p, PRIV_NETINET_RESERVEDPORT) + (error = priv_check(td, PRIV_NETINET_RESERVEDPORT)) != 0) { #elif defined(__APPLE__) && !defined(__Userspace__) - suser(p->p_ucred, &p->p_acflag) -#elif defined(__Userspace__) /* must be true to use raw socket */ - 1 + (error = suser(p->p_ucred, &p->p_acflag)) != 0) { +#elif defined(__Userspace__) + /* TODO ensure uid is 0, etc... */ + 0) { #else - suser(p, 0) + (error = suser(p, 0)) != 0) { #endif - ) != 0)) { - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return (error); - } + goto out; } #endif + SCTP_INP_INCR_REF(inp); SCTP_INP_WUNLOCK(inp); if (bindall) { #ifdef SCTP_MVRF @@ -3474,10 +3370,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, port_reuse_active = 1; goto continue_anyway; } + SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); - return (EADDRINUSE); + error = EADDRINUSE; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #ifdef SCTP_MVRF } @@ -3500,14 +3397,16 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, port_reuse_active = 1; goto continue_anyway; } + SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); - return (EADDRINUSE); + error = EADDRINUSE; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } } continue_anyway: SCTP_INP_WLOCK(inp); + SCTP_INP_DECR_REF(inp); if (bindall) { /* verify that no lport is not used by a singleton */ if ((port_reuse_active == 0) && @@ -3517,54 +3416,41 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, (sctp_is_feature_on(inp_tmp, SCTP_PCB_FLAGS_PORTREUSE))) { port_reuse_active = 1; } else { - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); - return (EADDRINUSE); + error = EADDRINUSE; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } } } } else { uint16_t first, last, candidate; uint16_t count; - int done; -#if defined(_WIN32) && !defined(__Userspace__) +#if defined(__Userspace__) + first = MODULE_GLOBAL(ipport_firstauto); + last = MODULE_GLOBAL(ipport_lastauto); +#elif defined(_WIN32) first = 1; last = 0xffff; -#else -#if defined(__Userspace__) - /* TODO ensure uid is 0, etc... */ -#elif (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) +#elif defined(__FreeBSD__) || defined(__APPLE__) 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 = #if defined(__FreeBSD__) - priv_check(p, PRIV_NETINET_RESERVEDPORT) -#elif defined(__APPLE__) - suser(p->p_ucred, &p->p_acflag) + if ((error = priv_check(td, PRIV_NETINET_RESERVEDPORT)) != 0) { #else - suser(p, 0) + if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) { #endif - )) { - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - return (error); + goto out; } first = MODULE_GLOBAL(ipport_lowfirstauto); last = MODULE_GLOBAL(ipport_lowlastauto); } else { -#endif first = MODULE_GLOBAL(ipport_firstauto); last = MODULE_GLOBAL(ipport_lastauto); -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) } -#endif #endif if (first > last) { uint16_t temp; @@ -3576,8 +3462,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, count = last - first + 1; /* number of candidates */ candidate = first + sctp_select_initial_TSN(&inp->sctp_ep) % (count); - done = 0; - while (!done) { + for (;;) { #ifdef SCTP_MVRF for (i = 0; i < inp->num_vrfs; i++) { if (sctp_isport_inuse(inp, htons(candidate), inp->m_vrf_ids[i]) != NULL) { @@ -3585,40 +3470,35 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, } } if (i == inp->num_vrfs) { - done = 1; + lport = htons(candidate); + break; } #else if (sctp_isport_inuse(inp, htons(candidate), inp->def_vrf_id) == NULL) { - done = 1; + lport = htons(candidate); + break; } #endif - if (!done) { - if (--count == 0) { - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); - return (EADDRINUSE); - } - if (candidate == last) - candidate = first; - else - candidate = candidate + 1; + if (--count == 0) { + error = EADDRINUSE; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } + if (candidate == last) + candidate = first; + else + candidate = candidate + 1; } - lport = htons(candidate); } - SCTP_INP_DECR_REF(inp); if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { /* * this really should not happen. The guy did a non-blocking * bind and then did a close at the same time. */ - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } /* ok we look clear to give out this port, so lets setup the binding */ if (bindall) { @@ -3710,21 +3590,19 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, vrf_id, SCTP_ADDR_NOT_LOCKED); } if (ifa == NULL) { + error = EADDRNOTAVAIL; /* Can't find an interface with that address */ - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRNOTAVAIL); - return (EADDRNOTAVAIL); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } #ifdef INET6 if (addr->sa_family == AF_INET6) { /* GAK, more FIXME IFA lock? */ if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { /* Can't bind a non-existent addr. */ - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); + goto out; } } #endif @@ -3737,11 +3615,8 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, /* add this address to the endpoint list */ error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, 0); - if (error != 0) { - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return (error); - } + if (error != 0) + goto out; inp->laddr_count++; } /* find the bucket */ @@ -3760,10 +3635,39 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, inp->sctp_lport = lport; /* turn off just the unbound flag */ + KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) != 0, + ("%s: inp %p is already bound", __func__, inp)); inp->sctp_flags &= ~SCTP_PCB_FLAGS_UNBOUND; +out: + return (error); +} + +int +#if defined(__FreeBSD__) && !defined(__Userspace__) +sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, struct thread *td) +#elif defined(_WIN32) && !defined(__Userspace__) +sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, PKTHREAD p) +#else +sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, struct proc *p) +#endif +{ + struct sctp_inpcb *inp; + int error; + + inp = so->so_pcb; + SCTP_INP_INFO_WLOCK(); + SCTP_INP_WLOCK(inp); +#if defined(__FreeBSD__) && !defined(__Userspace__) + error = sctp_inpcb_bind_locked(inp, addr, sctp_ifap, td); +#else + error = sctp_inpcb_bind_locked(inp, addr, sctp_ifap, p); +#endif SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); - return (0); + return (error); } static void @@ -3847,7 +3751,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * freeing. a) Any local lists. b) Any associations. c) The hash of * all associations. d) finally the ep itself. */ - struct sctp_tcb *asoc, *nasoc; + struct sctp_tcb *stcb, *nstcb; struct sctp_laddr *laddr, *nladdr; struct inpcb *ip_pcb; struct socket *so; @@ -3871,19 +3775,15 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) /* mark any iterators on the list or being processed */ sctp_iterator_inp_being_freed(inp); SCTP_ITERATOR_UNLOCK(); - so = inp->sctp_socket; - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - /* been here before.. eeks.. get out of here */ - SCTP_PRINTF("This conflict in free SHOULD not be happening! from %d, imm %d\n", from, immediate); -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 1); -#endif - return; - } + SCTP_ASOC_CREATE_LOCK(inp); SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); + so = inp->sctp_socket; + KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) != 0, + ("%s: inp %p still has socket", __func__, inp)); + KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0, + ("%s: double free of inp %p", __func__, inp)); if (from == SCTP_CALLED_AFTER_CMPSET_OFCLOSE) { inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP; /* socket is gone, so no more wakeups allowed */ @@ -3910,124 +3810,122 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) int cnt_in_sd; cnt_in_sd = 0; - LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_list, sctp_tcblist, nasoc) { - SCTP_TCB_LOCK(asoc); - if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + LIST_FOREACH_SAFE(stcb, &inp->sctp_asoc_list, sctp_tcblist, nstcb) { + SCTP_TCB_LOCK(stcb); + /* Disconnect the socket please. */ + stcb->sctp_socket = NULL; + SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_CLOSED_SOCKET); + if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { /* Skip guys being freed */ cnt_in_sd++; - if (asoc->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { + if (stcb->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { /* * Special case - we did not start a kill * timer on the asoc due to it was not * closed. So go ahead and start it now. */ - SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_IN_ACCEPT_QUEUE); - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, asoc, NULL); + SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); + sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); } - SCTP_TCB_UNLOCK(asoc); + SCTP_TCB_UNLOCK(stcb); continue; } - 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 (((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || + (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) && + (stcb->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 * or connect/send/close. And it wants the data * to get across first. */ /* Just abandon things in the front states */ - if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, + if (sctp_free_assoc(inp, stcb, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) { cnt_in_sd++; } continue; } - /* Disconnect the socket please */ - asoc->sctp_socket = NULL; - 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) || - (so && (so->so_rcv.sb_cc > 0))) { + if ((stcb->asoc.size_on_reasm_queue > 0) || + (stcb->asoc.size_on_all_streams > 0) || + ((so != NULL) && (SCTP_SBAVAIL(&so->so_rcv) > 0))) { /* Left with Data unread */ 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; - sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3; + sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); - 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); } - if (sctp_free_assoc(inp, asoc, + if (sctp_free_assoc(inp, stcb, 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.ss_functions.sctp_ss_is_user_msgs_incomplete)(asoc, &asoc->asoc)) { + } else if (TAILQ_EMPTY(&stcb->asoc.send_queue) && + TAILQ_EMPTY(&stcb->asoc.sent_queue) && + (stcb->asoc.stream_queue_cnt == 0)) { + if ((*stcb->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, &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)) { struct sctp_nets *netp; /* * there is nothing queued to send, * so I send shutdown */ - 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_stop_timers_for_shutdown(asoc); - if (asoc->asoc.alternate) { - netp = asoc->asoc.alternate; + SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); + sctp_stop_timers_for_shutdown(stcb); + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; } else { - netp = asoc->asoc.primary_destination; + netp = stcb->asoc.primary_destination; } - sctp_send_shutdown(asoc, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc, + sctp_send_shutdown(stcb, netp); + sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, netp); - 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); + sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL); + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED); } } else { /* mark into shutdown pending */ - 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); + SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); + if ((*stcb->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, &stcb->asoc)) { + SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); } - if (TAILQ_EMPTY(&asoc->asoc.send_queue) && - TAILQ_EMPTY(&asoc->asoc.sent_queue) && - (asoc->asoc.state & SCTP_STATE_PARTIAL_MSG_LEFT)) { + if (TAILQ_EMPTY(&stcb->asoc.send_queue) && + TAILQ_EMPTY(&stcb->asoc.sent_queue) && + (stcb->asoc.state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 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; - sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5; + sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); - 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); } - if (sctp_free_assoc(inp, asoc, + if (sctp_free_assoc(inp, stcb, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_6) == 0) { cnt_in_sd++; } continue; } else { - sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); } } cnt_in_sd++; - SCTP_TCB_UNLOCK(asoc); + SCTP_TCB_UNLOCK(stcb); } /* now is there some left in our SHUTDOWN state? */ if (cnt_in_sd) { @@ -4042,8 +3940,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } } inp->sctp_socket = NULL; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) != - SCTP_PCB_FLAGS_UNBOUND) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { /* * ok, this guy has been bound. It's port is * somewhere in the SCTP_BASE_INFO(hash table). Remove @@ -4059,41 +3956,41 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * to die ... */ cnt = 0; - LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_list, sctp_tcblist, nasoc) { - SCTP_TCB_LOCK(asoc); + LIST_FOREACH_SAFE(stcb, &inp->sctp_asoc_list, sctp_tcblist, nstcb) { + SCTP_TCB_LOCK(stcb); if (immediate != SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE) { /* Disconnect the socket please */ - asoc->sctp_socket = NULL; - SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_CLOSED_SOCKET); + stcb->sctp_socket = NULL; + SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_CLOSED_SOCKET); } - if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - if (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); + if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + if (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); } cnt++; - SCTP_TCB_UNLOCK(asoc); + SCTP_TCB_UNLOCK(stcb); continue; } /* Free associations that are NOT killing us */ - if ((SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) && - ((asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) { + if ((SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) && + ((stcb->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; - sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_7; + sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); - } else if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + } else if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { cnt++; - SCTP_TCB_UNLOCK(asoc); + SCTP_TCB_UNLOCK(stcb); continue; } - 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); } - if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, + if (sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) { cnt++; } @@ -4141,7 +4038,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) sctp_log_closing(inp, NULL, 5); #endif #if !(defined(_WIN32) || defined(__Userspace__)) -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) +#if !(defined(__FreeBSD__) && !defined(__Userspace__)) rt = ip_pcb->inp_route.ro_rt; #endif #endif @@ -4158,7 +4055,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) TAILQ_REMOVE(&inp->read_queue, sq, next); sctp_free_remote_addr(sq->whoFrom); if (so) - so->so_rcv.sb_cc -= sq->length; + SCTP_SB_DECR(&so->so_rcv, sq->length); if (sq->data) { sctp_m_freem(sq->data); sq->data = NULL; @@ -4215,7 +4112,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) inp->ip_inp.inp.inp_state = INPCB_STATE_DEAD; if (in_pcb_checkstate(&inp->ip_inp.inp, WNT_STOPUSING, 1) != WNT_STOPUSING) { #ifdef INVARIANTS - panic("sctp_inpcb_free inp = %p couldn't set to STOPUSING\n", (void *)inp); + panic("sctp_inpcb_free inp = %p couldn't set to STOPUSING", (void *)inp); #else SCTP_PRINTF("sctp_inpcb_free inp = %p couldn't set to STOPUSING\n", (void *)inp); #endif @@ -4233,9 +4130,9 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) #ifdef SCTP_TRACK_FREED_ASOCS /* TEMP CODE */ - LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_free_list, sctp_tcblist, nasoc) { - LIST_REMOVE(asoc, sctp_tcblist); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), asoc); + LIST_FOREACH_SAFE(stcb, &inp->sctp_asoc_free_list, sctp_tcblist, nstcb) { + LIST_REMOVE(stcb, sctp_tcblist); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); SCTP_DECR_ASOC_COUNT(); } /* *** END TEMP CODE ****/ @@ -4254,7 +4151,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) INP_LOCK_DESTROY(&inp->ip_inp.inp); #endif SCTP_INP_LOCK_DESTROY(inp); - SCTP_INP_READ_DESTROY(inp); + SCTP_INP_READ_LOCK_DESTROY(inp); SCTP_ASOC_CREATE_LOCK_DESTROY(inp); #if !(defined(__APPLE__) && !defined(__Userspace__)) SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); @@ -4597,7 +4494,12 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, net->src_addr_selected = 1; /* Now get the interface MTU */ if (net->ro._s_addr->ifn_p != NULL) { - imtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p); + /* + * XXX: Should we here just use + * net->ro._s_addr->ifn_p->ifn_mtu + */ + imtu = SCTP_GATHER_MTU_FROM_IFN_INFO(net->ro._s_addr->ifn_p->ifn_p, + net->ro._s_addr->ifn_p->ifn_index); } else { imtu = 0; } @@ -4678,7 +4580,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) { - sctp_pathmtu_adjustment(stcb, net->mtu); + sctp_pathmtu_adjustment(stcb, net->mtu, true); } #ifdef INET6 #ifdef SCTP_EMBEDDED_V6_SCOPE @@ -4850,21 +4752,21 @@ sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb) * careful to add all additional addresses once they are know right away or * else the assoc will be may experience a blackout scenario. */ -struct sctp_tcb * -sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, - int *error, uint32_t override_tag, uint32_t vrf_id, - uint16_t o_streams, uint16_t port, +static struct sctp_tcb * +sctp_aloc_assoc_locked(struct sctp_inpcb *inp, struct sockaddr *firstaddr, + int *error, uint32_t override_tag, uint32_t initial_tsn, + uint32_t vrf_id, uint16_t o_streams, uint16_t port, #if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p, + struct thread *p, #elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p, + PKTHREAD p, #else #if defined(__Userspace__) - /* __Userspace__ NULL proc is going to be passed here. See sctp_lower_sosend */ + /* __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) + int initialize_auth_params) { /* note the p argument is only valid in unbound sockets */ @@ -4874,6 +4776,9 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, uint16_t rport; int err; + SCTP_INP_INFO_WLOCK_ASSERT(); + SCTP_INP_WLOCK_ASSERT(inp); + /* * Assumption made here: Caller has done a * sctp_findassociation_ep_addr(ep, addr's); to make sure the @@ -4890,7 +4795,11 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, *error = EINVAL; return (NULL); } - SCTP_INP_RLOCK(inp); + if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); + *error = EINVAL; + return (NULL); + } if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) || (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { @@ -4900,7 +4809,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, * sctp_aloc_assoc.. or the one-2-many socket. If a peeled * off, or connected one does this.. its an error. */ - SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); @@ -4909,7 +4817,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED)) { - SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); @@ -4953,19 +4860,17 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, sin = (struct sockaddr_in *)firstaddr; if ((ntohs(sin->sin_port) == 0) || - (sin->sin_addr.s_addr == INADDR_ANY) || - (sin->sin_addr.s_addr == INADDR_BROADCAST) || + in_broadcast(sin->sin_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) && + ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) || + ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && (SCTP_IPV6_V6ONLY(inp) != 0)))) { #else - (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) && + ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && (SCTP_IPV6_V6ONLY(inp) != 0))) { #endif /* Invalid address */ - SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); @@ -4985,7 +4890,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, 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); *error = EINVAL; return (NULL); @@ -5004,7 +4908,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, (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); *error = EINVAL; return (NULL); @@ -5015,18 +4918,16 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, #endif default: /* not supported family type */ - SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } - SCTP_INP_RUNLOCK(inp); if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { /* * 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, NULL, NULL, p))) { + if ((err = sctp_inpcb_bind_locked(inp, NULL, NULL, p))) { /* bind error, probably perm */ *error = err; return (NULL); @@ -5045,35 +4946,18 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, asoc = &stcb->asoc; 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, o_streams))) { + if ((err = sctp_init_asoc(inp, stcb, override_tag, initial_tsn, vrf_id, o_streams))) { /* failed */ SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_TCB_SEND_LOCK_DESTROY(stcb); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); SCTP_DECR_ASOC_COUNT(); *error = err; return (NULL); } - /* and the port */ - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); - if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - /* inpcb freed while alloc going on */ - SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_TCB_SEND_LOCK_DESTROY(stcb); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_DECR_ASOC_COUNT(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } SCTP_TCB_LOCK(stcb); asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb); @@ -5081,7 +4965,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, 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 (sctp_add_remote_addr(stcb, firstaddr, NULL, port, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC)) { /* failure.. memory error? */ @@ -5100,10 +4983,9 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, SCTP_DECR_ASOC_COUNT(); SCTP_TCB_UNLOCK(stcb); SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_TCB_SEND_LOCK_DESTROY(stcb); + LIST_REMOVE(stcb, sctp_asocs); LIST_REMOVE(stcb, sctp_tcbasocidhash); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_INP_WUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); *error = ENOBUFS; return (NULL); @@ -5126,11 +5008,69 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, 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); } +struct sctp_tcb * +sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, + int *error, uint32_t override_tag, uint32_t initial_tsn, + 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 + struct proc *p, +#endif + int initialize_auth_params) +{ + struct sctp_tcb *stcb; + + SCTP_INP_INFO_WLOCK(); + SCTP_INP_WLOCK(inp); + stcb = sctp_aloc_assoc_locked(inp, firstaddr, error, override_tag, + initial_tsn, vrf_id, o_streams, port, p, initialize_auth_params); + SCTP_INP_INFO_WUNLOCK(); + SCTP_INP_WUNLOCK(inp); + return (stcb); +} + +struct sctp_tcb * +sctp_aloc_assoc_connected(struct sctp_inpcb *inp, struct sockaddr *firstaddr, + int *error, uint32_t override_tag, uint32_t initial_tsn, + 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 + struct proc *p, +#endif + int initialize_auth_params) +{ + struct sctp_tcb *stcb; + + SCTP_INP_INFO_WLOCK(); + SCTP_INP_WLOCK(inp); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && + SCTP_IS_LISTENING(inp)) { + SCTP_INP_INFO_WUNLOCK(); + SCTP_INP_WUNLOCK(inp); + *error = EINVAL; + return (NULL); + } + stcb = sctp_aloc_assoc_locked(inp, firstaddr, error, override_tag, + initial_tsn, vrf_id, o_streams, port, p, initialize_auth_params); + SCTP_INP_INFO_WUNLOCK(); + if (stcb != NULL && (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { + inp->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; + soisconnecting(inp->sctp_socket); + } + SCTP_INP_WUNLOCK(inp); + return (stcb); +} + void sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net) { @@ -5181,6 +5121,10 @@ out: /* Clear net */ asoc->last_control_chunk_from = NULL; } + if (net == asoc->last_net_cmt_send_started) { + /* Clear net */ + asoc->last_net_cmt_send_started = NULL; + } if (net == stcb->asoc.alternate) { sctp_free_remote_addr(stcb->asoc.alternate); stcb->asoc.alternate = NULL; @@ -5233,99 +5177,70 @@ sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr) return (-2); } -void -sctp_delete_from_timewait(uint32_t tag, uint16_t lport, uint16_t rport) +static bool +sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport, time_t now) { struct sctpvtaghead *chain; struct sctp_tagblock *twait_block; - int found = 0; int i; + SCTP_INP_INFO_LOCK_ASSERT(); chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { - if ((twait_block->vtag_block[i].v_tag == tag) && - (twait_block->vtag_block[i].lport == lport) && - (twait_block->vtag_block[i].rport == rport)) { - twait_block->vtag_block[i].tv_sec_at_expire = 0; - twait_block->vtag_block[i].v_tag = 0; - twait_block->vtag_block[i].lport = 0; - twait_block->vtag_block[i].rport = 0; - found = 1; - break; - } - } - if (found) - break; - } -} - -int -sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport) -{ - struct sctpvtaghead *chain; - struct sctp_tagblock *twait_block; - int found = 0; - int i; - - SCTP_INP_INFO_WLOCK(); - chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; - LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { - for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { - if ((twait_block->vtag_block[i].v_tag == tag) && - (twait_block->vtag_block[i].lport == lport) && + if ((twait_block->vtag_block[i].tv_sec_at_expire >= now) && + (twait_block->vtag_block[i].v_tag == tag) && + (twait_block->vtag_block[i].lport == lport) && (twait_block->vtag_block[i].rport == rport)) { - found = 1; - break; + return (true); } } - if (found) - break; } - SCTP_INP_INFO_WUNLOCK(); - return (found); + return (false); } -void -sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport) +static void +sctp_set_vtag_block(struct sctp_timewait *vtag_block, time_t time, + uint32_t tag, uint16_t lport, uint16_t rport) +{ + vtag_block->tv_sec_at_expire = time; + vtag_block->v_tag = tag; + vtag_block->lport = lport; + vtag_block->rport = rport; +} + +static void +sctp_add_vtag_to_timewait(uint32_t tag, uint16_t lport, uint16_t rport) { struct sctpvtaghead *chain; struct sctp_tagblock *twait_block; struct timeval now; - int set, i; + time_t time; + int i; + bool set; - if (time == 0) { - /* Its disabled */ - return; - } + SCTP_INP_INFO_WLOCK_ASSERT(); (void)SCTP_GETTIME_TIMEVAL(&now); + time = now.tv_sec + SCTP_BASE_SYSCTL(sctp_vtag_time_wait); chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; - set = 0; + set = false; LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { /* Block(s) present, lets find space, and expire on the fly */ for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { - if ((twait_block->vtag_block[i].v_tag == 0) && - !set) { - twait_block->vtag_block[i].tv_sec_at_expire = - now.tv_sec + time; - twait_block->vtag_block[i].v_tag = tag; - twait_block->vtag_block[i].lport = lport; - twait_block->vtag_block[i].rport = rport; - set = 1; - } else if ((twait_block->vtag_block[i].v_tag) && - ((long)twait_block->vtag_block[i].tv_sec_at_expire < now.tv_sec)) { - /* Audit expires this guy */ - twait_block->vtag_block[i].tv_sec_at_expire = 0; - twait_block->vtag_block[i].v_tag = 0; - twait_block->vtag_block[i].lport = 0; - twait_block->vtag_block[i].rport = 0; - if (set == 0) { - /* Reuse it for my new tag */ - twait_block->vtag_block[i].tv_sec_at_expire = now.tv_sec + time; - twait_block->vtag_block[i].v_tag = tag; - twait_block->vtag_block[i].lport = lport; - twait_block->vtag_block[i].rport = rport; - set = 1; + if ((twait_block->vtag_block[i].v_tag == 0) && !set) { + sctp_set_vtag_block(twait_block->vtag_block + i, time, tag, lport, rport); + set = true; + continue; + } + if ((twait_block->vtag_block[i].v_tag != 0) && + (twait_block->vtag_block[i].tv_sec_at_expire < now.tv_sec)) { + if (set) { + /* Audit expires this guy */ + sctp_set_vtag_block(twait_block->vtag_block + i, 0, 0, 0, 0); + } else { + /* Reuse it for the new tag */ + sctp_set_vtag_block(twait_block->vtag_block + i, time, tag, lport, rport); + set = true; } } } @@ -5346,10 +5261,7 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t } memset(twait_block, 0, sizeof(struct sctp_tagblock)); LIST_INSERT_HEAD(chain, twait_block, sctp_nxt_tagblock); - twait_block->vtag_block[0].tv_sec_at_expire = now.tv_sec + time; - twait_block->vtag_block[0].v_tag = tag; - twait_block->vtag_block[0].lport = lport; - twait_block->vtag_block[0].rport = rport; + sctp_set_vtag_block(twait_block->vtag_block, time, tag, lport, rport); } } @@ -5422,6 +5334,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre #if defined(__APPLE__) && !defined(__Userspace__) sctp_lock_assert(SCTP_INP_SO(inp)); #endif + SCTP_TCB_LOCK_ASSERT(stcb); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 6); @@ -5433,7 +5346,6 @@ 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; @@ -5470,7 +5382,6 @@ 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); @@ -5492,28 +5403,19 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre * will be now. */ if (sq->end_added == 0) { - /* Held for PD-API clear that. */ + /* Held for PD-API, clear that. */ sq->pdapi_aborted = 1; sq->held_length = 0; if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) { - /* - * Need to add a PD-API aborted indication. - * Setting the control_pdapi assures that it will - * be added right after this msg. - */ - uint32_t strseq; - stcb->asoc.control_pdapi = sq; - strseq = (sq->sinfo_stream << 16) | (sq->mid & 0x0000ffff); sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, stcb, SCTP_PARTIAL_DELIVERY_ABORTED, - (void *)&strseq, + (void *)sq, SCTP_SO_LOCKED); - stcb->asoc.control_pdapi = NULL; } + /* Add an end to wake them */ + sq->end_added = 1; } - /* Add an end to wake them */ - sq->end_added = 1; } } SCTP_INP_READ_UNLOCK(inp); @@ -5526,14 +5428,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre if ((stcb->asoc.refcnt) || (stcb->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE)) { /* Someone holds a reference OR the socket is unaccepted yet. */ - if ((stcb->asoc.refcnt) || + if ((stcb->asoc.refcnt) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 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)) /* nothing around */ @@ -5543,6 +5443,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sctp_sorwakeup(inp, so); sctp_sowwakeup(inp, so); } + SCTP_TCB_UNLOCK(stcb); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 9); @@ -5571,12 +5472,10 @@ 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) || @@ -5597,7 +5496,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SOCKBUF_LOCK(&so->so_rcv); so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING | +#if !(defined(__FreeBSD__) && !defined(__Userspace__)) SS_ISCONFIRMING | +#endif SS_ISCONNECTED); so->so_state |= SS_ISDISCONNECTED; #if defined(__APPLE__) && !defined(__Userspace__) @@ -5618,7 +5519,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre */ /* re-increment the lock */ if (from_inpcbfree == SCTP_NORMAL_PROC) { - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); } if (stcb->asoc.refcnt) { SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); @@ -5627,7 +5528,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_INP_INFO_WUNLOCK(); SCTP_INP_WUNLOCK(inp); } - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); return (0); } @@ -5638,6 +5538,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre if (stcb->asoc.in_asocid_hash) { LIST_REMOVE(stcb, sctp_tcbasocidhash); } + if (inp->sctp_socket == NULL) { + stcb->sctp_socket = NULL; + } /* Now lets remove it from the list of ALL associations in the EP */ LIST_REMOVE(stcb, sctp_tcblist); if (from_inpcbfree == SCTP_NORMAL_PROC) { @@ -5646,8 +5549,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } /* pull from vtag hash */ LIST_REMOVE(stcb, sctp_asocs); - sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_BASE_SYSCTL(sctp_vtag_time_wait), - inp->sctp_lport, stcb->rport); + sctp_add_vtag_to_timewait(asoc->my_vtag, inp->sctp_lport, stcb->rport); /* Now restop the timers to be sure * this is paranoia at is finest! @@ -5667,7 +5569,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre 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); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp); sctp_free_spbufspace(stcb, asoc, sp); if (sp->data) { if (so) { @@ -5890,10 +5792,8 @@ 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); if (from_inpcbfree == SCTP_NORMAL_PROC) { SCTP_INP_INFO_WUNLOCK(); SCTP_INP_RLOCK(inp); @@ -6449,7 +6349,7 @@ sctp_startup_mcore_threads(void) (void)kproc_create(sctp_mcore_thread, (void *)&sctp_mcore_workers[cpu], &sctp_mcore_workers[cpu].thread_proc, - RFPROC, + 0, SCTP_KTHREAD_PAGES, SCTP_MCORE_NAME); } @@ -6490,6 +6390,13 @@ sctp_netisr_hdlr(struct mbuf *m, uintptr_t source) } #endif +#endif +#if defined(__FreeBSD__) && !defined(__Userspace__) +#define VALIDATE_LOADER_TUNABLE(var_name, prefix) \ + if (SCTP_BASE_SYSCTL(var_name) < prefix##_MIN || \ + SCTP_BASE_SYSCTL(var_name) > prefix##_MAX) \ + SCTP_BASE_SYSCTL(var_name) = prefix##_DEFAULT + #endif void #if defined(__Userspace__) @@ -6514,6 +6421,7 @@ sctp_pcb_init(void) #if defined(SCTP_PROCESS_LEVEL_LOCKS) #if !defined(_WIN32) pthread_mutexattr_init(&SCTP_BASE_VAR(mtx_attr)); + pthread_rwlockattr_init(&SCTP_BASE_VAR(rwlock_attr)); #ifdef INVARIANTS pthread_mutexattr_settype(&SCTP_BASE_VAR(mtx_attr), PTHREAD_MUTEX_ERRORCHECK); #endif @@ -6581,6 +6489,9 @@ sctp_pcb_init(void) 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)); + VALIDATE_LOADER_TUNABLE(sctp_hashtblsize, SCTPCTL_TCBHASHSIZE); + VALIDATE_LOADER_TUNABLE(sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE); + VALIDATE_LOADER_TUNABLE(sctp_chunkscale, SCTPCTL_CHUNKSCALE); #endif SCTP_BASE_INFO(sctp_asochash) = SCTP_HASH_INIT((SCTP_BASE_SYSCTL(sctp_hashtblsize) * 31), &SCTP_BASE_INFO(hashasocmark)); @@ -6784,6 +6695,7 @@ sctp_pcb_finish(void) #else pthread_cond_destroy(&sctp_it_ctl.iterator_wakeup); pthread_mutexattr_destroy(&SCTP_BASE_VAR(mtx_attr)); + pthread_rwlockattr_destroy(&SCTP_BASE_VAR(rwlock_attr)); #endif #endif /* In FreeBSD the iterator thread never exits @@ -7041,7 +6953,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, inp = stcb->sctp_ep; atomic_add_int(&stcb->asoc.refcnt, 1); stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net_tmp, dst, stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || inp == NULL) { /* we must add the source address */ @@ -7125,8 +7037,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* Skip multi-cast addresses */ goto next_param; } - if ((sin.sin_addr.s_addr == INADDR_BROADCAST) || - (sin.sin_addr.s_addr == INADDR_ANY)) { + if (in_broadcast(sin.sin_addr)) { goto next_param; } sa = (struct sockaddr *)&sin; @@ -7134,7 +7045,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, atomic_add_int(&stcb->asoc.refcnt, 1); stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, dst, stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || inp == NULL) { @@ -7182,7 +7093,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), msg); sctp_abort_an_association(stcb_tmp->sctp_ep, - stcb_tmp, op_err, + stcb_tmp, op_err, false, SCTP_SO_NOT_LOCKED); goto add_it_now; } @@ -7227,7 +7138,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, atomic_add_int(&stcb->asoc.refcnt, 1); stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, dst, stcb); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); if (stcb_tmp == NULL && (inp == stcb->sctp_ep || inp == NULL)) { /* @@ -7276,7 +7187,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), msg); sctp_abort_an_association(stcb_tmp->sctp_ep, - stcb_tmp, op_err, + stcb_tmp, op_err, false, SCTP_SO_NOT_LOCKED); goto add_it_now6; } @@ -7371,6 +7282,24 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } else if (ptype == SCTP_PRSCTP_SUPPORTED) { /* Peer supports pr-sctp */ peer_supports_prsctp = 1; + } else if (ptype == SCTP_ZERO_CHECKSUM_ACCEPTABLE) { + struct sctp_zero_checksum_acceptable zero_chksum, *zero_chksum_p; + + phdr = sctp_get_next_param(m, offset, + (struct sctp_paramhdr *)&zero_chksum, + sizeof(struct sctp_zero_checksum_acceptable)); + if (phdr != NULL) { + /* + * Only send zero checksums if the upper layer + * has enabled the support for the same method + * as allowed by the peer. + */ + zero_chksum_p = (struct sctp_zero_checksum_acceptable *)phdr; + if ((ntohl(zero_chksum_p->edmid) != SCTP_EDMID_NONE) && + (ntohl(zero_chksum_p->edmid) == stcb->asoc.rcv_edmid)) { + stcb->asoc.snd_edmid = stcb->asoc.rcv_edmid; + } + } } else if (ptype == SCTP_SUPPORTED_CHUNK_EXT) { /* A supported extension chunk */ struct sctp_supported_chunk_types_param *pr_supported; @@ -7529,7 +7458,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, break; } phdr = sctp_get_next_param(m, offset, ¶m_buf, - sizeof(param_buf)); + sizeof(param_buf)); } /* Now check to see if we need to purge any addresses */ TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) { @@ -7539,11 +7468,15 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* remove and free it */ stcb->asoc.numnets--; TAILQ_REMOVE(&stcb->asoc.nets, net, sctp_next); - sctp_free_remote_addr(net); + if (net == stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } if (net == stcb->asoc.primary_destination) { stcb->asoc.primary_destination = NULL; sctp_select_primary_destination(stcb); } + sctp_free_remote_addr(net); } } if ((stcb->asoc.ecn_supported == 1) && @@ -7578,7 +7511,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, stcb->asoc.nrsack_supported = 0; } if ((stcb->asoc.pktdrop_supported == 1) && - (peer_supports_pktdrop == 0)){ + (peer_supports_pktdrop == 0)) { stcb->asoc.pktdrop_supported = 0; } /* validate authentication required parameters */ @@ -7651,7 +7584,8 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa, return (0); } stcb->asoc.primary_destination = net; - if (!(net->dest_state & SCTP_ADDR_PF) && (stcb->asoc.alternate)) { + if (((net->dest_state & SCTP_ADDR_PF) == 0) && + (stcb->asoc.alternate != NULL)) { sctp_free_remote_addr(stcb->asoc.alternate); stcb->asoc.alternate = NULL; } @@ -7669,24 +7603,15 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa, } } -int +bool sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now) { - /* - * This function serves two purposes. It will see if a TAG can be - * re-used and return 1 for yes it is ok and 0 for don't use that - * tag. A secondary function it will do is purge out old tags that - * can be removed. - */ - struct sctpvtaghead *chain; - struct sctp_tagblock *twait_block; struct sctpasochead *head; struct sctp_tcb *stcb; - int i; - SCTP_INP_INFO_RLOCK(); - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, - SCTP_BASE_INFO(hashasocmark))]; + SCTP_INP_INFO_LOCK_ASSERT(); + + head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, SCTP_BASE_INFO(hashasocmark))]; LIST_FOREACH(stcb, head, sctp_asocs) { /* We choose not to lock anything here. TCB's can't be * removed since we have the read lock, so they can't @@ -7705,40 +7630,11 @@ sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval * if (stcb->sctp_ep->sctp_lport != lport) { continue; } - /* Its a used tag set */ - SCTP_INP_INFO_RUNLOCK(); - return (0); + /* The tag is currently used, so don't use it. */ + return (false); } } - chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; - /* Now what about timed wait ? */ - LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { - /* - * Block(s) are present, lets see if we have this tag in the - * list - */ - for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { - if (twait_block->vtag_block[i].v_tag == 0) { - /* not used */ - continue; - } else if ((long)twait_block->vtag_block[i].tv_sec_at_expire < - now->tv_sec) { - /* Audit expires this guy */ - twait_block->vtag_block[i].tv_sec_at_expire = 0; - twait_block->vtag_block[i].v_tag = 0; - twait_block->vtag_block[i].lport = 0; - twait_block->vtag_block[i].rport = 0; - } else if ((twait_block->vtag_block[i].v_tag == tag) && - (twait_block->vtag_block[i].lport == lport) && - (twait_block->vtag_block[i].rport == rport)) { - /* Bad tag, sorry :< */ - SCTP_INP_INFO_RUNLOCK(); - return (0); - } - } - } - SCTP_INP_INFO_RUNLOCK(); - return (1); + return (!sctp_is_in_timewait(tag, lport, rport, now->tv_sec)); } static void @@ -7942,16 +7838,19 @@ sctp_drain_mbufs(struct sctp_tcb *stcb) */ } -void -sctp_drain() -{ - /* - * We must walk the PCB lists for ALL associations here. The system - * is LOW on MBUF's and needs help. This is where reneging will - * occur. We really hope this does NOT happen! - */ #if defined(__FreeBSD__) && !defined(__Userspace__) +static void +sctp_drain(void *arg __unused, int flags __unused) +#else +void +sctp_drain(void) +#endif +{ +#if defined(__FreeBSD__) && !defined(__Userspace__) + struct epoch_tracker et; VNET_ITERATOR_DECL(vnet_iter); + + NET_EPOCH_ENTER(et); #else struct sctp_inpcb *inp; struct sctp_tcb *stcb; @@ -7961,6 +7860,11 @@ sctp_drain() return; } #endif + /* + * We must walk the PCB lists for ALL associations here. The system + * is LOW on MBUF's and needs help. This is where reneging will + * occur. We really hope this does NOT happen! + */ #if defined(__FreeBSD__) && !defined(__Userspace__) VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { @@ -7975,6 +7879,7 @@ sctp_drain() #ifdef VIMAGE continue; #else + NET_EPOCH_EXIT(et); return; #endif } @@ -7996,8 +7901,13 @@ sctp_drain() CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); + NET_EPOCH_EXIT(et); #endif } +#if defined(__FreeBSD__) && !defined(__Userspace__) +EVENTHANDLER_DEFINE(vm_lowmem, sctp_drain, NULL, LOWMEM_PRI_DEFAULT); +EVENTHANDLER_DEFINE(mbuf_lowmem, sctp_drain, NULL, LOWMEM_PRI_DEFAULT); +#endif /* * start a new iterator @@ -8085,3 +7995,18 @@ sctp_initiate_iterator(inp_func inpf, /* sa_ignore MEMLEAK {memory is put on the tailq for the iterator} */ return (0); } + +/* + * Atomically add flags to the sctp_flags of an inp. + * To be used when the write lock of the inp is not held. + */ +void +sctp_pcb_add_flags(struct sctp_inpcb *inp, uint32_t flags) +{ + uint32_t old_flags, new_flags; + + do { + old_flags = inp->sctp_flags; + new_flags = old_flags | flags; + } while (atomic_cmpset_int(&inp->sctp_flags, old_flags, new_flags) == 0); +} diff --git a/netwerk/sctp/src/netinet/sctp_pcb.h b/netwerk/sctp/src/netinet/sctp_pcb.h index 0382430d22..3d893bc436 100644 --- a/netwerk/sctp/src/netinet/sctp_pcb.h +++ b/netwerk/sctp/src/netinet/sctp_pcb.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_PCB_H_ #define _NETINET_SCTP_PCB_H_ @@ -136,10 +131,10 @@ struct sctp_block_entry { }; struct sctp_timewait { - uint32_t tv_sec_at_expire; /* the seconds from boot to expire */ - uint32_t v_tag; /* the vtag that can not be reused */ - uint16_t lport; /* the local port used in vtag */ - uint16_t rport; /* the remote port used in vtag */ + time_t tv_sec_at_expire; /* the seconds from boot to expire */ + uint32_t v_tag; /* the vtag that can not be reused */ + uint16_t lport; /* the local port used in vtag */ + uint16_t rport; /* the remote port used in vtag */ }; struct sctp_tagblock { @@ -210,8 +205,8 @@ struct sctp_epinfo { struct mtx ipi_pktlog_mtx; struct mtx wq_addr_mtx; #elif defined(SCTP_PROCESS_LEVEL_LOCKS) - userland_mutex_t ipi_ep_mtx; - userland_mutex_t ipi_addr_mtx; + userland_rwlock_t ipi_ep_mtx; + userland_rwlock_t ipi_addr_mtx; userland_mutex_t ipi_count_mtx; userland_mutex_t ipi_pktlog_mtx; userland_mutex_t wq_addr_mtx; @@ -312,6 +307,7 @@ struct sctp_base_info { int timer_thread_started; #if !defined(_WIN32) pthread_mutexattr_t mtx_attr; + pthread_rwlockattr_t rwlock_attr; #if defined(INET) || defined(INET6) int userspace_route; userland_thread_t recvthreadroute; @@ -351,8 +347,8 @@ struct sctp_base_info { * access /dev/random. */ struct sctp_pcb { - unsigned int time_of_secret_change; /* number of seconds from - * timeval.tv_sec */ + time_t time_of_secret_change; /* number of seconds from + * timeval.tv_sec */ uint32_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_NUMBER_OF_SECRETS]; unsigned int size_of_a_cookie; @@ -481,7 +477,6 @@ struct sctp_inpcb { #ifdef SCTP_TRACK_FREED_ASOCS struct sctpasochead sctp_asoc_free_list; #endif - struct sctp_iterator *inp_starting_point_for_iterator; uint32_t sctp_frag_point; uint32_t partial_delivery_point; uint32_t sctp_context; @@ -496,6 +491,7 @@ struct sctp_inpcb { uint8_t reconfig_supported; uint8_t nrsack_supported; uint8_t pktdrop_supported; + uint8_t rcv_edmid; struct sctp_nonpad_sndrcvinfo def_send; /*- * These three are here for the sosend_dgram @@ -617,16 +613,12 @@ struct sctp_tcb { uint16_t resv; #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__) && !defined(__Userspace__) lck_mtx_t* tcb_mtx; - lck_mtx_t* tcb_send_mtx; #elif defined(_WIN32) && !defined(__Userspace__) struct spinlock tcb_lock; - struct spinlock tcb_send_lock; #elif defined(__Userspace__) #endif #if defined(__APPLE__) && !defined(__Userspace__) @@ -689,18 +681,6 @@ struct sctp_vrf *sctp_allocate_vrf(int vrfid); struct sctp_vrf *sctp_find_vrf(uint32_t vrfid); void sctp_free_vrf(struct sctp_vrf *vrf); -/*- - * Change address state, can be used if - * O/S supports telling transports about - * changes to IFA/IFN's (link layer triggers). - * If a ifn goes down, we will do src-addr-selection - * and NOT use that, as a source address. This does - * not stop the routing system from routing out - * that interface, but we won't put it as a source. - */ -void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); -void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); - struct sctp_ifa * sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index, uint32_t ifn_type, @@ -708,28 +688,37 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add); -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); + void *ifn, uint32_t ifn_index); 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__) && !defined(__Userspace__) -int sctp_inpcb_bind(struct socket *, struct sockaddr *, - struct sctp_ifa *,struct thread *); +int +sctp_inpcb_bind(struct socket *, struct sockaddr *, + struct sctp_ifa *, struct thread *); +int +sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *, + struct sctp_ifa *, struct thread *); #elif defined(_WIN32) && !defined(__Userspace__) -int sctp_inpcb_bind(struct socket *, struct sockaddr *, - struct sctp_ifa *,PKTHREAD); +int +sctp_inpcb_bind(struct socket *, struct sockaddr *, + struct sctp_ifa *, PKTHREAD); +int +sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *, + struct sctp_ifa *, PKTHREAD); #else /* struct proc is a dummy for __Userspace__ */ -int sctp_inpcb_bind(struct socket *, struct sockaddr *, - struct sctp_ifa *, struct proc *); +int +sctp_inpcb_bind(struct socket *, struct sockaddr *, + struct sctp_ifa *, struct proc *); +int +sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *, + struct sctp_ifa *, struct proc *); #endif struct sctp_tcb * @@ -780,29 +769,31 @@ void sctp_inpcb_free(struct sctp_inpcb *, int, int); #if defined(__FreeBSD__) && !defined(__Userspace__) struct sctp_tcb * sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, - int *, uint32_t, uint32_t, uint16_t, uint16_t, struct thread *, - int); + int *, uint32_t, uint32_t, uint32_t, uint16_t, uint16_t, + struct thread *, int); +struct sctp_tcb * +sctp_aloc_assoc_connected(struct sctp_inpcb *, struct sockaddr *, + int *, uint32_t, 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, uint16_t, uint16_t, PKTHREAD, int); +sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, + uint32_t, uint32_t, uint16_t, uint16_t, PKTHREAD, int); +struct sctp_tcb * +sctp_aloc_assoc_connected(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, + 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, uint16_t, uint16_t, struct proc *, - int); +sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, + uint32_t, uint32_t, uint16_t, uint16_t, struct proc *, int); +struct sctp_tcb * +sctp_aloc_assoc_connected(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, + 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); - -void -sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport); - void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t); void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *); @@ -832,9 +823,8 @@ int sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets *); -int sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *); - -/* void sctp_drain(void); */ +bool +sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *); int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *); @@ -842,6 +832,9 @@ int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp); void sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh); +void +sctp_pcb_add_flags(struct sctp_inpcb *, uint32_t); + /*- * 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. diff --git a/netwerk/sctp/src/netinet/sctp_peeloff.c b/netwerk/sctp/src/netinet/sctp_peeloff.c index 8581f515f4..2e74db048b 100644 --- a/netwerk/sctp/src/netinet/sctp_peeloff.c +++ b/netwerk/sctp/src/netinet/sctp_peeloff.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.c 362054 2020-06-11 13:34:09Z tuexen $"); -#endif - #include #include #include @@ -134,7 +129,6 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) n_inp->sctp_context = inp->sctp_context; n_inp->max_cwnd = inp->max_cwnd; n_inp->local_strreset_support = inp->local_strreset_support; - n_inp->inp_starting_point_for_iterator = NULL; /* copy in the authentication parameters from the original endpoint */ if (n_inp->sctp_ep.local_hmacs) sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs); diff --git a/netwerk/sctp/src/netinet/sctp_peeloff.h b/netwerk/sctp/src/netinet/sctp_peeloff.h index 7e1c5eceeb..3011fa3517 100644 --- a/netwerk/sctp/src/netinet/sctp_peeloff.h +++ b/netwerk/sctp/src/netinet/sctp_peeloff.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.h 309607 2016-12-06 10:21:25Z tuexen $"); -#endif - #ifndef _NETINET_SCTP_PEELOFF_H_ #define _NETINET_SCTP_PEELOFF_H_ #if defined(HAVE_SCTP_PEELOFF_SOCKOPT) diff --git a/netwerk/sctp/src/netinet/sctp_process_lock.h b/netwerk/sctp/src/netinet/sctp_process_lock.h index ff0e05048e..feaa2c6acd 100644 --- a/netwerk/sctp/src/netinet/sctp_process_lock.h +++ b/netwerk/sctp/src/netinet/sctp_process_lock.h @@ -60,6 +60,9 @@ #define SCTP_INP_INFO_RUNLOCK() #define SCTP_INP_INFO_WLOCK() #define SCTP_INP_INFO_WUNLOCK() +#define SCTP_INP_INFO_LOCK_ASSERT() +#define SCTP_INP_INFO_RLOCK_ASSERT() +#define SCTP_INP_INFO_WLOCK_ASSERT() #define SCTP_INP_INFO_LOCK_DESTROY() #define SCTP_IPI_COUNT_INIT() #define SCTP_IPI_COUNT_DESTROY() @@ -69,16 +72,14 @@ #define SCTP_INP_INFO_RUNLOCK() #define SCTP_INP_INFO_WLOCK() #define SCTP_INP_INFO_WUNLOCK() +#define SCTP_INP_INFO_LOCK_ASSERT() +#define SCTP_INP_INFO_RLOCK_ASSERT() +#define SCTP_INP_INFO_WLOCK_ASSERT() #define SCTP_INP_INFO_LOCK_DESTROY() #define SCTP_IPI_COUNT_INIT() #define SCTP_IPI_COUNT_DESTROY() #endif -#define SCTP_TCB_SEND_LOCK_INIT(_tcb) -#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) -#define SCTP_TCB_SEND_LOCK(_tcb) -#define SCTP_TCB_SEND_UNLOCK(_tcb) - /* Lock for INP */ #define SCTP_INP_LOCK_INIT(_inp) #define SCTP_INP_LOCK_DESTROY(_inp) @@ -97,10 +98,11 @@ #define SCTP_ASOC_CREATE_LOCK(_inp) #define SCTP_ASOC_CREATE_UNLOCK(_inp) -#define SCTP_INP_READ_INIT(_inp) -#define SCTP_INP_READ_DESTROY(_inp) +#define SCTP_INP_READ_LOCK_INIT(_inp) +#define SCTP_INP_READ_LOCK_DESTROY(_inp) #define SCTP_INP_READ_LOCK(_inp) #define SCTP_INP_READ_UNLOCK(_inp) +#define SCTP_INP_READ_LOCK_ASSERT(_inp) /* Lock for TCB */ #define SCTP_TCB_LOCK_INIT(_tcb) @@ -128,6 +130,7 @@ LeaveCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx)) #define SCTP_WQ_ADDR_LOCK_ASSERT() +#if WINVER < 0x0600 #define SCTP_INP_INFO_LOCK_INIT() \ InitializeCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_LOCK_DESTROY() \ @@ -142,6 +145,27 @@ LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_WUNLOCK() \ LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_LOCK_ASSERT() +#define SCTP_INP_INFO_RLOCK_ASSERT() +#define SCTP_INP_INFO_WLOCK_ASSERT() +#else +#define SCTP_INP_INFO_LOCK_INIT() \ + InitializeSRWLock(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_LOCK_DESTROY() +#define SCTP_INP_INFO_RLOCK() \ + AcquireSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_TRYLOCK() \ + TryAcquireSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_WLOCK() \ + AcquireSRWLockExclusive(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_RUNLOCK() \ + ReleaseSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_WUNLOCK() \ + ReleaseSRWLockExclusive(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_LOCK_ASSERT() +#define SCTP_INP_INFO_RLOCK_ASSERT() +#define SCTP_INP_INFO_WLOCK_ASSERT() +#endif #define SCTP_IP_PKTLOG_INIT() \ InitializeCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx)) @@ -157,14 +181,15 @@ * we want to change something at the endpoint level for example random_store * or cookie secrets we lock the INP level. */ -#define SCTP_INP_READ_INIT(_inp) \ +#define SCTP_INP_READ_LOCK_INIT(_inp) \ InitializeCriticalSection(&(_inp)->inp_rdata_mtx) -#define SCTP_INP_READ_DESTROY(_inp) \ +#define SCTP_INP_READ_LOCK_DESTROY(_inp) \ DeleteCriticalSection(&(_inp)->inp_rdata_mtx) #define SCTP_INP_READ_LOCK(_inp) \ EnterCriticalSection(&(_inp)->inp_rdata_mtx) #define SCTP_INP_READ_UNLOCK(_inp) \ LeaveCriticalSection(&(_inp)->inp_rdata_mtx) +#define SCTP_INP_READ_LOCK_ASSERT(_inp) #define SCTP_INP_LOCK_INIT(_inp) \ InitializeCriticalSection(&(_inp)->inp_mtx) @@ -190,17 +215,8 @@ #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) \ - 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_INP_DECR_REF(_inp) atomic_subtract_int(&((_inp)->refcount), 1) #define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \ InitializeCriticalSection(&(_inp)->inp_create_mtx) @@ -258,9 +274,9 @@ (void)pthread_mutex_destroy(&SCTP_BASE_INFO(wq_addr_mtx)) #ifdef INVARIANTS #define SCTP_WQ_ADDR_LOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s: wq_addr_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s:%d: wq_addr_mtx already locked", __FILE__, __LINE__)) #define SCTP_WQ_ADDR_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s: wq_addr_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s:%d: wq_addr_mtx not locked", __FILE__, __LINE__)) #else #define SCTP_WQ_ADDR_LOCK() \ (void)pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) @@ -268,33 +284,36 @@ (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__)) + KASSERT(pthread_mutex_trylock(&SCTP_BASE_INFO(wq_addr_mtx)) == EBUSY, ("%s:%d: wq_addr_mtx not locked", __FILE__, __LINE__)) #define SCTP_INP_INFO_LOCK_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_ep_mtx), &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_rwlock_init(&SCTP_BASE_INFO(ipi_ep_mtx), &SCTP_BASE_VAR(rwlock_attr)) #define SCTP_INP_INFO_LOCK_DESTROY() \ - (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_ep_mtx)) + (void)pthread_rwlock_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__)) + KASSERT(pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s%d: ipi_ep_mtx already locked", __FILE__, __LINE__)) #define SCTP_INP_INFO_WLOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx already locked", __func__)) + KASSERT(pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s:%d: ipi_ep_mtx already locked", __FILE__, __LINE__)) #define SCTP_INP_INFO_RUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx not locked", __func__)) + KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s:%d: ipi_ep_mtx not locked", __FILE__, __LINE__)) #define SCTP_INP_INFO_WUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx not locked", __func__)) + KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s:%d: ipi_ep_mtx not locked", __FILE__, __LINE__)) #else #define SCTP_INP_INFO_RLOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) + (void)pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_WLOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) + (void)pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_RUNLOCK() \ - (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) + (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_WUNLOCK() \ - (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) + (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) #endif +#define SCTP_INP_INFO_LOCK_ASSERT() +#define SCTP_INP_INFO_RLOCK_ASSERT() +#define SCTP_INP_INFO_WLOCK_ASSERT() #define SCTP_INP_INFO_TRYLOCK() \ - (!(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_ep_mtx)))) + (!(pthread_rwlock_tryrdlock(&SCTP_BASE_INFO(ipi_ep_mtx)))) #define SCTP_IP_PKTLOG_INIT() \ (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), &SCTP_BASE_VAR(mtx_attr)) @@ -302,9 +321,9 @@ (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_pktlog_mtx)) #ifdef INVARIANTS #define SCTP_IP_PKTLOG_LOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s: ipi_pktlog_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s:%d: ipi_pktlog_mtx already locked", __FILE__, __LINE__)) #define SCTP_IP_PKTLOG_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s: ipi_pktlog_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s:%d: ipi_pktlog_mtx not locked", __FILE__, __LINE__)) #else #define SCTP_IP_PKTLOG_LOCK() \ (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) @@ -318,21 +337,23 @@ * we want to change something at the endpoint level for example random_store * or cookie secrets we lock the INP level. */ -#define SCTP_INP_READ_INIT(_inp) \ +#define SCTP_INP_READ_LOCK_INIT(_inp) \ (void)pthread_mutex_init(&(_inp)->inp_rdata_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_INP_READ_DESTROY(_inp) \ +#define SCTP_INP_READ_LOCK_DESTROY(_inp) \ (void)pthread_mutex_destroy(&(_inp)->inp_rdata_mtx) #ifdef INVARIANTS #define SCTP_INP_READ_LOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_rdata_mtx) == 0, ("%s: inp_rdata_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&(_inp)->inp_rdata_mtx) == 0, ("%s:%d: inp_rdata_mtx already locked", __FILE__, __LINE__)) #define SCTP_INP_READ_UNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) == 0, ("%s: inp_rdata_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) == 0, ("%s:%d: inp_rdata_mtx not locked", __FILE__, __LINE__)) #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_READ_LOCK_ASSERT(_inp) \ + KASSERT(pthread_mutex_trylock(&(_inp)->inp_rdata_mtx) == EBUSY, ("%s:%d: inp_rdata_mtx not locked", __FILE__, __LINE__)) #define SCTP_INP_LOCK_INIT(_inp) \ (void)pthread_mutex_init(&(_inp)->inp_mtx, &SCTP_BASE_VAR(mtx_attr)) @@ -340,26 +361,26 @@ (void)pthread_mutex_destroy(&(_inp)->inp_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, NULL, SCTP_LOG_LOCK_INP); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) \ +#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:%d: inp_mtx already locked", __FILE__, __LINE__)); \ } while (0) -#define SCTP_INP_WLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) +#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:%d: inp_mtx already locked", __FILE__, __LINE__)); \ } while (0) #else #define SCTP_INP_RLOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx already locked", __FILE__, __LINE__)) #define SCTP_INP_WLOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx already locked", __FILE__, __LINE__)) #endif #define SCTP_INP_RUNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) #define SCTP_INP_WUNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) #else #ifdef SCTP_LOCK_LOGGING #define SCTP_INP_RLOCK(_inp) do { \ @@ -384,27 +405,11 @@ (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__)) + KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) #define SCTP_INP_WLOCK_ASSERT(_inp) \ - KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s: inp_mtx not locked", __func__)) + KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) #define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1) -#define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1) - -#define SCTP_TCB_SEND_LOCK_INIT(_tcb) \ - (void)pthread_mutex_init(&(_tcb)->tcb_send_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) \ - (void)pthread_mutex_destroy(&(_tcb)->tcb_send_mtx) -#ifdef INVARIANTS -#define SCTP_TCB_SEND_LOCK(_tcb) \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_send_mtx) == 0, ("%s: tcb_send_mtx already locked", __func__)) -#define SCTP_TCB_SEND_UNLOCK(_tcb) \ - KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_send_mtx) == 0, ("%s: tcb_send_mtx not locked", __func__)) -#else -#define SCTP_TCB_SEND_LOCK(_tcb) \ - (void)pthread_mutex_lock(&(_tcb)->tcb_send_mtx) -#define SCTP_TCB_SEND_UNLOCK(_tcb) \ - (void)pthread_mutex_unlock(&(_tcb)->tcb_send_mtx) -#endif +#define SCTP_INP_DECR_REF(_inp) atomic_subtract_int(&((_inp)->refcount), 1) #define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \ (void)pthread_mutex_init(&(_inp)->inp_create_mtx, &SCTP_BASE_VAR(mtx_attr)) @@ -412,17 +417,17 @@ (void)pthread_mutex_destroy(&(_inp)->inp_create_mtx) #ifdef INVARIANTS #ifdef SCTP_LOCK_LOGGING -#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx already locked", __func__)) \ +#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:%d: inp_create_mtx already locked", __FILE__, __LINE__)); \ } while (0) #else #define SCTP_ASOC_CREATE_LOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s:%d: inp_create_mtx already locked", __FILE__, __LINE__)) #endif #define SCTP_ASOC_CREATE_UNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&(_inp)->inp_create_mtx) == 0, ("%s:%d: inp_create_mtx not locked", __FILE__, __LINE__)) #else #ifdef SCTP_LOCK_LOGGING #define SCTP_ASOC_CREATE_LOCK(_inp) do { \ @@ -451,17 +456,17 @@ (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); \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__)) \ +#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:%d: tcb_mtx already locked", __FILE__, __LINE__)) \ } while (0) #else #define SCTP_TCB_LOCK(_tcb) \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s:%d: tcb_mtx already locked", __FILE__, __LINE__)) #endif #define SCTP_TCB_UNLOCK(_tcb) \ - KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_mtx) == 0, ("%s:%d: tcb_mtx not locked", __FILE__, __LINE__)) #else #ifdef SCTP_LOCK_LOGGING #define SCTP_TCB_LOCK(_tcb) do { \ @@ -476,7 +481,7 @@ #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__)) + KASSERT(pthread_mutex_trylock(&(_tcb)->tcb_mtx) == EBUSY, ("%s:%d: tcb_mtx not locked", __FILE__, __LINE__)) #define SCTP_TCB_TRYLOCK(_tcb) (!(pthread_mutex_trylock(&(_tcb)->tcb_mtx))) #endif @@ -506,12 +511,12 @@ 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__)) + KASSERT(pthread_mutex_trylock(SOCKBUF_MTX(_so_buf)) == EBUSY, ("%s:%d: socket buffer not locked", __FILE__, __LINE__)) #ifdef INVARIANTS #define SOCKBUF_LOCK(_so_buf) \ - KASSERT(pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) == 0, ("%s: sockbuf_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) == 0, ("%s:%d: sockbuf_mtx already locked", __FILE__, __LINE__)) #define SOCKBUF_UNLOCK(_so_buf) \ - KASSERT(pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) == 0, ("%s: sockbuf_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) == 0, ("%s:%d: sockbuf_mtx not locked", __FILE__, __LINE__)) #else #define SOCKBUF_LOCK(_so_buf) \ pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) @@ -531,6 +536,7 @@ #if defined(_WIN32) /* address list locks */ +#if WINVER < 0x0600 #define SCTP_IPI_ADDR_INIT() \ InitializeCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_DESTROY() \ @@ -545,7 +551,21 @@ LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_LOCK_ASSERT() #define SCTP_IPI_ADDR_WLOCK_ASSERT() - +#else +#define SCTP_IPI_ADDR_INIT() \ + InitializeSRWLock(&SCTP_BASE_INFO(ipi_addr_mtx)) +#define SCTP_IPI_ADDR_DESTROY() +#define SCTP_IPI_ADDR_RLOCK() \ + AcquireSRWLockShared(&SCTP_BASE_INFO(ipi_addr_mtx)) +#define SCTP_IPI_ADDR_RUNLOCK() \ + ReleaseSRWLockShared(&SCTP_BASE_INFO(ipi_addr_mtx)) +#define SCTP_IPI_ADDR_WLOCK() \ + AcquireSRWLockExclusive(&SCTP_BASE_INFO(ipi_addr_mtx)) +#define SCTP_IPI_ADDR_WUNLOCK() \ + ReleaseSRWLockExclusive(&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() \ @@ -569,34 +589,30 @@ #else /* address list locks */ #define SCTP_IPI_ADDR_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_addr_mtx), &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_rwlock_init(&SCTP_BASE_INFO(ipi_addr_mtx), &SCTP_BASE_VAR(rwlock_attr)) #define SCTP_IPI_ADDR_DESTROY() \ - (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_addr_mtx)) + (void)pthread_rwlock_destroy(&SCTP_BASE_INFO(ipi_addr_mtx)) #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__)) + KASSERT(pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx already locked", __FILE__, __LINE__)) #define SCTP_IPI_ADDR_RUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx not locked", __func__)) + KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx not locked", __FILE__, __LINE__)) #define SCTP_IPI_ADDR_WLOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx already locked", __func__)) + KASSERT(pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx already locked", __FILE__, __LINE__)) #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__)) + KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx not locked", __FILE__, __LINE__)) #else #define SCTP_IPI_ADDR_RLOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) + (void)pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_RUNLOCK() \ - (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) + (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_WLOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) + (void)pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_WUNLOCK() \ - (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) + (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) +#endif #define SCTP_IPI_ADDR_LOCK_ASSERT() #define SCTP_IPI_ADDR_WLOCK_ASSERT() -#endif /* iterator locks */ #define SCTP_ITERATOR_LOCK_INIT() \ @@ -605,9 +621,9 @@ (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__)) + KASSERT(pthread_mutex_lock(&sctp_it_ctl.it_mtx) == 0, ("%s:%d: it_mtx already locked", __FILE__, __LINE__)) #define SCTP_ITERATOR_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&sctp_it_ctl.it_mtx) == 0, ("%s: it_mtx not locked", __func__)) + KASSERT(pthread_mutex_unlock(&sctp_it_ctl.it_mtx) == 0, ("%s:%d: it_mtx not locked", __FILE__, __LINE__)) #else #define SCTP_ITERATOR_LOCK() \ (void)pthread_mutex_lock(&sctp_it_ctl.it_mtx) @@ -621,9 +637,9 @@ (void)pthread_mutex_destroy(&sctp_it_ctl.ipi_iterator_wq_mtx) #ifdef INVARIANTS #define SCTP_IPI_ITERATOR_WQ_LOCK() \ - KASSERT(pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s: ipi_iterator_wq_mtx already locked", __func__)) + KASSERT(pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s:%d: ipi_iterator_wq_mtx already locked", __FILE__, __LINE__)) #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__)) + KASSERT(pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s:%d: ipi_iterator_wq_mtx not locked", __FILE__, __LINE__)) #else #define SCTP_IPI_ITERATOR_WQ_LOCK() \ (void)pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) diff --git a/netwerk/sctp/src/netinet/sctp_sha1.h b/netwerk/sctp/src/netinet/sctp_sha1.h index d535ee4639..8e136045f6 100644 --- a/netwerk/sctp/src/netinet/sctp_sha1.h +++ b/netwerk/sctp/src/netinet/sctp_sha1.h @@ -32,12 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - - #ifndef __NETINET_SCTP_SHA1_H__ #define __NETINET_SCTP_SHA1_H__ diff --git a/netwerk/sctp/src/netinet/sctp_ss_functions.c b/netwerk/sctp/src/netinet/sctp_ss_functions.c index 431cbf23ae..07060c3806 100644 --- a/netwerk/sctp/src/netinet/sctp_ss_functions.c +++ b/netwerk/sctp/src/netinet/sctp_ss_functions.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved. * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved. @@ -28,40 +28,31 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 365071 2020-09-01 21:19:14Z mjg $"); -#endif - +#include #include -#if defined(__Userspace__) -#include -#endif /* * Default simple round-robin algorithm. - * Just interates the streams in the order they appear. + * Just iterates the streams in the order they appear. */ static void sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *, struct sctp_stream_out *, - struct sctp_stream_queue_pending *, int); + struct sctp_stream_queue_pending *); static void sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *, struct sctp_stream_out *, - struct sctp_stream_queue_pending *, int); + struct sctp_stream_queue_pending *); static void -sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc, - int holds_lock) +sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc) { uint16_t i; - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + asoc->ss_data.locked_on_sending = NULL; asoc->ss_data.last_out_stream = NULL; TAILQ_INIT(&asoc->ss_data.out.wheel); @@ -71,42 +62,37 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc, * been changed. We need to add all stream queues * to the wheel. */ - 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, 1); - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + for (i = 0; i < asoc->streamoutcnt; i++) { + stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, + &asoc->strmout[i], + NULL); } return; } static void sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - int clear_values SCTP_UNUSED, int holds_lock) + bool clear_values SCTP_UNUSED) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + 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; + KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); + strq->ss_params.scheduled = false; } asoc->ss_data.last_out_stream = NULL; - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } return; } static void sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -115,72 +101,60 @@ sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *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; + strq->ss_params.scheduled = false; return; } static void sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock) + struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + /* Add to wheel if not already on it and stream queue not empty */ - 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(&strq->outqueue) && !strq->ss_params.scheduled) { TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, - strq, ss_params.rr.next_spoke); - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + strq, ss_params.ss.rr.next_spoke); + strq->ss_params.scheduled = true; } return; } -static int +static bool sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { - if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - return (1); - } else { - return (0); - } + SCTP_TCB_LOCK_ASSERT(stcb); + + return (TAILQ_EMPTY(&asoc->ss_data.out.wheel)); } static void sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock) + struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + /* Remove from wheel if stream queue is empty and actually is on the wheel */ - 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(&strq->outqueue) && strq->ss_params.scheduled) { 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); + sctpwheel_listhead, + ss_params.ss.rr.next_spoke); if (asoc->ss_data.last_out_stream == NULL) { asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, - sctpwheel_listhead); + sctpwheel_listhead); } 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); - strq->ss_params.rr.next_spoke.tqe_next = NULL; - strq->ss_params.rr.next_spoke.tqe_prev = NULL; - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + if (asoc->ss_data.locked_on_sending == strq) { + asoc->ss_data.locked_on_sending = NULL; + } + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); + strq->ss_params.scheduled = false; } return; } @@ -191,20 +165,29 @@ sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt; - if (asoc->ss_data.locked_on_sending) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (asoc->ss_data.locked_on_sending != NULL) { + KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, + ("locked_on_sending %p not scheduled", + (void *)asoc->ss_data.locked_on_sending)); return (asoc->ss_data.locked_on_sending); } strqt = asoc->ss_data.last_out_stream; + KASSERT(strqt == NULL || strqt->ss_params.scheduled, + ("last_out_stream %p not scheduled", (void *)strqt)); default_again: /* Find the next stream to use */ if (strqt == NULL) { strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { - strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); + strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); if (strq == NULL) { strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } + KASSERT(strq == NULL || strq->ss_params.scheduled, + ("strq %p not scheduled", (void *)strq)); /* If CMT is off, we must validate that * the stream in question has the first @@ -242,16 +225,20 @@ sctp_ss_default_scheduled(struct sctp_tcb *stcb, { struct sctp_stream_queue_pending *sp; + KASSERT(strq != NULL, ("strq is NULL")); + KASSERT(strq->ss_params.scheduled, ("strq %p is not scheduled", (void *)strq)); + SCTP_TCB_LOCK_ASSERT(stcb); + asoc->ss_data.last_out_stream = strq; - if (stcb->asoc.idata_supported == 0) { + if (asoc->idata_supported == 0) { sp = TAILQ_FIRST(&strq->outqueue); if ((sp != NULL) && (sp->some_taken == 1)) { - stcb->asoc.ss_data.locked_on_sending = strq; + asoc->ss_data.locked_on_sending = strq; } else { - stcb->asoc.ss_data.locked_on_sending = NULL; + asoc->ss_data.locked_on_sending = NULL; } } else { - stcb->asoc.ss_data.locked_on_sending = NULL; + asoc->ss_data.locked_on_sending = NULL; } return; } @@ -260,6 +247,8 @@ static void sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED) { + SCTP_TCB_LOCK_ASSERT(stcb); + /* Nothing to be done here */ return; } @@ -268,6 +257,8 @@ static int sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED) { + SCTP_TCB_LOCK_ASSERT(stcb); + /* Nothing to be done here */ return (-1); } @@ -276,76 +267,77 @@ static int sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED) { + SCTP_TCB_LOCK_ASSERT(stcb); + /* Nothing to be done here */ return (-1); } -static int +static bool 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; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->stream_queue_cnt != 1) { - return (0); + return (false); } strq = asoc->ss_data.locked_on_sending; if (strq == NULL) { - return (0); + return (false); } sp = TAILQ_FIRST(&strq->outqueue); if (sp == NULL) { - return (0); + return (false); } - return (!sp->msg_is_complete); + return (sp->msg_is_complete == 0); } /* * Real round-robin algorithm. - * Always interates the streams in ascending order. + * Always iterates the streams in ascending order. */ static void sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock) + struct sctp_stream_queue_pending *sp SCTP_UNUSED) { struct sctp_stream_out *strqt; - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } - if (!TAILQ_EMPTY(&strq->outqueue) && - (strq->ss_params.rr.next_spoke.tqe_next == NULL) && - (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); + TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); } else { strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); while (strqt != NULL && (strqt->sid < strq->sid)) { - strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); + strqt = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); } if (strqt != NULL) { - TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke); + TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.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.ss.rr.next_spoke); } } - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + strq->ss_params.scheduled = true; } return; } /* * Real round-robin per packet algorithm. - * Always interates the streams in ascending order and + * Always iterates the streams in ascending order and * only fills messages of the same stream in a packet. */ 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) { + SCTP_TCB_LOCK_ASSERT(stcb); + return (asoc->ss_data.last_out_stream); } @@ -355,17 +347,23 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net { struct sctp_stream_out *strq, *strqt; + SCTP_TCB_LOCK_ASSERT(stcb); + strqt = asoc->ss_data.last_out_stream; + KASSERT(strqt == NULL || strqt->ss_params.scheduled, + ("last_out_stream %p not scheduled", (void *)strqt)); rrp_again: /* Find the next stream to use */ if (strqt == NULL) { strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { - strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); + strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); if (strq == NULL) { strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } + KASSERT(strq == NULL || strq->ss_params.scheduled, + ("strq %p not scheduled", (void *)strq)); /* If CMT is off, we must validate that * the stream in question has the first @@ -401,32 +399,30 @@ rrp_again: */ static void sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - int clear_values, int holds_lock) + bool clear_values) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { struct sctp_stream_out *strq; strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); + KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); if (clear_values) { - strq->ss_params.prio.priority = 0; + strq->ss_params.ss.prio.priority = 0; } - 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; + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); + strq->ss_params.scheduled = false; } asoc->ss_data.last_out_stream = NULL; - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } return; } static void sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -435,79 +431,68 @@ sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, st 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; + strq->ss_params.scheduled = false; if (with_strq != NULL) { - strq->ss_params.prio.priority = with_strq->ss_params.prio.priority; + strq->ss_params.ss.prio.priority = with_strq->ss_params.ss.prio.priority; } else { - strq->ss_params.prio.priority = 0; + strq->ss_params.ss.prio.priority = 0; } return; } static void sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED, - int holds_lock) + struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { struct sctp_stream_out *strqt; - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + /* Add to wheel if not already on it and stream queue not empty */ - 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(&strq->outqueue) && !strq->ss_params.scheduled) { if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke); + TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); } else { 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); + while (strqt != NULL && strqt->ss_params.ss.prio.priority < strq->ss_params.ss.prio.priority) { + strqt = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke); } if (strqt != NULL) { - TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke); + TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.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.ss.prio.next_spoke); } } - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + strq->ss_params.scheduled = true; } return; } static void sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED, - int holds_lock) + struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + /* Remove from wheel if stream queue is empty and actually is on the wheel */ - 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(&strq->outqueue) && strq->ss_params.scheduled) { 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); + asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, + sctpwheel_listhead, + ss_params.ss.prio.next_spoke); if (asoc->ss_data.last_out_stream == NULL) { asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, - sctpwheel_listhead); + sctpwheel_listhead); } 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); - strq->ss_params.prio.next_spoke.tqe_next = NULL; - strq->ss_params.prio.next_spoke.tqe_prev = NULL; - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + if (asoc->ss_data.locked_on_sending == strq) { + asoc->ss_data.locked_on_sending = NULL; + } + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); + strq->ss_params.scheduled = false; } return; } @@ -518,23 +503,32 @@ sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt, *strqn; - if (asoc->ss_data.locked_on_sending) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (asoc->ss_data.locked_on_sending != NULL) { + KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, + ("locked_on_sending %p not scheduled", + (void *)asoc->ss_data.locked_on_sending)); return (asoc->ss_data.locked_on_sending); } strqt = asoc->ss_data.last_out_stream; + KASSERT(strqt == NULL || strqt->ss_params.scheduled, + ("last_out_stream %p not scheduled", (void *)strqt)); prio_again: /* Find the next stream to use */ if (strqt == NULL) { strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { - strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); + strqn = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke); if (strqn != NULL && - strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) { + strqn->ss_params.ss.prio.priority == strqt->ss_params.ss.prio.priority) { strq = strqn; } else { strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } + KASSERT(strq == NULL || strq->ss_params.scheduled, + ("strq %p not scheduled", (void *)strq)); /* If CMT is off, we must validate that * the stream in question has the first @@ -567,10 +561,12 @@ static int sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, struct sctp_stream_out *strq, uint16_t *value) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (strq == NULL) { return (-1); } - *value = strq->ss_params.prio.priority; + *value = strq->ss_params.ss.prio.priority; return (1); } @@ -578,47 +574,47 @@ static int sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, uint16_t value) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (strq == NULL) { return (-1); } - strq->ss_params.prio.priority = value; - sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1); - sctp_ss_prio_add(stcb, asoc, strq, NULL, 1); + strq->ss_params.ss.prio.priority = value; + sctp_ss_prio_remove(stcb, asoc, strq, NULL); + sctp_ss_prio_add(stcb, asoc, strq, NULL); return (1); } /* * Fair bandwidth algorithm. - * Maintains an equal troughput per stream. + * Maintains an equal throughput per stream. */ static void sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - int clear_values, int holds_lock) + bool clear_values) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { struct sctp_stream_out *strq; strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); + KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); if (clear_values) { - strq->ss_params.fb.rounds = -1; + strq->ss_params.ss.fb.rounds = -1; } - 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; + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); + strq->ss_params.scheduled = false; } asoc->ss_data.last_out_stream = NULL; - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } return; } static void sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -627,66 +623,55 @@ sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, stru 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; + strq->ss_params.scheduled = false; if (with_strq != NULL) { - strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds; + strq->ss_params.ss.fb.rounds = with_strq->ss_params.ss.fb.rounds; } else { - strq->ss_params.fb.rounds = -1; + strq->ss_params.ss.fb.rounds = -1; } return; } static void sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED, - int holds_lock) + struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } - if (!TAILQ_EMPTY(&strq->outqueue) && - (strq->ss_params.fb.next_spoke.tqe_next == NULL) && - (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); - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); + + if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { + if (strq->ss_params.ss.fb.rounds < 0) + strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; + TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); + strq->ss_params.scheduled = true; } return; } static void sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED, - int holds_lock) + struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + /* Remove from wheel if stream queue is empty and actually is on the wheel */ - if (TAILQ_EMPTY(&strq->outqueue) && - (strq->ss_params.fb.next_spoke.tqe_next != NULL || - strq->ss_params.fb.next_spoke.tqe_prev != NULL)) { + if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { 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); + asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, + sctpwheel_listhead, + ss_params.ss.fb.next_spoke); if (asoc->ss_data.last_out_stream == NULL) { asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, - sctpwheel_listhead); + sctpwheel_listhead); } 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); - strq->ss_params.fb.next_spoke.tqe_next = NULL; - strq->ss_params.fb.next_spoke.tqe_prev = NULL; - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + if (asoc->ss_data.locked_on_sending == strq) { + asoc->ss_data.locked_on_sending = NULL; + } + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); + strq->ss_params.scheduled = false; } return; } @@ -697,14 +682,19 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq = NULL, *strqt; - if (asoc->ss_data.locked_on_sending) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (asoc->ss_data.locked_on_sending != NULL) { + KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, + ("locked_on_sending %p not scheduled", + (void *)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->ss_data.last_out_stream, ss_params.fb.next_spoke); + strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.ss.fb.next_spoke); } do { if ((strqt != NULL) && @@ -713,13 +703,14 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) || (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL && TAILQ_FIRST(&strqt->outqueue)->net == net))))) { - if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL || - strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) { + if ((strqt->ss_params.ss.fb.rounds >= 0) && + ((strq == NULL) || + (strqt->ss_params.ss.fb.rounds < strq->ss_params.ss.fb.rounds))) { strq = strqt; } } if (strqt != NULL) { - strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke); + strqt = TAILQ_NEXT(strqt, ss_params.ss.fb.next_spoke); } else { strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); } @@ -736,26 +727,28 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, struct sctp_stream_out *strqt; int subtract; - if (stcb->asoc.idata_supported == 0) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (asoc->idata_supported == 0) { sp = TAILQ_FIRST(&strq->outqueue); if ((sp != NULL) && (sp->some_taken == 1)) { - stcb->asoc.ss_data.locked_on_sending = strq; + asoc->ss_data.locked_on_sending = strq; } else { - stcb->asoc.ss_data.locked_on_sending = NULL; + asoc->ss_data.locked_on_sending = NULL; } } else { - stcb->asoc.ss_data.locked_on_sending = NULL; + 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) { - strqt->ss_params.fb.rounds -= subtract; - if (strqt->ss_params.fb.rounds < 0) - strqt->ss_params.fb.rounds = 0; + subtract = strq->ss_params.ss.fb.rounds; + TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.ss.fb.next_spoke) { + strqt->ss_params.ss.fb.rounds -= subtract; + if (strqt->ss_params.ss.fb.rounds < 0) + strqt->ss_params.ss.fb.rounds = 0; } if (TAILQ_FIRST(&strq->outqueue)) { - strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; + strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; } else { - strq->ss_params.fb.rounds = -1; + strq->ss_params.ss.fb.rounds = -1; } asoc->ss_data.last_out_stream = strq; return; @@ -768,19 +761,17 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, static void sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq SCTP_UNUSED, - struct sctp_stream_queue_pending *sp, int holds_lock); + struct sctp_stream_queue_pending *sp); static void -sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc, - int holds_lock) +sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc) { uint32_t x, n = 0, add_more = 1; struct sctp_stream_queue_pending *sp; uint16_t i; - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } + SCTP_TCB_LOCK_ASSERT(stcb); + TAILQ_INIT(&asoc->ss_data.out.list); /* * If there is data in the stream queues already, @@ -791,8 +782,8 @@ sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc, */ while (add_more) { add_more = 0; - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue); + for (i = 0; i < asoc->streamoutcnt; i++) { + sp = TAILQ_FIRST(&asoc->strmout[i].outqueue); x = 0; /* Find n. message in current stream queue */ while (sp != NULL && x < n) { @@ -800,44 +791,38 @@ 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, 1); + sctp_ss_fcfs_add(stcb, asoc, &asoc->strmout[i], sp); add_more = 1; } } n++; } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } return; } static void sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - int clear_values, int holds_lock) + bool clear_values SCTP_UNUSED) { 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)) { - 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); - } + SCTP_TCB_LOCK_ASSERT(stcb); + + while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) { + sp = TAILQ_FIRST(&asoc->ss_data.out.list); + KASSERT(sp->scheduled, ("sp %p not scheduled", (void *)sp)); + TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); + sp->scheduled = false; } + asoc->ss_data.last_out_stream = NULL; return; } static void sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -846,56 +831,40 @@ sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, st 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; + strq->ss_params.scheduled = false; return; } static void sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp, - int holds_lock) + struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } - if (sp && (sp->ss_next.tqe_next == NULL) && - (sp->ss_next.tqe_prev == NULL)) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (!sp->scheduled) { TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next); - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); + sp->scheduled = true; } return; } -static int +static bool sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { - if (TAILQ_EMPTY(&asoc->ss_data.out.list)) { - return (1); - } else { - return (0); - } + SCTP_TCB_LOCK_ASSERT(stcb); + + return (TAILQ_EMPTY(&asoc->ss_data.out.list)); } static void sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp, - int holds_lock) + struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp) { - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } - if (sp && - ((sp->ss_next.tqe_next != NULL) || - (sp->ss_next.tqe_prev != NULL))) { + SCTP_TCB_LOCK_ASSERT(stcb); + + if (sp->scheduled) { 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); + sp->scheduled = false; } return; } @@ -907,6 +876,8 @@ 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; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->ss_data.locked_on_sending) { return (asoc->ss_data.locked_on_sending); } @@ -942,6 +913,30 @@ default_again: return (strq); } +static void +sctp_ss_fcfs_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; + + KASSERT(strq != NULL, ("strq is NULL")); + asoc->ss_data.last_out_stream = strq; + if (asoc->idata_supported == 0) { + sp = TAILQ_FIRST(&strq->outqueue); + if ((sp != NULL) && (sp->some_taken == 1)) { + asoc->ss_data.locked_on_sending = strq; + } else { + asoc->ss_data.locked_on_sending = NULL; + } + } else { + asoc->ss_data.locked_on_sending = NULL; + } + return; +} + const struct sctp_ss_functions sctp_ss_functions[] = { /* SCTP_SS_DEFAULT */ { @@ -973,7 +968,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, -/* SCTP_SS_ROUND_ROBIN */ +/* SCTP_SS_RR */ { #if defined(_WIN32) sctp_ss_default_init, @@ -1003,7 +998,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, -/* SCTP_SS_ROUND_ROBIN_PACKET */ +/* SCTP_SS_RR_PKT */ { #if defined(_WIN32) sctp_ss_default_init, @@ -1033,7 +1028,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, -/* SCTP_SS_PRIORITY */ +/* SCTP_SS_PRIO */ { #if defined(_WIN32) sctp_ss_default_init, @@ -1063,7 +1058,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, -/* SCTP_SS_FAIR_BANDWITH */ +/* SCTP_SS_FB */ { #if defined(_WIN32) sctp_ss_default_init, @@ -1093,7 +1088,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, -/* SCTP_SS_FIRST_COME */ +/* SCTP_SS_FCFS */ { #if defined(_WIN32) sctp_ss_fcfs_init, @@ -1103,7 +1098,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_fcfs_is_empty, sctp_ss_fcfs_remove, sctp_ss_fcfs_select, - sctp_ss_default_scheduled, + sctp_ss_fcfs_scheduled, sctp_ss_default_packet_done, sctp_ss_default_get_value, sctp_ss_default_set_value, @@ -1116,7 +1111,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_is_empty = sctp_ss_fcfs_is_empty, .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove, .sctp_ss_select_stream = sctp_ss_fcfs_select, - .sctp_ss_scheduled = sctp_ss_default_scheduled, + .sctp_ss_scheduled = sctp_ss_fcfs_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, diff --git a/netwerk/sctp/src/netinet/sctp_structs.h b/netwerk/sctp/src/netinet/sctp_structs.h index 708ab702f1..894137ae5d 100644 --- a/netwerk/sctp/src/netinet/sctp_structs.h +++ b/netwerk/sctp/src/netinet/sctp_structs.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_STRUCTS_H_ #define _NETINET_SCTP_STRUCTS_H_ @@ -135,6 +130,26 @@ struct sctp_mcore_ctrl { #endif #endif +/* This struct is here to cut out the compatiabilty + * pad that bulks up both the inp and stcb. The non + * pad portion MUST stay in complete sync with + * sctp_sndrcvinfo... i.e. if sinfo_xxxx is added + * this must be done here too. + */ +struct sctp_nonpad_sndrcvinfo { + uint16_t sinfo_stream; + uint16_t sinfo_ssn; + uint16_t sinfo_flags; + uint32_t sinfo_ppid; + uint32_t sinfo_context; + uint32_t sinfo_timetolive; + uint32_t sinfo_tsn; + uint32_t sinfo_cumtsn; + sctp_assoc_t sinfo_assoc_id; + uint16_t sinfo_keynumber; + uint16_t sinfo_keynumber_valid; +}; + struct sctp_iterator { TAILQ_ENTRY(sctp_iterator) sctp_nxt_itr; #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -166,7 +181,7 @@ TAILQ_HEAD(sctpiterators, sctp_iterator); struct sctp_copy_all { struct sctp_inpcb *inp; /* ep */ struct mbuf *m; - struct sctp_sndrcvinfo sndrcv; + struct sctp_nonpad_sndrcvinfo sndrcv; ssize_t sndlen; int cnt_sent; int cnt_failed; @@ -555,6 +570,7 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */ * the user is in the explict MSG_EOR mode * and wrote some data, but has not completed * sending. + * ss_next and scheduled are only used by the FCFS stream scheduler. */ struct sctp_stream_queue_pending { struct mbuf *data; @@ -579,6 +595,7 @@ struct sctp_stream_queue_pending { uint8_t put_last_out; uint8_t discard_rest; uint8_t processing; + bool scheduled; }; /* @@ -598,6 +615,20 @@ struct sctp_stream_in { TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out); TAILQ_HEAD(sctplist_listhead, sctp_stream_queue_pending); +/* + * This union holds all data necessary for + * different stream schedulers. + */ +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; +}; + /* Round-robin schedulers */ struct ss_rr { /* next link in wheel */ @@ -620,28 +651,17 @@ struct ss_fb { int32_t rounds; }; -/* - * This union holds all data necessary for - * different stream schedulers. - */ -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; -}; - /* * This union holds all parameters per stream * necessary for different stream schedulers. */ -union scheduling_parameters { - struct ss_rr rr; - struct ss_prio prio; - struct ss_fb fb; +struct scheduling_parameters { + union { + struct ss_rr rr; + struct ss_prio prio; + struct ss_fb fb; + } ss; + bool scheduled; }; /* States for outgoing streams */ @@ -651,12 +671,10 @@ union scheduling_parameters { #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; + struct scheduling_parameters ss_params; 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]; @@ -676,6 +694,8 @@ struct sctp_stream_out { uint8_t state; }; +#define SCTP_MAX_STREAMS_AT_ONCE_RESET 200 + /* used to keep track of the addresses yet to try to add/delete */ TAILQ_HEAD(sctp_asconf_addrhead, sctp_asconf_addr); struct sctp_asconf_addr { @@ -722,26 +742,6 @@ struct sctp_fs_spec_log { uint8_t decr; }; -/* This struct is here to cut out the compatiabilty - * pad that bulks up both the inp and stcb. The non - * pad portion MUST stay in complete sync with - * sctp_sndrcvinfo... i.e. if sinfo_xxxx is added - * this must be done here too. - */ -struct sctp_nonpad_sndrcvinfo { - uint16_t sinfo_stream; - uint16_t sinfo_ssn; - uint16_t sinfo_flags; - uint32_t sinfo_ppid; - uint32_t sinfo_context; - uint32_t sinfo_timetolive; - uint32_t sinfo_tsn; - uint32_t sinfo_cumtsn; - sctp_assoc_t sinfo_assoc_id; - uint16_t sinfo_keynumber; - uint16_t sinfo_keynumber_valid; -}; - /* * JRS - Structure to hold function pointers to the functions responsible * for congestion control. @@ -781,16 +781,15 @@ struct sctp_cc_functions { * for stream scheduling. */ struct sctp_ss_functions { - void (*sctp_ss_init)(struct sctp_tcb *stcb, struct sctp_association *asoc, - int holds_lock); + void (*sctp_ss_init)(struct sctp_tcb *stcb, struct sctp_association *asoc); void (*sctp_ss_clear)(struct sctp_tcb *stcb, struct sctp_association *asoc, - int clear_values, int holds_lock); + bool clear_values); 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); + struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp); + bool (*sctp_ss_is_empty)(struct sctp_tcb *stcb, struct sctp_association *asoc); void (*sctp_ss_remove_from_stream)(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, struct sctp_stream_queue_pending *sp); struct sctp_stream_out* (*sctp_ss_select_stream)(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_association *asoc); void (*sctp_ss_scheduled)(struct sctp_tcb *stcb, struct sctp_nets *net, @@ -801,7 +800,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); + bool (*sctp_ss_is_user_msgs_incomplete)(struct sctp_tcb *stcb, struct sctp_association *asoc); }; /* used to save ASCONF chunks for retransmission */ @@ -1004,15 +1003,6 @@ struct sctp_association { uint32_t fast_recovery_tsn; uint32_t sat_t3_recovery_tsn; uint32_t tsn_last_delivered; - /* - * 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 - * "stuck" on the read queue until we finish all the pd-api. - */ - struct sctp_queued_to_read *control_pdapi; - uint32_t tsn_of_pdapi_last_delivered; uint32_t pdapi_ppid; uint32_t context; @@ -1230,6 +1220,10 @@ struct sctp_association { uint8_t pktdrop_supported; uint8_t idata_supported; + /* Zero checksum supported information */ + uint8_t rcv_edmid; + uint8_t snd_edmid; + /* Did the peer make the stream config (add out) request */ uint8_t peer_req_out; diff --git a/netwerk/sctp/src/netinet/sctp_sysctl.c b/netwerk/sctp/src/netinet/sctp_sysctl.c index bb49e17385..f1fc2acff7 100644 --- a/netwerk/sctp/src/netinet/sctp_sysctl.c +++ b/netwerk/sctp/src/netinet/sctp_sysctl.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #include #include #include @@ -61,7 +56,7 @@ FEATURE(sctp, "Stream Control Transmission Protocol"); */ void -sctp_init_sysctls() +sctp_init_sysctls(void) { SCTP_BASE_SYSCTL(sctp_sendspace) = SCTPCTL_MAXDGRAM_DEFAULT; SCTP_BASE_SYSCTL(sctp_recvspace) = SCTPCTL_RECVSPACE_DEFAULT; @@ -151,6 +146,7 @@ sctp_init_sysctls() 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; + SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum) = SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT; #if defined(SCTP_LOCAL_TRACE_BUF) #if defined(_WIN32) && !defined(__Userspace__) /* On Windows, the resource for global variables is limited. */ @@ -201,7 +197,7 @@ sctp_sysctl_number_of_addresses(struct sctp_inpcb *inp) struct sctp_laddr *laddr; cnt = 0; - /* neither Mac OS X nor FreeBSD support mulitple routing functions */ + /* neither Mac OS X nor FreeBSD support multiple routing functions */ if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) { return (0); } @@ -246,8 +242,15 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st { struct sctp_ifn *sctp_ifn; struct sctp_ifa *sctp_ifa; - int loopback_scope, ipv4_local_scope, local_scope, site_scope; - int ipv4_addr_legal, ipv6_addr_legal; + int loopback_scope; +#ifdef INET + int ipv4_local_scope; + int ipv4_addr_legal; +#endif +#ifdef INET6 + int local_scope, site_scope; + int ipv6_addr_legal; +#endif #if defined(__Userspace__) int conn_addr_legal; #endif @@ -257,68 +260,90 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st int error; /* Turn on all the appropriate scope */ - if (stcb) { + if (stcb != NULL) { /* use association specific values */ loopback_scope = stcb->asoc.scope.loopback_scope; +#ifdef INET ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; + ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; +#endif +#ifdef INET6 local_scope = stcb->asoc.scope.local_scope; site_scope = stcb->asoc.scope.site_scope; - ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; +#endif #if defined(__Userspace__) conn_addr_legal = stcb->asoc.scope.conn_addr_legal; #endif } else { /* Use generic values for endpoints. */ loopback_scope = 1; +#ifdef INET ipv4_local_scope = 1; +#endif +#ifdef INET6 local_scope = 1; site_scope = 1; +#endif if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { +#ifdef INET6 ipv6_addr_legal = 1; +#endif +#ifdef INET if (SCTP_IPV6_V6ONLY(inp)) { ipv4_addr_legal = 0; } else { ipv4_addr_legal = 1; } +#endif #if defined(__Userspace__) conn_addr_legal = 0; #endif } else { +#ifdef INET6 ipv6_addr_legal = 0; +#endif #if defined(__Userspace__) if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { conn_addr_legal = 1; +#ifdef INET ipv4_addr_legal = 0; +#endif } else { conn_addr_legal = 0; +#ifdef INET ipv4_addr_legal = 1; +#endif } #else +#ifdef INET ipv4_addr_legal = 1; +#endif #endif } } - /* neither Mac OS X nor FreeBSD support mulitple routing functions */ + /* Neither Mac OS X nor FreeBSD support multiple routing functions. */ if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) { SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); - return (-1); + return (ENOENT); } if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if ((loopback_scope == 0) && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) - /* Skip loopback if loopback_scope not set */ + if ((loopback_scope == 0) && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { + /* Skip loopback if loopback_scope not set. */ continue; + } LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (stcb) { + if (stcb != NULL) { /* - * ignore if blacklisted at - * association level + * Ignore if blacklisted at + * association level. */ - if (sctp_is_addr_restricted(stcb, sctp_ifa)) + if (sctp_is_addr_restricted(stcb, sctp_ifa)) { continue; + } } switch (sctp_ifa->address.sa.sa_family) { #ifdef INET @@ -327,16 +352,18 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st struct sockaddr_in *sin; sin = &sctp_ifa->address.sin; - if (sin->sin_addr.s_addr == 0) + if (sin->sin_addr.s_addr == 0) { continue; + } #if defined(__FreeBSD__) && !defined(__Userspace__) if (prison_check_ip4(inp->ip_inp.inp.inp_cred, &sin->sin_addr) != 0) { continue; } #endif - if ((ipv4_local_scope == 0) && (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) + if ((ipv4_local_scope == 0) && (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { continue; + } } else { continue; } @@ -348,8 +375,9 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st struct sockaddr_in6 *sin6; sin6 = &sctp_ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { continue; + } #if defined(__FreeBSD__) && !defined(__Userspace__) if (prison_check_ip6(inp->ip_inp.inp.inp_cred, &sin6->sin6_addr) != 0) { @@ -357,11 +385,13 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st } #endif if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (local_scope == 0) + if (local_scope == 0) { continue; + } } - if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) + if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { continue; + } } else { continue; } @@ -382,7 +412,7 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error) { + if (error != 0) { return (error); } else { SCTP_INP_INFO_RLOCK(); @@ -393,7 +423,7 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st } else { LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { /* ignore if blacklisted at association level */ - if (stcb && sctp_is_addr_restricted(stcb, laddr->ifa)) + if (stcb != NULL && sctp_is_addr_restricted(stcb, laddr->ifa)) continue; memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); memcpy((void *)&xladdr.address, (const void *)&laddr->ifa->address, sizeof(union sctp_sockstore)); @@ -402,7 +432,7 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error) { + if (error != 0) { return (error); } else { SCTP_INP_INFO_RLOCK(); @@ -416,7 +446,7 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error) { + if (error != 0) { return (error); } else { SCTP_INP_INFO_RLOCK(); @@ -999,6 +1029,9 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS) sb.sctps_send_burst_avoid += sarry->sctps_send_burst_avoid; sb.sctps_send_cwnd_avoid += sarry->sctps_send_cwnd_avoid; sb.sctps_fwdtsn_map_over += sarry->sctps_fwdtsn_map_over; + sb.sctps_queue_upd_ecne += sarry->sctps_queue_upd_ecne; + sb.sctps_recvzerocrc += sarry->sctps_recvzerocrc; + sb.sctps_sendzerocrc += sarry->sctps_sendzerocrc; if (req->newptr != NULL) { memcpy(sarry, &sb_temp, sizeof(struct sctpstat)); } @@ -1072,6 +1105,14 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS) #if (defined(__APPLE__) || defined(__FreeBSD__)) && !defined(__Userspace__) #if defined(__FreeBSD__) #define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \ + SCTP_UINT_SYSCTL_FLAG(mib_name, var_name, prefix, \ + CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW) + +#define SCTP_UINT_SYSCTL_TUN(mib_name, var_name, prefix) \ + SCTP_UINT_SYSCTL_FLAG(mib_name, var_name, prefix, \ + CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RWTUN|CTLFLAG_NOFETCH) + +#define SCTP_UINT_SYSCTL_FLAG(mib_name, var_name, prefix, flags) \ static int \ sctp_sysctl_handle_##mib_name(SYSCTL_HANDLER_ARGS) \ { \ @@ -1090,9 +1131,14 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS) } \ 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); + SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, flags, NULL, 0, \ + sctp_sysctl_handle_##mib_name, "IU", prefix##_DESC) + +#define SCTP_UINT_SYSCTL_RDTUN(mib_name, var_name, prefix) \ + SYSCTL_UINT(_net_inet_sctp, OID_AUTO, mib_name, \ + CTLFLAG_VNET|CTLFLAG_RDTUN|CTLFLAG_NOFETCH, \ + &VNET_NAME(system_base_info.sctpsysctl.var_name), 0, \ + prefix##_DESC) #else #define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \ static int \ @@ -1118,7 +1164,7 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS) } \ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \ CTLTYPE_INT | CTLFLAG_RW, NULL, 0, \ - sctp_sysctl_handle_##mib_name, "I", prefix##_DESC); + sctp_sysctl_handle_##mib_name, "I", prefix##_DESC) #define CTLTYPE_UINT CTLTYPE_INT #define CTLFLAG_VNET 0 #endif @@ -1127,66 +1173,72 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS) * sysctl definitions */ -SCTP_UINT_SYSCTL(sendspace, sctp_sendspace, SCTPCTL_MAXDGRAM) -SCTP_UINT_SYSCTL(recvspace, sctp_recvspace, SCTPCTL_RECVSPACE) -SCTP_UINT_SYSCTL(auto_asconf, sctp_auto_asconf, SCTPCTL_AUTOASCONF) -SCTP_UINT_SYSCTL(ecn_enable, sctp_ecn_enable, SCTPCTL_ECN_ENABLE) -SCTP_UINT_SYSCTL(pr_enable, sctp_pr_enable, SCTPCTL_PR_ENABLE) +SCTP_UINT_SYSCTL(sendspace, sctp_sendspace, SCTPCTL_MAXDGRAM); +SCTP_UINT_SYSCTL(recvspace, sctp_recvspace, SCTPCTL_RECVSPACE); +SCTP_UINT_SYSCTL(auto_asconf, sctp_auto_asconf, SCTPCTL_AUTOASCONF); +SCTP_UINT_SYSCTL(ecn_enable, sctp_ecn_enable, SCTPCTL_ECN_ENABLE); +SCTP_UINT_SYSCTL(pr_enable, sctp_pr_enable, SCTPCTL_PR_ENABLE); SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auth_enable, CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, sctp_sysctl_handle_auth, "IU", SCTPCTL_AUTH_ENABLE_DESC); SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, sctp_sysctl_handle_asconf, "IU", SCTPCTL_ASCONF_ENABLE_DESC); -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(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); #if defined(__APPLE__) && !defined(__Userspace__) -SCTP_UINT_SYSCTL(loopback_nocsum, sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM) +SCTP_UINT_SYSCTL(loopback_nocsum, sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM); #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) -SCTP_UINT_SYSCTL(maxchunks, sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS) -SCTP_UINT_SYSCTL(tcbhashsize, sctp_hashtblsize, SCTPCTL_TCBHASHSIZE) -SCTP_UINT_SYSCTL(pcbhashsize, sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE) -SCTP_UINT_SYSCTL(min_split_point, sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT) -SCTP_UINT_SYSCTL(chunkscale, sctp_chunkscale, SCTPCTL_CHUNKSCALE) -SCTP_UINT_SYSCTL(delayed_sack_time, sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME) -SCTP_UINT_SYSCTL(sack_freq, sctp_sack_freq_default, SCTPCTL_SACK_FREQ) -SCTP_UINT_SYSCTL(sys_resource, sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE) -SCTP_UINT_SYSCTL(asoc_resource, sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE) -SCTP_UINT_SYSCTL(heartbeat_interval, sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL) -SCTP_UINT_SYSCTL(pmtu_raise_time, sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME) -SCTP_UINT_SYSCTL(shutdown_guard_time, sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME) -SCTP_UINT_SYSCTL(secret_lifetime, sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME) -SCTP_UINT_SYSCTL(rto_max, sctp_rto_max_default, SCTPCTL_RTO_MAX) -SCTP_UINT_SYSCTL(rto_min, sctp_rto_min_default, SCTPCTL_RTO_MIN) -SCTP_UINT_SYSCTL(rto_initial, sctp_rto_initial_default, SCTPCTL_RTO_INITIAL) -SCTP_UINT_SYSCTL(init_rto_max, sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX) -SCTP_UINT_SYSCTL(valid_cookie_life, sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE) -SCTP_UINT_SYSCTL(init_rtx_max, sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX) -SCTP_UINT_SYSCTL(assoc_rtx_max, sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX) -SCTP_UINT_SYSCTL(path_rtx_max, sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX) -SCTP_UINT_SYSCTL(path_pf_threshold, sctp_path_pf_threshold, SCTPCTL_PATH_PF_THRESHOLD) -SCTP_UINT_SYSCTL(add_more_on_output, sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT) -SCTP_UINT_SYSCTL(incoming_streams, sctp_nr_incoming_streams_default, SCTPCTL_INCOMING_STREAMS) -SCTP_UINT_SYSCTL(outgoing_streams, sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS) -SCTP_UINT_SYSCTL(cmt_on_off, sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF) -SCTP_UINT_SYSCTL(cmt_use_dac, sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC) -SCTP_UINT_SYSCTL(cwnd_maxburst, sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST) -SCTP_UINT_SYSCTL(nat_friendly, sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY) -SCTP_UINT_SYSCTL(abc_l_var, sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR) -SCTP_UINT_SYSCTL(max_chained_mbufs, sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS) -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(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) -SCTP_UINT_SYSCTL(default_cc_module, sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE) -SCTP_UINT_SYSCTL(default_ss_module, sctp_default_ss_module, SCTPCTL_DEFAULT_SS_MODULE) -SCTP_UINT_SYSCTL(default_frag_interleave, sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE) -SCTP_UINT_SYSCTL(mobility_base, sctp_mobility_base, SCTPCTL_MOBILITY_BASE) -SCTP_UINT_SYSCTL(mobility_fasthandoff, sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF) +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); +SCTP_UINT_SYSCTL(maxchunks, sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS); +#if defined(__FreeBSD__) && !defined(__Userspace__) +SCTP_UINT_SYSCTL_RDTUN(tcbhashsize, sctp_hashtblsize, SCTPCTL_TCBHASHSIZE); +SCTP_UINT_SYSCTL_TUN(pcbhashsize, sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE); +SCTP_UINT_SYSCTL_RDTUN(chunkscale, sctp_chunkscale, SCTPCTL_CHUNKSCALE); +#else +SCTP_UINT_SYSCTL(tcbhashsize, sctp_hashtblsize, SCTPCTL_TCBHASHSIZE); +SCTP_UINT_SYSCTL(pcbhashsize, sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE); +SCTP_UINT_SYSCTL(chunkscale, sctp_chunkscale, SCTPCTL_CHUNKSCALE); +#endif +SCTP_UINT_SYSCTL(min_split_point, sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT); +SCTP_UINT_SYSCTL(delayed_sack_time, sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME); +SCTP_UINT_SYSCTL(sack_freq, sctp_sack_freq_default, SCTPCTL_SACK_FREQ); +SCTP_UINT_SYSCTL(sys_resource, sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE); +SCTP_UINT_SYSCTL(asoc_resource, sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE); +SCTP_UINT_SYSCTL(heartbeat_interval, sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL); +SCTP_UINT_SYSCTL(pmtu_raise_time, sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME); +SCTP_UINT_SYSCTL(shutdown_guard_time, sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME); +SCTP_UINT_SYSCTL(secret_lifetime, sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME); +SCTP_UINT_SYSCTL(rto_max, sctp_rto_max_default, SCTPCTL_RTO_MAX); +SCTP_UINT_SYSCTL(rto_min, sctp_rto_min_default, SCTPCTL_RTO_MIN); +SCTP_UINT_SYSCTL(rto_initial, sctp_rto_initial_default, SCTPCTL_RTO_INITIAL); +SCTP_UINT_SYSCTL(init_rto_max, sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX); +SCTP_UINT_SYSCTL(valid_cookie_life, sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE); +SCTP_UINT_SYSCTL(init_rtx_max, sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX); +SCTP_UINT_SYSCTL(assoc_rtx_max, sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX); +SCTP_UINT_SYSCTL(path_rtx_max, sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX); +SCTP_UINT_SYSCTL(path_pf_threshold, sctp_path_pf_threshold, SCTPCTL_PATH_PF_THRESHOLD); +SCTP_UINT_SYSCTL(add_more_on_output, sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT); +SCTP_UINT_SYSCTL(incoming_streams, sctp_nr_incoming_streams_default, SCTPCTL_INCOMING_STREAMS); +SCTP_UINT_SYSCTL(outgoing_streams, sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS); +SCTP_UINT_SYSCTL(cmt_on_off, sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF); +SCTP_UINT_SYSCTL(cmt_use_dac, sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC); +SCTP_UINT_SYSCTL(cwnd_maxburst, sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST); +SCTP_UINT_SYSCTL(nat_friendly, sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY); +SCTP_UINT_SYSCTL(abc_l_var, sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR); +SCTP_UINT_SYSCTL(max_chained_mbufs, sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS); +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(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); +SCTP_UINT_SYSCTL(default_cc_module, sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE); +SCTP_UINT_SYSCTL(default_ss_module, sctp_default_ss_module, SCTPCTL_DEFAULT_SS_MODULE); +SCTP_UINT_SYSCTL(default_frag_interleave, sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE); +SCTP_UINT_SYSCTL(mobility_base, sctp_mobility_base, SCTPCTL_MOBILITY_BASE); +SCTP_UINT_SYSCTL(mobility_fasthandoff, sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF); #if defined(SCTP_LOCAL_TRACE_BUF) SYSCTL_PROC(_net_inet_sctp, OID_AUTO, log, CTLFLAG_VNET|CTLTYPE_STRUCT|CTLFLAG_RD, NULL, 0, sctp_sysctl_handle_trace_log, "S,sctplog", "SCTP logging (struct sctp_log)"); @@ -1195,31 +1247,32 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, clear_trace, CTLFLAG_VNET|CTLTYPE_UINT | C #endif SYSCTL_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_port, CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, sctp_sysctl_handle_udp_tunneling, "IU", SCTPCTL_UDP_TUNNELING_PORT_DESC); -SCTP_UINT_SYSCTL(enable_sack_immediately, sctp_enable_sack_immediately, SCTPCTL_SACK_IMMEDIATELY_ENABLE) -SCTP_UINT_SYSCTL(nat_friendly_init, sctp_inits_include_nat_friendly, SCTPCTL_NAT_FRIENDLY_INITS) -SCTP_UINT_SYSCTL(vtag_time_wait, sctp_vtag_time_wait, SCTPCTL_TIME_WAIT) -SCTP_UINT_SYSCTL(buffer_splitting, sctp_buffer_splitting, SCTPCTL_BUFFER_SPLITTING) -SCTP_UINT_SYSCTL(initial_cwnd, sctp_initial_cwnd, SCTPCTL_INITIAL_CWND) -SCTP_UINT_SYSCTL(rttvar_bw, sctp_rttvar_bw, SCTPCTL_RTTVAR_BW) -SCTP_UINT_SYSCTL(rttvar_rtt, sctp_rttvar_rtt, SCTPCTL_RTTVAR_RTT) -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) +SCTP_UINT_SYSCTL(enable_sack_immediately, sctp_enable_sack_immediately, SCTPCTL_SACK_IMMEDIATELY_ENABLE); +SCTP_UINT_SYSCTL(nat_friendly_init, sctp_inits_include_nat_friendly, SCTPCTL_NAT_FRIENDLY_INITS); +SCTP_UINT_SYSCTL(vtag_time_wait, sctp_vtag_time_wait, SCTPCTL_TIME_WAIT); +SCTP_UINT_SYSCTL(buffer_splitting, sctp_buffer_splitting, SCTPCTL_BUFFER_SPLITTING); +SCTP_UINT_SYSCTL(initial_cwnd, sctp_initial_cwnd, SCTPCTL_INITIAL_CWND); +SCTP_UINT_SYSCTL(rttvar_bw, sctp_rttvar_bw, SCTPCTL_RTTVAR_BW); +SCTP_UINT_SYSCTL(rttvar_rtt, sctp_rttvar_rtt, SCTPCTL_RTTVAR_RTT); +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); +SCTP_UINT_SYSCTL(ootb_with_zero_cksum, sctp_ootb_with_zero_cksum, SCTPCTL_OOTB_WITH_ZERO_CKSUM); #ifdef SCTP_DEBUG -SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG) +SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG); #endif #if defined(__APPLE__) && !defined(__Userspace__) -SCTP_UINT_SYSCTL(main_timer, sctp_main_timer, SCTPCTL_MAIN_TIMER) +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) +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(__Userspace__) -SCTP_UINT_SYSCTL(output_unlocked, sctp_output_unlocked, SCTPCTL_OUTPUT_UNLOCKED) +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, NULL, 0, sctp_sysctl_handle_stats, "S,sctpstat", "SCTP statistics (struct sctp_stat)"); @@ -1307,6 +1360,7 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS) 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); + RANGECHK(SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum), SCTPCTL_OOTB_WITH_ZERO_CKSUM_MIN, SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX); #ifdef SCTP_DEBUG RANGECHK(SCTP_BASE_SYSCTL(sctp_debug_on), SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX); #endif @@ -1607,6 +1661,10 @@ sysctl_setup_sctp(void) &SCTP_BASE_SYSCTL(sctp_diag_info_code), 0, sctp_sysctl_handle_int, SCTPCTL_DIAG_INFO_CODE_DESC); + sysctl_add_oid(&sysctl_oid_top, "ootb_with_zero_cksum", CTLTYPE_INT|CTLFLAG_RW, + &SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum), 0, sctp_sysctl_handle_int, + SCTPCTL_OOTB_WITH_ZERO_CKSUM_DESC); + #ifdef SCTP_DEBUG sysctl_add_oid(&sysctl_oid_top, "debug", CTLTYPE_INT|CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_debug_on), 0, sctp_sysctl_handle_int, diff --git a/netwerk/sctp/src/netinet/sctp_sysctl.h b/netwerk/sctp/src/netinet/sctp_sysctl.h index 006a11f31d..fb77a3aeb5 100644 --- a/netwerk/sctp/src/netinet/sctp_sysctl.h +++ b/netwerk/sctp/src/netinet/sctp_sysctl.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.h 366750 2020-10-16 10:44:48Z tuexen $"); -#endif - #ifndef _NETINET_SCTP_SYSCTL_H_ #define _NETINET_SCTP_SYSCTL_H_ @@ -56,7 +51,7 @@ struct sctp_sysctl { uint32_t sctp_nrsack_enable; uint32_t sctp_pktdrop_enable; uint32_t sctp_fr_max_burst_default; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) +#if !(defined(__FreeBSD__) && !defined(__Userspace__)) uint32_t sctp_no_csum_on_loopback; #endif uint32_t sctp_peer_chunk_oh; @@ -111,7 +106,6 @@ struct sctp_sysctl { uint32_t sctp_rttvar_eqret; uint32_t sctp_steady_step; uint32_t sctp_use_dccc_ecn; - uint32_t sctp_diag_info_code; #if defined(SCTP_LOCAL_TRACE_BUF) #if defined(_WIN32) && !defined(__Userspace__) struct sctp_log *sctp_log; @@ -126,6 +120,8 @@ struct sctp_sysctl { uint32_t sctp_initial_cwnd; uint32_t sctp_blackhole; uint32_t sctp_sendall_limit; + uint32_t sctp_diag_info_code; + uint32_t sctp_ootb_with_zero_cksum; #if defined(SCTP_DEBUG) uint32_t sctp_debug_on; #endif @@ -170,7 +166,7 @@ struct sctp_sysctl { #define SCTPCTL_AUTOASCONF_DEFAULT 1 /* autoasconf: Enable SCTP Auto-ASCONF */ -#define SCTPCTL_MULTIPLEASCONFS_DESC "Enable SCTP Muliple-ASCONFs" +#define SCTPCTL_MULTIPLEASCONFS_DESC "Enable SCTP Multiple-ASCONFs" #define SCTPCTL_MULTIPLEASCONFS_MIN 0 #define SCTPCTL_MULTIPLEASCONFS_MAX 1 #define SCTPCTL_MULTIPLEASCONFS_DEFAULT SCTP_DEFAULT_MULTIPLE_ASCONFS @@ -576,6 +572,11 @@ struct sctp_sysctl { #define SCTPCTL_DIAG_INFO_CODE_MAX 65535 #define SCTPCTL_DIAG_INFO_CODE_DEFAULT 0 +#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DESC "Accept OOTB packets with zero checksum" +#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MIN 0 +#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX 1 +#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT 0 + #if defined(SCTP_DEBUG) /* debug: Configure debug output */ #define SCTPCTL_DEBUG_DESC "Configure debug output" diff --git a/netwerk/sctp/src/netinet/sctp_timer.c b/netwerk/sctp/src/netinet/sctp_timer.c index a0ca4aabf4..52cb95f26d 100644 --- a/netwerk/sctp/src/netinet/sctp_timer.c +++ b/netwerk/sctp/src/netinet/sctp_timer.c @@ -32,16 +32,11 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #define _IP_VHL #include #include -#ifdef INET6 #if defined(__FreeBSD__) && defined(__Userspace__) +#ifdef INET6 #include #endif #endif @@ -97,7 +92,10 @@ static int sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net, uint16_t threshold) { - if (net) { + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + + if (net != NULL) { net->error_count++; SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", (void *)net, net->error_count, @@ -114,7 +112,7 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } } else if ((net->pf_threshold < net->failure_threshold) && (net->error_count > net->pf_threshold)) { - if (!(net->dest_state & SCTP_ADDR_PF)) { + if ((net->dest_state & SCTP_ADDR_PF) == 0) { net->dest_state |= SCTP_ADDR_PF; net->last_active = sctp_get_tick_count(); sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); @@ -124,28 +122,23 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); } } - } - if (stcb == NULL) - return (0); - - if (net) { if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_INCR, - stcb->asoc.overall_error_count, - (stcb->asoc.overall_error_count+1), - SCTP_FROM_SCTP_TIMER, - __LINE__); + stcb->asoc.overall_error_count, + (stcb->asoc.overall_error_count+1), + SCTP_FROM_SCTP_TIMER, + __LINE__); } stcb->asoc.overall_error_count++; } } else { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_INCR, - stcb->asoc.overall_error_count, - (stcb->asoc.overall_error_count+1), - SCTP_FROM_SCTP_TIMER, - __LINE__); + stcb->asoc.overall_error_count, + (stcb->asoc.overall_error_count+1), + SCTP_FROM_SCTP_TIMER, + __LINE__); } stcb->asoc.overall_error_count++; } @@ -164,15 +157,15 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 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_2; - sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); + sctp_abort_an_association(inp, stcb, op_err, true, SCTP_SO_NOT_LOCKED); return (1); } return (0); } /* - * sctp_find_alternate_net() returns a non-NULL pointer as long - * the argument net is non-NULL. + * sctp_find_alternate_net() returns a non-NULL pointer as long as there + * exists nets, which are not being deleted. */ struct sctp_nets * sctp_find_alternate_net(struct sctp_tcb *stcb, @@ -181,20 +174,20 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, { /* Find and return an alternate network if possible */ struct sctp_nets *alt, *mnet, *min_errors_net = NULL , *max_cwnd_net = NULL; - int once; + bool looped; /* JRS 5/14/07 - Initialize min_errors to an impossible value. */ int min_errors = -1; uint32_t max_cwnd = 0; if (stcb->asoc.numnets == 1) { - /* No others but net */ + /* No selection can be made. */ return (TAILQ_FIRST(&stcb->asoc.nets)); } /* * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate net algorithm. * This algorithm chooses the active destination (not in PF state) with the largest * cwnd value. If all destinations are in PF state, unreachable, or unconfirmed, choose - * the desination that is in PF state with the lowest error count. In case of a tie, + * the destination that is in PF state with the lowest error count. In case of a tie, * choose the destination that was most recently active. */ if (mode == 2) { @@ -323,25 +316,22 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, return (max_cwnd_net); } } - mnet = net; - once = 0; - - if (mnet == NULL) { - mnet = TAILQ_FIRST(&stcb->asoc.nets); - if (mnet == NULL) { - return (NULL); - } + /* Look for an alternate net, which is active. */ + if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) { + alt = TAILQ_NEXT(net, sctp_next); + } else { + alt = TAILQ_FIRST(&stcb->asoc.nets); } + looped = false; for (;;) { - alt = TAILQ_NEXT(mnet, sctp_next); if (alt == NULL) { - once++; - if (once > 1) { - break; + if (!looped) { + alt = TAILQ_FIRST(&stcb->asoc.nets); + looped = true; } - alt = TAILQ_FIRST(&stcb->asoc.nets); + /* Definitely out of candidates. */ if (alt == NULL) { - return (NULL); + break; } } #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -361,43 +351,56 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, #else (alt->ro.ro_rt != NULL) && #endif - (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))) { - /* Found a reachable address */ + ((alt->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) && + (alt != net)) { + /* Found an alternate net, which is reachable. */ break; } - mnet = alt; + alt = TAILQ_NEXT(alt, sctp_next); } if (alt == NULL) { - /* Case where NO insv network exists (dormant state) */ - /* we rotate destinations */ - once = 0; - mnet = net; + /* + * In case no active alternate net has been found, look for + * an alternate net, which is confirmed. + */ + if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) { + alt = TAILQ_NEXT(net, sctp_next); + } else { + alt = TAILQ_FIRST(&stcb->asoc.nets); + } + looped = false; for (;;) { - if (mnet == NULL) { - return (TAILQ_FIRST(&stcb->asoc.nets)); - } - alt = TAILQ_NEXT(mnet, sctp_next); if (alt == NULL) { - once++; - if (once > 1) { - break; + if (!looped) { + alt = TAILQ_FIRST(&stcb->asoc.nets); + looped = true; } - alt = TAILQ_FIRST(&stcb->asoc.nets); + /* Definitely out of candidates. */ if (alt == NULL) { break; } } - if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && + if (((alt->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) && (alt != net)) { - /* Found an alternate address */ + /* Found an alternate net, which is confirmed. */ break; } - mnet = alt; + alt = TAILQ_NEXT(alt, sctp_next); } } if (alt == NULL) { - return (net); + /* + * In case no confirmed alternate net has been found, just + * return net, if it is not being deleted. In the other case + * just return the first net. + */ + if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) { + alt = net; + } + if (alt == NULL) { + alt = TAILQ_FIRST(&stcb->asoc.nets); + } } return (alt); } @@ -497,7 +500,9 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, unsigned int cnt_mk; uint32_t orig_flight, orig_tf; uint32_t tsnlast, tsnfirst; +#ifndef INVARIANTS int recovery_cnt = 0; +#endif /* none in flight now */ audit_tf = 0; @@ -536,8 +541,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, min_wait.tv_sec = min_wait.tv_usec = 0; } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); - sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); + sctp_log_fr(cur_rto, (uint32_t)now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); + sctp_log_fr(0, (uint32_t)min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); } /* * Our rwnd will be incorrect here since we are not adding back the @@ -559,10 +564,10 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, /* 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); - recovery_cnt++; #ifdef INVARIANTS panic("last acked >= chk on sent-Q"); #else + recovery_cnt++; SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt); sctp_recover_sent_list(stcb); if (recovery_cnt < 10) { @@ -584,7 +589,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, - chk->sent_rcv_time.tv_sec, + (uint32_t)chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_usec, SCTP_FR_T3_MARK_TIME); } @@ -596,7 +601,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(0, - chk->sent_rcv_time.tv_sec, + (uint32_t)chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_usec, SCTP_FR_T3_STOPPED); } @@ -850,11 +855,11 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, if (net != stcb->asoc.primary_destination) { /* send a immediate HB if our RTO is stale */ struct timeval now; - unsigned int ms_goneby; + uint32_t ms_goneby; (void)SCTP_GETTIME_TIMEVAL(&now); if (net->last_sent_time.tv_sec) { - ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000; + ms_goneby = (uint32_t)(now.tv_sec - net->last_sent_time.tv_sec) * 1000; } else { ms_goneby = 0; } @@ -909,7 +914,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, num_mk = 0; num_abandoned = 0; (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, - &num_mk, &num_abandoned); + &num_mk, &num_abandoned); /* FR Loss recovery just ended with the T3. */ stcb->asoc.fast_retran_loss_recovery = 0; @@ -928,16 +933,16 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, /* Backoff the timer and cwnd */ sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); - if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) || + if (((net->dest_state & SCTP_ADDR_REACHABLE) == 0) || (net->dest_state & SCTP_ADDR_PF)) { /* Move all pending over too */ sctp_move_chunks_from_net(stcb, net); /* Get the address that failed, to - * force a new src address selecton and + * force a new src address selection and * a route allocation. */ - if (net->ro._s_addr) { + if (net->ro._s_addr != NULL) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; } @@ -947,7 +952,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, #if defined(__FreeBSD__) && !defined(__Userspace__) RO_NHFREE(&net->ro); #else - if (net->ro.ro_rt) { + if (net->ro.ro_rt != NULL) { RTFREE(net->ro.ro_rt); net->ro.ro_rt = NULL; } @@ -962,7 +967,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, * change-primary then this flag must be cleared * from any net structures. */ - if (stcb->asoc.alternate) { + if (stcb->asoc.alternate != NULL) { sctp_free_remote_addr(stcb->asoc.alternate); } stcb->asoc.alternate = alt; @@ -1075,7 +1080,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp, 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_3; - sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); } else { #ifdef INVARIANTS panic("Cookie timer expires in wrong state?"); @@ -1161,7 +1166,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb) atomic_add_int(&alt->ref_count, 1); } } - if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { /* * If the address went un-reachable, we need to move to * alternates for ALL chk's in queue @@ -1256,7 +1261,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, chk->sent = SCTP_DATAGRAM_RESEND; chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; } - if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { /* * If the address went un-reachable, we need to move * to the alternate for ALL chunks in queue @@ -1347,17 +1352,17 @@ sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } static void -sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, - struct sctp_tcb *stcb) +sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, struct sctp_tcb *stcb) { struct sctp_stream_queue_pending *sp; unsigned int i, chks_in_queue = 0; int being_filled = 0; - /* - * This function is ONLY called when the send/sent queues are empty. - */ - if ((stcb == NULL) || (inp == NULL)) - return; + + KASSERT(inp != NULL, ("inp is NULL")); + KASSERT(stcb != NULL, ("stcb is NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT(TAILQ_EMPTY(&stcb->asoc.send_queue), ("send_queue not empty")); + KASSERT(TAILQ_EMPTY(&stcb->asoc.sent_queue), ("sent_queue not empty")); if (stcb->asoc.sent_queue_retran_cnt) { SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", @@ -1366,7 +1371,7 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, } if (stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { /* No stream scheduler information, initialize scheduler */ - stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 0); + stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { /* yep, we lost a stream or two */ SCTP_PRINTF("Found additional streams NOT managed by scheduler, corrected\n"); @@ -1414,15 +1419,11 @@ int sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { - uint8_t net_was_pf; + bool net_was_pf; - if (net->dest_state & SCTP_ADDR_PF) { - net_was_pf = 1; - } else { - net_was_pf = 0; - } + net_was_pf = (net->dest_state & SCTP_ADDR_PF) != 0; if (net->hb_responded == 0) { - if (net->ro._s_addr) { + if (net->ro._s_addr != NULL) { /* Invalidate the src address if we did not get * a response last time. */ @@ -1437,7 +1438,7 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } } /* Zero PBA, if it needs it */ - if (net->partial_bytes_acked) { + if (net->partial_bytes_acked > 0) { net->partial_bytes_acked = 0; } if ((stcb->asoc.total_output_queue_size > 0) && @@ -1445,10 +1446,11 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { sctp_audit_stream_queues_for_size(inp, stcb); } - if (!(net->dest_state & SCTP_ADDR_NOHB) && - !((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) { - /* when move to PF during threshold mangement, a HB has been - queued in that routine */ + if ((((net->dest_state & SCTP_ADDR_NOHB) == 0) || + (net->dest_state & SCTP_ADDR_UNCONFIRMED)) && + (net_was_pf || ((net->dest_state & SCTP_ADDR_PF) == 0))) { + /* When moving to PF during threshold management, a HB has been + queued in that routine. */ uint32_t ms_gone_by; if ((net->last_sent_time.tv_sec > 0) || @@ -1470,6 +1472,7 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, ms_gone_by = 0xffffffff; } if ((ms_gone_by >= net->heart_beat_delay) || + (net->dest_state & SCTP_ADDR_UNCONFIRMED) || (net->dest_state & SCTP_ADDR_PF)) { sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); } diff --git a/netwerk/sctp/src/netinet/sctp_timer.h b/netwerk/sctp/src/netinet/sctp_timer.h index 8cfbbca5da..166e86620f 100644 --- a/netwerk/sctp/src/netinet/sctp_timer.h +++ b/netwerk/sctp/src/netinet/sctp_timer.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_TIMER_H_ #define _NETINET_SCTP_TIMER_H_ diff --git a/netwerk/sctp/src/netinet/sctp_uio.h b/netwerk/sctp/src/netinet/sctp_uio.h index 18956f1a14..053d1cb16b 100644 --- a/netwerk/sctp/src/netinet/sctp_uio.h +++ b/netwerk/sctp/src/netinet/sctp_uio.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__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_ @@ -810,6 +805,10 @@ struct sctp_get_nonce_values { uint32_t gn_local_tag; }; +/* Values for SCTP_ACCEPT_ZERO_CHECKSUM */ +#define SCTP_EDMID_NONE 0 +#define SCTP_EDMID_LOWER_LAYER_DTLS 1 + /* Debugging logs */ struct sctp_str_log { void *stcb; /* FIXME: LP64 issue */ @@ -1104,8 +1103,10 @@ struct sctpstat { uint32_t sctps_send_burst_avoid; /* Unused */ uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already max burst inflight to net */ uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via fwd-tsn's */ - uint32_t sctps_queue_upd_ecne; /* Number of times we queued or updated an ECN chunk on send queue */ - uint32_t sctps_reserved[31]; /* Future ABI compat - remove int's from here when adding new */ + uint32_t sctps_queue_upd_ecne; /* Number of times we queued or updated an ECN chunk on send queue */ + uint32_t sctps_recvzerocrc; /* Number of accepted packets with zero CRC */ + uint32_t sctps_sendzerocrc; /* Number of packets sent with zero CRC */ + uint32_t sctps_reserved[29]; /* Future ABI compat - remove int's from here when adding new */ }; #define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1) @@ -1277,7 +1278,7 @@ int sctp_lower_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, - struct mbuf *i_pak, + struct mbuf *top, struct mbuf *control, int flags, struct sctp_sndrcvinfo *srcv diff --git a/netwerk/sctp/src/netinet/sctp_userspace.c b/netwerk/sctp/src/netinet/sctp_userspace.c index ba64aaff77..71888901fe 100644 --- a/netwerk/sctp/src/netinet/sctp_userspace.c +++ b/netwerk/sctp/src/netinet/sctp_userspace.c @@ -96,37 +96,48 @@ sctp_userspace_set_threadname(const char *name) #if !defined(_WIN32) && !defined(__native_client__) int -sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af) +sctp_userspace_get_mtu_from_ifn(uint32_t if_index) { +#if defined(INET) || defined(INET6) struct ifreq ifr; int fd; +#endif + int mtu; - 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; + if (if_index == 0xffffffff) { + mtu = 1280; } else { - return (0); + mtu = 0; +#if defined(INET) || defined(INET6) + 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 defined(INET) + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { +#else + if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0) { +#endif + if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0) { + mtu = ifr.ifr_mtu; + } + close(fd); + } + } +#endif } + return (mtu); } #endif #if defined(__native_client__) int -sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af) +sctp_userspace_get_mtu_from_ifn(uint32_t if_index) { return 1280; } #endif -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__linux__) || defined(__native_client__) || defined(__NetBSD__) || defined(_WIN32) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__linux__) || defined(__native_client__) || defined(__NetBSD__) || defined(__QNX__) || defined(_WIN32) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) int timingsafe_bcmp(const void *b1, const void *b2, size_t n) { @@ -141,43 +152,51 @@ timingsafe_bcmp(const void *b1, const void *b2, size_t n) #ifdef _WIN32 int -sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af) +sctp_userspace_get_mtu_from_ifn(uint32_t if_index) { +#if defined(INET) || defined(INET6) PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt; DWORD AdapterAddrsSize, Err; - int ret; +#endif + int mtu; - 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); - ret = -1; + if (if_index == 0xffffffff) { + mtu = 1280; + } else { + mtu = 0; +#if defined(INET) || defined(INET6) + 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); + mtu = -1; + goto cleanup; + } + } + if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { + SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); + mtu = -1; goto cleanup; } - } - if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { - SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); - 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); - ret = -1; - goto cleanup; - } - for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { - if (pAdapt->IfIndex == if_index) { - ret = pAdapt->Mtu; - break; + if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { + SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() failed with error code %d\n", Err); + mtu = -1; + goto cleanup; } + for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { + if (pAdapt->IfIndex == if_index) { + mtu = pAdapt->Mtu; + break; + } + } + cleanup: + if (pAdapterAddrs != NULL) { + GlobalFree(pAdapterAddrs); + } +#endif } -cleanup: - if (pAdapterAddrs != NULL) { - GlobalFree(pAdapterAddrs); - } - return (ret); + return (mtu); } void diff --git a/netwerk/sctp/src/netinet/sctp_usrreq.c b/netwerk/sctp/src/netinet/sctp_usrreq.c index e5fba96717..1f87682876 100644 --- a/netwerk/sctp/src/netinet/sctp_usrreq.c +++ b/netwerk/sctp/src/netinet/sctp_usrreq.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 366750 2020-10-16 10:44:48Z tuexen $"); -#endif - #include #if defined(__FreeBSD__) && !defined(__Userspace__) #include @@ -67,18 +62,26 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 366750 2020-10-16 10:44:48Z t #if defined(HAVE_SCTP_PEELOFF_SOCKOPT) #include #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ +#if defined(_WIN32) && defined(__MINGW32__) +#include +#endif extern const struct sctp_cc_functions sctp_cc_functions[]; extern const struct sctp_ss_functions sctp_ss_functions[]; -void #if defined(__Userspace__) +void 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, ...), int start_threads) #elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) +void sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED) +#elif defined(__FreeBSD__) +static void +sctp_init(void *arg SCTP_UNUSED) #else +void sctp_init(void) #endif { @@ -105,7 +108,7 @@ sctp_init(void) */ sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, - (((uint32_t)nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); + (((uint32_t)nmbclusters / 2) * MCLBYTES)); #endif /* * Now for the recv window, should we take the same amount? or @@ -160,8 +163,9 @@ sctp_init(void) sctp_addr_change_event_handler, NULL, EVENTHANDLER_PRI_FIRST); #endif } - #if defined(__FreeBSD__) && !defined(__Userspace__) +VNET_SYSINIT(sctp_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, sctp_init, NULL); + #ifdef VIMAGE static void sctp_finish(void *unused __unused) @@ -198,44 +202,67 @@ sctp_finish(void) #endif void -sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) +sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint32_t mtu, bool resend) { + struct sctp_association *asoc; struct sctp_tmit_chunk *chk; - uint16_t overhead; + uint32_t overhead; - /* Adjust that too */ - stcb->asoc.smallest_mtu = nxtsz; - /* now off to subtract IP_DF flag if needed */ - 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); + asoc = &stcb->asoc; + KASSERT(mtu < asoc->smallest_mtu, + ("Currently only reducing association MTU %u supported (MTU %u)", + asoc->smallest_mtu, mtu)); + asoc->smallest_mtu = mtu; + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + overhead = SCTP_MIN_OVERHEAD; + } else { +#if defined(__Userspace__) + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { + overhead = sizeof(struct sctphdr); + } else { + overhead = SCTP_MIN_V4_OVERHEAD; + } +#else + overhead = SCTP_MIN_V4_OVERHEAD; +#endif } - TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { - if ((chk->send_size + overhead) > nxtsz) { + if (asoc->idata_supported) { + if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) { + overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); + } + } else { + if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) { + overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); + } + } + KASSERT(overhead % 4 == 0, + ("overhead (%u) not a multiple of 4", overhead)); + TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { + if (((uint32_t)chk->send_size + overhead) > mtu) { chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; } } - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if ((chk->send_size + overhead) > nxtsz) { - /* - * For this guy we also mark for immediate resend - * since we sent to big of chunk - */ + TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { + if (((uint32_t)chk->send_size + overhead) > mtu) { chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - if (chk->sent < SCTP_DATAGRAM_RESEND) { + if (resend && chk->sent < SCTP_DATAGRAM_RESEND) { + /* + * If requested, mark the chunk for immediate + * resend, since we sent it being too big. + */ sctp_flight_size_decrease(chk); sctp_total_flight_decrease(stcb, chk); chk->sent = SCTP_DATAGRAM_RESEND; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); + sctp_ucount_incr(asoc->sent_queue_retran_cnt); chk->rec.data.doing_fast_retransmit = 0; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, - chk->whoTo->flight_size, - chk->book_size, - (uint32_t)(uintptr_t)chk->whoTo, - chk->rec.data.tsn); + chk->whoTo->flight_size, + chk->book_size, + (uint32_t)(uintptr_t)chk->whoTo, + chk->rec.data.tsn); } - /* Clear any time so NO RTT is being done */ + /* Clear any time, so NO RTT is being done. */ if (chk->do_rtt == 1) { chk->do_rtt = 0; chk->whoTo->rto_needed = 1; @@ -291,7 +318,7 @@ sctp_notify(struct sctp_inpcb *inp, } 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); + sctp_abort_notification(stcb, true, false, 0, NULL, SCTP_SO_NOT_LOCKED); #if defined(__APPLE__) && !defined(__Userspace__) so = SCTP_INP_SO(inp); atomic_add_int(&stcb->asoc.refcnt, 1); @@ -346,7 +373,7 @@ sctp_notify(struct sctp_inpcb *inp, } /* Update the association MTU */ if (stcb->asoc.smallest_mtu > next_mtu) { - sctp_pathmtu_adjustment(stcb, next_mtu); + sctp_pathmtu_adjustment(stcb, next_mtu, true); } /* Finally, start the PMTU timer if it was running before. */ if (timer_stopped) { @@ -360,6 +387,96 @@ sctp_notify(struct sctp_inpcb *inp, #endif #if !defined(__Userspace__) +#if defined(__FreeBSD__) +void sctp_ctlinput(struct icmp *icmp) +{ + struct ip *inner_ip, *outer_ip; + struct sctphdr *sh; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctp_init_chunk *ch; + struct sockaddr_in src, dst; + + if (icmp_errmap(icmp) == 0) + return; + + outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); + inner_ip = &icmp->icmp_ip; + sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + 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; + dst.sin_len = sizeof(struct sockaddr_in); + 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 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) + 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; + } + } + sctp_notify(inp, stcb, net, + icmp->icmp_type, + icmp->icmp_code, + ntohs(inner_ip->ip_len), + (uint32_t)ntohs(icmp->icmp_nextmtu)); + } 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); + } + } +} +#else 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) @@ -367,24 +484,20 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip, struct ifnet *ifp SCTP_UN sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) #endif { -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct ip *outer_ip; -#endif struct ip *inner_ip; struct sctphdr *sh; 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 !defined(__FreeBSD__) && !defined(__Userspace__) if (sa->sa_family != AF_INET || ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { return; } +#endif if (PRC_IS_REDIRECT(cmd)) { vip = NULL; } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { @@ -394,9 +507,6 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) 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; @@ -438,41 +548,16 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) return; } } else { -#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 } 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) && + if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && (stcb->sctp_socket != NULL)) { struct socket *upcall_socket; @@ -505,6 +590,7 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) } #endif #endif +#endif #if defined(__FreeBSD__) && !defined(__Userspace__) static int @@ -521,8 +607,9 @@ sctp_getcred(SYSCTL_HANDLER_ARGS) /* FIX, for non-bsd is this right? */ vrf_id = SCTP_DEFAULT_VRFID; + if (req->newptr == NULL) + return (EINVAL); error = priv_check(req->td, PRIV_NETINET_GETCRED); - if (error) return (error); @@ -573,13 +660,10 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, "Get the ucred of a SCTP connection"); #endif -#ifdef INET -#if defined(_WIN32) || defined(__Userspace__) -int -#elif defined(__FreeBSD__) -static void +#if defined(__FreeBSD__) && !defined(__Userspace__) +void #else -static int +int #endif sctp_abort(struct socket *so) { @@ -587,7 +671,6 @@ sctp_abort(struct socket *so) struct epoch_tracker et; #endif struct sctp_inpcb *inp; - uint32_t flags; inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { @@ -599,28 +682,28 @@ sctp_abort(struct socket *so) #endif } + SCTP_INP_WLOCK(inp); #if defined(__FreeBSD__) && !defined(__Userspace__) NET_EPOCH_ENTER(et); #endif - sctp_must_try_again: - flags = inp->sctp_flags; #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 17); #endif - 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)))) { + if (((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)) { + inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP; #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 16); #endif + SCTP_INP_WUNLOCK(inp); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); + SCTP_CALLED_AFTER_CMPSET_OFCLOSE); SOCK_LOCK(so); +#if defined(__FreeBSD__) && !defined(__Userspace__) + KASSERT(!SOLISTENING(so), + ("sctp_abort: called on listening socket %p", so)); +#endif SCTP_SB_CLEAR(so->so_snd); - /* same for the rcv ones, they are only - * here for the accounting/select. - */ SCTP_SB_CLEAR(so->so_rcv); - #if defined(__APPLE__) && !defined(__Userspace__) so->so_usecount--; #else @@ -629,19 +712,16 @@ sctp_abort(struct socket *so) #endif SOCK_UNLOCK(so); } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } + SCTP_INP_WUNLOCK(inp); } #if defined(__FreeBSD__) && !defined(__Userspace__) NET_EPOCH_EXIT(et); - return; #else return (0); #endif } +#ifdef INET #if defined(__Userspace__) int #else @@ -800,7 +880,6 @@ sctp_close(struct socket *so) struct epoch_tracker et; #endif struct sctp_inpcb *inp; - uint32_t flags; inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) @@ -809,60 +888,59 @@ sctp_close(struct socket *so) /* Inform all the lower layer assoc that we * are done. */ + SCTP_INP_WLOCK(inp); #if defined(__FreeBSD__) && !defined(__Userspace__) NET_EPOCH_ENTER(et); #endif - sctp_must_try_again: - flags = inp->sctp_flags; #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 17); #endif - 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)))) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { + inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP; #if defined(__Userspace__) if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { #else if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { #endif + (SCTP_SBAVAIL(&so->so_rcv) > 0)) { #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 13); #endif + SCTP_INP_WUNLOCK(inp); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); + SCTP_CALLED_AFTER_CMPSET_OFCLOSE); } else { #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 14); #endif + SCTP_INP_WUNLOCK(inp); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); + SCTP_CALLED_AFTER_CMPSET_OFCLOSE); } /* The socket is now detached, no matter what * the state of the SCTP association. */ SOCK_LOCK(so); +#if defined(__FreeBSD__) && !defined(__Userspace__) + if (!SOLISTENING(so)) { + SCTP_SB_CLEAR(so->so_snd); + SCTP_SB_CLEAR(so->so_rcv); + } +#else SCTP_SB_CLEAR(so->so_snd); - /* same for the rcv ones, they are only - * here for the accounting/select. - */ SCTP_SB_CLEAR(so->so_rcv); - +#endif #if !(defined(__APPLE__) && !defined(__Userspace__)) /* Now null out the reference, we are completely detached. */ so->so_pcb = NULL; #endif SOCK_UNLOCK(so); } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } + SCTP_INP_WUNLOCK(inp); } #if defined(__FreeBSD__) && !defined(__Userspace__) NET_EPOCH_EXIT(et); #endif - return; } #else int @@ -873,12 +951,8 @@ sctp_detach(struct socket *so) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - return; -#else SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); -#endif } sctp_must_try_again: flags = inp->sctp_flags; @@ -887,24 +961,19 @@ sctp_detach(struct socket *so) #endif 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)))) { -#if defined(__Userspace__) - if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { -#else if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { -#endif + (SCTP_SBAVAIL(&so->so_rcv) > 0)) { #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 13); #endif sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); + SCTP_CALLED_AFTER_CMPSET_OFCLOSE); } else { #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 13); #endif sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); + SCTP_CALLED_AFTER_CMPSET_OFCLOSE); } /* The socket is now detached, no matter what * the state of the SCTP association. @@ -924,11 +993,7 @@ sctp_detach(struct socket *so) goto sctp_must_try_again; } } -#if defined(__FreeBSD__) && !defined(__Userspace__) - return; -#else return (0); -#endif } #endif @@ -974,9 +1039,22 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { goto connected_type; - } else if (addr == NULL) { + } + + error = 0; + if (addr == NULL) { SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); error = EDESTADDRREQ; + } else if (addr->sa_family != AF_INET) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); + error = EAFNOSUPPORT; +#if defined(HAVE_SA_LEN) + } else if (addr->sa_len != sizeof(struct sockaddr_in)) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; +#endif + } + if (error != 0) { sctp_m_freem(m); if (control) { sctp_m_freem(control); @@ -984,19 +1062,6 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, } return (error); } -#ifdef INET6 - if (addr->sa_family != AF_INET) { - /* must be a v4 address! */ - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); - sctp_m_freem(m); - if (control) { - sctp_m_freem(control); - control = NULL; - } - error = EDESTADDRREQ; - return (error); - } -#endif /* INET6 */ connected_type: /* now what about control */ if (control) { @@ -1054,7 +1119,12 @@ connected_type: int sctp_disconnect(struct socket *so) { +#if defined(__FreeBSD__) && !defined(__Userspace__) + struct epoch_tracker et; +#endif struct sctp_inpcb *inp; + struct sctp_association *asoc; + struct sctp_tcb *stcb; inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { @@ -1062,199 +1132,214 @@ sctp_disconnect(struct socket *so) return (ENOTCONN); } SCTP_INP_RLOCK(inp); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - if (LIST_EMPTY(&inp->sctp_asoc_list)) { - /* No connection */ - SCTP_INP_RUNLOCK(inp); - return (0); - } else { + KASSERT(inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE || + inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL, + ("Not a one-to-one style socket")); + stcb = LIST_FIRST(&inp->sctp_asoc_list); + if (stcb == NULL) { + SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); + return (ENOTCONN); + } + SCTP_TCB_LOCK(stcb); + asoc = &stcb->asoc; + if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { + /* We are about to be freed, out of here */ + SCTP_TCB_UNLOCK(stcb); + SCTP_INP_RUNLOCK(inp); + return (0); + } #if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct sctp_association *asoc; - struct sctp_tcb *stcb; - - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - SCTP_TCB_LOCK(stcb); - asoc = &stcb->asoc; - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - /* We are about to be freed, out of here */ - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - return (0); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); + NET_EPOCH_ENTER(et); #endif #if defined(__Userspace__) - if (((so->so_options & SCTP_SO_LINGER) && - (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { + if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || + (SCTP_SBAVAIL(&so->so_rcv) > 0)) { #else - if (((so->so_options & SO_LINGER) && - (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { + if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || + (SCTP_SBAVAIL(&so->so_rcv) > 0)) { #endif - if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) { - /* Left with Data unread */ - struct mbuf *op_err; + if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) { + /* Left with Data unread */ + 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) == 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); - /* No unlock tcb assoc is gone */ + 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) == 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); + /* No unlock tcb assoc is gone */ #if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); + 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->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - goto abort_anyway; - } - 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; + 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->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { + goto abort_anyway; + } + 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(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 (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, NULL); - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_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 (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; } else { - /* - * we still got (or just got) data to send, - * so set SHUTDOWN_PENDING - */ - /* - * XXX sockets draft says that SCTP_EOF - * should be sent with no data. currently, - * we will allow user data to be sent first - * and move to SHUTDOWN-PENDING - */ - 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) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - 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; - sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - 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); -#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); - } + netp = stcb->asoc.primary_destination; } - soisdisconnecting(so); + 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); + sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); + } + } else { + /* + * we still got (or just got) data to send, + * so set SHUTDOWN_PENDING + */ + /* + * XXX sockets draft says that SCTP_EOF + * should be sent with no data. currently, + * we will allow user data to be sent first + * and move to SHUTDOWN-PENDING + */ + 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) && + (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { + 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; + sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); + SCTP_STAT_INCR_COUNTER32(sctps_aborted); + 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); #if defined(__FreeBSD__) && !defined(__Userspace__) NET_EPOCH_EXIT(et); #endif - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); return (0); + } else { + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); } - /* not reached */ - } else { - /* UDP model does not support this */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - return (EOPNOTSUPP); } + soisdisconnecting(so); +#if defined(__FreeBSD__) && !defined(__Userspace__) + NET_EPOCH_EXIT(et); +#endif + SCTP_TCB_UNLOCK(stcb); + SCTP_INP_RUNLOCK(inp); + return (0); } #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 - * will not be able to read the data, the socket - * will block that from happening. - */ +#if defined(__FreeBSD__) && !defined(__Userspace__) + struct epoch_tracker et; +#endif + struct sctp_tcb *stcb; + struct sctp_queued_to_read *control, *ncontrol; struct sctp_inpcb *inp; + struct mbuf *m, *op_err; + bool need_to_abort = false; + /* + * For 1-to-1 style sockets, flush the read queue and trigger an + * ungraceful shutdown of the association, if and only if user messages + * are lost. Loosing notifications does not need to be signalled to the + * peer. + */ + if (how == PRU_FLUSH_WR) { + /* This function is only relevant for the read directions. */ + return (0); + } inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } - SCTP_INP_RLOCK(inp); - /* For the 1 to many model this does nothing */ + SCTP_INP_WLOCK(inp); if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { - SCTP_INP_RUNLOCK(inp); + /* For 1-to-many style sockets this function does nothing. */ + SCTP_INP_WUNLOCK(inp); return (0); } - SCTP_INP_RUNLOCK(inp); - 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 - */ - SCTP_INP_WLOCK(inp); - SCTP_INP_READ_LOCK(inp); - inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; - SCTP_INP_READ_UNLOCK(inp); + stcb = LIST_FIRST(&inp->sctp_asoc_list); + if (stcb != NULL) { + SCTP_TCB_LOCK(stcb); + } + SCTP_INP_READ_LOCK(inp); + inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; + SOCK_LOCK(so); + TAILQ_FOREACH_SAFE(control, &inp->read_queue, next, ncontrol) { + if ((control->spec_flags & M_NOTIFICATION) == 0) { + need_to_abort = true; + } + TAILQ_REMOVE(&inp->read_queue, control, next); + control->on_read_q = 0; + for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { + sctp_sbfree(control, control->stcb, &so->so_rcv, m); + } + if (control->on_strm_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); + } else { + if (stcb != NULL) { + stcb->asoc.size_on_all_streams += control->length; + } + } + } + SOCK_UNLOCK(so); + SCTP_INP_READ_UNLOCK(inp); + if (need_to_abort && (stcb != NULL)) { + inp->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; SCTP_INP_WUNLOCK(inp); - so->so_rcv.sb_cc = 0; - so->so_rcv.sb_mbcnt = 0; - so->so_rcv.sb_mb = NULL; + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); +#if defined(__FreeBSD__) && !defined(__Userspace__) + NET_EPOCH_ENTER(et); +#endif + sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_LOCKED); +#if defined(__FreeBSD__) && !defined(__Userspace__) + NET_EPOCH_EXIT(et); +#endif + return (ECONNABORTED); } - 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; + if (stcb != NULL) { + SCTP_TCB_UNLOCK(stcb); } + SCTP_INP_WUNLOCK(inp); return (0); } #endif @@ -1356,6 +1441,8 @@ sctp_shutdown(struct socket *so) 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 { /* * We still got (or just got) data to send, so set @@ -1374,14 +1461,13 @@ sctp_shutdown(struct socket *so) 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); + op_err, false, 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); @@ -1559,7 +1645,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, sin = &sctp_ifa->address.sin; if (sin->sin_addr.s_addr == 0) { /* - * we skip unspecifed + * we skip unspecified * addresses */ continue; @@ -1611,7 +1697,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, sin6 = &sctp_ifa->address.sin6; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { /* - * we skip unspecifed + * we skip unspecified * addresses */ continue; @@ -1760,7 +1846,7 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, size_t limit, struct sockaddr *addr) { - size_t size = 0; + size_t size; #ifdef SCTP_MVRF uint32_t id; #endif @@ -1772,6 +1858,7 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, * in more than one VRF. */ /* fill up addresses for all VRFs on the endpoint */ + size = 0; for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) { size += sctp_fill_up_addresses_vrf(inp, stcb, limit, addr, inp->m_vrf_ids[id]); @@ -1786,17 +1873,17 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, return (size); } -static int -sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) +static size_t +sctp_max_size_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) { - int cnt = 0; - struct sctp_vrf *vrf = NULL; + struct sctp_vrf *vrf; + size_t size; /* - * In both sub-set bound an bound_all cases we return the MAXIMUM - * number of addresses that you COULD get. In reality the sub-set - * bound may have an exclusion list for a given TCB OR in the - * bound-all case a TCB may NOT include the loopback or other + * In both sub-set bound an bound_all cases we return the size of + * the maximum number of addresses that you could get. In reality + * the sub-set bound may have an exclusion list for a given TCB or + * in the bound-all case a TCB may NOT include the loopback or other * addresses as well. */ SCTP_IPI_ADDR_LOCK_ASSERT(); @@ -1804,6 +1891,7 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) if (vrf == NULL) { return (0); } + size = 0; if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { struct sctp_ifn *sctp_ifn; struct sctp_ifa *sctp_ifa; @@ -1816,22 +1904,22 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) case AF_INET: #ifdef INET6 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) - cnt += sizeof(struct sockaddr_in6); + size += sizeof(struct sockaddr_in6); else - cnt += sizeof(struct sockaddr_in); + size += sizeof(struct sockaddr_in); #else - cnt += sizeof(struct sockaddr_in); + size += sizeof(struct sockaddr_in); #endif break; #endif #ifdef INET6 case AF_INET6: - cnt += sizeof(struct sockaddr_in6); + size += sizeof(struct sockaddr_in6); break; #endif #if defined(__Userspace__) case AF_CONN: - cnt += sizeof(struct sockaddr_conn); + size += sizeof(struct sockaddr_conn); break; #endif default: @@ -1848,22 +1936,22 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) case AF_INET: #ifdef INET6 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) - cnt += sizeof(struct sockaddr_in6); + size += sizeof(struct sockaddr_in6); else - cnt += sizeof(struct sockaddr_in); + size += sizeof(struct sockaddr_in); #else - cnt += sizeof(struct sockaddr_in); + size += sizeof(struct sockaddr_in); #endif break; #endif #ifdef INET6 case AF_INET6: - cnt += sizeof(struct sockaddr_in6); + size += sizeof(struct sockaddr_in6); break; #endif #if defined(__Userspace__) case AF_CONN: - cnt += sizeof(struct sockaddr_conn); + size += sizeof(struct sockaddr_conn); break; #endif default: @@ -1871,13 +1959,13 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) } } } - return (cnt); + return (size); } -static int -sctp_count_max_addresses(struct sctp_inpcb *inp) +static size_t +sctp_max_size_addresses(struct sctp_inpcb *inp) { - int cnt = 0; + size_t size; #ifdef SCTP_MVRF int id; #endif @@ -1888,16 +1976,17 @@ sctp_count_max_addresses(struct sctp_inpcb *inp) * FIX ME: ?? this WILL count duplicate addresses if they appear * in more than one VRF. */ - /* count addresses for all VRFs on the endpoint */ + /* Maximum size of all addresses for all VRFs on the endpoint */ + size = 0; for (id = 0; id < inp->num_vrfs; id++) { - cnt += sctp_count_max_addresses_vrf(inp, inp->m_vrf_ids[id]); + size += sctp_max_size_addresses_vrf(inp, inp->m_vrf_ids[id]); } #else - /* count addresses for the endpoint's default VRF */ - cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); + /* Maximum size of all addresses for the endpoint's default VRF */ + size = sctp_max_size_addresses_vrf(inp, inp->def_vrf_id); #endif SCTP_IPI_ADDR_RUNLOCK(); - return (cnt); + return (size); } static int @@ -1975,8 +2064,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, } } #endif /* INET6 */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == - SCTP_PCB_FLAGS_UNBOUND) { + if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { /* Bind a ephemeral port */ error = sctp_inpcb_bind(so, NULL, NULL, p); if (error) { @@ -1988,26 +2076,21 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, vrf_id = inp->def_vrf_id; /* We are GOOD to go */ - stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, + stcb = sctp_aloc_assoc_connected(inp, sa, &error, 0, 0, vrf_id, + inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, #if defined(__FreeBSD__) && !defined(__Userspace__) - (struct thread *)p, + (struct thread *)p, #elif defined(_WIN32) && !defined(__Userspace__) - (PKTHREAD)p, + (PKTHREAD)p, #else - (struct proc *)p, + (struct proc *)p, #endif - SCTP_INITIALIZE_AUTH_PARAMS); + SCTP_INITIALIZE_AUTH_PARAMS); if (stcb == NULL) { /* Gak! no memory */ goto out_now; } - 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); - } SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); /* move to second address */ switch (sa->sa_family) { @@ -2323,7 +2406,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } break; } - case SCTP_PLUGGABLE_SS: + case SCTP_STREAM_SCHEDULER: { struct sctp_assoc_value *av; @@ -2350,7 +2433,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } break; } - case SCTP_SS_VALUE: + case SCTP_STREAM_SCHEDULER_VALUE: { struct sctp_stream_value *av; @@ -2635,13 +2718,12 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, case SCTP_MAXSEG: { struct sctp_assoc_value *av; - int ovh; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); + av->assoc_value = stcb->asoc.sctp_frag_point; SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -2649,15 +2731,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, ((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; - } else { - ovh = SCTP_MED_V4_OVERHEAD; - } - if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) - av->assoc_value = 0; - else - av->assoc_value = inp->sctp_frag_point - ovh; + av->assoc_value = inp->sctp_frag_point; SCTP_INP_RUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -2744,7 +2818,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); SCTP_INP_RLOCK(inp); - *value = sctp_count_max_addresses(inp); + *value = (uint32_t)sctp_max_size_addresses(inp); SCTP_INP_RUNLOCK(inp); *optsize = sizeof(uint32_t); break; @@ -2752,14 +2826,14 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, case SCTP_GET_REMOTE_ADDR_SIZE: { uint32_t *value; - size_t size; struct sctp_nets *net; + size_t size; SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); /* FIXME MT: change to sctp_assoc_value? */ - SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value); + SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t)*value); - if (stcb) { + if (stcb != NULL) { size = 0; /* Count the sizes */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { @@ -2792,11 +2866,16 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } } SCTP_TCB_UNLOCK(stcb); - *value = (uint32_t) size; + *value = (uint32_t)size; *optsize = sizeof(uint32_t); } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; + if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && + ((sctp_assoc_t)*value <= SCTP_ALL_ASSOC)) { + error = EINVAL; + } else { + error = ENOENT; + } + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); } break; } @@ -2814,7 +2893,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); - if (stcb) { + if (stcb != NULL) { left = *optsize - offsetof(struct sctp_getaddresses, addr); *optsize = offsetof(struct sctp_getaddresses, addr); addr = &saddr->addr[0].sa; @@ -2875,8 +2954,13 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } SCTP_TCB_UNLOCK(stcb); } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; + if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && + (saddr->sget_assoc_id <= SCTP_ALL_ASSOC)) { + error = EINVAL; + } else { + error = ENOENT; + } + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); } break; } @@ -2888,12 +2972,18 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); - limit = *optsize - offsetof(struct sctp_getaddresses, addr); - actual = sctp_fill_up_addresses(inp, stcb, limit, &saddr->addr[0].sa); - if (stcb) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && + ((saddr->sget_assoc_id == SCTP_CURRENT_ASSOC) || + (saddr->sget_assoc_id == SCTP_ALL_ASSOC))) { + error = EINVAL; + } else { + limit = *optsize - offsetof(struct sctp_getaddresses, addr); + actual = sctp_fill_up_addresses(inp, stcb, limit, &saddr->addr[0].sa); + *optsize = offsetof(struct sctp_getaddresses, addr) + actual; + } + if (stcb != NULL) { SCTP_TCB_UNLOCK(stcb); } - *optsize = offsetof(struct sctp_getaddresses, addr) + actual; break; } case SCTP_PEER_ADDR_PARAMS: @@ -3237,7 +3327,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 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); + sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb); net = stcb->asoc.primary_destination; if (net != NULL) { #ifdef HAVE_SA_LEN @@ -3396,7 +3486,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; sasoc->sasoc_number_peer_destinations = 0; sasoc->sasoc_peer_rwnd = 0; - sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); + sasoc->sasoc_local_rwnd = (uint32_t)sbspace(&inp->sctp_socket->so_rcv); SCTP_INP_RUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -3502,7 +3592,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, { struct sctp_hmacalgo *shmac; sctp_hmaclist_t *hmaclist; - uint32_t size; + size_t size; int i; SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); @@ -3517,8 +3607,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } /* is there room for all of the hmac ids? */ size = sizeof(*shmac) + (hmaclist->num_algo * - sizeof(shmac->shmac_idents[0])); - if ((size_t)(*optsize) < size) { + sizeof(shmac->shmac_idents[0])); + if (*optsize < size) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; SCTP_INP_RUNLOCK(inp); @@ -4511,7 +4601,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_REUSE_PORT: { SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { /* Can't set it after we are bound */ error = EINVAL; break; @@ -4582,7 +4672,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (av->assoc_value == 0) { inp->idata_supported = 0; } else { - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && + 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 { @@ -4726,29 +4816,27 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } - case SCTP_PLUGGABLE_SS: + case SCTP_STREAM_SCHEDULER: { struct sctp_assoc_value *av; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); if ((av->assoc_value != SCTP_SS_DEFAULT) && - (av->assoc_value != SCTP_SS_ROUND_ROBIN) && - (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && - (av->assoc_value != SCTP_SS_PRIORITY) && - (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && - (av->assoc_value != SCTP_SS_FIRST_COME)) { + (av->assoc_value != SCTP_SS_RR) && + (av->assoc_value != SCTP_SS_RR_PKT) && + (av->assoc_value != SCTP_SS_PRIO) && + (av->assoc_value != SCTP_SS_FB) && + (av->assoc_value != SCTP_SS_FCFS)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } 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_clear(stcb, &stcb->asoc, true); 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); + stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -4766,12 +4854,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 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_clear(stcb, &stcb->asoc, true); 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); + stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); @@ -4779,7 +4865,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } - case SCTP_SS_VALUE: + case SCTP_STREAM_SCHEDULER_VALUE: { struct sctp_stream_value *av; @@ -5757,22 +5843,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_MAXSEG: { struct sctp_assoc_value *av; - int ovh; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MED_OVERHEAD; - } else { - ovh = SCTP_MED_V4_OVERHEAD; - } if (stcb) { - if (av->assoc_value) { - stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); - } else { - stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; - } + stcb->asoc.sctp_frag_point = av->assoc_value; SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -5780,12 +5856,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, ((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) { - inp->sctp_frag_point = (av->assoc_value + ovh); - } else { - inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; - } + inp->sctp_frag_point = av->assoc_value; SCTP_INP_WUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -5866,9 +5937,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } else { sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_RLOCK(inp); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { SCTP_TCB_LOCK(stcb); if (events->sctp_association_event) { @@ -5925,21 +5994,21 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } /* Send up the sender dry event only for 1-to-1 style sockets. */ if (events->sctp_sender_dry_event) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + if (((inp->sctp_flags & (SCTP_PCB_FLAGS_TCPTYPE | SCTP_PCB_FLAGS_IN_TCPPOOL)) != 0) && + !SCTP_IS_LISTENING(inp)) { stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb) { + if (stcb != NULL) { SCTP_TCB_LOCK(stcb); 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_LOCKED); + sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); } SCTP_TCB_UNLOCK(stcb); } } } - SCTP_INP_RUNLOCK(inp); + SCTP_INP_WUNLOCK(inp); break; } case SCTP_ADAPTATION_LAYER: @@ -6112,6 +6181,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, return (EINVAL); } if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && + (paddrp->spp_pathmtu > 0) && ((paddrp->spp_pathmtu < SCTP_SMALLEST_PMTU) || (paddrp->spp_pathmtu > SCTP_LARGEST_PMTU))) { if (stcb) @@ -6125,10 +6195,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 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)) { + if (((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) && + ((net->dest_state & SCTP_ADDR_NOHB) == 0)) { sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); } net->dest_state |= SCTP_ADDR_NOHB; } @@ -6153,31 +6223,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 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_11); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); } net->dest_state |= SCTP_ADDR_NO_PMTUD; - net->mtu = paddrp->spp_pathmtu; - switch (net->ro._l_addr.sa.sa_family) { + if (paddrp->spp_pathmtu > 0) { + 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; + case AF_INET: + net->mtu += SCTP_MIN_V4_OVERHEAD; + break; #endif #ifdef INET6 - case AF_INET6: - net->mtu += SCTP_MIN_OVERHEAD; - break; + case AF_INET6: + net->mtu += SCTP_MIN_OVERHEAD; + break; #endif #if defined(__Userspace__) - case AF_CONN: - net->mtu += sizeof(struct sctphdr); - break; + 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); + default: + break; + } + if (net->mtu < stcb->asoc.smallest_mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu, true); + } } } if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { @@ -6186,7 +6258,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } net->dest_state &= ~SCTP_ADDR_NO_PMTUD; } - if (paddrp->spp_pathmaxrxt) { + if (paddrp->spp_pathmaxrxt > 0) { if (net->dest_state & SCTP_ADDR_PF) { if (net->error_count > paddrp->spp_pathmaxrxt) { net->dest_state &= ~SCTP_ADDR_PF; @@ -6229,7 +6301,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, #endif } else { /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ - if (paddrp->spp_pathmaxrxt != 0) { + if (paddrp->spp_pathmaxrxt > 0) { stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { if (net->dest_state & SCTP_ADDR_PF) { @@ -6261,7 +6333,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, net->failure_threshold = paddrp->spp_pathmaxrxt; } } - if (paddrp->spp_flags & SPP_HB_ENABLE) { if (paddrp->spp_hbinterval != 0) { stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; @@ -6286,9 +6357,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } if (paddrp->spp_flags & SPP_HB_DISABLE) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (!(net->dest_state & SCTP_ADDR_NOHB)) { + if ((net->dest_state & SCTP_ADDR_NOHB) == 0) { net->dest_state |= SCTP_ADDR_NOHB; - if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15); @@ -6301,34 +6372,38 @@ 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_16); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16); } net->dest_state |= SCTP_ADDR_NO_PMTUD; - net->mtu = paddrp->spp_pathmtu; - switch (net->ro._l_addr.sa.sa_family) { + if (paddrp->spp_pathmtu > 0) { + 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; + case AF_INET: + net->mtu += SCTP_MIN_V4_OVERHEAD; + break; #endif #ifdef INET6 - case AF_INET6: - net->mtu += SCTP_MIN_OVERHEAD; - break; + case AF_INET6: + net->mtu += SCTP_MIN_OVERHEAD; + break; #endif #if defined(__Userspace__) - case AF_CONN: - net->mtu += sizeof(struct sctphdr); - break; + 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); + default: + break; + } + if (net->mtu < stcb->asoc.smallest_mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu, true); + } } } - stcb->asoc.default_mtu = paddrp->spp_pathmtu; + if (paddrp->spp_pathmtu > 0) { + 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) { @@ -6374,7 +6449,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, * For the TOS/FLOWLABEL stuff you set it * with the options on the socket */ - if (paddrp->spp_pathmaxrxt != 0) { + if (paddrp->spp_pathmaxrxt > 0) { inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; } @@ -6400,7 +6475,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 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; + if (paddrp->spp_pathmtu > 0) { + inp->sctp_ep.default_mtu = paddrp->spp_pathmtu; + } sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); } if (paddrp->spp_flags & SPP_DSCP) { @@ -6597,11 +6674,11 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if ((stcb != NULL) && (net != NULL)) { if (net != stcb->asoc.primary_destination) { - if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { /* 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_PF) == 0) && (net->dest_state & SCTP_ADDR_REACHABLE)) { sctp_free_remote_addr(stcb->asoc.alternate); stcb->asoc.alternate = NULL; @@ -7716,6 +7793,23 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } + case SCTP_ACCEPT_ZERO_CHECKSUM: + { + uint32_t *value; + + SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); + if ((*value == SCTP_EDMID_NONE) || + (*value == SCTP_EDMID_LOWER_LAYER_DTLS)) { + SCTP_INP_WLOCK(inp); + inp->rcv_edmid = *value; + SCTP_INP_WUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + break; + } + default: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; @@ -7944,8 +8038,7 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p) goto out_now; } #endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == - SCTP_PCB_FLAGS_UNBOUND) { + if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { /* Bind a ephemeral port */ error = sctp_inpcb_bind(so, NULL, NULL, p); if (error) { @@ -8005,19 +8098,14 @@ 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, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, p, - SCTP_INITIALIZE_AUTH_PARAMS); + stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 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; } - 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); - } SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); @@ -8112,7 +8200,7 @@ sctpconn_connect(struct socket *so, struct sockaddr *addr) goto out_now; } #endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == SCTP_PCB_FLAGS_UNBOUND) { + if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { /* Bind a ephemeral port */ error = sctp_inpcb_bind(so, NULL, NULL, p); if (error) { @@ -8172,19 +8260,14 @@ sctpconn_connect(struct socket *so, struct sockaddr *addr) } #endif /* We are GOOD to go */ - 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); + stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 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; } - 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); - } SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); @@ -8334,20 +8417,12 @@ sctp_listen(struct socket *so, struct proc *p) } } } - SCTP_INP_RLOCK(inp); + SCTP_INP_INFO_WLOCK(); + SCTP_INP_WLOCK(inp); #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); } -#endif -#if defined(__FreeBSD__) || defined(__Userspace__) - SOCK_LOCK(so); - error = solisten_proto_check(so); - SOCK_UNLOCK(so); - if (error) { - SCTP_INP_RUNLOCK(inp); - return (error); - } #endif if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { @@ -8358,36 +8433,65 @@ sctp_listen(struct socket *so, struct proc *p) * - We must then move the guy that was listener to the TCP Pool. */ if (sctp_swap_inpcb_for_listen(inp)) { - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); - return (EADDRINUSE); + error = EADDRINUSE; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + goto out; } } - +#if defined(__FreeBSD__) || defined(__Userspace__) + SOCK_LOCK(so); + error = solisten_proto_check(so); + if (error) { + SOCK_UNLOCK(so); + goto out; + } +#endif if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { - /* We are already connected AND the TCP model */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); - return (EADDRINUSE); + SOCK_UNLOCK(so); +#if defined(__FreeBSD__) && !defined(__Userspace__) + solisten_proto_abort(so); +#endif + error = EADDRINUSE; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + goto out; + } + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && + ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || + (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED))) { + SOCK_UNLOCK(so); +#if defined(__FreeBSD__) && !defined(__Userspace__) + solisten_proto_abort(so); +#endif + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + goto out; } - SCTP_INP_RUNLOCK(inp); if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { - /* We must do a bind. */ - if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { + if ((error = sctp_inpcb_bind_locked(inp, NULL, NULL, p))) { + SOCK_UNLOCK(so); +#if defined(__FreeBSD__) && !defined(__Userspace__) + solisten_proto_abort(so); +#endif /* bind error, probably perm */ - return (error); + goto out; } } - SCTP_INP_WLOCK(inp); #if defined(__FreeBSD__) && !defined(__Userspace__) if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) { - SOCK_LOCK(so); solisten_proto(so, backlog); SOCK_UNLOCK(so); + inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING; + } else { + solisten_proto_abort(so); + SOCK_UNLOCK(so); + if (backlog > 0) { + inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING; + } else { + inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING; + } } #elif defined(_WIN32) || defined(__Userspace__) - SOCK_LOCK(so); solisten_proto(so, backlog); #endif #if !(defined(__FreeBSD__) && !defined(__Userspace__)) @@ -8400,17 +8504,15 @@ sctp_listen(struct socket *so, struct proc *p) #endif } 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 +out: SCTP_INP_WUNLOCK(inp); + SCTP_INP_INFO_WUNLOCK(); return (error); } @@ -8781,27 +8883,42 @@ sctp_peeraddr(struct socket *so, struct mbuf *nam) } #if !defined(__Userspace__) -struct pr_usrreqs sctp_usrreqs = { #if defined(__FreeBSD__) - .pru_abort = sctp_abort, - .pru_accept = sctp_accept, - .pru_attach = sctp_attach, - .pru_bind = sctp_bind, - .pru_connect = sctp_connect, - .pru_control = in_control, - .pru_close = sctp_close, - .pru_detach = sctp_close, - .pru_sopoll = sopoll_generic, - .pru_flush = sctp_flush, - .pru_disconnect = sctp_disconnect, - .pru_listen = sctp_listen, - .pru_peeraddr = sctp_peeraddr, - .pru_send = sctp_sendm, - .pru_shutdown = sctp_shutdown, - .pru_sockaddr = sctp_ingetaddr, - .pru_sosend = sctp_sosend, - .pru_soreceive = sctp_soreceive -#elif defined(__APPLE__) +#define SCTP_PROTOSW \ + .pr_protocol = IPPROTO_SCTP, \ + .pr_ctloutput = sctp_ctloutput, \ + .pr_abort = sctp_abort, \ + .pr_accept = sctp_accept, \ + .pr_attach = sctp_attach, \ + .pr_bind = sctp_bind, \ + .pr_connect = sctp_connect, \ + .pr_control = in_control, \ + .pr_close = sctp_close, \ + .pr_detach = sctp_close, \ + .pr_flush = sctp_flush, \ + .pr_disconnect = sctp_disconnect, \ + .pr_listen = sctp_listen, \ + .pr_peeraddr = sctp_peeraddr, \ + .pr_send = sctp_sendm, \ + .pr_shutdown = sctp_shutdown, \ + .pr_sockaddr = sctp_ingetaddr, \ + .pr_sosend = sctp_sosend, \ + .pr_soreceive = sctp_soreceive \ + +struct protosw sctp_seqpacket_protosw = { + .pr_type = SOCK_SEQPACKET, + .pr_flags = PR_WANTRCVD, + SCTP_PROTOSW +}; + +struct protosw sctp_stream_protosw = { + .pr_type = SOCK_STREAM, + .pr_flags = PR_CONNREQUIRED | PR_WANTRCVD, + SCTP_PROTOSW +}; +#else +struct pr_usrreqs sctp_usrreqs = { +#if defined(__APPLE__) .pru_abort = sctp_abort, .pru_accept = sctp_accept, .pru_attach = sctp_attach, @@ -8848,127 +8965,7 @@ struct pr_usrreqs sctp_usrreqs = { sctp_close #endif }; -#elif !defined(__Userspace__) -int -sctp_usrreq(so, req, m, nam, control) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; -{ - struct proc *p = curproc; - int error; - int family; - struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb; - - error = 0; - 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); - 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(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); - error = EAFNOSUPPORT; - } - return (error); - } - switch (req) { - case PRU_ATTACH: - error = sctp_attach(so, family, p); - break; - case PRU_DETACH: - error = sctp_detach(so); - break; - case PRU_BIND: - if (nam == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - error = sctp_bind(so, nam, p); - break; - case PRU_LISTEN: - error = sctp_listen(so, p); - break; - case PRU_CONNECT: - if (nam == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - error = sctp_connect(so, nam, p); - break; - case PRU_DISCONNECT: - error = sctp_disconnect(so); - break; - case PRU_ACCEPT: - if (nam == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - error = sctp_accept(so, nam); - break; - case PRU_SHUTDOWN: - error = sctp_shutdown(so); - break; - - case PRU_RCVD: - /* - * For Open and Net BSD, this is real ugly. The mbuf *nam - * that is passed (by soreceive()) is the int flags c ast as - * a (mbuf *) yuck! - */ - break; - - case PRU_SEND: - /* Flags are ignored */ - { - struct sockaddr *addr; - - if (nam == NULL) - addr = NULL; - else - addr = mtod(nam, struct sockaddr *); - - error = sctp_sendm(so, 0, m, addr, control, p); - } - break; - case PRU_ABORT: - error = sctp_abort(so); - break; - - case PRU_SENSE: - error = 0; - break; - case PRU_RCVOOB: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); - error = EAFNOSUPPORT; - break; - case PRU_SENDOOB: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); - error = EAFNOSUPPORT; - break; - case PRU_PEERADDR: - error = sctp_peeraddr(so, nam); - break; - case PRU_SOCKADDR: - error = sctp_ingetaddr(so, nam); - break; - case PRU_SLOWTIMO: - error = 0; - break; - default: - break; - } - return (error); -} - #endif #endif diff --git a/netwerk/sctp/src/netinet/sctp_var.h b/netwerk/sctp/src/netinet/sctp_var.h index 3cdfdfe76b..ab67402219 100644 --- a/netwerk/sctp/src/netinet/sctp_var.h +++ b/netwerk/sctp/src/netinet/sctp_var.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_VAR_H_ #define _NETINET_SCTP_VAR_H_ @@ -45,8 +40,12 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 365071 2020-09-01 21:19:14Z mjg #if defined(_KERNEL) || defined(__Userspace__) #if !defined(__Userspace__) +#if defined(__FreeBSD__) +extern struct protosw sctp_seqpacket_protosw, sctp_stream_protosw; +#else extern struct pr_usrreqs sctp_usrreqs; #endif +#endif #define sctp_feature_on(inp, feature) (inp->sctp_features |= feature) #define sctp_feature_off(inp, feature) (inp->sctp_features &= ~feature) @@ -89,7 +88,7 @@ extern struct pr_usrreqs sctp_usrreqs; #define sctp_sbspace(asoc, sb) ((long) ((sctp_maxspace(sb) > (asoc)->sb_cc) ? (sctp_maxspace(sb) - (asoc)->sb_cc) : 0)) -#define sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > (sb)->sb_cc) ? (sctp_maxspace(sb) - (sb)->sb_cc) : 0)) +#define sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > SCTP_SBAVAIL(sb)) ? (sctp_maxspace(sb) - SCTP_SBAVAIL(sb)) : 0)) #define sctp_sbspace_sub(a,b) (((a) > (b)) ? ((a) - (b)) : 0) @@ -203,7 +202,7 @@ extern struct pr_usrreqs sctp_usrreqs; } #define sctp_sbfree(ctl, stcb, sb, m) { \ - SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \ + SCTP_SB_DECR(sb, SCTP_BUF_LEN((m))); \ SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \ if (((ctl)->do_not_ref_stcb == 0) && stcb) {\ SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ @@ -215,7 +214,7 @@ extern struct pr_usrreqs sctp_usrreqs; } #define sctp_sballoc(stcb, sb, m) { \ - atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \ + SCTP_SB_INCR(sb, SCTP_BUF_LEN((m))); \ atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \ if (stcb) { \ atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ @@ -246,7 +245,7 @@ extern struct pr_usrreqs sctp_usrreqs; } #define sctp_sbfree(ctl, stcb, sb, m) { \ - SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \ + SCTP_SB_DECR(sb, SCTP_BUF_LEN((m))); \ SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \ if (((ctl)->do_not_ref_stcb == 0) && stcb) { \ SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ @@ -255,7 +254,7 @@ extern struct pr_usrreqs sctp_usrreqs; } #define sctp_sballoc(stcb, sb, m) { \ - atomic_add_int(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \ + SCTP_SB_INCR(sb, SCTP_BUF_LEN((m))); \ atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \ if (stcb) { \ atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ @@ -368,10 +367,17 @@ void sctp_close(struct socket *so); #else int sctp_detach(struct socket *so); #endif +#if defined(__FreeBSD__) && !defined(__Userspace__) +void sctp_abort(struct socket *so); +#else +int sctp_abort(struct socket *so); +#endif int sctp_disconnect(struct socket *so); #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); +#elif defined(__FreeBSD__) +ipproto_ctlinput_t sctp_ctlinput; #else void sctp_ctlinput(int, struct sockaddr *, void *); #endif @@ -384,17 +390,19 @@ int sctp_input(struct mbuf **, int *, int); void sctp_input(struct mbuf *, int); #endif #endif -void sctp_pathmtu_adjustment(struct sctp_tcb *, uint16_t); +void sctp_pathmtu_adjustment(struct sctp_tcb *, uint32_t, bool); #else #if defined(__Userspace__) -void sctp_pathmtu_adjustment(struct sctp_tcb *, uint16_t); +void sctp_pathmtu_adjustment(struct sctp_tcb *, uint32_t, bool); #else void sctp_input(struct mbuf *,...); #endif void *sctp_ctlinput(int, struct sockaddr *, void *); int sctp_ctloutput(int, struct socket *, int, int, struct mbuf **); #endif +#if !(defined(__FreeBSD__) && !defined(__Userspace__)) 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), @@ -402,7 +410,9 @@ void sctp_init(uint16_t, #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 +#if !defined(__FreeBSD__) void sctp_init(void); +#endif void sctp_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint8_t, uint8_t, uint16_t, uint32_t); #endif diff --git a/netwerk/sctp/src/netinet/sctputil.c b/netwerk/sctp/src/netinet/sctputil.c index 41910ec49d..565ffa9b4f 100644 --- a/netwerk/sctp/src/netinet/sctputil.c +++ b/netwerk/sctp/src/netinet/sctputil.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 366482 2020-10-06 11:08:52Z tuexen $"); -#endif - #include #include #include @@ -70,6 +65,9 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 366482 2020-10-06 11:08:52Z tuex #include #endif #endif +#if defined(_WIN32) && defined(__MINGW32__) +#include +#endif #if defined(_WIN32) && !defined(__Userspace__) #if !defined(SCTP_LOCAL_TRACE_BUF) @@ -92,7 +90,7 @@ sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) struct sctp_cwnd_log sctp_clog; sctp_clog.x.sb.stcb = stcb; - sctp_clog.x.sb.so_sbcc = sb->sb_cc; + sctp_clog.x.sb.so_sbcc = SCTP_SBAVAIL(sb); if (stcb) sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc; else @@ -398,9 +396,9 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) } sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); 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)); - sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx)); + sctp_clog.x.lock.sock_lock = mtx_owned(SOCK_MTX(inp->sctp_socket)); + sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(SOCKBUF_MTX(&inp->sctp_socket->so_rcv)); + sctp_clog.x.lock.socksndbuf_lock = mtx_owned(SOCKBUF_MTX(&inp->sctp_socket->so_snd)); } else { sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN; sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; @@ -1142,7 +1140,8 @@ sctp_map_assoc_state(int kernel_state) int sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms) + uint32_t override_tag, uint32_t initial_tsn, uint32_t vrf_id, + uint16_t o_strms) { struct sctp_association *asoc; /* @@ -1177,6 +1176,8 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->nrsack_supported = inp->nrsack_supported; asoc->pktdrop_supported = inp->pktdrop_supported; asoc->idata_supported = inp->idata_supported; + asoc->rcv_edmid = inp->rcv_edmid; + asoc->snd_edmid = SCTP_EDMID_NONE; asoc->sctp_cmt_pf = (uint8_t)0; asoc->sctp_frag_point = inp->sctp_frag_point; asoc->sctp_features = inp->sctp_features; @@ -1219,23 +1220,28 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #endif asoc->refcnt = 0; asoc->assoc_up_sent = 0; - asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq = - sctp_select_initial_TSN(&inp->sctp_ep); - asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; - /* we are optimisitic here */ + if (override_tag) { + asoc->init_seq_number = initial_tsn; + } else { + asoc->init_seq_number = sctp_select_initial_TSN(&inp->sctp_ep); + } + asoc->asconf_seq_out = asoc->init_seq_number; + asoc->str_reset_seq_out = asoc->init_seq_number; + asoc->sending_seq = asoc->init_seq_number; + asoc->asconf_seq_out_acked = asoc->init_seq_number - 1; + /* we are optimistic here */ asoc->peer_supports_nat = 0; asoc->sent_queue_retran_cnt = 0; /* for CMT */ - asoc->last_net_cmt_send_started = NULL; + asoc->last_net_cmt_send_started = NULL; - /* This will need to be adjusted */ asoc->last_acked_seq = asoc->init_seq_number - 1; - asoc->advanced_peer_ack_point = asoc->last_acked_seq; - asoc->asconf_seq_in = asoc->last_acked_seq; + asoc->advanced_peer_ack_point = asoc->init_seq_number - 1; + asoc->asconf_seq_in = asoc->init_seq_number - 1; /* here we are different, we hold the next one we expect */ - asoc->str_reset_seq_in = asoc->last_acked_seq + 1; + asoc->str_reset_seq_in = asoc->init_seq_number; asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max; asoc->initial_rto = inp->sctp_ep.initial_rto; @@ -1284,7 +1290,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND); asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket); - asoc->smallest_mtu = inp->sctp_frag_point; + asoc->smallest_mtu = 0; asoc->minrto = inp->sctp_ep.sctp_minrto; asoc->maxrto = inp->sctp_ep.sctp_maxrto; @@ -1324,6 +1330,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); } + SCTP_TCB_LOCK(stcb); for (i = 0; i < asoc->streamoutcnt; i++) { /* * inbound side must be set to 0xffff, also NOTE when we get @@ -1333,9 +1340,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_mid_ordered = 0; - asoc->strmout[i].next_mid_unordered = 0; TAILQ_INIT(&asoc->strmout[i].outqueue); + asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL); asoc->strmout[i].chunks_on_queues = 0; #if defined(SCTP_DETAILED_STR_STATS) for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { @@ -1346,12 +1352,14 @@ 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].next_mid_ordered = 0; + asoc->strmout[i].next_mid_unordered = 0; asoc->strmout[i].sid = i; asoc->strmout[i].last_msg_incomplete = 0; 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); + asoc->ss_functions.sctp_ss_init(stcb, asoc); + SCTP_TCB_UNLOCK(stcb); /* Now the mapping array */ asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; @@ -1558,7 +1566,7 @@ select_a_new_ep: SCTP_INP_RUNLOCK(it->inp); goto no_stcb; } - while (it->stcb) { + while (it->stcb != NULL) { SCTP_TCB_LOCK(it->stcb); if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { /* not in the right state... keep looking */ @@ -1580,7 +1588,7 @@ select_a_new_ep: if (sctp_it_ctl.iterator_flags) { /* We won't be staying here */ SCTP_INP_DECR_REF(it->inp); - atomic_add_int(&it->stcb->asoc.refcnt, -1); + atomic_subtract_int(&it->stcb->asoc.refcnt, 1); #if !(defined(__FreeBSD__) && !defined(__Userspace__)) if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) { @@ -1605,22 +1613,29 @@ select_a_new_ep: SCTP_INP_RLOCK(it->inp); SCTP_INP_DECR_REF(it->inp); SCTP_TCB_LOCK(it->stcb); - atomic_add_int(&it->stcb->asoc.refcnt, -1); + atomic_subtract_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)); + SCTP_INP_RLOCK_ASSERT(it->inp); + SCTP_TCB_LOCK_ASSERT(it->stcb); /* run function on this one */ (*it->function_assoc)(it->inp, it->stcb, it->pointer, it->val); + SCTP_INP_RLOCK_ASSERT(it->inp); + SCTP_TCB_LOCK_ASSERT(it->stcb); /* * we lie here, it really needs to have its own type but * first I must verify that this won't effect things :-0 */ - if (it->no_chunk_output == 0) + if (it->no_chunk_output == 0) { sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); + SCTP_INP_RLOCK_ASSERT(it->inp); + SCTP_TCB_LOCK_ASSERT(it->stcb); + } SCTP_TCB_UNLOCK(it->stcb); next_assoc: @@ -1834,7 +1849,7 @@ sctp_timeout_handler(void *t) * necessary below. * This is safe now that we have acquired the lock. */ - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); released_asoc_reference = true; if ((type != SCTP_TIMER_TYPE_ASOCKILL) && ((stcb->asoc.state == SCTP_STATE_EMPTY) || @@ -1869,7 +1884,7 @@ sctp_timeout_handler(void *t) #if defined(__Userspace__) if ((stcb != NULL) && - !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) && + ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && (stcb->sctp_socket != NULL)) { upcall_socket = stcb->sctp_socket; SOCK_LOCK(upcall_socket); @@ -1975,7 +1990,7 @@ sctp_timeout_handler(void *t) #ifdef SCTP_AUDITING_ENABLED sctp_auditing(4, inp, stcb, net); #endif - if (!(net->dest_state & SCTP_ADDR_NOHB)) { + if ((net->dest_state & SCTP_ADDR_NOHB) == 0) { 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; @@ -2071,7 +2086,7 @@ sctp_timeout_handler(void *t) 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); + sctp_abort_an_association(inp, stcb, op_err, true, SCTP_SO_NOT_LOCKED); /* no need to unlock on tcb its gone */ goto out_decr; case SCTP_TIMER_TYPE_AUTOCLOSE: @@ -2117,14 +2132,13 @@ sctp_timeout_handler(void *t) SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1); #endif inp = NULL; - goto out_no_decr; + goto out_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(__Userspace__) @@ -2145,7 +2159,7 @@ sctp_timeout_handler(void *t) * duplicate unlock or unlock of a free mtx :-0 */ stcb = NULL; - goto out_no_decr; + goto out_decr; case SCTP_TIMER_TYPE_ADDR_WQ: KASSERT(inp == NULL && stcb == NULL && net == NULL, ("timeout of type %d: inp = %p, stcb = %p, net = %p", @@ -2209,12 +2223,11 @@ out_decr: SCTP_INP_DECR_REF(inp); } if ((stcb != NULL) && !released_asoc_reference) { - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); } if (net != NULL) { sctp_free_remote_addr(net); } -out_no_decr: SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler finished.\n", type); #if defined(__FreeBSD__) && !defined(__Userspace__) CURVNET_RESTORE(); @@ -2326,7 +2339,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, case SCTP_TIMER_TYPE_RECV: /* * Here we use the Delayed-Ack timer value from the inp, - * ususually about 200ms. + * usually about 200ms. */ if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { #ifdef INVARIANTS @@ -2371,7 +2384,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, #endif } if ((net->dest_state & SCTP_ADDR_NOHB) && - !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) { SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n", t_type, inp, stcb, net); @@ -2383,16 +2396,24 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, } 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; + if (!((net->dest_state & SCTP_ADDR_UNCONFIRMED) && + (net->dest_state & SCTP_ADDR_REACHABLE)) && + ((net->dest_state & SCTP_ADDR_PF) == 0)) { + if (to_ticks > 1) { + rndval = sctp_select_initial_TSN(&inp->sctp_ep); + jitter = rndval % to_ticks; + to_ticks >>= 1; + if (jitter < (UINT32_MAX - to_ticks)) { + to_ticks += jitter; + } else { + to_ticks = UINT32_MAX; + } + } + if (net->heart_beat_delay < (UINT32_MAX - to_ticks)) { + to_ticks += net->heart_beat_delay; + } else { + to_ticks = UINT32_MAX; + } } /* * Now we must convert the to_ticks that are now in @@ -2423,7 +2444,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; case SCTP_TIMER_TYPE_NEWCOOKIE: /* - * Nothing needed but the endpoint here ususually about 60 + * Nothing needed but the endpoint here usually about 60 * minutes. */ if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { @@ -2439,7 +2460,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; case SCTP_TIMER_TYPE_PATHMTURAISE: /* - * Here we use the value found in the EP for PMTUD, ususually + * Here we use the value found in the EP for PMTUD, usually * about 10 minutes. */ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { @@ -2554,7 +2575,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; case SCTP_TIMER_TYPE_INPKILL: /* - * The inp is setup to die. We re-use the signature_chage + * The inp is setup to die. We re-use the signature_change * timer since that has stopped and we are in the GONE * state. */ @@ -2862,7 +2883,7 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; case SCTP_TIMER_TYPE_INPKILL: /* - * The inp is setup to die. We re-use the signature_chage + * The inp is setup to die. We re-use the signature_change * timer since that has stopped and we are in the GONE * state. */ @@ -2957,20 +2978,23 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, * that were incremented in sctp_timer_start(). */ if (tmr->ep != NULL) { - SCTP_INP_DECR_REF(inp); tmr->ep = NULL; + SCTP_INP_DECR_REF(inp); } if (tmr->tcb != NULL) { - atomic_add_int(&stcb->asoc.refcnt, -1); tmr->tcb = NULL; + atomic_subtract_int(&stcb->asoc.refcnt, 1); } if (tmr->net != NULL) { + struct sctp_nets *tmr_net; + /* * 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 = tmr->net; tmr->net = NULL; + sctp_free_remote_addr(tmr_net); } } else { SCTPDBG(SCTP_DEBUG_TIMER2, @@ -2983,48 +3007,16 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint32_t sctp_calculate_len(struct mbuf *m) { - uint32_t tlen = 0; struct mbuf *at; + uint32_t tlen; - at = m; - while (at) { + tlen = 0; + for (at = m; at != NULL; at = SCTP_BUF_NEXT(at)) { tlen += SCTP_BUF_LEN(at); - at = SCTP_BUF_NEXT(at); } return (tlen); } -void -sctp_mtu_size_reset(struct sctp_inpcb *inp, - struct sctp_association *asoc, uint32_t mtu) -{ - /* - * Reset the P-MTU size on this association, this involves changing - * the asoc MTU, going through ANY chunk+overhead larger than mtu to - * allow the DF flag to be cleared. - */ - struct sctp_tmit_chunk *chk; - unsigned int eff_mtu, ovh; - - asoc->smallest_mtu = mtu; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MIN_OVERHEAD; - } else { - ovh = SCTP_MIN_V4_OVERHEAD; - } - eff_mtu = mtu - ovh; - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->send_size > eff_mtu) { - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - } - } - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - if (chk->send_size > eff_mtu) { - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - } - } -} - /* * Given an association and starting time of the current RTT period, update * RTO in number of msecs. net should point to the current network. @@ -3109,7 +3101,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb, rto_logging(net, SCTP_LOG_RTTVAR); } } else { - /* First RTO measurment */ + /* First RTO measurement */ net->RTO_measured = 1; first_measure = 1; net->lastsa = rtt << SCTP_RTT_SHIFT; @@ -3248,22 +3240,30 @@ 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) + uint16_t error, struct sctp_abort_chunk *abort, + bool from_peer, bool timedout, int so_locked) { struct mbuf *m_notify; struct sctp_assoc_change *sac; struct sctp_queued_to_read *control; + struct sctp_inpcb *inp; unsigned int notif_len; - uint16_t abort_len; unsigned int i; + uint16_t abort_len; #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)) { + KASSERT(abort == NULL || from_peer, + ("sctp_notify_assoc_change: ABORT chunk provided for local termination")); + KASSERT(!from_peer || !timedout, + ("sctp_notify_assoc_change: timeouts can only be local")); + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + inp = stcb->sctp_ep; + SCTP_INP_READ_LOCK_ASSERT(inp); + + if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { notif_len = (unsigned int)sizeof(struct sctp_assoc_change); if (abort != NULL) { abort_len = ntohs(abort->ch.chunk_length); @@ -3299,9 +3299,13 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, sac->sac_length = sizeof(struct sctp_assoc_change); sac->sac_state = state; sac->sac_error = error; - /* XXX verify these stream counts */ - sac->sac_outbound_streams = stcb->asoc.streamoutcnt; - sac->sac_inbound_streams = stcb->asoc.streamincnt; + if (state == SCTP_CANT_STR_ASSOC) { + sac->sac_outbound_streams = 0; + sac->sac_inbound_streams = 0; + } else { + sac->sac_outbound_streams = stcb->asoc.streamoutcnt; + sac->sac_inbound_streams = stcb->asoc.streamincnt; + } sac->sac_assoc_id = sctp_get_associd(stcb); if (notif_len > sizeof(struct sctp_assoc_change)) { if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { @@ -3337,10 +3341,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, 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); + sctp_add_to_readq(inp, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } else { sctp_m_freem(m_notify); } @@ -3350,8 +3353,8 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, * comes in. */ set_error: - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && + if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { SOCK_LOCK(stcb->sctp_socket); if (from_peer) { @@ -3363,8 +3366,7 @@ set_error: stcb->sctp_socket->so_error = ECONNRESET; } } else { - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { + if (timedout) { SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT); stcb->sctp_socket->so_error = ETIMEDOUT; } else { @@ -3376,7 +3378,7 @@ set_error: } /* Wake ANY sleepers */ #if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); + so = SCTP_INP_SO(inp); if (!so_locked) { atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(stcb); @@ -3389,8 +3391,8 @@ set_error: } } #endif - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && + if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { socantrcvmore(stcb->sctp_socket); } @@ -3411,11 +3413,15 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, struct sctp_paddr_change *spc; struct sctp_queued_to_read *control; - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { /* event not enabled */ return; } + m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) return; @@ -3457,7 +3463,7 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, (void)sa6_recoverscope(sin6); #else (void)in6_recoverscope(sin6, &sin6->sin6_addr, - NULL); + NULL); #endif } else { /* clear embedded scope_id for user */ @@ -3497,16 +3503,14 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, control->spec_flags = M_NOTIFICATION; /* not that we need this */ control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, + sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, - so_locked); + SCTP_READ_LOCK_HELD, 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) + struct sctp_tmit_chunk *chk, int so_locked) { struct mbuf *m_notify; struct sctp_send_failed *ssf; @@ -3515,9 +3519,12 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, 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) && - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && + sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { /* event not enabled */ return; } @@ -3628,16 +3635,14 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, control->spec_flags = M_NOTIFICATION; /* not that we need this */ control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, + sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, - so_locked); + SCTP_READ_LOCK_HELD, so_locked); } static void sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, - struct sctp_stream_queue_pending *sp, int so_locked) + struct sctp_stream_queue_pending *sp, int so_locked) { struct mbuf *m_notify; struct sctp_send_failed *ssf; @@ -3645,12 +3650,16 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, struct sctp_queued_to_read *control; int notifhdr_len; - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && + sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { /* event not enabled */ return; } + if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { notifhdr_len = sizeof(struct sctp_send_failed_event); } else { @@ -3726,20 +3735,23 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, 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); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } static void -sctp_notify_adaptation_layer(struct sctp_tcb *stcb) +sctp_notify_adaptation_layer(struct sctp_tcb *stcb, int so_locked) { struct mbuf *m_notify; struct sctp_adaptation_event *sai; struct sctp_queued_to_read *control; - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { /* event not enabled */ return; } @@ -3773,29 +3785,30 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb) 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, SCTP_SO_NOT_LOCKED); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } -/* 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) + struct sctp_queued_to_read *aborted_control, + int so_locked) { struct mbuf *m_notify; struct sctp_pdapi_event *pdapi; struct sctp_queued_to_read *control; struct sockbuf *sb; - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { + KASSERT(aborted_control != NULL, ("aborted_control is NULL")); + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { /* event not enabled */ return; } - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { - return; - } m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) @@ -3808,15 +3821,15 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, pdapi->pdapi_flags = 0; pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); pdapi->pdapi_indication = error; - pdapi->pdapi_stream = (val >> 16); - pdapi->pdapi_seq = (val & 0x0000ffff); + pdapi->pdapi_stream = aborted_control->sinfo_stream; + pdapi->pdapi_seq = (uint16_t)aborted_control->mid; pdapi->pdapi_assoc_id = sctp_get_associd(stcb); SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); SCTP_BUF_NEXT(m_notify) = NULL; control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); + 0, 0, stcb->asoc.context, 0, 0, 0, + m_notify); if (control == NULL) { /* no memory */ sctp_m_freem(m_notify); @@ -3835,12 +3848,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); } control->end_added = 1; - if (stcb->asoc.control_pdapi) - TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); - else { - /* we really should not see this case */ - TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); - } + TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, aborted_control, control, next); if (stcb->sctp_ep && stcb->sctp_socket) { /* This should always be the case */ #if defined(__APPLE__) && !defined(__Userspace__) @@ -3869,12 +3877,16 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, } static void -sctp_notify_shutdown_event(struct sctp_tcb *stcb) +sctp_notify_shutdown_event(struct sctp_tcb *stcb, int so_locked) { struct mbuf *m_notify; struct sctp_shutdown_event *sse; struct sctp_queued_to_read *control; + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + /* * For TCP model AND UDP connected sockets we will send an error up * when an SHUTDOWN completes @@ -3901,6 +3913,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb) SCTP_SOCKET_UNLOCK(so, 1); #endif } + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { /* event not enabled */ return; @@ -3933,21 +3946,23 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb) 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, SCTP_SO_NOT_LOCKED); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } static void -sctp_notify_sender_dry_event(struct sctp_tcb *stcb, - int so_locked) +sctp_notify_sender_dry_event(struct sctp_tcb *stcb, int so_locked) { struct mbuf *m_notify; struct sctp_sender_dry_event *event; struct sctp_queued_to_read *control; - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { /* event not enabled */ return; } @@ -3982,21 +3997,26 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb, /* 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); + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } -void -sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag) +static void +sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int flag, int so_locked) { struct mbuf *m_notify; struct sctp_queued_to_read *control; struct sctp_stream_change_event *stradd; - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT)) { /* event not enabled */ return; } + if ((stcb->asoc.peer_req_out) && flag) { /* Peer made the request, don't tell the local user */ stcb->asoc.peer_req_out = 0; @@ -4014,8 +4034,8 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t stradd->strchange_flags = flag; stradd->strchange_length = sizeof(struct sctp_stream_change_event); stradd->strchange_assoc_id = sctp_get_associd(stcb); - stradd->strchange_instrms = numberin; - stradd->strchange_outstrms = numberout; + stradd->strchange_instrms = stcb->asoc.streamincnt; + stradd->strchange_outstrms = stcb->asoc.streamoutcnt; SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event); SCTP_BUF_NEXT(m_notify) = NULL; if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { @@ -4036,23 +4056,27 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t 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, SCTP_SO_NOT_LOCKED); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } -void -sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag) +static void +sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, int flag, int so_locked) { struct mbuf *m_notify; struct sctp_queued_to_read *control; struct sctp_assoc_reset_event *strasoc; - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT)) { /* event not enabled */ return; } + m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) /* no space left */ @@ -4064,8 +4088,8 @@ sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32 strasoc->assocreset_flags = flag; strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event); strasoc->assocreset_assoc_id= sctp_get_associd(stcb); - strasoc->assocreset_local_tsn = sending_tsn; - strasoc->assocreset_remote_tsn = recv_tsn; + strasoc->assocreset_local_tsn = stcb->asoc.sending_seq; + strasoc->assocreset_remote_tsn = stcb->asoc.mapping_array_base_tsn + 1; SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event); SCTP_BUF_NEXT(m_notify) = NULL; if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { @@ -4086,22 +4110,25 @@ sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32 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, SCTP_SO_NOT_LOCKED); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } static void sctp_notify_stream_reset(struct sctp_tcb *stcb, - int number_entries, uint16_t * list, int flag) + int number_entries, uint16_t *list, int flag, int so_locked) { struct mbuf *m_notify; struct sctp_queued_to_read *control; struct sctp_stream_reset_event *strreset; int len; - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) { /* event not enabled */ return; } @@ -4150,13 +4177,14 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb, 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, SCTP_SO_NOT_LOCKED); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, so_locked); } static void -sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk) +sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, + struct sctp_error_chunk *chunk, int so_locked) { struct mbuf *m_notify; struct sctp_remote_error *sre; @@ -4164,10 +4192,14 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro unsigned int notif_len; uint16_t chunk_len; - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); + + if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { return; } + if (chunk != NULL) { chunk_len = ntohs(chunk->ch.chunk_length); /* @@ -4211,10 +4243,9 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro control->spec_flags = M_NOTIFICATION; /* not that we need this */ control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, + 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_HELD, so_locked); } else { sctp_m_freem(m_notify); } @@ -4222,29 +4253,25 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro void sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, - uint32_t error, void *data, int so_locked) + uint32_t error, void *data, int so_locked) { - if ((stcb == NULL) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* If the socket is gone we are out of here */ - return; - } -#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; - } + struct sctp_inpcb *inp; + struct sctp_nets *net; + + KASSERT(stcb != NULL, ("stcb == NULL")); + SCTP_TCB_LOCK_ASSERT(stcb); + + inp = stcb->sctp_ep; #if defined(__APPLE__) && !defined(__Userspace__) if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); + sctp_lock_assert(SCTP_INP_SO(inp)); } else { - sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); + sctp_unlock_assert(SCTP_INP_SO(inp)); } #endif + if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { + return; + } if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || @@ -4254,24 +4281,35 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, return; } } + if (notification != SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION) { + SCTP_INP_READ_LOCK(inp); + } + SCTP_INP_READ_LOCK_ASSERT(inp); + + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) { + SCTP_INP_READ_UNLOCK(inp); + return; + } + switch (notification) { case SCTP_NOTIFY_ASSOC_UP: if (stcb->asoc.assoc_up_sent == 0) { - sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked); + sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, false, false, so_locked); stcb->asoc.assoc_up_sent = 1; } if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { - sctp_notify_adaptation_layer(stcb); + sctp_notify_adaptation_layer(stcb, so_locked); } if (stcb->asoc.auth_supported == 0) { - sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, - NULL, so_locked); + sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, 0, so_locked); } break; case SCTP_NOTIFY_ASSOC_DOWN: - sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked); + sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, false, false, so_locked); #if defined(__Userspace__) - if (stcb->sctp_ep->recv_callback) { + if (inp->recv_callback) { if (stcb->sctp_socket) { union sctp_sockstore addr; struct sctp_rcvinfo rcv; @@ -4280,7 +4318,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, memset(&rcv, 0, sizeof(struct sctp_rcvinfo)); atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(stcb); - stcb->sctp_ep->recv_callback(stcb->sctp_socket, addr, NULL, 0, rcv, 0, stcb->sctp_ep->ulp_info); + inp->recv_callback(stcb->sctp_socket, addr, NULL, 0, rcv, 0, inp->ulp_info); SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); } @@ -4288,32 +4326,20 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, #endif break; case SCTP_NOTIFY_INTERFACE_DOWN: - { - struct sctp_nets *net; - - net = (struct sctp_nets *)data; - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, - (struct sockaddr *)&net->ro._l_addr, error, so_locked); - break; - } + net = (struct sctp_nets *)data; + sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, + &net->ro._l_addr.sa, error, so_locked); + break; case SCTP_NOTIFY_INTERFACE_UP: - { - struct sctp_nets *net; - - net = (struct sctp_nets *)data; - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, - (struct sockaddr *)&net->ro._l_addr, error, so_locked); - break; - } + net = (struct sctp_nets *)data; + sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, + &net->ro._l_addr.sa, error, so_locked); + break; case SCTP_NOTIFY_INTERFACE_CONFIRMED: - { - struct sctp_nets *net; - - net = (struct sctp_nets *)data; - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, - (struct sockaddr *)&net->ro._l_addr, error, so_locked); - break; - } + net = (struct sctp_nets *)data; + sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, + &net->ro._l_addr.sa, error, so_locked); + break; case SCTP_NOTIFY_SPECIAL_SP_FAIL: sctp_notify_send_failed2(stcb, error, (struct sctp_stream_queue_pending *)data, so_locked); @@ -4327,61 +4353,71 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, (struct sctp_tmit_chunk *)data, so_locked); break; case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: - { - uint32_t val; - val = *((uint32_t *)data); - - sctp_notify_partial_delivery_indication(stcb, error, val, so_locked); + sctp_notify_partial_delivery_indication(stcb, error, + (struct sctp_queued_to_read *)data, + so_locked); break; - } case SCTP_NOTIFY_ASSOC_LOC_ABORTED: 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); + sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, false, false, so_locked); } else { - sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked); + sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, false, false, so_locked); } break; case SCTP_NOTIFY_ASSOC_REM_ABORTED: 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); + sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, true, false, so_locked); } else { - sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked); + sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, true, false, so_locked); + } + break; + case SCTP_NOTIFY_ASSOC_TIMEDOUT: + 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, false, true, so_locked); + } else { + sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, false, true, so_locked); } break; case SCTP_NOTIFY_ASSOC_RESTART: - sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked); + sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, false, false, so_locked); if (stcb->asoc.auth_supported == 0) { - sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, - NULL, so_locked); + sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, 0, so_locked); } break; case SCTP_NOTIFY_STR_RESET_SEND: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING_SSN); + sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING_SSN, so_locked); break; case SCTP_NOTIFY_STR_RESET_RECV: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING); + sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING, so_locked); break; case SCTP_NOTIFY_STR_RESET_FAILED_OUT: sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_OUTGOING_SSN|SCTP_STREAM_RESET_FAILED)); + (SCTP_STREAM_RESET_OUTGOING_SSN|SCTP_STREAM_RESET_FAILED), so_locked); break; case SCTP_NOTIFY_STR_RESET_DENIED_OUT: sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_OUTGOING_SSN|SCTP_STREAM_RESET_DENIED)); + (SCTP_STREAM_RESET_OUTGOING_SSN|SCTP_STREAM_RESET_DENIED), so_locked); break; case SCTP_NOTIFY_STR_RESET_FAILED_IN: sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_INCOMING|SCTP_STREAM_RESET_FAILED)); + (SCTP_STREAM_RESET_INCOMING|SCTP_STREAM_RESET_FAILED), so_locked); break; case SCTP_NOTIFY_STR_RESET_DENIED_IN: sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_INCOMING|SCTP_STREAM_RESET_DENIED)); + (SCTP_STREAM_RESET_INCOMING|SCTP_STREAM_RESET_DENIED), so_locked); + break; + case SCTP_NOTIFY_STR_RESET_ADD: + sctp_notify_stream_reset_add(stcb, error, so_locked); + break; + case SCTP_NOTIFY_STR_RESET_TSN: + sctp_notify_stream_reset_tsn(stcb, error, so_locked); break; case SCTP_NOTIFY_ASCONF_ADD_IP: sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, - error, so_locked); + error, so_locked); break; case SCTP_NOTIFY_ASCONF_DELETE_IP: sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, @@ -4392,34 +4428,34 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, error, so_locked); break; case SCTP_NOTIFY_PEER_SHUTDOWN: - sctp_notify_shutdown_event(stcb); + sctp_notify_shutdown_event(stcb, so_locked); break; case SCTP_NOTIFY_AUTH_NEW_KEY: - sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error, - (uint16_t)(uintptr_t)data, - so_locked); + sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, + *(uint16_t *)data, so_locked); break; case SCTP_NOTIFY_AUTH_FREE_KEY: - sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, - (uint16_t)(uintptr_t)data, - so_locked); + sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, + *(uint16_t *)data, so_locked); break; case SCTP_NOTIFY_NO_PEER_AUTH: - sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, - (uint16_t)(uintptr_t)data, - so_locked); + sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, + 0, so_locked); break; case SCTP_NOTIFY_SENDER_DRY: sctp_notify_sender_dry_event(stcb, so_locked); break; case SCTP_NOTIFY_REMOTE_ERROR: - sctp_notify_remote_error(stcb, error, data); + sctp_notify_remote_error(stcb, error, data, so_locked); break; default: SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", - __func__, notification, notification); + __func__, notification, notification); break; - } /* end switch */ + } + if (notification != SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION) { + SCTP_INP_READ_UNLOCK(inp); + } } void @@ -4507,7 +4543,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int so_locked) 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); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp); sctp_free_spbufspace(stcb, asoc, sp); if (sp->data) { sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, @@ -4531,8 +4567,9 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int so_locked) } void -sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error, - struct sctp_abort_chunk *abort, int so_locked) +sctp_abort_notification(struct sctp_tcb *stcb, bool from_peer, bool timeout, + uint16_t error, struct sctp_abort_chunk *abort, + int so_locked) { if (stcb == NULL) { return; @@ -4544,25 +4581,29 @@ sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); } #endif + SCTP_TCB_LOCK_ASSERT(stcb); + if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; + sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_WAS_ABORTED); } if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (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, so_locked); - SCTP_TCB_SEND_UNLOCK(stcb); if (from_peer) { sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); } else { - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); + if (timeout) { + sctp_ulp_notify(SCTP_NOTIFY_ASSOC_TIMEDOUT, stcb, error, abort, so_locked); + } else { + sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); + } } } @@ -4576,15 +4617,25 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #endif uint32_t vrf_id, uint16_t port) { - uint32_t vtag; #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; #endif + struct sctp_gen_error_cause* cause; + uint32_t vtag; + uint16_t cause_code; - vtag = 0; if (stcb != NULL) { vtag = stcb->asoc.peer_vtag; vrf_id = stcb->asoc.vrf_id; + if (op_err != NULL) { + /* Read the cause code from the error cause. */ + cause = mtod(op_err, struct sctp_gen_error_cause *); + cause_code = ntohs(cause->code); + } else { + cause_code = 0; + } + } else { + vtag = 0; } sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -4593,7 +4644,7 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 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); + sctp_abort_notification(stcb, false, false, cause_code, NULL, SCTP_SO_NOT_LOCKED); /* Ok, now lets free it */ #if defined(__APPLE__) && !defined(__Userspace__) so = SCTP_INP_SO(inp); @@ -4679,12 +4730,13 @@ 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) + struct mbuf *op_err, bool timedout, int so_locked) { #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; #endif + struct sctp_gen_error_cause* cause; + uint16_t cause_code; #if defined(__APPLE__) && !defined(__Userspace__) so = SCTP_INP_SO(inp); @@ -4716,6 +4768,13 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } return; } + if (op_err != NULL) { + /* Read the cause code from the error cause. */ + cause = mtod(op_err, struct sctp_gen_error_cause *); + cause_code = ntohs(cause->code); + } else { + cause_code = 0; + } /* notify the peer */ sctp_send_abort_tcb(stcb, op_err, so_locked); SCTP_STAT_INCR_COUNTER32(sctps_aborted); @@ -4725,7 +4784,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } /* notify the ulp */ if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - sctp_abort_notification(stcb, 0, 0, NULL, so_locked); + sctp_abort_notification(stcb, false, timedout, cause_code, NULL, so_locked); } /* now free the asoc */ #ifdef SCTP_ASOCLOG_OF_TSNS @@ -4832,7 +4891,7 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, * if there is return 1, else return 0. */ int -sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t * vtagfill) +sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtag) { struct sctp_chunkhdr *ch; struct sctp_init_chunk *init_chk, chunk_buf; @@ -4853,12 +4912,13 @@ sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t * vtagfill) /* yep, tell them */ return (1); } - if (ch->chunk_type == SCTP_INITIATION) { + if ((ch->chunk_type == SCTP_INITIATION) || + (ch->chunk_type == SCTP_INITIATION_ACK)) { /* need to update the Vtag */ init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, - offset, sizeof(*init_chk), (uint8_t *) & chunk_buf); + offset, sizeof(struct sctp_init_chunk), (uint8_t *) & chunk_buf); if (init_chk != NULL) { - *vtagfill = ntohl(init_chk->init.initiate_tag); + *vtag = ntohl(init_chk->init.initiate_tag); } } /* Nope, move to the next chunk */ @@ -5098,9 +5158,13 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, new_so = new_inp->sctp_socket; TAILQ_INIT(&tmp_queue); #if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) +#if defined(__FreeBSD__) + error = SOCK_IO_RECV_LOCK(old_so, waitflags); +#else error = sblock(&old_so->so_rcv, waitflags); +#endif if (error) { - /* Gak, can't get sblock, we have a problem. + /* Gak, can't get I/O lock, we have a problem. * data will be left stranded.. and we * don't dare look at it since the * other thread may be reading something. @@ -5135,13 +5199,12 @@ 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 */ + /* Remove the recv-lock on the old socket */ #if defined(__APPLE__) && !defined(__Userspace__) sbunlock(&old_so->so_rcv, 1); #endif - #if defined(__FreeBSD__) && !defined(__Userspace__) - sbunlock(&old_so->so_rcv); + SOCK_IO_RECV_UNLOCK(old_so); #endif /* Now we move them over to the new socket buffer */ SCTP_INP_READ_LOCK(new_inp); @@ -5171,7 +5234,10 @@ sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, #endif ) { - if ((inp != NULL) && (inp->sctp_socket != NULL)) { + if ((inp != NULL) && + (inp->sctp_socket != NULL) && + (((inp->sctp_flags & (SCTP_PCB_FLAGS_TCPTYPE | SCTP_PCB_FLAGS_IN_TCPPOOL)) == 0) || + !SCTP_IS_LISTENING(inp))) { #if defined(__APPLE__) && !defined(__Userspace__) struct socket *so; @@ -5330,8 +5396,9 @@ sctp_add_to_readq(struct sctp_inpcb *inp, sctp_unlock_assert(SCTP_INP_SO(inp)); } #endif - if (inp_read_lock_held == 0) + if (inp_read_lock_held == SCTP_READ_LOCK_NOT_HELD) { SCTP_INP_READ_LOCK(inp); + } if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { if (!control->on_strm_q) { sctp_free_remote_addr(control->whoFrom); @@ -5341,11 +5408,12 @@ sctp_add_to_readq(struct sctp_inpcb *inp, } sctp_free_a_readq(stcb, control); } - if (inp_read_lock_held == 0) + if (inp_read_lock_held == SCTP_READ_LOCK_NOT_HELD) { SCTP_INP_READ_UNLOCK(inp); + } return; } - if (!(control->spec_flags & M_NOTIFICATION)) { + if ((control->spec_flags & M_NOTIFICATION) == 0) { atomic_add_int(&inp->total_recvs, 1); if (!control->do_not_ref_stcb) { atomic_add_int(&stcb->total_recvs, 1); @@ -5354,7 +5422,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp, m = control->data; control->held_length = 0; control->length = 0; - while (m) { + while (m != NULL) { if (SCTP_BUF_LEN(m) == 0) { /* Skip mbufs with NO length */ if (prev == NULL) { @@ -5398,14 +5466,15 @@ sctp_add_to_readq(struct sctp_inpcb *inp, } 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 defined(__Userspace__) - sctp_invoke_recv_callback(inp, stcb, control, inp_read_lock_held); + sctp_invoke_recv_callback(inp, stcb, control, SCTP_READ_LOCK_HELD); #endif - if (inp && inp->sctp_socket) { + if ((inp != NULL) && (inp->sctp_socket != NULL)) { sctp_wakeup_the_read_socket(inp, stcb, so_locked); } + if (inp_read_lock_held == SCTP_READ_LOCK_NOT_HELD) { + SCTP_INP_READ_UNLOCK(inp); + } } /*************HOLD THIS COMMENT FOR PATCH FILE OF @@ -5462,7 +5531,6 @@ sctp_generate_no_user_data_cause(uint32_t tsn) return (m); } -#ifdef SCTP_MBCNT_LOGGING void sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_tmit_chunk *tp1, int chk_cnt) @@ -5470,35 +5538,31 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, if (tp1->data == NULL) { return; } - asoc->chunks_on_out_queue -= chk_cnt; + atomic_subtract_int(&asoc->chunks_on_out_queue, chk_cnt); +#ifdef SCTP_MBCNT_LOGGING if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, - asoc->total_output_queue_size, - tp1->book_size, - 0, - tp1->mbcnt); + asoc->total_output_queue_size, + tp1->book_size, + 0, + tp1->mbcnt); } +#endif if (asoc->total_output_queue_size >= tp1->book_size) { - atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size); + atomic_subtract_int(&asoc->total_output_queue_size, tp1->book_size); } else { asoc->total_output_queue_size = 0; } - - if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { - if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { - stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size; - } else { - stcb->sctp_socket->so_snd.sb_cc = 0; - } + if ((stcb->sctp_socket != NULL) && + (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || + ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { + SCTP_SB_DECR(&stcb->sctp_socket->so_snd, tp1->book_size); } } -#endif - int sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, - uint8_t sent, int so_locked) + uint8_t sent, int so_locked) { struct sctp_stream_out *strq; struct sctp_tmit_chunk *chk = NULL, *tp2; @@ -5517,9 +5581,11 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); } #endif + SCTP_TCB_LOCK_ASSERT(stcb); + sid = tp1->rec.data.sid; mid = tp1->rec.data.mid; - if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { + if (sent || ((tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0)) { stcb->asoc.abandoned_sent[0]++; stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; stcb->asoc.strmout[sid].abandoned_sent[0]++; @@ -5623,7 +5689,6 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, * Still no eom found. That means there * is stuff left on the stream out queue.. yuck. */ - SCTP_TCB_SEND_LOCK(stcb); strq = &stcb->asoc.strmout[sid]; sp = TAILQ_FIRST(&strq->outqueue); if (sp != NULL) { @@ -5708,7 +5773,6 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, sp->length = 0; } } - SCTP_TCB_SEND_UNLOCK(stcb); } if (do_wakeup_routine) { #if defined(__APPLE__) && !defined(__Userspace__) @@ -6006,7 +6070,7 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock, SCTP_INP_DECR_REF(stcb->sctp_ep); no_lock: - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); return; } @@ -6106,14 +6170,14 @@ sctp_sorecvmsg(struct socket *so, #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); + rwnd_req, in_eeor_mode, SCTP_SBAVAIL(&so->so_rcv), uio->uio_resid); #else sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio_resid(uio)); + rwnd_req, in_eeor_mode, SCTP_SBAVAIL(&so->so_rcv), uio_resid(uio)); #endif #else sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); + rwnd_req, in_eeor_mode, SCTP_SBAVAIL(&so->so_rcv), (uint32_t)uio->uio_resid); #endif } #if defined(__Userspace__) @@ -6124,14 +6188,14 @@ sctp_sorecvmsg(struct socket *so, #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); + rwnd_req, block_allowed, SCTP_SBAVAIL(&so->so_rcv), uio->uio_resid); #else sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, so->so_rcv.sb_cc, uio_resid(uio)); + rwnd_req, block_allowed, SCTP_SBAVAIL(&so->so_rcv), uio_resid(uio)); #endif #else sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); + rwnd_req, block_allowed, SCTP_SBAVAIL(&so->so_rcv), (uint32_t)uio->uio_resid); #endif } @@ -6139,7 +6203,7 @@ sctp_sorecvmsg(struct socket *so, error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags)); #endif #if defined(__FreeBSD__) && !defined(__Userspace__) - error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); + error = SOCK_IO_RECV_LOCK(so, SBLOCKWAIT(in_flags)); #endif if (error) { goto release_unlocked; @@ -6168,9 +6232,9 @@ sctp_sorecvmsg(struct socket *so, goto out; } #if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__) - if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) { + if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && SCTP_SBAVAIL(&so->so_rcv) == 0) { #else - if ((so->so_state & SS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) { + if ((so->so_state & SS_CANTRCVMORE) && SCTP_SBAVAIL(&so->so_rcv) == 0) { #endif if (so->so_error) { error = so->so_error; @@ -6178,14 +6242,14 @@ sctp_sorecvmsg(struct socket *so, so->so_error = 0; goto out; } else { - if (so->so_rcv.sb_cc == 0) { + if (SCTP_SBAVAIL(&so->so_rcv) == 0) { /* indicate EOF */ error = 0; goto out; } } } - if (so->so_rcv.sb_cc <= held_length) { + if (SCTP_SBAVAIL(&so->so_rcv) <= held_length) { if (so->so_error) { error = so->so_error; if ((in_flags & MSG_PEEK) == 0) { @@ -6193,7 +6257,7 @@ sctp_sorecvmsg(struct socket *so, } goto out; } - if ((so->so_rcv.sb_cc == 0) && + if ((SCTP_SBAVAIL(&so->so_rcv) == 0) && ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { @@ -6207,7 +6271,9 @@ sctp_sorecvmsg(struct socket *so, } so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING | +#if !(defined(__FreeBSD__) && !defined(__Userspace__)) SS_ISCONFIRMING | +#endif SS_ISCONNECTED); if (error == 0) { if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { @@ -6219,7 +6285,11 @@ sctp_sorecvmsg(struct socket *so, } } if (block_allowed) { +#if defined(__FreeBSD__) && !defined(__Userspace__) + error = sbwait(so, SO_RCV); +#else error = sbwait(&so->so_rcv); +#endif if (error) { goto out; } @@ -6250,11 +6320,11 @@ sctp_sorecvmsg(struct socket *so, SCTP_INP_READ_LOCK(inp); } control = TAILQ_FIRST(&inp->read_queue); - if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { + if ((control == NULL) && (SCTP_SBAVAIL(&so->so_rcv) > 0)) { #ifdef INVARIANTS panic("Huh, its non zero and nothing on control?"); #endif - so->so_rcv.sb_cc = 0; + SCTP_SB_CLEAR(so->so_rcv); } SCTP_INP_READ_UNLOCK(inp); hold_rlock = 0; @@ -6289,7 +6359,7 @@ sctp_sorecvmsg(struct socket *so, } else { /* remove it */ TAILQ_REMOVE(&inp->read_queue, control, next); - /* Add back any hiddend data */ + /* Add back any hidden data */ sctp_free_remote_addr(control->whoFrom); sctp_free_a_readq(stcb, control); } @@ -6366,7 +6436,7 @@ sctp_sorecvmsg(struct socket *so, * have the strm interleave feature present. Then if we have * taken some (pdapi) or we can refer to tht tcb AND we have * not started a delivery for this stream, we can take it. - * Note we do NOT allow a notificaiton on the same assoc to + * Note we do NOT allow a notification on the same assoc to * be delivered. */ control = ctl; @@ -6380,8 +6450,8 @@ sctp_sorecvmsg(struct socket *so, * fragment interleave is NOT on. So stuff the sb_cc * into the our held count, and its time to sleep again. */ - held_length = so->so_rcv.sb_cc; - control->held_length = so->so_rcv.sb_cc; + held_length = SCTP_SBAVAIL(&so->so_rcv); + control->held_length = SCTP_SBAVAIL(&so->so_rcv); goto restart; } /* Clear the held length since there is something to read */ @@ -6634,7 +6704,7 @@ sctp_sorecvmsg(struct socket *so, if ((SCTP_BUF_NEXT(m)== NULL) && (control->end_added)) { out_flags |= MSG_EOR; - if ((control->do_not_ref_stcb == 0) && + if ((control->do_not_ref_stcb == 0) && (control->stcb != NULL) && ((control->spec_flags & M_NOTIFICATION) == 0)) control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; @@ -6661,7 +6731,7 @@ sctp_sorecvmsg(struct socket *so, copied_so_far += cp_len; freed_so_far += (uint32_t)cp_len; freed_so_far += MSIZE; - atomic_subtract_int(&control->length, cp_len); + atomic_subtract_int(&control->length, (int)cp_len); control->data = sctp_m_free(m); m = control->data; /* been through it all, must hold sb lock ok to null tail */ @@ -6698,10 +6768,10 @@ sctp_sorecvmsg(struct socket *so, 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, (int)cp_len); } - atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); + SCTP_SB_DECR(&so->so_rcv, cp_len); if ((control->do_not_ref_stcb == 0) && stcb) { - atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); + atomic_subtract_int(&stcb->asoc.sb_cc, (int)cp_len); } copied_so_far += cp_len; freed_so_far += (uint32_t)cp_len; @@ -6710,7 +6780,7 @@ sctp_sorecvmsg(struct socket *so, sctp_sblog(&so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); } - atomic_subtract_int(&control->length, cp_len); + atomic_subtract_int(&control->length, (int)cp_len); } else { copied_so_far += cp_len; } @@ -6744,7 +6814,7 @@ sctp_sorecvmsg(struct socket *so, #ifdef INVARIANTS panic("control->data not null at read eor?"); #else - SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n"); + SCTP_PRINTF("Strange, data left in the control buffer .. invariants would panic?\n"); sctp_m_freem(control->data); control->data = NULL; #endif @@ -6755,7 +6825,7 @@ sctp_sorecvmsg(struct socket *so, hold_rlock = 1; } TAILQ_REMOVE(&inp->read_queue, control, next); - /* Add back any hiddend data */ + /* Add back any hidden data */ if (control->held_length) { held_length = 0; control->held_length = 0; @@ -6823,10 +6893,11 @@ sctp_sorecvmsg(struct socket *so, goto release; } /* - * We need to wait for more data a few things: - We don't - * sbunlock() so we don't get someone else reading. - We - * must be sure to account for the case where what is added - * is NOT to our control when we wakeup. + * We need to wait for more data a few things: + * - We don't release the I/O lock so we don't get someone else + * reading. + * - We must be sure to account for the case where what is added + * is NOT to our control when we wakeup. */ /* Do we need to tell the transport a rwnd update might be @@ -6867,13 +6938,17 @@ sctp_sorecvmsg(struct socket *so, #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 (SCTP_SBAVAIL(&so->so_rcv) <= control->held_length) { #if defined(__FreeBSD__) && !defined(__Userspace__) - goto release; + error = sbwait(so, SO_RCV); #else + error = sbwait(&so->so_rcv); +#endif + if (error) { +#if defined(__APPLE__) && !defined(__Userspace__) goto release_unlocked; +#else + goto release; #endif } control->held_length = 0; @@ -6901,8 +6976,8 @@ sctp_sorecvmsg(struct socket *so, } goto done_with_control; } - if (so->so_rcv.sb_cc > held_length) { - control->held_length = so->so_rcv.sb_cc; + if (SCTP_SBAVAIL(&so->so_rcv) > held_length) { + control->held_length = SCTP_SBAVAIL(&so->so_rcv); held_length = 0; } goto wait_some_more; @@ -7003,7 +7078,7 @@ sctp_sorecvmsg(struct socket *so, #endif #if defined(__FreeBSD__) && !defined(__Userspace__) - sbunlock(&so->so_rcv); + SOCK_IO_RECV_UNLOCK(so); sockbuf_lock = 0; #endif @@ -7039,7 +7114,7 @@ sctp_sorecvmsg(struct socket *so, } #if defined(__FreeBSD__) && !defined(__Userspace__) if (sockbuf_lock) { - sbunlock(&so->so_rcv); + SOCK_IO_RECV_UNLOCK(so); } #endif @@ -7060,37 +7135,37 @@ sctp_sorecvmsg(struct socket *so, } /* Save the value back for next time */ stcb->freed_by_sorcv_sincelast = freed_so_far; - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_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, + freed_so_far, #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) - ((uio) ? (slen - uio->uio_resid) : slen), + ((uio) ? (slen - uio->uio_resid) : slen), #else - ((uio) ? (slen - uio_resid(uio)) : slen), + ((uio) ? (slen - uio_resid(uio)) : slen), #endif #else - (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), + (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), #endif - stcb->asoc.my_rwnd, - so->so_rcv.sb_cc); + stcb->asoc.my_rwnd, + SCTP_SBAVAIL(&so->so_rcv)); } else { sctp_misc_ints(SCTP_SORECV_DONE, - freed_so_far, + freed_so_far, #if defined(__APPLE__) && !defined(__Userspace__) #if defined(APPLE_LEOPARD) - ((uio) ? (slen - uio->uio_resid) : slen), + ((uio) ? (slen - uio->uio_resid) : slen), #else - ((uio) ? (slen - uio_resid(uio)) : slen), + ((uio) ? (slen - uio_resid(uio)) : slen), #endif #else - (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), + (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), #endif - 0, - so->so_rcv.sb_cc); + 0, + SCTP_SBAVAIL(&so->so_rcv)); } } stage_left: @@ -7416,8 +7491,7 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, case AF_INET: incr = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *)sa; - if ((sin->sin_addr.s_addr == INADDR_ANY) || - (sin->sin_addr.s_addr == INADDR_BROADCAST) || + if (in_broadcast(sin->sin_addr) || 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, @@ -7526,17 +7600,17 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, { struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - /* Must be non-mapped for connectx */ - return (EINVAL); - } incr = (unsigned int)sizeof(struct sockaddr_in6); #ifdef HAVE_SA_LEN if (sa->sa_len != incr) { return (EINVAL); } #endif + sin6 = (struct sockaddr_in6 *)sa; + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + /* Must be non-mapped for connectx */ + return (EINVAL); + } (*num_v6) += 1; break; } @@ -8026,7 +8100,7 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_ #endif #if defined(__FreeBSD__) && !defined(__Userspace__) -static void +static bool sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) { @@ -8104,18 +8178,20 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, goto out; break; } - return; + return (true); out: m_freem(m); + + return (true); } #ifdef INET static void -sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED) +sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) { + struct icmp *icmp = param.icmp; struct ip *outer_ip, *inner_ip; struct sctphdr *sh; - struct icmp *icmp; struct udphdr *udp; struct sctp_inpcb *inp; struct sctp_tcb *stcb; @@ -8124,9 +8200,7 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct 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))); + inner_ip = &icmp->icmp_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) { @@ -8210,7 +8284,7 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct 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) && + if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && (stcb->sctp_socket != NULL)) { struct socket *upcall_socket; @@ -8244,9 +8318,9 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct #ifdef INET6 static void -sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED) +sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) { - struct ip6ctlparam *ip6cp; + struct ip6ctlparam *ip6cp = param.ip6cp; struct sctp_inpcb *inp; struct sctp_tcb *stcb; struct sctp_nets *net; @@ -8255,7 +8329,6 @@ sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx 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. @@ -8383,7 +8456,7 @@ sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx 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) && + if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && (stcb->sctp_socket != NULL)) { struct socket *upcall_socket; @@ -8418,7 +8491,7 @@ void sctp_over_udp_stop(void) { /* - * This function assumes sysctl caller holds sctp_sysctl_info_lock() for writting! + * This function assumes sysctl caller holds sctp_sysctl_info_lock() for writing! */ #ifdef INET if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { @@ -8446,7 +8519,7 @@ sctp_over_udp_start(void) struct sockaddr_in6 sin6; #endif /* - * This function assumes sysctl caller holds sctp_sysctl_info_lock() for writting! + * This function assumes sysctl caller holds sctp_sysctl_info_lock() for writing! */ port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); if (ntohs(port) == 0) { diff --git a/netwerk/sctp/src/netinet/sctputil.h b/netwerk/sctp/src/netinet/sctputil.h index 14aaf530a1..5e0fc81f9a 100644 --- a/netwerk/sctp/src/netinet/sctputil.h +++ b/netwerk/sctp/src/netinet/sctputil.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #ifndef _NETINET_SCTP_UTIL_H_ #define _NETINET_SCTP_UTIL_H_ @@ -83,16 +78,10 @@ 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, uint16_t); +int sctp_init_asoc(struct sctp_inpcb *, struct sctp_tcb *, uint32_t, uint32_t, uint32_t, uint16_t); void sctp_fill_random_store(struct sctp_pcb *); -void -sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, - uint16_t numberout, int flag); -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 @@ -112,9 +101,6 @@ sctp_timer_stop(int, struct sctp_inpcb *, struct sctp_tcb *, int sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id); -void -sctp_mtu_size_reset(struct sctp_inpcb *, struct sctp_association *, uint32_t); - void sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked @@ -181,8 +167,8 @@ 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); +void sctp_abort_notification(struct sctp_tcb *, bool, bool, uint16_t, + struct sctp_abort_chunk *, int); /* We abort responding to an IP packet for some reason */ void @@ -197,7 +183,7 @@ sctp_abort_association(struct sctp_inpcb *, struct sctp_tcb *, struct mbuf *, /* We choose to abort via user input */ void sctp_abort_an_association(struct sctp_inpcb *, struct sctp_tcb *, - struct mbuf *, int); + struct mbuf *, bool, int); void sctp_handle_ootb(struct mbuf *, int, int, struct sockaddr *, struct sockaddr *, @@ -277,34 +263,10 @@ void sctp_bindx_delete_address(struct sctp_inpcb *inp, struct sockaddr *sa, int sctp_local_addr_count(struct sctp_tcb *stcb); -#ifdef SCTP_MBCNT_LOGGING void sctp_free_bufspace(struct sctp_tcb *, struct sctp_association *, struct sctp_tmit_chunk *, int); -#else -#define sctp_free_bufspace(stcb, asoc, tp1, chk_cnt) \ -do { \ - if (tp1->data != NULL) { \ - atomic_subtract_int(&((asoc)->chunks_on_out_queue), chk_cnt); \ - if ((asoc)->total_output_queue_size >= tp1->book_size) { \ - atomic_subtract_int(&((asoc)->total_output_queue_size), tp1->book_size); \ - } else { \ - (asoc)->total_output_queue_size = 0; \ - } \ - if (stcb->sctp_socket && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \ - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \ - if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { \ - atomic_subtract_int(&((stcb)->sctp_socket->so_snd.sb_cc), tp1->book_size); \ - } else { \ - stcb->sctp_socket->so_snd.sb_cc = 0; \ - } \ - } \ - } \ -} while (0) - -#endif - #define sctp_free_spbufspace(stcb, asoc, sp) \ do { \ if (sp->data != NULL) { \ @@ -315,11 +277,7 @@ do { \ } \ if (stcb->sctp_socket && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \ (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \ - if (stcb->sctp_socket->so_snd.sb_cc >= sp->length) { \ - atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc,sp->length); \ - } else { \ - stcb->sctp_socket->so_snd.sb_cc = 0; \ - } \ + SCTP_SB_DECR(&stcb->sctp_socket->so_snd, sp->length); \ } \ } \ } while (0) @@ -330,7 +288,7 @@ do { \ 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_add_int(&stcb->sctp_socket->so_snd.sb_cc,sz); \ + SCTP_SB_INCR(&stcb->sctp_socket->so_snd, sz); \ } \ } while (0) diff --git a/netwerk/sctp/src/netinet6/sctp6_usrreq.c b/netwerk/sctp/src/netinet6/sctp6_usrreq.c index 5a931dd5a2..2960c98269 100644 --- a/netwerk/sctp/src/netinet6/sctp6_usrreq.c +++ b/netwerk/sctp/src/netinet6/sctp6_usrreq.c @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 365071 2020-09-01 21:19:14Z mjg $"); -#endif - #include #ifdef INET6 #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -259,13 +254,14 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { goto out; } - ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); #if defined(__FreeBSD__) + ecn_bits = IPV6_TRAFFIC_CLASS(ip6); if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { SCTP_STAT_INCR(sctps_recvhwcrc); compute_crc = 0; } else { #else + ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && (IN6_ARE_ADDR_EQUAL(&src.sin6_addr, &dst.sin6_addr))) { SCTP_STAT_INCR(sctps_recvhwcrc); @@ -340,7 +336,7 @@ sctp6_notify(struct sctp_inpcb *inp, 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); + sctp_abort_notification(stcb, true, false, 0, NULL, SCTP_SO_NOT_LOCKED); #if defined(__APPLE__) so = SCTP_INP_SO(inp); atomic_add_int(&stcb->asoc.refcnt, 1); @@ -386,7 +382,7 @@ sctp6_notify(struct sctp_inpcb *inp, } /* Update the association MTU */ if (stcb->asoc.smallest_mtu > next_mtu) { - sctp_pathmtu_adjustment(stcb, next_mtu); + sctp_pathmtu_adjustment(stcb, next_mtu, true); } /* Finally, start the PMTU timer if it was running before. */ if (timer_stopped) { @@ -400,6 +396,121 @@ sctp6_notify(struct sctp_inpcb *inp, } } +#if defined(__FreeBSD__) && !defined(__Userspace__) +void +sctp6_ctlinput(struct ip6ctlparam *ip6cp) +{ + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctphdr sh; + struct sockaddr_in6 src, dst; + + if (icmp6_errmap(ip6cp->ip6c_icmp6) == 0) { + 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 < + (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { + return; + } + + /* 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; + src.sin6_len = sizeof(struct sockaddr_in6); + src.sin6_port = sh.src_port; + src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; + if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } + memset(&dst, 0, sizeof(struct sockaddr_in6)); + dst.sin6_family = AF_INET6; + dst.sin6_len = sizeof(struct sockaddr_in6); + dst.sin6_port = sh.dest_port; + dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; + if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } + 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 { + 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; + } + } + sctp6_notify(inp, stcb, net, + ip6cp->ip6c_icmp6->icmp6_type, + ip6cp->ip6c_icmp6->icmp6_code, + ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); + } 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); + } + } +} +#else 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) @@ -468,11 +579,6 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) #endif 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 @@ -480,11 +586,6 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) #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, @@ -505,51 +606,16 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) return; } } else { -#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 } 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) { + if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && + (stcb->sctp_socket != NULL)) { struct socket *upcall_socket; upcall_socket = stcb->sctp_socket; @@ -579,9 +645,10 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) } } #endif +#endif /* - * this routine can probably be collasped into the one in sctp_userreq.c + * this routine can probably be collapsed into the one in sctp_userreq.c * since they do the same thing and now we lookup with a sockaddr */ #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -598,11 +665,9 @@ sctp6_getcred(SYSCTL_HANDLER_ARGS) vrf_id = SCTP_DEFAULT_VRFID; -#if defined(__FreeBSD__) && !defined(__Userspace__) + if (req->newptr == NULL) + return (EINVAL); error = priv_check(req->td, PRIV_NETINET_GETCRED); -#else - error = suser(req->p); -#endif if (error) return (error); @@ -654,78 +719,12 @@ out: return (error); } -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"); +SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, + CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_NEEDGIANT, + 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(__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__) || 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 - sctp_log_closing(inp, NULL, 17); -#endif - 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, 16); -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - SOCK_LOCK(so); - SCTP_SB_CLEAR(so->so_snd); - /* same for the rcv ones, they are only - * here for the accounting/select. - */ - SCTP_SB_CLEAR(so->so_rcv); -#if defined(__APPLE__) && !defined(__Userspace__) - so->so_usecount--; -#else - /* Now null out the reference, we are completely detached. */ - so->so_pcb = NULL; -#endif - SOCK_UNLOCK(so); - } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); - return; -#else - return (0); -#endif -} - #if defined(__Userspace__) int sctp6_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) @@ -937,15 +936,6 @@ sctp6_detach(struct socket *so) #endif -#if !defined(__Userspace__) -static -#endif -int -sctp6_disconnect(struct socket *so) -{ - return (sctp_disconnect(so)); -} - int #if defined(__FreeBSD__) && !defined(__Userspace__) sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, @@ -1007,6 +997,46 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam, SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); return (EDESTADDRREQ); } + switch (addr->sa_family) { +#ifdef INET + case AF_INET: +#if defined(HAVE_SA_LEN) + if (addr->sa_len != sizeof(struct sockaddr_in)) { + if (control) { + SCTP_RELEASE_PKT(control); + control = NULL; + } + SCTP_RELEASE_PKT(m); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); + return (EINVAL); + } +#endif + break; +#endif +#ifdef INET6 + case AF_INET6: +#if defined(HAVE_SA_LEN) + if (addr->sa_len != sizeof(struct sockaddr_in6)) { + if (control) { + SCTP_RELEASE_PKT(control); + control = NULL; + } + SCTP_RELEASE_PKT(m); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); + return (EINVAL); + } +#endif + break; +#endif + default: + if (control) { + SCTP_RELEASE_PKT(control); + control = NULL; + } + SCTP_RELEASE_PKT(m); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); + return (EINVAL); + } #ifdef INET sin6 = (struct sockaddr_in6 *)addr; if (SCTP_IPV6_V6ONLY(inp)) { @@ -1015,15 +1045,26 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam, * v4 addr or v4-mapped addr */ if (addr->sa_family == AF_INET) { + if (control) { + SCTP_RELEASE_PKT(control); + control = NULL; + } + SCTP_RELEASE_PKT(m); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL); } if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + if (control) { + SCTP_RELEASE_PKT(control); + control = NULL; + } + SCTP_RELEASE_PKT(m); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL); } } - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + if ((addr->sa_family == AF_INET6) && + IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { struct sockaddr_in sin; /* convert v4-mapped into v4 addr and send */ @@ -1061,8 +1102,8 @@ connected_type: * note with the current version this code will only be used * by OpenBSD, NetBSD and FreeBSD have methods for * re-defining sosend() to use sctp_sosend(). One can - * optionaly switch back to this code (by changing back the - * defininitions but this is not advisable. + * optionally switch back to this code (by changing back the + * definitions but this is not advisable. */ #if defined(__FreeBSD__) && !defined(__Userspace__) struct epoch_tracker et; @@ -1201,7 +1242,8 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p) return (EINVAL); } } - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + if ((addr->sa_family == AF_INET6) && + IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { /* convert v4-mapped into v4 addr */ in6_sin6_2_sin(&store.sin, sin6); addr = &store.sa; @@ -1235,20 +1277,15 @@ 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, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, p, - SCTP_INITIALIZE_AUTH_PARAMS); + stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 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 */ return (error); } - 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); - } SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); #if defined(__FreeBSD__) && !defined(__Userspace__) @@ -1618,28 +1655,44 @@ sctp6_getpeeraddr(struct socket *so, struct mbuf *nam) } #if !defined(__Userspace__) -struct pr_usrreqs sctp6_usrreqs = { #if defined(__FreeBSD__) - .pru_abort = sctp6_abort, - .pru_accept = sctp_accept, - .pru_attach = sctp6_attach, - .pru_bind = sctp6_bind, - .pru_connect = sctp6_connect, - .pru_control = in6_control, - .pru_close = sctp6_close, - .pru_detach = sctp6_close, - .pru_sopoll = sopoll_generic, - .pru_flush = sctp_flush, - .pru_disconnect = sctp6_disconnect, - .pru_listen = sctp_listen, - .pru_peeraddr = sctp6_getpeeraddr, - .pru_send = sctp6_send, - .pru_shutdown = sctp_shutdown, - .pru_sockaddr = sctp6_in6getaddr, - .pru_sosend = sctp_sosend, - .pru_soreceive = sctp_soreceive -#elif defined(__APPLE__) && !defined(__Userspace__) - .pru_abort = sctp6_abort, +#define SCTP6_PROTOSW \ + .pr_protocol = IPPROTO_SCTP, \ + .pr_ctloutput = sctp_ctloutput, \ + .pr_abort = sctp_abort, \ + .pr_accept = sctp_accept, \ + .pr_attach = sctp6_attach, \ + .pr_bind = sctp6_bind, \ + .pr_connect = sctp6_connect, \ + .pr_control = in6_control, \ + .pr_close = sctp6_close, \ + .pr_detach = sctp6_close, \ + .pr_sopoll = sopoll_generic, \ + .pr_flush = sctp_flush, \ + .pr_disconnect = sctp_disconnect, \ + .pr_listen = sctp_listen, \ + .pr_peeraddr = sctp6_getpeeraddr, \ + .pr_send = sctp6_send, \ + .pr_shutdown = sctp_shutdown, \ + .pr_sockaddr = sctp6_in6getaddr, \ + .pr_sosend = sctp_sosend, \ + .pr_soreceive = sctp_soreceive + +struct protosw sctp6_seqpacket_protosw = { + .pr_type = SOCK_SEQPACKET, + .pr_flags = PR_WANTRCVD, + SCTP6_PROTOSW +}; + +struct protosw sctp6_stream_protosw = { + .pr_type = SOCK_STREAM, + .pr_flags = PR_CONNREQUIRED | PR_WANTRCVD, + SCTP6_PROTOSW +}; +#else +struct pr_usrreqs sctp6_usrreqs = { +#if defined(__APPLE__) && !defined(__Userspace__) + .pru_abort = sctp_abort, .pru_accept = sctp_accept, .pru_attach = sctp6_attach, .pru_bind = sctp6_bind, @@ -1647,7 +1700,7 @@ struct pr_usrreqs sctp6_usrreqs = { .pru_connect2 = pru_connect2_notsupp, .pru_control = in6_control, .pru_detach = sctp6_detach, - .pru_disconnect = sctp6_disconnect, + .pru_disconnect = sctp_disconnect, .pru_listen = sctp_listen, .pru_peeraddr = sctp6_getpeeraddr, .pru_rcvd = NULL, @@ -1660,7 +1713,7 @@ struct pr_usrreqs sctp6_usrreqs = { .pru_soreceive = sctp_soreceive, .pru_sopoll = sopoll #elif defined(_WIN32) && !defined(__Userspace__) - sctp6_abort, + sctp_abort, sctp_accept, sctp6_attach, sctp6_bind, @@ -1668,7 +1721,7 @@ struct pr_usrreqs sctp6_usrreqs = { pru_connect2_notsupp, NULL, NULL, - sctp6_disconnect, + sctp_disconnect, sctp_listen, sctp6_getpeeraddr, NULL, @@ -1683,120 +1736,8 @@ struct pr_usrreqs sctp6_usrreqs = { sopoll_generic, NULL, sctp6_close -#endif }; - -#elif !defined(__Userspace__) -int -sctp6_usrreq(so, req, m, nam, control, p) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; - struct proc *p; -{ - int error; - int family; - - 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); - 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); - error = EAFNOSUPPORT; - } - return (error); - } - switch (req) { - case PRU_ATTACH: - error = sctp6_attach(so, family, p); - break; - case PRU_DETACH: - error = sctp6_detach(so); - break; - case PRU_BIND: - if (nam == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - error = sctp6_bind(so, nam, p); - break; - case PRU_LISTEN: - error = sctp_listen(so, p); - break; - case PRU_CONNECT: - if (nam == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - error = sctp6_connect(so, nam, p); - break; - case PRU_DISCONNECT: - error = sctp6_disconnect(so); - break; - case PRU_ACCEPT: - if (nam == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - error = sctp_accept(so, nam); - break; - case PRU_SHUTDOWN: - error = sctp_shutdown(so); - break; - - case PRU_RCVD: - /* - * For OpenBSD and NetBSD, this is real ugly. The (mbuf *) - * nam that is passed (by soreceive()) is the int flags cast - * as a (mbuf *) yuck! - */ - error = sctp_usr_recvd(so, (int)((long)nam)); - break; - - case PRU_SEND: - /* Flags are ignored */ - error = sctp6_send(so, 0, m, nam, control, p); - break; - case PRU_ABORT: - error = sctp6_abort(so); - break; - - case PRU_SENSE: - error = 0; - break; - case PRU_RCVOOB: - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT); - error = EAFNOSUPPORT; - break; - case PRU_SENDOOB: - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT); - error = EAFNOSUPPORT; - break; - case PRU_PEERADDR: - error = sctp6_getpeeraddr(so, nam); - break; - case PRU_SOCKADDR: - error = sctp6_in6getaddr(so, nam); - break; - case PRU_SLOWTIMO: - error = 0; - break; - default: - error = 0; - break; - } - return (error); -} +#endif +#endif #endif #endif diff --git a/netwerk/sctp/src/netinet6/sctp6_var.h b/netwerk/sctp/src/netinet6/sctp6_var.h index 56a6c3af3d..8bfef64ca3 100644 --- a/netwerk/sctp/src/netinet6/sctp6_var.h +++ b/netwerk/sctp/src/netinet6/sctp6_var.h @@ -32,11 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_var.h 317457 2017-04-26 19:26:40Z tuexen $"); -#endif - #ifndef _NETINET6_SCTP6_VAR_H_ #define _NETINET6_SCTP6_VAR_H_ @@ -51,7 +46,11 @@ extern void in6_sin_2_v4mapsin6(const struct sockaddr_in *, struct sockaddr_in6 #if !defined(__Userspace__) SYSCTL_DECL(_net_inet6_sctp6); +#if defined(__FreeBSD__) +extern struct protosw sctp6_seqpacket_protosw, sctp6_stream_protosw; +#else extern struct pr_usrreqs sctp6_usrreqs; +#endif #else int sctp6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *); #endif @@ -67,10 +66,12 @@ 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); +#elif defined(__FreeBSD__) && !defined(__Userspace__) +ip6proto_ctlinput_t sctp6_ctlinput; #else -void sctp6_ctlinput(int, struct sockaddr *, void *); +void sctp6_ctlinput(int, struct sockaddr_in6 *, ip6ctlparam *); #endif -#if !((defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)) +#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 *); diff --git a/netwerk/sctp/src/user_environment.c b/netwerk/sctp/src/user_environment.c index 1887718911..a007597b61 100644 --- a/netwerk/sctp/src/user_environment.c +++ b/netwerk/sctp/src/user_environment.c @@ -367,7 +367,7 @@ read_random(void *buf, size_t size) position = 0; while (position < size) { - if (nacl_secure_random((char *)buf + position, size - position, &n) == 0) + if (nacl_secure_random((char *)buf + position, size - position, &n) == 0) { position += n; } } diff --git a/netwerk/sctp/src/user_mbuf.c b/netwerk/sctp/src/user_mbuf.c index 57b532bb71..f49d11c16a 100644 --- a/netwerk/sctp/src/user_mbuf.c +++ b/netwerk/sctp/src/user_mbuf.c @@ -35,6 +35,10 @@ * */ +#if defined(_WIN32) && defined(__MINGW32__) +#include +#endif + #include #include /* #include This defines MSIZE 256 */ @@ -80,8 +84,6 @@ static void mb_dtor_clust(void *, void *); static int mbuf_constructor_dup(struct mbuf *m, int pkthdr, short type) { int flags = pkthdr; - if (type == MT_NOINIT) - return (0); m->m_next = NULL; m->m_nextpkt = NULL; @@ -577,13 +579,6 @@ mb_ctor_mbuf(void *mem, void *arg, int flgs) flags = args->flags; type = args->type; - /* - * The mbuf is initialized later. - * - */ - if (type == MT_NOINIT) - return (0); - m->m_next = NULL; m->m_nextpkt = NULL; m->m_len = 0; @@ -1310,6 +1305,38 @@ out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) m->m_pkthdr.len = totlen; } +/* + * Apply function f to the data in an mbuf chain starting "off" bytes from + * the beginning, continuing for "len" bytes. + */ +int +m_apply(struct mbuf *m, int off, int len, + int (*f)(void *, void *, u_int), void *arg) +{ + u_int count; + int rval; + + KASSERT(off >= 0, ("m_apply, negative off %d", off)); + KASSERT(len >= 0, ("m_apply, negative len %d", len)); + while (off > 0) { + KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain")); + if (off < m->m_len) + break; + off -= m->m_len; + m = m->m_next; + } + while (len > 0) { + KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain")); + count = min(m->m_len - off, len); + rval = (*f)(arg, mtod(m, caddr_t) + off, count); + if (rval) + return (rval); + len -= count; + off = 0; + m = m->m_next; + } + return (0); +} /* * Lesser-used path for M_PREPEND: diff --git a/netwerk/sctp/src/user_mbuf.h b/netwerk/sctp/src/user_mbuf.h index c11b38c9cb..268988f912 100644 --- a/netwerk/sctp/src/user_mbuf.h +++ b/netwerk/sctp/src/user_mbuf.h @@ -113,6 +113,7 @@ void m_freem(struct mbuf *); 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); +int m_apply(struct mbuf *, int, int, int (*)(void *, void *, u_int), void *arg); struct mbuf *m_pullup(struct mbuf *, int); struct mbuf *m_pulldown(struct mbuf *, int off, int len, int *offp); int m_dup_pkthdr(struct mbuf *, struct mbuf *, int); @@ -125,9 +126,6 @@ void m_copydata(const struct mbuf *, int, int, caddr_t); #define MBUF_CLUSTER_MEM_NAME "mbuf_cluster" #define MBUF_EXTREFCNT_MEM_NAME "mbuf_ext_refcnt" -#define MT_NOINIT 255 /* Not a type but a flag to allocate - a non-initialized mbuf */ - /* * 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 @@ -293,9 +291,6 @@ struct mbuf { #define MT_OOBDATA 15 /* expedited data */ #define MT_NTYPES 16 /* number of mbuf types for mbtypes[] */ -#define MT_NOINIT 255 /* Not a type but a flag to allocate - a non-initialized mbuf */ - /* * __Userspace__ flags like M_NOWAIT are defined in malloc.h * Flags like these are used in functions like uma_zalloc() @@ -332,6 +327,10 @@ extern int max_protohdr; /* Size of largest protocol layer header. See user_mbuf (!(((m)->m_flags & M_EXT)) || \ (*((m)->m_ext.ref_cnt) == 1)) ) \ +/* Check if the supplied mbuf has a packet header, or else panic. */ +#define M_ASSERTPKTHDR(m) \ + KASSERT((m) != NULL && (m)->m_flags & M_PKTHDR, \ + ("%s: no mbuf packet header!", __func__)) /* * Compute the amount of space available before the current start of data in diff --git a/netwerk/sctp/src/user_recv_thread.c b/netwerk/sctp/src/user_recv_thread.c index bb436cd20d..75c9076c7b 100644 --- a/netwerk/sctp/src/user_recv_thread.c +++ b/netwerk/sctp/src/user_recv_thread.c @@ -56,8 +56,14 @@ #endif #endif #endif -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) -#include +#if defined(HAVE_NET_ROUTE_H) +# include +#elif defined(__APPLE__) +/* Apple SDKs for iOS, tvOS, watchOS, etc. don't ship this header */ +# define RTM_NEWADDR 0xc +# define RTM_DELADDR 0xd +# define RTAX_IFA 5 +# define RTAX_MAX 8 #endif /* local macros and datatypes used to get IP addresses system independently */ #if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) @@ -129,8 +135,7 @@ sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa 1); } else { sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, - if_nametoindex(ifa->ifa_name), - ifa->ifa_name); + NULL, if_nametoindex(ifa->ifa_name)); } freeifaddrs(ifas); } @@ -274,6 +279,7 @@ recv_function_raw(void *arg) struct sctp_chunkhdr *ch; struct sockaddr_in src, dst; #if !defined(_WIN32) + ssize_t res; unsigned int ncounter; struct msghdr msg; struct iovec recv_iovec[MAXLEN_MBUF_CHAIN]; @@ -340,14 +346,16 @@ recv_function_raw(void *arg) msg.msg_iovlen = MAXLEN_MBUF_CHAIN; msg.msg_control = NULL; msg.msg_controllen = 0; - ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0); - if (n < 0) { + res = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0); + if (res < 0) { if (errno == EAGAIN || errno == EINTR) { continue; } else { break; } } + ncounter = (unsigned int)res; + n = (int)res; #endif SCTP_HEADER_LEN(recvmbuf[0]) = n; /* length of total packet */ SCTP_STAT_INCR(sctps_recvpackets); @@ -451,7 +459,8 @@ recv_function_raw6(void *arg) { struct mbuf **recvmbuf6; #if !defined(_WIN32) - unsigned int ncounter = 0; + ssize_t res; + unsigned int ncounter; struct iovec recv_iovec[MAXLEN_MBUF_CHAIN]; struct msghdr msg; struct cmsghdr *cmsgptr; @@ -538,15 +547,16 @@ recv_function_raw6(void *arg) msg.msg_control = (void *)cmsgbuf; 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) { + res = recvmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, 0); + if (res < 0) { if (errno == EAGAIN || errno == EINTR) { continue; } else { break; } } + ncounter = (unsigned int)res; + n = (int)res; #endif SCTP_HEADER_LEN(recvmbuf6[0]) = n; /* length of total packet */ SCTP_STAT_INCR(sctps_recvpackets); @@ -662,6 +672,7 @@ recv_function_udp(void *arg) #endif int compute_crc = 1; #if !defined(_WIN32) + ssize_t res; unsigned int ncounter; struct iovec iov[MAXLEN_MBUF_CHAIN]; struct msghdr msg; @@ -715,14 +726,16 @@ recv_function_udp(void *arg) msg.msg_controllen = sizeof(cmsgbuf); msg.msg_flags = 0; - ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0); - if (n < 0) { + res = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0); + if (res < 0) { if (errno == EAGAIN || errno == EINTR) { continue; } else { break; } } + ncounter = (unsigned int)res; + n = (int)res; #else nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp), SIO_GET_EXTENSION_FUNCTION_POINTER, &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, @@ -874,6 +887,7 @@ recv_function_udp6(void *arg) struct iovec iov[MAXLEN_MBUF_CHAIN]; struct msghdr msg; struct cmsghdr *cmsgptr; + ssize_t res; unsigned int ncounter; #else GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; @@ -924,14 +938,16 @@ recv_function_udp6(void *arg) 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) { + res = recvmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, 0); + if (res < 0) { if (errno == EAGAIN || errno == EINTR) { continue; } else { break; } } + ncounter = (unsigned int)res; + n = (int)res; #else nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER, &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, diff --git a/netwerk/sctp/src/user_socket.c b/netwerk/sctp/src/user_socket.c index 513a5a9a40..163db3428e 100644 --- a/netwerk/sctp/src/user_socket.c +++ b/netwerk/sctp/src/user_socket.c @@ -60,9 +60,12 @@ #endif userland_mutex_t accept_mtx; userland_cond_t accept_cond; -#ifdef _WIN32 +#if defined(_WIN32) #include #include +#if !defined(_MSC_VER) +#include +#endif #endif MALLOC_DEFINE(M_PCB, "sctp_pcb", "sctp pcb"); @@ -251,7 +254,7 @@ sofree(struct socket *so) ACCEPT_LOCK_ASSERT(); SOCK_LOCK_ASSERT(so); - /* SS_NOFDREF unset in accept call. this condition seems irrelevent + /* SS_NOFDREF unset in accept call. this condition seems irrelevant * for __Userspace__... */ if (so->so_count != 0 || @@ -296,7 +299,7 @@ sofree(struct socket *so) * necessary from sorflush(). * * Notice that the socket buffer and kqueue state are torn down - * before calling pru_detach. This means that protocols shold not + * before calling pru_detach. This means that protocols should not * assume they can perform socket wakeups, etc, in their detach code. */ sodealloc(so); @@ -308,22 +311,7 @@ sofree(struct socket *so) void soabort(struct socket *so) { -#if defined(INET6) - struct sctp_inpcb *inp; -#endif - -#if defined(INET6) - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - sctp6_abort(so); - } else { -#if defined(INET) - sctp_abort(so); -#endif - } -#elif defined(INET) sctp_abort(so); -#endif ACCEPT_LOCK(); SOCK_LOCK(so); sofree(so); @@ -1878,7 +1866,7 @@ soconnect(struct socket *so, struct sockaddr *nam) * Otherwise, if connected, try to disconnect first. This allows * user to disconnect by connecting to, e.g., a null address. */ - if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && (error = sodisconnect(so))) { + if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && (sodisconnect(so) != 0)) { error = EISCONN; } else { /* @@ -2210,7 +2198,7 @@ usrsctp_getsockopt(struct socket *so, int level, int option_name, int *buf_size; buf_size = (int *)option_value; - *buf_size = so->so_rcv.sb_hiwat;; + *buf_size = so->so_rcv.sb_hiwat; *option_len = (socklen_t)sizeof(int); return (0); } @@ -2695,22 +2683,26 @@ usrsctp_getpaddrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs) { struct sctp_getaddresses *addrs; struct sockaddr *sa; - sctp_assoc_t asoc; caddr_t lim; socklen_t opt_len; + uint32_t size_of_addresses; int cnt; if (raddrs == NULL) { errno = EFAULT; return (-1); } - asoc = id; - opt_len = (socklen_t)sizeof(sctp_assoc_t); - if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, &asoc, &opt_len) != 0) { - return (-1); + /* When calling getsockopt(), the value contains the assoc_id. */ + size_of_addresses = (uint32_t)id; + opt_len = (socklen_t)sizeof(uint32_t); + if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, &size_of_addresses, &opt_len) != 0) { + if (errno == ENOENT) { + return (0); + } else { + return (-1); + } } - /* size required is returned in 'asoc' */ - opt_len = (socklen_t)((size_t)asoc + sizeof(struct sctp_getaddresses)); + opt_len = (socklen_t)((size_t)size_of_addresses + sizeof(struct sctp_getaddresses)); addrs = calloc(1, (size_t)opt_len); if (addrs == NULL) { errno = ENOMEM; @@ -2770,10 +2762,10 @@ int usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs) { struct sctp_getaddresses *addrs; - caddr_t lim; struct sockaddr *sa; - size_t size_of_addresses; + caddr_t lim; socklen_t opt_len; + uint32_t size_of_addresses; int cnt; if (raddrs == NULL) { @@ -2781,13 +2773,8 @@ usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs) return (-1); } size_of_addresses = 0; - opt_len = (socklen_t)sizeof(int); + opt_len = (socklen_t)sizeof(uint32_t); if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, &size_of_addresses, &opt_len) != 0) { - errno = ENOMEM; - return (-1); - } - if (size_of_addresses == 0) { - errno = ENOTCONN; return (-1); } opt_len = (socklen_t)(size_of_addresses + sizeof(struct sctp_getaddresses)); @@ -2800,9 +2787,12 @@ usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs) /* Now lets get the array of addresses */ if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, &opt_len) != 0) { free(addrs); - errno = ENOMEM; return (-1); } + if (size_of_addresses == 0) { + free(addrs); + return (0); + } *raddrs = &addrs->addr[0].sa; cnt = 0; sa = &addrs->addr[0].sa; @@ -2850,14 +2840,13 @@ usrsctp_freeladdrs(struct sockaddr *addrs) #ifdef INET void sctp_userspace_ip_output(int *result, struct mbuf *o_pak, - sctp_route_t *ro, void *stcb, + sctp_route_t *ro, void *inp, uint32_t vrf_id) { struct mbuf *m; struct mbuf *m_orig; int iovcnt; int len; - int send_count; struct ip *ip; struct udphdr *udp; struct sockaddr_in dst; @@ -2930,16 +2919,13 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak, m_adj(m, sizeof(struct ip) + sizeof(struct udphdr)); } - send_count = 0; for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) { #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; #else send_iovec[iovcnt].buf = (caddr_t)m->m_data; send_iovec[iovcnt].len = SCTP_BUF_LEN(m); - send_count += send_iovec[iovcnt].len; #endif } @@ -2995,14 +2981,13 @@ free_mbuf: #if defined(INET6) void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, - struct route_in6 *ro, void *stcb, + struct route_in6 *ro, void *inp, uint32_t vrf_id) { struct mbuf *m; struct mbuf *m_orig; int iovcnt; int len; - int send_count; struct ip6_hdr *ip6; struct udphdr *udp; struct sockaddr_in6 dst; @@ -3073,19 +3058,16 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, if (use_udp_tunneling) { m_adj(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); } else { - m_adj(m, sizeof(struct ip6_hdr)); + m_adj(m, sizeof(struct ip6_hdr)); } - send_count = 0; for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) { #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; #else send_iovec[iovcnt].buf = (caddr_t)m->m_data; send_iovec[iovcnt].len = SCTP_BUF_LEN(m); - send_count += send_iovec[iovcnt].len; #endif } if (m != NULL) { @@ -3175,8 +3157,7 @@ usrsctp_deregister_address(void *addr) sconn.sconn_addr = addr; sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, (struct sockaddr *)&sconn, - 0xffffffff, - "conn"); + NULL, 0xffffffff); } #define PREAMBLE_FORMAT "\n%c %02d:%02d:%02d.%06ld " @@ -3500,6 +3481,7 @@ 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) +USRSCTP_SYSCTL_SET_DEF(sctp_ootb_with_zero_cksum, SCTPCTL_OOTB_WITH_ZERO_CKSUM) #ifdef SCTP_DEBUG USRSCTP_SYSCTL_SET_DEF(sctp_debug_on, SCTPCTL_DEBUG) #endif @@ -3582,6 +3564,7 @@ USRSCTP_SYSCTL_GET_DEF(sctp_steady_step) USRSCTP_SYSCTL_GET_DEF(sctp_use_dccc_ecn) USRSCTP_SYSCTL_GET_DEF(sctp_buffer_splitting) USRSCTP_SYSCTL_GET_DEF(sctp_initial_cwnd) +USRSCTP_SYSCTL_GET_DEF(sctp_ootb_with_zero_cksum) #ifdef SCTP_DEBUG USRSCTP_SYSCTL_GET_DEF(sctp_debug_on) #endif diff --git a/netwerk/sctp/src/user_socketvar.h b/netwerk/sctp/src/user_socketvar.h index e8eccc7fb1..04c806a88f 100644 --- a/netwerk/sctp/src/user_socketvar.h +++ b/netwerk/sctp/src/user_socketvar.h @@ -404,15 +404,25 @@ void sofree(struct socket *so); #define soref(so) do { \ SOCK_LOCK_ASSERT(so); \ ++(so)->so_count; \ + SCTPDBG(SCTP_DEBUG_USR, "soref(%p) -> %d, %s:%s:%d\n", \ + (so), (so)->so_count, \ + __func__, __FILE__, __LINE__) \ } while (0) #define sorele(so) do { \ ACCEPT_LOCK_ASSERT(); \ SOCK_LOCK_ASSERT(so); \ KASSERT((so)->so_count > 0, ("sorele")); \ - if (--(so)->so_count == 0) \ + if (--(so)->so_count == 0) { \ + SCTPDBG(SCTP_DEBUG_USR, "sorele(%p) -> %d, %s:%s:%d\n", \ + (so), (so)->so_count, \ + __func__, __FILE__, __LINE__) \ sofree(so); \ + } \ else { \ + SCTPDBG(SCTP_DEBUG_USR, "sorele(%p) -> %d, %s:%s:%d\n", \ + (so), (so)->so_count, \ + __func__, __FILE__, __LINE__) \ SOCK_UNLOCK(so); \ ACCEPT_UNLOCK(); \ } \ diff --git a/netwerk/sctp/src/usrsctp.h b/netwerk/sctp/src/usrsctp.h index b7192904e4..93e89b386c 100644 --- a/netwerk/sctp/src/usrsctp.h +++ b/netwerk/sctp/src/usrsctp.h @@ -64,19 +64,19 @@ extern "C" { #elif defined(SCTP_STDINT_INCLUDE) #include SCTP_STDINT_INCLUDE #else -#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 +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int16 int16_t; +typedef __int32 int32_t; #endif #ifndef ssize_t #ifdef _WIN64 -#define ssize_t __int64 +typedef __int64 ssize_t; #elif defined _WIN32 -#define ssize_t int +typedef int ssize_t; #else #error "Unknown platform!" #endif @@ -560,6 +560,7 @@ struct sctp_event_subscribe { #define SCTP_NRSACK_SUPPORTED 0x00000030 #define SCTP_PKTDROP_SUPPORTED 0x00000031 #define SCTP_MAX_CWND 0x00000032 +#define SCTP_ACCEPT_ZERO_CHECKSUM 0x00000033 #define SCTP_ENABLE_STREAM_RESET 0x00000900 /* struct sctp_assoc_value */ @@ -767,6 +768,10 @@ struct sctp_get_nonce_values { uint32_t gn_local_tag; }; +/* Values for SCTP_ACCEPT_ZERO_CHECKSUM */ +#define SCTP_EDMID_NONE 0 +#define SCTP_EDMID_LOWER_LAYER_DTLS 1 + /* * Main SCTP chunk types @@ -1146,6 +1151,7 @@ USRSCTP_SYSCTL_DECL(sctp_steady_step) USRSCTP_SYSCTL_DECL(sctp_use_dccc_ecn) USRSCTP_SYSCTL_DECL(sctp_buffer_splitting) USRSCTP_SYSCTL_DECL(sctp_initial_cwnd) +USRSCTP_SYSCTL_DECL(sctp_ootb_with_zero_cksum) #ifdef SCTP_DEBUG USRSCTP_SYSCTL_DECL(sctp_debug_on) /* More specific values can be found in sctp_constants, but @@ -1304,7 +1310,9 @@ struct sctpstat { uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already max burst inflight to net */ uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via fwd-tsn's */ uint32_t sctps_queue_upd_ecne; /* Number of times we queued or updated an ECN chunk on send queue */ - uint32_t sctps_reserved[31]; /* Future ABI compat - remove int's from here when adding new */ + uint32_t sctps_recvzerocrc; /* Number of accepted packets with zero CRC */ + uint32_t sctps_sendzerocrc; /* Number of packets sent with zero CRC */ + uint32_t sctps_reserved[29]; /* Future ABI compat - remove int's from here when adding new */ }; void From b265d9495dd57925eed580045146548eadbc6366 Mon Sep 17 00:00:00 2001 From: Basilisk-Dev Date: Thu, 19 Feb 2026 07:46:37 -0500 Subject: [PATCH 2/4] Issue #2925 - Incorporate FreeBSD patch from dbsoft after usrsctp upgrade --- netwerk/sctp/src/user_recv_thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/sctp/src/user_recv_thread.c b/netwerk/sctp/src/user_recv_thread.c index 75c9076c7b..497d2b6960 100644 --- a/netwerk/sctp/src/user_recv_thread.c +++ b/netwerk/sctp/src/user_recv_thread.c @@ -56,7 +56,7 @@ #endif #endif #endif -#if defined(HAVE_NET_ROUTE_H) +#if defined(HAVE_NET_ROUTE_H) || defined(__FreeBSD__) || defined(__DragonFly__) # include #elif defined(__APPLE__) /* Apple SDKs for iOS, tvOS, watchOS, etc. don't ship this header */ From c9bdbd560307d172fd620d2daa56e5d1c9f92e7d Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 20 Feb 2026 09:57:46 +0100 Subject: [PATCH 3/4] Issue #2955 - Implement form.requestSubmit(element) --- dom/bindings/Errors.msg | 1 + dom/html/HTMLFormElement.cpp | 35 +++++++++++++++++++++++++++++++ dom/html/HTMLFormElement.h | 13 ++++++++++++ dom/webidl/HTMLFormElement.webidl | 2 ++ modules/libpref/init/all.js | 3 +++ 5 files changed, 54 insertions(+) diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index db689e5bc0..a2661597b3 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -111,3 +111,4 @@ MSG_DEF(MSG_PMO_INVALID_MEMBERS, 0, JSEXN_TYPEERR, "PerformanceMeasureOptions ca MSG_DEF(MSG_PMO_CONSTRUCTOR_INACCESSIBLE, 0, JSEXN_TYPEERR, "Can't access PerformanceMark constructor, performance is null.") MSG_DEF(MSG_PMO_UNEXPECTED_START_TIME, 0, JSEXN_TYPEERR, "Expected startTime >= 0.") MSG_DEF(MSG_PMO_INVALID_ATTR_FOR_NON_GLOBAL, 1, JSEXN_TYPEERR, "Cannot get PerformanceTiming attribute values for non-Window global object. Given: {0}.") +MSG_DEF(MSG_NOT_SUBMIT_BUTTON, 0, JSEXN_TYPEERR, "The submitter is not a submit button.") diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index f44077c54e..a5f2442489 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -276,6 +276,41 @@ HTMLFormElement::Submit() return rv.StealNSResult(); } +// https://html.spec.whatwg.org/multipage/forms.html#dom-form-requestsubmit +void +HTMLFormElement::RequestSubmit(nsGenericHTMLElement* aSubmitter, + ErrorResult& aRv) { + // 1. If submitter is not null, then: + if (aSubmitter) { + nsCOMPtr fc = do_QueryObject(aSubmitter); + + // 1.1. If submitter is not a submit button, then throw a TypeError. + if (!fc || !fc->IsSubmitControl()) { + aRv.ThrowTypeError(); + return; + } + + // 1.2. If submitter's form owner is not this form element, then throw a + // "NotFoundError" DOMException. + if (fc->GetFormElement() != this) { + aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); + return; + } + } + + // 2. Otherwise, set submitter to this form element. + // 3. Submit this form element, from submitter. + // We go through the presShell here for the corner case a submit event + // is pending while the window is being destroyed. + InternalFormEvent event(true, eFormSubmit); + event.mOriginator = aSubmitter; + nsEventStatus status = nsEventStatus_eIgnore; + nsCOMPtr presShell = GetComposedDoc()->GetShell(); + if (MOZ_LIKELY(presShell)) { + presShell->HandleDOMEventWithTarget(this, &event, &status); + } +} + NS_IMETHODIMP HTMLFormElement::Reset() { diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index b0d355d5a7..e752fd5a82 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -391,6 +391,19 @@ public: void Submit(ErrorResult& aRv); + /** + * Requests to submit the form. Unlike submit(), this method includes + * interactive constraint validation and firing a submit event, + * either of which can cancel submission. + * + * @param aSubmitter The submitter argument can be used to point to a specific + * submit button. + * @param aRv An ErrorResult. + * @see + * https://html.spec.whatwg.org/multipage/forms.html#dom-form-requestsubmit + */ + void RequestSubmit(nsGenericHTMLElement* aSubmitter, ErrorResult& aRv); + // XPCOM Reset() is OK bool CheckValidity() diff --git a/dom/webidl/HTMLFormElement.webidl b/dom/webidl/HTMLFormElement.webidl index 064fe9fade..a1407a718e 100644 --- a/dom/webidl/HTMLFormElement.webidl +++ b/dom/webidl/HTMLFormElement.webidl @@ -43,6 +43,8 @@ interface HTMLFormElement : HTMLElement { [Throws] void submit(); + [Pref="dom.forms.requestsubmit.enabled", Throws] + void requestSubmit(optional HTMLElement? submitter = null); [CEReactions] void reset(); boolean checkValidity(); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 6ee2a88236..6ae7223600 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1196,6 +1196,9 @@ pref("dom.forms.autocomplete.experimental", false); // Enables requestAutocomplete DOM API on forms. pref("dom.forms.requestAutocomplete", false); +// Enables requestSubmit DOM API on forms. +pref("dom.forms.requestsubmit.enabled", true); + // Enable Directory API. By default, disabled. pref("dom.input.dirpicker", false); From 483762871c37e9cf0a2d7bbe4968a970856856bb Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sun, 22 Feb 2026 14:20:37 +0100 Subject: [PATCH 4/4] No issue - Fix cairo warnings This fixes warning spew because warnings are thrown in case of mixed use of cairo_status_t and cairo_int_status_t, which is a hack in cairo because C99 doesn't support real enums (it's mapped to uint8 internally). The "register" storage type is no longer a thing in C++17, which would also warn; just letting the compiler decide is best, so just removing the keyword is the proper solution in cairoint.h --- gfx/cairo/cairo/src/cairoint.h | 2 +- gfx/cairo/cairo/src/moz.build | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index f5dc0da817..e9d3b3ce55 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -148,7 +148,7 @@ _cairo_popcount (uint32_t mask) #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) return __builtin_popcount (mask); #else - register int y; + int y; y = (mask >> 1) &033333333333; y = mask - y - ((y >>1) & 033333333333); diff --git a/gfx/cairo/cairo/src/moz.build b/gfx/cairo/cairo/src/moz.build index d2536e10f4..e39e638836 100644 --- a/gfx/cairo/cairo/src/moz.build +++ b/gfx/cairo/cairo/src/moz.build @@ -215,9 +215,25 @@ if CONFIG['MOZ_TREE_FREETYPE']: # Suppress warnings in third-party code. if CONFIG['_MSC_VER']: CFLAGS += [ - '-wd4005', - '-wd4146', + '-wd4005', # 'WIN32_LEAN_AND_MEAN' : macro redefinition + '-wd4018', # '>' : signed/unsigned mismatch + '-wd4047', # different levels of indirection + '-wd4101', # unreferenced local variable + '-wd4133', # 'function' : incompatible types + '-wd4146', # unary minus operator applied to unsigned type + '-wd4311', # 'variable' : pointer truncation from 'type' to 'type' + '-wd4477', # format string '%s' requires an argument of type 'type' + '-wd4996', # The compiler encountered a deprecated declaration. + '-wd5286', # implicit conversion between enum types + '-wd5287', # operands are different enum types ] + CXXFLAGS += [ + '-wd4005', # 'WIN32_LEAN_AND_MEAN' : macro redefinition + '-wd4018', # '>' : signed/unsigned mismatch + '-wd4146', # unary minus operator applied to unsigned type + '-wd4828', # illegal in the current source character set + '-wd4838', # requires a narrowing conversion +] if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: CFLAGS += [ '-Wno-enum-compare',