net/tcp: Add TCP-AO sign to twsk
Add support for sockets in time-wait state. ao_info as well as all keys are inherited on transition to time-wait socket. The lifetime of ao_info is now protected by ref counter, so that tcp_ao_destroy_sock() will destruct it only when the last user is gone. Co-developed-by: Francesco Ruggeri <fruggeri@arista.com> Signed-off-by: Francesco Ruggeri <fruggeri@arista.com> Co-developed-by: Salam Noureddine <noureddine@arista.com> Signed-off-by: Salam Noureddine <noureddine@arista.com> Signed-off-by: Dmitry Safonov <dima@arista.com> Acked-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
ba7783ad45
commit
decde2586b
@ -159,6 +159,7 @@ static struct tcp_ao_info *tcp_ao_alloc_info(gfp_t flags)
|
||||
if (!ao)
|
||||
return NULL;
|
||||
INIT_HLIST_HEAD(&ao->head);
|
||||
refcount_set(&ao->refcnt, 1);
|
||||
|
||||
return ao;
|
||||
}
|
||||
@ -176,27 +177,54 @@ static void tcp_ao_key_free_rcu(struct rcu_head *head)
|
||||
kfree_sensitive(key);
|
||||
}
|
||||
|
||||
void tcp_ao_destroy_sock(struct sock *sk)
|
||||
void tcp_ao_destroy_sock(struct sock *sk, bool twsk)
|
||||
{
|
||||
struct tcp_ao_info *ao;
|
||||
struct tcp_ao_key *key;
|
||||
struct hlist_node *n;
|
||||
|
||||
ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 1);
|
||||
tcp_sk(sk)->ao_info = NULL;
|
||||
if (twsk) {
|
||||
ao = rcu_dereference_protected(tcp_twsk(sk)->ao_info, 1);
|
||||
tcp_twsk(sk)->ao_info = NULL;
|
||||
} else {
|
||||
ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 1);
|
||||
tcp_sk(sk)->ao_info = NULL;
|
||||
}
|
||||
|
||||
if (!ao)
|
||||
if (!ao || !refcount_dec_and_test(&ao->refcnt))
|
||||
return;
|
||||
|
||||
hlist_for_each_entry_safe(key, n, &ao->head, node) {
|
||||
hlist_del_rcu(&key->node);
|
||||
atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc);
|
||||
if (!twsk)
|
||||
atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc);
|
||||
call_rcu(&key->rcu, tcp_ao_key_free_rcu);
|
||||
}
|
||||
|
||||
kfree_rcu(ao, rcu);
|
||||
}
|
||||
|
||||
void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp)
|
||||
{
|
||||
struct tcp_ao_info *ao_info = rcu_dereference_protected(tp->ao_info, 1);
|
||||
|
||||
if (ao_info) {
|
||||
struct tcp_ao_key *key;
|
||||
struct hlist_node *n;
|
||||
int omem = 0;
|
||||
|
||||
hlist_for_each_entry_safe(key, n, &ao_info->head, node) {
|
||||
omem += tcp_ao_sizeof_key(key);
|
||||
}
|
||||
|
||||
refcount_inc(&ao_info->refcnt);
|
||||
atomic_sub(omem, &(((struct sock *)tp)->sk_omem_alloc));
|
||||
rcu_assign_pointer(tcptw->ao_info, ao_info);
|
||||
} else {
|
||||
tcptw->ao_info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4 tuple and ISNs are expected in NBO */
|
||||
static int tcp_v4_ao_calc_key(struct tcp_ao_key *mkt, u8 *key,
|
||||
__be32 saddr, __be32 daddr,
|
||||
@ -514,11 +542,13 @@ int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb,
|
||||
if (!sk)
|
||||
return -ENOTCONN;
|
||||
|
||||
if ((1 << sk->sk_state) &
|
||||
(TCPF_LISTEN | TCPF_NEW_SYN_RECV | TCPF_TIME_WAIT))
|
||||
if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV)) {
|
||||
return -1;
|
||||
|
||||
ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
|
||||
if (sk->sk_state == TCP_TIME_WAIT)
|
||||
ao_info = rcu_dereference(tcp_twsk(sk)->ao_info);
|
||||
else
|
||||
ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
|
||||
if (!ao_info)
|
||||
return -ENOENT;
|
||||
|
||||
@ -910,6 +940,9 @@ static struct tcp_ao_info *setsockopt_ao_info(struct sock *sk)
|
||||
if (sk_fullsock(sk)) {
|
||||
return rcu_dereference_protected(tcp_sk(sk)->ao_info,
|
||||
lockdep_sock_is_held(sk));
|
||||
} else if (sk->sk_state == TCP_TIME_WAIT) {
|
||||
return rcu_dereference_protected(tcp_twsk(sk)->ao_info,
|
||||
lockdep_sock_is_held(sk));
|
||||
}
|
||||
return ERR_PTR(-ESOCKTNOSUPPORT);
|
||||
}
|
||||
|
Reference in New Issue
Block a user