diff options
-rw-r--r-- | net/sctp/input.c | 29 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 4 |
2 files changed, 23 insertions, 10 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c index 4aa6fc60357..c463e4049c5 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -262,15 +262,12 @@ int sctp_rcv(struct sk_buff *skb) else sctp_backlog_rcv(sk, skb); - /* Release the sock and any reference counts we took in the - * lookup calls. + /* Release the sock and the sock ref we took in the lookup calls. + * The asoc/ep ref will be released in sctp_backlog_rcv. */ sctp_bh_unlock_sock(sk); - if (asoc) - sctp_association_put(asoc); - else - sctp_endpoint_put(ep); sock_put(sk); + return ret; discard_it: @@ -296,9 +293,23 @@ discard_release: int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; - struct sctp_inq *inqueue = &chunk->rcvr->inqueue; - - sctp_inq_push(inqueue, chunk); + struct sctp_inq *inqueue = NULL; + struct sctp_ep_common *rcvr = NULL; + + rcvr = chunk->rcvr; + if (rcvr->dead) { + sctp_chunk_free(chunk); + } else { + inqueue = &chunk->rcvr->inqueue; + sctp_inq_push(inqueue, chunk); + } + + /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ + if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) + sctp_association_put(sctp_assoc(rcvr)); + else + sctp_endpoint_put(sctp_ep(rcvr)); + return 0; } diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 2d33922c044..297b8951463 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue) /* If there is a packet which is currently being worked on, * free it as well. */ - if (queue->in_progress) + if (queue->in_progress) { sctp_chunk_free(queue->in_progress); + queue->in_progress = NULL; + } if (queue->malloced) { /* Dump the master memory segment. */ |