1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-02-04 17:15:50 +00:00

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.
This commit is contained in:
Randall Stewart 2016-04-07 09:10:34 +00:00
parent 5ce34567e6
commit 44249214d3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=297662
18 changed files with 2264 additions and 1743 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -43,35 +43,31 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
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);
#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, stream_no, stream_seq, flags, dm) do { \
#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, stream_no, stream_seq, flags, dm, tfsn, msgid) do { \
if (_ctl) { \
atomic_add_int(&((net)->ref_count), 1); \
memset(_ctl, 0, sizeof(struct sctp_queued_to_read)); \
(_ctl)->sinfo_stream = stream_no; \
(_ctl)->sinfo_ssn = stream_seq; \
TAILQ_INIT(&_ctl->reasm); \
(_ctl)->top_fsn = tfsn; \
(_ctl)->msg_id = msgid; \
(_ctl)->sinfo_flags = (flags << 8); \
(_ctl)->sinfo_ppid = ppid; \
(_ctl)->sinfo_context = context; \
(_ctl)->sinfo_timetolive = 0; \
(_ctl)->fsn_included = 0xffffffff; \
(_ctl)->top_fsn = 0xffffffff; \
(_ctl)->sinfo_tsn = tsn; \
(_ctl)->sinfo_cumtsn = tsn; \
(_ctl)->sinfo_assoc_id = sctp_get_associd((in_it)); \
(_ctl)->length = 0; \
(_ctl)->held_length = 0; \
(_ctl)->whoFrom = net; \
(_ctl)->data = dm; \
(_ctl)->tail_mbuf = NULL; \
(_ctl)->aux_data = NULL; \
(_ctl)->stcb = (in_it); \
(_ctl)->port_from = (in_it)->rport; \
(_ctl)->spec_flags = 0; \
(_ctl)->do_not_ref_stcb = 0; \
(_ctl)->end_added = 0; \
(_ctl)->pdapi_aborted = 0; \
(_ctl)->some_taken = 0; \
} \
} while (0)

View File

@ -386,17 +386,9 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
if (asoc->strmin != NULL) {
/* Free the old ones */
struct sctp_queued_to_read *ctl, *nctl;
for (i = 0; i < asoc->streamincnt; i++) {
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) {
TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next);
sctp_free_remote_addr(ctl->whoFrom);
ctl->whoFrom = NULL;
sctp_m_freem(ctl->data);
ctl->data = NULL;
sctp_free_a_readq(stcb, ctl);
}
sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue);
sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue);
}
SCTP_FREE(asoc->strmin, SCTP_M_STRMI);
}
@ -414,8 +406,10 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
}
for (i = 0; i < asoc->streamincnt; i++) {
asoc->strmin[i].stream_no = i;
asoc->strmin[i].last_sequence_delivered = 0xffff;
asoc->strmin[i].last_sequence_delivered = 0xffffffff;
TAILQ_INIT(&asoc->strmin[i].inqueue);
TAILQ_INIT(&asoc->strmin[i].uno_inqueue);
asoc->strmin[i].pd_api_started = 0;
asoc->strmin[i].delivery_started = 0;
}
/*
@ -894,6 +888,29 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
* With a normal shutdown we assume the end of last record.
*/
SCTP_INP_READ_LOCK(stcb->sctp_ep);
if (asoc->control_pdapi->on_strm_q) {
struct sctp_stream_in *strm;
strm = &asoc->strmin[asoc->control_pdapi->sinfo_stream];
if (asoc->control_pdapi->on_strm_q == SCTP_ON_UNORDERED) {
/* Unordered */
TAILQ_REMOVE(&strm->uno_inqueue, asoc->control_pdapi, next_instrm);
asoc->control_pdapi->on_strm_q = 0;
} else if (asoc->control_pdapi->on_strm_q == SCTP_ON_ORDERED) {
/* Ordered */
TAILQ_REMOVE(&strm->inqueue, asoc->control_pdapi, next_instrm);
asoc->control_pdapi->on_strm_q = 0;
} else {
panic("Unknown state on ctrl:%p on_strm_q:%d",
asoc->control_pdapi,
asoc->control_pdapi->on_strm_q);
}
}
printf("%s:%d End added to ctl:%p (%d)\n",
__FUNCTION__,
__LINE__,
asoc->control_pdapi,
asoc->control_pdapi->on_strm_q);
asoc->control_pdapi->end_added = 1;
asoc->control_pdapi->pdapi_aborted = 1;
asoc->control_pdapi = NULL;
@ -1009,6 +1026,11 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
* With a normal shutdown we assume the end of last record.
*/
SCTP_INP_READ_LOCK(stcb->sctp_ep);
printf("%s:%d End added to ctl:%p (%d)\n",
__FUNCTION__,
__LINE__,
asoc->control_pdapi,
asoc->control_pdapi->on_strm_q);
asoc->control_pdapi->end_added = 1;
asoc->control_pdapi->pdapi_aborted = 1;
asoc->control_pdapi = NULL;
@ -1083,6 +1105,7 @@ sctp_process_unrecog_chunk(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr,
case SCTP_ASCONF:
sctp_asconf_cleanup(stcb, net);
break;
case SCTP_IFORWARD_CUM_TSN:
case SCTP_FORWARD_CUM_TSN:
stcb->asoc.prsctp_supported = 0;
break;
@ -3450,6 +3473,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
/* resend last asconf ack */
sctp_send_asconf_ack(stcb);
break;
case SCTP_IFORWARD_CUM_TSN:
case SCTP_FORWARD_CUM_TSN:
send_forward_tsn(stcb, &stcb->asoc);
break;
@ -3475,8 +3499,8 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *
uint16_t temp;
/*
* We set things to 0xffff since this is the last delivered sequence
* and we will be sending in 0 after the reset.
* We set things to 0xffffffff since this is the last delivered
* sequence and we will be sending in 0 after the reset.
*/
if (number_entries) {
@ -3485,12 +3509,12 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *
if (temp >= stcb->asoc.streamincnt) {
continue;
}
stcb->asoc.strmin[temp].last_sequence_delivered = 0xffff;
stcb->asoc.strmin[temp].last_sequence_delivered = 0xffffffff;
}
} else {
list = NULL;
for (i = 0; i < stcb->asoc.streamincnt; i++) {
stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
stcb->asoc.strmin[i].last_sequence_delivered = 0xffffffff;
}
}
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED);
@ -4031,20 +4055,28 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
/* copy off the old data */
for (i = 0; i < stcb->asoc.streamincnt; i++) {
TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue);
stcb->asoc.strmin[i].stream_no = i;
stcb->asoc.strmin[i].last_sequence_delivered = oldstrm[i].last_sequence_delivered;
stcb->asoc.strmin[i].delivery_started = oldstrm[i].delivery_started;
stcb->asoc.strmin[i].pd_api_started = oldstrm[i].pd_api_started;
/* now anything on those queues? */
TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next, nctl) {
TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next);
TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next);
TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next_instrm, nctl) {
TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next_instrm);
TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next_instrm);
}
TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].uno_inqueue, next_instrm, nctl) {
TAILQ_REMOVE(&oldstrm[i].uno_inqueue, ctl, next_instrm);
TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].uno_inqueue, ctl, next_instrm);
}
}
/* Init the new streams */
for (i = stcb->asoc.streamincnt; i < num_stream; i++) {
TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue);
stcb->asoc.strmin[i].stream_no = i;
stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
stcb->asoc.strmin[i].last_sequence_delivered = 0xffffffff;
stcb->asoc.strmin[i].pd_api_started = 0;
stcb->asoc.strmin[i].delivery_started = 0;
}
SCTP_FREE(oldstrm, SCTP_M_STRMI);
@ -5441,6 +5473,7 @@ process_control_chunks:
}
break;
case SCTP_FORWARD_CUM_TSN:
case SCTP_IFORWARD_CUM_TSN:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_FWD-TSN\n");
if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) {
/* Its not ours */

View File

@ -480,9 +480,9 @@ sctp_get_mbuf_for_msg(unsigned int space_needed,
#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
{ \
int32_t oldval; \
oldval = atomic_fetchadd_int(addr, -val); \
oldval = atomic_fetchadd_int(addr, -val); \
if (oldval < val) { \
panic("Counter goes negative"); \
panic("Counter goes negative addr:%p val:%d oldval:%d", addr, val, oldval); \
} \
}
#else

View File

@ -3326,10 +3326,11 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
#endif
/**
* Rules: - Find the route if needed, cache if I can. - Look at
* interface address in route, Is it in the bound list. If so we
* have the best source. - If not we must rotate amongst the
* addresses.
* Rules:
* - Find the route if needed, cache if I can.
* - Look at interface address in route, Is it in the bound list. If so we
* have the best source.
* - If not we must rotate amongst the addresses.
*
* Cavets and issues
*
@ -4796,6 +4797,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len);
if (stcb->asoc.prsctp_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
if (stcb->asoc.idata_supported) {
pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN;
}
}
if (stcb->asoc.auth_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION;
@ -4807,6 +4811,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
if (stcb->asoc.reconfig_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
}
if (stcb->asoc.idata_supported) {
pr_supported->chunk_types[num_ext++] = SCTP_IDATA;
}
if (stcb->asoc.nrsack_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
}
@ -5951,6 +5958,10 @@ do_a_abort:
if (((asoc != NULL) && (asoc->prsctp_supported == 1)) ||
((asoc == NULL) && (inp->prsctp_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
if (((asoc != NULL) && (asoc->idata_supported == 1)) ||
((asoc == NULL) && (inp->idata_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN;
}
}
if (((asoc != NULL) && (asoc->auth_supported == 1)) ||
((asoc == NULL) && (inp->auth_supported == 1))) {
@ -5965,6 +5976,10 @@ do_a_abort:
((asoc == NULL) && (inp->reconfig_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
}
if (((asoc != NULL) && (asoc->idata_supported == 1)) ||
((asoc == NULL) && (inp->idata_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_IDATA;
}
if (((asoc != NULL) && (asoc->nrsack_supported == 1)) ||
((asoc == NULL) && (inp->nrsack_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
@ -6232,11 +6247,15 @@ sctp_get_frag_point(struct sctp_tcb *stcb,
* we use a larger frag point.
*/
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
ovh = SCTP_MED_OVERHEAD;
ovh = SCTP_MIN_OVERHEAD;
} else {
ovh = SCTP_MED_V4_OVERHEAD;
ovh = SCTP_MIN_V4_OVERHEAD;
}
if (stcb->asoc.idata_supported) {
ovh += sizeof(struct sctp_idata_chunk);
} else {
ovh += sizeof(struct sctp_data_chunk);
}
if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu)
siz = asoc->smallest_mtu - ovh;
else
@ -6361,6 +6380,8 @@ sctp_msg_append(struct sctp_tcb *stcb,
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
sp->context = srcv->sinfo_context;
sp->fsn = 0;
sp->msg_id = atomic_fetchadd_int(&stcb->asoc.assoc_msg_id, 1);
if (sp->sinfo_flags & SCTP_ADDR_OVER) {
sp->net = net;
atomic_add_int(&sp->net->ref_count, 1);
@ -7163,8 +7184,9 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
struct sctp_association *asoc;
struct sctp_stream_queue_pending *sp;
struct sctp_tmit_chunk *chk;
struct sctp_data_chunk *dchkh;
uint32_t to_move, length;
struct sctp_data_chunk *dchkh = NULL;
struct sctp_idata_chunk *ndchkh = NULL;
uint32_t to_move, length, leading;
uint8_t rcv_flags = 0;
uint8_t some_taken;
uint8_t send_lock_up = 0;
@ -7173,6 +7195,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
asoc = &stcb->asoc;
one_more_time:
/* sa_ignore FREED_MEMORY */
*locked = 0;
sp = TAILQ_FIRST(&strq->outqueue);
if (sp == NULL) {
*locked = 0;
@ -7184,7 +7207,9 @@ one_more_time:
if (sp) {
goto one_more_time;
}
if (strq->last_msg_incomplete) {
if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_EXPLICIT_EOR) == 0) &&
(stcb->asoc.idata_supported == 0) &&
(strq->last_msg_incomplete)) {
SCTP_PRINTF("Huh? Stream:%d lm_in_c=%d but queue is NULL\n",
strq->stream_no,
strq->last_msg_incomplete);
@ -7248,7 +7273,8 @@ one_more_time:
* sender just finished this but still holds a
* reference
*/
*locked = 1;
if (stcb->asoc.idata_supported == 0)
*locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@ -7257,7 +7283,8 @@ one_more_time:
/* is there some to get */
if (sp->length == 0) {
/* no */
*locked = 1;
if (stcb->asoc.idata_supported == 0)
*locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@ -7280,7 +7307,8 @@ one_more_time:
}
sp->length = 0;
sp->some_taken = 1;
*locked = 1;
if (stcb->asoc.idata_supported == 0)
*locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@ -7342,7 +7370,8 @@ re_look:
}
} else {
/* Nothing to take. */
if (sp->some_taken) {
if ((sp->some_taken) &&
(stcb->asoc.idata_supported == 0)) {
*locked = 1;
}
*giveup = 1;
@ -7461,7 +7490,12 @@ dont_do_it:
} else {
atomic_subtract_int(&sp->length, to_move);
}
if (M_LEADINGSPACE(chk->data) < (int)sizeof(struct sctp_data_chunk)) {
if (stcb->asoc.idata_supported == 0) {
leading = (int)sizeof(struct sctp_data_chunk);
} else {
leading = (int)sizeof(struct sctp_idata_chunk);
}
if (M_LEADINGSPACE(chk->data) < leading) {
/* Not enough room for a chunk header, get some */
struct mbuf *m;
@ -7502,7 +7536,11 @@ dont_do_it:
M_ALIGN(chk->data, 4);
}
}
SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT);
if (stcb->asoc.idata_supported == 0) {
SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT);
} else {
SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_idata_chunk), M_NOWAIT);
}
if (chk->data == NULL) {
/* HELP, TSNH since we assured it would not above? */
#ifdef INVARIANTS
@ -7515,8 +7553,13 @@ dont_do_it:
to_move = 0;
goto out_of;
}
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
chk->book_size = chk->send_size = (uint16_t) (to_move + sizeof(struct sctp_data_chunk));
if (stcb->asoc.idata_supported == 0) {
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
chk->book_size = chk->send_size = (uint16_t) (to_move + sizeof(struct sctp_data_chunk));
} else {
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_idata_chunk));
chk->book_size = chk->send_size = (uint16_t) (to_move + sizeof(struct sctp_idata_chunk));
}
chk->book_size_scale = 0;
chk->sent = SCTP_DATAGRAM_UNSENT;
@ -7555,7 +7598,11 @@ dont_do_it:
(uint32_t) ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq),
chk->rec.data.TSN_seq);
}
dchkh = mtod(chk->data, struct sctp_data_chunk *);
if (stcb->asoc.idata_supported == 0) {
dchkh = mtod(chk->data, struct sctp_data_chunk *);
} else {
ndchkh = mtod(chk->data, struct sctp_idata_chunk *);
}
/*
* Put the rest of the things in place now. Size was done earlier in
* previous loop prior to padding.
@ -7577,14 +7624,29 @@ dont_do_it:
asoc->out_tsnlog[asoc->tsn_out_at].in_out = 2;
asoc->tsn_out_at++;
#endif
dchkh->ch.chunk_type = SCTP_DATA;
dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
dchkh->dp.stream_id = htons(strq->stream_no);
dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq);
dchkh->dp.protocol_id = chk->rec.data.payloadtype;
dchkh->ch.chunk_length = htons(chk->send_size);
if (stcb->asoc.idata_supported == 0) {
dchkh->ch.chunk_type = SCTP_DATA;
dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
dchkh->dp.stream_id = htons((strq->stream_no & 0x0000ffff));
dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq);
dchkh->dp.protocol_id = chk->rec.data.payloadtype;
dchkh->ch.chunk_length = htons(chk->send_size);
} else {
ndchkh->ch.chunk_type = SCTP_IDATA;
ndchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
ndchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
ndchkh->dp.stream_id = htons(strq->stream_no);
/* WHAT DO WE DO HERE??? */
ndchkh->dp.reserved = htons(0);
ndchkh->dp.msg_id = htonl(sp->msg_id);
if (sp->fsn == 0)
ndchkh->dp.protocol_id = chk->rec.data.payloadtype;
else
ndchkh->dp.fsn = htonl(sp->fsn);
sp->fsn++;
ndchkh->ch.chunk_length = htons(chk->send_size);
}
/* Now advance the chk->send_size by the actual pad needed. */
if (chk->send_size < SCTP_SIZE32(chk->book_size)) {
/* need a pad */
@ -7640,7 +7702,8 @@ dont_do_it:
stcb->asoc.locked_on_sending = NULL;
} else {
/* more to go, we are locked */
*locked = 1;
if (stcb->asoc.idata_supported == 0)
*locked = 1;
}
asoc->chunks_on_out_queue++;
strq->chunks_on_queues++;
@ -7686,7 +7749,11 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
break;
}
/* Need an allowance for the data chunk header too */
goal_mtu -= sizeof(struct sctp_data_chunk);
if (stcb->asoc.idata_supported == 0) {
goal_mtu -= sizeof(struct sctp_data_chunk);
} else {
goal_mtu -= sizeof(struct sctp_idata_chunk);
}
/* must make even word boundary */
goal_mtu &= 0xfffffffc;
@ -7797,12 +7864,15 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
{
/**
* Ok this is the generic chunk service queue. we must do the
* following: - Service the stream queue that is next, moving any
* message (note I must get a complete message i.e. FIRST/MIDDLE and
* LAST to the out queue in one pass) and assigning TSN's - Check to
* see if the cwnd/rwnd allows any output, if so we go ahead and
* fomulate and send the low level chunks. Making sure to combine
* any control in the control chunk queue also.
* following:
* - Service the stream queue that is next, moving any
* message (note I must get a complete message i.e. FIRST/MIDDLE and
* LAST to the out queue in one pass) and assigning TSN's. This
* only applys though if the peer does not support NDATA. For NDATA
* chunks its ok to not send the entire message ;-)
* - Check to see if the cwnd/rwnd allows any output, if so we go ahead and
* fomulate and send the low level chunks. Making sure to combine
* any control in the control chunk queue also.
*/
struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL;
struct mbuf *outchain, *endoutchain;
@ -10225,7 +10295,13 @@ send_forward_tsn(struct sctp_tcb *stcb,
struct sctp_tmit_chunk *chk;
struct sctp_forward_tsn_chunk *fwdtsn;
uint32_t advance_peer_ack_point;
int old;
if (asoc->idata_supported) {
old = 0;
} else {
old = 1;
}
SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) {
@ -10247,6 +10323,11 @@ send_forward_tsn(struct sctp_tcb *stcb,
}
asoc->fwd_tsn_cnt++;
chk->copy_by_ref = 0;
/*
* We don't do the old thing here since this is used not for on-wire
* but to tell if we are sending a fwd-tsn by the stack during
* output. And if its a IFORWARD or a FORWARD it is a fwd-tsn.
*/
chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN;
chk->rec.chunk_id.can_take_data = 0;
chk->flags = 0;
@ -10271,6 +10352,7 @@ sctp_fill_in_rest:
{
struct sctp_tmit_chunk *at, *tp1, *last;
struct sctp_strseq *strseq;
struct sctp_strseq_mid *strseq_m;
unsigned int cnt_of_space, i, ovh;
unsigned int space_needed;
unsigned int cnt_of_skipped = 0;
@ -10287,9 +10369,13 @@ sctp_fill_in_rest:
}
cnt_of_skipped++;
}
space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
(cnt_of_skipped * sizeof(struct sctp_strseq)));
if (old) {
space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
(cnt_of_skipped * sizeof(struct sctp_strseq)));
} else {
space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
(cnt_of_skipped * sizeof(struct sctp_strseq_mid)));
}
cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data);
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
@ -10318,8 +10404,13 @@ sctp_fill_in_rest:
0xff, 0xff, cnt_of_space,
space_needed);
}
cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
cnt_of_skipped /= sizeof(struct sctp_strseq);
if (old) {
cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
cnt_of_skipped /= sizeof(struct sctp_strseq);
} else {
cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
cnt_of_skipped /= sizeof(struct sctp_strseq_mid);
}
/*-
* Go through and find the TSN that will be the one
* we report.
@ -10346,15 +10437,24 @@ sctp_fill_in_rest:
*/
if (last)
advance_peer_ack_point = last->rec.data.TSN_seq;
space_needed = sizeof(struct sctp_forward_tsn_chunk) +
cnt_of_skipped * sizeof(struct sctp_strseq);
if (old) {
space_needed = sizeof(struct sctp_forward_tsn_chunk) +
cnt_of_skipped * sizeof(struct sctp_strseq);
} else {
space_needed = sizeof(struct sctp_forward_tsn_chunk) +
cnt_of_skipped * sizeof(struct sctp_strseq_mid);
}
}
chk->send_size = space_needed;
/* Setup the chunk */
fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
fwdtsn->ch.chunk_length = htons(chk->send_size);
fwdtsn->ch.chunk_flags = 0;
fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
if (old) {
fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
} else {
fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN;
}
fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
SCTP_BUF_LEN(chk->data) = chk->send_size;
fwdtsn++;
@ -10362,7 +10462,11 @@ sctp_fill_in_rest:
* Move pointer to after the fwdtsn and transfer to the
* strseq pointer.
*/
strseq = (struct sctp_strseq *)fwdtsn;
if (old) {
strseq = (struct sctp_strseq *)fwdtsn;
} else {
strseq_m = (struct sctp_strseq_mid *)fwdtsn;
}
/*-
* Now populate the strseq list. This is done blindly
* without pulling out duplicate stream info. This is
@ -10389,9 +10493,15 @@ sctp_fill_in_rest:
if (at->rec.data.TSN_seq == advance_peer_ack_point) {
at->rec.data.fwd_tsn_cnt = 0;
}
strseq->stream = ntohs(at->rec.data.stream_number);
strseq->sequence = ntohs(at->rec.data.stream_seq);
strseq++;
if (old) {
strseq->stream = ntohs(at->rec.data.stream_number);
strseq->sequence = ntohs(at->rec.data.stream_seq);
strseq++;
} else {
strseq_m->stream = ntohs(at->rec.data.stream_number);
strseq_m->msg_id = ntohl(at->rec.data.stream_seq);
strseq_m++;
}
at = tp1;
}
}
@ -12312,6 +12422,8 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
sp->context = srcv->sinfo_context;
sp->fsn = 0;
sp->msg_id = atomic_fetchadd_int(&stcb->asoc.assoc_msg_id, 1);
(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
sp->stream = srcv->sinfo_stream;
@ -13065,8 +13177,10 @@ skip_preblock:
* interrupt.
*/
strm->last_msg_incomplete = 1;
asoc->stream_locked = 1;
asoc->stream_locked_on = srcv->sinfo_stream;
if (stcb->asoc.idata_supported == 0) {
asoc->stream_locked = 1;
asoc->stream_locked_on = srcv->sinfo_stream;
}
sp->sender_all_done = 0;
}
sctp_snd_sb_alloc(stcb, sp->length);
@ -13325,8 +13439,10 @@ skip_preblock:
if (sp) {
if (sp->msg_is_complete == 0) {
strm->last_msg_incomplete = 1;
asoc->stream_locked = 1;
asoc->stream_locked_on = srcv->sinfo_stream;
if (stcb->asoc.idata_supported == 0) {
asoc->stream_locked = 1;
asoc->stream_locked_on = srcv->sinfo_stream;
}
} else {
sp->sender_all_done = 1;
strm->last_msg_incomplete = 0;

View File

@ -2476,6 +2476,8 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
inp->reconfig_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_reconfig_enable);
inp->nrsack_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_nrsack_enable);
inp->pktdrop_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_pktdrop_enable);
inp->idata_supported = 0;
inp->fibnum = so->so_fibnum;
/* init the small hash table we use to track asocid <-> tcb */
inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark);
@ -3660,8 +3662,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* no need to free the net count, since at this point all
* assoc's are gone.
*/
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq);
SCTP_DECR_READQ_COUNT();
sctp_free_a_readq(NULL, sq);
}
/* Now the sctp_pcb things */
/*
@ -4649,6 +4650,45 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t
}
}
void
sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh)
{
struct sctp_tmit_chunk *chk, *nchk;
struct sctp_queued_to_read *ctl, *nctl;
TAILQ_FOREACH_SAFE(ctl, rh, next_instrm, nctl) {
TAILQ_REMOVE(rh, ctl, next_instrm);
ctl->on_strm_q = 0;
if (ctl->on_read_q == 0) {
sctp_free_remote_addr(ctl->whoFrom);
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
}
}
/* Reassembly free? */
TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
if (chk->holds_key_ref)
sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED);
sctp_free_remote_addr(chk->whoTo);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
SCTP_DECR_CHK_COUNT();
/* sa_ignore FREED_MEMORY */
}
/*
* We don't free the address here since all the net's were
* freed above.
*/
if (ctl->on_read_q == 0) {
sctp_free_a_readq(stcb, ctl);
}
}
}
/*-
@ -4986,8 +5026,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
sq->whoFrom = NULL;
sq->stcb = NULL;
/* Free the ctl entry */
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq);
SCTP_DECR_READQ_COUNT();
sctp_free_a_readq(stcb, sq);
/* sa_ignore FREED_MEMORY */
}
TAILQ_FOREACH_SAFE(chk, &asoc->free_chunks, sctp_next, nchk) {
@ -5100,20 +5139,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_DECR_CHK_COUNT();
/* sa_ignore FREED_MEMORY */
}
TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
if (chk->holds_key_ref)
sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED);
sctp_free_remote_addr(chk->whoTo);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
SCTP_DECR_CHK_COUNT();
/* sa_ignore FREED_MEMORY */
}
if (asoc->mapping_array) {
SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
asoc->mapping_array = NULL;
@ -5129,23 +5154,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
asoc->strm_realoutsize = asoc->streamoutcnt = 0;
if (asoc->strmin) {
struct sctp_queued_to_read *ctl, *nctl;
for (i = 0; i < asoc->streamincnt; i++) {
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) {
TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next);
sctp_free_remote_addr(ctl->whoFrom);
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
}
/*
* We don't free the address here since all
* the net's were freed above.
*/
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl);
SCTP_DECR_READQ_COUNT();
}
sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue);
sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue);
}
SCTP_FREE(asoc->strmin, SCTP_M_STRMI);
asoc->strmin = NULL;
@ -6094,6 +6105,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
uint8_t peer_supports_reconfig;
uint8_t peer_supports_nrsack;
uint8_t peer_supports_pktdrop;
uint8_t peer_supports_idata;
#ifdef INET
struct sockaddr_in sin;
@ -6122,6 +6134,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
} else {
sa = src;
}
peer_supports_idata = 0;
peer_supports_ecn = 0;
peer_supports_prsctp = 0;
peer_supports_auth = 0;
@ -6502,6 +6515,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
case SCTP_AUTHENTICATION:
peer_supports_auth = 1;
break;
case SCTP_IDATA:
peer_supports_idata = 1;
break;
default:
/* one I have not learned yet */
break;
@ -6660,6 +6676,10 @@ next_param:
(peer_supports_reconfig == 0)) {
stcb->asoc.reconfig_supported = 0;
}
if ((stcb->asoc.idata_supported == 1) &&
(peer_supports_idata == 0)) {
stcb->asoc.idata_supported = 0;
}
if ((stcb->asoc.nrsack_supported == 1) &&
(peer_supports_nrsack == 0)) {
stcb->asoc.nrsack_supported = 0;
@ -6851,26 +6871,9 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
SCTP_STAT_INCR(sctps_protocol_drains_done);
cumulative_tsn_p1 = asoc->cumulative_tsn + 1;
cnt = 0;
/* First look in the re-assembly queue */
TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) {
if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn);
asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
}
/* Ok that was fun, now we will drain all the inbound streams? */
for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next, nctl) {
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next_instrm, nctl) {
if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
@ -6878,14 +6881,58 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next);
TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next_instrm);
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
}
sctp_free_remote_addr(ctl->whoFrom);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl);
SCTP_DECR_READQ_COUNT();
/* Now its reasm? */
TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn);
asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&ctl->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, ctl);
}
}
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].uno_inqueue, next_instrm, nctl) {
if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn);
asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, ctl, next_instrm);
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
}
sctp_free_remote_addr(ctl->whoFrom);
/* Now its reasm? */
TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn);
asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&ctl->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, ctl);
}
}
}

View File

@ -410,6 +410,7 @@ struct sctp_inpcb {
uint8_t ecn_supported;
uint8_t prsctp_supported;
uint8_t auth_supported;
uint8_t idata_supported;
uint8_t asconf_supported;
uint8_t reconfig_supported;
uint8_t nrsack_supported;
@ -629,6 +630,8 @@ int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *);
int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp);
void sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh);
/*-
* Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg
* indicates run on ONLY assoc's of the specified endpoint.

View File

@ -389,7 +389,7 @@ struct sctp_nets {
struct sctp_data_chunkrec {
uint32_t TSN_seq; /* the TSN of this transmit */
uint16_t stream_seq; /* the stream sequence number of this transmit */
uint32_t stream_seq; /* the stream sequence number of this transmit */
uint16_t stream_number; /* the stream number of this guy */
uint32_t payloadtype;
uint32_t context; /* from send */
@ -400,6 +400,7 @@ struct sctp_data_chunkrec {
*/
uint32_t fast_retran_tsn; /* sending_seq at the time of FR */
struct timeval timetodrop; /* time we drop it from queue */
uint32_t fsn_num; /* Fragment Sequence Number */
uint8_t doing_fast_retransmit;
uint8_t rcv_flags; /* flags pulled from data chunk on inbound for
* outbound holds sending flags for PR-SCTP. */
@ -458,7 +459,7 @@ struct sctp_tmit_chunk {
*/
struct sctp_queued_to_read { /* sinfo structure Pluse more */
uint16_t sinfo_stream; /* off the wire */
uint16_t sinfo_ssn; /* off the wire */
uint32_t sinfo_ssn; /* off the wire */
uint16_t sinfo_flags; /* SCTP_UNORDERED from wire use SCTP_EOF for
* EOR */
uint32_t sinfo_ppid; /* off the wire */
@ -468,8 +469,11 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
uint32_t sinfo_cumtsn; /* Use this in reassembly as last TSN */
sctp_assoc_t sinfo_assoc_id; /* our assoc id */
/* Non sinfo stuff */
uint32_t msg_id; /* Fragment Index */
uint32_t length; /* length of data */
uint32_t held_length; /* length held in sb */
uint32_t top_fsn; /* Highest FSN in queue */
uint32_t fsn_included; /* Highest FSN in *data portion */
struct sctp_nets *whoFrom; /* where it came from */
struct mbuf *data; /* front of the mbuf chain of data with
* PKT_HDR */
@ -478,14 +482,24 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
* take it from us */
struct sctp_tcb *stcb; /* assoc, used for window update */
TAILQ_ENTRY(sctp_queued_to_read) next;
TAILQ_ENTRY(sctp_queued_to_read) next_instrm;
struct sctpchunk_listhead reasm;
uint16_t port_from;
uint16_t spec_flags; /* Flags to hold the notification field */
uint8_t do_not_ref_stcb;
uint8_t end_added;
uint8_t pdapi_aborted;
uint8_t pdapi_started;
uint8_t some_taken;
uint8_t last_frag_seen;
uint8_t first_frag_seen;
uint8_t on_read_q;
uint8_t on_strm_q;
};
#define SCTP_ON_ORDERED 1
#define SCTP_ON_UNORDERED 2
/* This data structure will be on the outbound
* stream queues. Data will be pulled off from
* the front of the mbuf data and chunk-ified
@ -511,6 +525,8 @@ struct sctp_stream_queue_pending {
struct sctp_nets *net;
TAILQ_ENTRY(sctp_stream_queue_pending) next;
TAILQ_ENTRY(sctp_stream_queue_pending) ss_next;
uint32_t fsn;
uint32_t msg_id;
uint32_t length;
uint32_t timetolive;
uint32_t ppid;
@ -534,9 +550,11 @@ struct sctp_stream_queue_pending {
TAILQ_HEAD(sctpwheelunrel_listhead, sctp_stream_in);
struct sctp_stream_in {
struct sctp_readhead inqueue;
struct sctp_readhead uno_inqueue;
uint32_t last_sequence_delivered; /* used for re-order */
uint16_t stream_no;
uint16_t last_sequence_delivered; /* used for re-order */
uint8_t delivery_started;
uint8_t pd_api_started;
};
TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out);
@ -605,8 +623,8 @@ struct sctp_stream_out {
uint32_t abandoned_unsent[1];
uint32_t abandoned_sent[1];
#endif
uint32_t next_sequence_send; /* next one I expect to send out */
uint16_t stream_no;
uint16_t next_sequence_send; /* next one I expect to send out */
uint8_t last_msg_incomplete;
uint8_t state;
};
@ -635,12 +653,13 @@ struct sctp_scoping {
struct sctp_tsn_log {
void *stcb;
uint32_t tsn;
uint32_t seq;
uint16_t strm;
uint16_t seq;
uint16_t sz;
uint16_t flgs;
uint16_t in_pos;
uint16_t in_out;
uint16_t resv;
};
#define SCTP_FS_SPEC_LOG_SIZE 200
@ -811,9 +830,6 @@ struct sctp_association {
struct sctpchunk_listhead sent_queue;
struct sctpchunk_listhead send_queue;
/* re-assembly queue for fragmented chunks on the inbound path */
struct sctpchunk_listhead reasmqueue;
/* Scheduling queues */
union scheduling_data ss_data;
@ -881,7 +897,7 @@ struct sctp_association {
uint32_t stream_scheduling_module;
uint32_t vrf_id;
uint32_t assoc_msg_id;
uint32_t cookie_preserve_req;
/* ASCONF next seq I am sending out, inits at init-tsn */
uint32_t asconf_seq_out;
@ -1177,12 +1193,12 @@ struct sctp_association {
uint8_t reconfig_supported;
uint8_t nrsack_supported;
uint8_t pktdrop_supported;
uint8_t idata_supported;
/* Did the peer make the stream config (add out) request */
uint8_t peer_req_out;
uint8_t local_strreset_support;
uint8_t peer_supports_nat;
struct sctp_scoping scope;

View File

@ -432,7 +432,7 @@ struct sctp_sysctl {
#define SCTPCTL_STRICT_DATA_ORDER_DESC "Enforce strict data ordering, abort if control inside data"
#define SCTPCTL_STRICT_DATA_ORDER_MIN 0
#define SCTPCTL_STRICT_DATA_ORDER_MAX 1
#define SCTPCTL_STRICT_DATA_ORDER_DEFAULT 0
#define SCTPCTL_STRICT_DATA_ORDER_DEFAULT 1
/* min_residual: min residual in a data fragment leftover */
#define SCTPCTL_MIN_RESIDUAL_DESC "Minimum residual data chunk in second part of split"

View File

@ -318,12 +318,13 @@ struct sctp_assoc_change {
#define SCTP_CANT_STR_ASSOC 0x0005
/* sac_info values */
#define SCTP_ASSOC_SUPPORTS_PR 0x01
#define SCTP_ASSOC_SUPPORTS_AUTH 0x02
#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03
#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04
#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05
#define SCTP_ASSOC_SUPPORTS_MAX 0x05
#define SCTP_ASSOC_SUPPORTS_PR 0x01
#define SCTP_ASSOC_SUPPORTS_AUTH 0x02
#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03
#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04
#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05
#define SCTP_ASSOC_SUPPORTS_INTERLEAVING 0x06
#define SCTP_ASSOC_SUPPORTS_MAX 0x06
/*
* Address event
*/

View File

@ -1730,6 +1730,37 @@ flags_out:
*optsize = sizeof(uint32_t);
break;
}
case SCTP_INTERLEAVING_SUPPORTED:
{
struct sctp_assoc_value *av;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
av->assoc_value = stcb->asoc.idata_supported;
SCTP_TCB_UNLOCK(stcb);
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
(av->assoc_id == SCTP_FUTURE_ASSOC)) {
SCTP_INP_RLOCK(inp);
if (inp->idata_supported) {
av->assoc_value = 1;
} else {
av->assoc_value = 0;
}
SCTP_INP_RUNLOCK(inp);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
}
if (error == 0) {
*optsize = sizeof(struct sctp_assoc_value);
}
break;
}
case SCTP_CMT_ON_OFF:
{
struct sctp_assoc_value *av;
@ -3904,6 +3935,47 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
}
case SCTP_INTERLEAVING_SUPPORTED:
{
struct sctp_assoc_value *av;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
(av->assoc_id == SCTP_FUTURE_ASSOC)) {
SCTP_INP_WLOCK(inp);
if (av->assoc_value == 0) {
inp->idata_supported = 0;
} else {
if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS))) {
inp->idata_supported = 1;
} else {
/*
* Must have Frag
* interleave and
* stream interleave
* on
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
}
SCTP_INP_WUNLOCK(inp);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
}
break;
}
case SCTP_CMT_ON_OFF:
if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
struct sctp_assoc_value *av;

View File

@ -97,11 +97,19 @@ extern struct pr_usrreqs sctp_usrreqs;
* an mbuf cache as well so it is not really worth doing, at least
* right now :-D
*/
#ifdef INVARIANTS
#define sctp_free_a_readq(_stcb, _readq) { \
if ((_readq)->on_strm_q) \
panic("On strm q stcb:%p readq:%p", (_stcb), (_readq)); \
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \
SCTP_DECR_READQ_COUNT(); \
}
#else
#define sctp_free_a_readq(_stcb, _readq) { \
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \
SCTP_DECR_READQ_COUNT(); \
}
#endif
#define sctp_alloc_a_readq(_stcb, _readq) { \
(_readq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_readq), struct sctp_queued_to_read); \
@ -196,7 +204,7 @@ extern struct pr_usrreqs sctp_usrreqs;
}
#define sctp_sbfree(ctl, stcb, sb, m) { \
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \
if (((ctl)->do_not_ref_stcb == 0) && stcb) {\
SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
@ -211,7 +219,7 @@ extern struct pr_usrreqs sctp_usrreqs;
atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \
atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \
if (stcb) { \
atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \
atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \
} \
if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \

View File

@ -970,11 +970,13 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
asoc->ecn_supported = inp->ecn_supported;
asoc->prsctp_supported = inp->prsctp_supported;
asoc->idata_supported = inp->idata_supported;
asoc->auth_supported = inp->auth_supported;
asoc->asconf_supported = inp->asconf_supported;
asoc->reconfig_supported = inp->reconfig_supported;
asoc->nrsack_supported = inp->nrsack_supported;
asoc->pktdrop_supported = inp->pktdrop_supported;
asoc->idata_supported = inp->idata_supported;
asoc->sctp_cmt_pf = (uint8_t) 0;
asoc->sctp_frag_point = inp->sctp_frag_point;
asoc->sctp_features = inp->sctp_features;
@ -1163,7 +1165,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
TAILQ_INIT(&asoc->asconf_send_queue);
TAILQ_INIT(&asoc->send_queue);
TAILQ_INIT(&asoc->sent_queue);
TAILQ_INIT(&asoc->reasmqueue);
TAILQ_INIT(&asoc->resetHead);
asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
TAILQ_INIT(&asoc->asconf_queue);
@ -2736,6 +2737,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
if (stcb->asoc.asconf_supported == 1) {
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
}
if (stcb->asoc.idata_supported == 1) {
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING;
}
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
if (stcb->asoc.reconfig_supported == 1) {
sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG;
@ -4449,6 +4453,43 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
SCTP_INP_READ_UNLOCK(new_inp);
}
void
sctp_wakeup_the_read_socket(struct sctp_inpcb *inp)
{
if (inp && inp->sctp_socket) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
} else {
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(inp);
if (!so_locked) {
if (stcb) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
}
SCTP_SOCKET_LOCK(so, 1);
if (stcb) {
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
SCTP_SOCKET_UNLOCK(so, 1);
return;
}
}
#endif
sctp_sorwakeup(inp, inp->sctp_socket);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
#endif
}
}
}
void
sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
@ -4484,7 +4525,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
sctp_m_freem(control->data);
control->data = NULL;
}
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
sctp_free_a_readq(stcb, control);
if (inp_read_lock_held == 0)
SCTP_INP_READ_UNLOCK(inp);
return;
@ -4530,7 +4571,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
} else {
/* Everything got collapsed out?? */
sctp_free_remote_addr(control->whoFrom);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
sctp_free_a_readq(stcb, control);
if (inp_read_lock_held == 0)
SCTP_INP_READ_UNLOCK(inp);
return;
@ -4539,39 +4580,11 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
control->end_added = 1;
}
TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
control->on_read_q = 1;
if (inp_read_lock_held == 0)
SCTP_INP_READ_UNLOCK(inp);
if (inp && inp->sctp_socket) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
} else {
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(inp);
if (!so_locked) {
if (stcb) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
}
SCTP_SOCKET_LOCK(so, 1);
if (stcb) {
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
SCTP_SOCKET_UNLOCK(so, 1);
return;
}
}
#endif
sctp_sorwakeup(inp, inp->sctp_socket);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
#endif
}
sctp_wakeup_the_read_socket(inp);
}
}
@ -5552,6 +5565,10 @@ restart_nosblocks:
sctp_m_free(control->aux_data);
control->aux_data = NULL;
}
if (control->on_strm_q) {
panic("About to free ctl:%p so:%p and its in %d",
control, so, control->on_strm_q);
}
sctp_free_remote_addr(control->whoFrom);
sctp_free_a_readq(stcb, control);
if (hold_rlock) {
@ -5822,15 +5839,8 @@ get_more_data:
/* error we are out of here */
goto release;
}
if ((SCTP_BUF_NEXT(m) == NULL) &&
(cp_len >= SCTP_BUF_LEN(m)) &&
((control->end_added == 0) ||
(control->end_added &&
(TAILQ_NEXT(control, next) == NULL)))
) {
SCTP_INP_READ_LOCK(inp);
hold_rlock = 1;
}
SCTP_INP_READ_LOCK(inp);
hold_rlock = 1;
if (cp_len == SCTP_BUF_LEN(m)) {
if ((SCTP_BUF_NEXT(m) == NULL) &&
(control->end_added)) {
@ -5948,19 +5958,9 @@ get_more_data:
#endif
}
done_with_control:
if (TAILQ_NEXT(control, next) == NULL) {
/*
* If we don't have a next we need a
* lock, if there is a next
* interrupt is filling ahead of us
* and we don't need a lock to
* remove this guy (which is the
* head of the queue).
*/
if (hold_rlock == 0) {
SCTP_INP_READ_LOCK(inp);
hold_rlock = 1;
}
if (hold_rlock == 0) {
SCTP_INP_READ_LOCK(inp);
hold_rlock = 1;
}
TAILQ_REMOVE(&inp->read_queue, control, next);
/* Add back any hiddend data */
@ -5976,6 +5976,10 @@ get_more_data:
no_rcv_needed = control->do_not_ref_stcb;
sctp_free_remote_addr(control->whoFrom);
control->data = NULL;
if (control->on_strm_q) {
panic("About to free ctl:%p so:%p and its in %d",
control, so, control->on_strm_q);
}
sctp_free_a_readq(stcb, control);
control = NULL;
if ((freed_so_far >= rwnd_req) &&
@ -6096,7 +6100,7 @@ wait_some_more:
* corrupt?
*/
#ifdef INVARIANTS
panic("Impossible data==NULL length !=0");
panic("Impossible data==NULL length !=0 control:%p stcb:%p length:%d", control, stcb, control->length);
#endif
out_flags |= MSG_EOR;
out_flags |= MSG_TRUNC;

View File

@ -107,6 +107,9 @@ int
void
sctp_mtu_size_reset(struct sctp_inpcb *, struct sctp_association *, uint32_t);
void
sctp_wakeup_the_read_socket(struct sctp_inpcb *inp);
void
sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,