Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@ struct xfrm_state {

RH_KABI_EXTEND(u32 output_mark_mask)
RH_KABI_EXTEND(u32 if_id)
RH_KABI_EXTEND(struct sock __rcu *encap_sk)
RH_KABI_EXTEND(struct hlist_node byseq)
};

Expand Down
53 changes: 7 additions & 46 deletions net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,46 +119,15 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
}

#ifdef CONFIG_INET_ESPINTCP
struct esp_tcp_sk {
struct sock *sk;
struct rcu_head rcu;
};

static void esp_free_tcp_sk(struct rcu_head *head)
{
struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);

sock_put(esk->sk);
kfree(esk);
}

static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
{
struct xfrm_encap_tmpl *encap = x->encap;
struct esp_tcp_sk *esk;
__be16 sport, dport;
struct sock *nsk;
struct sock *sk;

sk = rcu_dereference(x->encap_sk);
if (sk && sk->sk_state == TCP_ESTABLISHED)
return sk;

spin_lock_bh(&x->lock);
sport = encap->encap_sport;
dport = encap->encap_dport;
nsk = rcu_dereference_protected(x->encap_sk,
lockdep_is_held(&x->lock));
if (sk && sk == nsk) {
esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
if (!esk) {
spin_unlock_bh(&x->lock);
return ERR_PTR(-ENOMEM);
}
RCU_INIT_POINTER(x->encap_sk, NULL);
esk->sk = sk;
call_rcu(&esk->rcu, esp_free_tcp_sk);
}
spin_unlock_bh(&x->lock);

sk = inet_lookup_established(xs_net(x), &tcp_hashinfo, x->id.daddr.a4,
Expand All @@ -171,20 +140,6 @@ static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
return ERR_PTR(-EINVAL);
}

spin_lock_bh(&x->lock);
nsk = rcu_dereference_protected(x->encap_sk,
lockdep_is_held(&x->lock));
if (encap->encap_sport != sport ||
encap->encap_dport != dport) {
sock_put(sk);
sk = nsk ?: ERR_PTR(-EREMCHG);
} else if (sk == nsk) {
sock_put(sk);
} else {
rcu_assign_pointer(x->encap_sk, sk);
}
spin_unlock_bh(&x->lock);

return sk;
}

Expand All @@ -197,8 +152,10 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)

sk = esp_find_tcp_sk(x);
err = PTR_ERR_OR_ZERO(sk);
if (err)
if (err) {
kfree_skb(skb);
goto out;
}

bh_lock_sock(sk);
if (sock_owned_by_user(sk))
Expand All @@ -207,6 +164,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
err = espintcp_push_skb(sk, skb);
bh_unlock_sock(sk);

sock_put(sk);

out:
rcu_read_unlock();
return err;
Expand Down Expand Up @@ -389,6 +348,8 @@ static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
if (IS_ERR(sk))
return ERR_CAST(sk);

sock_put(sk);

*lenp = htons(len);
esph = (struct ip_esp_hdr *)(lenp + 1);

Expand Down
53 changes: 7 additions & 46 deletions net/ipv6/esp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,46 +148,15 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
}

#ifdef CONFIG_INET6_ESPINTCP
struct esp_tcp_sk {
struct sock *sk;
struct rcu_head rcu;
};

static void esp_free_tcp_sk(struct rcu_head *head)
{
struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);

sock_put(esk->sk);
kfree(esk);
}

static struct sock *esp6_find_tcp_sk(struct xfrm_state *x)
{
struct xfrm_encap_tmpl *encap = x->encap;
struct esp_tcp_sk *esk;
__be16 sport, dport;
struct sock *nsk;
struct sock *sk;

sk = rcu_dereference(x->encap_sk);
if (sk && sk->sk_state == TCP_ESTABLISHED)
return sk;

spin_lock_bh(&x->lock);
sport = encap->encap_sport;
dport = encap->encap_dport;
nsk = rcu_dereference_protected(x->encap_sk,
lockdep_is_held(&x->lock));
if (sk && sk == nsk) {
esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
if (!esk) {
spin_unlock_bh(&x->lock);
return ERR_PTR(-ENOMEM);
}
RCU_INIT_POINTER(x->encap_sk, NULL);
esk->sk = sk;
call_rcu(&esk->rcu, esp_free_tcp_sk);
}
spin_unlock_bh(&x->lock);

sk = __inet6_lookup_established(xs_net(x), &tcp_hashinfo, &x->id.daddr.in6,
Expand All @@ -200,20 +169,6 @@ static struct sock *esp6_find_tcp_sk(struct xfrm_state *x)
return ERR_PTR(-EINVAL);
}

spin_lock_bh(&x->lock);
nsk = rcu_dereference_protected(x->encap_sk,
lockdep_is_held(&x->lock));
if (encap->encap_sport != sport ||
encap->encap_dport != dport) {
sock_put(sk);
sk = nsk ?: ERR_PTR(-EREMCHG);
} else if (sk == nsk) {
sock_put(sk);
} else {
rcu_assign_pointer(x->encap_sk, sk);
}
spin_unlock_bh(&x->lock);

return sk;
}

Expand All @@ -226,8 +181,10 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)

sk = esp6_find_tcp_sk(x);
err = PTR_ERR_OR_ZERO(sk);
if (err)
if (err) {
kfree_skb(skb);
goto out;
}

bh_lock_sock(sk);
if (sock_owned_by_user(sk))
Expand All @@ -236,6 +193,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
err = espintcp_push_skb(sk, skb);
bh_unlock_sock(sk);

sock_put(sk);

out:
rcu_read_unlock();
return err;
Expand Down Expand Up @@ -437,6 +396,8 @@ static struct ip_esp_hdr *esp6_output_tcp_encap(struct xfrm_state *x,
if (IS_ERR(sk))
return ERR_CAST(sk);

sock_put(sk);

*lenp = htons(len);
esph = (struct ip_esp_hdr *)(lenp + 1);

Expand Down
11 changes: 9 additions & 2 deletions net/xfrm/espintcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,10 @@ int espintcp_queue_out(struct sock *sk, struct sk_buff *skb)
{
struct espintcp_ctx *ctx = espintcp_getctx(sk);

if (skb_queue_len(&ctx->out_queue) >= netdev_max_backlog)
if (skb_queue_len(&ctx->out_queue) >= netdev_max_backlog) {
kfree_skb(skb);
return -ENOBUFS;
}

__skb_queue_tail(&ctx->out_queue, skb);

Expand Down Expand Up @@ -340,6 +342,10 @@ static int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
err = -ENOBUFS;
goto unlock;
}
if (emsg->len) {
err = -ENOBUFS;
goto unlock;
}

sk_msg_init(&emsg->skmsg);
while (1) {
Expand Down Expand Up @@ -522,7 +528,8 @@ static void espintcp_close(struct sock *sk, long timeout)
strp_stop(&ctx->strp);

sk->sk_prot = &tcp_prot;
barrier();

synchronize_rcu();

cancel_work_sync(&ctx->work);
strp_done(&ctx->strp);
Expand Down
3 changes: 0 additions & 3 deletions net/xfrm/xfrm_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,6 @@ int __xfrm_state_delete(struct xfrm_state *x)
net->xfrm.state_num--;
spin_unlock(&net->xfrm.xfrm_state_lock);

if (x->encap_sk)
sock_put(rcu_dereference_raw(x->encap_sk));

xfrm_dev_state_delete(x);

/* All xfrm_state objects are created by xfrm_state_alloc.
Expand Down
Loading