diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 36 | 
1 files changed, 36 insertions, 0 deletions
| diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d4730ada7f32..6f45d1713452 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -170,6 +170,36 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)  	sk_mem_charge(sk, chunk->skb->truesize);  } +static void sctp_clear_owner_w(struct sctp_chunk *chunk) +{ +	skb_orphan(chunk->skb); +} + +static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, +				       void (*cb)(struct sctp_chunk *)) + +{ +	struct sctp_outq *q = &asoc->outqueue; +	struct sctp_transport *t; +	struct sctp_chunk *chunk; + +	list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) +		list_for_each_entry(chunk, &t->transmitted, transmitted_list) +			cb(chunk); + +	list_for_each_entry(chunk, &q->retransmit, list) +		cb(chunk); + +	list_for_each_entry(chunk, &q->sacked, list) +		cb(chunk); + +	list_for_each_entry(chunk, &q->abandoned, list) +		cb(chunk); + +	list_for_each_entry(chunk, &q->out_chunk_list, list) +		cb(chunk); +} +  /* Verify that this is a valid address. */  static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,  				   int len) @@ -4906,6 +4936,10 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)  	struct socket *sock;  	int err = 0; +	/* Do not peel off from one netns to another one. */ +	if (!net_eq(current->nsproxy->net_ns, sock_net(sk))) +		return -EINVAL; +  	if (!asoc)  		return -EINVAL; @@ -8208,7 +8242,9 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,  	 * paths won't try to lock it and then oldsk.  	 */  	lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); +	sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w);  	sctp_assoc_migrate(assoc, newsk); +	sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w);  	/* If the association on the newsk is already closed before accept()  	 * is called, set RCV_SHUTDOWN flag. | 
