summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-08-24 00:53:53 +0000
committerrrs <rrs@FreeBSD.org>2007-08-24 00:53:53 +0000
commit1d0af67d1affeebe2b3f9ddd01a55aa656b374cd (patch)
tree51e754ba3033b2f2132dba153d2b5d92895a7b2c
parentfcca9c0b24382feab4ce953a658a57a7c257ff4e (diff)
downloadFreeBSD-src-1d0af67d1affeebe2b3f9ddd01a55aa656b374cd.zip
FreeBSD-src-1d0af67d1affeebe2b3f9ddd01a55aa656b374cd.tar.gz
- Fix address add handling to clear cached routes and source addresses
when peer acks the add in case the routing table changes. - Fix sctp_lower_sosend to send shutdown chunk for mbuf send case when sndlen = 0 and sinfoflag = SCTP_EOF - Fix sctp_lower_sosend for SCTP_ABORT mbuf send case with null data, So that it does not send the "null" data mbuf out and cause it to get freed twice. - Fix so auto-asconf sysctl actually effect the socket's asconf state. - Do not allow SCTP_AUTO_ASCONF option to be used on subset bound sockets. - Memset bug in sctp_output.c (arguments were reversed) submitted found and reported by Dave Jones (davej@codemonkey.org.uk). - PD-API point needs to be invoked >= not just > to conform to socket api draft this fixes sctp_indata.c in the two places need to be >=. - move M_NOTIFICATION to use M_PROTO5. - PEER_ADDR_PARAMS did not fail properly if you specify an address that is not in the association with a valid assoc_id. This meant you got or set the stcb level values instead of the destination you thought you were going to get/set. Now validate if the stcb is non-null and the net is NULL that the sa_family is set and the address is unspecified otherwise return an error. - The thread based iterator could crash if associations were freed at the exact time it was running. rework the worker thread to use the increment/decrement to prevent this and no longer use the markers that the timer based iterator uses. - Fix the memleak in sctp_add_addr_to_vrf() for the case when it is detected that ifa is already pointing to a ifn. - Fix it so that if someone is so insane that they drop the send window below the minimal add mark, they still can send. - Changed all state for associations to use mask safe macro. - During front states in association freeing in sctp_inpcbfree, we had a locking problem where locks were not in place where they should have been. - Free association calls were not testing the return value in sctp_inpcb_free() properly... others should be cast void returns where we don't care about the return value. - If a reference count is held on an assoc, even from the "force free" we should not do the actual free.. but instead let the timer free it. - When we enter sctp_input(), if the SCTP_ASOC_ABOUT_TO_BE_FREED flag is set, we must NOT process the packet but handle it like ootb. This is because while freeing an assoc we release the locks to get all the higher order locks so we can purge all the hash tables. This leaves a hole if a packet comes in just at that point. Now sctp_common_input_processing() will call the ootb code in such a case. - Change MBUF M_NOTIFICATION to use M_PROTO5 (per Sam L). This makes it so we don't have a conflict (I think this is a covertity change). We made this change AFTER some conversation and looking to make sure that M_PROTO5 does not have a problem between SCTP and the 802.11 stuff (which is the only other place its used). - Fixed lock order reversal and missing atomic protection around locked_tcb during association lookup and the 1-2-1 model. - Added debug to source address selection. - V6 output must always do checksum even for loopback. - Remove more locks around inp that are not needed for an atomically added/subtracted ref count. - slight optimization in the way we zero the array in sctp_sack_check() - It was possible to respond to a ABORT() with bad checksum with a PKT-DROP. This lead to a PKT-DROP/ABORT war. Add code to NOT send a PKT-DROP to any ABORT(). - Add an option for local logging (useful for macintosh or when you need better performing during debugging). Note no commands are here to get the log info, you must just use kgdb. - The timer code needs to be aware of if it needs to call sctp_sack_check() to slide the maps and adjust the cum-ack. This is because it may be out of sync cum-ack wise. - Added threshold managment logging. - If the user picked just the right size, that just filled the send window minus one mtu, we would enter a forever loop not copying and at the same time not blocking. Change from < to <= solves this. - Sysctl added to control the fragment interleave level which defaults to 1. - My rwnd control was not being used to control the rwnd properly (we did not add and subtract to it :-() this is now fixed so we handle small messages (1 byte etc) better to bring our rwnd down more slowly. Approved by: re@freebsd.org (Bruce Mah)
-rw-r--r--sys/netinet/sctp.h2
-rw-r--r--sys/netinet/sctp_asconf.c14
-rw-r--r--sys/netinet/sctp_auth.c2
-rw-r--r--sys/netinet/sctp_constants.h13
-rw-r--r--sys/netinet/sctp_header.h1
-rw-r--r--sys/netinet/sctp_indata.c58
-rw-r--r--sys/netinet/sctp_input.c167
-rw-r--r--sys/netinet/sctp_os.h1
-rw-r--r--sys/netinet/sctp_os_bsd.h21
-rw-r--r--sys/netinet/sctp_output.c263
-rw-r--r--sys/netinet/sctp_pcb.c119
-rw-r--r--sys/netinet/sctp_pcb.h1
-rw-r--r--sys/netinet/sctp_peeloff.c16
-rw-r--r--sys/netinet/sctp_structs.h6
-rw-r--r--sys/netinet/sctp_sysctl.c8
-rw-r--r--sys/netinet/sctp_sysctl.h18
-rw-r--r--sys/netinet/sctp_timer.c16
-rw-r--r--sys/netinet/sctp_usrreq.c271
-rw-r--r--sys/netinet/sctp_var.h13
-rw-r--r--sys/netinet/sctputil.c164
-rw-r--r--sys/netinet/sctputil.h5
-rw-r--r--sys/netinet6/sctp6_usrreq.c67
-rw-r--r--sys/sys/mbuf.h2
23 files changed, 979 insertions, 269 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index 659ef4e..bd060d0 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -534,5 +534,7 @@ __attribute__((packed));
#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000
#define SCTP_LTRACE_ERROR_ENABLE 0x00800000
#define SCTP_LAST_PACKET_TRACING 0x01000000
+#define SCTP_THRESHOLD_LOGGING 0x02000000
+
#endif /* !_NETINET_SCTP_H_ */
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index b66e1b2..d7a8db2 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1140,6 +1140,13 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
net->error_count = 0;
}
stcb->asoc.overall_error_count = 0;
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_ASCONF,
+ __LINE__);
+ }
/* queue in an advisory set primary too */
(void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
/* let caller know we should send this out immediately */
@@ -2002,7 +2009,7 @@ sctp_asconf_iterator_end(void *ptr, uint32_t val)
* sa is the sockaddr to ask the peer to set primary to.
* returns: 0 = completed, -1 = error
*/
-int
+int32_t
sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
{
/* NOTE: we currently don't check the validity of the address! */
@@ -2691,6 +2698,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
struct sctp_ifa *ifa;
if (sa->sa_len == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
return (EINVAL);
}
if (sctp_ifap) {
@@ -2713,12 +2721,14 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
sizeof(struct sctp_asconf_iterator),
SCTP_M_ASC_IT);
if (asc == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
return (ENOMEM);
}
wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr,
struct sctp_laddr);
if (wi == NULL) {
SCTP_FREE(asc, SCTP_M_ASC_IT);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
return (ENOMEM);
}
if (type == SCTP_ADD_IP_ADDRESS) {
@@ -2730,6 +2740,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
/* can't delete the last local address */
SCTP_FREE(asc, SCTP_M_ASC_IT);
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, wi);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
return (EINVAL);
}
LIST_FOREACH(laddr, &inp->sctp_addr_list,
@@ -2757,6 +2768,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
sctp_asconf_iterator_end, inp, 0);
} else {
/* invalid address! */
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL);
return (EADDRNOTAVAIL);
}
return (0);
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index e5bf051..2e7d457 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -780,7 +780,7 @@ sctp_alloc_authinfo(void)
/* out of memory */
return (NULL);
}
- bzero(&new_authinfo, sizeof(*new_authinfo));
+ bzero(new_authinfo, sizeof(*new_authinfo));
return (new_authinfo);
}
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index cf852a4..f6bdf34 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -209,8 +209,11 @@ __FBSDID("$FreeBSD$");
#define SCTP_FLIGHT_LOG_DOWN_PMTU 115
#define SCTP_SACK_LOG_NORMAL 116
#define SCTP_SACK_LOG_EXPRESS 117
+#define SCTP_MAP_TSN_ENTERS 118
+#define SCTP_THRESHOLD_CLEAR 119
+#define SCTP_THRESHOLD_INCR 120
-#define SCTP_LOG_MAX_TYPES 118
+#define SCTP_LOG_MAX_TYPES 121
/*
* To turn on various logging, you must first enable 'options KTR' and
* you might want to bump the entires 'options KTR_ENTRIES=80000'.
@@ -220,6 +223,12 @@ __FBSDID("$FreeBSD$");
* This gets the compile in place, but you still need to turn the
* logging flag on too in the sysctl (see in sctp.h).
*/
+
+/* For SCTP only logging */
+#define SCTP_MAX_LOGGING_SIZE 30000
+#define SCTP_TRACE_PARAMS 6
+
+
#define SCTP_LOG_EVENT_UNKNOWN 0
#define SCTP_LOG_EVENT_CWND 1
#define SCTP_LOG_EVENT_BLOCK 2
@@ -480,6 +489,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_STATE_MASK 0x007f
#define SCTP_GET_STATE(asoc) ((asoc)->state & SCTP_STATE_MASK)
+#define SCTP_SET_STATE(asoc, newstate) ((asoc)->state = ((asoc)->state & ~SCTP_STATE_MASK) | newstate)
/* SCTP reachability state for each address */
#define SCTP_ADDR_REACHABLE 0x001
@@ -831,6 +841,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_FROM_SCTP_OUTPUT 0x90000000
#define SCTP_FROM_SCTP_PEELOFF 0xa0000000
#define SCTP_FROM_SCTP_PANDA 0xb0000000
+#define SCTP_FROM_SCTP_SYSCTL 0xc0000000
/* Location ID's */
#define SCTP_LOC_1 0x00000001
diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h
index 121c796..090e96d 100644
--- a/sys/netinet/sctp_header.h
+++ b/sys/netinet/sctp_header.h
@@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#ifndef __sctp_header_h__
#define __sctp_header_h__
-
#include <sys/time.h>
#include <netinet/sctp.h>
#include <netinet/sctp_constants.h>
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 30aa980..aa85a6f 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -775,7 +775,7 @@ doit_again:
* but should we?
*/
if ((sctp_is_all_msg_on_reasm(asoc, &tsize) ||
- (tsize > stcb->sctp_ep->partial_delivery_point))) {
+ (tsize >= stcb->sctp_ep->partial_delivery_point))) {
/*
* Yes, we setup to start reception, by
@@ -1452,7 +1452,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
protocol_id = ch->dp.protocol_id;
ordered = ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0);
if (sctp_logging_level & SCTP_MAP_LOGGING_ENABLE) {
- sctp_log_map(0, tsn, asoc->cumulative_tsn, SCTP_MAP_PREPARE_SLIDE);
+ sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
}
if (stcb == NULL) {
return (0);
@@ -2209,7 +2209,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
*/
struct sctp_association *asoc;
int i, at;
- int all_ones, last_all_ones = 0;
+ int last_all_ones = 0;
int slide_from, slide_end, lgap, distance;
uint32_t old_cumack, old_base, old_highest;
unsigned char aux_array[64];
@@ -2231,7 +2231,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
* We could probably improve this a small bit by calculating the
* offset of the current cum-ack as the starting point.
*/
- all_ones = 1;
at = 0;
for (i = 0; i < stcb->asoc.mapping_array_size; i++) {
@@ -2240,7 +2239,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
last_all_ones = 1;
} else {
/* there is a 0 bit */
- all_ones = 0;
at += sctp_map_lookup_tab[asoc->mapping_array[i]];
last_all_ones = 0;
break;
@@ -2260,24 +2258,16 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
#endif
}
- if (all_ones ||
- (asoc->cumulative_tsn == asoc->highest_tsn_inside_map && at >= 8)) {
+ if ((asoc->cumulative_tsn == asoc->highest_tsn_inside_map) && (at >= 8)) {
/* The complete array was completed by a single FR */
/* higest becomes the cum-ack */
int clr;
asoc->cumulative_tsn = asoc->highest_tsn_inside_map;
/* clear the array */
- if (all_ones)
+ clr = (at >> 3) + 1;
+ if (clr > asoc->mapping_array_size) {
clr = asoc->mapping_array_size;
- else {
- clr = (at >> 3) + 1;
- /*
- * this should be the allones case but just in case
- * :>
- */
- if (clr > asoc->mapping_array_size)
- clr = asoc->mapping_array_size;
}
memset(asoc->mapping_array, 0, clr);
/* base becomes one ahead of the cum-ack */
@@ -2467,7 +2457,7 @@ doit_again:
* delivery queue and something can be delivered.
*/
if ((sctp_is_all_msg_on_reasm(asoc, &tsize) ||
- (tsize > stcb->sctp_ep->partial_delivery_point))) {
+ (tsize >= stcb->sctp_ep->partial_delivery_point))) {
asoc->fragmented_delivery_inprogress = 1;
asoc->tsn_last_delivered = chk->rec.data.TSN_seq - 1;
asoc->str_of_pdapi = chk->rec.data.stream_number;
@@ -2722,10 +2712,17 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
}
if (num_chunks) {
/*
- * Did we get data, if so update the time for auto-close and
+ * Did we get data, if sa update the time for auto-close and
* give peer credit for being alive.
*/
SCTP_STAT_INCR(sctps_recvpktwithdata);
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INDATA,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd);
}
@@ -3866,6 +3863,13 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
}
}
asoc->this_sack_highest_gap = cumack;
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INDATA,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) {
/* process the new consecutive TSN first */
@@ -4187,7 +4191,7 @@ again:
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
@@ -4202,7 +4206,7 @@ again:
goto abort_out_now;
}
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
@@ -4296,6 +4300,13 @@ sctp_handle_sack(struct mbuf *m, int offset,
num_dup = ntohs(sack->num_dup_tsns);
old_rwnd = stcb->asoc.peers_rwnd;
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INDATA,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
asoc = &stcb->asoc;
if (sctp_logging_level & SCTP_SACK_LOGGING_ENABLE) {
@@ -4847,7 +4858,7 @@ done_with_it:
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
@@ -4863,7 +4874,7 @@ done_with_it:
goto abort_out_now;
}
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
@@ -5254,6 +5265,9 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
if (gap > m_size) {
asoc->highest_tsn_inside_map = back_out_htsn;
+ if (sctp_logging_level & SCTP_MAP_LOGGING_ENABLE) {
+ sctp_log_map(0, 0, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
+ }
if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
struct mbuf *oper;
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 46c23cd..32adf9b 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -425,6 +425,13 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
op_err = NULL;
}
/* extract the cookie and queue it to "echo" it back... */
+ if (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;
net->error_count = 0;
@@ -603,7 +610,8 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
- sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_6);
+ (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_6);
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n");
}
@@ -645,7 +653,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) {
- asoc->state = SCTP_STATE_SHUTDOWN_RECEIVED;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_RECEIVED);
/*
* notify upper layer that peer has initiated a
* shutdown
@@ -680,7 +688,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
/* start SHUTDOWN timer */
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep,
@@ -739,7 +747,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
}
SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB but first save off the ep */
- sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
+ (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_10);
}
@@ -866,7 +874,8 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
asoc->max_init_times) {
sctp_abort_notification(stcb, 0);
/* now free the asoc */
- sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_11);
+ (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_11);
return (-1);
}
/* blast back to INIT state */
@@ -941,7 +950,6 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id)
{
struct sctp_init_ack *init_ack;
- int *state;
struct mbuf *op_err;
SCTPDBG(SCTP_DEBUG_INPUT2,
@@ -995,8 +1003,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
return (-1);
}
/* process according to association state... */
- state = &stcb->asoc.state;
- switch (*state & SCTP_STATE_MASK) {
+ switch (stcb->asoc.state & SCTP_STATE_MASK) {
case SCTP_STATE_COOKIE_WAIT:
/* this is the expected state for this chunk */
/* process the INIT-ACK parameters */
@@ -1020,14 +1027,16 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
}
/* update our state */
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to COOKIE-ECHOED state\n");
- if (*state & SCTP_STATE_SHUTDOWN_PENDING) {
- *state = SCTP_STATE_COOKIE_ECHOED |
- SCTP_STATE_SHUTDOWN_PENDING;
- } else {
- *state = SCTP_STATE_COOKIE_ECHOED;
- }
+ SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_ECHOED);
/* reset the RTO calc */
+ if (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;
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
/*
@@ -1195,14 +1204,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
else
SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
+
+ SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
-
- } else {
- /* if ok, move to OPEN state */
- asoc->state = SCTP_STATE_OPEN;
}
SCTP_STAT_INCR_GAUGE32(sctps_currestab);
sctp_stop_all_cookie_timers(stcb);
@@ -1381,13 +1387,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
} else {
SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
}
+ SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
- } else {
- asoc->state = SCTP_STATE_OPEN;
}
sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, asoc);
@@ -1438,14 +1442,13 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_STAT_INCR_GAUGE32(sctps_collisionestab);
}
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN |
- SCTP_STATE_SHUTDOWN_PENDING;
+ SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
} else if (!(asoc->state & SCTP_STATE_SHUTDOWN_SENT)) {
/* move to OPEN state, if not in SHUTDOWN_SENT */
- asoc->state = SCTP_STATE_OPEN;
+ SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
}
asoc->pre_open_streams =
ntohs(initack_cp->init.num_outbound_streams);
@@ -1667,7 +1670,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
sh, op_err, vrf_id);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
atomic_add_int(&stcb->asoc.refcnt, -1);
return (NULL);
@@ -1692,7 +1695,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
retval = 0;
if (retval < 0) {
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
atomic_add_int(&stcb->asoc.refcnt, -1);
return (NULL);
}
@@ -1701,7 +1704,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
init_offset + sizeof(struct sctp_init_chunk), initack_offset, sh,
init_src)) {
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17);
atomic_add_int(&stcb->asoc.refcnt, -1);
return (NULL);
}
@@ -1722,7 +1725,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
SCTPDBG(SCTP_DEBUG_AUTH1,
"COOKIE-ECHO: AUTH failed\n");
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18);
atomic_add_int(&stcb->asoc.refcnt, -1);
return (NULL);
} else {
@@ -1732,12 +1735,10 @@ 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(asoc, SCTP_STATE_OPEN);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
- } else {
- asoc->state = SCTP_STATE_OPEN;
}
sctp_stop_all_cookie_timers(stcb);
SCTP_STAT_INCR_COUNTER32(sctps_passiveestab);
@@ -1772,7 +1773,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
sizeof(sin6->sin6_addr));
} else {
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
atomic_add_int(&stcb->asoc.refcnt, -1);
return (NULL);
}
@@ -2201,7 +2202,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(*inp_p, NULL, m, iphlen,
sh, op_err, vrf_id);
- sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
+ (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
return (NULL);
}
inp = (struct sctp_inpcb *)so->so_pcb;
@@ -2304,13 +2305,11 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp,
if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) {
/* state change only needed when I am in right state */
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
+ SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
- } else {
- asoc->state = SCTP_STATE_OPEN;
}
/* update RTO */
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
@@ -2500,7 +2499,7 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp,
sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_22);
SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB */
- sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23);
+ (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23);
return;
}
@@ -3657,6 +3656,13 @@ __attribute__((noinline))
(ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) &&
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
/* implied cookie-ack.. we must have lost the ack */
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb,
*netp);
@@ -3826,7 +3832,7 @@ process_control_chunks:
}
*offset = length;
if (stcb) {
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27);
}
return (NULL);
}
@@ -3927,6 +3933,13 @@ process_control_chunks:
chk_length, *netp);
/* He's alive so give him credit */
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
}
break;
@@ -3941,6 +3954,13 @@ process_control_chunks:
return (NULL);
}
/* He's alive so give him credit */
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
SCTP_STAT_INCR(sctps_recvheartbeatack);
if (netp && *netp)
@@ -4130,13 +4150,20 @@ process_control_chunks:
if ((stcb) && (stcb->asoc.total_output_queue_size)) {
;
} else if (stcb) {
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27);
*offset = length;
return (NULL);
}
}
/* He's alive so give him credit */
if ((stcb) && netp && *netp) {
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, *netp);
}
@@ -4153,6 +4180,13 @@ process_control_chunks:
return (NULL);
}
if (stcb) {
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch,
stcb);
@@ -4170,6 +4204,13 @@ process_control_chunks:
return (NULL);
}
if (stcb) {
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb);
}
@@ -4196,6 +4237,13 @@ process_control_chunks:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n");
/* He's alive so give him credit */
if (stcb) {
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_asconf(m, *offset,
(struct sctp_asconf_chunk *)ch, stcb);
@@ -4213,6 +4261,13 @@ process_control_chunks:
}
if ((stcb) && netp && *netp) {
/* He's alive so give him credit */
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_asconf_ack(m, *offset,
(struct sctp_asconf_ack_chunk *)ch, stcb, *netp);
@@ -4233,10 +4288,17 @@ process_control_chunks:
int abort_flag = 0;
stcb->asoc.overall_error_count = 0;
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
*fwd_tsn_seen = 1;
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29);
*offset = length;
return (NULL);
}
@@ -4246,6 +4308,13 @@ process_control_chunks:
*offset = length;
return (NULL);
} else {
+ if (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;
}
@@ -4263,7 +4332,7 @@ process_control_chunks:
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_30);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_30);
*offset = length;
return (NULL);
}
@@ -4510,7 +4579,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
/* always clear this before beginning a packet */
stcb->asoc.authenticated = 0;
stcb->asoc.seen_a_sack_this_pkt = 0;
- if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) {
+ if ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) ||
+ (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) {
/*-
* If we hit here, we had a ref count
* up when the assoc was aborted and the
@@ -4610,6 +4680,13 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
* shows us the cookie-ack was lost. Imply it was
* there.
*/
+ if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) {
+ sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, net);
break;
@@ -4928,9 +5005,7 @@ sctp_skip_csum_4:
}
if ((inp) && (refcount_up)) {
/* reduce ref-count */
- SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
}
return;
bad:
@@ -4939,9 +5014,7 @@ bad:
}
if ((inp) && (refcount_up)) {
/* reduce ref-count */
- SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
}
if (m) {
sctp_m_freem(m);
diff --git a/sys/netinet/sctp_os.h b/sys/netinet/sctp_os.h
index 1e38cdf..fb7c536 100644
--- a/sys/netinet/sctp_os.h
+++ b/sys/netinet/sctp_os.h
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
+
/* All os's must implement this address gatherer. If
* no VRF's exist, then vrf 0 is the only one and all
* addresses and ifn's live here.
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index a6cdbf6..9a1dc43 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -121,6 +121,16 @@ MALLOC_DECLARE(SCTP_M_MVRF);
MALLOC_DECLARE(SCTP_M_ITER);
MALLOC_DECLARE(SCTP_M_SOCKOPT);
+#if defined(SCTP_LOCAL_TRACE_BUF)
+
+#define SCTP_GET_CYCLECOUNT get_cyclecount()
+#define SCTP_CTR6 sctp_log_trace
+
+#else
+#define SCTP_CTR6 CTR6
+#endif
+
+
/*
*
*/
@@ -166,11 +176,18 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT);
#endif
#ifdef SCTP_LTRACE_ERRORS
-#define SCTP_LTRACE_ERR(a, b, c, d) if(sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) CTR6(KTR_SUBSYS, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_ERROR_RET, 0, a, b, c, d)
+#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err) if(sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) \
+ printf("mbuf:%p inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \
+ m, inp, stcb, net, file, __LINE__, err);
+#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err) if(sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) \
+ printf("inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \
+ inp, stcb, net, file, __LINE__, err);
#else
-#define SCTP_LTRACE_ERR(a, b, c, d)
+#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err)
+#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err)
#endif
+
/*
* Local address and interface list handling
*/
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 9e4f0f0..85824fd 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -2712,12 +2712,15 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
-
emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index);
if (sctp_ifn == NULL) {
/* ?? We don't have this guy ?? */
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "No ifn emit interface?\n");
goto bound_all_plan_b;
}
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifn_index:%d name:%s is emit interface\n",
+ ifn_index, sctp_ifn->ifn_name);
+
if (net) {
cur_addr_num = net->indx_of_eligible_next_to_use;
}
@@ -2726,8 +2729,8 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
non_asoc_addr_ok,
dest_is_loop,
dest_is_priv, fam);
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses\n",
- num_preferred);
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses for intf:%s\n",
+ num_preferred, sctp_ifn->ifn_name);
if (num_preferred == 0) {
/*
* no eligible addresses, we must use some other interface
@@ -2768,13 +2771,18 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
bound_all_plan_b:
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan B\n");
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "Examine interface %s\n",
+ sctp_ifn->ifn_name);
if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
/* wrong base scope */
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "skip\n");
continue;
}
- if ((sctp_ifn == looked_at) && looked_at)
+ if ((sctp_ifn == looked_at) && looked_at) {
/* already looked at this guy */
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "already seen\n");
continue;
+ }
num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, stcb, non_asoc_addr_ok,
dest_is_loop, dest_is_priv, fam);
SCTPDBG(SCTP_DEBUG_OUTPUT2,
@@ -2782,6 +2790,7 @@ bound_all_plan_b:
ifn, num_preferred);
if (num_preferred == 0) {
/* None on this interface. */
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefered -- skipping to next\n");
continue;
}
SCTPDBG(SCTP_DEBUG_OUTPUT2,
@@ -3259,6 +3268,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_route_t *ro = NULL;
if ((net) && (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
sctp_m_freem(m);
return (EFAULT);
}
@@ -3276,6 +3286,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctphdr = mtod(m, struct sctphdr *);
if (sctp_no_csum_on_loopback &&
(stcb) &&
+ (to->sa_family == AF_INET) &&
(stcb->asoc.loopback_scope)) {
sctphdr->checksum = 0;
/*
@@ -3298,7 +3309,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
newm = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA);
if (newm == NULL) {
sctp_m_freem(m);
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
SCTP_ALIGN_TO_END(newm, sizeof(struct ip));
@@ -3474,6 +3485,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
}
}
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH);
sctp_m_freem(m);
return (EHOSTUNREACH);
}
@@ -3489,8 +3501,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
/* failed to prepend data, give up */
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
sctp_m_freem(m);
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
return (ENOMEM);
}
#ifdef SCTP_PACKET_LOGGING
@@ -3565,7 +3577,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA);
if (newm == NULL) {
sctp_m_freem(m);
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr));
@@ -3588,8 +3600,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sin6 = &tmp;
/* KAME hack: embed scopeid */
- if (sa6_embedscope(sin6, ip6_use_defzone) != 0)
+ if (sa6_embedscope(sin6, ip6_use_defzone) != 0) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
+ }
if (net == NULL) {
memset(&ip6route, 0, sizeof(ip6route));
ro = (sctp_route_t *) & ip6route;
@@ -3681,6 +3695,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
lsa6_storage.sin6_family = AF_INET6;
lsa6_storage.sin6_len = sizeof(lsa6_storage);
if ((error = sa6_recoverscope(&lsa6_storage)) != 0) {
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "recover scope fails error %d\n", error);
sctp_m_freem(m);
return (error);
}
@@ -3717,7 +3732,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
/* failed to prepend data, give up */
sctp_m_freem(m);
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
#ifdef SCTP_PACKET_LOGGING
@@ -3790,6 +3805,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Unknown protocol (TSNH) type %d\n",
((struct sockaddr *)to)->sa_family);
sctp_m_freem(m);
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
return (EFAULT);
}
}
@@ -3841,6 +3857,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
}
if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
/* This case should not happen */
+ SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - failed timer?\n");
return;
}
/* start the INIT timer */
@@ -3849,6 +3866,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
m = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_DONTWAIT, 1, MT_DATA);
if (m == NULL) {
/* No memory, INIT timer will re-attempt. */
+ SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n");
return;
}
SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg);
@@ -4059,9 +4077,11 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
}
p_len += padval;
}
+ SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n");
ret = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
m, 0, NULL, 0, 0, NULL, 0);
+ SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
(void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
@@ -5382,11 +5402,13 @@ sctp_msg_append(struct sctp_tcb *stcb,
holds_lock = hold_stcb_lock;
if (srcv->sinfo_stream >= stcb->asoc.streamoutcnt) {
/* Invalid stream number */
+ SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_now;
}
if ((stcb->asoc.stream_locked) &&
(stcb->asoc.stream_locked_on != srcv->sinfo_stream)) {
+ SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN);
error = EAGAIN;
goto out_now;
}
@@ -5397,12 +5419,13 @@ sctp_msg_append(struct sctp_tcb *stcb,
(SCTP_GET_STATE(&stcb->asoc) == 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;
goto out_now;
}
sctp_alloc_a_strmoq(stcb, sp);
if (sp == NULL) {
- SCTP_LTRACE_ERR(stcb->sctp_ep, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
error = ENOMEM;
goto out_now;
}
@@ -5720,7 +5743,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
asoc->primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
@@ -5882,7 +5905,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
SCTP_M_COPYAL);
if (ca == NULL) {
sctp_m_freem(m);
- SCTP_LTRACE_ERR(inp, NULL, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
memset(ca, 0, sizeof(struct sctp_copy_all));
@@ -5900,7 +5923,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
ca->m = sctp_copy_out_all(uio, ca->sndlen);
if (ca->m == NULL) {
SCTP_FREE(ca, SCTP_M_COPYAL);
- SCTP_LTRACE_ERR(inp, NULL, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
} else {
@@ -5923,6 +5946,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
if (ret) {
SCTP_PRINTF("Failed to initiate iterator for sendall\n");
SCTP_FREE(ca, SCTP_M_COPYAL);
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
return (EFAULT);
}
return (0);
@@ -6136,6 +6160,14 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
return (goal_mtu);
}
}
+ /*-
+ * For those strange folk that make the send buffer
+ * smaller than our fragmentation point, we can't
+ * get a full msg in so we have to allow splitting.
+ */
+ if (SCTP_SB_LIMIT_SND(stcb->sctp_socket) < frag_point) {
+ return (sp->length);
+ }
if ((sp->length <= goal_mtu) ||
((sp->length - goal_mtu) < sctp_min_residual)) {
/* Sub-optimial residual don't split in non-eeor mode. */
@@ -6341,7 +6373,7 @@ out_gu:
rcv_flags |= SCTP_DATA_UNORDERED;
}
/* clear out the chunk before setting up */
- memset(chk, sizeof(*chk), 0);
+ memset(chk, 0, sizeof(*chk));
chk->rec.data.rcv_flags = rcv_flags;
if (SCTP_BUF_IS_EXTENDED(sp->data)) {
chk->copy_by_ref = 1;
@@ -7098,7 +7130,7 @@ again_one_more_time:
chk->send_size, chk->copy_by_ref);
if (outchain == NULL) {
*reason_code = 8;
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
@@ -7195,6 +7227,7 @@ again_one_more_time:
SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT);
if (outchain == NULL) {
/* no memory */
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
error = ENOBUFS;
goto error_out_again;
}
@@ -7361,7 +7394,7 @@ again_one_more_time:
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
*reason_code = 3;
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
/* upate our MTU size */
@@ -7467,6 +7500,7 @@ again_one_more_time:
SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT);
if (outchain == NULL) {
/* out of mbufs */
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
error = ENOBUFS;
goto errored_send;
}
@@ -8066,7 +8100,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
struct mbuf *m, *endofchain;
struct sctphdr *shdr;
int asconf;
- struct sctp_nets *net;
+ struct sctp_nets *net = NULL;
uint32_t tsns_sent = 0;
int no_fragmentflg, bundle_at, cnt_thru;
unsigned int mtu;
@@ -8147,6 +8181,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT);
if (m == NULL) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
return (ENOBUFS);
}
shdr = mtod(m, struct sctphdr *);
@@ -8207,8 +8242,10 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
SCTP_PRINTF("Gak, chk->snd_count:%d >= max:%d - send abort\n",
chk->snd_count,
sctp_max_retran_chunk);
- sctp_send_abort_tcb(stcb, NULL);
- sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, 0, NULL);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (SCTP_RETRAN_EXIT);
}
/* pick up the net */
@@ -8292,7 +8329,7 @@ one_chunk_around:
}
m = sctp_copy_mbufchain(chk->data, m, &endofchain, 0, chk->send_size, chk->copy_by_ref);
if (m == NULL) {
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
/* Do clear IP_DF ? */
@@ -8344,7 +8381,7 @@ one_chunk_around:
}
m = sctp_copy_mbufchain(fwd->data, m, &endofchain, 0, fwd->send_size, fwd->copy_by_ref);
if (m == NULL) {
- SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
/* Do clear IP_DF ? */
@@ -8383,6 +8420,7 @@ one_chunk_around:
}
SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT);
if (m == NULL) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
return (ENOBUFS);
}
shdr = mtod(m, struct sctphdr *);
@@ -8831,9 +8869,11 @@ sctp_output(inp, m, addr, control, p, flags)
int flags;
{
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
if (inp->sctp_socket == NULL) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
return (sctp_sosend(inp->sctp_socket,
@@ -9240,8 +9280,15 @@ sctp_send_sack(struct sctp_tcb *stcb)
offset += 8;
}
if (num_gap_blocks == 0) {
- /* reneged all chunks */
- asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
+ /*
+ * slide not yet happened, and somehow we got called
+ * to send a sack. Cumack needs to move up.
+ */
+ int abort_flag = 0;
+
+ asoc->cumulative_tsn = asoc->highest_tsn_inside_map;
+ sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
+ sctp_sack_check(stcb, 0, 0, &abort_flag);
}
}
/* now we must add any dups we are going to report. */
@@ -9333,6 +9380,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
abort->ch.chunk_flags = 0;
abort->ch.chunk_length = htons(sizeof(*abort) + sz);
+
/* prepend and fill in the SCTP header */
SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT);
if (m_out == NULL) {
@@ -9811,6 +9859,9 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
struct ip *iph;
int fullsz = 0, extra = 0;
long spc;
+ int offset;
+ struct sctp_chunkhdr *ch, chunk_buf;
+ unsigned int chk_length;
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -9843,6 +9894,28 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
ip6h = mtod(m, struct ip6_hdr *);
len = chk->send_size = htons(ip6h->ip6_plen);
}
+ /* Validate that we do not have an ABORT in here. */
+ offset = iphlen + sizeof(struct sctphdr);
+ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
+ sizeof(*ch), (uint8_t *) & chunk_buf);
+ while (ch != NULL) {
+ chk_length = ntohs(ch->chunk_length);
+ if (chk_length < sizeof(*ch)) {
+ /* break to abort land */
+ break;
+ }
+ switch (ch->chunk_type) {
+ case SCTP_ABORT_ASSOCIATION:
+ /* we don't respond with an PKT-DROP to an ABORT */
+ return;
+ default:
+ break;
+ }
+ offset += SCTP_SIZE32(chk_length);
+ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
+ sizeof(*ch), (uint8_t *) & chunk_buf);
+ }
+
if ((len + SCTP_MAX_OVERHEAD + sizeof(struct sctp_pktdrop_chunk)) >
min(stcb->asoc.smallest_mtu, MCLBYTES)) {
/*
@@ -10181,19 +10254,22 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
/*-
* Already one pending, must get ACK back to clear the flag.
*/
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY);
return (EBUSY);
}
if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0)) {
/* nothing to do */
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
if (send_tsn_req && (send_out_req || send_in_req)) {
/* error, can't do that */
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
- SCTP_LTRACE_ERR(stcb->sctp_ep, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
chk->copy_by_ref = 0;
@@ -10207,7 +10283,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk);
- SCTP_LTRACE_ERR(stcb->sctp_ep, stcb, ENOMEM, 0);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
@@ -10586,9 +10662,10 @@ sctp_copy_resume(struct sctp_stream_queue_pending *sp,
m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0,
(M_PKTHDR | (user_marks_eor ? M_EOR : 0)));
- if (m == NULL)
+ if (m == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
*error = ENOMEM;
- else {
+ } else {
*sndout = m_length(m, NULL);
*new_tail = m_last(m);
}
@@ -10605,9 +10682,10 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
left = sp->length;
sp->data = m_uiotombuf(uio, M_WAITOK, sp->length,
resv_upfront, 0);
- if (sp->data == NULL)
+ if (sp->data == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
-
+ }
sp->tail_mbuf = m_last(sp->data);
return (0);
}
@@ -10640,6 +10718,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
if (((user_marks_eor == 0) && non_blocking) &&
(uio->uio_resid > (int)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) {
/* It will NEVER fit */
+ SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE);
*error = EMSGSIZE;
goto out_now;
}
@@ -10649,11 +10728,13 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
(SCTP_GET_STATE(asoc) == 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);
*error = ENOMEM;
goto out_now;
}
@@ -10707,8 +10788,7 @@ sctp_sosend(struct socket *so,
struct uio *uio,
struct mbuf *top,
struct mbuf *control,
- int flags
- ,
+ int flags,
struct thread *p
)
{
@@ -10781,30 +10861,41 @@ sctp_lower_sosend(struct socket *so,
asoc = NULL;
t_inp = inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
error = EFAULT;
goto out_unlocked;
}
if ((uio == NULL) && (i_pak == NULL)) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
atomic_add_int(&inp->total_sends, 1);
- if (uio)
+ if (uio) {
+ if (uio->uio_resid < 0) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ return (EINVAL);
+ }
sndlen = uio->uio_resid;
- else {
- sndlen = SCTP_HEADER_LEN(i_pak);
+ } else {
top = SCTP_HEADER_TO_CHAIN(i_pak);
+ sndlen = SCTP_HEADER_LEN(i_pak);
}
- /*
- * Pre-screen address, if one is given the sin-len must be set
- * correctly!
+ SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n",
+ addr,
+ sndlen);
+ /*-
+ * Pre-screen address, if one is given the sin-len
+ * must be set correctly!
*/
if (addr) {
if ((addr->sa_family == AF_INET) &&
(addr->sa_len != sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
} else if ((addr->sa_family == AF_INET6) &&
(addr->sa_len != sizeof(struct sockaddr_in6))) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
}
@@ -10814,12 +10905,14 @@ sctp_lower_sosend(struct socket *so,
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(inp->sctp_socket->so_qlimit)) {
/* The listener can NOT send */
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
error = EFAULT;
goto out_unlocked;
}
if ((use_rcvinfo) && srcv) {
if (INVALID_SINFO_FLAG(srcv->sinfo_flags) ||
PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
}
@@ -10840,6 +10933,7 @@ sctp_lower_sosend(struct socket *so,
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
error = ENOTCONN;
goto out_unlocked;
}
@@ -10886,6 +10980,7 @@ sctp_lower_sosend(struct socket *so,
}
}
if (net == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
}
@@ -10905,6 +11000,7 @@ sctp_lower_sosend(struct socket *so,
struct sockaddr_in *sin;
if (addr == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
}
@@ -10942,12 +11038,14 @@ sctp_lower_sosend(struct socket *so,
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, EFAULT);
error = EFAULT;
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;
}
@@ -10964,6 +11062,7 @@ sctp_lower_sosend(struct socket *so,
hold_tcblock = 1;
}
if (t_inp != inp) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
error = ENOTCONN;
goto out_unlocked;
}
@@ -10971,9 +11070,11 @@ sctp_lower_sosend(struct socket *so,
if (stcb == NULL) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
error = ENOTCONN;
goto out_unlocked;
} else if (addr == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT);
error = ENOENT;
goto out_unlocked;
} else {
@@ -10992,6 +11093,7 @@ sctp_lower_sosend(struct socket *so,
* User asks to abort a non-existant assoc,
* or EOF a non-existant assoc with no data
*/
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT);
error = ENOENT;
goto out_unlocked;
}
@@ -11016,7 +11118,7 @@ sctp_lower_sosend(struct socket *so,
*/
queue_only = 1;
asoc = &stcb->asoc;
- asoc->state = SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT);
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
/* initialize authentication params for the assoc */
@@ -11134,6 +11236,7 @@ sctp_lower_sosend(struct socket *so,
(sndlen + stcb->asoc.total_output_queue_size)) ||
(stcb->asoc.chunks_on_out_queue >
sctp_max_chunks_on_queue)) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK);
error = EWOULDBLOCK;
atomic_add_int(&stcb->sctp_ep->total_nospaces, 1);
goto out_unlocked;
@@ -11146,6 +11249,7 @@ sctp_lower_sosend(struct socket *so,
free_cnt_applied = 1;
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;
}
@@ -11157,6 +11261,7 @@ sctp_lower_sosend(struct socket *so,
/*
* Can't queue any data while stream reset is underway.
*/
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN);
error = EAGAIN;
goto out_unlocked;
}
@@ -11181,6 +11286,7 @@ sctp_lower_sosend(struct socket *so,
(srcv->sinfo_flags & SCTP_ABORT)) {
;
} else {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
error = ECONNRESET;
goto out_unlocked;
}
@@ -11195,6 +11301,7 @@ sctp_lower_sosend(struct socket *so,
}
}
if (net == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
}
@@ -11228,6 +11335,7 @@ sctp_lower_sosend(struct socket *so,
(SCTP_GET_STATE(asoc) == 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);
error = EINVAL;
goto out;
}
@@ -11236,14 +11344,15 @@ sctp_lower_sosend(struct socket *so,
hold_tcblock = 0;
}
if (top) {
- struct mbuf *cntm;
+ struct mbuf *cntm = NULL;
mm = sctp_get_mbuf_for_msg(1, 0, M_WAIT, 1, MT_DATA);
-
- cntm = top;
- while (cntm) {
- tot_out += SCTP_BUF_LEN(cntm);
- cntm = SCTP_BUF_NEXT(cntm);
+ if (sndlen != 0) {
+ cntm = top;
+ while (cntm) {
+ tot_out += SCTP_BUF_LEN(cntm);
+ cntm = SCTP_BUF_NEXT(cntm);
+ }
}
tot_demand = (tot_out + sizeof(struct sctp_paramhdr));
} else {
@@ -11254,6 +11363,7 @@ sctp_lower_sosend(struct socket *so,
mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAIT, 1, MT_DATA);
}
if (mm == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
error = ENOMEM;
goto out;
}
@@ -11283,7 +11393,9 @@ sctp_lower_sosend(struct socket *so,
mm = NULL;
}
} else {
- SCTP_BUF_NEXT(mm) = top;
+ if (sndlen != 0) {
+ SCTP_BUF_NEXT(mm) = top;
+ }
}
}
if (hold_tcblock == 0) {
@@ -11299,6 +11411,14 @@ sctp_lower_sosend(struct socket *so,
/* 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 top != NULL and driver
+ * would free it after sending the packet out
+ */
+ if (sndlen != 0) {
+ top = NULL;
+ }
goto out_unlocked;
}
/* Calculate the maximum we can send */
@@ -11314,16 +11434,18 @@ sctp_lower_sosend(struct socket *so,
/* Is the stream no. valid? */
if (srcv->sinfo_stream >= asoc->streamoutcnt) {
/* Invalid stream number */
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
goto out_unlocked;
}
if (asoc->strmout == NULL) {
/* huh? software error */
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
error = EFAULT;
goto out_unlocked;
}
len = 0;
- if (max_len < sctp_add_more_threshold) {
+ if ((max_len < sctp_add_more_threshold) && (SCTP_SB_LIMIT_SND(so) > sctp_add_more_threshold)) {
/* No room right no ! */
SOCKBUF_LOCK(&so->so_snd);
while (SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) {
@@ -11365,27 +11487,33 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked;
}
atomic_add_int(&stcb->total_sends, 1);
+ /*
+ * 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) || ((uio) && (uio->uio_resid == 0))) {
+ if (srcv->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, initial_out;
int user_marks_eor;
- if (uio->uio_resid == 0) {
- if (srcv->sinfo_flags & SCTP_EOF) {
- got_all_of_the_send = 1;
- goto dataless_eof;
- } else {
- error = EINVAL;
- goto out;
- }
- }
initial_out = uio->uio_resid;
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, EAGAIN);
error = EAGAIN;
goto out;
}
@@ -11459,8 +11587,9 @@ sctp_lower_sosend(struct socket *so,
max_len = 0;
if ((max_len > sctp_add_more_threshold) ||
+ (max_len && (SCTP_SB_LIMIT_SND(so) < sctp_add_more_threshold)) ||
(uio->uio_resid &&
- (uio->uio_resid < (int)max_len))) {
+ (uio->uio_resid <= (int)max_len))) {
sndout = 0;
new_tail = NULL;
if (hold_tcblock) {
@@ -11482,8 +11611,10 @@ sctp_lower_sosend(struct socket *so,
* aborted.
*/
sctp_m_freem(mm);
- if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED)
+ if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
error = ECONNRESET;
+ }
SCTP_TCB_SEND_UNLOCK(stcb);
goto out;
}
@@ -11613,7 +11744,7 @@ sctp_lower_sosend(struct socket *so,
queue_only = 0;
} else {
sctp_send_initiate(inp, stcb);
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT);
queue_only_for_init = 0;
queue_only = 1;
}
@@ -11659,7 +11790,9 @@ sctp_lower_sosend(struct socket *so,
* size we KNOW we will get to sleep safely with the
* wakeup flag in place.
*/
- if (SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) {
+ if (SCTP_SB_LIMIT_SND(so) <= (stcb->asoc.total_output_queue_size +
+ min(sctp_add_more_threshold, SCTP_SB_LIMIT_SND(so)))
+ ) {
if (sctp_logging_level & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK,
so, asoc, uio->uio_resid);
@@ -11748,7 +11881,7 @@ dataless_eof:
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
asoc->primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
@@ -11872,11 +12005,7 @@ skip_out_eof:
queue_only = 0;
} else {
sctp_send_initiate(inp, stcb);
- if (stcb->asoc.state & SCTP_STATE_SHUTDOWN_PENDING)
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT |
- SCTP_STATE_SHUTDOWN_PENDING;
- else
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
queue_only_for_init = 0;
queue_only = 1;
}
@@ -11916,10 +12045,10 @@ skip_out_eof:
(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
&reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point);
}
- SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d \n",
+ SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d",
queue_only, stcb->asoc.peers_rwnd, un_sent,
stcb->asoc.total_flight, stcb->asoc.chunks_on_out_queue,
- stcb->asoc.total_output_queue_size);
+ stcb->asoc.total_output_queue_size, error);
out:
out_unlocked:
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index b4c2def..3d7ecb7 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -368,7 +368,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
(sctp_ifap->ifn_p->ifn_index == ifn_index)) {
if (new_ifn_af) {
/* Remove the created one that we don't want */
- sctp_delete_ifn(sctp_ifap->ifn_p, 1);
+ sctp_delete_ifn(sctp_ifnp, 1);
}
if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) {
/* easy to solve, just switch back to active */
@@ -392,7 +392,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
* Remove the created one that we
* don't want
*/
- sctp_delete_ifn(sctp_ifap->ifn_p, 1);
+ sctp_delete_ifn(sctp_ifnp, 1);
}
goto exit_stage_left;
} else {
@@ -808,6 +808,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
* UN-lock so we can do proper locking here this occurs when
* called from load_addresses_from_init.
*/
+ atomic_add_int(&locked_tcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(locked_tcb);
}
SCTP_INP_INFO_RLOCK();
@@ -825,13 +826,12 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
netp, inp->def_vrf_id);
if ((stcb != NULL) && (locked_tcb == NULL)) {
/* we have a locked tcb, lower refcount */
- SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
}
if ((locked_tcb != NULL) && (locked_tcb != stcb)) {
SCTP_INP_RLOCK(locked_tcb->sctp_ep);
SCTP_TCB_LOCK(locked_tcb);
+ atomic_subtract_int(&locked_tcb->asoc.refcnt, 1);
SCTP_INP_RUNLOCK(locked_tcb->sctp_ep);
}
SCTP_INP_INFO_RUNLOCK();
@@ -880,6 +880,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
} else if (locked_tcb != stcb) {
SCTP_TCB_LOCK(locked_tcb);
}
+ if (locked_tcb) {
+ atomic_subtract_int(&locked_tcb->asoc.refcnt, 1);
+ }
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
return (stcb);
@@ -900,6 +903,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
} else if (locked_tcb != stcb) {
SCTP_TCB_LOCK(locked_tcb);
}
+ if (locked_tcb) {
+ atomic_subtract_int(&locked_tcb->asoc.refcnt, 1);
+ }
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
return (stcb);
@@ -953,6 +959,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
} else if (locked_tcb != stcb) {
SCTP_TCB_LOCK(locked_tcb);
}
+ if (locked_tcb) {
+ atomic_subtract_int(&locked_tcb->asoc.refcnt, 1);
+ }
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
return (stcb);
@@ -974,6 +983,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
} else if (locked_tcb != stcb) {
SCTP_TCB_LOCK(locked_tcb);
}
+ if (locked_tcb) {
+ atomic_subtract_int(&locked_tcb->asoc.refcnt, 1);
+ }
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
return (stcb);
@@ -987,6 +999,7 @@ null_return:
/* clean up for returning null */
if (locked_tcb) {
SCTP_TCB_LOCK(locked_tcb);
+ atomic_subtract_int(&locked_tcb->asoc.refcnt, 1);
}
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
@@ -1793,6 +1806,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
if (inp == NULL) {
SCTP_PRINTF("Out of SCTP-INPCB structures - no resources\n");
SCTP_INP_INFO_WUNLOCK();
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
return (ENOBUFS);
}
/* zap it */
@@ -1846,15 +1860,25 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
* in protosw
*/
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP);
return (EOPNOTSUPP);
}
- sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
-
+ if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_1) {
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
+ } else if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_2) {
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
+ } else if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_0) {
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
+ }
inp->sctp_tcbhash = SCTP_HASH_INIT(sctp_pcbtblsize,
&inp->sctp_hashmark);
if (inp->sctp_tcbhash == NULL) {
SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n");
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
return (ENOBUFS);
}
inp->def_vrf_id = vrf_id;
@@ -2152,6 +2176,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
#endif
if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
/* already did a bind, subsequent binds NOT allowed ! */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
#ifdef INVARIANTS
@@ -2167,11 +2192,13 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
/* IPV6_V6ONLY socket? */
if (SCTP_IPV6_V6ONLY(ip_inp)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
- if (addr->sa_len != sizeof(*sin))
+ if (addr->sa_len != sizeof(*sin)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
-
+ }
sin = (struct sockaddr_in *)addr;
lport = sin->sin_port;
if (prison) {
@@ -2180,8 +2207,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
* prison_ip() call will tranmute the ip
* address to the proper valie.
*/
- if (prison_ip(p->td_ucred, 0, &sin->sin_addr.s_addr))
+ if (prison_ip(p->td_ucred, 0, &sin->sin_addr.s_addr)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
+ }
}
if (sin->sin_addr.s_addr != INADDR_ANY) {
bindall = 0;
@@ -2192,9 +2221,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
sin6 = (struct sockaddr_in6 *)addr;
- if (addr->sa_len != sizeof(*sin6))
+ if (addr->sa_len != sizeof(*sin6)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
-
+ }
lport = sin6->sin6_port;
/*
* Jail checks for IPv6 should go HERE! i.e. add the
@@ -2204,12 +2234,15 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
bindall = 0;
/* KAME hack: embed scopeid */
- if (sa6_embedscope(sin6, ip6_use_defzone) != 0)
+ if (sa6_embedscope(sin6, ip6_use_defzone) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
+ }
}
/* this must be cleared for ifa_ifwithaddr() */
sin6->sin6_scope_id = 0;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EAFNOSUPPORT);
return (EAFNOSUPPORT);
}
}
@@ -2240,6 +2273,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
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);
}
SCTP_INP_WUNLOCK(inp);
@@ -2258,6 +2292,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
SCTP_INP_DECR_REF(inp);
/* unlock info */
SCTP_INP_INFO_WUNLOCK();
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE);
return (EADDRINUSE);
}
} else {
@@ -2274,6 +2309,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
SCTP_INP_DECR_REF(inp);
/* unlock info */
SCTP_INP_INFO_WUNLOCK();
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE);
return (EADDRINUSE);
}
}
@@ -2285,6 +2321,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
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);
}
}
@@ -2303,6 +2340,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
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);
}
first = ipport_lowfirstauto;
@@ -2331,6 +2369,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
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)
@@ -2350,17 +2389,19 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
*/
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
/* ok we look clear to give out this port, so lets setup the binding */
if (bindall) {
/* binding to all addresses, so just set in the proper flags */
inp->sctp_flags |= SCTP_PCB_FLAGS_BOUNDALL;
- sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
/* set the automatic addr changes from kernel flag */
if (sctp_auto_asconf == 0) {
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF);
sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
} else {
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
}
} else {
@@ -2411,6 +2452,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
/* 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);
}
if (addr->sa_family == AF_INET6) {
@@ -2419,6 +2461,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
/* 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);
}
}
@@ -2586,10 +2629,12 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL;
asoc = nasoc) {
nasoc = LIST_NEXT(asoc, sctp_tcblist);
+ SCTP_TCB_LOCK(asoc);
if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
/* Skip guys being freed */
asoc->sctp_socket = NULL;
cnt_in_sd++;
+ SCTP_TCB_UNLOCK(asoc);
continue;
}
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_WAIT) ||
@@ -2605,11 +2650,14 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* Just abandon things in the front
* states
*/
- sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_2);
+
+ if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) {
+ cnt_in_sd++;
+ }
continue;
}
}
- SCTP_TCB_LOCK(asoc);
/* Disconnect the socket please */
asoc->sctp_socket = NULL;
asoc->asoc.state |= SCTP_STATE_CLOSED_SOCKET;
@@ -2645,7 +2693,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_4);
+ if (sctp_free_assoc(inp, asoc,
+ 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) &&
@@ -2665,7 +2716,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->asoc.state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
@@ -2725,7 +2776,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_6);
+ if (sctp_free_assoc(inp, asoc,
+ SCTP_PCBFREE_NOFORCE,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_6) == 0) {
+ cnt_in_sd++;
+ }
continue;
}
}
@@ -2801,7 +2856,9 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8);
+ if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) {
+ cnt++;
+ }
}
if (cnt) {
/* Ok we have someone out there that will kill us */
@@ -3344,10 +3401,12 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
*/
if (sctppcbinfo.ipi_count_asoc >= SCTP_MAX_NUM_OF_ASOC) {
/* Hit max assoc, sorry no more */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
*error = ENOBUFS;
return (NULL);
}
if (firstaddr == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
*error = EINVAL;
return (NULL);
}
@@ -3360,6 +3419,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
* 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);
}
@@ -3380,6 +3440,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
if ((sin->sin_port == 0) || (sin->sin_addr.s_addr == 0)) {
/* Invalid address */
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
*error = EINVAL;
return (NULL);
}
@@ -3392,6 +3453,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
(IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
/* Invalid address */
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
*error = EINVAL;
return (NULL);
}
@@ -3399,6 +3461,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
} else {
/* not supported family type */
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
*error = EINVAL;
return (NULL);
}
@@ -3421,6 +3484,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
stcb = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_asoc, struct sctp_tcb);
if (stcb == NULL) {
/* out of memory? */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM);
*error = ENOMEM;
return (NULL);
}
@@ -3454,6 +3518,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
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);
}
@@ -3481,6 +3546,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
SCTP_INP_WUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
*error = ENOBUFS;
return (NULL);
}
@@ -3668,8 +3734,13 @@ sctp_iterator_asoc_being_freed(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
}
-/*
- * Free the association after un-hashing the remote port.
+/*-
+ * Free the association after un-hashing the remote port. This
+ * function ALWAYS returns holding NO LOCK on the stcb. It DOES
+ * expect that the input to this function IS a locked TCB.
+ * It will return 0, if it did NOT destroy the association (instead
+ * it unlocks it. It will return NON-zero if it either destroyed the
+ * association OR the association is already destroyed.
*/
int
sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfree, int from_location)
@@ -3689,6 +3760,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
int cnt = 0;
/* first, lets purge the entry from the hash table. */
+ SCTP_TCB_LOCK_ASSERT(stcb);
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, stcb, 6);
@@ -3810,11 +3882,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_INP_READ_UNLOCK(inp);
if (stcb->block_entry) {
cnt++;
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PCB, ECONNRESET);
stcb->block_entry->error = ECONNRESET;
stcb->block_entry = NULL;
}
}
- if ((from_inpcbfree != SCTP_PCBFREE_FORCE) && (stcb->asoc.refcnt)) {
+ if (stcb->asoc.refcnt) {
/*
* reader or writer in the way, we have hopefully given him
* something to chew on above.
@@ -4516,6 +4589,7 @@ sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
laddr = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (laddr == NULL) {
/* out of memory? */
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
SCTP_INCR_LADDR_COUNT();
@@ -5666,6 +5740,7 @@ sctp_initiate_iterator(inp_func inpf,
SCTP_MALLOC(it, struct sctp_iterator *, sizeof(struct sctp_iterator),
SCTP_M_ITER);
if (it == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM);
return (ENOMEM);
}
memset(it, 0, sizeof(*it));
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index 6cdf0ca..2ab7adc 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -533,6 +533,7 @@ int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *);
void sctp_pcb_init(void);
+
void sctp_add_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c
index e810e34..daded1f 100644
--- a/sys/netinet/sctp_peeloff.c
+++ b/sys/netinet/sctp_peeloff.c
@@ -55,10 +55,12 @@ sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
inp = (struct sctp_inpcb *)head->so_pcb;
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
return (EFAULT);
}
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
if (stcb == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
return (ENOTCONN);
}
state = SCTP_GET_STATE((&stcb->asoc));
@@ -67,6 +69,7 @@ sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
(state == SCTP_STATE_COOKIE_WAIT) ||
(state == SCTP_STATE_COOKIE_ECHOED)) {
SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
return (ENOTCONN);
}
SCTP_TCB_UNLOCK(stcb);
@@ -82,18 +85,22 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
uint32_t state;
inp = (struct sctp_inpcb *)head->so_pcb;
- if (inp == NULL)
+ if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
return (EFAULT);
+ }
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
- if (stcb == NULL)
+ if (stcb == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
return (ENOTCONN);
-
+ }
state = SCTP_GET_STATE((&stcb->asoc));
if ((state == SCTP_STATE_EMPTY) ||
(state == SCTP_STATE_INUSE) ||
(state == SCTP_STATE_COOKIE_WAIT) ||
(state == SCTP_STATE_COOKIE_ECHOED)) {
SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
return (ENOTCONN);
}
n_inp = (struct sctp_inpcb *)so->so_pcb;
@@ -133,11 +140,13 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
SCTPDBG(SCTP_DEBUG_PEEL1, "SCTP peel-off called\n");
inp = (struct sctp_inpcb *)head->so_pcb;
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
*error = EFAULT;
return (NULL);
}
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
if (stcb == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
*error = ENOTCONN;
return (NULL);
}
@@ -145,6 +154,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
);
if (newso == NULL) {
SCTPDBG(SCTP_DEBUG_PEEL1, "sctp_peeloff:sonewconn failed\n");
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOMEM);
*error = ENOMEM;
SCTP_TCB_UNLOCK(stcb);
return (NULL);
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 79df612..f4480d4 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -781,13 +781,13 @@ struct sctp_association {
uint32_t peers_rwnd;
uint32_t my_rwnd;
uint32_t my_last_reported_rwnd;
- uint32_t my_rwnd_control_len;
uint32_t sctp_frag_point;
uint32_t total_output_queue_size;
- uint32_t sb_cc; /* shadow of sb_cc in one-2-one */
- uint32_t sb_mbcnt; /* shadow of sb_mbcnt in one-2-one */
+ uint32_t sb_cc; /* shadow of sb_cc */
+ uint32_t my_rwnd_control_len; /* shadow of sb_mbcnt used for rwnd
+ * control */
/* 32 bit nonce stuff */
uint32_t nonce_resync_tsn;
uint32_t nonce_wait_tsn;
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index b3a6783..02450eb 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -99,6 +99,8 @@ uint32_t sctp_max_retran_chunk = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT;
/* JRS - Variable for default congestion control module */
uint32_t sctp_default_cc_module = SCTPCTL_DEFAULT_CC_MODULE_DEFAULT;
+uint32_t sctp_default_frag_interleave = SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT;
+
uint32_t sctp_L2_abc_variable = 1;
uint32_t sctp_early_fr = 0;
uint32_t sctp_early_fr_msec = SCTP_MINFR_MSEC_TIMER;
@@ -345,6 +347,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
}
if (req->newptr != USER_ADDR_NULL) {
SCTP_INP_INFO_RUNLOCK();
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_SYSCTL, EPERM);
return EPERM;
}
LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
@@ -624,6 +627,11 @@ SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_cc_module, CTLFLAG_RW,
&sctp_default_cc_module, 0,
"Default congestion control module");
+
+SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_frag_interleave, CTLFLAG_RW,
+ &sctp_default_frag_interleave, 0,
+ SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC);
+
SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLFLAG_RW,
&sctp_use_cwnd_based_maxburst, 0,
"Use a CWND adjusting maxburst");
diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h
index 59e0922..86a0f9e 100644
--- a/sys/netinet/sctp_sysctl.h
+++ b/sys/netinet/sctp_sysctl.h
@@ -413,18 +413,27 @@ __FBSDID("$FreeBSD$");
#define SCTPCTL_DEFAULT_CC_MODULE_MAX 2
#define SCTPCTL_DEFAULT_CC_MODULE_DEFAULT 0
+
+/* RRS - default fragment interleave */
+#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE 54
+#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC "Default fragment interleave level"
+#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN 0
+#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX 2
+#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT 1
+
+
#ifdef SCTP_DEBUG
/* debug: Configure debug output */
-#define SCTPCTL_DEBUG 54
+#define SCTPCTL_DEBUG 55
#define SCTPCTL_DEBUG_DESC "Configure debug output"
#define SCTPCTL_DEBUG_MIN 0
#define SCTPCTL_DEBUG_MAX 0xFFFFFFFF
#define SCTPCTL_DEBUG_DEFAULT 0
-#define SCTPCTL_MAXID 54
-#else
#define SCTPCTL_MAXID 55
+#else
+#define SCTPCTL_MAXID 56
#endif
/*
@@ -487,6 +496,7 @@ __FBSDID("$FreeBSD$");
{ "min_residual", CTLTYPE_INT }, \
{ "max_retran_chunk", CTLTYPE_INT }, \
{ "sctp_logging", CTLTYPE_INT }, \
+ { "frag_interleave", CTLTYPE_INT }, \
{ "debug", CTLTYPE_INT }, \
}
#else
@@ -545,6 +555,7 @@ __FBSDID("$FreeBSD$");
{ "min_residual", CTLTYPE_INT }, \
{ "max_retran_chunk", CTLTYPE_INT }, \
{ "sctp_logging", CTLTYPE_INT }, \
+ { "frag_interleave", CTLTYPE_INT }, \
}
#endif
@@ -594,6 +605,7 @@ extern uint32_t sctp_cmt_pf;
/* JRS - Variable for the default congestion control module */
extern uint32_t sctp_default_cc_module;
+extern uint32_t sctp_default_frag_interleave;
extern uint32_t sctp_use_cwnd_based_maxburst;
extern uint32_t sctp_early_fr;
extern uint32_t sctp_use_rttvar_cc;
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index 47720d3..a5322e5 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -234,9 +234,23 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (net) {
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
+ if (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++;
}
} else {
+ if (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++;
}
SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n",
@@ -1726,7 +1740,7 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index fa2b922..1cebfba 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -187,7 +187,7 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
}
totsz = ip->ip_len;
- nxtsz = ntohs(icmph->icmp_seq);
+ nxtsz = ntohs(icmph->icmp_nextmtu);
if (nxtsz == 0) {
/*
* old type router that does not tell us what the next size
@@ -300,7 +300,7 @@ sctp_notify(struct sctp_inpcb *inp,
* TCB
*/
sctp_abort_notification(stcb, SCTP_PEER_FAULTY);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
/* no need to unlock here, since the TCB is gone */
}
} else {
@@ -428,6 +428,7 @@ sctp_getcred(SYSCTL_HANDLER_ARGS)
SCTP_INP_DECR_REF(inp);
goto cred_can_cont;
}
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
goto out;
}
@@ -463,9 +464,9 @@ sctp_abort(struct socket *so)
uint32_t flags;
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == 0)
+ if (inp == 0) {
return;
-
+ }
sctp_must_try_again:
flags = inp->sctp_flags;
#ifdef SCTP_LOG_CLOSING
@@ -512,6 +513,7 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
#endif
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
}
error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace);
@@ -558,21 +560,25 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
static int
sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
{
- struct sctp_inpcb *inp;
+ struct sctp_inpcb *inp = NULL;
int error;
#ifdef INET6
- if (addr && addr->sa_family != AF_INET)
+ if (addr && addr->sa_family != AF_INET) {
/* must be a v4 address! */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
+ }
#endif /* INET6 */
if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
}
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == 0)
+ if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
-
+ }
error = sctp_inpcb_bind(so, addr, NULL, p);
return error;
}
@@ -654,6 +660,7 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
sctp_m_freem(control);
control = NULL;
}
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
sctp_m_freem(m);
return EINVAL;
}
@@ -664,6 +671,7 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
) {
goto connected_type;
} else if (addr == NULL) {
+ SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
error = EDESTADDRREQ;
sctp_m_freem(m);
if (control) {
@@ -675,13 +683,14 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
#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 EINVAL;
+ return EDESTADDRREQ;
}
#endif /* INET6 */
connected_type:
@@ -731,6 +740,7 @@ sctp_disconnect(struct socket *so)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
return (ENOTCONN);
}
SCTP_INP_RLOCK(inp);
@@ -747,6 +757,7 @@ sctp_disconnect(struct socket *so)
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);
@@ -786,7 +797,7 @@ sctp_disconnect(struct socket *so)
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
/* No unlock tcb assoc is gone */
return (0);
}
@@ -808,7 +819,7 @@ sctp_disconnect(struct socket *so)
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
@@ -877,7 +888,7 @@ sctp_disconnect(struct socket *so)
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
SCTP_INP_RUNLOCK(inp);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
return (0);
}
}
@@ -889,6 +900,7 @@ sctp_disconnect(struct socket *so)
} 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;
}
}
@@ -900,6 +912,7 @@ sctp_shutdown(struct socket *so)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
}
SCTP_INP_RLOCK(inp);
@@ -909,6 +922,7 @@ sctp_shutdown(struct socket *so)
so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
/* This proc will wakeup for read and do nothing (I hope) */
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
return (EOPNOTSUPP);
}
/*
@@ -950,7 +964,7 @@ sctp_shutdown(struct socket *so)
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
@@ -1286,9 +1300,11 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
/* We are already connected AND the TCP model */
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
return (EADDRINUSE);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
@@ -1297,6 +1313,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
SCTP_INP_RUNLOCK(inp);
}
if (stcb) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
return (EALREADY);
}
SCTP_INP_INCR_REF(inp);
@@ -1304,6 +1321,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
creat_lock_on = 1;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
error = EFAULT;
goto out_now;
}
@@ -1317,8 +1335,10 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
creat_lock_on = 0;
if (stcb)
SCTP_TCB_UNLOCK(stcb);
- if (bad_addresses == 0)
+ if (bad_addresses == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
+ }
goto out_now;
}
#ifdef INET6
@@ -1337,6 +1357,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
* if IPV6_V6ONLY flag, ignore connections destined
* to a v4 addr or v4-mapped addr
*/
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto out_now;
}
@@ -1361,7 +1382,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
/* Gak! no memory */
goto out_now;
}
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
/* move to second address */
if (sa->sa_family == AF_INET)
sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
@@ -1372,7 +1393,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
/* Fill in the return id */
if (error) {
- sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
+ (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
goto out_now;
}
a_id = (sctp_assoc_t *) optval;
@@ -1415,6 +1436,7 @@ out_now:
} else if (assoc_id != 0) { \
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
if (stcb == NULL) { \
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
error = ENOENT; \
break; \
} \
@@ -1426,6 +1448,7 @@ out_now:
#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
if (size < sizeof(type)) { \
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
error = EINVAL; \
break; \
} else { \
@@ -1437,16 +1460,19 @@ static int
sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
void *p)
{
- struct sctp_inpcb *inp;
+ struct sctp_inpcb *inp = NULL;
int error, val = 0;
struct sctp_tcb *stcb = NULL;
if (optval == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == 0)
+ if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
+ }
error = 0;
switch (optname) {
@@ -1466,7 +1492,14 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
break;
case SCTP_AUTO_ASCONF:
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ /* only valid for bound all sockets */
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ goto flags_out;
+ }
break;
case SCTP_EXPLICIT_EOR:
val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
@@ -1485,6 +1518,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
break;
default:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
} /* end switch (sopt->sopt_name) */
if (optname != SCTP_AUTOCLOSE) {
@@ -1492,8 +1526,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
val = (val != 0);
}
if (*optsize < sizeof(val)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
+flags_out:
SCTP_INP_RUNLOCK(inp);
if (error == 0) {
/* return the option value */
@@ -1511,6 +1547,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
ret = sctp_copy_out_packet_log(target, (int)*optsize);
*optsize = ret;
#else
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
#endif
break;
@@ -1553,9 +1590,11 @@ 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, ENOTCONN);
error = ENOTCONN;
}
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
}
*optsize = sizeof(*av);
@@ -1595,6 +1634,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
error = 0;
}
#endif
+ if (error)
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+
*optsize = sizeof(*av);
}
break;
@@ -1628,6 +1670,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
} else {
error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
}
@@ -1669,6 +1712,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_FIND_STCB(inp, stcb, id->assoc_id);
if (stcb == NULL) {
error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
id->assoc_value = stcb->asoc.vrf_id;
@@ -1676,6 +1720,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
}
case SCTP_GET_VRF_IDS:
{
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
break;
}
@@ -1691,6 +1736,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
gnv->gn_local_tag = stcb->asoc.my_vtag;
SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
*optsize = sizeof(*gnv);
@@ -1729,6 +1775,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
stcb->asoc.size_on_all_streams);
SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
*optsize = sizeof(struct sctp_sockstat);
@@ -1878,6 +1925,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_TCB_UNLOCK(stcb);
*value = (uint32_t) size;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
*optsize = sizeof(uint32_t);
@@ -1932,6 +1980,7 @@ 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;
}
}
@@ -1979,7 +2028,37 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_INP_DECR_REF(inp);
}
}
+ if (stcb && (net == NULL)) {
+ struct sockaddr *sa;
+
+ sa = (struct sockaddr *)&paddrp->spp_address;
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)sa;
+ if (sin->sin_addr.s_addr) {
+ error = EINVAL;
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ error = EINVAL;
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
+ } else {
+ error = EAFNOSUPPORT;
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
+ }
if (stcb) {
/* Applys to the specific association */
paddrp->spp_flags = 0;
@@ -2123,6 +2202,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
}
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
}
*optsize = sizeof(struct sctp_paddrinfo);
@@ -2147,6 +2227,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
if (stcb == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
error = EINVAL;
break;
}
@@ -2291,6 +2372,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
len);
SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
error = EINVAL;
}
*optsize = sizeof(*ssp);
@@ -2318,6 +2400,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
size = sizeof(*shmac) + (hmaclist->num_algo *
sizeof(shmac->shmac_idents[0]));
if ((size_t)(*optsize) < size) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
error = EINVAL;
SCTP_INP_RUNLOCK(inp);
break;
@@ -2365,6 +2448,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
size = sctp_auth_get_chklist_size(chklist);
if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
} else {
/* copy in the chunks */
(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
@@ -2378,6 +2462,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
size = sctp_auth_get_chklist_size(chklist);
if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
} else {
/* copy in the chunks */
(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
@@ -2403,12 +2488,14 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
size = sctp_auth_get_chklist_size(chklist);
if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
} else {
/* copy in the chunks */
(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
}
SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
}
*optsize = sizeof(struct sctp_authchunks) + size;
@@ -2417,6 +2504,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
default:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
*optsize = 0;
break;
@@ -2431,16 +2519,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
int error, set_opt;
uint32_t *mopt;
struct sctp_tcb *stcb = NULL;
- struct sctp_inpcb *inp;
+ struct sctp_inpcb *inp = NULL;
uint32_t vrf_id;
if (optval == NULL) {
SCTP_PRINTF("optval is NULL\n");
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
SCTP_PRINTF("inp is NULL?\n");
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
}
vrf_id = inp->def_vrf_id;
@@ -2464,7 +2554,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
break;
case SCTP_AUTO_ASCONF:
- set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
+ /*
+ * NOTE: we don't really support this flag
+ */
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ /* only valid for bound all sockets */
+ set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ return (EINVAL);
+ }
break;
case SCTP_EXPLICIT_EOR:
set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
@@ -2476,6 +2575,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
break;
@@ -2485,6 +2585,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
case SCTP_AUTOCLOSE:
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
@@ -2509,6 +2610,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
if (*value > SCTP_SB_LIMIT_RCV(so)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -2532,6 +2634,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
}
@@ -2547,9 +2650,11 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value;
SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
}
}
@@ -2620,6 +2725,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
*/
default:
{
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
break;
@@ -2633,6 +2739,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
break;
default:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
};
@@ -2640,6 +2747,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
case SCTP_CLR_STAT_LOG:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
break;
case SCTP_CONTEXT:
@@ -2665,6 +2773,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
if (*default_vrfid > SCTP_MAX_VRF_ID) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -2673,11 +2782,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
case SCTP_DEL_VRF_ID:
{
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
break;
}
case SCTP_ADD_VRF_ID:
{
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
break;
}
@@ -2724,8 +2835,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
SCTP_INP_WLOCK(inp);
- if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks))
+ if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
+ }
SCTP_INP_WUNLOCK(inp);
break;
}
@@ -2753,6 +2866,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (size > 0) {
key = sctp_set_key(sca->sca_key, (uint32_t) size);
if (key == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
error = ENOMEM;
SCTP_TCB_UNLOCK(stcb);
break;
@@ -2761,6 +2875,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
shared_key = sctp_alloc_sharedkey();
if (shared_key == NULL) {
sctp_free_key(key);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
error = ENOMEM;
SCTP_TCB_UNLOCK(stcb);
break;
@@ -2785,6 +2900,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (size > 0) {
key = sctp_set_key(sca->sca_key, (uint32_t) size);
if (key == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
error = ENOMEM;
SCTP_INP_WUNLOCK(inp);
break;
@@ -2793,6 +2909,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
shared_key = sctp_alloc_sharedkey();
if (shared_key == NULL) {
sctp_free_key(key);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
error = ENOMEM;
SCTP_INP_WUNLOCK(inp);
break;
@@ -2815,6 +2932,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]);
hmaclist = sctp_alloc_hmaclist(size);
if (hmaclist == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
error = ENOMEM;
break;
}
@@ -2822,6 +2940,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
hmacid = shmac->shmac_idents[i];
if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) {
/* invalid HMACs were found */ ;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
sctp_free_hmaclist(hmaclist);
goto sctp_set_hmac_done;
@@ -2836,6 +2955,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
if (!found) {
sctp_free_hmaclist(hmaclist);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -2858,14 +2978,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
/* set the active key on the right place */
if (stcb) {
/* set the active key on the assoc */
- if (sctp_auth_setactivekey(stcb, scact->scact_keynumber))
+ if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
+ }
SCTP_TCB_UNLOCK(stcb);
} else {
/* set the active key on the endpoint */
SCTP_INP_WLOCK(inp);
- if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber))
+ if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
+ }
SCTP_INP_WUNLOCK(inp);
}
break;
@@ -2879,13 +3003,17 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
/* delete the key from the right place */
if (stcb) {
- if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber))
+ if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
+ }
SCTP_TCB_UNLOCK(stcb);
} else {
SCTP_INP_WLOCK(inp);
- if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber))
+ if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
+ }
SCTP_INP_WUNLOCK(inp);
}
break;
@@ -2901,6 +3029,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id);
if (stcb == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
break;
}
@@ -2911,11 +3040,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
* for this feature and this peer, not the
* socket request in general.
*/
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT);
error = EPROTONOSUPPORT;
SCTP_TCB_UNLOCK(stcb);
break;
}
if (stcb->asoc.stream_reset_outstanding) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
SCTP_TCB_UNLOCK(stcb);
break;
@@ -2930,6 +3061,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
send_tsn = 1;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
break;
@@ -2938,11 +3070,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if ((send_in) &&
(strrst->strrst_list[i] > stcb->asoc.streamincnt)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto get_out;
}
if ((send_out) &&
(strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto get_out;
}
@@ -2964,6 +3098,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
case SCTP_CONNECT_X:
if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -2972,6 +3107,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
case SCTP_CONNECT_X_DELAYED:
if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -3011,6 +3147,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
if (stcb == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
break;
}
@@ -3026,6 +3163,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
* already expired or did not use delayed
* connectx
*/
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
}
SCTP_TCB_UNLOCK(stcb);
@@ -3182,6 +3320,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) {
memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
SCTP_TCB_UNLOCK(stcb);
@@ -3219,15 +3358,48 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_INP_DECR_REF(inp);
}
}
+ if (stcb && (net == NULL)) {
+ struct sockaddr *sa;
+
+ sa = (struct sockaddr *)&paddrp->spp_address;
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)sa;
+ if (sin->sin_addr.s_addr) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ SCTP_TCB_UNLOCK(stcb);
+ error = EINVAL;
+ break;
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ SCTP_TCB_UNLOCK(stcb);
+ error = EINVAL;
+ break;
+ }
+ } else {
+ error = EAFNOSUPPORT;
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
+ }
/* sanity checks */
if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
if (stcb)
SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
if (stcb)
SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
if (stcb) {
@@ -3256,6 +3428,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
/* on demand HB */
if (sctp_send_hb(stcb, 1, net) < 0) {
/* asoc destroyed */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -3430,6 +3603,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
stcb->asoc.maxrto = new_max;
stcb->asoc.minrto = new_min;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDOM);
error = EDOM;
}
SCTP_TCB_UNLOCK(stcb);
@@ -3452,6 +3626,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
inp->sctp_ep.sctp_maxrto = new_max;
inp->sctp_ep.sctp_minrto = new_min;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDOM);
error = EDOM;
}
SCTP_INP_WUNLOCK(inp);
@@ -3557,6 +3732,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
}
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
if (stcb) {
@@ -3590,6 +3766,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
stcb->asoc.vrf_id, 0);
if (ifa == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto out_of_it;
}
@@ -3613,17 +3790,20 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
}
if (!found) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto out_of_it;
}
}
if (sctp_set_primary_ip_address_sa(stcb,
(struct sockaddr *)&sspp->sspp_addr) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
out_of_it:
SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
@@ -3645,15 +3825,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (addrs->addr->sa_family == AF_INET) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
if (optsize < sz) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
error = EADDRNOTAVAIL;
}
} else if (addrs->addr->sa_family == AF_INET6) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
if (optsize < sz) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -3679,15 +3862,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (addrs->addr->sa_family == AF_INET) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
if (optsize < sz) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
error = EADDRNOTAVAIL;
}
} else if (addrs->addr->sa_family == AF_INET6) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
if (optsize < sz) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -3699,6 +3885,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
default:
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
break;
} /* end switch (opt) */
@@ -3718,6 +3905,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
/* I made the same as TCP since we are not setup? */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
if (sopt->sopt_level != IPPROTO_SCTP) {
@@ -3734,6 +3922,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
if (optsize) {
SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
if (optval == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
return (ENOBUFS);
}
error = sooptcopyin(sopt, optval, optsize, optsize);
@@ -3748,6 +3937,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
} else if (sopt->sopt_dir == SOPT_GET) {
error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
if ((error == 0) && (optval != NULL)) {
@@ -3773,15 +3963,19 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
/* I made the same as TCP since we are not setup? */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
- if (addr == NULL)
+ if (addr == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
-
+ }
if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
SCTP_ASOC_CREATE_LOCK(inp);
@@ -3791,12 +3985,14 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
/* Should I really unlock ? */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
error = EFAULT;
goto out_now;
}
#ifdef INET6
if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
(addr->sa_family == AF_INET6)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto out_now;
}
@@ -3811,12 +4007,14 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
}
/* Now do we connect? */
if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto out_now;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
/* We are already connected AND the TCP model */
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
error = EADDRINUSE;
goto out_now;
}
@@ -3840,6 +4038,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
}
if (stcb != NULL) {
/* Already have or am bring up an association */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
goto out_now;
}
@@ -3855,7 +4054,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
/* Set the connected flag so we can queue data */
soisconnecting(so);
}
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
+ SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
/* initialize authentication parameters for the assoc */
@@ -3889,6 +4088,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
/* I made the same as TCP since we are not setup? */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
SCTP_INP_RLOCK(inp);
@@ -3909,6 +4109,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
/* We are already connected AND the TCP model */
SCTP_INP_RUNLOCK(inp);
SOCK_UNLOCK(so);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
return (EADDRINUSE);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
@@ -3951,20 +4152,24 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
SCTP_INP_RUNLOCK(inp);
- return (ENOTSUP);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
+ return (EOPNOTSUPP);
}
if (so->so_state & SS_ISDISCONNECTED) {
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
return (ECONNABORTED);
}
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
SCTP_TCB_LOCK(stcb);
@@ -4044,6 +4249,7 @@ sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
inp = (struct sctp_inpcb *)so->so_pcb;
if (!inp) {
SCTP_FREE_SONAME(sin);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return ECONNRESET;
}
SCTP_INP_RLOCK(inp);
@@ -4112,6 +4318,7 @@ sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
if (!fnd) {
SCTP_FREE_SONAME(sin);
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
return ENOENT;
}
}
@@ -4135,6 +4342,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr)
if ((inp == NULL) ||
((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
/* UDP type and listeners will drop out here */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
return (ENOTCONN);
}
SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
@@ -4145,6 +4353,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr)
inp = (struct sctp_inpcb *)so->so_pcb;
if (!inp) {
SCTP_FREE_SONAME(sin);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return ECONNRESET;
}
SCTP_INP_RLOCK(inp);
@@ -4155,6 +4364,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr)
SCTP_INP_RUNLOCK(inp);
if (stcb == NULL) {
SCTP_FREE_SONAME(sin);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return ECONNRESET;
}
fnd = 0;
@@ -4171,6 +4381,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr)
if (!fnd) {
/* No IPv4 address */
SCTP_FREE_SONAME(sin);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
return ENOENT;
}
(*addr) = (struct sockaddr *)sin;
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index 38c694b..ba33d9e 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -167,16 +167,10 @@ extern struct pr_usrreqs sctp_usrreqs;
if (val < SCTP_BUF_LEN((m))) {\
panic("stcb->sb_cc goes negative"); \
} \
- val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(MSIZE)); \
+ val = atomic_fetchadd_int(&(stcb)->asoc.my_rwnd_control_len,-(MSIZE)); \
if (val < MSIZE) { \
panic("asoc->mbcnt goes negative"); \
} \
- if (SCTP_BUF_IS_EXTENDED(m)) { \
- val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(SCTP_BUF_EXTEND_SIZE(m))); \
- if (val < SCTP_BUF_EXTEND_SIZE(m)) { \
- panic("assoc stcb->mbcnt would go negative"); \
- } \
- } \
} \
if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
SCTP_BUF_TYPE(m) != MT_OOBDATA) \
@@ -191,9 +185,7 @@ extern struct pr_usrreqs sctp_usrreqs;
atomic_add_int(&(sb)->sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \
if (stcb) { \
atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \
- atomic_add_int(&(stcb)->asoc.sb_mbcnt, MSIZE); \
- if (SCTP_BUF_IS_EXTENDED(m)) \
- atomic_add_int(&(stcb)->asoc.sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \
+ atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \
} \
if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
SCTP_BUF_TYPE(m) != MT_OOBDATA) \
@@ -291,6 +283,7 @@ extern struct pr_usrreqs sctp_usrreqs;
#endif
+
struct sctp_nets;
struct sctp_inpcb;
struct sctp_tcb;
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index e7e0987..76dfc28 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -71,7 +71,7 @@ sctp_sblog(struct sockbuf *sb,
else
sctp_clog.x.sb.stcb_sbcc = 0;
sctp_clog.x.sb.incr = incr;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_SB,
from,
sctp_clog.x.misc.log1,
@@ -95,7 +95,7 @@ sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
sctp_clog.x.close.state = 0;
}
sctp_clog.x.close.loc = loc;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_CLOSE,
0,
sctp_clog.x.misc.log1,
@@ -112,7 +112,7 @@ rto_logging(struct sctp_nets *net, int from)
sctp_clog.x.rto.net = (void *)net;
sctp_clog.x.rto.rtt = net->prev_rtt;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_RTT,
from,
sctp_clog.x.misc.log1,
@@ -133,7 +133,7 @@ sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16
sctp_clog.x.strlog.e_tsn = 0;
sctp_clog.x.strlog.e_sseq = 0;
sctp_clog.x.strlog.strm = stream;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_STRM,
from,
sctp_clog.x.misc.log1,
@@ -153,7 +153,7 @@ sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size;
sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue;
sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_NAGLE,
action,
sctp_clog.x.misc.log1,
@@ -173,7 +173,7 @@ sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps,
sctp_clog.x.sack.tsn = tsn;
sctp_clog.x.sack.numGaps = gaps;
sctp_clog.x.sack.numDups = dups;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_SACK,
from,
sctp_clog.x.misc.log1,
@@ -190,7 +190,7 @@ sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
sctp_clog.x.map.base = map;
sctp_clog.x.map.cum = cum;
sctp_clog.x.map.high = high;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_MAP,
from,
sctp_clog.x.misc.log1,
@@ -208,7 +208,7 @@ sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn,
sctp_clog.x.fr.largest_tsn = biggest_tsn;
sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn;
sctp_clog.x.fr.tsn = tsn;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_FR,
from,
sctp_clog.x.misc.log1,
@@ -235,7 +235,7 @@ sctp_log_mb(struct mbuf *m, int from)
sctp_clog.x.mb.ext = 0;
sctp_clog.x.mb.refcnt = 0;
}
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_MBUF,
from,
sctp_clog.x.misc.log1,
@@ -266,7 +266,7 @@ sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_rea
sctp_clog.x.strlog.e_tsn = 0;
sctp_clog.x.strlog.e_sseq = 0;
}
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_STRM,
from,
sctp_clog.x.misc.log1,
@@ -302,7 +302,7 @@ sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t
sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd;
}
sctp_clog.x.cwnd.cwnd_augment = augment;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_CWND,
from,
sctp_clog.x.misc.log1,
@@ -346,7 +346,7 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN;
sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN;
}
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_LOCK_EVENT,
from,
sctp_clog.x.misc.log1,
@@ -373,7 +373,7 @@ sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int b
sctp_clog.x.cwnd.cnt_in_str = 255;
else
sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_MAXBURST,
from,
sctp_clog.x.misc.log1,
@@ -392,7 +392,7 @@ sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t ove
sctp_clog.x.rwnd.send_size = snd_size;
sctp_clog.x.rwnd.overhead = overhead;
sctp_clog.x.rwnd.new_rwnd = 0;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_RWND,
from,
sctp_clog.x.misc.log1,
@@ -410,7 +410,7 @@ sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint3
sctp_clog.x.rwnd.send_size = flight_size;
sctp_clog.x.rwnd.overhead = overhead;
sctp_clog.x.rwnd.new_rwnd = a_rwndval;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_RWND,
from,
sctp_clog.x.misc.log1,
@@ -428,7 +428,7 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb
sctp_clog.x.mbcnt.size_change = book;
sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q;
sctp_clog.x.mbcnt.mbcnt_change = mbcnt;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_MBCNT,
from,
sctp_clog.x.misc.log1,
@@ -441,7 +441,7 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb
void
sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_MISC_EVENT,
from,
a, b, c, d);
@@ -484,7 +484,7 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t cumtsn, uint32_t wake_cnt, int f
} else {
sctp_clog.x.wake.sbflags = 0xff;
}
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_WAKE,
from,
sctp_clog.x.misc.log1,
@@ -506,7 +506,7 @@ sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc, i
sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue;
sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight / 1024);
sctp_clog.x.blk.sndlen = sendlen;
- CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
+ SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_BLOCK,
from,
sctp_clog.x.misc.log1,
@@ -876,7 +876,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc = &stcb->asoc;
/* init all variables to a known value. */
- asoc->state = SCTP_STATE_INUSE;
+ SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE);
asoc->max_burst = m->sctp_ep.max_burst;
asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
asoc->cookie_life = m->sctp_ep.def_cookie_life;
@@ -902,6 +902,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
if (sctp_is_vtag_good(m, override_tag, &now)) {
asoc->my_vtag = override_tag;
} else {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
return (ENOMEM);
}
@@ -1095,6 +1096,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
SCTP_M_STRMO);
if (asoc->strmout == NULL) {
/* big trouble no memory */
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
return (ENOMEM);
}
for (i = 0; i < asoc->streamoutcnt; i++) {
@@ -1119,6 +1121,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
SCTP_M_MAP);
if (asoc->mapping_array == NULL) {
SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
return (ENOMEM);
}
memset(asoc->mapping_array, 0, asoc->mapping_array_size);
@@ -1219,8 +1222,6 @@ select_a_new_ep:
SCTP_INP_WLOCK(it->inp);
}
- /* mark the current iterator on the endpoint */
- it->inp->inp_starting_point_for_iterator = it;
SCTP_INP_WUNLOCK(it->inp);
SCTP_INP_RLOCK(it->inp);
@@ -1243,10 +1244,6 @@ select_a_new_ep:
SCTP_INP_RUNLOCK(it->inp);
goto no_stcb;
}
- if ((it->stcb) &&
- (it->stcb->asoc.stcb_starting_point_for_iterator == it)) {
- it->stcb->asoc.stcb_starting_point_for_iterator = NULL;
- }
while (it->stcb) {
SCTP_TCB_LOCK(it->stcb);
if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
@@ -1254,18 +1251,20 @@ select_a_new_ep:
SCTP_TCB_UNLOCK(it->stcb);
goto next_assoc;
}
- /* mark the current iterator on the assoc */
- it->stcb->asoc.stcb_starting_point_for_iterator = it;
/* see if we have limited out the iterator loop */
iteration_count++;
if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
/* Pause to let others grab the lock */
atomic_add_int(&it->stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(it->stcb);
+
+ SCTP_INP_INCR_REF(it->inp);
SCTP_INP_RUNLOCK(it->inp);
SCTP_ITERATOR_UNLOCK();
SCTP_ITERATOR_LOCK();
SCTP_INP_RLOCK(it->inp);
+
+ SCTP_INP_DECR_REF(it->inp);
SCTP_TCB_LOCK(it->stcb);
atomic_add_int(&it->stcb->asoc.refcnt, -1);
iteration_count = 0;
@@ -1297,7 +1296,6 @@ no_stcb:
/* done with all assocs on this endpoint, move on to next endpoint */
it->done_current_ep = 0;
SCTP_INP_WLOCK(it->inp);
- it->inp->inp_starting_point_for_iterator = NULL;
SCTP_INP_WUNLOCK(it->inp);
if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
it->inp = NULL;
@@ -1582,10 +1580,15 @@ sctp_timeout_handler(void *t)
case SCTP_TIMER_TYPE_RECV:
if ((stcb == NULL) || (inp == NULL)) {
break;
+ } {
+ int abort_flag;
+
+ SCTP_STAT_INCR(sctps_timosack);
+ stcb->asoc.timosack++;
+ if (stcb->asoc.cumulative_tsn != stcb->asoc.highest_tsn_inside_map)
+ sctp_sack_check(stcb, 0, 0, &abort_flag);
+ sctp_send_sack(stcb);
}
- SCTP_STAT_INCR(sctps_timosack);
- stcb->asoc.timosack++;
- sctp_send_sack(stcb);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@@ -1769,7 +1772,7 @@ sctp_timeout_handler(void *t)
/* 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);
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
/*
* free asoc, always unlocks (or destroy's) so prevent
* duplicate unlock or unlock of a free mtx :-0
@@ -2176,7 +2179,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
tmr->tcb = (void *)stcb;
tmr->net = (void *)net;
tmr->self = (void *)tmr;
- tmr->ticks = ticks;
+ tmr->ticks = sctp_get_tick_count();
(void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
return;
}
@@ -2767,6 +2770,7 @@ sctp_add_pad_tombuf(struct mbuf *m, int padlen)
int i;
if (padlen > 3) {
+ SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
return (ENOBUFS);
}
if (M_TRAILINGSPACE(m)) {
@@ -2783,6 +2787,7 @@ sctp_add_pad_tombuf(struct mbuf *m, int padlen)
tmp = sctp_get_mbuf_for_msg(padlen, 0, M_DONTWAIT, 1, MT_DATA);
if (tmp == NULL) {
/* Out of space GAK! we are in big trouble. */
+ SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (ENOSPC);
}
/* setup and insert in middle */
@@ -2816,6 +2821,7 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
m_at = SCTP_BUF_NEXT(m_at);
}
}
+ SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
return (EFAULT);
}
@@ -2849,10 +2855,13 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
((event == SCTP_COMM_LOST) || (event == SCTP_CANT_STR_ASSOC))) {
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT)
+ if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
stcb->sctp_socket->so_error = ECONNREFUSED;
- else
+ } else {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
stcb->sctp_socket->so_error = ECONNRESET;
+ }
/* Wake ANY sleepers */
sorwakeup(stcb->sctp_socket);
sowwakeup(stcb->sctp_socket);
@@ -3658,7 +3667,7 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id);
if (stcb != NULL) {
/* Ok, now lets free it */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
} else {
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
@@ -3766,7 +3775,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
}
void
@@ -4687,6 +4696,7 @@ sctp_sorecvmsg(struct socket *so,
int sockbuf_lock = 0;
if (uio == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (EINVAL);
}
if (msg_flags) {
@@ -4704,6 +4714,7 @@ sctp_sorecvmsg(struct socket *so,
return (EOPNOTSUPP);
}
if ((in_flags & MSG_PEEK) && (mp != NULL)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (EINVAL);
}
if ((in_flags & (MSG_DONTWAIT
@@ -4715,6 +4726,7 @@ sctp_sorecvmsg(struct socket *so,
/* setup the endpoint */
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
return (EFAULT);
}
rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT);
@@ -4753,6 +4765,7 @@ restart_nosblocks:
if ((in_flags & MSG_PEEK) == 0)
so->so_error = 0;
} else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
error = ENOTCONN;
}
goto out;
@@ -4773,6 +4786,7 @@ restart_nosblocks:
* You were aborted, passive side
* always hits here
*/
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
error = ECONNRESET;
/*
* You get this once if you are
@@ -4792,6 +4806,7 @@ restart_nosblocks:
SS_ISCONNECTED);
if (error == 0) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
error = ENOTCONN;
} else {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED;
@@ -4825,6 +4840,7 @@ restart_nosblocks:
* You were aborted, passive
* side always hits here
*/
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
error = ECONNRESET;
/*
* You get this once if you
@@ -4845,6 +4861,7 @@ restart_nosblocks:
SS_ISCONNECTED);
if (error == 0) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
error = ENOTCONN;
} else {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED;
@@ -4853,6 +4870,7 @@ restart_nosblocks:
goto out;
}
}
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK);
error = EWOULDBLOCK;
}
goto out;
@@ -5216,6 +5234,7 @@ get_more_data:
embuf = m;
copied_so_far += cp_len;
freed_so_far += cp_len;
+ freed_so_far += MSIZE;
atomic_subtract_int(&control->length, cp_len);
control->data = sctp_m_free(m);
m = control->data;
@@ -5266,6 +5285,7 @@ get_more_data:
copied_so_far += cp_len;
embuf = m;
freed_so_far += cp_len;
+ freed_so_far += MSIZE;
if (sctp_logging_level & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb,
SCTP_LOG_SBRESULT, 0);
@@ -5483,6 +5503,7 @@ wait_some_more:
}
sctp_sbfree(control, stcb, &so->so_rcv, m);
freed_so_far += SCTP_BUF_LEN(m);
+ freed_so_far += MSIZE;
if (sctp_logging_level & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(&so->so_rcv,
control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
@@ -5612,6 +5633,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
if (ifa == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
return (EADDRNOTAVAIL);
}
/*
@@ -5620,6 +5642,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
*/
wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (wi == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
return (ENOMEM);
}
/* Now incr the count and int wi structure */
@@ -5666,6 +5689,7 @@ sctp_soreceive(struct socket *so,
inp = (struct sctp_inpcb *)so->so_pcb;
/* pickup the assoc we are reading from */
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (EINVAL);
}
if ((sctp_is_feature_off(inp,
@@ -5723,6 +5747,7 @@ sctp_l_soreceive(struct socket *so,
inp = (struct sctp_inpcb *)so->so_pcb;
/* pickup the assoc we are reading from */
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (EINVAL);
}
if ((sctp_is_feature_off(inp,
@@ -5790,7 +5815,8 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
incr = sizeof(struct sockaddr_in);
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
*error = ENOBUFS;
goto out_now;
}
@@ -5799,7 +5825,8 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
incr = sizeof(struct sockaddr_in6);
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
*error = ENOBUFS;
goto out_now;
}
@@ -5829,6 +5856,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
(*num_v4) += 1;
incr = sizeof(struct sockaddr_in);
if (sa->sa_len != incr) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
*bad_addr = 1;
return (NULL);
@@ -5839,6 +5867,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
sin6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
/* Must be non-mapped for connectx */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
*bad_addr = 1;
return (NULL);
@@ -5846,6 +5875,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
(*num_v6) += 1;
incr = sizeof(struct sockaddr_in6);
if (sa->sa_len != incr) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
*bad_addr = 1;
return (NULL);
@@ -5886,6 +5916,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
/* see if we're bound all already! */
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -5895,11 +5926,13 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
struct sockaddr_in6 *sin6;
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
/* can only bind v6 on PF_INET6 sockets */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -5908,6 +5941,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
/* can't bind v4-mapped on PF_INET sockets */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -5918,12 +5952,14 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
#endif
if (sa->sa_family == AF_INET) {
if (sa->sa_len != sizeof(struct sockaddr_in)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
/* can't bind v4 on PF_INET sockets */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -5931,6 +5967,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
if (p == NULL) {
/* Can't get proc for Net/Open BSD */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -5950,6 +5987,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
/* validate the incoming port */
if ((lsin->sin_port != 0) &&
(lsin->sin_port != inp->sctp_lport)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
} else {
@@ -6000,6 +6038,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
/* see if we're bound all already! */
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -6009,11 +6048,13 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
struct sockaddr_in6 *sin6;
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
/* can only bind v6 on PF_INET6 sockets */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -6022,6 +6063,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
/* can't bind mapped-v4 on PF_INET sockets */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -6032,12 +6074,14 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
#endif
if (sa->sa_family == AF_INET) {
if (sa->sa_len != sizeof(struct sockaddr_in)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
/* can't bind v4 on PF_INET sockets */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
return;
}
@@ -6168,3 +6212,43 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
}
return (count);
}
+
+#if defined(SCTP_LOCAL_TRACE_BUF)
+
+struct sctp_dump_log {
+ u_int64_t timestamp;
+ const char *descr;
+ uint32_t subsys;
+ uint32_t params[SCTP_TRACE_PARAMS];
+};
+int sctp_log_index = 0;
+struct sctp_dump_log sctp_log[SCTP_MAX_LOGGING_SIZE];
+
+void
+sctp_log_trace(uint32_t subsys, const char *str, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f)
+{
+ int saveindex, newindex;
+
+ do {
+ saveindex = sctp_log_index;
+ if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
+ newindex = 1;
+ } else {
+ newindex = saveindex + 1;
+ }
+ } while (atomic_cmpset_int(&sctp_log_index, saveindex, newindex) == 0);
+ if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
+ saveindex = 0;
+ }
+ sctp_log[saveindex].timestamp = SCTP_GET_CYCLECOUNT;
+ sctp_log[saveindex].subsys = subsys;
+ sctp_log[saveindex].descr = str;
+ sctp_log[saveindex].params[0] = a;
+ sctp_log[saveindex].params[1] = b;
+ sctp_log[saveindex].params[2] = c;
+ sctp_log[saveindex].params[3] = d;
+ sctp_log[saveindex].params[4] = e;
+ sctp_log[saveindex].params[5] = f;
+}
+
+#endif
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index 46d63d8..b1f5542 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -54,6 +54,11 @@ void sctp_m_freem(struct mbuf *m);
#define sctp_m_freem m_freem
#endif
+#if defined(SCTP_LOCAL_TRACE_BUF) || defined(__APPLE__)
+void
+ sctp_log_trace(uint32_t fr, const char *str, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f);
+
+#endif
#define sctp_get_associd(stcb) ((sctp_assoc_t)stcb->asoc.assoc_id)
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 6517b48..d2ee49c 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -440,10 +440,14 @@ sctp6_getcred(SYSCTL_HANDLER_ARGS)
if (error)
return (error);
- if (req->newlen != sizeof(addrs))
+ if (req->newlen != sizeof(addrs)) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
- if (req->oldlen != sizeof(struct ucred))
+ }
+ if (req->oldlen != sizeof(struct ucred)) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
+ }
error = SYSCTL_IN(req, addrs, sizeof(addrs));
if (error)
return (error);
@@ -458,6 +462,7 @@ sctp6_getcred(SYSCTL_HANDLER_ARGS)
SCTP_INP_DECR_REF(inp);
goto cred_can_cont;
}
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
error = ENOENT;
goto out;
}
@@ -537,9 +542,10 @@ sctp6_attach(struct socket *so, int proto, struct thread *p)
uint32_t vrf_id = SCTP_DEFAULT_VRFID;
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp != NULL)
+ if (inp != NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
-
+ }
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace);
if (error)
@@ -580,16 +586,19 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
int error;
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == 0)
+ if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
-
+ }
if (addr) {
if ((addr->sa_family == AF_INET6) &&
(addr->sa_len != sizeof(struct sockaddr_in6))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
if ((addr->sa_family == AF_INET) &&
(addr->sa_len != sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
}
@@ -622,6 +631,7 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
/* IPV6_V6ONLY socket */
if (addr->sa_family == AF_INET) {
/* can't bind v4 addr to v6 only socket! */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
} else {
struct sockaddr_in6 *sin6_p;
@@ -631,7 +641,8 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr))
/* can't bind v4-mapped addrs either! */
/* NOTE: we don't support SIIT */
- return EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
+ return EINVAL;
}
}
error = sctp_inpcb_bind(so, addr, NULL, p);
@@ -707,6 +718,7 @@ sctp6_disconnect(struct socket *so)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
return (ENOTCONN);
}
SCTP_INP_RLOCK(inp);
@@ -714,6 +726,7 @@ sctp6_disconnect(struct socket *so)
if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) {
/* No connection */
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
return (ENOTCONN);
} else {
int some_on_streamwheel = 0;
@@ -723,6 +736,7 @@ sctp6_disconnect(struct socket *so)
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
SCTP_TCB_LOCK(stcb);
@@ -744,8 +758,10 @@ sctp6_disconnect(struct socket *so)
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- sctp_free_assoc(inp, stcb, SCTP_DONOT_SETSCOPE,
- SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2);
+ if (sctp_free_assoc(inp, stcb, SCTP_DONOT_SETSCOPE,
+ SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2) == 0) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
/* No unlock tcb assoc is gone */
return (0);
}
@@ -776,7 +792,7 @@ sctp6_disconnect(struct socket *so)
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
- asoc->state = SCTP_STATE_SHUTDOWN_SENT;
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
@@ -804,6 +820,7 @@ sctp6_disconnect(struct socket *so)
} else {
/* UDP model does not support this */
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EOPNOTSUPP);
return EOPNOTSUPP;
}
}
@@ -835,6 +852,7 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
control = NULL;
}
SCTP_RELEASE_PKT(m);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
in_inp = (struct inpcb *)inp;
@@ -853,6 +871,7 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
SCTP_RELEASE_PKT(control);
control = NULL;
}
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
return (EDESTADDRREQ);
}
#ifdef INET
@@ -863,9 +882,11 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
* v4 addr or v4-mapped addr
*/
if (addr->sa_family == AF_INET) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
}
@@ -879,6 +900,7 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
control, p);
} else {
/* mapped addresses aren't enabled */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
}
@@ -940,16 +962,20 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
inp6 = (struct in6pcb *)so->so_pcb;
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
return (ECONNRESET); /* I made the same as TCP since we are
* not setup? */
}
if (addr == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
vrf_id = inp->def_vrf_id;
@@ -972,6 +998,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
/* We are already connected AND the TCP model */
SCTP_INP_RUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
return (EADDRINUSE);
}
#ifdef INET
@@ -984,11 +1011,13 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
if (addr->sa_family == AF_INET) {
SCTP_INP_RUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
SCTP_INP_RUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
}
@@ -1001,6 +1030,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
/* mapped addresses aren't enabled */
SCTP_INP_RUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
} else
@@ -1031,6 +1061,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
/* Already have or am bring up an association */
SCTP_ASOC_CREATE_UNLOCK(inp);
SCTP_TCB_UNLOCK(stcb);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
return (EALREADY);
}
/* We are GOOD to go */
@@ -1076,6 +1107,7 @@ sctp6_getaddr(struct socket *so, struct sockaddr **addr)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
SCTP_FREE_SONAME(sin6);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
return ECONNRESET;
}
SCTP_INP_RLOCK(inp);
@@ -1137,6 +1169,7 @@ sctp6_getaddr(struct socket *so, struct sockaddr **addr)
if (!fnd) {
SCTP_FREE_SONAME(sin6);
SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
return ENOENT;
}
}
@@ -1168,6 +1201,7 @@ sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
inp = (struct sctp_inpcb *)so->so_pcb;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
/* UDP type and listeners will drop out here */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
return (ENOTCONN);
}
SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
@@ -1178,6 +1212,7 @@ sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
SCTP_FREE_SONAME(sin6);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
return ECONNRESET;
}
SCTP_INP_RLOCK(inp);
@@ -1188,6 +1223,7 @@ sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
SCTP_INP_RUNLOCK(inp);
if (stcb == NULL) {
SCTP_FREE_SONAME(sin6);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
return ECONNRESET;
}
fnd = 0;
@@ -1204,6 +1240,7 @@ sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
if (!fnd) {
/* No IPv4 address */
SCTP_FREE_SONAME(sin6);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
return ENOENT;
}
if ((error = sa6_recoverscope(sin6)) != 0)
@@ -1219,9 +1256,10 @@ sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
struct in6pcb *inp6 = sotoin6pcb(so);
int error;
- if (inp6 == NULL)
+ if (inp6 == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
-
+ }
/* allow v6 addresses precedence */
error = sctp6_getaddr(so, nam);
if (error) {
@@ -1251,9 +1289,10 @@ sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
struct in6pcb *inp6 = sotoin6pcb(so);
int error;
- if (inp6 == NULL)
+ if (inp6 == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
-
+ }
/* allow v6 addresses precedence */
error = sctp6_peeraddr(so, nam);
if (error) {
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index bff95b5..bf7c073 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -178,7 +178,7 @@ struct mbuf {
#define M_PROTO3 0x0040 /* protocol-specific */
#define M_PROTO4 0x0080 /* protocol-specific */
#define M_PROTO5 0x0100 /* protocol-specific */
-#define M_NOTIFICATION 0x2000 /* SCTP notification */
+#define M_NOTIFICATION M_PROTO5/* SCTP notification */
#define M_SKIP_FIREWALL 0x4000 /* skip firewall processing */
#define M_FREELIST 0x8000 /* mbuf is on the free list */
OpenPOWER on IntegriCloud