mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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>
This commit is contained in:
committed by
Jakub Kicinski
parent
151b98d10e
commit
16942cf4d3
@@ -755,9 +755,7 @@ EXPORT_SYMBOL(inet_stream_connect);
|
||||
|
||||
void __inet_accept(struct socket *sock, struct socket *newsock, struct sock *newsk)
|
||||
{
|
||||
/* TODO: use sk_clone_lock() in SCTP and remove protocol checks */
|
||||
if (mem_cgroup_sockets_enabled &&
|
||||
(!IS_ENABLED(CONFIG_IP_SCTP) || sk_is_tcp(newsk))) {
|
||||
if (mem_cgroup_sockets_enabled) {
|
||||
gfp_t gfp = GFP_KERNEL | __GFP_NOFAIL;
|
||||
|
||||
mem_cgroup_sk_alloc(newsk);
|
||||
|
||||
@@ -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);
|
||||
asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
|
||||
struct sctp_association, asocs);
|
||||
|
||||
newsk = sp->pf->create_accept_sk(sk, asoc, arg->kern);
|
||||
if (!newsk) {
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
newsk = sctp_clone_sock(sk, asoc, SCTP_SOCKET_TCP);
|
||||
if (IS_ERR(newsk)) {
|
||||
error = PTR_ERR(newsk);
|
||||
newsk = NULL;
|
||||
}
|
||||
|
||||
newsp = sctp_sk(newsk);
|
||||
newsp->ep = sctp_endpoint_new(newsk, GFP_KERNEL);
|
||||
if (!newsp->ep) {
|
||||
error = -ENOMEM;
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
Reference in New Issue
Block a user