From c0d708f7aca25a94dd4dbbf68f850381d2b48f99 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 17 Jan 2006 11:56:26 -0800 Subject: [PATCH] --- yaml --- r: 19030 b: refs/heads/master c: c4d2444e992c4eda1d7fc3287e93ba58295bf6b9 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/include/net/sctp/sctp.h | 2 ++ trunk/net/sctp/input.c | 35 ++++++++++++++++++++++++++++++++++- trunk/net/sctp/socket.c | 4 ++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index 6729e04043a2..3cd18b19e715 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 313e7b4d2588539e388d31c1febd50503a0083fc +refs/heads/master: c4d2444e992c4eda1d7fc3287e93ba58295bf6b9 diff --git a/trunk/include/net/sctp/sctp.h b/trunk/include/net/sctp/sctp.h index a553f39f6aee..e673b2c984e9 100644 --- a/trunk/include/net/sctp/sctp.h +++ b/trunk/include/net/sctp/sctp.h @@ -175,6 +175,8 @@ void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, void sctp_icmp_proto_unreachable(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t); +void sctp_backlog_migrate(struct sctp_association *assoc, + struct sock *oldsk, struct sock *newsk); /* * Section: Macros, externs, and inlines diff --git a/trunk/net/sctp/input.c b/trunk/net/sctp/input.c index c463e4049c52..71fd56375641 100644 --- a/trunk/net/sctp/input.c +++ b/trunk/net/sctp/input.c @@ -257,12 +257,21 @@ int sctp_rcv(struct sk_buff *skb) */ sctp_bh_lock_sock(sk); + /* It is possible that the association could have moved to a different + * socket if it is peeled off. If so, update the sk. + */ + if (sk != rcvr->sk) { + sctp_bh_lock_sock(rcvr->sk); + sctp_bh_unlock_sock(sk); + sk = rcvr->sk; + } + if (sock_owned_by_user(sk)) sk_add_backlog(sk, skb); else sctp_backlog_rcv(sk, skb); - /* Release the sock and the sock ref 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); @@ -297,6 +306,9 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) struct sctp_ep_common *rcvr = NULL; rcvr = chunk->rcvr; + + BUG_TRAP(rcvr->sk == sk); + if (rcvr->dead) { sctp_chunk_free(chunk); } else { @@ -313,6 +325,27 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) return 0; } +void sctp_backlog_migrate(struct sctp_association *assoc, + struct sock *oldsk, struct sock *newsk) +{ + struct sk_buff *skb; + struct sctp_chunk *chunk; + + skb = oldsk->sk_backlog.head; + oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL; + while (skb != NULL) { + struct sk_buff *next = skb->next; + + chunk = SCTP_INPUT_CB(skb)->chunk; + skb->next = NULL; + if (&assoc->base == chunk->rcvr) + sk_add_backlog(newsk, skb); + else + sk_add_backlog(oldsk, skb); + skb = next; + } +} + /* Handle icmp frag needed error. */ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t, __u32 pmtu) diff --git a/trunk/net/sctp/socket.c b/trunk/net/sctp/socket.c index 6a0b1af89932..fb1821d9f338 100644 --- a/trunk/net/sctp/socket.c +++ b/trunk/net/sctp/socket.c @@ -5602,8 +5602,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ newsp->type = type; + spin_lock_bh(&oldsk->sk_lock.slock); + /* Migrate the backlog from oldsk to newsk. */ + sctp_backlog_migrate(assoc, oldsk, newsk); /* Migrate the association to the new socket. */ sctp_assoc_migrate(assoc, newsk); + spin_unlock_bh(&oldsk->sk_lock.slock); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag.