|
@@ -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)
|
|
@@ -8212,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.
|