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
This commit is contained in:
Randall Stewart 2006-12-14 17:02:55 +00:00
parent e0ccd04489
commit a5d547add3
17 changed files with 1087 additions and 406 deletions

View File

@ -338,7 +338,8 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
#endif /* SCTP_DEBUG */ #endif /* SCTP_DEBUG */
} }
/* add the address */ /* 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 #ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_ASCONF1) { if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
printf("process_asconf_add_ip: error adding address\n"); 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 = m_reply =
sctp_asconf_success_response(aph->correlation_id); 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); 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 * 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++; stcb->asoc.asconf_seq_out++;
/* remove the old ASCONF on our outbound queue */ /* remove the old ASCONF on our outbound queue */
sctp_toss_old_asconf(stcb); sctp_toss_old_asconf(stcb);
@ -1500,7 +1501,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
return; return;
} }
/* stop our timer */ /* 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 */ /* process the ASCONF-ACK contents */
ack_length = ntohs(cp->ch.chunk_length) - ack_length = ntohs(cp->ch.chunk_length) -

View File

@ -151,8 +151,9 @@ __FBSDID("$FreeBSD$");
#define SCTP_RANDY_STUFF1 103 #define SCTP_RANDY_STUFF1 103
#define SCTP_STRMOUT_LOG_ASSIGN 104 #define SCTP_STRMOUT_LOG_ASSIGN 104
#define SCTP_STRMOUT_LOG_SEND 105 #define SCTP_STRMOUT_LOG_SEND 105
#define SCTP_FLIGHT_LOG_DOWN 106
#define SCTP_LOG_MAX_TYPES 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 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. * 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 #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 /* This value determines the default for when
* we try to add more on the send queue., if * we try to add more on the send queue., if
* there is room. This prevents us from cycling * there is room. This prevents us from cycling

View File

@ -28,7 +28,7 @@
* THE POSSIBILITY OF SUCH DAMAGE. * 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 <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __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_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x00000001); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_1);
ippp++; ippp++;
*ippp = control->sinfo_tsn; *ippp = control->sinfo_tsn;
ippp++; ippp++;
*ippp = ((control->sinfo_stream << 16) | control->sinfo_ssn); *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_abort_an_association(stcb->sctp_ep, stcb,
SCTP_PEER_FAULTY, oper); 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); htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000001); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_2);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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_abort_an_association(stcb->sctp_ep, stcb,
SCTP_PEER_FAULTY, oper); SCTP_PEER_FAULTY, oper);
*abort_flag = 1; *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); htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000002); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_3);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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_abort_an_association(stcb->sctp_ep, stcb,
SCTP_PEER_FAULTY, oper); SCTP_PEER_FAULTY, oper);
*abort_flag = 1; *abort_flag = 1;
@ -960,12 +963,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
ph->param_length = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000003); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_4);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); stcb, SCTP_PEER_FAULTY, oper);
*abort_flag = 1; *abort_flag = 1;
@ -997,13 +1001,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
ph->param_length = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000004); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_5);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); stcb, SCTP_PEER_FAULTY, oper);
*abort_flag = 1; *abort_flag = 1;
@ -1099,13 +1104,14 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
ph->param_length = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000005); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); stcb, SCTP_PEER_FAULTY, oper);
*abort_flag = 1; *abort_flag = 1;
@ -1140,12 +1146,13 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
ph->param_length = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000006); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_7);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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 = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000007); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_8);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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 = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000008); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_9);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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 = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x10000009); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_10);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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 = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x1000000a); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_11);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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 = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x1000000b); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_12);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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 = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x1000000c); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_13);
ippp++; ippp++;
*ippp = chk->rec.data.TSN_seq; *ippp = chk->rec.data.TSN_seq;
ippp++; ippp++;
*ippp = ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq); *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, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); 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_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x20000001); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_14);
ippp++; ippp++;
*ippp = tsn; *ippp = tsn;
ippp++; ippp++;
*ippp = ((strmno << 16) | strmseq); *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_abort_an_association(stcb->sctp_ep, stcb,
SCTP_PEER_FAULTY, oper); SCTP_PEER_FAULTY, oper);
*abort_flag = 1; *abort_flag = 1;
@ -1807,12 +1821,13 @@ failed_express_del:
asoc->last_flags_delivered = ch->ch.chunk_flags; asoc->last_flags_delivered = ch->ch.chunk_flags;
asoc->last_strm_seq_delivered = strmseq; asoc->last_strm_seq_delivered = strmseq;
asoc->last_strm_no_delivered = strmno; asoc->last_strm_no_delivered = strmno;
asoc->tsn_last_delivered = tsn;
if (end) { if (end) {
/* clean up the flags and such */ /* clean up the flags and such */
asoc->fragmented_delivery_inprogress = 0; asoc->fragmented_delivery_inprogress = 0;
if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) {
asoc->strmin[strmno].last_sequence_delivered++; asoc->strmin[strmno].last_sequence_delivered++;
}
stcb->asoc.control_pdapi = NULL; stcb->asoc.control_pdapi = NULL;
} }
control = NULL; control = NULL;
@ -1900,12 +1915,13 @@ failed_pdapi_express_del:
htons(SCTP_CAUSE_PROTOCOL_VIOLATION); htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x20000002); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_15);
ippp++; ippp++;
*ippp = tsn; *ippp = tsn;
ippp++; ippp++;
*ippp = ((strmno << 16) | strmseq); *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_abort_an_association(stcb->sctp_ep, stcb,
SCTP_PEER_FAULTY, oper); SCTP_PEER_FAULTY, oper);
@ -1934,12 +1950,13 @@ failed_pdapi_express_del:
ph->param_length = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x20000003); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_16);
ippp++; ippp++;
*ippp = tsn; *ippp = tsn;
ippp++; ippp++;
*ippp = ((strmno << 16) | strmseq); *ippp = ((strmno << 16) | strmseq);
} }
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
sctp_abort_an_association(stcb->sctp_ep, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); stcb, SCTP_PEER_FAULTY, oper);
@ -1977,12 +1994,13 @@ failed_pdapi_express_del:
ph->param_length = ph->param_length =
htons(oper->m_len); htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x20000004); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_17);
ippp++; ippp++;
*ippp = tsn; *ippp = tsn;
ippp++; ippp++;
*ippp = ((strmno << 16) | strmseq); *ippp = ((strmno << 16) | strmseq);
} }
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
sctp_abort_an_association(stcb->sctp_ep, sctp_abort_an_association(stcb->sctp_ep,
stcb, SCTP_PEER_FAULTY, oper); stcb, SCTP_PEER_FAULTY, oper);
@ -2062,6 +2080,11 @@ failed_pdapi_express_del:
/* Into the re-assembly queue */ /* Into the re-assembly queue */
sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag); sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag);
if (*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); 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, if (compare_with_wrap(asoc->cumulative_tsn,
asoc->highest_tsn_inside_map, asoc->highest_tsn_inside_map,
MAX_TSN)) { MAX_TSN)) {
#ifdef INVARIENTS #ifdef INVARIANTS
panic("huh, cumack greater than high-tsn in map"); panic("huh, cumack greater than high-tsn in map");
#else #else
printf("huh, cumack greater than high-tsn in map - should panic?\n"); 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)) { if (callout_pending(&stcb->asoc.dack_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 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_shutdown(stcb, stcb->asoc.primary_destination);
sctp_send_sack(stcb); 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); htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(op_err->m_len); ph->param_length = htons(op_err->m_len);
ippp = (uint32_t *) (ph + 1); ippp = (uint32_t *) (ph + 1);
*ippp = htonl(0x30000001); *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_19);
ippp++; ippp++;
*ippp = asoc->cumulative_tsn; *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, sctp_abort_association(inp, stcb, m, iphlen, sh,
op_err); op_err);
return (2); return (2);
@ -2988,19 +3012,13 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
frag_end, frag_end,
SCTP_LOG_TSN_ACKED); SCTP_LOG_TSN_ACKED);
#endif #endif
#ifdef SCTP_FLIGHT_LOGGING
if (tp1->rec.data.chunk_was_revoked == 0) { sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN,
/* tp1->whoTo->flight_size,
* Revoked tp1->book_size,
* chunks (uintptr_t) stcb,
* don't tp1->rec.data.TSN_seq);
* count, #endif
* since we
* previously
* pulled
* them from
* the fs.
*/
if (tp1->whoTo->flight_size >= tp1->book_size) if (tp1->whoTo->flight_size >= tp1->book_size)
tp1->whoTo->flight_size -= tp1->book_size; tp1->whoTo->flight_size -= tp1->book_size;
else else
@ -3018,34 +3036,15 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (tp1->snd_count < 2) { if (tp1->snd_count < 2) {
/* /*
* Tru * True
* e * non-retran
* no * smited
* n * chunk */
* -r
* e
* tr
* a
* ns
* m
* it
* e
* d
* ch
* u
* nk
* */
tp1->whoTo->net_ack2 += tp1->send_size; tp1->whoTo->net_ack2 += tp1->send_size;
/* /*
* upd * update RTO
* * too ? */
* ate
*
* RTO
*
* too
* ? */
if (tp1->do_rtt) { if (tp1->do_rtt) {
tp1->whoTo->RTO = tp1->whoTo->RTO =
sctp_calculate_rto(stcb, sctp_calculate_rto(stcb,
@ -3057,7 +3056,6 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
} }
} }
} }
}
if (tp1->sent <= SCTP_DATAGRAM_RESEND && if (tp1->sent <= SCTP_DATAGRAM_RESEND &&
tp1->sent != SCTP_DATAGRAM_UNSENT && tp1->sent != SCTP_DATAGRAM_UNSENT &&
compare_with_wrap(tp1->rec.data.TSN_seq, compare_with_wrap(tp1->rec.data.TSN_seq,
@ -3117,14 +3115,15 @@ sctp_check_for_revoked(struct sctp_association *asoc, uint32_t cumack,
*/ */
if (tp1->sent == SCTP_DATAGRAM_ACKED) { if (tp1->sent == SCTP_DATAGRAM_ACKED) {
/* it has been revoked */ /* 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->sent = SCTP_DATAGRAM_SENT;
tp1->rec.data.chunk_was_revoked = 1; 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++; tot_revoked++;
#ifdef SCTP_SACK_LOGGING #ifdef SCTP_SACK_LOGGING
sctp_log_sack(asoc->last_acked_seq, 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; tp1->do_rtt = 0;
} }
/* fix counts and things */ /* 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++; tp1->whoTo->net_ack++;
if (tp1->whoTo->flight_size >= tp1->book_size) if (tp1->whoTo->flight_size >= tp1->book_size)
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)) { if (callout_pending(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 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_STAT_INCR(sctps_earlyfrstrid);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 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 */ /* No, stop it if its running */
if (callout_pending(&net->fr_timer.timer)) { if (callout_pending(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 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_nets *net;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_tmit_chunk *tp1, *tp2; struct sctp_tmit_chunk *tp1, *tp2;
int j;
SCTP_TCB_LOCK_ASSERT(stcb); SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc; asoc = &stcb->asoc;
@ -4101,16 +4109,14 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
* now no-longer in flight. Higher * now no-longer in flight. Higher
* values may occur during marking * values may occur during marking
*/ */
if (tp1->rec.data.chunk_was_revoked == 1) { #ifdef SCTP_FLIGHT_LOGGING
/* sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN,
* If its been revoked, and tp1->whoTo->flight_size,
* now ack'd we do NOT take tp1->book_size,
* away fs etc. since when (uintptr_t) stcb,
* it is retransmitted we tp1->rec.data.TSN_seq);
* clear this flag. #endif
*/
goto skip_fs_update;
}
if (tp1->whoTo->flight_size >= tp1->book_size) { if (tp1->whoTo->flight_size >= tp1->book_size) {
tp1->whoTo->flight_size -= tp1->book_size; tp1->whoTo->flight_size -= tp1->book_size;
} else { } 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); sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
#endif #endif
} }
skip_fs_update:
if (tp1->sent == SCTP_DATAGRAM_RESEND) { if (tp1->sent == SCTP_DATAGRAM_RESEND) {
sctp_ucount_decr(asoc->sent_queue_retran_cnt); 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; asoc->peers_rwnd = 0;
} }
/* Now assure a timer where data is queued at */ /* Now assure a timer where data is queued at */
again:
j = 0;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if (net->flight_size) { if (net->flight_size) {
int to_ticks; int to_ticks;
@ -4268,22 +4275,48 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
} else { } else {
to_ticks = MSEC_TO_TICKS(net->RTO); to_ticks = MSEC_TO_TICKS(net->RTO);
} }
j++;
callout_reset(&net->rxt_timer.timer, to_ticks, callout_reset(&net->rxt_timer.timer, to_ticks,
sctp_timeout_handler, &net->rxt_timer); sctp_timeout_handler, &net->rxt_timer);
} else { } else {
if (callout_pending(&net->rxt_timer.timer)) { if (callout_pending(&net->rxt_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 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 (sctp_early_fr) {
if (callout_pending(&net->fr_timer.timer)) { if (callout_pending(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck4); 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 */ /* 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_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); 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); sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper);
} else { } else {
asoc->state = SCTP_STATE_SHUTDOWN_SENT; 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_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); 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); sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper);
return; return;
} }
@ -4536,11 +4571,12 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
/* stop any timers */ /* stop any timers */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 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 (sctp_early_fr) {
if (callout_pending(&net->fr_timer.timer)) { if (callout_pending(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck1); 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; 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 &= tp1->whoTo->dest_state &=
~SCTP_ADDR_UNCONFIRMED; ~SCTP_ADDR_UNCONFIRMED;
} }
if (tp1->rec.data.chunk_was_revoked == 1) { #ifdef SCTP_FLIGHT_LOGGING
/* sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN,
* If its been revoked, and tp1->whoTo->flight_size,
* now ack'd we do NOT take tp1->book_size,
* away fs etc. since when (uintptr_t) stcb,
* it is retransmitted we tp1->rec.data.TSN_seq);
* clear this flag. #endif
*/
goto skip_fs_update;
}
if (tp1->whoTo->flight_size >= tp1->book_size) { if (tp1->whoTo->flight_size >= tp1->book_size) {
tp1->whoTo->flight_size -= tp1->book_size; tp1->whoTo->flight_size -= tp1->book_size;
} else { } else {
@ -4648,7 +4681,6 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
tp1->do_rtt = 0; tp1->do_rtt = 0;
} }
} }
skip_fs_update:
/* /*
* CMT: CUCv2 algorithm. From the * CMT: CUCv2 algorithm. From the
* cumack'd TSNs, for each TSN being * cumack'd TSNs, for each TSN being
@ -4746,14 +4778,15 @@ skip_segments:
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if (net->new_pseudo_cumack) if (net->new_pseudo_cumack)
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net); stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
} }
} else { } else {
if (accum_moved) { if (accum_moved) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 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 @@ done_with_it:
if ((tp1->sent > SCTP_DATAGRAM_RESEND) && if ((tp1->sent > SCTP_DATAGRAM_RESEND) &&
(tp1->sent < SCTP_FORWARD_TSN_SKIP)) { (tp1->sent < SCTP_FORWARD_TSN_SKIP)) {
tp1->sent = SCTP_DATAGRAM_SENT; 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++; cnt_revoked++;
} }
} }
@ -4892,11 +4929,12 @@ done_with_it:
if (sctp_early_fr) { if (sctp_early_fr) {
if (callout_pending(&net->fr_timer.timer)) { if (callout_pending(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck4); 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, 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->flight_size = 0;
net->partial_bytes_acked = 0; net->partial_bytes_acked = 0;
} }
@ -4959,8 +4997,9 @@ done_with_it:
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); 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); sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper);
return; return;
} else { } else {
@ -5116,7 +5155,7 @@ done_with_it:
asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1;
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 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, sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, net); stcb->sctp_ep, stcb, net);
} }
@ -5220,12 +5259,39 @@ done_with_it:
* Now we must setup so we have a timer up for anyone with * Now we must setup so we have a timer up for anyone with
* outstanding data. * outstanding data.
*/ */
again:
j = 0;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if (net->flight_size) { if (net->flight_size) {
j++;
sctp_timer_start(SCTP_TIMER_TYPE_SEND, sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, net); 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 #ifdef SCTP_SACK_RWND_LOGGING
sctp_misc_ints(SCTP_SACK_RWND_UPDATE, sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
a_rwnd, a_rwnd,

View File

@ -100,19 +100,34 @@ extern uint32_t sctp_debug_on;
#endif #endif
struct sctp_foo_stuff sctp_logoff[30000];
int sctp_logoff_stuff = 0;
static void static void
sctp_stop_all_cookie_timers(struct sctp_tcb *stcb) sctp_stop_all_cookie_timers(struct sctp_tcb *stcb)
{ {
struct sctp_nets *net; 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); SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if ((callout_pending(&net->rxt_timer.timer)) && if (net->rxt_timer.type == SCTP_TIMER_TYPE_COOKIE) {
(net->rxt_timer.type == SCTP_TIMER_TYPE_COOKIE)) {
sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE,
stcb->sctp_ep, stcb->sctp_ep,
stcb, 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 * No sense in further INIT's since we will get the
* same param back * 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); return (-1);
} }
@ -415,7 +430,10 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
* primary. * primary.
*/ */
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, stcb, 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); retval = sctp_send_cookie_echo(m, offset, stcb, net);
if (retval < 0) { if (retval < 0) {
@ -453,9 +471,6 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
} }
return (retval); return (retval);
} }
/* calculate the RTO */
net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered);
return (0); return (0);
} }
@ -548,7 +563,7 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
/* ignore abort for addresses being deleted */ /* ignore abort for addresses being deleted */
/* stop any receive timers */ /* 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... */ /* notify user of the abort and clean up... */
sctp_abort_notification(stcb, 0); sctp_abort_notification(stcb, 0);
/* free the tcb */ /* 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_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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 #ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_INPUT2) { if (sctp_debug_on & SCTP_DEBUG_INPUT2) {
printf("sctp_handle_abort: finished\n"); printf("sctp_handle_abort: finished\n");
@ -579,9 +594,9 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
#endif #endif
if (stcb == NULL) if (stcb == NULL)
return; return;
asoc = &stcb->asoc;
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) { (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
return; return;
} }
if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_shutdown_chunk)) { if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_shutdown_chunk)) {
@ -590,18 +605,17 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
} else { } else {
sctp_update_acked(stcb, cp, net, abort_flag); sctp_update_acked(stcb, cp, net, abort_flag);
} }
asoc = &stcb->asoc; if (asoc->control_pdapi) {
if (stcb->asoc.control_pdapi) {
/* /*
* With a normal shutdown we assume the end of last record. * With a normal shutdown we assume the end of last record.
*/ */
SCTP_INP_READ_LOCK(stcb->sctp_ep); SCTP_INP_READ_LOCK(stcb->sctp_ep);
stcb->asoc.control_pdapi->end_added = 1; asoc->control_pdapi->end_added = 1;
stcb->asoc.control_pdapi->pdapi_aborted = 1; asoc->control_pdapi->pdapi_aborted = 1;
if (stcb->asoc.control_pdapi->tail_mbuf) { if (asoc->control_pdapi->tail_mbuf) {
stcb->asoc.control_pdapi->tail_mbuf->m_flags |= M_EOR; 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_INP_READ_UNLOCK(stcb->sctp_ep);
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 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 * stop the shutdown timer, since we WILL move to
* SHUTDOWN-ACK-SENT. * 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? */ /* Now are we there yet? */
some_on_streamwheel = 0; some_on_streamwheel = 0;
@ -683,17 +697,17 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
SCTP_TCB_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb);
return; return;
} }
if (stcb->asoc.control_pdapi) { if (asoc->control_pdapi) {
/* /*
* With a normal shutdown we assume the end of last record. * With a normal shutdown we assume the end of last record.
*/ */
SCTP_INP_READ_LOCK(stcb->sctp_ep); SCTP_INP_READ_LOCK(stcb->sctp_ep);
stcb->asoc.control_pdapi->end_added = 1; asoc->control_pdapi->end_added = 1;
stcb->asoc.control_pdapi->pdapi_aborted = 1; asoc->control_pdapi->pdapi_aborted = 1;
if (stcb->asoc.control_pdapi->tail_mbuf) { if (asoc->control_pdapi->tail_mbuf) {
stcb->asoc.control_pdapi->tail_mbuf->m_flags |= M_EOR; 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_INP_READ_UNLOCK(stcb->sctp_ep);
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 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); sctp_report_all_outbound(stcb, 0);
} }
/* stop the timer */ /* 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 */ /* send SHUTDOWN-COMPLETE */
sctp_send_shutdown_complete(stcb, net); sctp_send_shutdown_complete(stcb, net);
/* notify upper layer protocol */ /* notify upper layer protocol */
@ -718,7 +732,8 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
} }
SCTP_STAT_INCR_COUNTER32(sctps_shutdown); SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB but first save off the ep */ /* 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) { asoc->max_init_times) {
sctp_abort_notification(stcb, 0); sctp_abort_notification(stcb, 0);
/* now free the asoc */ /* 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); return (-1);
} }
/* blast back to INIT state */ /* 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); SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
/* /*
* collapse the init timer back in case of a exponential * collapse the init timer back in case of a exponential
* backoff n * backoff
*/ */
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep, sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep,
stcb, net); 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_chunk *init_cp, init_buf;
struct sctp_init_ack_chunk *initack_cp, initack_buf; struct sctp_init_ack_chunk *initack_cp, initack_buf;
int chk_length; int chk_length;
int init_offset, initack_offset; int init_offset, initack_offset, i;
int retval; int retval;
int spec_flag = 0; int spec_flag = 0;
@ -1179,9 +1194,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* Duplicate INIT case */ /* Duplicate INIT case */
/* we have already processed the INIT so no problem */ /* we have already processed the INIT so no problem */
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb,
net); net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_11);
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net); sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_12);
sctp_stop_all_cookie_timers(stcb);
/* update current state */ /* update current state */
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
asoc->state = SCTP_STATE_OPEN | 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 */ /* if ok, move to OPEN state */
asoc->state = SCTP_STATE_OPEN; asoc->state = SCTP_STATE_OPEN;
} }
sctp_stop_all_cookie_timers(stcb);
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
(inp->sctp_socket->so_qlimit == 0) (inp->sctp_socket->so_qlimit == 0)
@ -1228,7 +1243,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/ */
break; break;
} /* end switch */ } /* end switch */
sctp_stop_all_cookie_timers(stcb);
/* /*
* We ignore the return code here.. not sure if we should * We ignore the return code here.. not sure if we should
* somehow abort.. but we do have an existing asoc. This * 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); return (NULL);
} }
/* respond with a COOKIE-ACK */ /* respond with a COOKIE-ACK */
sctp_toss_old_cookies(stcb, asoc);
sctp_send_cookie_ack(stcb); sctp_send_cookie_ack(stcb);
return (stcb); return (stcb);
} /* end if */ } /* 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 * case B in Section 5.2.4 Table 2: MXAA or MOAA my info
* should be ok, re-accept peer info * should be ok, re-accept peer info
*/ */
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_13);
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
sctp_stop_all_cookie_timers(stcb); sctp_stop_all_cookie_timers(stcb);
/* /*
* since we did not send a HB make sure we don't double * 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; asoc->state = SCTP_STATE_OPEN;
} }
sctp_stop_all_cookie_timers(stcb); sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, asoc);
sctp_send_cookie_ack(stcb); sctp_send_cookie_ack(stcb);
if (spec_flag) { 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) * case A in Section 5.2.4 Table 2: XXMM (peer restarted)
*/ */
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net); /* temp code */
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 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); *sac_assoc_id = sctp_get_associd(stcb);
/* notify upper layer */ /* notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_RESTART; *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 */ /* send up all the data */
SCTP_TCB_SEND_LOCK(stcb); 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) */ /* process the INIT-ACK info (my info) */
asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); asoc->my_vtag = ntohl(initack_cp->init.initiate_tag);
asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); 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); asoc->mapping_array_size);
/* process the INIT info (peer's info) */ /* process the INIT info (peer's info) */
SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_SEND_UNLOCK(stcb);
SCTP_INP_WUNLOCK(stcb->sctp_ep);
SCTP_INP_INFO_WUNLOCK();
retval = sctp_process_init(init_cp, stcb, net); retval = sctp_process_init(init_cp, stcb, net);
if (retval < 0) { if (retval < 0) {
return (NULL); return (NULL);
@ -1429,6 +1458,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
} }
/* respond with a COOKIE-ACK */ /* respond with a COOKIE-ACK */
sctp_stop_all_cookie_timers(stcb); sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, asoc);
sctp_send_cookie_ack(stcb); sctp_send_cookie_ack(stcb);
return (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) */ /* process the INIT info (peer's info) */
retval = sctp_process_init(init_cp, stcb, *netp); retval = sctp_process_init(init_cp, stcb, *netp);
if (retval < 0) { 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); return (NULL);
} }
/* load all addresses */ /* load all addresses */
if (sctp_load_addresses_from_init(stcb, m, iphlen, if (sctp_load_addresses_from_init(stcb, m, iphlen,
init_offset + sizeof(struct sctp_init_chunk), initack_offset, sh, init_offset + sizeof(struct sctp_init_chunk), initack_offset, sh,
init_src)) { 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); return (NULL);
} }
/* /*
@ -1612,7 +1642,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
if (sctp_debug_on & SCTP_DEBUG_AUTH1) if (sctp_debug_on & SCTP_DEBUG_AUTH1)
printf("COOKIE-ECHO: AUTH failed\n"); printf("COOKIE-ECHO: AUTH failed\n");
#endif /* SCTP_DEBUG */ #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); return (NULL);
} else { } else {
/* remaining chunks checked... good to go */ /* remaining chunks checked... good to go */
@ -1632,12 +1662,9 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
} else { } else {
asoc->state = SCTP_STATE_OPEN; asoc->state = SCTP_STATE_OPEN;
} }
sctp_stop_all_cookie_timers(stcb);
SCTP_STAT_INCR_COUNTER32(sctps_passiveestab); SCTP_STAT_INCR_COUNTER32(sctps_passiveestab);
SCTP_STAT_INCR_GAUGE32(sctps_currestab); 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 * 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, memcpy(&sin6->sin6_addr, cookie->laddress,
sizeof(sin6->sin6_addr)); sizeof(sin6->sin6_addr));
} else { } else {
sctp_free_assoc(inp, stcb, 0); sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
return (NULL); 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); sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL);
} }
/* respond with a COOKIE-ACK */ /* respond with a COOKIE-ACK */
/* calculate the RTT */
(*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp,
&cookie->time_entered);
sctp_send_cookie_ack(stcb); sctp_send_cookie_ack(stcb);
return (stcb); return (stcb);
} }
@ -1723,7 +1753,7 @@ static struct mbuf *
sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp, struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp,
struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp, 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 sctp_state_cookie *cookie;
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
@ -2014,6 +2044,31 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
if (l_inp != *inp_p) { if (l_inp != *inp_p) {
printf("Bad problem find_ep got a diff inp then special_locate?\n"); 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; 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? */ /* TSNH! Huh, why do I need to add this address here? */
int ret; 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); netl = sctp_findnet(*stcb, to);
} }
if (netl) { 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); op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(*inp_p, NULL, m, iphlen, sctp_abort_association(*inp_p, NULL, m, iphlen,
sh, op_err); 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); return (NULL);
} }
inp = (struct sctp_inpcb *)so->so_pcb; inp = (struct sctp_inpcb *)so->so_pcb;
@ -2386,10 +2442,10 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp,
} }
} }
/* stop the timer */ /* 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); SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB */ /* 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; return;
} }
@ -2499,11 +2555,18 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
/* restart the timer */ /* restart the timer */
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 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, sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, tp1->whoTo); stcb, tp1->whoTo);
/* fix counts and things */ /* 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) if (tp1->whoTo->flight_size >= tp1->book_size)
tp1->whoTo->flight_size -= tp1->book_size; tp1->whoTo->flight_size -= tp1->book_size;
else else
@ -2569,7 +2632,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
* this, otherwise we let the timer fire. * this, otherwise we let the timer fire.
*/ */
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, 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); sctp_send_initiate(stcb->sctp_ep, stcb);
} }
break; break;
@ -2738,7 +2801,7 @@ sctp_clean_up_stream_reset(struct sctp_tcb *stcb)
if (stcb->asoc.str_reset == NULL) { if (stcb->asoc.str_reset == NULL) {
return; 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, TAILQ_REMOVE(&asoc->control_send_queue,
chk, chk,
sctp_next); sctp_next);
@ -3460,6 +3523,9 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
*/ */
vtag_in = ntohl(sh->v_tag); vtag_in = ntohl(sh->v_tag);
if (locked_tcb) {
SCTP_TCB_LOCK_ASSERT(locked_tcb);
}
if (ch->chunk_type == SCTP_INITIATION) { if (ch->chunk_type == SCTP_INITIATION) {
if (vtag_in != 0) { if (vtag_in != 0) {
/* protocol error- silently discard... */ /* protocol error- silently discard... */
@ -3754,7 +3820,7 @@ process_control_chunks:
SCTP_TCB_UNLOCK(locked_tcb); SCTP_TCB_UNLOCK(locked_tcb);
*offset = length; *offset = length;
if (stcb) { 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); return (NULL);
} }
@ -3972,7 +4038,15 @@ process_control_chunks:
process_cookie_anyway: process_cookie_anyway:
{ {
struct mbuf *ret_buf; struct mbuf *ret_buf;
struct sctp_inpcb *linp;
if (stcb)
linp = NULL;
else
linp = inp;
if (linp)
SCTP_ASOC_CREATE_LOCK(linp);
ret_buf = ret_buf =
sctp_handle_cookie_echo(m, iphlen, sctp_handle_cookie_echo(m, iphlen,
*offset, sh, *offset, sh,
@ -3980,8 +4054,10 @@ process_control_chunks:
&inp, &stcb, netp, &inp, &stcb, netp,
auth_skipped, auth_skipped,
auth_offset, auth_offset,
auth_len); auth_len,
&locked_tcb);
if (linp)
SCTP_ASOC_CREATE_UNLOCK(linp);
if (ret_buf == NULL) { if (ret_buf == NULL) {
if (locked_tcb) { if (locked_tcb) {
SCTP_TCB_UNLOCK(locked_tcb); SCTP_TCB_UNLOCK(locked_tcb);
@ -4028,7 +4104,7 @@ process_control_chunks:
if ((stcb) && (stcb->asoc.total_output_queue_size)) { if ((stcb) && (stcb->asoc.total_output_queue_size)) {
; ;
} else { } else {
sctp_free_assoc(inp, stcb, 0); sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27);
*offset = length; *offset = length;
return (NULL); return (NULL);
} }
@ -4117,7 +4193,7 @@ process_control_chunks:
*fwd_tsn_seen = 1; *fwd_tsn_seen = 1;
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */ /* 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; *offset = length;
return (NULL); return (NULL);
} }
@ -4142,7 +4218,7 @@ process_control_chunks:
chk_length, chunk_buf); chk_length, chunk_buf);
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */ /* 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; *offset = length;
return (NULL); 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 * Rest should be DATA only. Check authentication state if AUTH for
* DATA is required. * DATA is required.
*/ */
if ((stcb != NULL) && !sctp_auth_disable && if ((length > offset) && (stcb != NULL) && !sctp_auth_disable &&
sctp_auth_is_required_chunk(SCTP_DATA, sctp_auth_is_required_chunk(SCTP_DATA,
stcb->asoc.local_auth_chunks) && stcb->asoc.local_auth_chunks) &&
!stcb->asoc.authenticated) { !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) if (sctp_debug_on & SCTP_DEBUG_AUTH1)
printf("Data chunk requires AUTH, skipped\n"); printf("Data chunk requires AUTH, skipped\n");
#endif #endif
SCTP_TCB_UNLOCK(stcb); goto trigger_send;
return (1);
} }
if (length > offset) { if (length > offset) {
int retval; 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 of any chunks in queue... */
trigger_send:
#ifdef SCTP_AUDITING_ENABLED #ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xE0, 2); sctp_audit_log(0xE0, 2);
sctp_auditing(1, inp, stcb, net); 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; extern int sctp_no_csum_on_loopback;
int sctp_buf_index = 0;
uint8_t sctp_list_of_chunks[30000];
void void
sctp_input(m, off) sctp_input(m, off)
struct mbuf *m; struct mbuf *m;
@ -4698,6 +4778,16 @@ sctp_skip_csum_4:
if (mlen < (ip->ip_len - iphlen)) { if (mlen < (ip->ip_len - iphlen)) {
SCTP_STAT_INCR(sctps_hdrops); SCTP_STAT_INCR(sctps_hdrops);
goto bad; 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 * Locate pcb and tcb for datagram sctp_findassociation_addr() wants
@ -4736,6 +4826,14 @@ sctp_skip_csum_4:
if (init_chk != NULL) if (init_chk != NULL)
sh->v_tag = init_chk->init.initiate_tag; sh->v_tag = init_chk->init.initiate_tag;
} }
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); sctp_send_abort(m, iphlen, sh, 0, NULL);
goto bad; goto bad;
} else if (stcb == NULL) { } else if (stcb == NULL) {

View File

@ -71,6 +71,10 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
extern struct sctp_foo_stuff sctp_logoff[];
extern int sctp_logoff_stuff;
#define SCTP_IPI_COUNT_INIT() #define SCTP_IPI_COUNT_INIT()
#define SCTP_STATLOG_INIT_LOCK() #define SCTP_STATLOG_INIT_LOCK()
@ -87,6 +91,7 @@ __FBSDID("$FreeBSD$");
} \ } \
} }
#define SCTP_INP_INFO_LOCK_INIT() \ #define SCTP_INP_INFO_LOCK_INIT() \
mtx_init(&sctppcbinfo.ipi_ep_mtx, "sctp-info", "inp_info", MTX_DEF) 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) #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_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1)
#define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1) #define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1)
#endif
#ifdef SCTP_LOCK_LOGGING #ifdef SCTP_LOCK_LOGGING
#define SCTP_ASOC_CREATE_LOCK(_inp) \ #define SCTP_ASOC_CREATE_LOCK(_inp) \
do { \ do { \

View File

@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$");
*/ */
typedef struct mbuf *sctp_mbuf_t; typedef struct mbuf *sctp_mbuf_t;
#define USER_ADDR_NULL (NULL) /* FIX ME: temp */
/* /*
* general memory allocation * general memory allocation
*/ */

View File

@ -3617,6 +3617,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* place in my tag */ /* place in my tag */
if ((asoc != NULL) && if ((asoc != NULL) &&
((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_INUSE) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) { (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) {
/* re-use the v-tags and init-seq here */ /* re-use the v-tags and init-seq here */
initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); 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 */ /* take off and then setup so we know it is not on the wheel */
SCTP_TCB_SEND_LOCK(stcb); 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); TAILQ_REMOVE(&asoc->out_wheel, strq, next_spoke);
strq->next_spoke.tqe_next = NULL; strq->next_spoke.tqe_next = NULL;
strq->next_spoke.tqe_prev = NULL; strq->next_spoke.tqe_prev = NULL;
SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_SEND_UNLOCK(stcb);
} }
static void static void
sctp_prune_prsctp(struct sctp_tcb *stcb, sctp_prune_prsctp(struct sctp_tcb *stcb,
struct sctp_association *asoc, 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->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags);
sp->pr_sctp_on = 1; sp->pr_sctp_on = 1;
} else { } else {
goto sctp_no_policy; return;
} }
switch (PR_SCTP_POLICY(sp->sinfo_flags)) { switch (PR_SCTP_POLICY(sp->sinfo_flags)) {
case CHUNK_FLAGS_PR_SCTP_BUF: case CHUNK_FLAGS_PR_SCTP_BUF:
@ -4116,13 +4121,8 @@ sctp_set_prsctp_policy(struct sctp_tcb *stcb,
break; break;
} }
} }
sctp_no_policy:
if (sp->sinfo_flags & SCTP_UNORDERED)
sp->act_flags |= SCTP_DATA_UNORDERED;
} }
static int static int
sctp_msg_append(struct sctp_tcb *stcb, sctp_msg_append(struct sctp_tcb *stcb,
struct sctp_nets *net, struct sctp_nets *net,
@ -4165,7 +4165,6 @@ sctp_msg_append(struct sctp_tcb *stcb,
goto out_now; goto out_now;
} }
SCTP_INCR_STRMOQ_COUNT(); SCTP_INCR_STRMOQ_COUNT();
sp->act_flags = 0;
sp->sinfo_flags = srcv->sinfo_flags; sp->sinfo_flags = srcv->sinfo_flags;
sp->timetolive = srcv->sinfo_timetolive; sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid; sp->ppid = srcv->sinfo_ppid;
@ -4217,7 +4216,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
if ((strm->next_spoke.tqe_next == NULL) && if ((strm->next_spoke.tqe_next == NULL) &&
(strm->next_spoke.tqe_prev == NULL)) { (strm->next_spoke.tqe_prev == NULL)) {
/* Not on wheel, insert */ /* Not on wheel, insert */
sctp_insert_on_wheel(stcb, &stcb->asoc, strm, 0); sctp_insert_on_wheel(stcb, &stcb->asoc, strm, 1);
} }
m = NULL; m = NULL;
SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_SEND_UNLOCK(stcb);
@ -4875,6 +4874,13 @@ all_done:
data_list[i]->sent = SCTP_DATAGRAM_SENT; data_list[i]->sent = SCTP_DATAGRAM_SENT;
data_list[i]->snd_count = 1; data_list[i]->snd_count = 1;
data_list[i]->rec.data.chunk_was_revoked = 0; 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; net->flight_size += data_list[i]->book_size;
asoc->total_flight += data_list[i]->book_size; asoc->total_flight += data_list[i]->book_size;
asoc->total_flight_count++; 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; struct sctp_data_chunk *dchkh;
int to_move; int to_move;
uint8_t rcv_flags = 0; uint8_t rcv_flags = 0;
uint8_t some_taken;
uint8_t took_all = 0;
SCTP_TCB_LOCK_ASSERT(stcb); SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc; asoc = &stcb->asoc;
sp = TAILQ_FIRST(&strq->outqueue); sp = TAILQ_FIRST(&strq->outqueue);
if (sp == NULL) { if (sp == NULL) {
*locked = 0; *locked = 0;
SCTP_TCB_SEND_LOCK(stcb); 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 */ /* This should not happen */
panic("sp length is 0?"); panic("sp length is 0?");
} }
some_taken = sp->some_taken;
if ((goal_mtu >= sp->length) && (sp->msg_is_complete)) { if ((goal_mtu >= sp->length) && (sp->msg_is_complete)) {
/* It all fits and its a complete msg, no brainer */ /* It all fits and its a complete msg, no brainer */
to_move = min(sp->length, frag_point); 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; sp->some_taken = 1;
} }
} else { } else {
to_move = sctp_can_we_split_this(stcb, to_move = sctp_can_we_split_this(stcb, sp, goal_mtu,
sp, goal_mtu, frag_point, eeor_mode); frag_point, eeor_mode);
if (to_move) { if (to_move) {
if (to_move >= sp->length) { if (to_move >= sp->length) {
to_move = sp->length; to_move = sp->length;
@ -5070,11 +5078,17 @@ out_gu:
*giveup = 1; *giveup = 1;
return (0); 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); memset(chk, sizeof(*chk), 0);
chk->rec.data.rcv_flags = rcv_flags; chk->rec.data.rcv_flags = rcv_flags;
SCTP_TCB_SEND_LOCK(stcb); SCTP_TCB_SEND_LOCK(stcb);
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
if (sp->data->m_flags & M_EXT) { if (sp->data->m_flags & M_EXT) {
chk->copy_by_ref = 1; chk->copy_by_ref = 1;
} else { } else {
@ -5086,21 +5100,21 @@ out_gu:
chk->last_mbuf = sp->tail_mbuf; chk->last_mbuf = sp->tail_mbuf;
/* register the stealing */ /* register the stealing */
sp->data = sp->tail_mbuf = NULL; sp->data = sp->tail_mbuf = NULL;
took_all = 1;
} else { } else {
struct mbuf *m; struct mbuf *m;
chk->data = m_copym(sp->data, 0, to_move, M_DONTWAIT); chk->data = m_copym(sp->data, 0, to_move, M_DONTWAIT);
chk->last_mbuf = NULL; chk->last_mbuf = NULL;
if (chk->data == NULL) { if (chk->data == NULL) {
sp->some_taken = some_taken;
sctp_free_a_chunk(stcb, chk); sctp_free_a_chunk(stcb, chk);
SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_SEND_UNLOCK(stcb);
goto out_gu; goto out_gu;
} }
/* Pull off the data */ /* Pull off the data */
m_adj(sp->data, to_move); 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; m = sp->data;
while (m && (m->m_len == 0)) { while (m && (m->m_len == 0)) {
sp->data = m->m_next; sp->data = m->m_next;
@ -5115,8 +5129,9 @@ out_gu:
} }
if (to_move > sp->length) { if (to_move > sp->length) {
panic("Huh, how can to_move be larger?"); panic("Huh, how can to_move be larger?");
} else } else {
sp->length -= to_move; sp->length -= to_move;
}
/* Update the new length in */ /* Update the new length in */
if (sp->data && (sp->data->m_flags & M_PKTHDR)) { if (sp->data && (sp->data->m_flags & M_PKTHDR)) {
@ -5129,7 +5144,31 @@ out_gu:
m = sctp_get_mbuf_for_msg(1, 1, M_DONTWAIT, 0, MT_DATA); m = sctp_get_mbuf_for_msg(1, 1, M_DONTWAIT, 0, MT_DATA);
if (m == NULL) { 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 { } else {
m->m_len = 0; m->m_len = 0;
m->m_next = chk->data; m->m_next = chk->data;
@ -5145,7 +5184,9 @@ out_gu:
SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_SEND_UNLOCK(stcb);
goto out_gu; 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; chk->sent = SCTP_DATAGRAM_UNSENT;
/* /*
@ -5196,9 +5237,7 @@ out_gu:
dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq); dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq);
dchkh->dp.protocol_id = chk->rec.data.payloadtype; dchkh->dp.protocol_id = chk->rec.data.payloadtype;
dchkh->ch.chunk_length = htons(chk->send_size); 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)) { if (chk->send_size < SCTP_SIZE32(chk->book_size)) {
/* need a pad */ /* need a pad */
struct mbuf *lm; struct mbuf *lm;
@ -5218,9 +5257,9 @@ out_gu:
chk->send_size += pads; chk->send_size += pads;
} }
/* We only re-set the policy if it is on */ /* 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); sctp_set_prsctp_policy(stcb, sp);
}
if (sp->msg_is_complete && (sp->length == 0)) { if (sp->msg_is_complete && (sp->length == 0)) {
/* All done pull and kill the message */ /* All done pull and kill the message */
asoc->stream_queue_cnt--; asoc->stream_queue_cnt--;
@ -5754,7 +5793,7 @@ again_one_more_time:
/* turn off the timer */ /* turn off the timer */
if (callout_pending(&stcb->asoc.dack_timer.timer)) { if (callout_pending(&stcb->asoc.dack_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
inp, stcb, net); inp, stcb, net, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1);
} }
} }
ctl_cnt++; ctl_cnt++;
@ -5991,7 +6030,7 @@ again_one_more_time:
to_out += chk->send_size; to_out += chk->send_size;
if (to_out > mx_mtu) { if (to_out > mx_mtu) {
#ifdef INVARIENT #ifdef INVARIANTS
panic("gag"); panic("gag");
#else #else
printf("Exceeding mtu of %d out size is %d\n", printf("Exceeding mtu of %d out size is %d\n",
@ -6135,7 +6174,8 @@ again_one_more_time:
if (net->flight_size < net->cwnd) { if (net->flight_size < net->cwnd) {
/* start or restart it */ /* start or restart it */
if (callout_pending(&net->fr_timer.timer)) { 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_STAT_INCR(sctps_earlyfrstrout);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net); sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net);
@ -6143,7 +6183,8 @@ again_one_more_time:
/* stop it if its running */ /* stop it if its running */
if (callout_pending(&net->fr_timer.timer)) { if (callout_pending(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpout); 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 @@ one_chunk_around:
if (asoc->sent_queue_retran_cnt < 0) { if (asoc->sent_queue_retran_cnt < 0) {
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; net->flight_size += data_list[i]->book_size;
asoc->total_flight += data_list[i]->book_size; asoc->total_flight += data_list[i]->book_size;
if (data_list[i]->book_size_scale) { if (data_list[i]->book_size_scale) {
@ -7069,7 +7117,8 @@ one_chunk_around:
* SACK back without a * SACK back without a
* t3-expiring. * 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); 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) { if (a_chk == NULL) {
/* No memory so we drop the idea, and set a timer */ /* No memory so we drop the idea, and set a timer */
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 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, sctp_timer_start(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL); stcb->sctp_ep, stcb, NULL);
return; return;
@ -7686,7 +7735,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
atomic_subtract_int(&a_chk->whoTo->ref_count, 1); atomic_subtract_int(&a_chk->whoTo->ref_count, 1);
sctp_free_a_chunk(stcb, a_chk); sctp_free_a_chunk(stcb, a_chk);
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 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, sctp_timer_start(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL); stcb->sctp_ep, stcb, NULL);
return; 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 */ /* ok we have a destination that needs a beat */
/* lets do the theshold management Qiaobing style */ /* lets do the theshold management Qiaobing style */
if (sctp_threshold_management(stcb->sctp_ep, stcb, net, if (sctp_threshold_management(stcb->sctp_ep, stcb, net,
stcb->asoc.max_send_times)) { stcb->asoc.max_send_times)) {
/* /*
@ -9324,6 +9374,12 @@ sctp_lower_sosend(struct socket *so,
stcb = NULL; stcb = NULL;
asoc = NULL; asoc = NULL;
t_inp = inp = (struct sctp_inpcb *)so->so_pcb; 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) if (uio)
sndlen = uio->uio_resid; sndlen = uio->uio_resid;
else else
@ -9340,6 +9396,9 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked; goto out_unlocked;
} }
if ((use_rcvinfo) && srcv) { if ((use_rcvinfo) && srcv) {
if (srcv->sinfo_flags)
SCTP_STAT_INCR(sctps_sends_with_flags);
if (srcv->sinfo_flags & SCTP_SENDALL) { if (srcv->sinfo_flags & SCTP_SENDALL) {
/* its a sendall */ /* its a sendall */
error = sctp_sendall(inp, uio, top, srcv); error = sctp_sendall(inp, uio, top, srcv);
@ -9414,6 +9473,18 @@ sctp_lower_sosend(struct socket *so,
splx(s); splx(s);
goto out_unlocked; 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 (stcb == NULL) {
if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
@ -9575,6 +9646,7 @@ sctp_lower_sosend(struct socket *so,
(stcb->asoc.chunks_on_out_queue > (stcb->asoc.chunks_on_out_queue >
sctp_max_chunks_on_queue)) { sctp_max_chunks_on_queue)) {
error = EWOULDBLOCK; error = EWOULDBLOCK;
atomic_add_int(&stcb->sctp_ep->total_nospaces, 1);
splx(s); splx(s);
goto out_unlocked; goto out_unlocked;
} }
@ -9661,6 +9733,7 @@ sctp_lower_sosend(struct socket *so,
struct mbuf *mm; struct mbuf *mm;
int tot_demand, tot_out, max; int tot_demand, tot_out, max;
SCTP_STAT_INCR(sctps_sends_with_abort);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
/* It has to be up before we abort */ /* 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) { if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
goto out_unlocked; goto out_unlocked;
} }
atomic_add_int(&stcb->total_sends, 1);
if (top == NULL) { if (top == NULL) {
struct sctp_stream_queue_pending *sp; struct sctp_stream_queue_pending *sp;
struct sctp_stream_out *strm; struct sctp_stream_out *strm;
@ -9831,6 +9905,7 @@ sctp_lower_sosend(struct socket *so,
strm = &stcb->asoc.strmout[srcv->sinfo_stream]; strm = &stcb->asoc.strmout[srcv->sinfo_stream];
user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
if (strm->last_msg_incomplete == 0) { 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); sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error, non_blocking);
if ((sp == NULL) || (error)) { if ((sp == NULL) || (error)) {
goto out; goto out;
@ -9860,7 +9935,10 @@ sctp_lower_sosend(struct socket *so,
(uint32_t) ((srcv->sinfo_stream << 16) | sp->strseq), 0); (uint32_t) ((srcv->sinfo_stream << 16) | sp->strseq), 0);
#endif #endif
strm->next_sequence_sent++; strm->next_sequence_sent++;
} else {
SCTP_STAT_INCR(sctps_sends_with_unord);
} }
if ((strm->next_spoke.tqe_next == NULL) && if ((strm->next_spoke.tqe_next == NULL) &&
(strm->next_spoke.tqe_prev == NULL)) { (strm->next_spoke.tqe_prev == NULL)) {
/* Not on wheel, insert */ /* Not on wheel, insert */
@ -9869,6 +9947,17 @@ sctp_lower_sosend(struct socket *so,
SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_SEND_UNLOCK(stcb);
} else { } else {
sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); 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) { while (uio->uio_resid > 0) {
/* How much room do we have? */ /* How much room do we have? */
@ -10019,11 +10108,16 @@ sctp_lower_sosend(struct socket *so,
SCTP_TCB_LOCK(stcb); SCTP_TCB_LOCK(stcb);
hold_tcblock = 1; hold_tcblock = 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); sctp_send_initiate(inp, stcb);
stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
queue_only_for_init = 0; queue_only_for_init = 0;
queue_only = 1; queue_only = 1;
SCTP_TCB_UNLOCK(stcb); }
hold_tcblock = 0;
} }
if ((queue_only == 0) && (nagle_applies == 0) if ((queue_only == 0) && (nagle_applies == 0)
) { ) {
@ -10126,6 +10220,7 @@ dataless_eof:
(got_all_of_the_send == 1) && (got_all_of_the_send == 1) &&
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)
) { ) {
SCTP_STAT_INCR(sctps_sends_with_eof);
error = 0; error = 0;
if (hold_tcblock == 0) { if (hold_tcblock == 0) {
SCTP_TCB_LOCK(stcb); SCTP_TCB_LOCK(stcb);
@ -10255,10 +10350,17 @@ skip_out_eof:
SCTP_TCB_LOCK(stcb); SCTP_TCB_LOCK(stcb);
hold_tcblock = 1; hold_tcblock = 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); sctp_send_initiate(inp, stcb);
stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
queue_only_for_init = 0; queue_only_for_init = 0;
queue_only = 1; queue_only = 1;
} }
}
if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) { if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) {
/* we can attempt to send too. */ /* we can attempt to send too. */
s = splnet(); s = splnet();
@ -10317,7 +10419,7 @@ out_unlocked:
if (stcb && free_cnt_applied) { if (stcb && free_cnt_applied) {
atomic_add_int(&stcb->asoc.refcnt, -1); atomic_add_int(&stcb->asoc.refcnt, -1);
} }
#ifdef INVARIENTS #ifdef INVARIANTS
if (stcb) { if (stcb) {
if (mtx_owned(&stcb->tcb_mtx)) { if (mtx_owned(&stcb->tcb_mtx)) {
panic("Leaving with tcb mtx owned?"); panic("Leaving with tcb mtx owned?");

View File

@ -408,7 +408,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
} }
/* now look at the list of remote addresses */ /* now look at the list of remote addresses */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
#ifdef INVARIENTS #ifdef INVARIANTS
if (net == (TAILQ_NEXT(net, sctp_next))) { if (net == (TAILQ_NEXT(net, sctp_next))) {
panic("Corrupt net list"); 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 */ /* now look at the list of remote addresses */
SCTP_TCB_LOCK(stcb); SCTP_TCB_LOCK(stcb);
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
#ifdef INVARIENTS #ifdef INVARIANTS
if (net == (TAILQ_NEXT(net, sctp_next))) { if (net == (TAILQ_NEXT(net, sctp_next))) {
panic("Corrupt net list"); 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); SCTP_INP_RUNLOCK(stcb->sctp_ep);
} }
/* Ok if we missed here, lets try the restart hash */ /* 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) { if (head == NULL) {
/* invalid id TSNH */ /* invalid id TSNH */
SCTP_INP_INFO_RUNLOCK(); SCTP_INP_INFO_RUNLOCK();
@ -1456,6 +1456,10 @@ sctp_inpcb_alloc(struct socket *so)
LIST_INIT(&inp->sctp_addr_list); LIST_INIT(&inp->sctp_addr_list);
LIST_INIT(&inp->sctp_asoc_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 */ /* Init the timer structure for signature change */
callout_init(&inp->sctp_ep.signature_change.timer, 1); callout_init(&inp->sctp_ep.signature_change.timer, 1);
inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NEWCOOKIE; 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; 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) { if (inp->control) {
sctp_m_freem(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)) { (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
/* Just abandon things in the front states */ /* Just abandon things in the front states */
if (asoc->asoc.total_output_queue_size == 0) { 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; continue;
} }
} }
@ -2165,15 +2170,16 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_CAUSE_USER_INITIATED_ABT); SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(op_err->m_len); ph->param_length = htons(op_err->m_len);
ippp = (uint32_t *) (ph + 1); 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_send_abort_tcb(asoc, op_err);
SCTP_STAT_INCR_COUNTER32(sctps_aborted); SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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; continue;
} else if (TAILQ_EMPTY(&asoc->asoc.send_queue) && } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
TAILQ_EMPTY(&asoc->asoc.sent_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); SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(op_err->m_len); ph->param_length = htons(op_err->m_len);
ippp = (uint32_t *) (ph + 1); 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_send_abort_tcb(asoc, op_err);
SCTP_STAT_INCR_COUNTER32(sctps_aborted); SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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; 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? */ /* now is there some left in our SHUTDOWN state? */
if (cnt_in_sd) { 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); splx(s);
SCTP_INP_WUNLOCK(inp); SCTP_INP_WUNLOCK(inp);
@ -2329,9 +2319,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_CAUSE_USER_INITIATED_ABT); SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(op_err->m_len); ph->param_length = htons(op_err->m_len);
ippp = (uint32_t *) (ph + 1); 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_send_abort_tcb(asoc, op_err);
SCTP_STAT_INCR_COUNTER32(sctps_aborted); SCTP_STAT_INCR_COUNTER32(sctps_aborted);
} else if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { } 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_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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) { if (cnt) {
/* Ok we have someone out there that will kill us */ /* 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_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
SCTP_DECR_LADDR_COUNT(); 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. */ /* Now lets see about freeing the EP hash table. */
if (inp->sctp_tcbhash != NULL) { if (inp->sctp_tcbhash != NULL) {
SCTP_FREE(inp->sctp_tcbhash); 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; stcb->asoc.site_scope = 1;
} }
} else { } else {
if (from == 8) { if (from == SCTP_ADDR_IS_CONFIRMED) {
/* From connectx */ /* From connectx */
if (sctp_is_address_on_local_host(newaddr)) { if (sctp_is_address_on_local_host(newaddr)) {
stcb->asoc.loopback_scope = 1; 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; stcb->asoc.site_scope = 1;
} }
} else { } else {
if (from == 8) { if (from == SCTP_ADDR_IS_CONFIRMED) {
/* From connectx */ /* From connectx so we check for localhost. */
if (sctp_is_address_on_local_host(newaddr)) { if (sctp_is_address_on_local_host(newaddr)) {
stcb->asoc.loopback_scope = 1; stcb->asoc.loopback_scope = 1;
stcb->asoc.ipv4_local_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 | net->dest_state = (SCTP_ADDR_REACHABLE |
SCTP_ADDR_OUT_OF_SCOPE); SCTP_ADDR_OUT_OF_SCOPE);
} else { } else {
if (from == 8) if (from == SCTP_ADDR_IS_CONFIRMED)
/* 8 is passed by connect_x */ /* SCTP_ADDR_IS_CONFIRMED is passed by connect_x */
net->dest_state = SCTP_ADDR_REACHABLE; net->dest_state = SCTP_ADDR_REACHABLE;
else else
net->dest_state = SCTP_ADDR_REACHABLE | 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) && if ((net->ro.ro_rt) &&
(net->ro.ro_rt->rt_ifp)) { (net->ro.ro_rt->rt_ifp)) {
net->mtu = net->ro.ro_rt->rt_ifp->if_mtu; net->mtu = net->ro.ro_rt->rt_ifp->if_mtu;
if (from == 1) { if (from == SCTP_ALLOC_ASOC) {
stcb->asoc.smallest_mtu = net->mtu; stcb->asoc.smallest_mtu = net->mtu;
} }
/* start things off to match mtu of interface please. */ /* 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); LIST_INSERT_HEAD(head, stcb, sctp_asocs);
SCTP_INP_INFO_WUNLOCK(); 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? */ /* failure.. memory error? */
if (asoc->strmout) if (asoc->strmout)
SCTP_FREE(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. * Free the association after un-hashing the remote port.
*/ */
int 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; int i;
struct sctp_association *asoc; 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 */ /* there is no asoc, really TSNH :-0 */
return (1); 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; asoc = &stcb->asoc;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) (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 so we abort early if a reader or writer is still in the way.
*/ */
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) && 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 * is it the timer driving us? if so are the reader/writers
* gone? * 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); callout_stop(&net->pmtu_timer.timer);
} }
/* Now the read queue needs to be cleaned up (only once) */ /* Now the read queue needs to be cleaned up (only once) */
cnt = 0;
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) {
SCTP_INP_READ_LOCK(inp); SCTP_INP_READ_LOCK(inp);
TAILQ_FOREACH(sq, &inp->read_queue, next) { 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); SCTP_INP_READ_UNLOCK(inp);
if (stcb->block_entry) { if (stcb->block_entry) {
cnt++;
stcb->block_entry->error = ECONNRESET; stcb->block_entry->error = ECONNRESET;
stcb->block_entry = NULL; stcb->block_entry = NULL;
} }
} }
stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED; 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 * reader or writer in the way, we have hopefully given him
* something to chew on above. * something to chew on above.
*/ */
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) { if (so) {
/* Wake any reader/writers */ /* Wake any reader/writers */
sctp_sorwakeup(inp, so); sctp_sorwakeup(inp, so);
sctp_sowwakeup(inp, so); sctp_sowwakeup(inp, so);
} }
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); SCTP_INP_RUNLOCK(inp);
SCTP_TCB_UNLOCK(stcb);
}
splx(s); splx(s);
#ifdef SCTP_LOG_CLOSING #ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, stcb, 9); 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 #ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, stcb, 10); sctp_log_closing(inp, stcb, 10);
#endif #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) || if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { (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 */ /* Stop any timer someone may have started */
callout_stop(&asoc->strreset_timer.timer); 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; asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE;
sctp_iterator_asoc_being_freed(inp, stcb); sctp_iterator_asoc_being_freed(inp, stcb);
/* re-increment the lock */ /* re-increment the lock */
if (from_inpcbfree == 0) { if (from_inpcbfree == SCTP_NORMAL_PROC) {
atomic_add_int(&stcb->asoc.refcnt, -1); atomic_add_int(&stcb->asoc.refcnt, -1);
} }
/* now restop the timers to be sure - this is paranoia at is finest! */ /* 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 */ /* Now lets remove it from the list of ALL associations in the EP */
LIST_REMOVE(stcb, sctp_tcblist); LIST_REMOVE(stcb, sctp_tcblist);
if (from_inpcbfree == 0) { if (from_inpcbfree == SCTP_NORMAL_PROC) {
SCTP_INP_INCR_REF(inp); SCTP_INP_INCR_REF(inp);
SCTP_INP_WUNLOCK(inp); SCTP_INP_WUNLOCK(inp);
SCTP_ITERATOR_UNLOCK(); 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); LIST_REMOVE(stcb, sctp_asocs);
sctp_add_vtag_to_timewait(inp, asoc->my_vtag); sctp_add_vtag_to_timewait(inp, asoc->my_vtag);
if (from_inpcbfree == 0) {
SCTP_INP_INFO_WUNLOCK();
}
prev = NULL; prev = NULL;
/* /*
* The chunk lists and such SHOULD be empty but we check them just * 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); net = TAILQ_FIRST(&asoc->nets);
/* pull from list */ /* pull from list */
if ((sctppcbinfo.ipi_count_raddr == 0) || (prev == net)) { if ((sctppcbinfo.ipi_count_raddr == 0) || (prev == net)) {
#ifdef INVARIENTS #ifdef INVARIANTS
panic("no net's left alloc'ed, or list points to itself"); panic("no net's left alloc'ed, or list points to itself");
#endif #endif
break; break;
@ -3703,12 +3724,23 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* Get rid of LOCK */ /* Get rid of LOCK */
SCTP_TCB_LOCK_DESTROY(stcb); SCTP_TCB_LOCK_DESTROY(stcb);
SCTP_TCB_SEND_LOCK_DESTROY(stcb); SCTP_TCB_SEND_LOCK_DESTROY(stcb);
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 */ /* now clean up the tasoc itself */
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
SCTP_DECR_ASOC_COUNT(); SCTP_DECR_ASOC_COUNT();
} else {
if (from_inpcbfree == 0) { LIST_INSERT_HEAD(&inp->sctp_asoc_free_list, stcb, sctp_tcblist);
SCTP_INP_RLOCK(inp); }
#else
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
SCTP_DECR_ASOC_COUNT();
#endif
if (from_inpcbfree == SCTP_NORMAL_PROC) {
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* /*
* If its NOT the inp_free calling us AND sctp_close * 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_inpcb_free(inp, 0, 0);
SCTP_INP_DECR_REF(inp); SCTP_INP_DECR_REF(inp);
goto out_of;
} else { } else {
/* The socket is still open. */ /* The socket is still open. */
SCTP_INP_DECR_REF(inp); SCTP_INP_DECR_REF(inp);
}
}
if (from_inpcbfree == SCTP_NORMAL_PROC) {
SCTP_INP_RUNLOCK(inp); SCTP_INP_RUNLOCK(inp);
} }
} out_of:
splx(s); splx(s);
/* destroyed the asoc */ /* destroyed the asoc */
#ifdef SCTP_LOG_CLOSING #ifdef SCTP_LOG_CLOSING
@ -4247,6 +4283,7 @@ sctp_pcb_init()
SCTP_INP_INFO_LOCK_INIT(); SCTP_INP_INFO_LOCK_INIT();
SCTP_STATLOG_INIT_LOCK(); SCTP_STATLOG_INIT_LOCK();
SCTP_ITERATOR_LOCK_INIT(); SCTP_ITERATOR_LOCK_INIT();
SCTP_IPI_COUNT_INIT(); SCTP_IPI_COUNT_INIT();
SCTP_IPI_ADDR_INIT(); SCTP_IPI_ADDR_INIT();
LIST_INIT(&sctppcbinfo.addr_wq); 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. */ /* no scope set here since we have a tcb already. */
if ((sa->sa_family == AF_INET) && if ((sa->sa_family == AF_INET) &&
(stcb->asoc.ipv4_addr_legal)) { (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); return (-1);
} }
} else if ((sa->sa_family == AF_INET6) && } else if ((sa->sa_family == AF_INET6) &&
(stcb->asoc.ipv6_addr_legal)) { (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); return (-2);
} }
} }
@ -4457,7 +4494,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
/* the assoc was freed? */ /* the assoc was freed? */
return (-7); 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); return (-8);
} }
} else if (stcb_tmp == stcb) { } 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 * we must add the address, no scope
* set * 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); return (-17);
} }
} else if (stcb_tmp == stcb) { } 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 */ /* We look for anything larger than the cum-ack + 1 */
SCTP_STAT_INCR(sctps_protocol_drain_calls);
if (sctp_do_drain == 0) { if (sctp_do_drain == 0) {
return; return;
} }
@ -5047,6 +5085,7 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
/* none we can reneg on. */ /* none we can reneg on. */
return; return;
} }
SCTP_STAT_INCR(sctps_protocol_drains_done);
cumulative_tsn_p1 = asoc->cumulative_tsn + 1; cumulative_tsn_p1 = asoc->cumulative_tsn + 1;
cnt = 0; cnt = 0;
/* First look in the re-assembly queue */ /* First look in the re-assembly queue */

View File

@ -198,6 +198,7 @@ struct sctp_epinfo {
struct mtx ipi_ep_mtx; struct mtx ipi_ep_mtx;
struct mtx it_mtx; struct mtx it_mtx;
struct mtx ipi_addr_mtx; struct mtx ipi_addr_mtx;
struct mtx timer_mtx;
uint32_t ipi_count_ep; uint32_t ipi_count_ep;
/* assoc/tcb zone info */ /* assoc/tcb zone info */
@ -342,6 +343,9 @@ struct sctp_inpcb {
u_long sctp_hashmark; u_long sctp_hashmark;
/* head of the list of all associations */ /* head of the list of all associations */
struct sctpasochead sctp_asoc_list; 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; struct sctp_iterator *inp_starting_point_for_iterator;
uint32_t sctp_frag_point; uint32_t sctp_frag_point;
uint32_t partial_delivery_point; uint32_t partial_delivery_point;
@ -359,6 +363,10 @@ struct sctp_inpcb {
struct mtx inp_create_mtx; struct mtx inp_create_mtx;
struct mtx inp_rdata_mtx; struct mtx inp_rdata_mtx;
int32_t refcount; int32_t refcount;
uint32_t total_sends;
uint32_t total_recvs;
uint32_t last_abort_code;
uint32_t total_nospaces;
}; };
struct sctp_tcb { struct sctp_tcb {
@ -380,6 +388,9 @@ struct sctp_tcb {
* in the reading of data. * in the reading of data.
*/ */
uint32_t freed_by_sorcv_sincelast; 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 rport; /* remote port in network format */
uint16_t resv; uint16_t resv;
struct mtx tcb_mtx; struct mtx tcb_mtx;
@ -450,7 +461,7 @@ struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
int, int *, uint32_t); 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 *); int sctp_add_local_addr_ep(struct sctp_inpcb *, struct ifaddr *);

View File

@ -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)) { if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE); sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE);
n_inp->sctp_ep.auto_close_time = 0; 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. */ /* Turn off any non-blocking semantic. */
newso->so_state &= ~SS_NBIO; newso->so_state &= ~SS_NBIO;

View File

@ -64,6 +64,7 @@ struct sctp_timer {
/* for sanity checking */ /* for sanity checking */
void *self; void *self;
uint32_t ticks; uint32_t ticks;
uint32_t stopped_from;
}; };
struct sctp_nonpad_sndrcvinfo { struct sctp_nonpad_sndrcvinfo {
@ -78,6 +79,13 @@ struct sctp_nonpad_sndrcvinfo {
sctp_assoc_t sinfo_assoc_id; 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 * 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 */ struct timeval timetodrop; /* time we drop it from queue */
uint8_t doing_fast_retransmit; uint8_t doing_fast_retransmit;
uint8_t rcv_flags; /* flags pulled from data chunk on inbound for 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 state_flags;
uint8_t chunk_was_revoked; uint8_t chunk_was_revoked;
}; };
@ -395,12 +403,11 @@ struct sctp_stream_queue_pending {
uint16_t sinfo_flags; uint16_t sinfo_flags;
uint16_t stream; uint16_t stream;
uint16_t strseq; uint16_t strseq;
uint16_t act_flags;
uint8_t msg_is_complete; uint8_t msg_is_complete;
uint8_t some_taken; uint8_t some_taken;
uint8_t addr_over; uint8_t addr_over;
uint8_t act_flags;
uint8_t pr_sctp_on; uint8_t pr_sctp_on;
uint8_t resv;
}; };
/* /*

View File

@ -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_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); 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); sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper);
return (1); return (1);
} }
@ -681,7 +682,19 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
stcb->asoc.total_flight_count--; stcb->asoc.total_flight_count--;
chk->sent = SCTP_DATAGRAM_RESEND; chk->sent = SCTP_DATAGRAM_RESEND;
SCTP_STAT_INCR(sctps_markedretrans); SCTP_STAT_INCR(sctps_markedretrans);
#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; net->flight_size -= chk->book_size;
else
net->flight_size = 0;
stcb->asoc.peers_rwnd += chk->send_size; stcb->asoc.peers_rwnd += chk->send_size;
stcb->asoc.peers_rwnd += sctp_peer_chunk_oh; 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; could_be_sent->sent = SCTP_DATAGRAM_RESEND;
} }
if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { 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", printf("Local Audit says there are %d for retran asoc cnt:%d\n",
cnt_mk, stcb->asoc.sent_queue_retran_cnt); cnt_mk, stcb->asoc.sent_queue_retran_cnt);
#endif #endif
@ -789,6 +802,13 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
} }
TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
if (chk->sent < SCTP_DATAGRAM_RESEND) { 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; stcb->asoc.total_flight += chk->book_size;
chk->whoTo->flight_size += chk->book_size; chk->whoTo->flight_size += chk->book_size;
stcb->asoc.total_flight_count++; 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_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
ph->param_length = htons(oper->m_len); ph->param_length = htons(oper->m_len);
ippp = (uint32_t *) (ph + 1); 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, sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
oper); oper);
} else { } else {
#ifdef INVARIENTS #ifdef INVARIANTS
panic("Cookie timer expires in wrong state?"); panic("Cookie timer expires in wrong state?");
#else #else
printf("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); printf("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc));

View File

@ -853,13 +853,13 @@ struct sctpstat {
u_long sctps_cmt_randry;/* Same for above */ u_long sctps_cmt_randry;/* Same for above */
u_long sctps_slowpath_sack; /* Sacks the slow way */ u_long sctps_slowpath_sack; /* Sacks the slow way */
u_long sctps_wu_sacks_sent; /* Window Update only sacks sent */ 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_sends_with_flags; /* number of sends with sinfo_flags
u_long sctps_locks_in_rcva; /* How man so_rcv buf locks we did */ * !=0 */
u_long sctps_locks_in_rcvb; /* How man so_rcv buf locks we did */ u_long sctps_sends_with_unord;
u_long sctps_locks_in_rcvc; /* How man so_rcv buf locks we did */ u_long sctps_sends_with_eof;
u_long sctps_locks_in_rcvd; /* How man so_rcv buf locks we did */ u_long sctps_sends_with_abort;
u_long sctps_locks_in_rcve; /* How man so_rcv buf locks we did */ u_long sctps_protocol_drain_calls;
u_long sctps_locks_in_rcvf; /* How man so_rcv buf locks we did */ u_long sctps_protocol_drains_done;
}; };
#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1) #define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1)
@ -884,6 +884,47 @@ union sctp_sockstore {
struct sockaddr sa; 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 * Kernel defined for sctp_send

View File

@ -316,7 +316,8 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
/* Stop any PMTU timer */ /* Stop any PMTU timer */
if (callout_pending(&net->pmtu_timer.timer)) { if (callout_pending(&net->pmtu_timer.timer)) {
tmr_stopped = 1; 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 */ /* Adjust destination size limit */
if (net->mtu > nxtsz) { if (net->mtu > nxtsz) {
@ -386,7 +387,7 @@ sctp_notify(struct sctp_inpcb *inp,
* TCB * TCB
*/ */
sctp_abort_notification(stcb, SCTP_PEER_FAULTY); 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 */ /* no need to unlock here, since the TCB is gone */
} }
} else { } else {
@ -541,6 +542,184 @@ out:
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 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"); 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 * sysctl definitions
@ -604,12 +783,10 @@ SYSCTL_INT(_net_inet_sctp, OID_AUTO, asoc_resource, CTLFLAG_RW,
&sctp_asoc_free_resc_limit, 0, &sctp_asoc_free_resc_limit, 0,
"Max number of cached resources in an asoc"); "Max number of cached resources in an asoc");
SYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW, SYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW,
&sctp_chunkscale, 0, &sctp_chunkscale, 0,
"Tuneable for Scaling of number of chunks and messages"); "Tuneable for Scaling of number of chunks and messages");
SYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW, SYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW,
&sctp_delayed_sack_time_default, 0, &sctp_delayed_sack_time_default, 0,
"Default delayed SACK timer in msec"); "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, &sctp_add_more_threshold, 0,
"When space wise is it worthwhile to try to add more to a socket send buffer"); "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, SYSCTL_UINT(_net_inet_sctp, OID_AUTO, nr_outgoing_streams, CTLFLAG_RW,
&sctp_nr_outgoing_streams_default, 0, &sctp_nr_outgoing_streams_default, 0,
"Default number of outgoing streams"); "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, SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW,
&sctpstat, sctpstat, &sctpstat, sctpstat,
"SCTP statistics (struct sctps_stat, netinet/sctp.h"); "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 #ifdef SCTP_DEBUG
SYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW, SYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW,
&sctp_debug_on, 0, "Configure debug output"); &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_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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 */ /* No unlock tcb assoc is gone */
splx(s); splx(s);
return (0); return (0);
@ -1187,8 +1368,9 @@ sctp_disconnect(struct socket *so)
SCTP_CAUSE_USER_INITIATED_ABT); SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(op_err->m_len); ph->param_length = htons(op_err->m_len);
ippp = (uint32_t *) (ph + 1); 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_send_abort_tcb(stcb, op_err);
SCTP_STAT_INCR_COUNTER32(sctps_aborted); SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 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_STAT_DECR_GAUGE32(sctps_currestab);
} }
SCTP_INP_RUNLOCK(inp); 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); splx(s);
return (0); return (0);
} }
@ -1325,8 +1507,9 @@ sctp_shutdown(struct socket *so)
SCTP_CAUSE_USER_INITIATED_ABT); SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(op_err->m_len); ph->param_length = htons(op_err->m_len);
ippp = (uint32_t *) (ph + 1); 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_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ, SCTP_RESPONSE_TO_USER_REQ,
op_err); op_err);
@ -1744,17 +1927,17 @@ sctp_do_connect_x(struct socket *so,
for (i = 1; i < totaddr; i++) { for (i = 1; i < totaddr; i++) {
if (sa->sa_family == AF_INET) { if (sa->sa_family == AF_INET) {
incr = sizeof(struct sockaddr_in); 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 */ /* 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; error = ENOBUFS;
goto out_now; goto out_now;
} }
} else if (sa->sa_family == AF_INET6) { } else if (sa->sa_family == AF_INET6) {
incr = sizeof(struct sockaddr_in6); 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 */ /* 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; error = ENOBUFS;
goto out_now; goto out_now;
} }
@ -3626,7 +3809,9 @@ sctp_optsset(struct socket *so,
if (stcb->asoc.delayed_connection == 1) { if (stcb->asoc.delayed_connection == 1) {
stcb->asoc.delayed_connection = 0; stcb->asoc.delayed_connection = 0;
SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 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); sctp_send_initiate(inp, stcb);
} else { } else {
/* /*
@ -3928,7 +4113,8 @@ sctp_optsset(struct socket *so,
} }
if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
if (callout_pending(&net->pmtu_timer.timer)) { 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) { if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
net->mtu = paddrp->spp_pathmtu; net->mtu = paddrp->spp_pathmtu;
@ -3983,7 +4169,7 @@ sctp_optsset(struct socket *so,
* addresses * addresses
*/ */
if (cnt_of_unconf == 0) { 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) { if (paddrp->spp_flags & SPP_HB_ENABLE) {

View File

@ -625,7 +625,7 @@ sctp_fill_stat_log(struct mbuf *m)
req->end_at = sctp_cwnd_log_at - 1; req->end_at = sctp_cwnd_log_at - 1;
req->num_ret = sctp_cwnd_log_at; req->num_ret = sctp_cwnd_log_at;
} }
#ifdef INVARIENTS #ifdef INVARIANTS
if (req->num_ret > num) { if (req->num_ret > num) {
panic("Bad statlog get?"); panic("Bad statlog get?");
} }
@ -1269,6 +1269,7 @@ sctp_timeout_handler(void *t)
splx(s); splx(s);
return; return;
} }
tmr->stopped_from = 0xa001;
if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) { if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) {
/* /*
* printf("SCTP timer fired with invalid type: 0x%x\n", * printf("SCTP timer fired with invalid type: 0x%x\n",
@ -1277,11 +1278,13 @@ sctp_timeout_handler(void *t)
splx(s); splx(s);
return; return;
} }
tmr->stopped_from = 0xa002;
if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) { if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) {
splx(s); splx(s);
return; return;
} }
/* if this is an iterator timeout, get the struct and clear inp */ /* if this is an iterator timeout, get the struct and clear inp */
tmr->stopped_from = 0xa003;
if (tmr->type == SCTP_TIMER_TYPE_ITERATOR) { if (tmr->type == SCTP_TIMER_TYPE_ITERATOR) {
it = (struct sctp_iterator *)inp; it = (struct sctp_iterator *)inp;
inp = NULL; inp = NULL;
@ -1300,6 +1303,7 @@ sctp_timeout_handler(void *t)
return; return;
} }
} }
tmr->stopped_from = 0xa004;
if (stcb) { if (stcb) {
if (stcb->asoc.state == 0) { if (stcb->asoc.state == 0) {
splx(s); splx(s);
@ -1309,6 +1313,7 @@ sctp_timeout_handler(void *t)
return; return;
} }
} }
tmr->stopped_from = 0xa005;
#ifdef SCTP_DEBUG #ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_TIMER1) { if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
printf("Timer type %d goes off\n", tmr->type); printf("Timer type %d goes off\n", tmr->type);
@ -1321,6 +1326,10 @@ sctp_timeout_handler(void *t)
} }
return; return;
} }
tmr->stopped_from = 0xa006;
/* record in stopped what t-o occured */
tmr->stopped_from = tmr->type;
if (stcb) { if (stcb) {
atomic_add_int(&stcb->asoc.refcnt, 1); atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_LOCK(stcb); SCTP_TCB_LOCK(stcb);
@ -1523,8 +1532,8 @@ sctp_timeout_handler(void *t)
SCTP_STAT_INCR(sctps_timoassockill); SCTP_STAT_INCR(sctps_timoassockill);
/* Can we free it yet? */ /* Can we free it yet? */
SCTP_INP_DECR_REF(inp); SCTP_INP_DECR_REF(inp);
sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
sctp_free_assoc(inp, stcb, 0); sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
/* /*
* free asoc, always unlocks (or destroy's) so prevent * free asoc, always unlocks (or destroy's) so prevent
* duplicate unlock or unlock of a free mtx :-0 * duplicate unlock or unlock of a free mtx :-0
@ -1539,7 +1548,7 @@ sctp_timeout_handler(void *t)
* killer * killer
*/ */
SCTP_INP_DECR_REF(inp); 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); sctp_inpcb_free(inp, 1, 0);
goto out_no_decr; goto out_no_decr;
break; 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) { if (t_type == SCTP_TIMER_TYPE_SEND) {
stcb->asoc.num_send_timers_up++; stcb->asoc.num_send_timers_up++;
} }
tmr->stopped_from = 0;
tmr->type = t_type; tmr->type = t_type;
tmr->ep = (void *)inp; tmr->ep = (void *)inp;
tmr->tcb = (void *)stcb; tmr->tcb = (void *)stcb;
@ -1943,7 +1953,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
int int
sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 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; 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->self = NULL;
tmr->stopped_from = from;
callout_stop(&tmr->timer); callout_stop(&tmr->timer);
return (0); 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) { } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
/* impossible .. garbage in nothing out */ /* impossible .. garbage in nothing out */
return (((net->lastsa >> 2) + net->lastsv) >> 1); 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 { } else {
/* impossible .. garbage in nothing out */ /* impossible .. garbage in nothing out */
return (((net->lastsa >> 2) + net->lastsv) >> 1); return (((net->lastsa >> 2) + net->lastsv) >> 1);
@ -2378,27 +2395,6 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
/***************************/ /***************************/
/* 2. update RTTVAR & SRTT */ /* 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; o_calctime = calc_time;
/* this is Van Jacobson's integer version */ /* this is Van Jacobson's integer version */
if (net->RTO) { 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); sctp_send_abort(m, iphlen, sh, vtag, op_err);
if (stcb != NULL) { if (stcb != NULL) {
/* Ok, now lets free it */ /* 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 { } else {
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) { 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); SCTP_STAT_DECR_GAUGE32(sctps_currestab);
} }
/* now free the asoc */ /* 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 void
@ -3787,12 +3783,14 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
if (inp == NULL) { if (inp == NULL) {
/* Gak, TSNH!! */ /* Gak, TSNH!! */
#ifdef INVARIENTS #ifdef INVARIANTS
panic("Gak, inp NULL on add_to_readq"); panic("Gak, inp NULL on add_to_readq");
#endif #endif
return; return;
} }
SCTP_INP_READ_LOCK(inp); SCTP_INP_READ_LOCK(inp);
atomic_add_int(&inp->total_recvs, 1);
atomic_add_int(&stcb->total_recvs, 1);
m = control->data; m = control->data;
control->held_length = 0; control->held_length = 0;
control->length = 0; control->length = 0;
@ -3914,7 +3912,7 @@ get_out:
/* Really there should always be a prev */ /* Really there should always be a prev */
if (m == NULL) { if (m == NULL) {
/* Huh nothing left? */ /* Huh nothing left? */
#ifdef INVARIENTS #ifdef INVARIANTS
panic("Nothing left to add?"); panic("Nothing left to add?");
#else #else
goto get_out; goto get_out;
@ -3938,7 +3936,7 @@ get_out:
control->tail_mbuf = tail; control->tail_mbuf = tail;
} else { } else {
/* nothing there */ /* nothing there */
#ifdef INVARIENTS #ifdef INVARIANTS
if (control->data != NULL) { if (control->data != NULL) {
panic("This should NOT happen"); 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_chunk_output(stcb->sctp_ep, stcb,
SCTP_OUTPUT_FROM_USR_RCVD); SCTP_OUTPUT_FROM_USR_RCVD);
/* make sure no timer is running */ /* 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); SCTP_TCB_UNLOCK(stcb);
} else { } else {
/* Update how much we have pending */ /* 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: out:
if (so && r_unlocked && hold_rlock) { if (so && r_unlocked && hold_rlock) {
SCTP_STAT_INCR(sctps_locks_in_rcv);
SCTP_INP_READ_LOCK(stcb->sctp_ep); SCTP_INP_READ_LOCK(stcb->sctp_ep);
} }
SCTP_INP_DECR_REF(stcb->sctp_ep); SCTP_INP_DECR_REF(stcb->sctp_ep);
@ -4438,7 +4435,7 @@ restart_nosblocks:
} }
control = TAILQ_FIRST(&inp->read_queue); control = TAILQ_FIRST(&inp->read_queue);
if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { if ((control == NULL) && (so->so_rcv.sb_cc != 0)) {
#ifdef INVARIENTS #ifdef INVARIANTS
panic("Huh, its non zero and nothing on control?"); panic("Huh, its non zero and nothing on control?");
#endif #endif
so->so_rcv.sb_cc = 0; so->so_rcv.sb_cc = 0;
@ -4454,7 +4451,6 @@ restart_nosblocks:
* pdapi.. maybe a peer in EEOR that just closed after * pdapi.. maybe a peer in EEOR that just closed after
* sending and never indicated a EOR. * sending and never indicated a EOR.
*/ */
SCTP_STAT_INCR(sctps_locks_in_rcva);
if (hold_rlock == 0) { if (hold_rlock == 0) {
hold_rlock = 1; hold_rlock = 1;
SCTP_INP_READ_LOCK(inp); SCTP_INP_READ_LOCK(inp);
@ -4701,7 +4697,6 @@ get_more_data:
m->m_len, m->m_len,
control->length); control->length);
#endif #endif
SCTP_STAT_INCR(sctps_locks_in_rcvb);
SCTP_INP_READ_LOCK(inp); SCTP_INP_READ_LOCK(inp);
hold_rlock = 1; hold_rlock = 1;
} }
@ -4756,7 +4751,7 @@ get_more_data:
* lock ok to null tail * lock ok to null tail
*/ */
if (control->data == NULL) { if (control->data == NULL) {
#ifdef INVARIENTS #ifdef INVARIANTS
if ((control->end_added == 0) || if ((control->end_added == 0) ||
(TAILQ_NEXT(control, next) == NULL)) { (TAILQ_NEXT(control, next) == NULL)) {
/* /*
@ -4772,7 +4767,7 @@ get_more_data:
} }
#endif #endif
control->tail_mbuf = NULL; control->tail_mbuf = NULL;
#ifdef INVARIENTS #ifdef INVARIANTS
if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) {
panic("end_added, nothing left and no MSG_EOR"); panic("end_added, nothing left and no MSG_EOR");
} }
@ -4854,7 +4849,7 @@ get_more_data:
/* we are done with this control */ /* we are done with this control */
if (control->length == 0) { if (control->length == 0) {
if (control->data) { if (control->data) {
#ifdef INVARIENTS #ifdef INVARIANTS
panic("control->data not null at read eor?"); panic("control->data not null at read eor?");
#else #else
printf("Strange, data left in the control buffer .. invarients would panic?\n"); printf("Strange, data left in the control buffer .. invarients would panic?\n");
@ -4880,7 +4875,6 @@ get_more_data:
* queue). * queue).
*/ */
if (hold_rlock == 0) { if (hold_rlock == 0) {
SCTP_STAT_INCR(sctps_locks_in_rcvc);
SCTP_INP_READ_LOCK(inp); SCTP_INP_READ_LOCK(inp);
hold_rlock = 1; hold_rlock = 1;
} }
@ -4907,7 +4901,7 @@ get_more_data:
* since we are leaving more behind on the * since we are leaving more behind on the
* control to read. * control to read.
*/ */
#ifdef INVARIENTS #ifdef INVARIANTS
if (control->end_added && (control->data == NULL) && if (control->end_added && (control->data == NULL) &&
(control->tail_mbuf == NULL)) { (control->tail_mbuf == NULL)) {
panic("Gak, control->length is corrupt?"); panic("Gak, control->length is corrupt?");
@ -5000,7 +4994,6 @@ wait_some_more:
goto done_with_control; goto done_with_control;
} }
if (so->so_rcv.sb_cc > held_length) { if (so->so_rcv.sb_cc > held_length) {
SCTP_STAT_INCR(sctps_locks_in_rcvf);
control->held_length = so->so_rcv.sb_cc; control->held_length = so->so_rcv.sb_cc;
held_length = 0; held_length = 0;
} }

View File

@ -75,7 +75,7 @@ sctp_timer_start(int, struct sctp_inpcb *, struct sctp_tcb *,
int int
sctp_timer_stop(int, struct sctp_inpcb *, struct sctp_tcb *, 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); uint32_t sctp_calculate_sum(struct mbuf *, int32_t *, uint32_t);

View File

@ -241,6 +241,14 @@ sctp_skip_csum:
(u_int8_t *) & chunk_buf); (u_int8_t *) & chunk_buf);
sh->v_tag = init_chk->init.initiate_tag; sh->v_tag = init_chk->init.initiate_tag;
} }
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); sctp_send_abort(m, iphlen, sh, 0, NULL);
goto bad; goto bad;
} else if (stcb == NULL) { } else if (stcb == NULL) {
@ -326,7 +334,7 @@ sctp6_notify_mbuf(struct sctp_inpcb *inp,
*/ */
nxtsz = ntohl(icmp6->icmp6_mtu); nxtsz = ntohl(icmp6->icmp6_mtu);
/* Stop any PMTU timer */ /* 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 */ /* Adjust destination size limit */
if (net->mtu > nxtsz) { if (net->mtu > nxtsz) {
@ -822,7 +830,8 @@ sctp6_disconnect(struct socket *so)
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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 */ /* No unlock tcb assoc is gone */
splx(s); splx(s);
return (0); return (0);