summaryrefslogtreecommitdiff
path: root/net/sctp
diff options
context:
space:
mode:
authorKuniyuki Iwashima <kuniyu@google.com>2025-10-23 23:16:54 +0000
committerJakub Kicinski <kuba@kernel.org>2025-10-27 18:04:58 -0700
commit16942cf4d3e31b6246b7d000dd823f7b0b38bf8c (patch)
tree2ff3c151daae714a0cc0ffdaab2e030c1102a061 /net/sctp
parent151b98d10ef7c3174465e409b99d8762e7e8de60 (diff)
sctp: Use sk_clone() in sctp_accept().
sctp_accept() calls sctp_v[46]_create_accept_sk() to allocate a new socket and calls sctp_sock_migrate() to copy fields from the parent socket to the new socket. sctp_v4_create_accept_sk() allocates sk by sk_alloc(), initialises it by sock_init_data(), and copy a bunch of fields from the parent socekt by sctp_copy_sock(). sctp_sock_migrate() calls sctp_copy_descendant() to copy most fields in sctp_sock from the parent socket by memcpy(). These can be simply replaced by sk_clone(). Let's consolidate sctp_v[46]_create_accept_sk() to sctp_clone_sock() with sk_clone(). We will reuse sctp_clone_sock() for sctp_do_peeloff() and then remove sctp_copy_descendant(). Note that sock_reset_flag(newsk, SOCK_ZAPPED) is not copied to sctp_clone_sock() as sctp does not use SOCK_ZAPPED at all. Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Acked-by: Xin Long <lucien.xin@gmail.com> Link: https://patch.msgid.link/20251023231751.4168390-6-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/socket.c113
1 files changed, 76 insertions, 37 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 70c75ac8da55..826f17747f17 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4842,6 +4842,74 @@ static int sctp_disconnect(struct sock *sk, int flags)
return 0;
}
+static struct sock *sctp_clone_sock(struct sock *sk,
+ struct sctp_association *asoc,
+ enum sctp_socket_type type)
+{
+ struct sock *newsk = sk_clone(sk, GFP_KERNEL, false);
+ struct inet_sock *newinet;
+ struct sctp_sock *newsp;
+ int err = -ENOMEM;
+
+ if (!newsk)
+ return ERR_PTR(err);
+
+ /* sk_clone() sets refcnt to 2 */
+ sock_put(newsk);
+
+ newinet = inet_sk(newsk);
+ newsp = sctp_sk(newsk);
+
+ newsp->pf->to_sk_daddr(&asoc->peer.primary_addr, newsk);
+ newinet->inet_dport = htons(asoc->peer.port);
+
+ newsp->pf->copy_ip_options(sk, newsk);
+ atomic_set(&newinet->inet_id, get_random_u16());
+
+ inet_set_bit(MC_LOOP, newsk);
+ newinet->mc_ttl = 1;
+ newinet->mc_index = 0;
+ newinet->mc_list = NULL;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == AF_INET6) {
+ struct ipv6_pinfo *newnp = inet6_sk(newsk);
+
+ newinet->pinet6 = &((struct sctp6_sock *)newsk)->inet6;
+ newinet->ipv6_fl_list = NULL;
+
+ memcpy(newnp, inet6_sk(sk), sizeof(struct ipv6_pinfo));
+ newnp->ipv6_mc_list = NULL;
+ newnp->ipv6_ac_list = NULL;
+ }
+#endif
+
+ skb_queue_head_init(&newsp->pd_lobby);
+
+ newsp->ep = sctp_endpoint_new(newsk, GFP_KERNEL);
+ if (!newsp->ep)
+ goto out_release;
+
+ SCTP_DBG_OBJCNT_INC(sock);
+ sk_sockets_allocated_inc(newsk);
+ sock_prot_inuse_add(sock_net(sk), newsk->sk_prot, 1);
+
+ err = sctp_sock_migrate(sk, newsk, asoc, type);
+ if (err)
+ goto out_release;
+
+ /* Set newsk security attributes from original sk and connection
+ * security attribute from asoc.
+ */
+ security_sctp_sk_clone(asoc, sk, newsk);
+
+ return newsk;
+
+out_release:
+ sk_common_release(newsk);
+ return ERR_PTR(err);
+}
+
/* 4.1.4 accept() - TCP Style Syntax
*
* Applications use accept() call to remove an established SCTP
@@ -4851,18 +4919,13 @@ static int sctp_disconnect(struct sock *sk, int flags)
*/
static struct sock *sctp_accept(struct sock *sk, struct proto_accept_arg *arg)
{
- struct sctp_sock *sp, *newsp;
- struct sctp_endpoint *ep;
- struct sock *newsk = NULL;
struct sctp_association *asoc;
- long timeo;
+ struct sock *newsk = NULL;
int error = 0;
+ long timeo;
lock_sock(sk);
- sp = sctp_sk(sk);
- ep = sp->ep;
-
if (!sctp_style(sk, TCP)) {
error = -EOPNOTSUPP;
goto out;
@@ -4883,43 +4946,19 @@ static struct sock *sctp_accept(struct sock *sk, struct proto_accept_arg *arg)
/* We treat the list of associations on the endpoint as the accept
* queue and pick the first association on the list.
*/
- asoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
-
- newsk = sp->pf->create_accept_sk(sk, asoc, arg->kern);
- if (!newsk) {
- error = -ENOMEM;
- goto out;
- }
+ asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
+ struct sctp_association, asocs);
- newsp = sctp_sk(newsk);
- newsp->ep = sctp_endpoint_new(newsk, GFP_KERNEL);
- if (!newsp->ep) {
- error = -ENOMEM;
- goto out_release;
+ newsk = sctp_clone_sock(sk, asoc, SCTP_SOCKET_TCP);
+ if (IS_ERR(newsk)) {
+ error = PTR_ERR(newsk);
+ newsk = NULL;
}
- skb_queue_head_init(&newsp->pd_lobby);
-
- sk_sockets_allocated_inc(newsk);
- sock_prot_inuse_add(sock_net(sk), newsk->sk_prot, 1);
- SCTP_DBG_OBJCNT_INC(sock);
-
- /* Populate the fields of the newsk from the oldsk and migrate the
- * asoc to the newsk.
- */
- error = sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP);
- if (error)
- goto out_release;
-
out:
release_sock(sk);
arg->err = error;
return newsk;
-
-out_release:
- sk_common_release(newsk);
- newsk = NULL;
- goto out;
}
/* The SCTP ioctl handler. */