Fix the aborting of association with the iterator using an empty

user initiated error cause (using SCTP_ABORT|SCTP_SENDALL).

Approved by: re (delphij)
MFC after: 1 week
This commit is contained in:
Michael Tuexen 2013-09-09 21:40:07 +00:00
parent 30d663c74e
commit 5dc80df9c5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=255434

View File

@ -6412,7 +6412,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
/* TSNH */
return;
}
if ((ca->m) && ca->sndlen) {
if (ca->sndlen > 0) {
m = SCTP_M_COPYM(ca->m, 0, M_COPYALL, M_NOWAIT);
if (m == NULL) {
/* can't copy so we are done */
@ -6441,38 +6441,40 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
}
if (ca->sndrcv.sinfo_flags & SCTP_ABORT) {
/* Abort this assoc with m as the user defined reason */
if (m) {
if (m != NULL) {
SCTP_BUF_PREPEND(m, sizeof(struct sctp_paramhdr), M_NOWAIT);
} else {
m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
0, M_NOWAIT, 1, MT_DATA);
SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr);
}
if (m != NULL) {
struct sctp_paramhdr *ph;
SCTP_BUF_PREPEND(m, sizeof(struct sctp_paramhdr), M_NOWAIT);
if (m) {
ph = mtod(m, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(sizeof(struct sctp_paramhdr) + ca->sndlen);
}
/*
* We add one here to keep the assoc from
* dis-appearing on us.
*/
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(inp, stcb, m, SCTP_SO_NOT_LOCKED);
/*
* sctp_abort_an_association calls sctp_free_asoc()
* free association will NOT free it since we
* incremented the refcnt .. we do this to prevent
* it being freed and things getting tricky since we
* could end up (from free_asoc) calling inpcb_free
* which would get a recursive lock call to the
* iterator lock.. But as a consequence of that the
* stcb will return to us un-locked.. since
* free_asoc returns with either no TCB or the TCB
* unlocked, we must relock.. to unlock in the
* iterator timer :-0
*/
SCTP_TCB_LOCK(stcb);
atomic_add_int(&stcb->asoc.refcnt, -1);
goto no_chunk_output;
ph = mtod(m, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(sizeof(struct sctp_paramhdr) + ca->sndlen);
}
/*
* We add one here to keep the assoc from dis-appearing on
* us.
*/
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(inp, stcb, m, SCTP_SO_NOT_LOCKED);
/*
* sctp_abort_an_association calls sctp_free_asoc() free
* association will NOT free it since we incremented the
* refcnt .. we do this to prevent it being freed and things
* getting tricky since we could end up (from free_asoc)
* calling inpcb_free which would get a recursive lock call
* to the iterator lock.. But as a consequence of that the
* stcb will return to us un-locked.. since free_asoc
* returns with either no TCB or the TCB unlocked, we must
* relock.. to unlock in the iterator timer :-0
*/
SCTP_TCB_LOCK(stcb);
atomic_add_int(&stcb->asoc.refcnt, -1);
goto no_chunk_output;
} else {
if (m) {
ret = sctp_msg_append(stcb, net, m,
@ -6566,8 +6568,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
(un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))
) {
(un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) {
do_chunk_output = 0;
}
if (do_chunk_output)
@ -6696,13 +6697,10 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
/* Gather the length of the send */
struct mbuf *mat;
mat = m;
ca->sndlen = 0;
while (m) {
ca->sndlen += SCTP_BUF_LEN(m);
m = SCTP_BUF_NEXT(m);
for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
ca->sndlen += SCTP_BUF_LEN(mat);
}
ca->m = mat;
}
ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL,
SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES,