Fix the accounting and add code to detect errors in accounting.

Joint work with rrs@
MFC after:	1 week
This commit is contained in:
Michael Tuexen 2017-07-19 12:27:40 +00:00
parent 1d2fef9b9a
commit 28cd0699b6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=321197
4 changed files with 292 additions and 140 deletions

View File

@ -1797,8 +1797,8 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb, control,

View File

@ -59,7 +59,7 @@ __FBSDID("$FreeBSD$");
* This will cause sctp_service_queues() to get called on the top entry in
* the list.
*/
static void
static uint32_t
sctp_add_chk_to_control(struct sctp_queued_to_read *control,
struct sctp_stream_in *strm,
struct sctp_tcb *stcb,
@ -92,6 +92,8 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
asoc->size_on_reasm_queue == 0 &&
asoc->size_on_all_streams == 0) {
/* Full rwnd granted */
KASSERT(asoc->cnt_on_reasm_queue == 0, ("cnt_on_reasm_queue is %u", asoc->cnt_on_reasm_queue));
KASSERT(asoc->cnt_on_all_streams == 0, ("cnt_on_all_streams is %u", asoc->cnt_on_all_streams));
calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
return (calc);
}
@ -558,7 +560,15 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb,
}
/* EY it wont be queued if it could be delivered directly */
queue_needed = 0;
asoc->size_on_all_streams -= control->length;
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
strm->last_mid_delivered++;
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
@ -571,10 +581,18 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb,
nxt_todel = strm->last_mid_delivered + 1;
if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) &&
(((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);
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
#ifdef INVARIANTS
} else {
panic("Huh control: %p is on_strm_q: %d",
@ -671,7 +689,7 @@ sctp_setup_tail_pointer(struct sctp_queued_to_read *control)
}
static void
sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m)
sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added)
{
struct mbuf *prev = NULL;
struct sctp_tcb *stcb;
@ -715,6 +733,7 @@ sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m)
*/
sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
}
*added += SCTP_BUF_LEN(m);
atomic_add_int(&control->length, SCTP_BUF_LEN(m));
m = SCTP_BUF_NEXT(m);
}
@ -815,7 +834,15 @@ sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
tchk = TAILQ_FIRST(&control->reasm);
if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
asoc->size_on_reasm_queue -= tchk->send_size;
if (asoc->size_on_reasm_queue >= tchk->send_size) {
asoc->size_on_reasm_queue -= tchk->send_size;
} else {
#ifdef INVARIANTS
panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size);
#else
asoc->size_on_reasm_queue = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
nc->first_frag_seen = 1;
nc->fsn_included = tchk->rec.data.fsn;
@ -1127,6 +1154,16 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
#endif
SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
}
if (strm->pd_api_started && control->pdapi_started) {
@ -1173,6 +1210,16 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
#endif
SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
}
ret++;
@ -1219,7 +1266,7 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
void
uint32_t
sctp_add_chk_to_control(struct sctp_queued_to_read *control,
struct sctp_stream_in *strm,
struct sctp_tcb *stcb, struct sctp_association *asoc,
@ -1229,6 +1276,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
* Given a control and a chunk, merge the data from the chk onto the
* control and free up the chunk resources.
*/
uint32_t added = 0;
int i_locked = 0;
if (control->on_read_q && (hold_rlock == 0)) {
@ -1242,7 +1290,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
control->data = chk->data;
sctp_setup_tail_pointer(control);
} else {
sctp_add_to_tail_pointer(control, chk->data);
sctp_add_to_tail_pointer(control, chk->data, &added);
}
control->fsn_included = chk->rec.data.fsn;
asoc->size_on_reasm_queue -= chk->send_size;
@ -1268,6 +1316,16 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
} else if (control->on_strm_q == SCTP_ON_ORDERED) {
/* Ordered */
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
#ifdef INVARIANTS
} else if (control->on_strm_q) {
@ -1283,6 +1341,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
}
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
return (added);
}
/*
@ -1302,6 +1361,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_tmit_chunk *at, *nat;
struct sctp_stream_in *strm;
int do_wakeup, unordered;
uint32_t lenadded;
strm = &asoc->strmin[control->sinfo_stream];
/*
@ -1314,6 +1374,9 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
/* Must be added to the stream-in queue */
if (created_control) {
if (unordered == 0) {
sctp_ucount_incr(asoc->cnt_on_all_streams);
}
if (sctp_place_control_in_stream(strm, asoc, control)) {
/* Duplicate SSN? */
sctp_clean_up_control(stcb, control);
@ -1373,6 +1436,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
chk->data = NULL;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
sctp_setup_tail_pointer(control);
asoc->size_on_all_streams += control->length;
} else {
/* Place the chunk in our list */
int inserted = 0;
@ -1529,7 +1593,8 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
at->rec.data.fsn,
next_fsn, control->fsn_included);
TAILQ_REMOVE(&control->reasm, at, sctp_next);
sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
asoc->size_on_all_streams += lenadded;
if (control->on_read_q) {
do_wakeup = 1;
}
@ -1600,7 +1665,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
uint16_t sid;
struct mbuf *op_err;
char msg[SCTP_DIAG_INFO_LEN];
struct sctp_queued_to_read *control = NULL;
struct sctp_queued_to_read *control, *ncontrol;
uint32_t ppid;
uint8_t chk_flags;
struct sctp_stream_reset_list *liste;
@ -2006,7 +2071,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
return (0);
}
if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
struct mbuf *m;
control->data = dmbuf;
m = control->data;
for (m = control->data; m; m = m->m_next) {
control->length += SCTP_BUF_LEN(m);
}
control->tail_mbuf = NULL;
control->end_added = 1;
control->last_frag_seen = 1;
@ -2116,16 +2187,16 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
/* first one on */
TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
} else {
struct sctp_queued_to_read *ctlOn, *nctlOn;
struct sctp_queued_to_read *lcontrol, *nlcontrol;
unsigned char inserted = 0;
TAILQ_FOREACH_SAFE(ctlOn, &asoc->pending_reply_queue, next, nctlOn) {
if (SCTP_TSN_GT(control->sinfo_tsn, ctlOn->sinfo_tsn)) {
TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) {
if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) {
continue;
} else {
/* found it */
TAILQ_INSERT_BEFORE(ctlOn, control, next);
TAILQ_INSERT_BEFORE(lcontrol, control, next);
inserted = 1;
break;
}
@ -2216,8 +2287,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
* pending_reply space 3: distribute any chunks in
* pending_reply_queue.
*/
struct sctp_queued_to_read *ctl, *nctl;
sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams);
TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED);
@ -2226,34 +2295,34 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
liste = TAILQ_FIRST(&asoc->resetHead);
if (TAILQ_EMPTY(&asoc->resetHead)) {
/* All can be removed */
TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag, &need_reasm_check);
TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
if (*abort_flag) {
return (0);
}
if (need_reasm_check) {
(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[ctl->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[control->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
need_reasm_check = 0;
}
}
} else {
TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
if (SCTP_TSN_GT(ctl->sinfo_tsn, liste->tsn)) {
TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) {
break;
}
/*
* if ctl->sinfo_tsn is <= liste->tsn we can
* process it which is the NOT of
* ctl->sinfo_tsn > liste->tsn
* if control->sinfo_tsn is <= liste->tsn we
* can process it which is the NOT of
* control->sinfo_tsn > liste->tsn
*/
TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag, &need_reasm_check);
TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
if (*abort_flag) {
return (0);
}
if (need_reasm_check) {
(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[ctl->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[control->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
need_reasm_check = 0;
}
}
@ -5181,7 +5250,7 @@ static void
sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
struct sctp_stream_in *strmin)
{
struct sctp_queued_to_read *ctl, *nctl;
struct sctp_queued_to_read *control, *ncontrol;
struct sctp_association *asoc;
uint32_t mid;
int need_reasm_check = 0;
@ -5192,43 +5261,51 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
* First deliver anything prior to and including the stream no that
* came in.
*/
TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) {
if (SCTP_MID_GE(asoc->idata_supported, mid, ctl->mid)) {
TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
/* this is deliverable now */
if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
if (ctl->on_strm_q) {
if (ctl->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm);
} else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm);
if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
if (control->on_strm_q) {
if (control->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
#ifdef INVARIANTS
} else {
panic("strmin: %p ctl: %p unknown %d",
strmin, ctl, ctl->on_strm_q);
strmin, control, control->on_strm_q);
#endif
}
ctl->on_strm_q = 0;
control->on_strm_q = 0;
}
/* subtract pending on streams */
asoc->size_on_all_streams -= ctl->length;
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
/* deliver it to at least the delivery-q */
if (stcb->sctp_socket) {
sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
sctp_add_to_readq(stcb->sctp_ep, stcb,
ctl,
control,
&stcb->sctp_socket->so_rcv,
1, SCTP_READ_LOCK_HELD,
SCTP_SO_NOT_LOCKED);
}
} else {
/* Its a fragmented message */
if (ctl->first_frag_seen) {
if (control->first_frag_seen) {
/*
* Make it so this is next to
* deliver, we restore later
*/
strmin->last_mid_delivered = ctl->mid - 1;
strmin->last_mid_delivered = control->mid - 1;
need_reasm_check = 1;
break;
}
@ -5257,32 +5334,40 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
* now ready.
*/
mid = strmin->last_mid_delivered + 1;
TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) {
if (SCTP_MID_EQ(asoc->idata_supported, mid, ctl->mid)) {
if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) {
if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
/* this is deliverable now */
if (ctl->on_strm_q) {
if (ctl->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm);
} else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm);
if (control->on_strm_q) {
if (control->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
#ifdef INVARIANTS
} else {
panic("strmin: %p ctl: %p unknown %d",
strmin, ctl, ctl->on_strm_q);
strmin, control, control->on_strm_q);
#endif
}
ctl->on_strm_q = 0;
control->on_strm_q = 0;
}
/* subtract pending on streams */
asoc->size_on_all_streams -= ctl->length;
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
/* deliver it to at least the delivery-q */
strmin->last_mid_delivered = ctl->mid;
strmin->last_mid_delivered = control->mid;
if (stcb->sctp_socket) {
sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
sctp_add_to_readq(stcb->sctp_ep, stcb,
ctl,
control,
&stcb->sctp_socket->so_rcv, 1,
SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
@ -5290,12 +5375,12 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
mid = strmin->last_mid_delivered + 1;
} else {
/* Its a fragmented message */
if (ctl->first_frag_seen) {
if (control->first_frag_seen) {
/*
* Make it so this is next to
* deliver
*/
strmin->last_mid_delivered = ctl->mid - 1;
strmin->last_mid_delivered = control->mid - 1;
need_reasm_check = 1;
break;
}
@ -5347,7 +5432,15 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
}
cnt_removed++;
TAILQ_REMOVE(&control->reasm, chk, sctp_next);
asoc->size_on_reasm_queue -= chk->send_size;
if (asoc->size_on_reasm_queue >= chk->send_size) {
asoc->size_on_reasm_queue -= chk->send_size;
} else {
#ifdef INVARIANTS
panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
#else
asoc->size_on_reasm_queue = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
if (chk->data) {
sctp_m_freem(chk->data);
@ -5373,6 +5466,16 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
}
if (control->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
@ -5416,7 +5519,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
unsigned int i, fwd_sz, m_size;
uint32_t str_seq;
struct sctp_stream_in *strm;
struct sctp_queued_to_read *ctl, *sv;
struct sctp_queued_to_read *control, *sv;
asoc = &stcb->asoc;
if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
@ -5575,25 +5678,35 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
for (cur_mid = strm->last_mid_delivered; SCTP_MID_GE(asoc->idata_supported, mid, cur_mid); cur_mid++) {
sctp_flush_reassm_for_str_seq(stcb, asoc, sid, cur_mid, ordered, new_cum_tsn);
}
TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
if ((ctl->sinfo_stream == sid) &&
(SCTP_MID_EQ(asoc->idata_supported, ctl->mid, mid))) {
TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) {
if ((control->sinfo_stream == sid) &&
(SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) {
str_seq = (sid << 16) | (0x0000ffff & mid);
ctl->pdapi_aborted = 1;
control->pdapi_aborted = 1;
sv = stcb->asoc.control_pdapi;
ctl->end_added = 1;
if (ctl->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strm->inqueue, ctl, next_instrm);
} else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strm->uno_inqueue, ctl, next_instrm);
control->end_added = 1;
if (control->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
} else if (ctl->on_strm_q) {
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
#ifdef INVARIANTS
} else if (control->on_strm_q) {
panic("strm: %p ctl: %p unknown %d",
strm, ctl, ctl->on_strm_q);
strm, control, control->on_strm_q);
#endif
}
ctl->on_strm_q = 0;
stcb->asoc.control_pdapi = ctl;
control->on_strm_q = 0;
stcb->asoc.control_pdapi = control;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
stcb,
SCTP_PARTIAL_DELIVERY_ABORTED,
@ -5601,8 +5714,8 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
SCTP_SO_NOT_LOCKED);
stcb->asoc.control_pdapi = sv;
break;
} else if ((ctl->sinfo_stream == sid) &&
SCTP_MID_GT(asoc->idata_supported, ctl->mid, mid)) {
} else if ((control->sinfo_stream == sid) &&
SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) {
/* We are past our victim SSN */
break;
}

View File

@ -4599,21 +4599,21 @@ 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;
struct sctp_queued_to_read *control, *ncontrol;
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;
TAILQ_FOREACH_SAFE(control, rh, next_instrm, ncontrol) {
TAILQ_REMOVE(rh, control, next_instrm);
control->on_strm_q = 0;
if (control->on_read_q == 0) {
sctp_free_remote_addr(control->whoFrom);
if (control->data) {
sctp_m_freem(control->data);
control->data = NULL;
}
}
/* Reassembly free? */
TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
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;
@ -4629,8 +4629,8 @@ sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh)
* 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);
if (control->on_read_q == 0) {
sctp_free_a_readq(stcb, control);
}
}
}
@ -6801,7 +6801,7 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
struct sctp_association *asoc;
struct sctp_tmit_chunk *chk, *nchk;
uint32_t cumulative_tsn_p1;
struct sctp_queued_to_read *ctl, *nctl;
struct sctp_queued_to_read *control, *ncontrol;
int cnt, strmat;
uint32_t gap, i;
int fnd = 0;
@ -6818,88 +6818,124 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
cnt = 0;
/* 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_instrm, nctl) {
TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].inqueue, next_instrm, ncontrol) {
#ifdef INVARIANTS
if (ctl->on_strm_q != SCTP_ON_ORDERED) {
if (control->on_strm_q != SCTP_ON_ORDERED) {
panic("Huh control: %p on_q: %d -- not ordered?",
ctl, ctl->on_strm_q);
control, control->on_strm_q);
}
#endif
if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
if (SCTP_TSN_GT(control->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_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn);
KASSERT(control->length > 0, ("control has zero length"));
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
if (ctl->on_read_q) {
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
ctl->on_read_q = 0;
if (control->on_read_q) {
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
control->on_read_q = 0;
}
TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next_instrm);
ctl->on_strm_q = 0;
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, control, next_instrm);
control->on_strm_q = 0;
if (control->data) {
sctp_m_freem(control->data);
control->data = NULL;
}
sctp_free_remote_addr(ctl->whoFrom);
sctp_free_remote_addr(control->whoFrom);
/* Now its reasm? */
TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn);
asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
KASSERT(chk->send_size > 0, ("chunk has zero length"));
if (asoc->size_on_reasm_queue >= chk->send_size) {
asoc->size_on_reasm_queue -= chk->send_size;
} else {
#ifdef INVARIANTS
panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
#else
asoc->size_on_reasm_queue = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
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, ctl);
sctp_free_a_readq(stcb, control);
}
}
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].uno_inqueue, next_instrm, nctl) {
TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].uno_inqueue, next_instrm, ncontrol) {
#ifdef INVARIANTS
if (ctl->on_strm_q != SCTP_ON_UNORDERED) {
if (control->on_strm_q != SCTP_ON_UNORDERED) {
panic("Huh control: %p on_q: %d -- not unordered?",
ctl, ctl->on_strm_q);
control, control->on_strm_q);
}
#endif
if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
if (SCTP_TSN_GT(control->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_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn);
KASSERT(control->length > 0, ("control has zero length"));
if (asoc->size_on_all_streams >= control->length) {
asoc->size_on_all_streams -= control->length;
} else {
#ifdef INVARIANTS
panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
#else
asoc->size_on_all_streams = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
if (ctl->on_read_q) {
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
ctl->on_read_q = 0;
if (control->on_read_q) {
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
control->on_read_q = 0;
}
TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, ctl, next_instrm);
ctl->on_strm_q = 0;
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, control, next_instrm);
control->on_strm_q = 0;
if (control->data) {
sctp_m_freem(control->data);
control->data = NULL;
}
sctp_free_remote_addr(ctl->whoFrom);
sctp_free_remote_addr(control->whoFrom);
/* Now its reasm? */
TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn);
asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
KASSERT(chk->send_size > 0, ("chunk has zero length"));
if (asoc->size_on_reasm_queue >= chk->send_size) {
asoc->size_on_reasm_queue -= chk->send_size;
} else {
#ifdef INVARIANTS
panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
#else
asoc->size_on_reasm_queue = 0;
#endif
}
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
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, ctl);
sctp_free_a_readq(stcb, control);
}
}
}

View File

@ -2754,9 +2754,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
@ -3039,7 +3039,10 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
sctp_m_freem(m_notify);
return;
}
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
@ -3139,7 +3142,10 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
sctp_m_freem(m_notify);
return;
}
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
@ -3240,12 +3246,10 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
control->held_length = 0;
control->length = 0;
sb = &stcb->sctp_socket->so_rcv;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
@ -3254,7 +3258,6 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
}
atomic_add_int(&control->length, SCTP_BUF_LEN(m_notify));
control->end_added = 1;
if (stcb->asoc.control_pdapi)
TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
@ -3349,8 +3352,8 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@ -3456,8 +3459,8 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@ -3506,8 +3509,8 @@ sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@ -3571,8 +3574,8 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@ -3627,9 +3630,9 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,