From a5d547add3475cbba521b738f99e366f187bedf1 Mon Sep 17 00:00:00 2001 From: Randall Stewart Date: Thu, 14 Dec 2006 17:02:55 +0000 Subject: [PATCH] 1) Fixes on a number of different collision case LOR's. 2) Fix all "magic numbers" to be constants. 3) A collision case that would generate two associations to the same peer due to a missing lock is fixed. 4) Added tracking of where timers are stopped. Approved by: gnn --- sys/netinet/sctp_asconf.c | 9 +- sys/netinet/sctp_constants.h | 76 +++++++- sys/netinet/sctp_indata.c | 328 +++++++++++++++++++++-------------- sys/netinet/sctp_input.c | 236 +++++++++++++++++-------- sys/netinet/sctp_lock_bsd.h | 32 ++++ sys/netinet/sctp_os_bsd.h | 2 + sys/netinet/sctp_output.c | 184 +++++++++++++++----- sys/netinet/sctp_pcb.c | 199 ++++++++++++--------- sys/netinet/sctp_pcb.h | 13 +- sys/netinet/sctp_peeloff.c | 3 +- sys/netinet/sctp_structs.h | 13 +- sys/netinet/sctp_timer.c | 31 +++- sys/netinet/sctp_uio.h | 55 +++++- sys/netinet/sctp_usrreq.c | 218 +++++++++++++++++++++-- sys/netinet/sctputil.c | 77 ++++---- sys/netinet/sctputil.h | 2 +- sys/netinet6/sctp6_usrreq.c | 15 +- 17 files changed, 1087 insertions(+), 406 deletions(-) diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index 7b44da5356e9..de1bc86e93d6 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -338,7 +338,8 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, #endif /* SCTP_DEBUG */ } /* add the address */ - if (sctp_add_remote_addr(stcb, sa, 0, 6) != 0) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, + SCTP_ADDR_DYNAMIC_ADDED) != 0) { #ifdef SCTP_DEBUG if (sctp_debug_on & SCTP_DEBUG_ASCONF1) { printf("process_asconf_add_ip: error adding address\n"); @@ -354,7 +355,7 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, m_reply = sctp_asconf_success_response(aph->correlation_id); } - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL); } @@ -1024,7 +1025,7 @@ sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net) /* * clear out any existing asconfs going out */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2); stcb->asoc.asconf_seq_out++; /* remove the old ASCONF on our outbound queue */ sctp_toss_old_asconf(stcb); @@ -1500,7 +1501,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset, return; } /* stop our timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3); /* process the ASCONF-ACK contents */ ack_length = ntohs(cp->ch.chunk_length) - diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index d11d380ca452..5d001930a943 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -151,8 +151,9 @@ __FBSDID("$FreeBSD$"); #define SCTP_RANDY_STUFF1 103 #define SCTP_STRMOUT_LOG_ASSIGN 104 #define SCTP_STRMOUT_LOG_SEND 105 - -#define SCTP_LOG_MAX_TYPES 106 +#define SCTP_FLIGHT_LOG_DOWN 106 +#define SCTP_FLIGHT_LOG_UP 107 +#define SCTP_LOG_MAX_TYPES 108 /* * To turn on various logging, you must first define SCTP_STAT_LOGGING. Then * to get something to log you define one of the logging defines i.e. @@ -740,6 +741,77 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_DEFAULT_SPLIT_POINT_MIN 1452 +/* ABORT CODES and other tell-tale location + * codes are generated by adding the below + * to the instance id. + */ + +/* File defines */ +#define SCTP_FROM_SCTP_INPUT 0x10000000 +#define SCTP_FROM_SCTP_PCB 0x20000000 +#define SCTP_FROM_SCTP_INDATA 0x30000000 +#define SCTP_FROM_SCTP_TIMER 0x40000000 +#define SCTP_FROM_SCTP_USRREQ 0x50000000 +#define SCTP_FROM_SCTPUTIL 0x60000000 +#define SCTP_FROM_SCTP6_USRREQ 0x70000000 +#define SCTP_FROM_SCTP_ASCONF 0x80000000 +#define SCTP_FROM_SCTP_OUTPUT 0x90000000 +#define SCTP_FROM_SCTP_PEELOFF 0xa0000000 + +/* Location ID's */ +#define SCTP_LOC_1 0x00000001 +#define SCTP_LOC_2 0x00000002 +#define SCTP_LOC_3 0x00000003 +#define SCTP_LOC_4 0x00000004 +#define SCTP_LOC_5 0x00000005 +#define SCTP_LOC_6 0x00000006 +#define SCTP_LOC_7 0x00000007 +#define SCTP_LOC_8 0x00000008 +#define SCTP_LOC_9 0x00000009 +#define SCTP_LOC_10 0x0000000a +#define SCTP_LOC_11 0x0000000b +#define SCTP_LOC_12 0x0000000c +#define SCTP_LOC_13 0x0000000d +#define SCTP_LOC_14 0x0000000e +#define SCTP_LOC_15 0x0000000f +#define SCTP_LOC_16 0x00000010 +#define SCTP_LOC_17 0x00000011 +#define SCTP_LOC_18 0x00000012 +#define SCTP_LOC_19 0x00000013 +#define SCTP_LOC_20 0x00000014 +#define SCTP_LOC_21 0x00000015 +#define SCTP_LOC_22 0x00000016 +#define SCTP_LOC_23 0x00000017 +#define SCTP_LOC_24 0x00000018 +#define SCTP_LOC_25 0x00000019 +#define SCTP_LOC_26 0x0000001a +#define SCTP_LOC_27 0x0000001b +#define SCTP_LOC_28 0x0000001c +#define SCTP_LOC_29 0x0000001d +#define SCTP_LOC_30 0x0000001e +#define SCTP_LOC_31 0x0000001f +#define SCTP_LOC_32 0x00000020 + + +/* Free assoc codes */ +#define SCTP_NORMAL_PROC 0 +#define SCTP_PCBFREE_NOFORCE 1 +#define SCTP_PCBFREE_FORCE 2 + +/* From codes for adding addresses */ +#define SCTP_ADDR_IS_CONFIRMED 8 +#define SCTP_ADDR_DYNAMIC_ADDED 6 +#define SCTP_IN_COOKIE_PROC 100 +#define SCTP_ALLOC_ASOC 1 +#define SCTP_LOAD_ADDR_2 2 +#define SCTP_LOAD_ADDR_3 3 +#define SCTP_LOAD_ADDR_4 4 +#define SCTP_LOAD_ADDR_5 5 + +#define SCTP_DONOT_SETSCOPE 0 +#define SCTP_DO_SETSCOPE 1 + + /* This value determines the default for when * we try to add more on the send queue., if * there is room. This prevents us from cycling diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 7b6596474e74..de258936e6a9 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -28,7 +28,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -/* $kejKAME: sctp_indata.c,v 1.36 2005/03/06 16:04:17 itojun Exp $ */ +/* $KAME: sctp_indata.c,v 1.36 2005/03/06 16:04:17 itojun Exp $ */ #include __FBSDID("$FreeBSD$"); @@ -623,12 +623,13 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x00000001); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_1); ippp++; *ippp = control->sinfo_tsn; ippp++; *ippp = ((control->sinfo_stream << 16) | control->sinfo_ssn); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -884,13 +885,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000001); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_2); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); *abort_flag = 1; @@ -920,12 +922,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000002); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_3); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); *abort_flag = 1; @@ -960,12 +963,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000003); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_4); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_4; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); *abort_flag = 1; @@ -997,13 +1001,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000004); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_5); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_5; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); *abort_flag = 1; @@ -1099,13 +1104,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000005); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_6); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_6; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); *abort_flag = 1; @@ -1140,12 +1146,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000006); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_7); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_7; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1182,12 +1189,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000007); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_8); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_8; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1220,13 +1228,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000008); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_9); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_9; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1269,12 +1278,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x10000009); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_10); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_10; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1313,13 +1323,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x1000000a); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_11); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_11; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1355,13 +1366,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x1000000b); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_12); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_12; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1398,12 +1410,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x1000000c); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_13); ippp++; *ippp = chk->rec.data.TSN_seq; ippp++; *ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_13; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1683,13 +1696,14 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x20000001); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_14); ippp++; *ippp = tsn; ippp++; *ippp = ((strmno << 16) | strmseq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); *abort_flag = 1; @@ -1807,12 +1821,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, asoc->last_flags_delivered = ch->ch.chunk_flags; asoc->last_strm_seq_delivered = strmseq; asoc->last_strm_no_delivered = strmno; - asoc->tsn_last_delivered = tsn; if (end) { /* clean up the flags and such */ asoc->fragmented_delivery_inprogress = 0; - asoc->strmin[strmno].last_sequence_delivered++; + if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) { + asoc->strmin[strmno].last_sequence_delivered++; + } stcb->asoc.control_pdapi = NULL; } control = NULL; @@ -1900,12 +1915,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x20000002); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_15); ippp++; *ippp = tsn; ippp++; *ippp = ((strmno << 16) | strmseq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1934,12 +1950,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x20000003); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_16); ippp++; *ippp = tsn; ippp++; *ippp = ((strmno << 16) | strmseq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -1977,12 +1994,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x20000004); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_17); ippp++; *ippp = tsn; ippp++; *ippp = ((strmno << 16) | strmseq); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); @@ -2062,6 +2080,11 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, /* Into the re-assembly queue */ sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag); if (*abort_flag) { + /* + * the assoc is now gone and chk was put onto the + * reasm queue, which has all been freed. + */ + *m = NULL; return (0); } } @@ -2190,7 +2213,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort if (compare_with_wrap(asoc->cumulative_tsn, asoc->highest_tsn_inside_map, MAX_TSN)) { -#ifdef INVARIENTS +#ifdef INVARIANTS panic("huh, cumack greater than high-tsn in map"); #else printf("huh, cumack greater than high-tsn in map - should panic?\n"); @@ -2346,7 +2369,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort */ if (callout_pending(&stcb->asoc.dack_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); + stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18); } sctp_send_shutdown(stcb, stcb->asoc.primary_destination); sctp_send_sack(stcb); @@ -2585,11 +2608,12 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000001); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_19); ippp++; *ippp = asoc->cumulative_tsn; } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; sctp_abort_association(inp, stcb, m, iphlen, sh, op_err); return (2); @@ -2988,73 +3012,47 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc, frag_end, SCTP_LOG_TSN_ACKED); #endif +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); +#endif + if (tp1->whoTo->flight_size >= tp1->book_size) + tp1->whoTo->flight_size -= tp1->book_size; + else + tp1->whoTo->flight_size = 0; + if (asoc->total_flight >= tp1->book_size) { + asoc->total_flight -= tp1->book_size; + if (asoc->total_flight_count > 0) + asoc->total_flight_count--; + } else { + asoc->total_flight = 0; + asoc->total_flight_count = 0; + } - if (tp1->rec.data.chunk_was_revoked == 0) { + tp1->whoTo->net_ack += tp1->send_size; + + if (tp1->snd_count < 2) { /* - * Revoked - * chunks - * don't - * count, - * since we - * previously - * pulled - * them from - * the fs. - */ - if (tp1->whoTo->flight_size >= tp1->book_size) - tp1->whoTo->flight_size -= tp1->book_size; - else - tp1->whoTo->flight_size = 0; - if (asoc->total_flight >= tp1->book_size) { - asoc->total_flight -= tp1->book_size; - if (asoc->total_flight_count > 0) - asoc->total_flight_count--; - } else { - asoc->total_flight = 0; - asoc->total_flight_count = 0; - } + * True + * non-retran + * smited + * chunk */ + tp1->whoTo->net_ack2 += tp1->send_size; - tp1->whoTo->net_ack += tp1->send_size; - - if (tp1->snd_count < 2) { - /* - * Tru - * e - * no - * n - * -r - * e - * tr - * a - * ns - * m - * it - * e - * d - * ch - * u - * nk - * */ - tp1->whoTo->net_ack2 += tp1->send_size; - - /* - * upd - * - * ate - * - * RTO - * - * too - * ? */ - if (tp1->do_rtt) { - tp1->whoTo->RTO = - sctp_calculate_rto(stcb, - asoc, - tp1->whoTo, - &tp1->sent_rcv_time); - tp1->whoTo->rto_pending = 0; - tp1->do_rtt = 0; - } + /* + * update RTO + * too ? */ + if (tp1->do_rtt) { + tp1->whoTo->RTO = + sctp_calculate_rto(stcb, + asoc, + tp1->whoTo, + &tp1->sent_rcv_time); + tp1->whoTo->rto_pending = 0; + tp1->do_rtt = 0; } } } @@ -3117,14 +3115,15 @@ sctp_check_for_revoked(struct sctp_association *asoc, uint32_t cumack, */ if (tp1->sent == SCTP_DATAGRAM_ACKED) { /* it has been revoked */ - /* - * We do NOT add back to flight size here - * since it is really NOT in flight. Resend - * (when/if it occurs will add to flight - * size - */ tp1->sent = SCTP_DATAGRAM_SENT; tp1->rec.data.chunk_was_revoked = 1; + /* + * We must add this stuff back in to assure + * timers and such get started. + */ + tp1->whoTo->flight_size += tp1->book_size; + asoc->total_flight_count++; + asoc->total_flight += tp1->book_size; tot_revoked++; #ifdef SCTP_SACK_LOGGING sctp_log_sack(asoc->last_acked_seq, @@ -3522,7 +3521,13 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->do_rtt = 0; } /* fix counts and things */ - +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); +#endif tp1->whoTo->net_ack++; if (tp1->whoTo->flight_size >= tp1->book_size) tp1->whoTo->flight_size -= tp1->book_size; @@ -3895,7 +3900,8 @@ sctp_cwnd_update(struct sctp_tcb *stcb, */ if (callout_pending(&net->fr_timer.timer)) { SCTP_STAT_INCR(sctps_earlyfrstpidsck2); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); } SCTP_STAT_INCR(sctps_earlyfrstrid); sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); @@ -3903,7 +3909,8 @@ sctp_cwnd_update(struct sctp_tcb *stcb, /* No, stop it if its running */ if (callout_pending(&net->fr_timer.timer)) { SCTP_STAT_INCR(sctps_earlyfrstpidsck3); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); } } } @@ -4071,6 +4078,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, struct sctp_nets *net; struct sctp_association *asoc; struct sctp_tmit_chunk *tp1, *tp2; + int j; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; @@ -4101,16 +4109,14 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, * now no-longer in flight. Higher * values may occur during marking */ - if (tp1->rec.data.chunk_was_revoked == 1) { - /* - * If its been revoked, and - * now ack'd we do NOT take - * away fs etc. since when - * it is retransmitted we - * clear this flag. - */ - goto skip_fs_update; - } +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); +#endif + if (tp1->whoTo->flight_size >= tp1->book_size) { tp1->whoTo->flight_size -= tp1->book_size; } else { @@ -4147,7 +4153,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK); #endif } - skip_fs_update: if (tp1->sent == SCTP_DATAGRAM_RESEND) { sctp_ucount_decr(asoc->sent_queue_retran_cnt); } @@ -4259,6 +4264,8 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, asoc->peers_rwnd = 0; } /* Now assure a timer where data is queued at */ +again: + j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { if (net->flight_size) { int to_ticks; @@ -4268,22 +4275,48 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, } else { to_ticks = MSEC_TO_TICKS(net->RTO); } + j++; callout_reset(&net->rxt_timer.timer, to_ticks, sctp_timeout_handler, &net->rxt_timer); } else { if (callout_pending(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net); + stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); } if (sctp_early_fr) { if (callout_pending(&net->fr_timer.timer)) { SCTP_STAT_INCR(sctps_earlyfrstpidsck4); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_23); } } } } - + if ((j == 0) && (!TAILQ_EMPTY(&asoc->sent_queue)) && (asoc->sent_queue_retran_cnt == 0)) { + /* huh, this should not happen */ +#ifdef INVARIANTS + panic("Flight size incorrect? fixing??"); +#else + printf("Flight size incorrect? fixing\n"); + TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + net->flight_size = 0; + } + asoc->total_flight = 0; + asoc->total_flight_count = 0; + asoc->sent_queue_retran_cnt = 0; + TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->whoTo->flight_size += tp1->book_size; + asoc->total_flight += tp1->book_size; + asoc->total_flight_count++; + } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { + asoc->sent_queue_retran_cnt++; + } + } +#endif + goto again; + } /**********************************/ /* Now what about shutdown issues */ /**********************************/ @@ -4332,8 +4365,9 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000003); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_24); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper); } else { asoc->state = SCTP_STATE_SHUTDOWN_SENT; @@ -4502,8 +4536,9 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000002); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_25); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper); return; } @@ -4536,11 +4571,12 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, /* stop any timers */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); if (sctp_early_fr) { if (callout_pending(&net->fr_timer.timer)) { SCTP_STAT_INCR(sctps_earlyfrstpidsck1); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); } } net->partial_bytes_acked = 0; @@ -4601,16 +4637,13 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, tp1->whoTo->dest_state &= ~SCTP_ADDR_UNCONFIRMED; } - if (tp1->rec.data.chunk_was_revoked == 1) { - /* - * If its been revoked, and - * now ack'd we do NOT take - * away fs etc. since when - * it is retransmitted we - * clear this flag. - */ - goto skip_fs_update; - } +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); +#endif if (tp1->whoTo->flight_size >= tp1->book_size) { tp1->whoTo->flight_size -= tp1->book_size; } else { @@ -4648,7 +4681,6 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, tp1->do_rtt = 0; } } - skip_fs_update: /* * CMT: CUCv2 algorithm. From the * cumack'd TSNs, for each TSN being @@ -4746,14 +4778,15 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, TAILQ_FOREACH(net, &asoc->nets, sctp_next) { if (net->new_pseudo_cumack) sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net); + stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_27); } } else { if (accum_moved) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28); } } } @@ -4868,6 +4901,10 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, if ((tp1->sent > SCTP_DATAGRAM_RESEND) && (tp1->sent < SCTP_FORWARD_TSN_SKIP)) { tp1->sent = SCTP_DATAGRAM_SENT; + tp1->rec.data.chunk_was_revoked = 1; + tp1->whoTo->flight_size += tp1->book_size; + asoc->total_flight_count++; + asoc->total_flight += tp1->book_size; cnt_revoked++; } } @@ -4892,11 +4929,12 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, if (sctp_early_fr) { if (callout_pending(&net->fr_timer.timer)) { SCTP_STAT_INCR(sctps_earlyfrstpidsck4); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); } } sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); net->flight_size = 0; net->partial_bytes_acked = 0; } @@ -4959,8 +4997,9 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000003); + *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_31); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper); return; } else { @@ -5116,7 +5155,7 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net); + stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); } @@ -5220,12 +5259,39 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, * Now we must setup so we have a timer up for anyone with * outstanding data. */ +again: + j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { if (net->flight_size) { + j++; sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); } } + if ((j == 0) && (!TAILQ_EMPTY(&asoc->sent_queue)) && (asoc->sent_queue_retran_cnt == 0)) { + /* huh, this should not happen */ +#ifdef INVARIANTS + panic("Flight size incorrect? fixing??"); +#else + printf("Flight size incorrect? fixing??\n"); + TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + net->flight_size = 0; + } + asoc->total_flight = 0; + asoc->total_flight_count = 0; + asoc->sent_queue_retran_cnt = 0; + TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->whoTo->flight_size += tp1->book_size; + asoc->total_flight += tp1->book_size; + asoc->total_flight_count++; + } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { + asoc->sent_queue_retran_cnt++; + } + } +#endif + goto again; + } #ifdef SCTP_SACK_RWND_LOGGING sctp_misc_ints(SCTP_SACK_RWND_UPDATE, a_rwnd, diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 69d441cdff7f..adeb48b16765 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -100,19 +100,34 @@ extern uint32_t sctp_debug_on; #endif + + +struct sctp_foo_stuff sctp_logoff[30000]; +int sctp_logoff_stuff = 0; + + static void sctp_stop_all_cookie_timers(struct sctp_tcb *stcb) { struct sctp_nets *net; + /* + * This now not only stops all cookie timers it also stops any INIT + * timers as well. This will make sure that the timers are stopped + * in all collision cases. + */ SCTP_TCB_LOCK_ASSERT(stcb); TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if ((callout_pending(&net->rxt_timer.timer)) && - (net->rxt_timer.type == SCTP_TIMER_TYPE_COOKIE)) { + if (net->rxt_timer.type == SCTP_TIMER_TYPE_COOKIE) { sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep, stcb, - net); + net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_1); + } else if (net->rxt_timer.type == SCTP_TIMER_TYPE_INIT) { + sctp_timer_stop(SCTP_TIMER_TYPE_INIT, + stcb->sctp_ep, + stcb, + net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_2); } } } @@ -372,7 +387,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, * No sense in further INIT's since we will get the * same param back */ - sctp_free_assoc(stcb->sctp_ep, stcb, 0); + sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); } return (-1); } @@ -415,7 +430,10 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, * primary. */ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, stcb, - asoc->primary_destination); + asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_4); + + /* calculate the RTO */ + net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered); retval = sctp_send_cookie_echo(m, offset, stcb, net); if (retval < 0) { @@ -453,9 +471,6 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, } return (retval); } - /* calculate the RTO */ - net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered); - return (0); } @@ -548,7 +563,7 @@ sctp_handle_abort(struct sctp_abort_chunk *cp, /* ignore abort for addresses being deleted */ /* stop any receive timers */ - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_5); /* notify user of the abort and clean up... */ sctp_abort_notification(stcb, 0); /* free the tcb */ @@ -557,7 +572,7 @@ sctp_handle_abort(struct sctp_abort_chunk *cp, (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(stcb->sctp_ep, stcb, 0); + sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); #ifdef SCTP_DEBUG if (sctp_debug_on & SCTP_DEBUG_INPUT2) { printf("sctp_handle_abort: finished\n"); @@ -579,9 +594,9 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, #endif if (stcb == NULL) return; - - if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) { + asoc = &stcb->asoc; + if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || + (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { return; } if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_shutdown_chunk)) { @@ -590,18 +605,17 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, } else { sctp_update_acked(stcb, cp, net, abort_flag); } - asoc = &stcb->asoc; - if (stcb->asoc.control_pdapi) { + if (asoc->control_pdapi) { /* * With a normal shutdown we assume the end of last record. */ SCTP_INP_READ_LOCK(stcb->sctp_ep); - stcb->asoc.control_pdapi->end_added = 1; - stcb->asoc.control_pdapi->pdapi_aborted = 1; - if (stcb->asoc.control_pdapi->tail_mbuf) { - stcb->asoc.control_pdapi->tail_mbuf->m_flags |= M_EOR; + asoc->control_pdapi->end_added = 1; + asoc->control_pdapi->pdapi_aborted = 1; + if (asoc->control_pdapi->tail_mbuf) { + asoc->control_pdapi->tail_mbuf->m_flags |= M_EOR; } - stcb->asoc.control_pdapi = NULL; + asoc->control_pdapi = NULL; SCTP_INP_READ_UNLOCK(stcb->sctp_ep); sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); } @@ -625,7 +639,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, * stop the shutdown timer, since we WILL move to * SHUTDOWN-ACK-SENT. */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_7); } /* Now are we there yet? */ some_on_streamwheel = 0; @@ -683,17 +697,17 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp, SCTP_TCB_UNLOCK(stcb); return; } - if (stcb->asoc.control_pdapi) { + if (asoc->control_pdapi) { /* * With a normal shutdown we assume the end of last record. */ SCTP_INP_READ_LOCK(stcb->sctp_ep); - stcb->asoc.control_pdapi->end_added = 1; - stcb->asoc.control_pdapi->pdapi_aborted = 1; - if (stcb->asoc.control_pdapi->tail_mbuf) { - stcb->asoc.control_pdapi->tail_mbuf->m_flags |= M_EOR; + asoc->control_pdapi->end_added = 1; + asoc->control_pdapi->pdapi_aborted = 1; + if (asoc->control_pdapi->tail_mbuf) { + asoc->control_pdapi->tail_mbuf->m_flags |= M_EOR; } - stcb->asoc.control_pdapi = NULL; + asoc->control_pdapi = NULL; SCTP_INP_READ_UNLOCK(stcb->sctp_ep); sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); } @@ -704,7 +718,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp, sctp_report_all_outbound(stcb, 0); } /* stop the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_8); /* send SHUTDOWN-COMPLETE */ sctp_send_shutdown_complete(stcb, net); /* notify upper layer protocol */ @@ -718,7 +732,8 @@ 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, 0); + sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_9); } /* @@ -861,7 +876,7 @@ 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, 0); + sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_10); return (-1); } /* blast back to INIT state */ @@ -1040,7 +1055,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh, SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); /* * collapse the init timer back in case of a exponential - * backoff n + * backoff */ sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep, stcb, net); @@ -1090,7 +1105,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, struct sctp_init_chunk *init_cp, init_buf; struct sctp_init_ack_chunk *initack_cp, initack_buf; int chk_length; - int init_offset, initack_offset; + int init_offset, initack_offset, i; int retval; int spec_flag = 0; @@ -1179,9 +1194,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* Duplicate INIT case */ /* we have already processed the INIT so no problem */ sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, - net); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net); - sctp_stop_all_cookie_timers(stcb); + net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); + sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_12); /* update current state */ if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { asoc->state = SCTP_STATE_OPEN | @@ -1193,6 +1207,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* if ok, move to OPEN state */ asoc->state = SCTP_STATE_OPEN; } + sctp_stop_all_cookie_timers(stcb); if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && (inp->sctp_socket->so_qlimit == 0) @@ -1228,7 +1243,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, */ break; } /* end switch */ - + sctp_stop_all_cookie_timers(stcb); /* * We ignore the return code here.. not sure if we should * somehow abort.. but we do have an existing asoc. This @@ -1240,6 +1255,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, return (NULL); } /* respond with a COOKIE-ACK */ + sctp_toss_old_cookies(stcb, asoc); sctp_send_cookie_ack(stcb); return (stcb); } /* end if */ @@ -1259,8 +1275,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, * case B in Section 5.2.4 Table 2: MXAA or MOAA my info * should be ok, re-accept peer info */ - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_13); sctp_stop_all_cookie_timers(stcb); /* * since we did not send a HB make sure we don't double @@ -1329,6 +1344,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, asoc->state = SCTP_STATE_OPEN; } sctp_stop_all_cookie_timers(stcb); + sctp_toss_old_cookies(stcb, asoc); sctp_send_cookie_ack(stcb); if (spec_flag) { /* @@ -1352,17 +1368,27 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* * case A in Section 5.2.4 Table 2: XXMM (peer restarted) */ - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + /* temp code */ + sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_14); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_15); *sac_assoc_id = sctp_get_associd(stcb); /* notify upper layer */ *notification = SCTP_NOTIFY_ASSOC_RESTART; - - + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_INP_INFO_WLOCK(); + SCTP_INP_WLOCK(stcb->sctp_ep); + SCTP_TCB_LOCK(stcb); + atomic_add_int(&stcb->asoc.refcnt, -1); /* send up all the data */ SCTP_TCB_SEND_LOCK(stcb); - sctp_report_all_outbound(stcb, 1); + sctp_report_all_outbound(stcb, 1); + for (i = 0; i < stcb->asoc.streamoutcnt; i++) { + stcb->asoc.strmout[i].stream_no = i; + stcb->asoc.strmout[i].next_sequence_sent = 0; + stcb->asoc.strmout[i].last_msg_incomplete = 0; + } /* process the INIT-ACK info (my info) */ asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); @@ -1402,6 +1428,9 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, asoc->mapping_array_size); /* process the INIT info (peer's info) */ SCTP_TCB_SEND_UNLOCK(stcb); + SCTP_INP_WUNLOCK(stcb->sctp_ep); + SCTP_INP_INFO_WUNLOCK(); + retval = sctp_process_init(init_cp, stcb, net); if (retval < 0) { return (NULL); @@ -1429,6 +1458,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } /* respond with a COOKIE-ACK */ sctp_stop_all_cookie_timers(stcb); + sctp_toss_old_cookies(stcb, asoc); sctp_send_cookie_ack(stcb); return (stcb); @@ -1584,14 +1614,14 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, /* process the INIT info (peer's info) */ retval = sctp_process_init(init_cp, stcb, *netp); if (retval < 0) { - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); return (NULL); } /* load all addresses */ if (sctp_load_addresses_from_init(stcb, m, iphlen, init_offset + sizeof(struct sctp_init_chunk), initack_offset, sh, init_src)) { - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); return (NULL); } /* @@ -1612,7 +1642,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, if (sctp_debug_on & SCTP_DEBUG_AUTH1) printf("COOKIE-ECHO: AUTH failed\n"); #endif /* SCTP_DEBUG */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18); return (NULL); } else { /* remaining chunks checked... good to go */ @@ -1632,12 +1662,9 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, } else { asoc->state = SCTP_STATE_OPEN; } + sctp_stop_all_cookie_timers(stcb); SCTP_STAT_INCR_COUNTER32(sctps_passiveestab); SCTP_STAT_INCR_GAUGE32(sctps_currestab); - sctp_stop_all_cookie_timers(stcb); - /* calculate the RTT */ - (*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp, - &cookie->time_entered); /* * if we're doing ASCONFs, check to see if we have any new local @@ -1667,7 +1694,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, memcpy(&sin6->sin6_addr, cookie->laddress, sizeof(sin6->sin6_addr)); } else { - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19); return (NULL); } @@ -1710,6 +1737,9 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); } /* respond with a COOKIE-ACK */ + /* calculate the RTT */ + (*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp, + &cookie->time_entered); sctp_send_cookie_ack(stcb); return (stcb); } @@ -1723,7 +1753,7 @@ static struct mbuf * sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp, struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp, - int auth_skipped, uint32_t auth_offset, uint32_t auth_len) + int auth_skipped, uint32_t auth_offset, uint32_t auth_len, struct sctp_tcb **locked_tcb) { struct sctp_state_cookie *cookie; struct sockaddr_in6 sin6; @@ -2014,6 +2044,31 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, if (l_inp != *inp_p) { printf("Bad problem find_ep got a diff inp then special_locate?\n"); } + } else { + if (*locked_tcb == NULL) { + /* + * In this case we found the assoc only + * after we locked the create lock. This + * means we are in a colliding case and we + * must make sure that we unlock the tcb if + * its one of the cases where we throw away + * the incoming packets. + */ + *locked_tcb = *stcb; + + /* + * We must also increment the inp ref count + * since the ref_count flags was set when we + * did not find the TCB, now we found it + * which reduces the refcount.. we must + * raise it back out to balance it all :-) + */ + SCTP_INP_INCR_REF((*stcb)->sctp_ep); + if ((*stcb)->sctp_ep != l_inp) { + printf("Huh? ep:%p diff then l_inp:%p?\n", + (*stcb)->sctp_ep, l_inp); + } + } } } cookie_len -= SCTP_SIGNATURE_SIZE; @@ -2046,7 +2101,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* TSNH! Huh, why do I need to add this address here? */ int ret; - ret = sctp_add_remote_addr(*stcb, to, 0, 100); + ret = sctp_add_remote_addr(*stcb, to, SCTP_DONOT_SETSCOPE, + SCTP_IN_COOKIE_PROC); netl = sctp_findnet(*stcb, to); } if (netl) { @@ -2106,7 +2162,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); - sctp_free_assoc(*inp_p, *stcb, 0); + 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; @@ -2386,10 +2442,10 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp, } } /* stop the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_21); SCTP_STAT_INCR_COUNTER32(sctps_shutdown); /* free the TCB */ - sctp_free_assoc(stcb->sctp_ep, stcb, 0); + sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_22); return; } @@ -2499,11 +2555,18 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, /* restart the timer */ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, tp1->whoTo); + stcb, tp1->whoTo, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23); sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, tp1->whoTo); /* fix counts and things */ +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); +#endif if (tp1->whoTo->flight_size >= tp1->book_size) tp1->whoTo->flight_size -= tp1->book_size; else @@ -2569,7 +2632,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, * this, otherwise we let the timer fire. */ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, - stcb, net); + stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_24); sctp_send_initiate(stcb->sctp_ep, stcb); } break; @@ -2738,7 +2801,7 @@ sctp_clean_up_stream_reset(struct sctp_tcb *stcb) if (stcb->asoc.str_reset == NULL) { return; } - sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo); + sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo, SCTP_FROM_SCTP_INPUT + SCTP_LOC_25); TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); @@ -3460,6 +3523,9 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, */ vtag_in = ntohl(sh->v_tag); + if (locked_tcb) { + SCTP_TCB_LOCK_ASSERT(locked_tcb); + } if (ch->chunk_type == SCTP_INITIATION) { if (vtag_in != 0) { /* protocol error- silently discard... */ @@ -3754,7 +3820,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, SCTP_TCB_UNLOCK(locked_tcb); *offset = length; if (stcb) { - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_26); } return (NULL); } @@ -3972,7 +4038,15 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, process_cookie_anyway: { struct mbuf *ret_buf; + struct sctp_inpcb *linp; + if (stcb) + linp = NULL; + else + linp = inp; + + if (linp) + SCTP_ASOC_CREATE_LOCK(linp); ret_buf = sctp_handle_cookie_echo(m, iphlen, *offset, sh, @@ -3980,8 +4054,10 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, &inp, &stcb, netp, auth_skipped, auth_offset, - auth_len); - + auth_len, + &locked_tcb); + if (linp) + SCTP_ASOC_CREATE_UNLOCK(linp); if (ret_buf == NULL) { if (locked_tcb) { SCTP_TCB_UNLOCK(locked_tcb); @@ -4028,7 +4104,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, if ((stcb) && (stcb->asoc.total_output_queue_size)) { ; } else { - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); *offset = length; return (NULL); } @@ -4117,7 +4193,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, *fwd_tsn_seen = 1; if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_28); *offset = length; return (NULL); } @@ -4142,7 +4218,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, chk_length, chunk_buf); if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); *offset = length; return (NULL); } @@ -4431,7 +4507,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, * Rest should be DATA only. Check authentication state if AUTH for * DATA is required. */ - if ((stcb != NULL) && !sctp_auth_disable && + if ((length > offset) && (stcb != NULL) && !sctp_auth_disable && sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks) && !stcb->asoc.authenticated) { @@ -4441,8 +4517,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, if (sctp_debug_on & SCTP_DEBUG_AUTH1) printf("Data chunk requires AUTH, skipped\n"); #endif - SCTP_TCB_UNLOCK(stcb); - return (1); + goto trigger_send; } if (length > offset) { int retval; @@ -4526,6 +4601,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, } } /* trigger send of any chunks in queue... */ +trigger_send: #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xE0, 2); sctp_auditing(1, inp, stcb, net); @@ -4567,6 +4643,10 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, extern int sctp_no_csum_on_loopback; +int sctp_buf_index = 0; +uint8_t sctp_list_of_chunks[30000]; + + void sctp_input(m, off) struct mbuf *m; @@ -4698,6 +4778,16 @@ sctp_input(m, off) if (mlen < (ip->ip_len - iphlen)) { SCTP_STAT_INCR(sctps_hdrops); goto bad; + } { + /* TEMP log the first chunk */ + int x; + + x = atomic_fetchadd_int(&sctp_buf_index, 1); + if (x > 30000) { + sctp_buf_index = 1; + x = 0;; + } + sctp_list_of_chunks[x] = ch->chunk_type; } /* * Locate pcb and tcb for datagram sctp_findassociation_addr() wants @@ -4736,7 +4826,15 @@ sctp_input(m, off) if (init_chk != NULL) sh->v_tag = init_chk->init.initiate_tag; } - sctp_send_abort(m, iphlen, sh, 0, NULL); + if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { + sctp_send_shutdown_complete2(m, iphlen, sh); + goto bad; + } + if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { + goto bad; + } + if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) + sctp_send_abort(m, iphlen, sh, 0, NULL); goto bad; } else if (stcb == NULL) { refcount_up = 1; diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h index 0121b23bbedf..a60d31b43b76 100644 --- a/sys/netinet/sctp_lock_bsd.h +++ b/sys/netinet/sctp_lock_bsd.h @@ -71,6 +71,10 @@ #include __FBSDID("$FreeBSD$"); + +extern struct sctp_foo_stuff sctp_logoff[]; +extern int sctp_logoff_stuff; + #define SCTP_IPI_COUNT_INIT() #define SCTP_STATLOG_INIT_LOCK() @@ -87,6 +91,7 @@ __FBSDID("$FreeBSD$"); } \ } + #define SCTP_INP_INFO_LOCK_INIT() \ mtx_init(&sctppcbinfo.ipi_ep_mtx, "sctp-info", "inp_info", MTX_DEF) @@ -185,10 +190,37 @@ __FBSDID("$FreeBSD$"); #define SCTP_TCB_SEND_UNLOCK(_tcb) mtx_unlock(&(_tcb)->tcb_send_mtx) +#ifdef INVARIANTS + +#define SCTP_INP_INCR_REF(_inp) { int x; \ + atomic_add_int(&((_inp)->refcount), 1); \ + x = atomic_fetchadd_int(&sctp_logoff_stuff, 1); \ + if(x == 30000) \ + sctp_logoff_stuff = x = 0; \ + sctp_logoff[x].inp = _inp; \ + sctp_logoff[x].ticks = ticks; \ + sctp_logoff[x].lineno = __LINE__; \ + sctp_logoff[x].updown = 1; \ +} + +#define SCTP_INP_DECR_REF(_inp) { int x; \ + if (atomic_fetchadd_int(&((_inp)->refcount), -1) == 0 ) panic("refcount goes negative"); \ + x = atomic_fetchadd_int(&sctp_logoff_stuff, 1); \ + if(x == 30000) \ + sctp_logoff_stuff = x = 0; \ + sctp_logoff[x].inp = _inp; \ + sctp_logoff[x].ticks = ticks; \ + sctp_logoff[x].lineno = __LINE__; \ + sctp_logoff[x].updown = 0; \ +} + +#else #define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1) #define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1) +#endif + #ifdef SCTP_LOCK_LOGGING #define SCTP_ASOC_CREATE_LOCK(_inp) \ do { \ diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index 50847e2cc71a..9b557a2bb97a 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$"); */ typedef struct mbuf *sctp_mbuf_t; +#define USER_ADDR_NULL (NULL) /* FIX ME: temp */ + /* * general memory allocation */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index e71e5acbdcaa..74e1181d88f1 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3617,6 +3617,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* place in my tag */ if ((asoc != NULL) && ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || + (SCTP_GET_STATE(asoc) == SCTP_STATE_INUSE) || (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) { /* re-use the v-tags and init-seq here */ initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); @@ -3929,13 +3930,17 @@ sctp_remove_from_wheel(struct sctp_tcb *stcb, { /* take off and then setup so we know it is not on the wheel */ SCTP_TCB_SEND_LOCK(stcb); + if (TAILQ_FIRST(&strq->outqueue)) { + /* more was added */ + SCTP_TCB_SEND_UNLOCK(stcb); + return; + } TAILQ_REMOVE(&asoc->out_wheel, strq, next_spoke); strq->next_spoke.tqe_next = NULL; strq->next_spoke.tqe_prev = NULL; SCTP_TCB_SEND_UNLOCK(stcb); } - static void sctp_prune_prsctp(struct sctp_tcb *stcb, struct sctp_association *asoc, @@ -4078,7 +4083,7 @@ sctp_set_prsctp_policy(struct sctp_tcb *stcb, sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags); sp->pr_sctp_on = 1; } else { - goto sctp_no_policy; + return; } switch (PR_SCTP_POLICY(sp->sinfo_flags)) { case CHUNK_FLAGS_PR_SCTP_BUF: @@ -4116,13 +4121,8 @@ sctp_set_prsctp_policy(struct sctp_tcb *stcb, break; } } -sctp_no_policy: - if (sp->sinfo_flags & SCTP_UNORDERED) - sp->act_flags |= SCTP_DATA_UNORDERED; - } - static int sctp_msg_append(struct sctp_tcb *stcb, struct sctp_nets *net, @@ -4165,7 +4165,6 @@ sctp_msg_append(struct sctp_tcb *stcb, goto out_now; } SCTP_INCR_STRMOQ_COUNT(); - sp->act_flags = 0; sp->sinfo_flags = srcv->sinfo_flags; sp->timetolive = srcv->sinfo_timetolive; sp->ppid = srcv->sinfo_ppid; @@ -4217,7 +4216,7 @@ sctp_msg_append(struct sctp_tcb *stcb, if ((strm->next_spoke.tqe_next == NULL) && (strm->next_spoke.tqe_prev == NULL)) { /* Not on wheel, insert */ - sctp_insert_on_wheel(stcb, &stcb->asoc, strm, 0); + sctp_insert_on_wheel(stcb, &stcb->asoc, strm, 1); } m = NULL; SCTP_TCB_SEND_UNLOCK(stcb); @@ -4875,6 +4874,13 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb, data_list[i]->sent = SCTP_DATAGRAM_SENT; data_list[i]->snd_count = 1; data_list[i]->rec.data.chunk_was_revoked = 0; +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_UP, + data_list[i]->whoTo->flight_size, + data_list[i]->book_size, + (uintptr_t) stcb, + data_list[i]->rec.data.TSN_seq); +#endif net->flight_size += data_list[i]->book_size; asoc->total_flight += data_list[i]->book_size; asoc->total_flight_count++; @@ -4997,11 +5003,12 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_data_chunk *dchkh; int to_move; uint8_t rcv_flags = 0; + uint8_t some_taken; + uint8_t took_all = 0; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; sp = TAILQ_FIRST(&strq->outqueue); - if (sp == NULL) { *locked = 0; SCTP_TCB_SEND_LOCK(stcb); @@ -5024,6 +5031,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, /* This should not happen */ panic("sp length is 0?"); } + some_taken = sp->some_taken; if ((goal_mtu >= sp->length) && (sp->msg_is_complete)) { /* It all fits and its a complete msg, no brainer */ to_move = min(sp->length, frag_point); @@ -5042,8 +5050,8 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, sp->some_taken = 1; } } else { - to_move = sctp_can_we_split_this(stcb, - sp, goal_mtu, frag_point, eeor_mode); + to_move = sctp_can_we_split_this(stcb, sp, goal_mtu, + frag_point, eeor_mode); if (to_move) { if (to_move >= sp->length) { to_move = sp->length; @@ -5070,11 +5078,17 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, *giveup = 1; return (0); } - /* clear it */ + /* + * Setup for unordered if needed by looking at the user sent info + * flags. + */ + if (sp->sinfo_flags & SCTP_UNORDERED) { + rcv_flags |= SCTP_DATA_UNORDERED; + } + /* clear out the chunk before setting up */ memset(chk, sizeof(*chk), 0); chk->rec.data.rcv_flags = rcv_flags; SCTP_TCB_SEND_LOCK(stcb); - sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk)); if (sp->data->m_flags & M_EXT) { chk->copy_by_ref = 1; } else { @@ -5086,21 +5100,21 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, chk->last_mbuf = sp->tail_mbuf; /* register the stealing */ sp->data = sp->tail_mbuf = NULL; + took_all = 1; } else { struct mbuf *m; chk->data = m_copym(sp->data, 0, to_move, M_DONTWAIT); chk->last_mbuf = NULL; if (chk->data == NULL) { + sp->some_taken = some_taken; sctp_free_a_chunk(stcb, chk); SCTP_TCB_SEND_UNLOCK(stcb); goto out_gu; } /* Pull off the data */ m_adj(sp->data, to_move); - /* - * Now lets work our way down and compact it - */ + /* Now lets work our way down and compact it */ m = sp->data; while (m && (m->m_len == 0)) { sp->data = m->m_next; @@ -5115,8 +5129,9 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, } if (to_move > sp->length) { panic("Huh, how can to_move be larger?"); - } else + } else { sp->length -= to_move; + } /* Update the new length in */ if (sp->data && (sp->data->m_flags & M_PKTHDR)) { @@ -5129,7 +5144,31 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, m = sctp_get_mbuf_for_msg(1, 1, M_DONTWAIT, 0, MT_DATA); if (m == NULL) { - printf("We will Panic maybe, out of mbufs\n"); + /* + * we're in trouble here. M_PREPEND below will free + * all the data if there is no leading space, so we + * must put the data back and restore. + */ + if (took_all) { + /* unsteal the data */ + sp->data = chk->data; + sp->tail_mbuf = chk->last_mbuf; + } else { + struct mbuf *m; + + /* reassemble the data */ + m = sp->data; + sp->data = chk->data; + sp->data->m_next = m; + } + sp->some_taken = some_taken; + sp->length += to_move; + if (sp->data && (sp->data->m_flags & M_PKTHDR)) { + sp->data->m_pkthdr.len = sp->length; + } + sctp_free_a_chunk(stcb, chk); + SCTP_TCB_SEND_UNLOCK(stcb); + goto out_gu; } else { m->m_len = 0; m->m_next = chk->data; @@ -5145,7 +5184,9 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, SCTP_TCB_SEND_UNLOCK(stcb); goto out_gu; } - chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk)); + sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk)); + chk->book_size = chk->send_size = (to_move + + sizeof(struct sctp_data_chunk)); chk->sent = SCTP_DATAGRAM_UNSENT; /* @@ -5196,9 +5237,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq); dchkh->dp.protocol_id = chk->rec.data.payloadtype; dchkh->ch.chunk_length = htons(chk->send_size); - /* - * Now advance the chk->send_size by the actual pad needed. - */ + /* Now advance the chk->send_size by the actual pad needed. */ if (chk->send_size < SCTP_SIZE32(chk->book_size)) { /* need a pad */ struct mbuf *lm; @@ -5218,9 +5257,9 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, chk->send_size += pads; } /* We only re-set the policy if it is on */ - if (sp->pr_sctp_on) + if (sp->pr_sctp_on) { sctp_set_prsctp_policy(stcb, sp); - + } if (sp->msg_is_complete && (sp->length == 0)) { /* All done pull and kill the message */ asoc->stream_queue_cnt--; @@ -5754,7 +5793,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, /* turn off the timer */ if (callout_pending(&stcb->asoc.dack_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - inp, stcb, net); + inp, stcb, net, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1); } } ctl_cnt++; @@ -5991,7 +6030,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, to_out += chk->send_size; if (to_out > mx_mtu) { -#ifdef INVARIENT +#ifdef INVARIANTS panic("gag"); #else printf("Exceeding mtu of %d out size is %d\n", @@ -6135,7 +6174,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, if (net->flight_size < net->cwnd) { /* start or restart it */ if (callout_pending(&net->fr_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2); } SCTP_STAT_INCR(sctps_earlyfrstrout); sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net); @@ -6143,7 +6183,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, /* stop it if its running */ if (callout_pending(&net->fr_timer.timer)) { SCTP_STAT_INCR(sctps_earlyfrstpout); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3); } } } @@ -7032,6 +7073,13 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, if (asoc->sent_queue_retran_cnt < 0) { asoc->sent_queue_retran_cnt = 0; } +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_UP, + data_list[i]->whoTo->flight_size, + data_list[i]->book_size, + (uintptr_t) stcb, + data_list[i]->rec.data.TSN_seq); +#endif net->flight_size += data_list[i]->book_size; asoc->total_flight += data_list[i]->book_size; if (data_list[i]->book_size_scale) { @@ -7069,7 +7117,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, * SACK back without a * t3-expiring. */ - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4); sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } } @@ -7617,7 +7666,7 @@ sctp_send_sack(struct sctp_tcb *stcb) if (a_chk == NULL) { /* No memory so we drop the idea, and set a timer */ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); + stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5); sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL); return; @@ -7686,7 +7735,7 @@ sctp_send_sack(struct sctp_tcb *stcb) atomic_subtract_int(&a_chk->whoTo->ref_count, 1); sctp_free_a_chunk(stcb, a_chk); sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); + stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL); return; @@ -8234,6 +8283,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net) } /* ok we have a destination that needs a beat */ /* lets do the theshold management Qiaobing style */ + if (sctp_threshold_management(stcb->sctp_ep, stcb, net, stcb->asoc.max_send_times)) { /* @@ -9324,6 +9374,12 @@ sctp_lower_sosend(struct socket *so, stcb = NULL; asoc = NULL; t_inp = inp = (struct sctp_inpcb *)so->so_pcb; + if (inp == NULL) { + error = EFAULT; + splx(s); + goto out_unlocked; + } + atomic_add_int(&inp->total_sends, 1); if (uio) sndlen = uio->uio_resid; else @@ -9340,6 +9396,9 @@ sctp_lower_sosend(struct socket *so, goto out_unlocked; } if ((use_rcvinfo) && srcv) { + if (srcv->sinfo_flags) + SCTP_STAT_INCR(sctps_sends_with_flags); + if (srcv->sinfo_flags & SCTP_SENDALL) { /* its a sendall */ error = sctp_sendall(inp, uio, top, srcv); @@ -9414,6 +9473,18 @@ sctp_lower_sosend(struct socket *so, splx(s); goto out_unlocked; } + SCTP_INP_WLOCK(inp); + SCTP_INP_INCR_REF(inp); + SCTP_INP_WUNLOCK(inp); + /* With the lock applied look again */ + stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); + if (stcb == NULL) { + SCTP_INP_WLOCK(inp); + SCTP_INP_DECR_REF(inp); + SCTP_INP_WUNLOCK(inp); + } else { + hold_tcblock = 1; + } } if (stcb == NULL) { if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { @@ -9575,6 +9646,7 @@ sctp_lower_sosend(struct socket *so, (stcb->asoc.chunks_on_out_queue > sctp_max_chunks_on_queue)) { error = EWOULDBLOCK; + atomic_add_int(&stcb->sctp_ep->total_nospaces, 1); splx(s); goto out_unlocked; } @@ -9661,6 +9733,7 @@ sctp_lower_sosend(struct socket *so, struct mbuf *mm; int tot_demand, tot_out, max; + SCTP_STAT_INCR(sctps_sends_with_abort); if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { /* It has to be up before we abort */ @@ -9806,6 +9879,7 @@ sctp_lower_sosend(struct socket *so, if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { goto out_unlocked; } + atomic_add_int(&stcb->total_sends, 1); if (top == NULL) { struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strm; @@ -9831,6 +9905,7 @@ sctp_lower_sosend(struct socket *so, strm = &stcb->asoc.strmout[srcv->sinfo_stream]; user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); if (strm->last_msg_incomplete == 0) { + do_a_copy_in: sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error, non_blocking); if ((sp == NULL) || (error)) { goto out; @@ -9860,7 +9935,10 @@ sctp_lower_sosend(struct socket *so, (uint32_t) ((srcv->sinfo_stream << 16) | sp->strseq), 0); #endif strm->next_sequence_sent++; + } else { + SCTP_STAT_INCR(sctps_sends_with_unord); } + if ((strm->next_spoke.tqe_next == NULL) && (strm->next_spoke.tqe_prev == NULL)) { /* Not on wheel, insert */ @@ -9869,6 +9947,17 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_SEND_UNLOCK(stcb); } else { sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); + if (sp == NULL) { + /* ???? Huh ??? last msg is gone */ +#ifdef INVARIANTS + panic("Warning: Last msg marked incomplete, yet nothing left?"); +#else + printf("Warning: Last msg marked incomplete, yet nothing left?\n"); + strm->last_msg_incomplete = 0; +#endif + goto do_a_copy_in; + + } } while (uio->uio_resid > 0) { /* How much room do we have? */ @@ -10019,11 +10108,16 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK(stcb); hold_tcblock = 1; } - sctp_send_initiate(inp, stcb); - queue_only_for_init = 0; - queue_only = 1; - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = 0; + if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + /* a collision took us forward? */ + queue_only_for_init = 0; + queue_only = 0; + } else { + sctp_send_initiate(inp, stcb); + stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; + queue_only_for_init = 0; + queue_only = 1; + } } if ((queue_only == 0) && (nagle_applies == 0) ) { @@ -10126,6 +10220,7 @@ sctp_lower_sosend(struct socket *so, (got_all_of_the_send == 1) && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) ) { + SCTP_STAT_INCR(sctps_sends_with_eof); error = 0; if (hold_tcblock == 0) { SCTP_TCB_LOCK(stcb); @@ -10255,9 +10350,16 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK(stcb); hold_tcblock = 1; } - sctp_send_initiate(inp, stcb); - queue_only_for_init = 0; - queue_only = 1; + if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + /* a collision took us forward? */ + queue_only_for_init = 0; + queue_only = 0; + } else { + sctp_send_initiate(inp, stcb); + stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; + queue_only_for_init = 0; + queue_only = 1; + } } if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) { /* we can attempt to send too. */ @@ -10317,7 +10419,7 @@ sctp_lower_sosend(struct socket *so, if (stcb && free_cnt_applied) { atomic_add_int(&stcb->asoc.refcnt, -1); } -#ifdef INVARIENTS +#ifdef INVARIANTS if (stcb) { if (mtx_owned(&stcb->tcb_mtx)) { panic("Leaving with tcb mtx owned?"); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index fb74b444e987..89e649bb94e4 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -408,7 +408,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } /* now look at the list of remote addresses */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { -#ifdef INVARIENTS +#ifdef INVARIANTS if (net == (TAILQ_NEXT(net, sctp_next))) { panic("Corrupt net list"); } @@ -481,7 +481,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, /* now look at the list of remote addresses */ SCTP_TCB_LOCK(stcb); TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { -#ifdef INVARIENTS +#ifdef INVARIANTS if (net == (TAILQ_NEXT(net, sctp_next))) { panic("Corrupt net list"); } @@ -603,7 +603,7 @@ sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int SCTP_INP_RUNLOCK(stcb->sctp_ep); } /* Ok if we missed here, lets try the restart hash */ - head = &sctppcbinfo.sctp_asochash[SCTP_PCBHASH_ASOC(id, sctppcbinfo.hashrestartmark)]; + head = &sctppcbinfo.sctp_restarthash[SCTP_PCBHASH_ASOC(id, sctppcbinfo.hashrestartmark)]; if (head == NULL) { /* invalid id TSNH */ SCTP_INP_INFO_RUNLOCK(); @@ -1456,6 +1456,10 @@ sctp_inpcb_alloc(struct socket *so) LIST_INIT(&inp->sctp_addr_list); LIST_INIT(&inp->sctp_asoc_list); +#ifdef SCTP_TRACK_FREED_ASOCS + /* TEMP CODE */ + LIST_INIT(&inp->sctp_asoc_free_list); +#endif /* Init the timer structure for signature change */ callout_init(&inp->sctp_ep.signature_change.timer, 1); inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NEWCOOKIE; @@ -2103,7 +2107,8 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) */ inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP; } - sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL, + SCTP_FROM_SCTP_PCB + SCTP_LOC_1); if (inp->control) { sctp_m_freem(inp->control); @@ -2134,7 +2139,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_ECHOED)) { /* Just abandon things in the front states */ if (asoc->asoc.total_output_queue_size == 0) { - sctp_free_assoc(inp, asoc, 1); + sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_2); continue; } } @@ -2165,15 +2170,16 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000004); + *ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_3); } + asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3; sctp_send_abort_tcb(asoc, op_err); SCTP_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, asoc, 1); + sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_4); continue; } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && @@ -2241,15 +2247,16 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000005); + *ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_5); } + asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5; sctp_send_abort_tcb(asoc, op_err); SCTP_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, asoc, 1); + sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_6); continue; } } @@ -2258,23 +2265,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } /* now is there some left in our SHUTDOWN state? */ if (cnt_in_sd) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) != - SCTP_PCB_FLAGS_UNBOUND) { - /* - * ok, this guy has been bound. It's port is - * somewhere in the sctppcbinfo hash table. - * Remove it! - * - * Note we are depending on lookup by vtag to - * find associations that are dieing. This - * free's the port so we don't have to block - * its useage. The SCTP_PCB_FLAGS_UNBOUND - * flags will prevent us from doing this - * again. - */ - LIST_REMOVE(inp, sctp_hash); - inp->sctp_flags |= SCTP_PCB_FLAGS_UNBOUND; - } splx(s); SCTP_INP_WUNLOCK(inp); @@ -2329,9 +2319,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000006); + *ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_7); } + asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_7; sctp_send_abort_tcb(asoc, op_err); SCTP_STAT_INCR_COUNTER32(sctps_aborted); } else if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { @@ -2343,7 +2334,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); } - sctp_free_assoc(inp, asoc, 2); + sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8); } if (cnt) { /* Ok we have someone out there that will kill us */ @@ -2457,6 +2448,18 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr); SCTP_DECR_LADDR_COUNT(); } + +#ifdef SCTP_TRACK_FREED_ASOCS + /* TEMP CODE */ + for ((asoc = LIST_FIRST(&inp->sctp_asoc_free_list)); asoc != NULL; + asoc = nasoc) { + nasoc = LIST_NEXT(asoc, sctp_tcblist); + LIST_REMOVE(asoc, sctp_tcblist); + SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, asoc); + SCTP_DECR_ASOC_COUNT(); + } + /* *** END TEMP CODE *** */ +#endif /* Now lets see about freeing the EP hash table. */ if (inp->sctp_tcbhash != NULL) { SCTP_FREE(inp->sctp_tcbhash); @@ -2611,7 +2614,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, stcb->asoc.site_scope = 1; } } else { - if (from == 8) { + if (from == SCTP_ADDR_IS_CONFIRMED) { /* From connectx */ if (sctp_is_address_on_local_host(newaddr)) { stcb->asoc.loopback_scope = 1; @@ -2661,8 +2664,8 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, stcb->asoc.site_scope = 1; } } else { - if (from == 8) { - /* From connectx */ + if (from == SCTP_ADDR_IS_CONFIRMED) { + /* From connectx so we check for localhost. */ if (sctp_is_address_on_local_host(newaddr)) { stcb->asoc.loopback_scope = 1; stcb->asoc.ipv4_local_scope = 1; @@ -2704,8 +2707,8 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, net->dest_state = (SCTP_ADDR_REACHABLE | SCTP_ADDR_OUT_OF_SCOPE); } else { - if (from == 8) - /* 8 is passed by connect_x */ + if (from == SCTP_ADDR_IS_CONFIRMED) + /* SCTP_ADDR_IS_CONFIRMED is passed by connect_x */ net->dest_state = SCTP_ADDR_REACHABLE; else net->dest_state = SCTP_ADDR_REACHABLE | @@ -2747,7 +2750,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, if ((net->ro.ro_rt) && (net->ro.ro_rt->rt_ifp)) { net->mtu = net->ro.ro_rt->rt_ifp->if_mtu; - if (from == 1) { + if (from == SCTP_ALLOC_ASOC) { stcb->asoc.smallest_mtu = net->mtu; } /* start things off to match mtu of interface please. */ @@ -3001,7 +3004,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, LIST_INSERT_HEAD(head, stcb, sctp_asocs); SCTP_INP_INFO_WUNLOCK(); - if ((err = sctp_add_remote_addr(stcb, firstaddr, 1, 1))) { + if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { /* failure.. memory error? */ if (asoc->strmout) SCTP_FREE(asoc->strmout); @@ -3210,7 +3213,7 @@ sctp_iterator_asoc_being_freed(struct sctp_inpcb *inp, struct sctp_tcb *stcb) * Free the association after un-hashing the remote port. */ int -sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfree) +sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfree, int from_location) { int i; struct sctp_association *asoc; @@ -3240,6 +3243,13 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* there is no asoc, really TSNH :-0 */ return (1); } + /* TEMP CODE */ + if (stcb->freed_from_where == 0) { + /* Only record the first place free happened from */ + stcb->freed_from_where = from_location; + } + /* TEMP CODE */ + asoc = &stcb->asoc; if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) @@ -3254,7 +3264,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre * if so we abort early if a reader or writer is still in the way. */ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) && - (from_inpcbfree == 0)) { + (from_inpcbfree == SCTP_NORMAL_PROC)) { /* * is it the timer driving us? if so are the reader/writers * gone? @@ -3286,6 +3296,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre callout_stop(&net->pmtu_timer.timer); } /* Now the read queue needs to be cleaned up (only once) */ + cnt = 0; if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { SCTP_INP_READ_LOCK(inp); TAILQ_FOREACH(sq, &inp->read_queue, next) { @@ -3322,23 +3333,33 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } SCTP_INP_READ_UNLOCK(inp); if (stcb->block_entry) { + cnt++; stcb->block_entry->error = ECONNRESET; stcb->block_entry = NULL; } } stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED; - if ((from_inpcbfree != 2) && (stcb->asoc.refcnt)) { + if ((from_inpcbfree != SCTP_PCBFREE_FORCE) && (stcb->asoc.refcnt)) { /* * reader or writer in the way, we have hopefully given him * something to chew on above. */ - if (so) { - /* Wake any reader/writers */ - sctp_sorwakeup(inp, so); - sctp_sowwakeup(inp, so); - } sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); SCTP_TCB_UNLOCK(stcb); + if (so) { + SCTP_INP_RLOCK(inp); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) + /* nothing around */ + so = NULL; + if (so) { + /* Wake any reader/writers */ + sctp_sorwakeup(inp, so); + sctp_sowwakeup(inp, so); + } + SCTP_INP_RUNLOCK(inp); + + } splx(s); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 9); @@ -3349,9 +3370,32 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 10); #endif - if ((from_inpcbfree == 0) && so) { - sctp_sorwakeup(inp, so); + /* + * When I reach here, no others want to kill the assoc yet.. and I + * own the lock. Now its possible an abort comes in when I do the + * lock exchange below to grab all the locks to do the final take + * out. to prevent this we increment the count, which will start a + * timer and blow out above thus assuring us that we hold exclusive + * killing of the asoc. Note that after getting back the TCB lock we + * will go ahead and increment the counter back up and stop any + * timer a passing stranger may have started :-S + */ + if (from_inpcbfree == SCTP_NORMAL_PROC) { + atomic_add_int(&stcb->asoc.refcnt, 1); + + SCTP_TCB_UNLOCK(stcb); + + SCTP_ITERATOR_LOCK(); + SCTP_INP_INFO_WLOCK(); + SCTP_INP_WLOCK(inp); + SCTP_TCB_LOCK(stcb); } + /* Double check the GONE flag */ + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) + /* nothing around */ + so = NULL; + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { /* @@ -3376,26 +3420,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } } - /* - * When I reach here, no others want to kill the assoc yet.. and I - * own the lock. Now its possible an abort comes in when I do the - * lock exchange below to grab all the locks to do the final take - * out. to prevent this we increment the count, which will start a - * timer and blow out above thus assuring us that we hold exclusive - * killing of the asoc. Note that after getting back the TCB lock we - * will go ahead and increment the counter back up and stop any - * timer a passing stranger may have started :-S - */ - if (from_inpcbfree == 0) { - atomic_add_int(&stcb->asoc.refcnt, 1); - - SCTP_TCB_UNLOCK(stcb); - - SCTP_ITERATOR_LOCK(); - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); - SCTP_TCB_LOCK(stcb); - } /* Stop any timer someone may have started */ callout_stop(&asoc->strreset_timer.timer); /* @@ -3405,7 +3429,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE; sctp_iterator_asoc_being_freed(inp, stcb); /* re-increment the lock */ - if (from_inpcbfree == 0) { + if (from_inpcbfree == SCTP_NORMAL_PROC) { atomic_add_int(&stcb->asoc.refcnt, -1); } /* now restop the timers to be sure - this is paranoia at is finest! */ @@ -3431,7 +3455,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } /* Now lets remove it from the list of ALL associations in the EP */ LIST_REMOVE(stcb, sctp_tcblist); - if (from_inpcbfree == 0) { + if (from_inpcbfree == SCTP_NORMAL_PROC) { SCTP_INP_INCR_REF(inp); SCTP_INP_WUNLOCK(inp); SCTP_ITERATOR_UNLOCK(); @@ -3440,9 +3464,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre LIST_REMOVE(stcb, sctp_asocs); sctp_add_vtag_to_timewait(inp, asoc->my_vtag); - if (from_inpcbfree == 0) { - SCTP_INP_INFO_WUNLOCK(); - } prev = NULL; /* * The chunk lists and such SHOULD be empty but we check them just @@ -3651,7 +3672,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre net = TAILQ_FIRST(&asoc->nets); /* pull from list */ if ((sctppcbinfo.ipi_count_raddr == 0) || (prev == net)) { -#ifdef INVARIENTS +#ifdef INVARIANTS panic("no net's left alloc'ed, or list points to itself"); #endif break; @@ -3703,12 +3724,23 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Get rid of LOCK */ SCTP_TCB_LOCK_DESTROY(stcb); SCTP_TCB_SEND_LOCK_DESTROY(stcb); - /* now clean up the tasoc itself */ + if (from_inpcbfree == SCTP_NORMAL_PROC) { + SCTP_INP_INFO_WUNLOCK(); + SCTP_INP_RLOCK(inp); + } +#ifdef SCTP_TRACK_FREED_ASOCS + if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { + /* now clean up the tasoc itself */ + SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb); + SCTP_DECR_ASOC_COUNT(); + } else { + LIST_INSERT_HEAD(&inp->sctp_asoc_free_list, stcb, sctp_tcblist); + } +#else SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb); SCTP_DECR_ASOC_COUNT(); - - if (from_inpcbfree == 0) { - SCTP_INP_RLOCK(inp); +#endif + if (from_inpcbfree == SCTP_NORMAL_PROC) { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* * If its NOT the inp_free calling us AND sctp_close @@ -3724,12 +3756,16 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre */ sctp_inpcb_free(inp, 0, 0); SCTP_INP_DECR_REF(inp); + goto out_of; } else { /* The socket is still open. */ SCTP_INP_DECR_REF(inp); - SCTP_INP_RUNLOCK(inp); } } + if (from_inpcbfree == SCTP_NORMAL_PROC) { + SCTP_INP_RUNLOCK(inp); + } +out_of: splx(s); /* destroyed the asoc */ #ifdef SCTP_LOG_CLOSING @@ -4247,6 +4283,7 @@ sctp_pcb_init() SCTP_INP_INFO_LOCK_INIT(); SCTP_STATLOG_INIT_LOCK(); SCTP_ITERATOR_LOCK_INIT(); + SCTP_IPI_COUNT_INIT(); SCTP_IPI_ADDR_INIT(); LIST_INIT(&sctppcbinfo.addr_wq); @@ -4384,12 +4421,12 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* no scope set here since we have a tcb already. */ if ((sa->sa_family == AF_INET) && (stcb->asoc.ipv4_addr_legal)) { - if (sctp_add_remote_addr(stcb, sa, 0, 2)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { return (-1); } } else if ((sa->sa_family == AF_INET6) && (stcb->asoc.ipv6_addr_legal)) { - if (sctp_add_remote_addr(stcb, sa, 0, 3)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { return (-2); } } @@ -4457,7 +4494,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* the assoc was freed? */ return (-7); } - if (sctp_add_remote_addr(stcb, sa, 0, 4)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { return (-8); } } else if (stcb_tmp == stcb) { @@ -4516,7 +4553,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * we must add the address, no scope * set */ - if (sctp_add_remote_addr(stcb, sa, 0, 5)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { return (-17); } } else if (stcb_tmp == stcb) { @@ -5039,6 +5076,7 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) /* We look for anything larger than the cum-ack + 1 */ + SCTP_STAT_INCR(sctps_protocol_drain_calls); if (sctp_do_drain == 0) { return; } @@ -5047,6 +5085,7 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) /* none we can reneg on. */ return; } + SCTP_STAT_INCR(sctps_protocol_drains_done); cumulative_tsn_p1 = asoc->cumulative_tsn + 1; cnt = 0; /* First look in the re-assembly queue */ diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 1e0750fbecdc..82f7db26f28f 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -198,6 +198,7 @@ struct sctp_epinfo { struct mtx ipi_ep_mtx; struct mtx it_mtx; struct mtx ipi_addr_mtx; + struct mtx timer_mtx; uint32_t ipi_count_ep; /* assoc/tcb zone info */ @@ -342,6 +343,9 @@ struct sctp_inpcb { u_long sctp_hashmark; /* head of the list of all associations */ struct sctpasochead sctp_asoc_list; +#ifdef SCTP_TRACK_FREED_ASOCS + struct sctpasochead sctp_asoc_free_list; +#endif struct sctp_iterator *inp_starting_point_for_iterator; uint32_t sctp_frag_point; uint32_t partial_delivery_point; @@ -359,6 +363,10 @@ struct sctp_inpcb { struct mtx inp_create_mtx; struct mtx inp_rdata_mtx; int32_t refcount; + uint32_t total_sends; + uint32_t total_recvs; + uint32_t last_abort_code; + uint32_t total_nospaces; }; struct sctp_tcb { @@ -380,6 +388,9 @@ struct sctp_tcb { * in the reading of data. */ uint32_t freed_by_sorcv_sincelast; + uint32_t total_sends; + uint32_t total_recvs; + int freed_from_where; uint16_t rport; /* remote port in network format */ uint16_t resv; struct mtx tcb_mtx; @@ -450,7 +461,7 @@ struct sctp_tcb * sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, int, int *, uint32_t); -int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int); +int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int); int sctp_add_local_addr_ep(struct sctp_inpcb *, struct ifaddr *); diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index cfa4a2d3479b..2589598e601c 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -210,7 +210,8 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE); n_inp->sctp_ep.auto_close_time = 0; - sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, n_inp, stcb, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, n_inp, stcb, NULL, + SCTP_FROM_SCTP_PEELOFF + SCTP_LOC_1); } /* Turn off any non-blocking semantic. */ newso->so_state &= ~SS_NBIO; diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index 6472c2f2e113..9f4e9d099df6 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -64,6 +64,7 @@ struct sctp_timer { /* for sanity checking */ void *self; uint32_t ticks; + uint32_t stopped_from; }; struct sctp_nonpad_sndrcvinfo { @@ -78,6 +79,13 @@ struct sctp_nonpad_sndrcvinfo { sctp_assoc_t sinfo_assoc_id; }; +struct sctp_foo_stuff { + struct sctp_inpcb *inp; + uint32_t lineno; + uint32_t ticks; + int updown; +}; + /* * This is the information we track on each interface that we know about from @@ -284,7 +292,7 @@ struct sctp_data_chunkrec { struct timeval timetodrop; /* time we drop it from queue */ uint8_t doing_fast_retransmit; uint8_t rcv_flags; /* flags pulled from data chunk on inbound for - * outbound holds sending flags. */ + * outbound holds sending flags for PR-SCTP. */ uint8_t state_flags; uint8_t chunk_was_revoked; }; @@ -395,12 +403,11 @@ struct sctp_stream_queue_pending { uint16_t sinfo_flags; uint16_t stream; uint16_t strseq; + uint16_t act_flags; uint8_t msg_is_complete; uint8_t some_taken; uint8_t addr_over; - uint8_t act_flags; uint8_t pr_sctp_on; - uint8_t resv; }; /* diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 6ac0b7faba9f..dc55ef66ffaa 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -324,8 +324,9 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x40000001); + *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); } + inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1; sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper); return (1); } @@ -681,7 +682,19 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, stcb->asoc.total_flight_count--; chk->sent = SCTP_DATAGRAM_RESEND; SCTP_STAT_INCR(sctps_markedretrans); - net->flight_size -= chk->book_size; +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + chk->whoTo->flight_size, + chk->book_size, + (uintptr_t) stcb, + chk->rec.data.TSN_seq); +#endif + + if (net->flight_size >= chk->book_size) + net->flight_size -= chk->book_size; + else + net->flight_size = 0; + stcb->asoc.peers_rwnd += chk->send_size; stcb->asoc.peers_rwnd += sctp_peer_chunk_oh; @@ -747,7 +760,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, could_be_sent->sent = SCTP_DATAGRAM_RESEND; } if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { -#ifdef INVARIENTS +#ifdef INVARIANTS printf("Local Audit says there are %d for retran asoc cnt:%d\n", cnt_mk, stcb->asoc.sent_queue_retran_cnt); #endif @@ -789,6 +802,13 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, } TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { if (chk->sent < SCTP_DATAGRAM_RESEND) { +#ifdef SCTP_FLIGHT_LOGGING + sctp_misc_ints(SCTP_FLIGHT_LOG_UP, + chk->whoTo->flight_size, + chk->book_size, + (uintptr_t) stcb, + chk->rec.data.TSN_seq); +#endif stcb->asoc.total_flight += chk->book_size; chk->whoTo->flight_size += chk->book_size; stcb->asoc.total_flight_count++; @@ -1077,12 +1097,13 @@ sctp_cookie_timer(struct sctp_inpcb *inp, ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); ph->param_length = htons(oper->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x40000002); + *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_2); } + inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3; sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR, oper); } else { -#ifdef INVARIENTS +#ifdef INVARIANTS panic("Cookie timer expires in wrong state?"); #else printf("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 0c308ae878d2..f12f0b999252 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -853,13 +853,13 @@ struct sctpstat { u_long sctps_cmt_randry;/* Same for above */ u_long sctps_slowpath_sack; /* Sacks the slow way */ u_long sctps_wu_sacks_sent; /* Window Update only sacks sent */ - u_long sctps_locks_in_rcv; /* How man so_rcv buf locks we did */ - u_long sctps_locks_in_rcva; /* How man so_rcv buf locks we did */ - u_long sctps_locks_in_rcvb; /* How man so_rcv buf locks we did */ - u_long sctps_locks_in_rcvc; /* How man so_rcv buf locks we did */ - u_long sctps_locks_in_rcvd; /* How man so_rcv buf locks we did */ - u_long sctps_locks_in_rcve; /* How man so_rcv buf locks we did */ - u_long sctps_locks_in_rcvf; /* How man so_rcv buf locks we did */ + u_long sctps_sends_with_flags; /* number of sends with sinfo_flags + * !=0 */ + u_long sctps_sends_with_unord; + u_long sctps_sends_with_eof; + u_long sctps_sends_with_abort; + u_long sctps_protocol_drain_calls; + u_long sctps_protocol_drains_done; }; #define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1) @@ -884,6 +884,47 @@ union sctp_sockstore { struct sockaddr sa; }; +struct xsctp_inpcb { + uint32_t last; + uint16_t local_port; + uint16_t number_local_addresses; + uint32_t number_associations; + uint32_t flags; + uint32_t features; + uint32_t total_sends; + uint32_t total_recvs; + uint32_t total_nospaces; + /* add more endpoint specific data here */ +}; + +struct xsctp_tcb { + uint16_t remote_port; + uint16_t number_local_addresses; + uint16_t number_remote_addresses; + uint16_t number_incomming_streams; + uint16_t number_outgoing_streams; + uint32_t state; + uint32_t total_sends; + uint32_t total_recvs; + uint32_t local_tag; + uint32_t remote_tag; + uint32_t initial_tsn; + uint32_t highest_tsn; + uint32_t cumulative_tsn; + uint32_t cumulative_tsn_ack; + /* add more association specific data here */ +}; + +struct xsctp_laddr { + union sctp_sockstore address; + /* add more local address specific data */ +}; + +struct xsctp_raddr { + union sctp_sockstore address; + uint16_t state; + /* add more remote address specific data */ +}; /* * Kernel defined for sctp_send diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 58e761690523..c650e352be35 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -316,7 +316,8 @@ sctp_notify_mbuf(struct sctp_inpcb *inp, /* Stop any PMTU timer */ if (callout_pending(&net->pmtu_timer.timer)) { tmr_stopped = 1; - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); } /* Adjust destination size limit */ if (net->mtu > nxtsz) { @@ -386,7 +387,7 @@ sctp_notify(struct sctp_inpcb *inp, * TCB */ sctp_abort_notification(stcb, SCTP_PEER_FAULTY); - sctp_free_assoc(inp, stcb, 0); + 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 { @@ -541,6 +542,184 @@ sctp_getcred(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); +static int +sctp_assoclist(SYSCTL_HANDLER_ARGS) +{ + unsigned int number_of_endpoints; + unsigned int number_of_local_addresses; + unsigned int number_of_associations; + unsigned int number_of_remote_addresses; + unsigned int n; + int error; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctp_laddr *laddr; + struct xsctp_inpcb xinpcb; + struct xsctp_tcb xstcb; + +/* struct xsctp_laddr xladdr; */ + struct xsctp_raddr xraddr; + + number_of_endpoints = 0; + number_of_local_addresses = 0; + number_of_associations = 0; + number_of_remote_addresses = 0; + + SCTP_INP_INFO_RLOCK(); + if (req->oldptr == USER_ADDR_NULL) { + LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) { + SCTP_INP_RLOCK(inp); + number_of_endpoints++; + /* FIXME MT */ + LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { + number_of_local_addresses++; + } + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + number_of_associations++; + /* FIXME MT */ + LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) { + number_of_local_addresses++; + } + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + number_of_remote_addresses++; + } + } + SCTP_INP_RUNLOCK(inp); + } + SCTP_INP_INFO_RUNLOCK(); + n = (number_of_endpoints + 1) * sizeof(struct xsctp_inpcb) + + number_of_local_addresses * sizeof(struct xsctp_laddr) + + number_of_associations * sizeof(struct xsctp_tcb) + + number_of_remote_addresses * sizeof(struct xsctp_raddr); +#ifdef SCTP_DEBUG + printf("inps = %u, stcbs = %u, laddrs = %u, raddrs = %u\n", + number_of_endpoints, number_of_associations, + number_of_local_addresses, number_of_remote_addresses); +#endif + /* request some more memory than needed */ + req->oldidx = (n + n / 8); + return 0; + } + if (req->newptr != USER_ADDR_NULL) { + SCTP_INP_INFO_RUNLOCK(); + return EPERM; + } + LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) { + SCTP_INP_RLOCK(inp); + number_of_local_addresses = 0; + number_of_associations = 0; + /* + * LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) + * { number_of_local_addresses++; } + */ + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + number_of_associations++; + } + xinpcb.last = 0; + xinpcb.local_port = ntohs(inp->sctp_lport); + xinpcb.number_local_addresses = number_of_local_addresses; + xinpcb.number_associations = number_of_associations; + xinpcb.flags = inp->sctp_flags; + xinpcb.features = inp->sctp_features; + xinpcb.total_sends = inp->total_sends; + xinpcb.total_recvs = inp->total_recvs; + xinpcb.total_nospaces = inp->total_nospaces; + SCTP_INP_INCR_REF(inp); + SCTP_INP_RUNLOCK(inp); + SCTP_INP_INFO_RUNLOCK(); + error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb)); + if (error) { + return error; + } + SCTP_INP_INFO_RLOCK(); + SCTP_INP_RLOCK(inp); + /* FIXME MT */ + /* + * LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) + * { error = SYSCTL_OUT(req, &xladdr, sizeof(struct + * xsctp_laddr)); if (error) { #if + * defined(SCTP_APPLE_FINE_GRAINED_LOCKING) + * socket_unlock(inp->ip_inp.inp.inp_socket, 1); + * lck_rw_unlock_shared(sctppcbinfo.ipi_ep_mtx); #endif + * SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return + * error; } } + */ + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + SCTP_TCB_LOCK(stcb); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + number_of_local_addresses = 0; + number_of_remote_addresses = 0; + /* FIXME MT */ + /* + * LIST_FOREACH(laddr, + * &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) + * { number_of_local_addresses++; } + */ + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + number_of_remote_addresses++; + } + xstcb.remote_port = ntohs(stcb->rport); + xstcb.number_local_addresses = number_of_local_addresses; + xstcb.number_remote_addresses = number_of_remote_addresses; + xstcb.number_incomming_streams = 0; + xstcb.number_outgoing_streams = 0; + xstcb.state = stcb->asoc.state; + xstcb.total_sends = stcb->total_sends; + xstcb.total_recvs = stcb->total_recvs; + xstcb.local_tag = stcb->asoc.my_vtag; + xstcb.remote_tag = stcb->asoc.peer_vtag; + xstcb.initial_tsn = stcb->asoc.init_seq_number; + xstcb.highest_tsn = stcb->asoc.sending_seq - 1; + xstcb.cumulative_tsn = stcb->asoc.last_acked_seq; + xstcb.cumulative_tsn_ack = stcb->asoc.cumulative_tsn; + SCTP_INP_RUNLOCK(inp); + SCTP_INP_INFO_RUNLOCK(); + error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb)); + if (error) { + atomic_add_int(&stcb->asoc.refcnt, -1); + return error; + } + /* FIXME MT */ + /* + * LIST_FOREACH(laddr, + * &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) + * { error = SYSCTL_OUT(req, &xladdr, sizeof(struct + * xsctp_laddr)); if (error) { #if + * defined(SCTP_APPLE_FINE_GRAINED_LOCKING) + * socket_unlock(inp->ip_inp.inp.inp_socket, 1); + * lck_rw_unlock_shared(sctppcbinfo.ipi_ep_mtx); + * #endif SCTP_INP_RUNLOCK(inp); + * SCTP_INP_INFO_RUNLOCK(); return error; } + * */ + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + xraddr.state = net->dest_state; + xraddr.address = net->ro._l_addr; + error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr)); + if (error) { + atomic_add_int(&stcb->asoc.refcnt, -1); + return error; + } + } + atomic_add_int(&stcb->asoc.refcnt, -1); + SCTP_INP_INFO_RLOCK(); + SCTP_INP_RLOCK(inp); + } + SCTP_INP_DECR_REF(inp); + SCTP_INP_RUNLOCK(inp); + } + SCTP_INP_INFO_RUNLOCK(); + + xinpcb.last = 1; + xinpcb.local_port = 0; + xinpcb.number_local_addresses = 0; + xinpcb.number_associations = 0; + xinpcb.flags = 0; + xinpcb.features = 0; + error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb)); + return error; +} /* * sysctl definitions @@ -604,12 +783,10 @@ SYSCTL_INT(_net_inet_sctp, OID_AUTO, asoc_resource, CTLFLAG_RW, &sctp_asoc_free_resc_limit, 0, "Max number of cached resources in an asoc"); - SYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW, &sctp_chunkscale, 0, "Tuneable for Scaling of number of chunks and messages"); - SYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW, &sctp_delayed_sack_time_default, 0, "Default delayed SACK timer in msec"); @@ -666,7 +843,6 @@ SYSCTL_UINT(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLFLAG_RW, &sctp_add_more_threshold, 0, "When space wise is it worthwhile to try to add more to a socket send buffer"); - SYSCTL_UINT(_net_inet_sctp, OID_AUTO, nr_outgoing_streams, CTLFLAG_RW, &sctp_nr_outgoing_streams_default, 0, "Default number of outgoing streams"); @@ -742,6 +918,11 @@ SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_data_order, CTLFLAG_RW, SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW, &sctpstat, sctpstat, "SCTP statistics (struct sctps_stat, netinet/sctp.h"); + +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_RD, + 0, 0, sctp_assoclist, + "S,xassoc", "List of active SCTP associations"); + #ifdef SCTP_DEBUG SYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW, &sctp_debug_on, 0, "Configure debug output"); @@ -1106,7 +1287,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, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); /* No unlock tcb assoc is gone */ splx(s); return (0); @@ -1187,8 +1368,9 @@ sctp_disconnect(struct socket *so) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000007); + *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; sctp_send_abort_tcb(stcb, op_err); SCTP_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || @@ -1196,7 +1378,7 @@ sctp_disconnect(struct socket *so) SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_INP_RUNLOCK(inp); - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); splx(s); return (0); } @@ -1325,8 +1507,9 @@ sctp_shutdown(struct socket *so) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000008); + *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); } + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, op_err); @@ -1744,17 +1927,17 @@ sctp_do_connect_x(struct socket *so, for (i = 1; i < totaddr; i++) { if (sa->sa_family == AF_INET) { incr = sizeof(struct sockaddr_in); - if (sctp_add_remote_addr(stcb, sa, 0, 8)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); error = ENOBUFS; goto out_now; } } else if (sa->sa_family == AF_INET6) { incr = sizeof(struct sockaddr_in6); - if (sctp_add_remote_addr(stcb, sa, 0, 8)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); error = ENOBUFS; goto out_now; } @@ -3626,7 +3809,9 @@ sctp_optsset(struct socket *so, if (stcb->asoc.delayed_connection == 1) { stcb->asoc.delayed_connection = 0; SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); + sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, + stcb->asoc.primary_destination, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); sctp_send_initiate(inp, stcb); } else { /* @@ -3928,7 +4113,8 @@ sctp_optsset(struct socket *so, } if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { if (callout_pending(&net->pmtu_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); } if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { net->mtu = paddrp->spp_pathmtu; @@ -3983,7 +4169,7 @@ sctp_optsset(struct socket *so, * addresses */ if (cnt_of_unconf == 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); } } if (paddrp->spp_flags & SPP_HB_ENABLE) { diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index f395fbbc5ed0..18fe59d2ff02 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -625,7 +625,7 @@ sctp_fill_stat_log(struct mbuf *m) req->end_at = sctp_cwnd_log_at - 1; req->num_ret = sctp_cwnd_log_at; } -#ifdef INVARIENTS +#ifdef INVARIANTS if (req->num_ret > num) { panic("Bad statlog get?"); } @@ -1269,6 +1269,7 @@ sctp_timeout_handler(void *t) splx(s); return; } + tmr->stopped_from = 0xa001; if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) { /* * printf("SCTP timer fired with invalid type: 0x%x\n", @@ -1277,11 +1278,13 @@ sctp_timeout_handler(void *t) splx(s); return; } + tmr->stopped_from = 0xa002; if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) { splx(s); return; } /* if this is an iterator timeout, get the struct and clear inp */ + tmr->stopped_from = 0xa003; if (tmr->type == SCTP_TIMER_TYPE_ITERATOR) { it = (struct sctp_iterator *)inp; inp = NULL; @@ -1300,6 +1303,7 @@ sctp_timeout_handler(void *t) return; } } + tmr->stopped_from = 0xa004; if (stcb) { if (stcb->asoc.state == 0) { splx(s); @@ -1309,6 +1313,7 @@ sctp_timeout_handler(void *t) return; } } + tmr->stopped_from = 0xa005; #ifdef SCTP_DEBUG if (sctp_debug_on & SCTP_DEBUG_TIMER1) { printf("Timer type %d goes off\n", tmr->type); @@ -1321,6 +1326,10 @@ sctp_timeout_handler(void *t) } return; } + tmr->stopped_from = 0xa006; + /* record in stopped what t-o occured */ + tmr->stopped_from = tmr->type; + if (stcb) { atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_LOCK(stcb); @@ -1523,8 +1532,8 @@ sctp_timeout_handler(void *t) SCTP_STAT_INCR(sctps_timoassockill); /* Can we free it yet? */ SCTP_INP_DECR_REF(inp); - sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); - sctp_free_assoc(inp, stcb, 0); + 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); /* * free asoc, always unlocks (or destroy's) so prevent * duplicate unlock or unlock of a free mtx :-0 @@ -1539,7 +1548,7 @@ sctp_timeout_handler(void *t) * killer */ SCTP_INP_DECR_REF(inp); - sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_3); sctp_inpcb_free(inp, 1, 0); goto out_no_decr; break; @@ -1931,6 +1940,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, if (t_type == SCTP_TIMER_TYPE_SEND) { stcb->asoc.num_send_timers_up++; } + tmr->stopped_from = 0; tmr->type = t_type; tmr->ep = (void *)inp; tmr->tcb = (void *)stcb; @@ -1943,7 +1953,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, int sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) + struct sctp_nets *net, uint32_t from) { struct sctp_timer *tmr; @@ -2100,6 +2110,7 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, } } tmr->self = NULL; + tmr->stopped_from = from; callout_stop(&tmr->timer); return (0); } @@ -2367,6 +2378,12 @@ sctp_calculate_rto(struct sctp_tcb *stcb, } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) { /* impossible .. garbage in nothing out */ return (((net->lastsa >> 2) + net->lastsv) >> 1); + } else if ((u_long)now.tv_usec == (u_long)old->tv_usec) { + /* + * We have to have 1 usec :-D this must be the + * loopback. + */ + calc_time = 1; } else { /* impossible .. garbage in nothing out */ return (((net->lastsa >> 2) + net->lastsv) >> 1); @@ -2378,27 +2395,6 @@ sctp_calculate_rto(struct sctp_tcb *stcb, /***************************/ /* 2. update RTTVAR & SRTT */ /***************************/ -#if 0 - /* if (net->lastsv || net->lastsa) { */ - /* per Section 5.3.1 C3 in SCTP */ - /* net->lastsv = (int) *//* RTTVAR */ - /* - * (((double)(1.0 - 0.25) * (double)net->lastsv) + (double)(0.25 * - * (double)abs(net->lastsa - calc_time))); net->lastsa = (int) -*//* SRTT */ - /* - * (((double)(1.0 - 0.125) * (double)net->lastsa) + (double)(0.125 * - * (double)calc_time)); } else { -*//* the first RTT calculation, per C2 Section 5.3.1 */ - /* net->lastsa = calc_time; *//* SRTT */ - /* net->lastsv = calc_time / 2; *//* RTTVAR */ - /* } */ - /* if RTTVAR goes to 0 you set to clock grainularity */ - /* - * if (net->lastsv == 0) { net->lastsv = SCTP_CLOCK_GRANULARITY; } - * new_rto = net->lastsa + 4 * net->lastsv; - */ -#endif o_calctime = calc_time; /* this is Van Jacobson's integer version */ if (net->RTO) { @@ -3380,7 +3376,7 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_send_abort(m, iphlen, sh, vtag, op_err); if (stcb != NULL) { /* Ok, now lets free it */ - sctp_free_assoc(inp, stcb, 0); + 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) { @@ -3417,7 +3413,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTP_STAT_DECR_GAUGE32(sctps_currestab); } /* now free the asoc */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5); } void @@ -3787,12 +3783,14 @@ sctp_add_to_readq(struct sctp_inpcb *inp, if (inp == NULL) { /* Gak, TSNH!! */ -#ifdef INVARIENTS +#ifdef INVARIANTS panic("Gak, inp NULL on add_to_readq"); #endif return; } SCTP_INP_READ_LOCK(inp); + atomic_add_int(&inp->total_recvs, 1); + atomic_add_int(&stcb->total_recvs, 1); m = control->data; control->held_length = 0; control->length = 0; @@ -3914,7 +3912,7 @@ sctp_append_to_readq(struct sctp_inpcb *inp, /* Really there should always be a prev */ if (m == NULL) { /* Huh nothing left? */ -#ifdef INVARIENTS +#ifdef INVARIANTS panic("Nothing left to add?"); #else goto get_out; @@ -3938,7 +3936,7 @@ sctp_append_to_readq(struct sctp_inpcb *inp, control->tail_mbuf = tail; } else { /* nothing there */ -#ifdef INVARIENTS +#ifdef INVARIANTS if (control->data != NULL) { panic("This should NOT happen"); } @@ -4233,7 +4231,7 @@ sctp_user_rcvd(struct sctp_tcb *stcb, int *freed_so_far, int hold_rlock, sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_USR_RCVD); /* make sure no timer is running */ - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_6); SCTP_TCB_UNLOCK(stcb); } else { /* Update how much we have pending */ @@ -4248,7 +4246,6 @@ sctp_user_rcvd(struct sctp_tcb *stcb, int *freed_so_far, int hold_rlock, } out: if (so && r_unlocked && hold_rlock) { - SCTP_STAT_INCR(sctps_locks_in_rcv); SCTP_INP_READ_LOCK(stcb->sctp_ep); } SCTP_INP_DECR_REF(stcb->sctp_ep); @@ -4438,7 +4435,7 @@ sctp_sorecvmsg(struct socket *so, } control = TAILQ_FIRST(&inp->read_queue); if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { -#ifdef INVARIENTS +#ifdef INVARIANTS panic("Huh, its non zero and nothing on control?"); #endif so->so_rcv.sb_cc = 0; @@ -4454,7 +4451,6 @@ sctp_sorecvmsg(struct socket *so, * pdapi.. maybe a peer in EEOR that just closed after * sending and never indicated a EOR. */ - SCTP_STAT_INCR(sctps_locks_in_rcva); if (hold_rlock == 0) { hold_rlock = 1; SCTP_INP_READ_LOCK(inp); @@ -4701,7 +4697,6 @@ sctp_sorecvmsg(struct socket *so, m->m_len, control->length); #endif - SCTP_STAT_INCR(sctps_locks_in_rcvb); SCTP_INP_READ_LOCK(inp); hold_rlock = 1; } @@ -4756,7 +4751,7 @@ sctp_sorecvmsg(struct socket *so, * lock ok to null tail */ if (control->data == NULL) { -#ifdef INVARIENTS +#ifdef INVARIANTS if ((control->end_added == 0) || (TAILQ_NEXT(control, next) == NULL)) { /* @@ -4772,7 +4767,7 @@ sctp_sorecvmsg(struct socket *so, } #endif control->tail_mbuf = NULL; -#ifdef INVARIENTS +#ifdef INVARIANTS if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { panic("end_added, nothing left and no MSG_EOR"); } @@ -4854,7 +4849,7 @@ sctp_sorecvmsg(struct socket *so, /* we are done with this control */ if (control->length == 0) { if (control->data) { -#ifdef INVARIENTS +#ifdef INVARIANTS panic("control->data not null at read eor?"); #else printf("Strange, data left in the control buffer .. invarients would panic?\n"); @@ -4880,7 +4875,6 @@ sctp_sorecvmsg(struct socket *so, * queue). */ if (hold_rlock == 0) { - SCTP_STAT_INCR(sctps_locks_in_rcvc); SCTP_INP_READ_LOCK(inp); hold_rlock = 1; } @@ -4907,7 +4901,7 @@ sctp_sorecvmsg(struct socket *so, * since we are leaving more behind on the * control to read. */ -#ifdef INVARIENTS +#ifdef INVARIANTS if (control->end_added && (control->data == NULL) && (control->tail_mbuf == NULL)) { panic("Gak, control->length is corrupt?"); @@ -5000,7 +4994,6 @@ sctp_sorecvmsg(struct socket *so, goto done_with_control; } if (so->so_rcv.sb_cc > held_length) { - SCTP_STAT_INCR(sctps_locks_in_rcvf); control->held_length = so->so_rcv.sb_cc; held_length = 0; } diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index 06f621884d09..dbd9959cc645 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -75,7 +75,7 @@ sctp_timer_start(int, struct sctp_inpcb *, struct sctp_tcb *, int sctp_timer_stop(int, struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); + struct sctp_nets *, uint32_t); uint32_t sctp_calculate_sum(struct mbuf *, int32_t *, uint32_t); diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index 8f8b62aab299..7bf4aafa235a 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -241,7 +241,15 @@ sctp6_input(mp, offp, proto) (u_int8_t *) & chunk_buf); sh->v_tag = init_chk->init.initiate_tag; } - sctp_send_abort(m, iphlen, sh, 0, NULL); + if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { + sctp_send_shutdown_complete2(m, iphlen, sh); + goto bad; + } + if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { + goto bad; + } + if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) + sctp_send_abort(m, iphlen, sh, 0, NULL); goto bad; } else if (stcb == NULL) { refcount_up = 1; @@ -326,7 +334,7 @@ sctp6_notify_mbuf(struct sctp_inpcb *inp, */ nxtsz = ntohl(icmp6->icmp6_mtu); /* Stop any PMTU timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); /* Adjust destination size limit */ if (net->mtu > nxtsz) { @@ -822,7 +830,8 @@ 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, 0); + sctp_free_assoc(inp, stcb, SCTP_DONOT_SETSCOPE, + SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2); /* No unlock tcb assoc is gone */ splx(s); return (0);