mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
Merge branch 'sctp-re-point-retained-control-chunks-on-association-migration'
Jun Yang says: ==================== sctp: re-point retained control chunks on association migration This series fixes ownership of retained SCTP control chunks during socket migration. Patch 1 carries David Lee's shared-key prerequisite. v3: https://lore.kernel.org/20260926100359.78731-1-juny24602@gmail.com ==================== Link: https://patch.msgid.link/20261009074244.3718-1-juny24602@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
ee3deb0151
|
|
@ -252,6 +252,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
|
|||
struct sctp_fwdtsn_skip *skiplist);
|
||||
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
|
||||
__u16 key_id);
|
||||
void sctp_control_set_owner_w(struct sctp_chunk *chunk);
|
||||
struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc,
|
||||
__u16 stream_num, __be16 *stream_list,
|
||||
bool out, bool in);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ static void sctp_control_release_owner(struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
||||
void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
||||
{
|
||||
struct sctp_association *asoc = chunk->asoc;
|
||||
struct sk_buff *skb = chunk->skb;
|
||||
|
|
@ -107,7 +107,8 @@ static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
|||
* For now don't do anything for now.
|
||||
*/
|
||||
if (chunk->auth) {
|
||||
chunk->shkey = asoc->shkey;
|
||||
if (!chunk->shkey)
|
||||
chunk->shkey = asoc->shkey;
|
||||
sctp_auth_shkey_hold(chunk->shkey);
|
||||
}
|
||||
skb->sk = asoc ? asoc->base.sk : NULL;
|
||||
|
|
|
|||
|
|
@ -147,25 +147,47 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
|
|||
|
||||
static void sctp_clear_owner_w(struct sctp_chunk *chunk)
|
||||
{
|
||||
/* Keep the shkey alive until the new owner takes its reference. */
|
||||
if (chunk->shkey)
|
||||
sctp_auth_shkey_hold(chunk->shkey);
|
||||
skb_orphan(chunk->skb);
|
||||
}
|
||||
|
||||
static void sctp_set_owner_w_migrate(struct sctp_chunk *chunk)
|
||||
{
|
||||
struct sctp_shared_key *shkey = chunk->shkey;
|
||||
|
||||
if (chunk->msg)
|
||||
sctp_set_owner_w(chunk);
|
||||
else
|
||||
sctp_control_set_owner_w(chunk);
|
||||
|
||||
if (shkey)
|
||||
sctp_auth_shkey_release(shkey);
|
||||
}
|
||||
|
||||
static void sctp_process_tx_chunk(struct sctp_association *asoc,
|
||||
struct sctp_chunk *chunk, bool clear,
|
||||
void (*cb)(struct sctp_chunk *))
|
||||
{
|
||||
if ((clear && asoc->base.sk == chunk->skb->sk) ||
|
||||
(!clear && asoc->base.sk != chunk->skb->sk))
|
||||
cb(chunk);
|
||||
}
|
||||
|
||||
#define traverse_and_process() \
|
||||
do { \
|
||||
msg = chunk->msg; \
|
||||
if (msg == prev_msg) \
|
||||
continue; \
|
||||
list_for_each_entry(c, &msg->chunks, frag_list) { \
|
||||
if ((clear && asoc->base.sk == c->skb->sk) || \
|
||||
(!clear && asoc->base.sk != c->skb->sk)) \
|
||||
cb(c); \
|
||||
} \
|
||||
list_for_each_entry(c, &msg->chunks, frag_list) \
|
||||
sctp_process_tx_chunk(asoc, c, clear, cb); \
|
||||
prev_msg = msg; \
|
||||
} while (0)
|
||||
|
||||
static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
|
||||
bool clear,
|
||||
void (*cb)(struct sctp_chunk *))
|
||||
static void sctp_for_each_tx_chunk(struct sctp_association *asoc,
|
||||
bool clear,
|
||||
void (*cb)(struct sctp_chunk *))
|
||||
|
||||
{
|
||||
struct sctp_datamsg *msg, *prev_msg = NULL;
|
||||
|
|
@ -188,6 +210,21 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
|
|||
|
||||
list_for_each_entry(chunk, &q->out_chunk_list, list)
|
||||
traverse_and_process();
|
||||
|
||||
list_for_each_entry(chunk, &q->control_chunk_list, list)
|
||||
sctp_process_tx_chunk(asoc, chunk, clear, cb);
|
||||
|
||||
list_for_each_entry(chunk, &asoc->asconf_ack_list, transmitted_list)
|
||||
sctp_process_tx_chunk(asoc, chunk, clear, cb);
|
||||
|
||||
list_for_each_entry(chunk, &asoc->addip_chunk_list, list)
|
||||
sctp_process_tx_chunk(asoc, chunk, clear, cb);
|
||||
|
||||
if (asoc->strreset_chunk)
|
||||
sctp_process_tx_chunk(asoc, asoc->strreset_chunk, clear, cb);
|
||||
|
||||
if (asoc->addip_last_asconf)
|
||||
sctp_process_tx_chunk(asoc, asoc->addip_last_asconf, clear, cb);
|
||||
}
|
||||
|
||||
static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk,
|
||||
|
|
@ -9635,9 +9672,9 @@ static int 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, true, sctp_clear_owner_w);
|
||||
sctp_for_each_tx_chunk(assoc, true, sctp_clear_owner_w);
|
||||
sctp_assoc_migrate(assoc, newsk);
|
||||
sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w);
|
||||
sctp_for_each_tx_chunk(assoc, false, sctp_set_owner_w_migrate);
|
||||
|
||||
/* If the association on the newsk is already closed before accept()
|
||||
* is called, set RCV_SHUTDOWN flag.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user