diff options
author | rrs <rrs@FreeBSD.org> | 2006-11-08 00:21:13 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2006-11-08 00:21:13 +0000 |
commit | 1bedc49b68670bf727f50429a15911323ca540e3 (patch) | |
tree | f6f786f609125bed924191c84569dc69cd63afc8 /sys/netinet/sctputil.c | |
parent | 0c2fa6c52c1266ecfbf3b99e2c6c0377acac1444 (diff) | |
download | FreeBSD-src-1bedc49b68670bf727f50429a15911323ca540e3.zip FreeBSD-src-1bedc49b68670bf727f50429a15911323ca540e3.tar.gz |
-Fixes first of all the getcred on IPv6 and V4. The
copy's were incorrect and so was the locking.
-A bug was also found that would create a race and
panic when an abort arrived on a socket being read
from.
-Also fix the reader to get MSG_TRUNC when a partial
delivery is aborted.
-Also addresses a couple of coverity caught error path
memory leaks and a couple of other valid complaints
Approved by: gnn
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 173 |
1 files changed, 62 insertions, 111 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 45ebbe5..927e444 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -377,7 +377,12 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) sctp_clog[sctp_cwnd_log_at].time_event = sctp_get_time_of_event(); sctp_clog[sctp_cwnd_log_at].from = (uint8_t) from; sctp_clog[sctp_cwnd_log_at].event_type = (uint8_t) SCTP_LOG_LOCK_EVENT; - sctp_clog[sctp_cwnd_log_at].x.lock.sock = (void *)inp->sctp_socket; + if (inp) { + sctp_clog[sctp_cwnd_log_at].x.lock.sock = (void *)inp->sctp_socket; + + } else { + sctp_clog[sctp_cwnd_log_at].x.lock.sock = (void *)NULL; + } sctp_clog[sctp_cwnd_log_at].x.lock.inp = (void *)inp; if (stcb) { sctp_clog[sctp_cwnd_log_at].x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx); @@ -2575,7 +2580,6 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb, struct mbuf *m_notify; struct sctp_assoc_change *sac; struct sctp_queued_to_read *control; - int locked = 0; /* * First if we are are going down dump everything we can to the @@ -2589,58 +2593,6 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb, /* If the socket is gone we are out of here */ return; } - if ((event == SCTP_COMM_LOST) || (event == SCTP_SHUTDOWN_COMP)) { - if (stcb->asoc.control_pdapi) { - /* - * we were in the middle of a PD-API verify its - * there. - */ - SCTP_INP_READ_LOCK(stcb->sctp_ep); - locked = 1; - TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) { - if (control == stcb->asoc.control_pdapi) { - /* Yep its here, notify them */ - if (event == SCTP_COMM_LOST) { - /* - * Abort/broken we had a - * real PD-API aborted - */ - if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT)) { - /* - * hmm.. don't want - * a notify if - * held_lenght is - * set,they may be - * stuck. clear and - * wake. - */ - if (control->held_length) { - control->held_length = 0; - control->end_added = 1; - } - } else { - sctp_notify_partial_delivery_indication(stcb, event, 1); - - } - } else { - /* implicit EOR on EOF */ - control->held_length = 0; - control->end_added = 1; - } - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); - locked = 0; - /* wake him up */ - control->do_not_ref_stcb = 1; - stcb->asoc.control_pdapi = NULL; - sorwakeup(stcb->sctp_socket); - break; - } - } - if (locked) - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); - - } - } /* * For TCP model AND UDP connected sockets we will send an error up * when an ABORT comes in. @@ -2936,13 +2888,15 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb, &stcb->sctp_socket->so_rcv, 1); } +/* This always must be called with the read-queue LOCKED in the INP */ void sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, - uint32_t error, int no_lock) + uint32_t error, int nolock) { struct mbuf *m_notify; struct sctp_pdapi_event *pdapi; struct sctp_queued_to_read *control; + struct sockbuf *sb; if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT)) /* event not enabled */ @@ -2965,62 +2919,44 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, m_notify->m_pkthdr.rcvif = 0; m_notify->m_len = sizeof(struct sctp_pdapi_event); m_notify->m_next = NULL; - - if (stcb->asoc.control_pdapi != NULL) { - /* we will do some substitution */ - control = stcb->asoc.control_pdapi; - if (no_lock == 0) - SCTP_INP_READ_LOCK(stcb->sctp_ep); - - if (control->data == NULL) { - control->data = control->tail_mbuf = m_notify; - control->held_length = 0; - control->length = m_notify->m_len; - control->end_added = 1; - sctp_sballoc(stcb, - &stcb->sctp_socket->so_rcv, - m_notify); - } else if (control->end_added == 0) { - struct mbuf *m = NULL; - - m = control->data; - while (m) { - sctp_sbfree(control, stcb, - &stcb->sctp_socket->so_rcv, m); - m = sctp_m_free(m); - } - control->data = NULL; - control->length = m_notify->m_len; - control->data = control->tail_mbuf = m_notify; - control->held_length = 0; - control->end_added = 1; - sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); - } else { - /* Hmm .. should not happen */ - control->end_added = 1; - stcb->asoc.control_pdapi = NULL; - goto add_to_end; - } - if (no_lock == 0) - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); + control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, + 0, 0, 0, 0, 0, 0, + m_notify); + if (control == NULL) { + /* no memory */ + sctp_m_freem(m_notify); + return; + } + control->length = m_notify->m_len; + /* not that we need this */ + control->tail_mbuf = m_notify; + control->held_length = 0; + control->length = 0; + if (nolock == 0) { + SCTP_INP_READ_LOCK(stcb->sctp_ep); + } + sb = &stcb->sctp_socket->so_rcv; +#ifdef SCTP_SB_LOGGING + sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, m_notify->m_len); +#endif + sctp_sballoc(stcb, sb, m_notify); +#ifdef SCTP_SB_LOGGING + sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); +#endif + atomic_add_int(&control->length, m_notify->m_len); + control->end_added = 1; + if (stcb->asoc.control_pdapi) + TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); + else { + /* we really should not see this case */ + TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); + } + if (nolock == 0) { + SCTP_INP_READ_UNLOCK(stcb->sctp_ep); + } + if (stcb->sctp_ep && stcb->sctp_socket) { + /* This should always be the case */ sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); - } else { - /* append to socket */ -add_to_end: - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, 0, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = m_notify->m_len; - /* 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); } } @@ -3150,10 +3086,14 @@ void sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, uint32_t error, void *data) { + if (stcb == NULL) { + /* unlikely but */ + return; + } if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) - ) { + ) { /* No notifications up when we are in a no socket state */ return; } @@ -3829,6 +3769,13 @@ sctp_add_to_readq(struct sctp_inpcb *inp, */ struct mbuf *m, *prev = NULL; + if (inp == NULL) { + /* Gak, TSNH!! */ +#ifdef INVARIENTS + panic("Gak, inp NULL on add_to_readq"); +#endif + return; + } SCTP_INP_READ_LOCK(inp); m = control->data; control->held_length = 0; @@ -5032,6 +4979,8 @@ wait_some_more: if (control->end_added == 1) { /* he aborted, or is done i.e.did a shutdown */ out_flags |= MSG_EOR; + if (control->pdapi_aborted) + out_flags |= MSG_TRUNC; goto done_with_control; } if (so->so_rcv.sb_cc > held_length) { @@ -5143,6 +5092,8 @@ get_more_data2: * shutdown */ out_flags |= MSG_EOR; + if (control->pdapi_aborted) + out_flags |= MSG_TRUNC; goto done_with_control; } if (so->so_rcv.sb_cc > held_length) { |