From owner-svn-src-head@freebsd.org Thu Apr 7 09:10:36 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 2AA11B076D6; Thu, 7 Apr 2016 09:10:36 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id BA25C1FE2; Thu, 7 Apr 2016 09:10:35 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u379AZZR007126; Thu, 7 Apr 2016 09:10:35 GMT (envelope-from rrs@FreeBSD.org) Received: (from rrs@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u379AYhh007120; Thu, 7 Apr 2016 09:10:34 GMT (envelope-from rrs@FreeBSD.org) Message-Id: <201604070910.u379AYhh007120@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rrs set sender to rrs@FreeBSD.org using -f From: Randall Stewart Date: Thu, 7 Apr 2016 09:10:34 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r297662 - head/sys/netinet X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Apr 2016 09:10:36 -0000 Author: rrs Date: Thu Apr 7 09:10:34 2016 New Revision: 297662 URL: https://svnweb.freebsd.org/changeset/base/297662 Log: This is work done by Michael Tuexen and myself at the IETF. This adds the new I-Data (Interleaved Data) message. This allows a user to be able to have complete freedom from Head Of Line blocking that was previously there due to the in-ability to send multiple large messages without the TSN's being in sequence. The code as been tested with Michaels various packet drill scripts as well as inter-networking between the IETF's location in Argentina and Germany. Modified: head/sys/netinet/sctp.h head/sys/netinet/sctp_constants.h head/sys/netinet/sctp_dtrace_define.h head/sys/netinet/sctp_header.h head/sys/netinet/sctp_indata.c head/sys/netinet/sctp_indata.h head/sys/netinet/sctp_input.c head/sys/netinet/sctp_os_bsd.h head/sys/netinet/sctp_output.c head/sys/netinet/sctp_pcb.c head/sys/netinet/sctp_pcb.h head/sys/netinet/sctp_structs.h head/sys/netinet/sctp_sysctl.h head/sys/netinet/sctp_uio.h head/sys/netinet/sctp_usrreq.c head/sys/netinet/sctp_var.h head/sys/netinet/sctputil.c head/sys/netinet/sctputil.h Modified: head/sys/netinet/sctp.h ============================================================================== --- head/sys/netinet/sctp.h Thu Apr 7 08:32:37 2016 (r297661) +++ head/sys/netinet/sctp.h Thu Apr 7 09:10:34 2016 (r297662) @@ -196,6 +196,9 @@ struct sctp_paramhdr { #define SCTP_SS_VALUE 0x00001204 #define SCTP_CC_OPTION 0x00001205 /* Options for CC * modules */ +/* For I-DATA */ +#define SCTP_INTERLEAVING_SUPPORTED 0x00001206 + /* read only */ #define SCTP_GET_SNDBUF_USE 0x00001101 #define SCTP_GET_STAT_LOG 0x00001103 @@ -452,6 +455,7 @@ struct sctp_error_auth_invalid_hmac { /* EY nr_sack chunk id*/ #define SCTP_NR_SELECTIVE_ACK 0x10 /************0x40 series ***********/ +#define SCTP_IDATA 0x40 /************0x80 series ***********/ /* RFC5061 */ #define SCTP_ASCONF_ACK 0x80 @@ -467,7 +471,7 @@ struct sctp_error_auth_invalid_hmac { #define SCTP_FORWARD_CUM_TSN 0xc0 /* RFC5061 */ #define SCTP_ASCONF 0xc1 - +#define SCTP_IFORWARD_CUM_TSN 0xc2 /* ABORT and SHUTDOWN COMPLETE FLAG */ #define SCTP_HAD_NO_TCB 0x01 Modified: head/sys/netinet/sctp_constants.h ============================================================================== --- head/sys/netinet/sctp_constants.h Thu Apr 7 08:32:37 2016 (r297661) +++ head/sys/netinet/sctp_constants.h Thu Apr 7 09:10:34 2016 (r297662) @@ -386,8 +386,8 @@ __FBSDID("$FreeBSD$"); /* align to 32-bit sizes */ #define SCTP_SIZE32(x) ((((x) + 3) >> 2) << 2) -#define IS_SCTP_CONTROL(a) ((a)->chunk_type != SCTP_DATA) -#define IS_SCTP_DATA(a) ((a)->chunk_type == SCTP_DATA) +#define IS_SCTP_CONTROL(a) (((a)->chunk_type != SCTP_DATA) && ((a)->chunk_type != SCTP_IDATA)) +#define IS_SCTP_DATA(a) (((a)->chunk_type == SCTP_DATA) || ((a)->chunk_type == SCTP_IDATA)) /* SCTP parameter types */ @@ -886,12 +886,19 @@ __FBSDID("$FreeBSD$"); /* modular comparison */ /* See RFC 1982 for details. */ -#define SCTP_SSN_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \ - ((a > b) && ((uint16_t)(a - b) < (1U<<15)))) -#define SCTP_SSN_GE(a, b) (SCTP_SSN_GT(a, b) || (a == b)) -#define SCTP_TSN_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \ - ((a > b) && ((uint32_t)(a - b) < (1U<<31)))) -#define SCTP_TSN_GE(a, b) (SCTP_TSN_GT(a, b) || (a == b)) +#define SCTP_UINT16_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \ + ((a > b) && ((uint16_t)(a - b) < (1U<<15)))) +#define SCTP_UINT16_GE(a, b) (SCTP_UINT16_GT(a, b) || (a == b)) +#define SCTP_UINT32_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \ + ((a > b) && ((uint32_t)(a - b) < (1U<<31)))) +#define SCTP_UINT32_GE(a, b) (SCTP_UINT32_GT(a, b) || (a == b)) + +#define SCTP_SSN_GT(a, b) SCTP_UINT16_GT(a, b) +#define SCTP_SSN_GE(a, b) SCTP_UINT16_GE(a, b) +#define SCTP_TSN_GT(a, b) SCTP_UINT32_GT(a, b) +#define SCTP_TSN_GE(a, b) SCTP_UINT32_GE(a, b) +#define SCTP_MSGID_GT(o, a, b) ((o == 1) ? SCTP_UINT16_GT((uint16_t)a, (uint16_t)b) : SCTP_UINT32_GT(a, b)) +#define SCTP_MSGID_GE(o, a, b) ((o == 1) ? SCTP_UINT16_GE((uint16_t)a, (uint16_t)b) : SCTP_UINT32_GE(a, b)) /* Mapping array manipulation routines */ #define SCTP_IS_TSN_PRESENT(arry, gap) ((arry[(gap >> 3)] >> (gap & 0x07)) & 0x01) Modified: head/sys/netinet/sctp_dtrace_define.h ============================================================================== --- head/sys/netinet/sctp_dtrace_define.h Thu Apr 7 08:32:37 2016 (r297661) +++ head/sys/netinet/sctp_dtrace_define.h Thu Apr 7 09:10:34 2016 (r297662) @@ -45,131 +45,131 @@ SDT_PROVIDER_DEFINE(sctp); /********************************************************/ /* Initial */ SDT_PROBE_DEFINE5(sctp, cwnd, net, init, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /* ACK-INCREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, ack, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /* ACK-INCREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, rttvar, - "uint64_t", /* The Vtag << 32 | localport << 16 | remoteport */ - "uint64_t", /* obw | nbw */ - "uint64_t", /* bwrtt | newrtt */ - "uint64_t", /* flight */ - "uint64_t"); /* (cwnd << 32) | point << 16 | retval(0/1) */ + "uint64_t", /* The Vtag << 32 | localport << 16 | + * remoteport */ + "uint64_t", /* obw | nbw */ + "uint64_t", /* bwrtt | newrtt */ + "uint64_t", /* flight */ + "uint64_t"); /* (cwnd << 32) | point << 16 | retval(0/1) */ SDT_PROBE_DEFINE5(sctp, cwnd, net, rttstep, - "uint64_t", /* The Vtag << 32 | localport << 16 | remoteport */ - "uint64_t", /* obw | nbw */ - "uint64_t", /* bwrtt | newrtt */ - "uint64_t", /* flight */ - "uint64_t"); /* (cwnd << 32) | point << 16 | retval(0/1) */ + "uint64_t", /* The Vtag << 32 | localport << 16 | + * remoteport */ + "uint64_t", /* obw | nbw */ + "uint64_t", /* bwrtt | newrtt */ + "uint64_t", /* flight */ + "uint64_t"); /* (cwnd << 32) | point << 16 | retval(0/1) */ /* FastRetransmit-DECREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, fr, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /* TimeOut-DECREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, to, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /* BurstLimit-DECREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, bl, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /* ECN-DECREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, ecn, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /* PacketDrop-DECREASE */ SDT_PROBE_DEFINE5(sctp, cwnd, net, pd, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The old value of the cwnd */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The old value of the cwnd */ + "int"); /* The new value of the cwnd */ /********************************************************/ /* Rwnd probe - tracks changes in the receiver window for an assoc */ /********************************************************/ SDT_PROBE_DEFINE4(sctp, rwnd, assoc, val, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "int", /* The up/down amount */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "int", /* The up/down amount */ + "int"); /* The new value of the cwnd */ /********************************************************/ /* flight probe - tracks changes in the flight size on a net or assoc */ /********************************************************/ SDT_PROBE_DEFINE5(sctp, flightsize, net, val, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "uintptr_t", /* The pointer to the struct sctp_nets * changing */ - "int", /* The up/down amount */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "uintptr_t", /* The pointer to the struct sctp_nets * + * changing */ + "int", /* The up/down amount */ + "int"); /* The new value of the cwnd */ /********************************************************/ /* The total flight version */ /********************************************************/ SDT_PROBE_DEFINE4(sctp, flightsize, assoc, val, - "uint32_t", /* The Vtag for this end */ - "uint32_t", /* - * The port number of the local side << 16 | port number - * of remote in network byte order. - */ - "int", /* The up/down amount */ - "int"); /* The new value of the cwnd */ + "uint32_t", /* The Vtag for this end */ + "uint32_t", /* The port number of the local side << 16 | + * port number of remote in network byte + * order. */ + "int", /* The up/down amount */ + "int"); /* The new value of the cwnd */ #endif Modified: head/sys/netinet/sctp_header.h ============================================================================== --- head/sys/netinet/sctp_header.h Thu Apr 7 08:32:37 2016 (r297661) +++ head/sys/netinet/sctp_header.h Thu Apr 7 09:10:34 2016 (r297662) @@ -152,6 +152,23 @@ struct sctp_data_chunk { struct sctp_data dp; } SCTP_PACKED; +struct sctp_idata { + uint32_t tsn; + uint16_t stream_id; + uint16_t reserved; /* Where does the SSN go? */ + uint32_t msg_id; + union { + uint32_t protocol_id; + uint32_t fsn; /* Fragment Sequence Number */ + }; + /* user data follows */ +} SCTP_PACKED; + +struct sctp_idata_chunk { + struct sctp_chunkhdr ch; + struct sctp_idata dp; +} SCTP_PACKED; + /* * Structures for the control chunks */ @@ -378,6 +395,12 @@ struct sctp_strseq { uint16_t sequence; } SCTP_PACKED; +struct sctp_strseq_mid { + uint16_t stream; + uint16_t reserved; + uint32_t msg_id; +}; + struct sctp_forward_tsn_msg { struct sctphdr sh; struct sctp_forward_tsn_chunk msg; Modified: head/sys/netinet/sctp_indata.c ============================================================================== --- head/sys/netinet/sctp_indata.c Thu Apr 7 08:32:37 2016 (r297661) +++ head/sys/netinet/sctp_indata.c Thu Apr 7 09:10:34 2016 (r297662) @@ -34,18 +34,22 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include -#include #include +#include #include #include -#include -#include #include +#include #include - - +#include +#include +#include +#include +#include +#include /* * NOTES: On the outbound side of things I need to check the sack timer to * see if I should generate a sack into the chunk queue (if I have data to @@ -55,6 +59,13 @@ __FBSDID("$FreeBSD$"); * This will cause sctp_service_queues() to get called on the top entry in * the list. */ +static void +sctp_add_chk_to_control(struct sctp_queued_to_read *control, + struct sctp_stream_in *strm, + struct sctp_tcb *stcb, + struct sctp_association *asoc, + struct sctp_tmit_chunk *chk); + void sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) @@ -74,9 +85,9 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, st * sctp_soreceive then we will fix this so that ONLY this * associations data is taken into account. */ - if (stcb->sctp_socket == NULL) + if (stcb->sctp_socket == NULL) { return (calc); - + } if (stcb->asoc.sb_cc == 0 && asoc->size_on_reasm_queue == 0 && asoc->size_on_all_streams == 0) { @@ -86,7 +97,6 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, st } /* get actual space */ calc = (uint32_t) sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv); - /* * take out what has NOT been put on socket queue and we yet hold * for putting up. @@ -95,7 +105,6 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, st asoc->cnt_on_reasm_queue * MSIZE)); calc = sctp_sbspace_sub(calc, (uint32_t) (asoc->size_on_all_streams + asoc->cnt_on_all_streams * MSIZE)); - if (calc == 0) { /* out of space */ return (calc); @@ -122,7 +131,7 @@ sctp_build_readq_entry(struct sctp_tcb * struct sctp_nets *net, uint32_t tsn, uint32_t ppid, uint32_t context, uint16_t stream_no, - uint16_t stream_seq, uint8_t flags, + uint32_t stream_seq, uint8_t flags, struct mbuf *dm) { struct sctp_queued_to_read *read_queue_e = NULL; @@ -131,73 +140,26 @@ sctp_build_readq_entry(struct sctp_tcb * if (read_queue_e == NULL) { goto failed_build; } + memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read)); read_queue_e->sinfo_stream = stream_no; read_queue_e->sinfo_ssn = stream_seq; read_queue_e->sinfo_flags = (flags << 8); read_queue_e->sinfo_ppid = ppid; read_queue_e->sinfo_context = context; - read_queue_e->sinfo_timetolive = 0; read_queue_e->sinfo_tsn = tsn; read_queue_e->sinfo_cumtsn = tsn; read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb); + read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff; + TAILQ_INIT(&read_queue_e->reasm); read_queue_e->whoFrom = net; - read_queue_e->length = 0; atomic_add_int(&net->ref_count, 1); read_queue_e->data = dm; - read_queue_e->spec_flags = 0; - read_queue_e->tail_mbuf = NULL; - read_queue_e->aux_data = NULL; - read_queue_e->stcb = stcb; - read_queue_e->port_from = stcb->rport; - read_queue_e->do_not_ref_stcb = 0; - read_queue_e->end_added = 0; - read_queue_e->some_taken = 0; - read_queue_e->pdapi_aborted = 0; -failed_build: - return (read_queue_e); -} - - -/* - * Build out our readq entry based on the incoming packet. - */ -static struct sctp_queued_to_read * -sctp_build_readq_entry_chk(struct sctp_tcb *stcb, - struct sctp_tmit_chunk *chk) -{ - struct sctp_queued_to_read *read_queue_e = NULL; - - sctp_alloc_a_readq(stcb, read_queue_e); - if (read_queue_e == NULL) { - goto failed_build; - } - read_queue_e->sinfo_stream = chk->rec.data.stream_number; - read_queue_e->sinfo_ssn = chk->rec.data.stream_seq; - read_queue_e->sinfo_flags = (chk->rec.data.rcv_flags << 8); - read_queue_e->sinfo_ppid = chk->rec.data.payloadtype; - read_queue_e->sinfo_context = stcb->asoc.context; - read_queue_e->sinfo_timetolive = 0; - read_queue_e->sinfo_tsn = chk->rec.data.TSN_seq; - read_queue_e->sinfo_cumtsn = chk->rec.data.TSN_seq; - read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb); - read_queue_e->whoFrom = chk->whoTo; - read_queue_e->aux_data = NULL; - read_queue_e->length = 0; - atomic_add_int(&chk->whoTo->ref_count, 1); - read_queue_e->data = chk->data; - read_queue_e->tail_mbuf = NULL; read_queue_e->stcb = stcb; read_queue_e->port_from = stcb->rport; - read_queue_e->spec_flags = 0; - read_queue_e->do_not_ref_stcb = 0; - read_queue_e->end_added = 0; - read_queue_e->some_taken = 0; - read_queue_e->pdapi_aborted = 0; failed_build: return (read_queue_e); } - struct mbuf * sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo) { @@ -317,6 +279,7 @@ sctp_mark_non_revokable(struct sctp_asso { uint32_t gap, i, cumackp1; int fnd = 0; + int in_r = 0, in_nr = 0; if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { return; @@ -330,15 +293,20 @@ sctp_mark_non_revokable(struct sctp_asso return; } SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); - if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { + in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap); + in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap); + if ((in_r == 0) && (in_nr == 0)) { +#ifdef INVARIANTS + panic("Things are really messed up now"); +#else SCTP_PRINTF("gap:%x tsn:%x\n", gap, tsn); sctp_print_mapping_array(asoc); -#ifdef INVARIANTS - panic("Things are really messed up now!!"); #endif } - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); + if (in_nr == 0) + SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); + if (in_r) + SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { asoc->highest_tsn_inside_nr_map = tsn; } @@ -358,191 +326,157 @@ sctp_mark_non_revokable(struct sctp_asso } } - -/* - * We are delivering currently from the reassembly queue. We must continue to - * deliver until we either: 1) run out of space. 2) run out of sequential - * TSN's 3) hit the SCTP_DATA_LAST_FRAG flag. - */ -static void -sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc) +static int +sctp_place_control_in_stream(struct sctp_stream_in *strm, + struct sctp_association *asoc, + struct sctp_queued_to_read *control) { - struct sctp_tmit_chunk *chk, *nchk; - uint16_t nxt_todel; - uint16_t stream_no; - int end = 0; - int cntDel; - struct sctp_queued_to_read *control, *ctl, *nctl; - - if (stcb == NULL) - return; + struct sctp_queued_to_read *at; + struct sctp_readhead *q; + uint8_t bits, unordered; - cntDel = stream_no = 0; - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* socket above is long gone or going.. */ -abandon: - asoc->fragmented_delivery_inprogress = 0; - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - /* - * Lose the data pointer, since its in the socket - * buffer - */ - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; + bits = (control->sinfo_flags >> 8); + unordered = bits & SCTP_DATA_UNORDERED; + if (unordered) { + q = &strm->uno_inqueue; + if (asoc->idata_supported == 0) { + if (!TAILQ_EMPTY(q)) { + /* + * Only one stream can be here in old style + * -- abort + */ + return (-1); } - /* Now free the address and data */ - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - /* sa_ignore FREED_MEMORY */ + TAILQ_INSERT_TAIL(q, control, next_instrm); + control->on_strm_q = SCTP_ON_UNORDERED; + return (0); } - return; + } else { + q = &strm->inqueue; } - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - if (chk->rec.data.TSN_seq != (asoc->tsn_last_delivered + 1)) { - /* Can't deliver more :< */ - return; - } - stream_no = chk->rec.data.stream_number; - nxt_todel = asoc->strmin[stream_no].last_sequence_delivered + 1; - if (nxt_todel != chk->rec.data.stream_seq && - (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { - /* - * Not the next sequence to deliver in its stream OR - * unordered - */ - return; - } - if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - - control = sctp_build_readq_entry_chk(stcb, chk); - if (control == NULL) { - /* out of memory? */ - return; - } - /* save it off for our future deliveries */ - stcb->asoc.control_pdapi = control; - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) - end = 1; - else - end = 0; - sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); - sctp_add_to_readq(stcb->sctp_ep, - stcb, control, &stcb->sctp_socket->so_rcv, end, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - cntDel++; + if ((bits & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + control->end_added = control->last_frag_seen = control->first_frag_seen = 1; + } + if (TAILQ_EMPTY(q)) { + /* Empty queue */ + TAILQ_INSERT_HEAD(q, control, next_instrm); + if (unordered) { + control->on_strm_q = SCTP_ON_UNORDERED; } else { - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) - end = 1; - else - end = 0; - sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); - if (sctp_append_to_readq(stcb->sctp_ep, stcb, - stcb->asoc.control_pdapi, - chk->data, end, chk->rec.data.TSN_seq, - &stcb->sctp_socket->so_rcv)) { + control->on_strm_q = SCTP_ON_ORDERED; + } + return (0); + } else { + TAILQ_FOREACH(at, q, next_instrm) { + if (SCTP_TSN_GT(at->msg_id, control->msg_id)) { /* - * something is very wrong, either - * control_pdapi is NULL, or the tail_mbuf - * is corrupt, or there is a EOM already on - * the mbuf chain. + * one in queue is bigger than the new one, + * insert before this one */ - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - goto abandon; + TAILQ_INSERT_BEFORE(at, control, next_instrm); + if (unordered) { + control->on_strm_q = SCTP_ON_UNORDERED; } else { -#ifdef INVARIANTS - if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) { - panic("This should not happen control_pdapi NULL?"); + control->on_strm_q = SCTP_ON_ORDERED; + } + break; + } else if (at->msg_id == control->msg_id) { + /* + * Gak, He sent me a duplicate msg id + * number?? return -1 to abort. + */ + return (-1); + } else { + if (TAILQ_NEXT(at, next_instrm) == NULL) { + /* + * We are at the end, insert it + * after this one + */ + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { + sctp_log_strm_del(control, at, + SCTP_STR_LOG_FROM_INSERT_TL); } - /* if we did not panic, it was a EOM */ - panic("Bad chunking ??"); -#else - if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) { - SCTP_PRINTF("This should not happen control_pdapi NULL?\n"); + TAILQ_INSERT_AFTER(q, + at, control, next_instrm); + if (unordered) { + control->on_strm_q = SCTP_ON_UNORDERED; + } else { + control->on_strm_q = SCTP_ON_ORDERED; } - SCTP_PRINTF("Bad chunking ??\n"); - SCTP_PRINTF("Dumping re-assembly queue this will probably hose the association\n"); - -#endif - goto abandon; + break; } } - cntDel++; - } - /* pull it we did it */ - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - asoc->fragmented_delivery_inprogress = 0; - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { - asoc->strmin[stream_no].last_sequence_delivered++; - } - if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { - SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); - } - } else if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - /* - * turn the flag back on since we just delivered - * yet another one. - */ - asoc->fragmented_delivery_inprogress = 1; } - asoc->tsn_of_pdapi_last_delivered = chk->rec.data.TSN_seq; - asoc->last_flags_delivered = chk->rec.data.rcv_flags; - asoc->last_strm_seq_delivered = chk->rec.data.stream_seq; - asoc->last_strm_no_delivered = chk->rec.data.stream_number; + } + return (0); +} - asoc->tsn_last_delivered = chk->rec.data.TSN_seq; - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - /* free up the chk */ - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); +static void +sctp_abort_in_reasm(struct sctp_tcb *stcb, + struct sctp_stream_in *strm, + struct sctp_queued_to_read *control, + struct sctp_tmit_chunk *chk, + int *abort_flag, int opspot) +{ + char msg[SCTP_DIAG_INFO_LEN]; + struct mbuf *oper; - if (asoc->fragmented_delivery_inprogress == 0) { - /* - * Now lets see if we can deliver the next one on - * the stream - */ - struct sctp_stream_in *strm; + if (stcb->asoc.idata_supported) { + snprintf(msg, sizeof(msg), + "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x", + opspot, + control->fsn_included, + chk->rec.data.TSN_seq, + chk->rec.data.stream_number, + chk->rec.data.fsn_num, chk->rec.data.stream_seq); + } else { + snprintf(msg, sizeof(msg), + "Reass %x, CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x, SSN:%4.4x", + opspot, + control->fsn_included, + chk->rec.data.TSN_seq, + chk->rec.data.stream_number, + chk->rec.data.fsn_num, + (uint16_t) chk->rec.data.stream_seq); + } + oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + sctp_m_freem(chk->data); + chk->data = NULL; + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; + sctp_abort_an_association(stcb->sctp_ep, stcb, oper, SCTP_SO_NOT_LOCKED); + *abort_flag = 1; +} - strm = &asoc->strmin[stream_no]; - nxt_todel = strm->last_sequence_delivered + 1; - TAILQ_FOREACH_SAFE(ctl, &strm->inqueue, next, nctl) { - /* Deliver more if we can. */ - if (nxt_todel == ctl->sinfo_ssn) { - TAILQ_REMOVE(&strm->inqueue, ctl, next); - asoc->size_on_all_streams -= ctl->length; - sctp_ucount_decr(asoc->cnt_on_all_streams); - strm->last_sequence_delivered++; - sctp_mark_non_revokable(asoc, ctl->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - ctl, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - } else { - break; - } - nxt_todel = strm->last_sequence_delivered + 1; - } - break; - } +static void +clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control) +{ + /* + * The control could not be placed and must be cleaned. + */ + struct sctp_tmit_chunk *chk, *nchk; + + TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { + TAILQ_REMOVE(&control->reasm, chk, sctp_next); + if (chk->data) + sctp_m_freem(chk->data); + chk->data = NULL; + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); } + sctp_free_a_readq(stcb, control); } /* * Queue the chunk either right into the socket buffer if it is the next one * to go OR put it in the correct place in the delivery queue. If we do - * append to the so_buf, keep doing so until we are out of order. One big - * question still remains, what to do when the socket buffer is FULL?? + * append to the so_buf, keep doing so until we are out of order as + * long as the control's entered are non-fragmented. */ static void -sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_queued_to_read *control, int *abort_flag) +sctp_queue_data_to_stream(struct sctp_tcb *stcb, + struct sctp_stream_in *strm, + struct sctp_association *asoc, + struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm) { /* * FIX-ME maybe? What happens when the ssn wraps? If we are getting @@ -562,27 +496,16 @@ sctp_queue_data_to_stream(struct sctp_tc * SSN alone. Maybe a hybred approach is the answer * */ - struct sctp_stream_in *strm; struct sctp_queued_to_read *at; int queue_needed; - uint16_t nxt_todel; + uint32_t nxt_todel; struct mbuf *op_err; char msg[SCTP_DIAG_INFO_LEN]; - queue_needed = 1; - asoc->size_on_all_streams += control->length; - sctp_ucount_incr(asoc->cnt_on_all_streams); - strm = &asoc->strmin[control->sinfo_stream]; - nxt_todel = strm->last_sequence_delivered + 1; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD); } - SCTPDBG(SCTP_DEBUG_INDATA1, - "queue to stream called for sid:%u ssn:%u tsn:%u lastdel:%u nxt:%u\n", - (uint32_t) control->sinfo_stream, (uint32_t) control->sinfo_ssn, - (uint32_t) control->sinfo_tsn, - (uint32_t) strm->last_sequence_delivered, (uint32_t) nxt_todel); - if (SCTP_SSN_GE(strm->last_sequence_delivered, control->sinfo_ssn)) { + if (SCTP_MSGID_GT((!asoc->idata_supported), strm->last_sequence_delivered, control->sinfo_ssn)) { /* The incoming sseq is behind where we last delivered? */ SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ:%d delivered:%d from peer, Abort association\n", control->sinfo_ssn, strm->last_sequence_delivered); @@ -591,32 +514,39 @@ protocol_error: * throw it in the stream so it gets cleaned up in * association destruction */ - TAILQ_INSERT_HEAD(&strm->inqueue, control, next); + TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm); snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", strm->last_sequence_delivered, control->sinfo_tsn, control->sinfo_stream, control->sinfo_ssn); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; } + if ((SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) && (asoc->idata_supported == 0)) { + goto protocol_error; + } + queue_needed = 1; + asoc->size_on_all_streams += control->length; + sctp_ucount_incr(asoc->cnt_on_all_streams); + nxt_todel = strm->last_sequence_delivered + 1; + if (nxt_todel == control->sinfo_ssn) { #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; + struct socket *so; - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } + so = SCTP_INP_SO(stcb->sctp_ep); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { + SCTP_SOCKET_UNLOCK(so, 1); + return; + } #endif - if (nxt_todel == control->sinfo_ssn) { /* can be delivered right away? */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL); @@ -626,19 +556,25 @@ protocol_error: asoc->size_on_all_streams -= control->length; sctp_ucount_decr(asoc->cnt_on_all_streams); strm->last_sequence_delivered++; - sctp_mark_non_revokable(asoc, control->sinfo_tsn); sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED); - TAILQ_FOREACH_SAFE(control, &strm->inqueue, next, at) { + SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); + TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) { /* all delivered */ nxt_todel = strm->last_sequence_delivered + 1; - if (nxt_todel == control->sinfo_ssn) { - TAILQ_REMOVE(&strm->inqueue, control, next); + if ((nxt_todel == control->sinfo_ssn) && + (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) { asoc->size_on_all_streams -= control->length; sctp_ucount_decr(asoc->cnt_on_all_streams); + if (control->on_strm_q == SCTP_ON_ORDERED) { + TAILQ_REMOVE(&strm->inqueue, control, next_instrm); + } else { + panic("Huh control:%p is on_strm_q:%d", + control, control->on_strm_q); + } + control->on_strm_q = 0; strm->last_sequence_delivered++; /* * We ignore the return of deliver_data here @@ -655,655 +591,1000 @@ protocol_error: control, &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, - SCTP_SO_LOCKED); + SCTP_SO_NOT_LOCKED); continue; + } else if (nxt_todel == control->sinfo_ssn) { + *need_reasm = 1; } break; } +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); +#endif } if (queue_needed) { /* * Ok, we did not deliver this guy, find the correct place * to put it on the queue. */ - if (SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) { -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - goto protocol_error; - } - if (TAILQ_EMPTY(&strm->inqueue)) { - /* Empty queue */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INSERT_HD); - } - TAILQ_INSERT_HEAD(&strm->inqueue, control, next); - } else { - TAILQ_FOREACH(at, &strm->inqueue, next) { - if (SCTP_SSN_GT(at->sinfo_ssn, control->sinfo_ssn)) { - /* - * one in queue is bigger than the - * new one, insert before this one - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, at, - SCTP_STR_LOG_FROM_INSERT_MD); - } - TAILQ_INSERT_BEFORE(at, control, next); - break; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***