Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 289842
b: refs/heads/master
c: a8afca0
h: refs/heads/master
v: v3
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Feb 1, 2012
1 parent cdaf4ca commit dc243c6
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 41de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1
refs/heads/master: a8afca032998850ec63e83d555cdcf0eb5680cd6
2 changes: 1 addition & 1 deletion trunk/include/linux/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ struct tcp_sock {
const struct tcp_sock_af_ops *af_specific;

/* TCP MD5 Signature Option information */
struct tcp_md5sig_info *md5sig_info;
struct tcp_md5sig_info __rcu *md5sig_info;
#endif

/* When the cookie options are generated and exchanged, then this
Expand Down
1 change: 1 addition & 0 deletions trunk/include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,7 @@ struct tcp_md5sig_key {
/* - sock block */
struct tcp_md5sig_info {
struct hlist_head head;
struct rcu_head rcu;
};

/* - pseudo header */
Expand Down
32 changes: 20 additions & 12 deletions trunk/net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -879,14 +879,18 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
struct tcp_md5sig_key *key;
struct hlist_node *pos;
unsigned int size = sizeof(struct in_addr);
struct tcp_md5sig_info *md5sig;

if (!tp->md5sig_info)
/* caller either holds rcu_read_lock() or socket lock */
md5sig = rcu_dereference_check(tp->md5sig_info,
sock_owned_by_user(sk));
if (!md5sig)
return NULL;
#if IS_ENABLED(CONFIG_IPV6)
if (family == AF_INET6)
size = sizeof(struct in6_addr);
#endif
hlist_for_each_entry_rcu(key, pos, &tp->md5sig_info->head, node) {
hlist_for_each_entry_rcu(key, pos, &md5sig->head, node) {
if (key->family != family)
continue;
if (!memcmp(&key->addr, addr, size))
Expand Down Expand Up @@ -932,15 +936,16 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
return 0;
}

md5sig = tp->md5sig_info;
md5sig = rcu_dereference_protected(tp->md5sig_info,
sock_owned_by_user(sk));
if (!md5sig) {
md5sig = kmalloc(sizeof(*md5sig), gfp);
if (!md5sig)
return -ENOMEM;

sk_nocaps_add(sk, NETIF_F_GSO_MASK);
INIT_HLIST_HEAD(&md5sig->head);
tp->md5sig_info = md5sig;
rcu_assign_pointer(tp->md5sig_info, md5sig);
}

key = sock_kmalloc(sk, sizeof(*key), gfp);
Expand All @@ -966,14 +971,17 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_md5sig_key *key;
struct tcp_md5sig_info *md5sig;

key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET);
if (!key)
return -ENOENT;
hlist_del_rcu(&key->node);
atomic_sub(sizeof(*key), &sk->sk_omem_alloc);
kfree_rcu(key, rcu);
if (hlist_empty(&tp->md5sig_info->head))
md5sig = rcu_dereference_protected(tp->md5sig_info,
sock_owned_by_user(sk));
if (hlist_empty(&md5sig->head))
tcp_free_md5sig_pool();
return 0;
}
Expand All @@ -984,10 +992,13 @@ void tcp_clear_md5_list(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_md5sig_key *key;
struct hlist_node *pos, *n;
struct tcp_md5sig_info *md5sig;

if (!hlist_empty(&tp->md5sig_info->head))
md5sig = rcu_dereference_protected(tp->md5sig_info, 1);

if (!hlist_empty(&md5sig->head))
tcp_free_md5sig_pool();
hlist_for_each_entry_safe(key, pos, n, &tp->md5sig_info->head, node) {
hlist_for_each_entry_safe(key, pos, n, &md5sig->head, node) {
hlist_del_rcu(&key->node);
atomic_sub(sizeof(*key), &sk->sk_omem_alloc);
kfree_rcu(key, rcu);
Expand All @@ -1009,12 +1020,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
if (sin->sin_family != AF_INET)
return -EINVAL;

if (!cmd.tcpm_key || !cmd.tcpm_keylen) {
if (!tcp_sk(sk)->md5sig_info)
return -ENOENT;
if (!cmd.tcpm_key || !cmd.tcpm_keylen)
return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,
AF_INET);
}

if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
return -EINVAL;
Expand Down Expand Up @@ -1896,7 +1904,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
/* Clean up the MD5 key list, if any */
if (tp->md5sig_info) {
tcp_clear_md5_list(sk);
kfree(tp->md5sig_info);
kfree_rcu(tp->md5sig_info, rcu);
tp->md5sig_info = NULL;
}
#endif
Expand Down
2 changes: 0 additions & 2 deletions trunk/net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,6 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
return -EINVAL;

if (!cmd.tcpm_keylen) {
if (!tcp_sk(sk)->md5sig_info)
return -ENOENT;
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
AF_INET);
Expand Down

0 comments on commit dc243c6

Please sign in to comment.